···55 import toast from "svelte-french-toast";
66 import { formatSecondsToDuration, generateId } from "$lib/utils";
77 import { local_lists, pinned_list, type List, type Task } from "$lib/stores.svelte";
88+ import TaskItem from "$lib/TaskItem.svelte";
89910 let is_menu_open = $state(false);
1010- let list : List | undefined = $state(local_lists.value!.find((l) => l.id === page.params.id));
1111+ let list : List | undefined = $derived(local_lists.current!.find((l) => l.id === page.params.id));
1112 let task_input = $state("");
1212- let user_lists = $derived(local_lists.value) as List[];
1313+ let user_lists = $derived(local_lists.current) as List[];
13141415 // since list points to something inside local_lists,
1516 // it will run when list state changes
1616- $effect(() => local_lists.update());
17171818 function addTask() {
1919 if (task_input.length === 0) {
···2424 list?.tasks.push({
2525 id: generateId(),
2626 description: task_input,
2727- is_completed: false
2727+ completed: false,
2828+ duration: 0
2829 });
29303031 task_input = "";
···3637 }
3738 }
38393939- function toggleInterval(id: string) {
4040- if (list) {
4141- const task = list.tasks.find((t) => t.id === id) as Task;
4242- if (task.stopwatchInterval) {
4343- clearInterval(task.stopwatchInterval);
4444- task.stopwatchInterval = undefined;
4545- }
4646- else {
4747- const interval = setInterval(() => {
4848- if (!task.duration) { task.duration = 0; }
4949- task.duration += 1;
5050- }, 1000);
5151- task.stopwatchInterval = interval;
5252- }
5353- }
5454- }
5555-5640 function createList() {
5741 const new_list = {
5842 id: generateId(),
···6044 tasks: []
6145 };
62466363- local_lists.value!.push(new_list);
6464- list = local_lists.value!.find((l) => l.id === new_list.id);
4747+ local_lists.current!.push(new_list);
4848+ list = local_lists.current!.find((l) => l.id === new_list.id);
6549 goto(`/${list!.id}`);
6650 }
67516852 function switchToList(id: string) {
6969- list = local_lists.value!.find((l) => l.id === id);
5353+ list = local_lists.current!.find((l) => l.id === id);
7054 goto(`/${list!.id}`);
7155 }
72567357 function pinList(id: string) {
7474- pinned_list.value = id;
5858+ pinned_list.current = id;
7559 }
76607761 function deleteList() {
7878- if (pinned_list.value === page.params.id) {
6262+ if (pinned_list.current === page.params.id) {
7963 toast.error("Cannot delete pinned list");
8064 return;
8165 }
82668383- local_lists.value = local_lists.value!.filter((l) => l.id !== page.params.id);
8484- list = local_lists.value.find((l) => l.id === pinned_list.value);
6767+ local_lists.current = local_lists.current!.filter((l) => l.id !== page.params.id);
6868+ list = local_lists.current.find((l) => l.id === pinned_list.current);
8569 goto(`/${list!.id}`);
8670 }
8787-8888- onMount(() => {
8989- if (list) {
9090- for (const task of list.tasks) {
9191- // if a task's stopwatch is still running
9292- // remove it so the user can start it again in one click
9393- // instead of two cause the first `toggleInterval` would
9494- // just remove the interval
9595- if (task.stopwatchInterval) {
9696- clearInterval(task.stopwatchInterval);
9797- task.stopwatchInterval = undefined;
9898- local_lists.update();
9999- }
100100- }
101101- }
102102- });
10371</script>
1047210573<main class="flex flex-col w-full px-2 pt-8 pb-28 lg:px-4 lg:pt-4 gap-8 text-xl lg:text-3xl">
···11583 </button>
11684 <button onclick={() => pinList(list!.id)}>
11785 <img
118118- src={pinned_list.value === list.id ? "/pin.svg" : "/pin-line.svg"}
8686+ src={pinned_list.current === list.id ? "/pin.svg" : "/pin-line.svg"}
11987 alt="Pin list button"
12088 class="w-12 h-12 hover:bg-slate-500/10 rounded-full"
12189 />
···166134 />
167135168136 <ul class="flex flex-col gap-4">
169169- {#each list.tasks as task (task.id)}
170170- <li class="group flex justify-between items-center gap-4">
171171- <div class="flex w-full gap-4 items-center pr-4 py-2">
172172- <input
173173- type="checkbox"
174174- bind:checked={task.is_completed}
175175- class="w-6 h-6 bg-transparent"
176176- />
177177- <input
178178- type="text"
179179- bind:value={task.description}
180180- class={`w-full hover:underline text-ellipsis overflow-hidden bg-transparent ${task.is_completed && "text-white/50"}`}
181181- />
182182- </div>
183183-184184- <div class="flex gap-4 w-fit items-center">
185185- <button
186186- onclick={() => toggleInterval(task.id)}
187187- class="w-fit h-fit tabular-nums text-lg"
188188- >
189189- {formatSecondsToDuration(task.duration!)}
190190- </button>
191191- <button
192192- onclick={() => deleteTask(task.id)}
193193- class="px-4 py-2 bg-red-500 rounded-xl text-white"
194194- >
195195- -
196196- </button>
197197- </div>
198198- </li>
137137+ {#each list.tasks as task, i (task.id)}
138138+ <TaskItem bind:task={list.tasks[i]} onDelete={deleteTask} />
199139 {/each}
200140 <li class="flex gap-4 w-full">
201141 <input type="text" bind:value={task_input} class="bg-transparent pr-4 py-2 border-b w-full"/>
+2-8
svelte.config.js
···11-import adapter from '@deno/svelte-adapter';
11+import adapter from '@sveltejs/adapter-netlify';
22import { vitePreprocess } from '@sveltejs/vite-plugin-svelte';
3344/** @type {import('@sveltejs/kit').Config} */
···66 // Consult https://kit.svelte.dev/docs/integrations#preprocessors
77 // for more information about preprocessors
88 preprocess: vitePreprocess(),
99-1010- kit: {
1111- // adapter-auto only supports some environments, see https://kit.svelte.dev/docs/adapter-auto for a list.
1212- // If your environment is not supported or you settled on a specific environment, switch out the adapter.
1313- // See https://kit.svelte.dev/docs/adapters for more information about adapters.
1414- adapter: adapter()
1515- }
99+ kit: { adapter: adapter() }
1610};
17111812export default config;