diff options
| author | Martin Kagamino Lehoux <martin@lehoux.net> | 2026-07-29 10:31:36 +0200 |
|---|---|---|
| committer | Martin Kagamino Lehoux <martin@lehoux.net> | 2026-07-29 10:31:36 +0200 |
| commit | 684d3c954e3577a6488101bf5ee85e36439fd53c (patch) | |
| tree | e9404b8eea57e811faaa9821675376f309d649e9 /src/routes/catalog/+page.svelte | |
| parent | 94212274cecf4da5f94b246a7ac9ab87077fb77f (diff) | |
feat: multi-select and bulk-update category from catalog
Diffstat (limited to 'src/routes/catalog/+page.svelte')
| -rw-r--r-- | src/routes/catalog/+page.svelte | 97 |
1 files changed, 97 insertions, 0 deletions
diff --git a/src/routes/catalog/+page.svelte b/src/routes/catalog/+page.svelte index 7d3ebbe..2079d12 100644 --- a/src/routes/catalog/+page.svelte +++ b/src/routes/catalog/+page.svelte @@ -1,9 +1,16 @@ <script lang="ts"> import { enhance } from '$app/forms'; + import { SvelteSet } from 'svelte/reactivity'; let { data, form } = $props(); let catalogItems = $derived(data?.items ?? []); + let selectedIds = new SvelteSet<number>(); + + function toggleId(id: number) { + if (selectedIds.has(id)) selectedIds.delete(id); + else selectedIds.add(id); + } function groupByCategory(items: typeof catalogItems) { const groups: Record<string, typeof catalogItems> = {}; @@ -15,7 +22,43 @@ } </script> +{#if catalogItems.length > 0} + <div class="bulk-bar"> + <form + method="POST" + action="?/bulkUpdateCategory" + use:enhance={() => { + return async ({ update }) => { + await update({ reset: false }); + selectedIds.clear(); + }; + }} + > + {#each Array.from(selectedIds) as id (id)} + <input type="hidden" name="ids" value={id} /> + {/each} + <select name="category_id" class="form-select"> + <option value={-1}>Non catégorisé</option> + {#each data.categories as cat (cat.id)} + <option value={cat.id}>{cat.name}</option> + {/each} + </select> + <button + class="btn-primary" + type="submit" + disabled={selectedIds.size === 0} + > + Mettre à jour ({selectedIds.size}) + </button> + </form> + </div> +{/if} + <main> + {#if form?.error} + <p class="error">{form.error}</p> + {/if} + {#if catalogItems.length === 0} <p class="empty">Aucun article</p> {:else} @@ -25,6 +68,12 @@ <ul class="item-list"> {#each items as item (item.id)} <li class="item-row item-row--fixed"> + <input + type="checkbox" + class="item-check" + checked={selectedIds.has(item.id)} + onchange={() => toggleId(item.id)} + /> <button class="item-btn item-btn--grow" name="id" @@ -60,12 +109,60 @@ </main> <style> + .bulk-bar { + display: flex; + gap: 0.5rem; + padding: 0.5rem 1rem; + position: sticky; + top: var(--nav-height); + background: var(--bg); + border-bottom: 1px solid var(--border); + z-index: 10; + } + + .bulk-bar form { + display: flex; + gap: 0.5rem; + align-items: center; + width: 100%; + } + + .bulk-bar .form-select { + flex: 1; + min-width: 0; + } + + .bulk-bar .btn-primary { + padding: 0.75rem 1rem; + align-self: center; + white-space: nowrap; + } + + .bulk-bar .btn-primary:disabled { + opacity: 0.5; + cursor: not-allowed; + transform: none; + box-shadow: none; + } + + .item-check { + width: 1.25rem; + height: 1.25rem; + accent-color: var(--accent); + cursor: pointer; + flex-shrink: 0; + } + .checked { text-decoration: line-through; color: var(--text-secondary); font-weight: 400; } + .error { + margin-bottom: 1rem; + } + .empty { margin-top: 1rem; padding: 2rem; |
