feat(frontend): sidebar colapsable por secciones + fly-out en modo colapsado #62

Merged
dmolinari merged 1 commits from chore/sidebar-collapsible-sections into main 2026-04-21 17:09:07 +00:00
Owner

Propósito

Mejora UX sobre PR #61 (categorización inicial). Dos problemas observados:

  1. Modo expandido: las 4 secciones agrupadas siempre mostraban todos sus items → lista aún larga.
  2. Modo colapsado: planteamiento inicial de mostrar TODOS los icons de todos los items generaba scroll vertical excesivo.

Solución

Modo expandido (240px)

  • Cada sección es colapsable independiente con chevron toggle.
  • Auto-expand de la sección activa: si estás en /admin/medios, "Maestros" se expande automáticamente — el header queda disabled sin chevron para evitar esconder items de la ruta actual.
  • Default primer uso: todas colapsadas excepto la activa — sidebar limpio al login.
  • Preferencia per-sección persistida en localStorage (key: sidebar-sections-collapsed). Si dejás "Catálogo" abierta, la próxima sesión arranca así.
  • Override runtime: la sección activa SIEMPRE prevalece, aunque localStorage diga otra cosa.

Modo colapsado (68px) — patrón VS Code / Azure Portal

  • 1 icono por grupo (4 grupos + Dashboard), no 12+ icons de items individuales.
  • Hover en el icono de grupo → fly-out panel al lado derecho con el nombre del grupo + items clickeables.
  • Dot indicator en el icono del grupo que contiene la ruta activa.
  • Icons de grupo: ShieldCheck (Seguridad), Building2 (Maestros), Package (Catálogo), Calculator (Tasación).

z-index management (pedido explícito)

  • aside wrapper en ProtectedLayout: z-10z-30 (sobre contenido de página).
  • HoverCardContent del fly-out: z-[60] (por encima de cualquier overlay de página; deja los modal dialogs standard en z-50 intactos).
  • hover-card.tsx de shadcn: envuelto en HoverCardPrimitive.Portal (faltaba — sin portal, el fly-out podía quedar cortado por overflow del aside o el layout).

Archivos

Nuevos

  • src/web/src/hooks/useSidebarSections.ts — hook con isCollapsed(name) + toggle(name) + persistencia localStorage.
  • src/web/src/components/ui/hover-card.tsx — shadcn primitive (agregado vía npx shadcn@latest add hover-card, luego ajustado con Portal).

Modificados

  • src/web/src/components/layout/AppSidebar.tsx — refactor completo: ExpandedSection (collapsible) + CollapsedSectionFlyout (hover panel).
  • src/web/src/layouts/ProtectedLayout.tsx — z-index del sidebar wrapper.
  • src/web/src/components/layout/__tests__/AppSidebar.test.tsx — 10 → 16 tests.
  • src/web/package.json + package-lock.json@radix-ui/react-hover-card.

Tests nuevos (6 casos agregados)

  • Default collapsed except la sección con ruta activa
  • Header de sección activa NO toggleable (disabled, sin chevron)
  • Click en header no-activo expande/colapsa
  • aria-expanded refleja estado
  • En Dashboard (/) ninguna sección contiene active → todas colapsadas
  • Preferencia persiste en localStorage

Total: 16/16 AppSidebar tests ✓

Verify

  • vitest: 526/526 green (+16 sidebar) — sin regresiones
  • tsc --noEmit: 0 errors, 0 warnings
  • Frontend-only, sin cambios de backend/BD

Screenshots mentales para review

Expandido + ruta en Maestros:

🏠 Dashboard
SEGURIDAD       ▶      ← colapsada (chevron rotado)
MAESTROS (activa)      ← expandida SIEMPRE (no-toggleable)
  📰 Medios ← active
  📑 Secciones
  🏪 Puntos de Venta
CATÁLOGO        ▶
TASACIÓN        ▶

Colapsado + hover en Maestros:

[☰]
[🏠]
────
[🛡️]          ← ShieldCheck (Seguridad)
[🏢] ← hover  ────────────────┐
[📦]          │  MAESTROS     │
[🧮]          │  📰 Medios    │
              │  📑 Secciones │
              │  🏪 PdV       │
              └───────────────┘

No merge automático

Siguiendo el flujo acordado: NO mergeo hasta tu OK después de revisar la UI en el browser. Link: #62

## Propósito Mejora UX sobre PR #61 (categorización inicial). Dos problemas observados: 1. **Modo expandido**: las 4 secciones agrupadas siempre mostraban todos sus items → lista aún larga. 2. **Modo colapsado**: planteamiento inicial de mostrar TODOS los icons de todos los items generaba scroll vertical excesivo. ## Solución ### Modo expandido (240px) - Cada sección es **colapsable independiente** con chevron toggle. - **Auto-expand de la sección activa**: si estás en `/admin/medios`, "Maestros" se expande automáticamente — el header queda `disabled` sin chevron para evitar esconder items de la ruta actual. - **Default primer uso**: todas colapsadas excepto la activa — sidebar limpio al login. - **Preferencia per-sección** persistida en `localStorage` (key: `sidebar-sections-collapsed`). Si dejás "Catálogo" abierta, la próxima sesión arranca así. - Override runtime: la sección activa SIEMPRE prevalece, aunque localStorage diga otra cosa. ### Modo colapsado (68px) — patrón VS Code / Azure Portal - **1 icono por grupo** (4 grupos + Dashboard), no 12+ icons de items individuales. - **Hover** en el icono de grupo → fly-out panel al lado derecho con el nombre del grupo + items clickeables. - **Dot indicator** en el icono del grupo que contiene la ruta activa. - Icons de grupo: `ShieldCheck` (Seguridad), `Building2` (Maestros), `Package` (Catálogo), `Calculator` (Tasación). ### z-index management (pedido explícito) - `aside` wrapper en `ProtectedLayout`: `z-10` → **`z-30`** (sobre contenido de página). - `HoverCardContent` del fly-out: **`z-[60]`** (por encima de cualquier overlay de página; deja los modal dialogs standard en z-50 intactos). - `hover-card.tsx` de shadcn: **envuelto en `HoverCardPrimitive.Portal`** (faltaba — sin portal, el fly-out podía quedar cortado por `overflow` del aside o el layout). ## Archivos ### Nuevos - `src/web/src/hooks/useSidebarSections.ts` — hook con `isCollapsed(name)` + `toggle(name)` + persistencia `localStorage`. - `src/web/src/components/ui/hover-card.tsx` — shadcn primitive (agregado vía `npx shadcn@latest add hover-card`, luego ajustado con Portal). ### Modificados - `src/web/src/components/layout/AppSidebar.tsx` — refactor completo: `ExpandedSection` (collapsible) + `CollapsedSectionFlyout` (hover panel). - `src/web/src/layouts/ProtectedLayout.tsx` — z-index del sidebar wrapper. - `src/web/src/components/layout/__tests__/AppSidebar.test.tsx` — 10 → 16 tests. - `src/web/package.json` + `package-lock.json` — `@radix-ui/react-hover-card`. ## Tests nuevos (6 casos agregados) - Default collapsed except la sección con ruta activa - Header de sección activa NO toggleable (disabled, sin chevron) - Click en header no-activo expande/colapsa - `aria-expanded` refleja estado - En Dashboard (`/`) ninguna sección contiene active → todas colapsadas - Preferencia persiste en `localStorage` Total: **16/16** AppSidebar tests ✓ ## Verify - `vitest`: **526/526 green** (+16 sidebar) — sin regresiones - `tsc --noEmit`: 0 errors, 0 warnings - Frontend-only, sin cambios de backend/BD ## Screenshots mentales para review **Expandido + ruta en Maestros**: ``` 🏠 Dashboard SEGURIDAD ▶ ← colapsada (chevron rotado) MAESTROS (activa) ← expandida SIEMPRE (no-toggleable) 📰 Medios ← active 📑 Secciones 🏪 Puntos de Venta CATÁLOGO ▶ TASACIÓN ▶ ``` **Colapsado + hover en Maestros**: ``` [☰] [🏠] ──── [🛡️] ← ShieldCheck (Seguridad) [🏢] ← hover ────────────────┐ [📦] │ MAESTROS │ [🧮] │ 📰 Medios │ │ 📑 Secciones │ │ 🏪 PdV │ └───────────────┘ ``` ## No merge automático Siguiendo el flujo acordado: **NO mergeo hasta tu OK** después de revisar la UI en el browser. Link: https://repo.eldiaservicios.com/dmolinari/SIG-CM2.0/pulls/62
dmolinari added 1 commit 2026-04-21 17:07:43 +00:00
Mejora UX post-refactor (PR #61): las 4 secciones del sidebar expandido son
ahora colapsables individualmente, y el modo colapsado reemplaza la lista
larga de iconos por un icono por grupo con fly-out panel on hover.

Expandido (240px):
- Click en header de sección (Seguridad/Maestros/Catálogo/Tasación) toggle
  collapse con chevron que rota.
- Default: todas colapsadas EXCEPTO la que contiene la ruta activa
  (auto-expand override).
- Sección activa tiene el header disabled + sin chevron (no se puede colapsar
  mientras estás ahí — evita esconder items de la ruta actual).
- Preferencia per-sección persistida en localStorage.

Colapsado (68px):
- Un icono por grupo en lugar de listar TODOS los items (evitando scroll
  largo en usuarios con muchos permisos).
- Hover sobre el grupo despliega un fly-out panel al lado derecho con el
  título del grupo + sus items clickeables.
- Grupo que contiene la ruta activa tiene un dot indicator.
- Icons de grupo: ShieldCheck (Seguridad), Building2 (Maestros),
  Package (Catálogo), Calculator (Tasación).

Accessibility:
- Headers expandidos: aria-expanded refleja estado.
- Fly-out: aria-haspopup='menu' + role='menu' + keyboard focus.

z-index management (pedido explícito del user):
- aside wrapper en ProtectedLayout: z-10 -> z-30 (sobre contenido).
- HoverCardContent del fly-out: z-[60] (sobre cualquier overlay app-level,
  excepto modal dialogs que siguen siendo z-50 por convención Radix).
- hover-card.tsx: envuelto en HoverCardPrimitive.Portal (faltaba en el
  shadcn generated) — previene que el fly-out quede cortado por overflow
  del aside.

Dependencies:
- shadcn hover-card agregado via 'npx shadcn@latest add' (+ @radix-ui/react-hover-card).

Tests:
- 16 tests (antes 10) — agregados 6 casos: default collapsed except active,
  click toggle expand/collapse, aria-expanded reflection, disabled header
  when active, root route collapses all, localStorage persistence.
dmolinari merged commit 5a231c206e into main 2026-04-21 17:09:07 +00:00
dmolinari deleted branch chore/sidebar-collapsible-sections 2026-04-21 17:09:08 +00:00
Sign in to join this conversation.
No Reviewers
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: dmolinari/SIG-CM2.0#62