feat(F-159): completed feature

This commit is contained in:
chattie
2026-08-22 18:02:11 +02:00
parent 8595e1ff95
commit f802a83773
12 changed files with 427 additions and 61 deletions

View File

@@ -0,0 +1,24 @@
# F-159 — Diseño
## Arquitectura
El estado vive en `DashboardShell`, única composición del layout autenticado:
- `desktopCollapsed`: preferencia persistida en `localStorage` bajo `mdv.admin.sidebar.collapsed`.
- `mobileOpen`: estado efímero del drawer.
`Sidebar` y `NavItemRow` siguen consumiendo la misma lista `visibleNavItems(role)`. No se crean menús alternativos.
## Responsive
- Sidebar base: drawer `fixed`, 240px y desplazado fuera de viewport cuando está cerrado.
- `lg+`: pasa a `sticky`, siempre visible, ancho 240px/80px según preferencia.
- Etiquetas usan `lg:hidden` solo durante collapse, por lo que el drawer móvil siempre conserva texto.
- Backdrop solo se renderiza con drawer abierto.
## Accesibilidad
- Toggle es `<button>` nativo con `aria-expanded`, `aria-controls` y etiqueta dinámica.
- Escape cierra drawer.
- Drawer móvil cerrado usa `invisible` para excluir enlaces del foco.
- Enlaces tienen `aria-label`; modo icon-only añade `title`.
## Transiciones
`transition-[width,transform] duration-300 ease-in-out`, respetando las utilidades existentes de Tailwind.

View File

@@ -0,0 +1,5 @@
# F-159 — Uso
- En desktop, el botón del header colapsa/expande el sidebar. La preferencia se conserva al recargar.
- Colapsado muestra iconos; cada icono mantiene tooltip y nombre accesible.
- En mobile/tablet, el botón abre un drawer. Se cierra al navegar, pulsar el fondo, el botón de cierre o Escape.

View File

@@ -0,0 +1,20 @@
# F-159 — Implementer
## Implementación
- `SidebarToggle` reutilizable para desktop y mobile.
- Estado desktop `expanded/collapsed` persistido en `localStorage` (`mdv.admin.sidebar.collapsed`).
- Desktop colapsado reduce 240px→80px y oculta etiquetas solo en breakpoint `lg`.
- Mobile/tablet usa el mismo sidebar como drawer con backdrop y cierre por navegación, botón o Escape.
- Drawer cerrado queda `invisible`, evitando foco en enlaces fuera de pantalla.
- Transiciones suaves de ancho, transformación e icono.
- Accesibilidad: botones nativos, `aria-label`, `aria-expanded`, `aria-controls`, `aria-current`, focus rings y tooltips.
- Restaurado acceso visible a cerrar sesión dentro del sidebar.
## Evidencia
- `cd project/apps/admin && npm run build`: PASS (29 rutas).
- `cd project && node_modules/.bin/tsc --noEmit`: PASS.
- `git diff --check`: PASS.
- `./scripts/verify.sh`: PASS.
## Archivo
- `project/apps/admin/src/app/(dashboard)/layout.tsx`

View File

@@ -0,0 +1,14 @@
{
"feature_id":"F-159",
"agent":"leader",
"stage":"close",
"verdict":"APPROVED",
"summary":"SidebarToggle responsive, persistente y accesible completado.",
"checks":[
{"item":"reviewer","ok":true},
{"item":"security","ok":true},
{"item":"qa","ok":true},
{"item":"build and verify","ok":true}
],
"issues":[]
}

View File

@@ -0,0 +1,15 @@
{
"feature_id": "F-159",
"agent": "qa",
"stage": "qa_gate",
"verdict": "APPROVED",
"summary": "Cumple persistencia, icon-only desktop, drawer mobile, transición y accesibilidad.",
"checks": [
{"item":"Desktop collapse","ok":true,"evidence":"lg width 60→20 and lg-only label hiding"},
{"item":"Mobile/tablet drawer","ok":true,"evidence":"fixed transform drawer plus backdrop"},
{"item":"Keyboard","ok":true,"evidence":"Native buttons, focus rings and Escape handler"},
{"item":"Persistence","ok":true,"evidence":"Stable localStorage key"},
{"item":"Regression","ok":true,"evidence":"Admin build, tsc and verify passed"}
],
"issues": []
}

View File

@@ -0,0 +1,14 @@
{
"feature_id": "F-159",
"agent": "reviewer",
"stage": "review_gate",
"verdict": "APPROVED",
"summary": "Una única jerarquía de navegación cubre collapse desktop y drawer mobile sin duplicación.",
"checks": [
{"item":"Single navigation source","ok":true,"evidence":"Sidebar maps visibleNavItems once"},
{"item":"Persisted desktop state","ok":true,"evidence":"localStorage key read on mount and written on toggle"},
{"item":"Mobile drawer","ok":true,"evidence":"fixed drawer, backdrop, route close and Escape close"},
{"item":"Admin build","ok":true,"evidence":"Next.js production build passed"}
],
"issues": []
}

View File

@@ -0,0 +1,13 @@
{
"feature_id": "F-159",
"agent": "security",
"stage": "security_gate",
"verdict": "APPROVED",
"summary": "Solo se persiste una preferencia booleana no sensible; no cambian auth, permisos ni destinos de navegación.",
"checks": [
{"item":"No sensitive storage","ok":true,"evidence":"localStorage contains only collapsed boolean"},
{"item":"RBAC preserved","ok":true,"evidence":"Navigation remains filtered by visibleNavItems(role)"},
{"item":"No dependency change","ok":true,"evidence":"Uses React and existing Tailwind only"}
],
"issues": []
}