src/lib/components/TaskItem.svelte (view raw)
1<script lang="ts">
2 import type { FormEventHandler } from "svelte/elements";
3 import tasksStore from "../store/tasksStore";
4 import { debounce } from "../utils";
5 import { getShortcutActions } from "./taskShortcuts.svelte";
6
7 let { task }: { task: Task } = $props();
8
9 const parseContent = (content: string) =>
10 content.replace(/#((\w|-)+)/g, '<span class="hashtag">#$1</span>');
11
12 const onUpdateName: FormEventHandler<HTMLDivElement> = event => {
13 const element = event.target as HTMLElement;
14 const newValue = element.innerText?.trim();
15 if (newValue) tasksStore.updateTask(task.id, { name: newValue });
16 else tasksStore.deleteTask(task.id);
17 };
18
19 const onUpdateDone: FormEventHandler<HTMLInputElement> = e => {
20 const element = e.target as HTMLInputElement;
21 const done = element.checked;
22 const endTime = done ? new Date() : null;
23 tasksStore.updateTask(task.id, { done, endTime });
24 };
25
26 const onUpdateDueDate: FormEventHandler<HTMLInputElement> = e => {
27 const element = e.target as HTMLInputElement;
28 const rawDate = element.value;
29 let dueDate;
30 if (rawDate) dueDate = new Date(rawDate);
31 tasksStore.updateTask(task.id, { dueDate });
32 };
33
34 const onDelete = () => {
35 tasksStore.deleteTask(task.id);
36 };
37
38 const { onKeyDown, onKeyUp } = getShortcutActions({
39 x: onDelete,
40 Backspace: onDelete,
41 l: () => console.log({ task }),
42 });
43</script>
44
45<li class="list-row flex items-center gap-4 p-2" id={task.id}>
46 <input
47 type="checkbox"
48 class="checkbox"
49 checked={task.done}
50 onchange={onUpdateDone}
51 />
52 <div class="flex w-full justify-between">
53 <div
54 role="form"
55 contenteditable
56 autocorrect="off"
57 oninput={debounce(onUpdateName, 750)}
58 class:line-through={task.done}
59 class:text-gray-400={task.done}
60 onkeydown={onKeyDown}
61 onkeyup={onKeyUp}
62 >
63 {@html parseContent(task.name)}
64 </div>
65 <input
66 type="date"
67 value={task.dueDate?.toISOString().split("T")[0]}
68 onchange={onUpdateDueDate}
69 disabled={task.done}
70 class:text-red-400={!task.done &&
71 task.dueDate &&
72 task.dueDate < new Date()}
73 class:text-primary={task.dueDate && task.dueDate >= new Date()}
74 class="rounded px-1 h-fit"
75 />
76 </div>
77</li>