feat: store-based category sorting presets for shopping list
All checks were successful
CI / update (push) Successful in 3m48s
All checks were successful
CI / update (push) Successful in 3m48s
Add toggleable store presets (Coop Max-Bill Platz, Migros Seebach) that reorder categories to match the physical store layout. Selection persisted in localStorage.
This commit is contained in:
@@ -2,7 +2,7 @@
|
||||
import { onMount, onDestroy } from 'svelte';
|
||||
import { getShoppingSync } from '$lib/js/shoppingSync.svelte';
|
||||
import { SHOPPING_CATEGORIES } from '$lib/data/shoppingCategoryItems';
|
||||
import { Plus, ListX, Apple, Beef, Milk, Croissant, Wheat, FlameKindling, GlassWater, Candy, Snowflake, SprayCan, Sparkles, Package, Search } from '@lucide/svelte';
|
||||
import { Plus, ListX, Apple, Beef, Milk, Croissant, Wheat, FlameKindling, GlassWater, Candy, Snowflake, SprayCan, Sparkles, Package, Search, Store } from '@lucide/svelte';
|
||||
import SyncIndicator from '$lib/components/fitness/SyncIndicator.svelte';
|
||||
import { flip } from 'svelte/animate';
|
||||
import { slide } from 'svelte/transition';
|
||||
@@ -34,6 +34,31 @@
|
||||
'Sonstiges': { icon: Package, color: 'var(--nord4)' },
|
||||
};
|
||||
|
||||
/** @type {Record<string, string[]>} */
|
||||
const STORE_PRESETS = {
|
||||
'Coop Max-Bill Platz': [
|
||||
'Haushalt', 'Hygiene & Körperpflege', 'Gewürze & Saucen', 'Süßes & Snacks',
|
||||
'Getränke', 'Pasta, Reis & Getreide', 'Brot & Backwaren', 'Milchprodukte',
|
||||
'Obst & Gemüse', 'Fleisch & Fisch', 'Tiefkühl', 'Sonstiges',
|
||||
],
|
||||
'Migros Seebach': [
|
||||
'Obst & Gemüse', 'Fleisch & Fisch', 'Milchprodukte', 'Süßes & Snacks',
|
||||
'Getränke', 'Brot & Backwaren', 'Gewürze & Saucen', 'Haushalt',
|
||||
'Hygiene & Körperpflege', 'Tiefkühl', 'Pasta, Reis & Getreide', 'Sonstiges',
|
||||
],
|
||||
};
|
||||
const STORE_NAMES = Object.keys(STORE_PRESETS);
|
||||
|
||||
let selectedStore = $state(
|
||||
(typeof localStorage !== 'undefined' && localStorage.getItem('shopping-store')) || STORE_NAMES[0]
|
||||
);
|
||||
let categoryOrder = $derived(STORE_PRESETS[selectedStore] || STORE_PRESETS[STORE_NAMES[0]]);
|
||||
|
||||
function setStore(name) {
|
||||
selectedStore = name;
|
||||
localStorage.setItem('shopping-store', name);
|
||||
}
|
||||
|
||||
let newItemName = $state('');
|
||||
/** @type {HTMLInputElement | null} */
|
||||
let inputEl = $state(null);
|
||||
@@ -95,12 +120,12 @@
|
||||
items.sort((a, b) => Number(a.checked) - Number(b.checked));
|
||||
}
|
||||
|
||||
const ordered = [...SHOPPING_CATEGORIES]
|
||||
const ordered = categoryOrder
|
||||
.filter(cat => groups.has(cat))
|
||||
.map(cat => ({ category: cat, items: groups.get(cat) }));
|
||||
|
||||
for (const [cat, items] of groups) {
|
||||
if (!SHOPPING_CATEGORIES.includes(/** @type {any} */ (cat))) {
|
||||
if (!categoryOrder.includes(cat)) {
|
||||
ordered.push({ category: cat, items });
|
||||
}
|
||||
}
|
||||
@@ -354,6 +379,16 @@
|
||||
{#if totalCount > 0}
|
||||
<p class="subtitle">{checkedCount} / {totalCount} erledigt</p>
|
||||
{/if}
|
||||
<div class="store-picker">
|
||||
<Store size={13} />
|
||||
{#each STORE_NAMES as name}
|
||||
<button
|
||||
class="store-btn"
|
||||
class:active={selectedStore === name}
|
||||
onclick={() => setStore(name)}
|
||||
>{name}</button>
|
||||
{/each}
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<div class="add-bar">
|
||||
@@ -599,6 +634,33 @@
|
||||
color: var(--color-text-secondary);
|
||||
font-size: 0.85rem;
|
||||
}
|
||||
.store-picker {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 0.35rem;
|
||||
margin-top: 0.5rem;
|
||||
color: var(--color-text-secondary);
|
||||
}
|
||||
.store-btn {
|
||||
padding: 0.2rem 0.5rem;
|
||||
border-radius: 100px;
|
||||
border: 1px solid var(--color-border);
|
||||
background: transparent;
|
||||
color: var(--color-text-secondary);
|
||||
font-size: 0.7rem;
|
||||
cursor: pointer;
|
||||
transition: all 150ms;
|
||||
}
|
||||
.store-btn:hover {
|
||||
border-color: var(--nord10);
|
||||
color: var(--color-text-primary);
|
||||
}
|
||||
.store-btn.active {
|
||||
background: var(--nord10);
|
||||
color: white;
|
||||
border-color: var(--nord10);
|
||||
}
|
||||
|
||||
/* Add bar */
|
||||
.add-bar {
|
||||
|
||||
Reference in New Issue
Block a user