diff options
| author | Martin Kagamino Lehoux <martin@lehoux.net> | 2026-07-28 19:30:07 +0200 |
|---|---|---|
| committer | Martin Kagamino Lehoux <martin@lehoux.net> | 2026-07-28 19:31:13 +0200 |
| commit | 1e720925e2ef690d455927c2f9e802571304982a (patch) | |
| tree | b5bcd4dd6a49115bdaca904832cb6bd8e859a35a | |
| parent | 0d100b83f8ba818c2f32663f415649db03534548 (diff) | |
fix: sticky form and navbar layout with consistent nav-height
| -rw-r--r-- | README.md | 3 | ||||
| -rw-r--r-- | src/app.css | 5 | ||||
| -rw-r--r-- | src/lib/components/Nav.svelte | 4 | ||||
| -rw-r--r-- | src/routes/+layout.svelte | 2 | ||||
| -rw-r--r-- | src/routes/+page.svelte | 89 | ||||
| -rw-r--r-- | src/routes/catalog/+page.svelte | 82 | ||||
| -rw-r--r-- | src/routes/categories/+page.svelte | 88 | ||||
| -rw-r--r-- | src/routes/grocery/[id]/+page.svelte | 216 |
8 files changed, 252 insertions, 237 deletions
@@ -55,7 +55,6 @@ efficient shopping walk. ## TODO -- [ ] Weird form stickyness that collapse the gap with the navbar - [ ] PWA - [ ] Live updates from server @@ -63,5 +62,5 @@ efficient shopping walk. ```bash docker build -t home-sveltekit . -docker save home-sveltekit | pv | ssh ubuntu@feed.kagamino.dev "sudo docker load" +docker save home-sveltekit | gzip | pv | ssh ubuntu@feed.kagamino.dev "gunzip | sudo docker load" ``` diff --git a/src/app.css b/src/app.css index 4982369..90ee084 100644 --- a/src/app.css +++ b/src/app.css @@ -22,6 +22,7 @@ --white: oklch(1 0 0); --bg: oklch(0.97 0.006 70); + --nav-height: 3rem; --surface: var(--white); --surface-hover: oklch(from var(--accent) 0.99 0.008 h); --border: oklch(0.91 0.006 70); @@ -49,6 +50,10 @@ body { -moz-osx-font-smoothing: grayscale; } +main { + padding: 0 1rem; +} + h1 { font-size: 1.875rem; font-weight: 700; diff --git a/src/lib/components/Nav.svelte b/src/lib/components/Nav.svelte index 5e8fa30..8f2e5c2 100644 --- a/src/lib/components/Nav.svelte +++ b/src/lib/components/Nav.svelte @@ -16,12 +16,14 @@ .navbar { display: flex; gap: 0.25rem; - padding: 0.75rem 0; border-bottom: 1px solid var(--border); position: sticky; top: 0; background: var(--bg); z-index: 20; + height: var(--nav-height); + align-items: center; + padding: 0 1rem; } .navbar a { diff --git a/src/routes/+layout.svelte b/src/routes/+layout.svelte index 9dc0244..a168c65 100644 --- a/src/routes/+layout.svelte +++ b/src/routes/+layout.svelte @@ -18,6 +18,6 @@ .app { max-width: 36rem; margin: 0 auto; - padding: 0 1rem 2rem; + padding-bottom: 2rem; } </style> diff --git a/src/routes/+page.svelte b/src/routes/+page.svelte index 25985f1..e4f78c5 100644 --- a/src/routes/+page.svelte +++ b/src/routes/+page.svelte @@ -96,57 +96,60 @@ > </div> -{#if addError || form?.error} - <p class="error">{addError || form?.error}</p> -{/if} +<main> + {#if addError || form?.error} + <p class="error">{addError || form?.error}</p> + {/if} -{#if localItems.length === 0} - <p class="empty">Rien à acheter</p> -{:else} - <form method="POST" action="?/toggle" use:enhance> - {#each groupByCategory(localItems) as [cat, items] (cat)} - <h3 class="category-name">{cat}</h3> - <ul class="item-list"> - {#each items as item (item.id)} - <li class="item-row item-row--fixed"> - <button - class="item-btn item-btn--grow" - name="id" - value={item.id} - type="submit" - aria-pressed={item.checked} - > - <span class="item-text"> - {item.name} - {#if item.bestRef} - <span class="best-ref" - >{item.bestRef.reference} - {#if item.bestRef.price && item.bestRef.unit} - {item.bestRef.price.toFixed(2)} {item.bestRef.unit} - {/if} - {#if item.bestRef.qualityScore != null} - ({item.bestRef.qualityScore}/100) - {/if} - </span> - {/if} - </span> - </button> - <a class="ref-link" href="/grocery/{item.id}?from=/">→</a> - </li> - {/each} - </ul> - {/each} - </form> -{/if} + {#if localItems.length === 0} + <p class="empty">Rien à acheter</p> + {:else} + <form method="POST" action="?/toggle" use:enhance> + {#each groupByCategory(localItems) as [cat, items] (cat)} + <h3 class="category-name">{cat}</h3> + <ul class="item-list"> + {#each items as item (item.id)} + <li class="item-row item-row--fixed"> + <button + class="item-btn item-btn--grow" + name="id" + value={item.id} + type="submit" + aria-pressed={item.checked} + > + <span class="item-text"> + {item.name} + {#if item.bestRef} + <span class="best-ref" + >{item.bestRef.reference} + {#if item.bestRef.price && item.bestRef.unit} + {item.bestRef.price.toFixed(2)} {item.bestRef.unit} + {/if} + {#if item.bestRef.qualityScore != null} + ({item.bestRef.qualityScore}/100) + {/if} + </span> + {/if} + </span> + </button> + <a class="ref-link" href="/grocery/{item.id}?from=/">→</a> + </li> + {/each} + </ul> + {/each} + </form> + {/if} +</main> <style> .add-bar { display: flex; gap: 0.5rem; - padding: 0.75rem 0; + padding: 0.5rem 1rem; position: sticky; - top: 3.1rem; + top: var(--nav-height); background: var(--bg); + border-bottom: 1px solid var(--border); z-index: 10; } diff --git a/src/routes/catalog/+page.svelte b/src/routes/catalog/+page.svelte index 469faa1..525c2ed 100644 --- a/src/routes/catalog/+page.svelte +++ b/src/routes/catalog/+page.svelte @@ -15,46 +15,48 @@ } </script> -{#if catalogItems.length === 0} - <p class="empty">Aucun article</p> -{:else} - <form method="POST" action="?/toggle" use:enhance> - {#each groupByCategory(catalogItems) as [cat, items] (cat)} - <h3 class="category-name">{cat}</h3> - <ul class="item-list"> - {#each items as item (item.id)} - <li class="item-row item-row--fixed"> - <button - class="item-btn item-btn--grow" - name="id" - value={item.id} - type="submit" - aria-pressed={item.checked} - > - <span class="item-text"> - <span class:checked={item.checked}>{item.name}</span> - {#if item.bestRef} - <span class="best-ref" - >{item.bestRef.reference} - {#if item.bestRef.price && item.bestRef.unit} - {item.bestRef.price.toFixed(2)} {item.bestRef.unit} - {/if} - {#if item.bestRef.qualityScore != null} - ({item.bestRef.qualityScore}/100) - {/if} - </span> - {/if} - </span> - </button> - <a class="ref-link" href="/grocery/{item.id}?from=/catalog" - >→</a - > - </li> - {/each} - </ul> - {/each} - </form> -{/if} +<main> + {#if catalogItems.length === 0} + <p class="empty">Aucun article</p> + {:else} + <form method="POST" action="?/toggle" use:enhance> + {#each groupByCategory(catalogItems) as [cat, items] (cat)} + <h3 class="category-name">{cat}</h3> + <ul class="item-list"> + {#each items as item (item.id)} + <li class="item-row item-row--fixed"> + <button + class="item-btn item-btn--grow" + name="id" + value={item.id} + type="submit" + aria-pressed={item.checked} + > + <span class="item-text"> + <span class:checked={item.checked}>{item.name}</span> + {#if item.bestRef} + <span class="best-ref" + >{item.bestRef.reference} + {#if item.bestRef.price && item.bestRef.unit} + {item.bestRef.price.toFixed(2)} {item.bestRef.unit} + {/if} + {#if item.bestRef.qualityScore != null} + ({item.bestRef.qualityScore}/100) + {/if} + </span> + {/if} + </span> + </button> + <a class="ref-link" href="/grocery/{item.id}?from=/catalog" + >→</a + > + </li> + {/each} + </ul> + {/each} + </form> + {/if} +</main> <style> .checked { diff --git a/src/routes/categories/+page.svelte b/src/routes/categories/+page.svelte index 41b40c5..1060eaa 100644 --- a/src/routes/categories/+page.svelte +++ b/src/routes/categories/+page.svelte @@ -5,52 +5,54 @@ let name = $state(''); </script> -<form - class="form-card form-card--compact" - method="POST" - action="?/add" - use:enhance -> - <label> - <span class="form-label">Nouvelle catégorie</span> - <input - class="form-input" - type="text" - name="name" - bind:value={name} - placeholder="ex. Boissons" - autocomplete="off" - /> - </label> - <button class="btn-primary" type="submit">Ajouter</button> -</form> +<main> + <form + class="form-card form-card--compact" + method="POST" + action="?/add" + use:enhance + > + <label> + <span class="form-label">Nouvelle catégorie</span> + <input + class="form-input" + type="text" + name="name" + bind:value={name} + placeholder="ex. Boissons" + autocomplete="off" + /> + </label> + <button class="btn-primary" type="submit">Ajouter</button> + </form> -{#if form?.error} - <p class="error">{form.error}</p> -{/if} + {#if form?.error} + <p class="error">{form.error}</p> + {/if} -<form method="POST" action="?/delete" use:enhance> - <ul class="item-list"> - {#each data?.categories ?? [] as cat (cat.id)} - <li class="item-row item-row--card"> - <span class="cat-name">{cat.name}</span> - <button - class="btn-ghost" - name="id" - value={cat.id} - type="submit" - aria-label="Supprimer" - > - × - </button> - </li> - {/each} - </ul> -</form> + <form method="POST" action="?/delete" use:enhance> + <ul class="item-list"> + {#each data?.categories ?? [] as cat (cat.id)} + <li class="item-row item-row--card"> + <span class="cat-name">{cat.name}</span> + <button + class="btn-ghost" + name="id" + value={cat.id} + type="submit" + aria-label="Supprimer" + > + × + </button> + </li> + {/each} + </ul> + </form> -{#if (data?.categories?.length ?? 0) === 0} - <p class="empty">Aucune catégorie</p> -{/if} + {#if (data?.categories?.length ?? 0) === 0} + <p class="empty">Aucune catégorie</p> + {/if} +</main> <style> .cat-name { diff --git a/src/routes/grocery/[id]/+page.svelte b/src/routes/grocery/[id]/+page.svelte index 6588ec0..1aa28b4 100644 --- a/src/routes/grocery/[id]/+page.svelte +++ b/src/routes/grocery/[id]/+page.svelte @@ -19,129 +19,131 @@ let qualityScore = $state(''); </script> -<form - class="form-card" - method="POST" - action="?/update" - use:enhance={() => { - return async ({ update }) => { - await update({ reset: false }); - }; - }} -> - <label> - <span class="form-label">Nom</span> - <input class="form-input" type="text" name="name" bind:value={name} /> - </label> - <label> - <span class="form-label">Catégorie</span> - <select class="form-select" name="category_id" bind:value={categoryId}> - <option value={-1}>—</option> - {#each data.categories as cat (cat.id)} - <option value={cat.id}>{cat.name}</option> - {/each} - </select> - </label> - <button class="btn-primary" type="submit" - >{saved ? '✓ Enregistré' : 'Enregistrer'}</button +<main> + <form + class="form-card" + method="POST" + action="?/update" + use:enhance={() => { + return async ({ update }) => { + await update({ reset: false }); + }; + }} > -</form> - -<hr /> - -<h2>Références</h2> - -<form class="form-card" method="POST" action="?/add" use:enhance> - <label> - <span class="form-label">Référence</span> - <input - class="form-input" - type="text" - name="reference" - bind:value={reference} - placeholder="ex. Carte Noire" - autocomplete="off" - /> - </label> - <div class="ref-row"> <label> - <span class="form-label">Prix</span> - <input - class="form-input" - type="number" - name="price" - bind:value={price} - placeholder="5.99" - step="0.01" - /> + <span class="form-label">Nom</span> + <input class="form-input" type="text" name="name" bind:value={name} /> </label> <label> - <span class="form-label">Unité</span> - <select class="form-select" name="unit" bind:value={unit}> - <option value="€/kg">€/kg</option> - <option value="€/L">€/L</option> - <option value="€/u">€/u</option> + <span class="form-label">Catégorie</span> + <select class="form-select" name="category_id" bind:value={categoryId}> + <option value={-1}>—</option> + {#each data.categories as cat (cat.id)} + <option value={cat.id}>{cat.name}</option> + {/each} </select> </label> + <button class="btn-primary" type="submit" + >{saved ? '✓ Enregistré' : 'Enregistrer'}</button + > + </form> + + <hr /> + + <h2>Références</h2> + + <form class="form-card" method="POST" action="?/add" use:enhance> <label> - <span class="form-label">Note</span> + <span class="form-label">Référence</span> <input class="form-input" - type="number" - name="quality_score" - bind:value={qualityScore} - placeholder="0–100" - min="0" - max="100" + type="text" + name="reference" + bind:value={reference} + placeholder="ex. Carte Noire" + autocomplete="off" /> </label> - </div> - <button class="btn-primary" type="submit">Ajouter une référence</button> -</form> + <div class="ref-row"> + <label> + <span class="form-label">Prix</span> + <input + class="form-input" + type="number" + name="price" + bind:value={price} + placeholder="5.99" + step="0.01" + /> + </label> + <label> + <span class="form-label">Unité</span> + <select class="form-select" name="unit" bind:value={unit}> + <option value="€/kg">€/kg</option> + <option value="€/L">€/L</option> + <option value="€/u">€/u</option> + </select> + </label> + <label> + <span class="form-label">Note</span> + <input + class="form-input" + type="number" + name="quality_score" + bind:value={qualityScore} + placeholder="0–100" + min="0" + max="100" + /> + </label> + </div> + <button class="btn-primary" type="submit">Ajouter une référence</button> + </form> -{#if form?.error} - <p class="error">{form.error}</p> -{/if} + {#if form?.error} + <p class="error">{form.error}</p> + {/if} -<form method="POST" action="?/delete" use:enhance> - <ul class="item-list item-list--wide"> - {#each data?.references ?? [] as ref (ref.id)} - <li class="item-row item-row--ref"> - <div class="ref-info"> - <strong>{ref.reference}</strong> - {#if ref.price} - <span class="ref-detail" - >{ref.price.toFixed(2)}{ref.unit ? ` ${ref.unit}` : ''}</span - > - {/if} - {#if ref.qualityScore != null} - <span class="ref-detail">Note : {ref.qualityScore}/100</span> - {/if} - </div> - <button - class="btn-ghost" - name="id" - value={ref.id} - type="submit" - aria-label="Supprimer" - > - × - </button> - </li> - {/each} - </ul> -</form> + <form method="POST" action="?/delete" use:enhance> + <ul class="item-list item-list--wide"> + {#each data?.references ?? [] as ref (ref.id)} + <li class="item-row item-row--ref"> + <div class="ref-info"> + <strong>{ref.reference}</strong> + {#if ref.price} + <span class="ref-detail" + >{ref.price.toFixed(2)}{ref.unit ? ` ${ref.unit}` : ''}</span + > + {/if} + {#if ref.qualityScore != null} + <span class="ref-detail">Note : {ref.qualityScore}/100</span> + {/if} + </div> + <button + class="btn-ghost" + name="id" + value={ref.id} + type="submit" + aria-label="Supprimer" + > + × + </button> + </li> + {/each} + </ul> + </form> -{#if (data?.references?.length ?? 0) === 0} - <p class="empty">Aucune référence</p> -{/if} + {#if (data?.references?.length ?? 0) === 0} + <p class="empty">Aucune référence</p> + {/if} -<form method="POST" action="?/deleteItem" use:enhance> - <input type="hidden" name="from" value={data.from} /> - <button type="submit" class="delete-item-btn">Supprimer l'article</button> -</form> + <form method="POST" action="?/deleteItem" use:enhance> + <input type="hidden" name="from" value={data.from} /> + <button type="submit" class="delete-item-btn">Supprimer l'article</button> + </form> -<a href={data.from} class="back-link">← Retour</a> + <a href={data.from} class="back-link">← Retour</a> +</main> <style> .ref-row { |
