all repos — kōi @ 13ba0aa72c94f508c54f3862f99e195a4ec73f4c

Minimalist task manager

src/routes/(auth)/TaskItem.svelte (view raw)

 1<script lang="ts">
 2	import { debounce } from '$lib/utils';
 3	import type { FormEventHandler } from 'svelte/elements';
 4	import tasksStore from './tasksStore';
 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 type="checkbox" class="checkbox mt-1" checked={task.done} onchange={onUpdateDone} />
34	<div class="flex w-full justify-between">
35		<div contenteditable oninput={debounce(onUpdateName, 750)}>
36			{@html parseContent(task.name)}
37		</div>
38		<input
39			type="date"
40			value={task.dueDate?.toISOString().split('T')[0]}
41			onchange={onUpdateDueDate}
42			class:text-red-400={task.dueDate && task.dueDate < new Date()}
43			class:text-primary={task.dueDate && task.dueDate >= new Date()}
44		/>
45	</div>
46</div>