From 565b35154f09fd4e72500b662fe7627184082813 Mon Sep 17 00:00:00 2001 From: Alexander Bocken Date: Wed, 8 Apr 2026 09:13:50 +0200 Subject: [PATCH] feat: group icons by category in edit modal, reorder categories, mobile padding --- src/routes/cospend/list/+page.svelte | 73 ++++++++++++++++++++++------ 1 file changed, 57 insertions(+), 16 deletions(-) diff --git a/src/routes/cospend/list/+page.svelte b/src/routes/cospend/list/+page.svelte index 09a5b96..b588ba8 100644 --- a/src/routes/cospend/list/+page.svelte +++ b/src/routes/cospend/list/+page.svelte @@ -8,6 +8,7 @@ import { slide } from 'svelte/transition'; import { SvelteSet } from 'svelte/reactivity'; import catalogData from '$lib/data/shoppingCatalog.json'; + import iconCategoriesData from '$lib/data/shoppingIconCategories.json'; import { Share2, X, Copy, Check } from '@lucide/svelte'; @@ -167,11 +168,27 @@ let editSaving = $state(false); const allIcons = Object.entries(/** @type {Record} */ (catalogData)); + const iconCategories = /** @type {Record} */ (iconCategoriesData); - let filteredIcons = $derived( + /** Icons grouped by category, ordered by SHOPPING_CATEGORIES */ + const iconsByCategory = (() => { + /** @type {Map} */ + const groups = new Map(); + for (const cat of SHOPPING_CATEGORIES) groups.set(cat, []); + for (const [name, file] of allIcons) { + const cat = iconCategories[name] || 'Sonstiges'; + if (!groups.has(cat)) groups.set(cat, []); + groups.get(cat)?.push([name, file]); + } + return [...groups.entries()].filter(([, icons]) => icons.length > 0); + })(); + + let filteredIconGroups = $derived( iconSearch.trim() - ? allIcons.filter(([name]) => name.includes(iconSearch.toLowerCase())) - : allIcons + ? iconsByCategory + .map(([cat, icons]) => /** @type {[string, [string,string][]]} */ ([cat, icons.filter(([name]) => name.includes(iconSearch.toLowerCase()))])) + .filter(([, icons]) => icons.length > 0) + : iconsByCategory ); /** @param {import('$lib/js/shoppingSync.svelte').ShoppingItem} item */ @@ -446,15 +463,23 @@
- {#each filteredIcons as [name, file]} - + {#each filteredIconGroups as [cat, icons]} + {@const meta = categoryMeta[cat] || categoryMeta['Sonstiges']} +
+ {cat} +
+ {#each icons as [name, file]} + + {/each} +
+
{/each}
@@ -891,14 +916,25 @@ } .icon-picker { - display: grid; - grid-template-columns: repeat(auto-fill, minmax(48px, 1fr)); - gap: 0.35rem; - max-height: 200px; + display: flex; + flex-direction: column; + gap: 0.5rem; + max-height: 250px; overflow-y: auto; margin-bottom: 1.25rem; padding: 0.25rem; } + .icon-group-label { + font-size: 0.65rem; + font-weight: 700; + text-transform: uppercase; + letter-spacing: 0.03em; + } + .icon-group-grid { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(42px, 1fr)); + gap: 0.3rem; + } .icon-option { aspect-ratio: 1; display: flex; @@ -1117,4 +1153,9 @@ z-index: 200; box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2); } + + @media (max-width: 500px) { + .edit-backdrop { padding: 0.5rem; } + .edit-modal { padding: 1rem 0.75rem; } + }