feat(fase-5.8): /lists big-button create — match /notes pattern
Remove the sticky bottom create input from /lists. The masthead now hosts
a primary "New list" button next to the Trash icon, styled identically to
the "New note" button on /notes. Click → createList with an empty name →
goto /lists/[id], where a prominent editable title input (above To buy /
Checked) autosaves on blur / input with a 500 ms debounce.
Changes
apps/web/src/routes/(app)/lists/+page.svelte
- remove `newListName`, `nameInput`, `handleKeydown`
- remove the absolute-positioned sticky bottom block
- handleCreate now creates with name = '' and navigates to the detail
- actions snippet gains the primary New list button; Trash button
demoted to ghost icon
apps/web/src/routes/(app)/lists/[id]/+page.svelte
- new listName / scheduleNameSave / flushNameSave state (mirrors the
/notes editor pattern)
- big editable title <input> at top of content, autosaves on blur
via renameList
- contextual header h1 trimmed to a secondary caption-size preview
on mobile (so the user still sees the list name at the top)
- flushNameSave on component destroy so unsaved renames commit
apps/web/messages/{en,es}.json: lists_new_list = "New list"/"Nueva lista"
Tests
apps/web/tests/e2e/lists.test.ts: createList helper now clicks the
button, fills the title input, blurs, waits for autosave, and goes
back to /lists to present the same "list-is-on-the-overview" state
that C-11 / C-12 expect. C-07 picks up the reload check.
apps/web/tests/e2e/session.test.ts: S-03 mirrors the new flow for its
fresh-list setup.
Verification
just test-e2e → 40 passed, 2 skipped (swipe-delete .skip remains).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -37,14 +37,25 @@ function cardActionsButton(page: Page, name: string) {
|
||||
|
||||
async function gotoListsClean(page: Page) {
|
||||
await page.goto('/lists');
|
||||
await expect(page.getByPlaceholder(PLACEHOLDER_NEW_LIST)).toBeVisible({ timeout: 15_000 });
|
||||
// The masthead "New list" button is the anchor now (replaces the sticky input).
|
||||
await expect(
|
||||
page.getByRole('button', { name: /new list|nueva lista/i })
|
||||
).toBeVisible({ timeout: 15_000 });
|
||||
}
|
||||
|
||||
async function createList(page: Page, name: string) {
|
||||
const input = page.getByPlaceholder(PLACEHOLDER_NEW_LIST);
|
||||
await input.fill(name);
|
||||
await input.press('Enter');
|
||||
await expect(listHeading(page, name)).toBeVisible({ timeout: 5_000 });
|
||||
await page.getByRole('button', { name: /new list|nueva lista/i }).click();
|
||||
// Lands on /lists/[id]; the editable title input carries the placeholder.
|
||||
await expect(page).toHaveURL(/\/lists\/[0-9a-f-]+$/, { timeout: 10_000 });
|
||||
const titleInput = page.getByPlaceholder(PLACEHOLDER_NEW_LIST);
|
||||
await expect(titleInput).toBeVisible({ timeout: 10_000 });
|
||||
await titleInput.fill(name);
|
||||
// Blur + wait for the 500 ms autosave debounce + buffer.
|
||||
await titleInput.blur();
|
||||
await page.waitForTimeout(900);
|
||||
// Navigate back to /lists to give callers a consistent starting state.
|
||||
await page.goto('/lists');
|
||||
await expect(listHeading(page, name)).toBeVisible({ timeout: 10_000 });
|
||||
}
|
||||
|
||||
test.describe('Shopping lists — member (Borja)', () => {
|
||||
|
||||
@@ -59,20 +59,20 @@ test.describe('Shopping session — full-screen mode', () => {
|
||||
page
|
||||
}) => {
|
||||
// Need a fresh list so completing it doesn't affect shared seed state.
|
||||
// Create via the lists overview.
|
||||
// Use the new big-button create flow: masthead "New list" → lands on
|
||||
// /lists/[id] → fill inline title → autosave → we're already on the
|
||||
// detail view, no need to navigate back.
|
||||
await page.goto('/lists');
|
||||
const listInput = page.getByPlaceholder(/weekly shop|compra semanal/i);
|
||||
await expect(listInput).toBeVisible({ timeout: 15_000 });
|
||||
await page
|
||||
.getByRole('button', { name: /new list|nueva lista/i })
|
||||
.click();
|
||||
await expect(page).toHaveURL(/\/lists\/[0-9a-f-]+$/, { timeout: 10_000 });
|
||||
const listName = `S-03-list-${Date.now()}`;
|
||||
await listInput.fill(listName);
|
||||
await listInput.press('Enter');
|
||||
// Wait for the new list's heading so we can click into it
|
||||
const heading = page.getByRole('heading', { name: new RegExp(`^${listName}$`) });
|
||||
await expect(heading).toBeVisible({ timeout: 5_000 });
|
||||
|
||||
// Navigate via the heading (linked to /lists/[id])
|
||||
await heading.click();
|
||||
await expect(page).toHaveURL(/\/lists\/[0-9a-f-]+$/, { timeout: 5_000 });
|
||||
const titleInput = page.getByPlaceholder(/weekly shop|compra semanal/i);
|
||||
await expect(titleInput).toBeVisible({ timeout: 10_000 });
|
||||
await titleInput.fill(listName);
|
||||
await titleInput.blur();
|
||||
await page.waitForTimeout(900); // autosave debounce
|
||||
|
||||
// Open session mode
|
||||
await page.getByTestId('start-session').click();
|
||||
|
||||
Reference in New Issue
Block a user