all repos — kōi @ 4a48ccfcb2820e792122c1a2d62d209c30239e47

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