diff --git a/CLAUDE.md b/CLAUDE.md index 9c4b1e0..b7d389b 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -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`. - `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) - `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) - `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/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` ## Local Dev: Required /etc/hosts Entry diff --git a/plan/fase-5-mobile-ux.md b/plan/fase-5-mobile-ux.md index cb0d3ba..b419610 100644 --- a/plan/fase-5-mobile-ux.md +++ b/plan/fase-5-mobile-ux.md @@ -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) **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) - 15 Vitest unit (was 11, +4 generateId) - 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). - [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.