all repos — kōi @ 76ba9e672f957a5b730f151f679d64d3e387ff98

Minimalist task manager

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    tasksStore.updateTask(task.id, { done });
23  };
24
25  const onUpdateDueDate: FormEventHandler<HTMLInputElement> = e => {
26    const element = e.target as HTMLInputElement;
27    const rawDate = element.value;
28    let dueDate;
29    if (rawDate) dueDate = new Date(rawDate);
30    tasksStore.updateTask(task.id, { dueDate });
31  };
32
33  const onDelete = () => {
34    tasksStore.deleteTask(task.id);
35  };
36
37  const { onKeyDown, onKeyUp } = getShortcutActions({
38    x: onDelete,
39    Backspace: onDelete,
40    l: () => console.log({ task }),
41  });
42</script>
43
44<li class="list-row flex items-center gap-4 p-2" id={task.id}>
45  <input
46    type="checkbox"
47    class="checkbox"
48    checked={task.done}
49    onchange={onUpdateDone}
50  />
51  <div class="flex w-full justify-between">
52    <div
53      role="form"
54      contenteditable
55      autocorrect="off"
56      oninput={debounce(onUpdateName, 750)}
57      class:line-through={task.done}
58      onkeydown={onKeyDown}
59      onkeyup={onKeyUp}
60    >
61      {@html parseContent(task.name)}
62    </div>
63    <input
64      type="date"
65      value={task.dueDate?.toISOString().split("T")[0]}
66      onchange={onUpdateDueDate}
67      class:text-red-400={task.dueDate && task.dueDate < new Date()}
68      class:text-primary={task.dueDate && task.dueDate >= new Date()}
69      class="rounded px-1 h-fit"
70    />
71  </div>
72</li>