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
6 let { task }: { task: Task } = $props();
7
8 const parseContent = (content: string) =>
9 content.replace(/#((\w|-)+)/g, '<span class="hashtag">#$1</span>');
10
11 const onUpdateName: FormEventHandler<HTMLDivElement> = event => {
12 const element = event.target as HTMLElement;
13 const newValue = element.innerText?.trim();
14 tasksStore.updateTask(task.id, { name: newValue });
15 };
16
17 const onUpdateDone: FormEventHandler<HTMLInputElement> = e => {
18 const element = e.target as HTMLInputElement;
19 const done = element.checked;
20 tasksStore.updateTask(task.id, { done });
21 };
22
23 const onUpdateDueDate: FormEventHandler<HTMLInputElement> = e => {
24 const element = e.target as HTMLInputElement;
25 const rawDate = element.value;
26 let dueDate;
27 if (rawDate) dueDate = new Date(rawDate);
28 tasksStore.updateTask(task.id, { dueDate });
29 };
30</script>
31
32<div class="flex items-center gap-4 rounded border p-2" id={task.id}>
33 <input
34 type="checkbox"
35 class="checkbox mt-1"
36 checked={task.done}
37 onchange={onUpdateDone}
38 />
39 <div class="flex w-full justify-between">
40 <div contenteditable oninput={debounce(onUpdateName, 750)}>
41 {@html parseContent(task.name)}
42 </div>
43 <input
44 type="date"
45 value={task.dueDate?.toISOString().split("T")[0]}
46 onchange={onUpdateDueDate}
47 class:text-red-400={task.dueDate && task.dueDate < new Date()}
48 class:text-primary={task.dueDate && task.dueDate >= new Date()}
49 />
50 </div>
51</div>