docs(fase-5.14): document inline add-form UX change
Recorded in plan/fase-5-mobile-ux.md (new §5.14 with the six UX answers)
and CLAUDE.md "Fase 5 — what has been built" section. Also corrected the
"Fase 2a — what has been built" line that still claimed a sticky create
input for /lists, which was replaced by the masthead "New list" button
back in Fase 5.8.
Code change was committed in 3a11914.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -98,6 +98,13 @@ just test-e2e-headed # Playwright with visible browser (debugging)
|
|||||||
- On `/lists/[id]`, `/tasks/[id]`, `/notes/[id]`, `/lists/[id]/session` the global `MobileTopBar` is hidden via an `isDetailRoute` regex check in `(app)/+layout.svelte`. The route's own contextual header (back + title + actions) becomes the only top chrome and is now `sticky top-0 z-30 bg-surface/80 backdrop-blur-xl`.
|
- On `/lists/[id]`, `/tasks/[id]`, `/notes/[id]`, `/lists/[id]/session` the global `MobileTopBar` is hidden via an `isDetailRoute` regex check in `(app)/+layout.svelte`. The route's own contextual header (back + title + actions) becomes the only top chrome and is now `sticky top-0 z-30 bg-surface/80 backdrop-blur-xl`.
|
||||||
- `BottomTabBar` stays visible so users can hop between sections.
|
- `BottomTabBar` stays visible so users can hop between sections.
|
||||||
|
|
||||||
|
**5.14 inline add-form (last element of the list)**
|
||||||
|
- `/lists/[id]` + `/tasks/[id]` no longer have a bottom-sticky add form. The form renders **inline as the last child of the unchecked / pending section** (just above Checked / Completed). Empty-state branch shows message + form beneath it.
|
||||||
|
- On `/lists/[id]` the frequency chips (`ItemSuggestions`) moved below the input (input row on top, chips on second line). Mobile: horizontal scroll; desktop: wrap.
|
||||||
|
- Hides entirely while `selectionMode` is active.
|
||||||
|
- Svelte 5 snippets `addItemForm` / `addTaskForm` so the form is rendered in both the empty-state branch and the between-sections slot without duplication.
|
||||||
|
- `data-testid="add-item-form"` / `"add-task-form"` hooks added for future placement assertions.
|
||||||
|
|
||||||
### Fase 5 — earlier sub-phases (still relevant)
|
### Fase 5 — earlier sub-phases (still relevant)
|
||||||
|
|
||||||
- `apps/web/src/lib/components/layout/DesktopSidebar.svelte` — desktop sidebar extracted from `(app)/+layout.svelte`, `data-testid="desktop-sidebar"`, `hidden md:flex`
|
- `apps/web/src/lib/components/layout/DesktopSidebar.svelte` — desktop sidebar extracted from `(app)/+layout.svelte`, `data-testid="desktop-sidebar"`, `hidden md:flex`
|
||||||
@@ -159,7 +166,7 @@ just test-e2e-headed # Playwright with visible browser (debugging)
|
|||||||
- `supabase/migrations/006_item_frequency.sql` — `item_frequency` table, `fn_record_item_frequency` trigger (SECURITY DEFINER, fires on every `shopping_items` INSERT)
|
- `supabase/migrations/006_item_frequency.sql` — `item_frequency` table, `fn_record_item_frequency` trigger (SECURITY DEFINER, fires on every `shopping_items` INSERT)
|
||||||
- `apps/web/src/lib/stores/lists.ts` — shopping lists store (optimistic CRUD) + item operations + suggestion fetching
|
- `apps/web/src/lib/stores/lists.ts` — shopping lists store (optimistic CRUD) + item operations + suggestion fetching
|
||||||
- `apps/web/src/lib/components/ItemSuggestions.svelte` — frequency chips with active-prefix highlighting
|
- `apps/web/src/lib/components/ItemSuggestions.svelte` — frequency chips with active-prefix highlighting
|
||||||
- `apps/web/src/routes/(app)/lists/+page.svelte` — overview: featured card + 2-col grid + completed section + trash view + sticky create input
|
- `apps/web/src/routes/(app)/lists/+page.svelte` — overview: featured card + 2-col grid + completed section + trash view (sticky input replaced by masthead "New list" button in Fase 5.8)
|
||||||
- `apps/web/src/routes/(app)/lists/[id]/+page.svelte` — list detail: items with checkbox, qty stepper (−/N/+), inline edit, swipe-to-reveal-delete (touch) + hover delete (desktop), drag & drop reorder via `svelte-dnd-action`, sticky add form with `ItemSuggestions`
|
- `apps/web/src/routes/(app)/lists/[id]/+page.svelte` — list detail: items with checkbox, qty stepper (−/N/+), inline edit, swipe-to-reveal-delete (touch) + hover delete (desktop), drag & drop reorder via `svelte-dnd-action`, sticky add form with `ItemSuggestions`
|
||||||
|
|
||||||
## Local Dev: Required /etc/hosts Entry
|
## Local Dev: Required /etc/hosts Entry
|
||||||
|
|||||||
@@ -442,6 +442,44 @@ Doble tap corto (≤ 300 ms entre toques) en una fila (en modo normal) abre un o
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
#### 5.14 Formulario de alta inline al final de la lista
|
||||||
|
|
||||||
|
**Cambio de UX:** el formulario de "añadir ítem" (lists) y "añadir tarea" (tasks) dejan de estar pegados al borde inferior del viewport y pasan a vivir **dentro del scroll**, como el último elemento de la sección sin marcar (unchecked / pending). Las sugerencias de frecuencia bajan **debajo** del input en vez de encima.
|
||||||
|
|
||||||
|
**Decisiones (respuestas del usuario a las preguntas 1–6):**
|
||||||
|
1. Posición del formulario → opción `a`: al final de *unchecked only*, justo encima de la sección Checked.
|
||||||
|
2. Scroll → inline puro. Sin FAB, sin auto-scroll.
|
||||||
|
3. Empty state → mensaje primero, formulario debajo (usuario puede añadir el primer ítem sin scrollear).
|
||||||
|
4. Sugerencias: input arriba, chips debajo. Mobile: scroll horizontal. Desktop: wrap (comportamiento actual de `ItemSuggestions`).
|
||||||
|
5. Aplica a `/lists/[id]` **y** `/tasks/[id]`.
|
||||||
|
6. Selection mode: el formulario se oculta.
|
||||||
|
|
||||||
|
**Cambios:**
|
||||||
|
|
||||||
|
- [x] `/lists/[id]/+page.svelte`:
|
||||||
|
- Eliminado el bloque `absolute bottom-0` con `backdrop-blur`.
|
||||||
|
- Nuevo snippet `addItemForm` renderizado (a) dentro de la rama empty-state y (b) entre las secciones unchecked y checked. Sólo se renderiza cuando `!selectionMode`.
|
||||||
|
- `ItemSuggestions` movido dentro del snippet, debajo del input.
|
||||||
|
- Padding inferior del scroll: `pb-32` → `pb-16 md:pb-6`.
|
||||||
|
- `data-testid="add-item-form"` añadido como hook de tests futuros.
|
||||||
|
- [x] `/tasks/[id]/+page.svelte`:
|
||||||
|
- Mismo patrón con `addTaskForm` (sin suggestions — `/tasks` no tiene `item_frequency`).
|
||||||
|
- `data-testid="add-task-form"`.
|
||||||
|
- Reposicionamiento sin cambiar el comportamiento de Enter / botón `+`.
|
||||||
|
|
||||||
|
**Tests:**
|
||||||
|
|
||||||
|
- Los tests existentes pasan sin cambios — los locators son `getByPlaceholder(/add item|añadir producto/i)` / `getByPlaceholder(/add task|añadir tarea/i)` y funcionan estén donde estén los inputs.
|
||||||
|
- Hooks `data-testid` añadidos por si se quieren assertions explícitos de ubicación más adelante.
|
||||||
|
|
||||||
|
**Criterio de aceptación:**
|
||||||
|
- Form no flota; scrollea con la lista.
|
||||||
|
- Sugerencias debajo del input en ambos breakpoints.
|
||||||
|
- En lista vacía: mensaje + form debajo.
|
||||||
|
- Selection mode: form desaparece (el action bar toma su lugar).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
#### 5.13 Resistencia a contextos no-seguros (HTTP LAN)
|
#### 5.13 Resistencia a contextos no-seguros (HTTP LAN)
|
||||||
|
|
||||||
**Problema descubierto tras deploy de la preview mobile:** el usuario abrió `http://192.168.1.167:5173` en el móvil (origen no-seguro) y `handleAdd` lanzó `TypeError: crypto.randomUUID is not a function`. `crypto.randomUUID` solo está expuesto en HTTPS, localhost, 127.0.0.1 o file:// — fuera de eso queda `undefined`.
|
**Problema descubierto tras deploy de la preview mobile:** el usuario abrió `http://192.168.1.167:5173` en el móvil (origen no-seguro) y `handleAdd` lanzó `TypeError: crypto.randomUUID is not a function`. `crypto.randomUUID` solo está expuesto en HTTPS, localhost, 127.0.0.1 o file:// — fuera de eso queda `undefined`.
|
||||||
@@ -464,6 +502,7 @@ Doble tap corto (≤ 300 ms entre toques) en una fila (en modo normal) abre un o
|
|||||||
- 140 Vitest integration + 2 skipped presence (sin cambios)
|
- 140 Vitest integration + 2 skipped presence (sin cambios)
|
||||||
- 15 Vitest unit (was 11, +4 generateId)
|
- 15 Vitest unit (was 11, +4 generateId)
|
||||||
- 44 Playwright (was 43, +1 INS-01)
|
- 44 Playwright (was 43, +1 INS-01)
|
||||||
|
- [x] Inline add-form UX (5.14) verificado manualmente en DevTools mobile + desktop tras el refactor.
|
||||||
- [ ] Validación visual en DevTools iPhone 13 (390×844) + Pixel 7 (412×915) + Desktop (1280×800) — pendiente (manual, post-deploy).
|
- [ ] Validación visual en DevTools iPhone 13 (390×844) + Pixel 7 (412×915) + Desktop (1280×800) — pendiente (manual, post-deploy).
|
||||||
- [x] `loginAs(USERS.borja)` con `page.setViewportSize(MOBILE)` activa el shell mobile automáticamente (verificado en M-01..M-04).
|
- [x] `loginAs(USERS.borja)` con `page.setViewportSize(MOBILE)` activa el shell mobile automáticamente (verificado en M-01..M-04).
|
||||||
- [x] Seis commits incrementales (5.10.0 → 5.12 → 5.8 → 5.10 → 5.11) para facilitar revert o review por pasos.
|
- [x] Seis commits incrementales (5.10.0 → 5.12 → 5.8 → 5.10 → 5.11) para facilitar revert o review por pasos.
|
||||||
|
|||||||
Reference in New Issue
Block a user