[Svelte Series 12] Building a Mini Dashboard: Integrating All Key Features

한국어 버전

Time to combine every pattern we've covered into a midterm learner dashboard.

Quick recap

  • What we're building: the /dashboard screen where a sidebar, content cards, and bottom log stay visible together, plus the CRUD flow behind each task card.
  • Why it matters: the mini dashboard is a checkpoint showing how layout, state, forms, and animations interlock.
  • Watch out for: lock in the slot-based layout first and double-check depends/invalidate keys so every panel refreshes in sync.

Key terms

  1. Dashboard: a single screen that shows multiple metric cards and forms at once so the team sees status immediately.
  2. Slot layout: a layout that reserves regions like sidebar, main, and bottom log, then swaps only the content inside each slot.

Core ideas

A dashboard is a status board. Slot layouts keep regions fixed so you can drop in new pages without rewriting the shell. Stores and load supply the initial data. Form actions plus optimistic UI reflect user input immediately. Transitions and spring motion smooth out state changes so attention stays on the content. Consider this the series midterm before we dive into auth, files, and live features.

Code examples

The root layout, page data, card list, and form work together.

<!-- src/routes/(app)/+layout.svelte -->
<AppShell>
  <svelte:fragment slot="sidebar">
    <SubjectSidebar />
  </svelte:fragment>

  <slot />

  <svelte:fragment slot="bottom-panel">
    <ActivityLog />
  </svelte:fragment>
</AppShell>
// src/routes/(app)/dashboard/+page.server.ts
export const load = async ({ fetch, depends }) => {
  depends('data:tasks');
  const [subjects, tasks] = await Promise.all([
    fetch('/api/subjects').then((r) => r.json()),
    fetch('/api/tasks').then((r) => r.json())
  ]);
  return { subjects, tasks };
};
<!-- Card list -->
<section class="grid" animate:flip>
  {#if filtered.length === 0}
    <EmptyState in:fade={{ duration: 120 }} />
  {:else}
    {#each filtered as task (task.id)}
      <TaskCard {task} transition:scale={{ duration: 120 }} on:toggle />
    {/each}
  {/if}
</section>

<form method="POST" action="?/create"
  use:enhance={({ result }) => {
    if (result.type === 'success') invalidate('data:tasks');
  }}>
  <input name="title" placeholder="New task" required />
  <select name="subjectId">
    {#each subjects as subject}
      <option value={subject.id}>{subject.name}</option>
    {/each}
  </select>
  <button>Add</button>
</form>

Toggle cards with the optimistic pattern from part 11: update state immediately, hold a snapshot, and roll back on failure.

http://localhost:5173/dashboard
DEV

UI Preview

Filters, cards, and logs at a glance

Filtering exam tasks animates the card grid, and the bottom Activity Log records actions in real time.

slot layoutstate sync

Sidebar

Subject filters

Injected via the sidebar slot.

Cards

TaskCard grid

Flip animation plus optimistic toggles.

Log

ActivityLog

Writes each action immediately.

Why it matters

Real products juggle multiple features. Building the dashboard yourself shows how layout, shared state, forms, and animation depend on one another. The finished screen can double as a club progress report or school project demo.

Practice tasks

  • Follow along: compose AppShell and /dashboard so the sidebar, body, and log render together.
  • Extend it: add at least one micro-interaction such as a spring motion or ActivityLog variant.
  • Debugging: if invalidate fails, confirm the key matches the depends call.
  • Done when: filter → toggle → create flows run smoothly without visual glitches.

Wrap-up

This dashboard bundles every pattern we've built so far. With this flow polished, you're ready to stack authentication, files, realtime, and deployment topics over parts 13–20.

💬 댓글

이 글에 대한 의견을 남겨주세요