# Shell applicatif — menu latéral (tiroir) et barre de navigation responsive (VIIZIA → Neoloop)

Note d’implémentation pour **reproduire le même comportement** sur Neoloop : vue **≤ 768 px** avec menu vertical en **overlay**, navbar **compacte** et **ancrée sous la lame haute**, fermetures accessibles et **reports** dans le tiroir de ce qui n’est plus affiché dans la nav.

Voir aussi [bulma-extensions.md](bulma-extensions.md) et [bulma-datepicker-compact-neoloop.md](bulma-datepicker-compact-neoloop.md).

---

## 1. Principes UX

| Brique | Desktop (≥ 769 px) | Petit écran (≤ 768 px) |
|--------|-------------------|------------------------|
| **Bande supérieure** | Fine bande décorative **`position: fixed`**, **`body`** compensé avec `padding-top`. | Idem |
| **Navbar** | **`position: sticky`**, **`top`** = hauteur de la bande, sous la lame. | **`position: fixed`** sous la lame (voir §6) pour qu’elle **ne défile pas** avec le contenu (scroll + overlay + couches). Barre réduite : **burger**, **logo / marque**, **titre de page** avec ellipsis si besoin. |
| **`navbar-end`** (date, menu utilisateur…) | Visible. | **`display: none`** : tout est retrouvé dans le **tiroir** (Mon compte, email, déconnexion, équivalent mois « calendrier »). |
| **Sidebar** | Colonne **`sticky`** à gauche, scroll interne. | **Tiroir** **`fixed`**, **hors écran par défaut** (`transform`), coulisse à l’ouverture ; **backdrop** semi-transparent sous la navbar. |
| **Contenu principal** | Colonne **`flex`** classique. | Pleine largeur ; padding réduit selon grille produit. |

---

## 2. Structure DOM (référence VIIZIA)

Fichier : `templates/base.html.twig`.

Ordre et **IDs stables** (utiles au JS sans framework) :

1. **`div.viz-topband`** — lame haute globale (`position: fixed` côté CSS).
2. **`nav.navbar.viz-navbar`** — après la bande, **hors** de `#viz-shell`.
3. **`#viz-shell.viz-shell`**
   - **`#viz-sidebar-backdrop`** (bouton décoratif clic = fermeture ; `hidden` hors ouvert).
   - **`aside#viz-sidebar`** — inclus `sidebar.html.twig`.
   - **`main.viz-content#viz-main`**.

Le **bouton d’ouverture** est dans **`navbar`** : **`#viz-sidebar-open`**, **`aria-controls="viz-sidebar"`**.

Références complémentaires :

- `templates/_partials/navbar.html.twig`
- `templates/_partials/sidebar.html.twig`
- `public/js/shell-sidebar.js`
- `public/css/app.css` (sections *LAYOUT*, *SIDEBAR*)

Sur Neoloop, conserver au minimum : **même enchaînement** (navbar au-dessus du shell ou équivalent permettant le même **`top`** / **`z-index`**) et **IDs** équivalents si vous réutilisez le script tel quel.

---

## 3. Variables CSS dédiées (layout)

```css
--viz-sidebar-width: 220px;   /* largeur sidebar desktop */
--viz-navbar-height: 3.25rem; /* réserve navbar : min-height desktop + référence top pour overlay */
--viz-topband-height: 4px;    /* hauteur lame + offset body / sticky / fixed */
```

Adapter les valeurs chez Neoloop ; **garder une seule source de vérité** pour calculer :

- `top` du sticky desktop sidebar : `topband + navbar`
- `top` du backdrop / tiroir mobile : idem
- `top` de la navbar **fixed** mobile : `topband` seulement
- `padding-top` du shell mobile : **`navbar-height`** (compensation du passage en `fixed`)

---

## 4. JavaScript — `shell-sidebar.js`

Rôle : basculer la classe **`is-sidebar-open`** sur **`#viz-shell`**, synchroniser backdrop, **ARIA** et **scroll du `body`**.

Comportement à documenter / porter :

| Action | Effet |
|--------|------|
| Clic **`#viz-sidebar-open`** | Bascule ouvert / fermé. |
| Clic **`#viz-sidebar-close`** | Ferme. |
| Clic **`#viz-sidebar-backdrop`** | Ferme. |
| **`Escape`** si ouvert | Ferme. |
| **`resize`** : passage **>** 768 px | Force **fermeture** (évite un shell « coincé » en mode bureau). |
| Clic lien **`a[href]`** dans **`#viz-sidebar`** | Ferme si **≤ 768 px** (navigation SPA / MPA suivante recharge quand même). |
| **`button[type="submit"]`** dans la sidebar | Ferme pareil (**POST**, ex. switch org). |

Détails d’état :

- **`document.body.classList`** : **`viz-sidebar-open`** quand le tiroir est ouvert (utile CSS global optionnel).
- **`document.body.style.overflow`** : **`hidden`** ouvert pour limiter le scroll de fond (**à compléter côté iOS avec des patterns connus si besoin** : `position: fixed` sur `body` + restauration `scrollY`, etc.).

---

## 5. CSS — menu en tiroir (≤ 768 px)

### 5.1 Conteneur shell

- **`#viz-shell`** : en mobile, garder **`display: flex`**, **`position: relative`**, **`min-width`** / flux utiles selon mise en page.
- **`padding-top: var(--viz-navbar-height)`** une fois la navbar **`fixed`** (§6).

### 5.2 Backdrop

- **`position: fixed`**
- **`top: calc(var(--viz-topband-height) + var(--viz-navbar-height))`**
- **`left: 0; right: 0; bottom: 0`**
- **`z-index`** inférieur à la sidebar mais supérieur au contenu (**ex. 55** VIIZIA)
- Hors ouvert : **`display: none`** (ou équivalent via attribut `hidden` + règle `display`)

### 5.3 Aside (sidebar)

- **`position: fixed`**
- Même **`top`** que le backdrop (navbar **toujours** visible au-dessus du voile latéral)
- **`bottom: 0`**
- **`width: min(288px, 88vw)`** (ajustable)
- **`z-index`** **au-dessus** du backdrop (**ex. 60**)
- **Fermé** : **`transform: translateX(-103%)`** (ou **-100%**) + **`transition`** sur `transform`
- **Ouvert** : **`#viz-shell.is-sidebar-open .viz-sidebar { transform: translateX(0); }`**

### 5.4 Barre « Menu » mobile dans le tiroir

Dans le HTML sidebar : bloc **`.viz-sidebar-mobile-bar`** (titre + **`#viz-sidebar-close`**).  
En **≥ 769 px** : **`display: none`** sur ce bloc.

### 5.5 Pied de sidebar — duplication « mobile only »

Bloc **`.viz-sidebar-mobile-util`** dans le footer de la sidebar :

- Par défaut **`display: none`** (desktop).
- **≤ 768 px** : **`display: block`** — date (équivalent info nav), email, bouton déconnexion.

Le **pill** « Mon compte » reste disponible pour tout le monde.

Objectif : **compenser la disparition de `navbar-end`** sans second burger.

---

## 6. CSS — navbar responsive (point sensible)

### 6.1 Desktop

- **`.viz-navbar`** : **`position: sticky`**, **`top: var(--viz-topband-height)`**, **`z-index`** modéré (**ex. 30**).

### 6.2 Mobile — pourquoi sortir du pur `sticky`

Avec **overlay**, **`overflow: hidden`** sur le `body`, contenus **riches** (tableaux en cartes, `backdrop-filter`, etc.), un **`sticky`** sur la navbar peut **cesser de coller** au viewport ou **défiler avec le contenu**.

**Décision VIIZIA (≤ 768 px)** :

```css
.viz-navbar.navbar {
    position: fixed;
    left: 0;
    right: 0;
    top: var(--viz-topband-height);
    z-index: 40; /* < backdrop 55 < sidebar 60 */
}
```

**Compensation** : **`#viz-shell { padding-top: var(--viz-navbar-height); }`** pour éviter que le main ne passe **sous** la navbar (qui n’occupe plus de place dans le flux).

### 6.3 Hiérarchie `z-index` (ordre actuel VIIZIA)

| Couche | `z-index` indicatif |
|--------|---------------------|
| Contenu « normal » | défaut (< 30) |
| Navbar mobile **fixed** | 40 |
| Backdrop | 55 |
| Sidebar ouverte | 60 |
| Lame/topband si besoin | selon stacking (VIIZIA : 50) |

À recaler chez Neoloop si d’autres modales (**dropdown globaux**) passent incorrectement au-dessus.

---

## 7. Checklist de portage Neoloop

- [ ] **`body`** avec **`padding-top`** = hauteur bande décorative **`fixed`**.
- [ ] **Navbar hors** du bloc scroll principal **ou** même structure **`body > topband, nav, shell`**.
- [ ] **`#viz-shell`** (ou équivalent) **avec** classe bascule **`is-sidebar-open`**.
- [ ] **`padding-top`** sur le shell mobile = **hauteur navbar** lorsque navbar **`fixed`**.
- [ ] **Backdrop** **`top`** = **topband + navbar** pour ne pas recouvrir la barre.
- [ ] **Sidebar** même **`top`**, **`z-index`** > backdrop.
- [ ] **`transform`** tiroir + état **`is-sidebar-open`**.
- [ ] **JS** : toggle classe, fermeture resize / Escape / lien / backdrop, **`aria-expanded`**, **`overflow`** optionnel sur `body`.
- [ ] **Masquer** la zone droite de la nav en mobile **et** **répliquer** les actions dans le tiroir (compte, déconnexion, infos date si pertinent).
- [ ] **Tester** : page longue + tiroir ouvert + scroll (navbar **reste** visible) ; thème clair / sombre.

---

## 8. Fichiers source VIIZIA (copier / comparer)

| Fichier | Contenu |
|---------|---------|
| `templates/base.html.twig` | Structure topband / nav / shell / IDs |
| `templates/_partials/navbar.html.twig` | Burger, brand, titre, `navbar-end` |
| `templates/_partials/sidebar.html.twig` | Barre fermeture mobile, footer + util bloc |
| `public/js/shell-sidebar.js` | Logique ouverture / fermeture |
| `public/css/app.css` | **`@media (max-width: 768px)`** layout + **`@media (min-width: 769px)`** masquages |

---

## 9. Maintenance

En cas de **nouvelle couche globale** (bannière système sous la lame, breadcrumbs collants, etc.) :

- Réajuster **`top`** calculés (backdrop / sidebar / nav **fixed**).
- Réajouter la **même valeur** dans **`padding-top` / `min-height`** si la hauteur totale chrome change.

Une évolution doit rester alignée avec Neoloop si les deux stacks partagent la même **cartographie des hauteurs** (`--viz-*` ou tokens équivalents).
