Welcome to your incomplete Svelte Task Dashboard! This project is intentionally about 50% complete to help you learn Svelte by filling in the gaps.
A task management dashboard built with SvelteKit that allows users to:
npm install
npm run dev
Then open http://localhost:5173 in your browser.
Complete the missing functionality to make the dashboard fully operational! The project will run even in its incomplete state, but features won't work properly until you fix them.
Work through these tasks in order (or jump around if you prefer!):
task prop exportpriorityColors object mapping (low/medium/high to colors)handleToggleComplete() functionhandleDelete() functiononMount function to load tasks from APIfilteredTaskshandleFilterChange() functionvalidateForm() function with validation ruleshandleSubmit() functiontotalTasks from the tasks arraycompletedTasks countcompletionPercentageaddTask() method in the task storedeleteTask() method in the task storetoggleComplete() method in the task storeupdateTask() method in the task storeloadTasks() async function with mock delaysaveTask() async functionremoveTask() async functiongetPriorityColor() function (wrong comparison operator)Transitions & Animations:
Custom Events (createEventDispatcher):
handleDelete() function to dispatch a 'delete' eventhandleEdit() function that dispatches an 'edit' eventhandleDelete() function to handle delete events from TaskCardon:delete event listener to TaskCard componenthandleTaskToggle() to update the storehandleTaskDelete() to update the storeon:delete event listener to TaskList componenthandleTaskEdit() for future editing functionalityDerived Stores:
completedTasksCount derived storecompletionPercentage derived storetasksByPriority derived store$totalTasksCount for total tasks$completedTasksCount for completed tasks$completionPercentage for completion rate$tasksByPriority for priority countsSlots (Default and Named Slots):
.card-header and .card-footer.modal-footer$$slots to conditionally render header/footerOnce you've completed all the tasks above, you should be able to:
Basic Functionality:
Advanced Features: 9. √ See smooth transitions when tasks are added, removed, or filtered (slide, fade animations) 10. √ Observe event flow from TaskCard → TaskList → Page → Store (check browser console) 11. √ See statistics auto-update via derived stores (no manual calculations in components) 12. √ Open the "About This App" modal and see custom slot content 13. √ Customize modal header and footer using named slots 14. √ (BONUS) See StatsCard wrapped in Card component with header/footer slots
Core Concepts (Original):
$: for computed valuesonMount for initializationbind:valueclass:directive{#each}Advanced Concepts (NEW):
transition:, in:, out: directives with built-in transitions (fade, slide, fly, scale)createEventDispatcher for component communication$ prefix to automatically subscribe to storesSvelte Reactivity: Use $: before statements to make them reactive
$: doubled = count * 2; // Updates whenever count changes
Store Updates: Use update() to modify store values
update((currentValue) => {
// Modify and return new value
return newValue;
});
Array Filtering: Use JavaScript's filter() method
const filtered = array.filter((item) => item.status === "todo");
Form Validation: Check string length and emptiness
if (!title || title.trim().length < 3) {
errors.title = "Title must be at least 3 characters";
}
Transitions: Import and use built-in transitions
<script>
import { fade, slide } from 'svelte/transition';
</script>
<div transition:fade={{ duration: 300 }}>Content</div>
Custom Events: Create and dispatch events
import { createEventDispatcher } from "svelte";
const dispatch = createEventDispatcher();
dispatch("eventName", { data: value });
Derived Stores: Create computed stores
import { derived } from "svelte/store";
export const doubled = derived(count, ($count) => $count * 2);
Slots: Use default and named slots
<!-- Parent -->
<Card>
<div slot="header">Header</div>
Main content
<div slot="footer">Footer</div>
</Card>
<!-- Card.svelte -->
<slot name="header"></slot>
<slot>Default content</slot>
<slot name="footer"></slot>
src/
├── routes/
│ ├── +page.svelte # Main dashboard page
│ └── +layout.svelte # App layout wrapper
├── lib/
│ ├── components/
│ │ ├── TaskCard.svelte # Individual task display
│ │ ├── TaskList.svelte # List of tasks
│ │ ├── StatsCard.svelte # Statistics display
│ │ ├── AddTaskForm.svelte # Form to add tasks
│ │ ├── Card.svelte # NEW: Reusable card wrapper (slots)
│ │ └── Modal.svelte # NEW: Modal component (slots)
│ ├── stores/
│ │ ├── tasks.js # Global task state (writable store)
│ │ └── derived.js # NEW: Derived stores for computed values
│ └── utils/
│ └── api.js # Mock API functions
└── app.css # Global styles
Issue: Tasks don't show up on page load
onMount function in +page.svelte and the loadTasks() function in api.jsIssue: Can't add new tasks
addTask() method in tasks.js and complete the form submission in AddTaskForm.svelteIssue: Statistics show as 0
Issue: Filtering doesn't work
currentFilterIssue: Wrong priority colors or sorting
Issue: Transitions not working
Issue: Custom events not firing
createEventDispatcher(), dispatched the event with the correct name, and added the on:eventname listener to the parent componentIssue: Derived stores showing 0 or undefined
$ prefix when accessing them in components (e.g., $completedTasksCount)Issue: Modal not appearing
isOpen is set to true when you click the button, and check that you've added the Modal component outside the main container divOnce you've completed this project, you'll have learned the essential Svelte concepts! Here are some ideas to continue your learning:
Feature Enhancements:
Technical Improvements:
Advanced Svelte Concepts to Explore:
use: directive) - for click-outside, tooltips, focus trap<script context="module">) - for shared component state<svelte:window>, <svelte:head>, <svelte:component>bind:this to get component instancesResources:
Good luck, and happy learning!