It's Day 2 of the #12DaysOfSvelteApps! π
Yesterday, we managed the cost of the holidays with the Budget Tracker. Today, we're managing the chaos of the gifts themselves.
The App: Purchase Tracker
The Purchase Tracker is your digital shopping assistant. While generic note-taking apps are fine, they lack structure. This app treats every potential gift as an "Item" with properties like category, default currency, and unit measurements.
π Try the App Live
π» View the Code
The "Use Case": The Anti-Spoiler List π€«
We all have that one family member who snoops on the shared "To-Do" list or the fridge notepad.
Use the Purchase Tracker to create a "Gifts" category.
- Name: The person you are buying for (or the item code name).
- Description: The actual item detail (e.g., "Size M, Blue, from that one vintage store").
- Privacy: Since the app functions essentially as a local database, your surprise plans remain on your device (or secured in your account).
Tech Spotlight: Optimistic UI β‘
One of the best UX patterns we implemented here is Optimistic UI. When you create a new Item, we don't want the user to wait for the server to say "Okay." We want it to appear instantly.
In our Svelte component:
function handleLocalCreateItem(e: SubmitEvent) {
e.preventDefault();
// ... extract form data ...
// 1. Update the local state IMMEDIATELY
const newItem = addItem(name, category, description, unit, currency);
// The UI updates instantly because 'items' is a reactive Svelte state
// items.current = [...oldItems, newItem];
toast.success('Item created successfully');
}
If the user is logged in, we perform the server request in the background. If it fails, we roll back. But 99% of the time, the user experiences zero latency.
Dealing with Complex Lists
We used shadcn-svelte components to quickly scaffold a beautiful Table view.
<Table>
<TableHeader>
<TableRow>
<TableHead>Name</TableHead>
<TableHead>Category</TableHead>
<!-- ... -->
</TableRow>
</TableHeader>
<TableBody>
{#each items.current as item (item.id)}
<TableRow onclick={() => navigateToPurchases(item.id)}>
<TableCell>{item.name}</TableCell>
<TableCell>
<!-- Category Icon + Name lookup -->
{categories.find(c => c.id === item.category)?.name}
</TableCell>
</TableRow>
{/each}
</TableBody>
</Table>
Using Svelte's {#each key} block (the (item.id) part) is crucial here. It ensures that when we delete or reorder items, the DOM updates efficiently without weird rendering artifactsβa must-have for any list-heavy application.
Next Up
Now that we have a Budget and a Shopping List, we need to actually get things done. Join us tomorrow for Day 3.
Top comments (1)
I like how you tied mindset work into the scents because that combo really does shift the vibe. Iβve found incense for good energy makes it easier to settle into visualization without my thoughts running off. Your take on weaving these habits into daily routines fits the way Nothing But Scents lays out their options, so readers can play around with what actually clicks for them.
Some comments may only be visible to logged-in visitors. Sign in to view all comments.