✨ Parsehasthtags, store updates
Tim Izzo tim@5ika.ch
Thu, 21 Nov 2024 17:02:44 +0100
9 files changed,
71 insertions(+),
32 deletions(-)
M
src/app.css
→
src/app.css
@@ -1,3 +1,7 @@
@import 'tailwindcss/base'; @import 'tailwindcss/components'; -@import 'tailwindcss/utilities' +@import 'tailwindcss/utilities'; + +.hashtag { + @apply text-secondary; +}
M
src/app.d.ts
→
src/app.d.ts
@@ -10,9 +10,9 @@ // interface Platform {}
} interface Task { - id: number + id: number; done?: boolean; - dueDate?: string; + dueDate?: Date; content: string; } }
M
src/app.html
→
src/app.html
@@ -4,6 +4,7 @@ <head>
<meta charset="utf-8" /> <link rel="icon" href="%sveltekit.assets%/favicon.png" /> <meta name="viewport" content="width=device-width, initial-scale=1" /> + <title>Kōi</title> %sveltekit.head% </head> <body data-sveltekit-preload-data="hover">
D
src/lib/store/tasks.ts
@@ -1,12 +0,0 @@
-import { writable } from 'svelte/store'; -import { v4 as uuidv4 } from 'uuid'; - -let { update, set, subscribe } = writable<Task[]>([]); - -const addTask = (taskInput: Omit<Task, 'id'>) => - update((tasks) => { - const task = { ...taskInput, id: uuidv4() }; - return [...tasks, task]; - }); - -export default { update, set, subscribe, addTask };
A
src/lib/utils.ts
@@ -0,0 +1,8 @@
+export const debounce = (callback: Function, wait = 300) => { + let timeout: ReturnType<typeof setTimeout>; + + return (...args: any[]) => { + clearTimeout(timeout); + timeout = setTimeout(() => callback(...args), wait); + }; +};
M
src/routes/NewTask.svelte
→
src/routes/NewTask.svelte
@@ -4,7 +4,8 @@
const onKeyDown = (e: KeyboardEvent) => { const element = e.target as HTMLInputElement; const inputValue = element?.value; - if (e.code === 'Enter' && inputValue) { + const enterKeys = ['Enter', 'NumpadEnter']; + if (inputValue && enterKeys.includes(e.code)) { db.tasks.add({ content: inputValue }); element.value = ''; }
M
src/routes/Task.svelte
→
src/routes/Task.svelte
@@ -1,18 +1,57 @@
<script lang="ts"> import { db } from '$lib/db'; + import { debounce } from '$lib/utils'; + import type { FormEventHandler } from 'svelte/elements'; let { task }: { task: Task } = $props(); - const onUpdateContent = (e: InputEvent) => { + const parseContent = (content: string) => + content.replace(/#((\w|-)+)/g, '<span class="hashtag">#$1</span>'); + + const onUpdateContent: FormEventHandler<HTMLDivElement> = (e) => { const element = e.target as HTMLElement; - db.tasks.update(task.id, { content: element.innerText }); + const content = element.innerText?.trim(); + if (content) db.tasks.update(task.id, { content }); + else db.tasks.delete(task.id); + }; + + const onUpdateDone: FormEventHandler<HTMLInputElement> = (e) => { + const element = e.target as HTMLInputElement; + const done = element.checked; + db.tasks.update(task.id, { done }); + }; + + const onUpdateDueDate: FormEventHandler<HTMLInputElement> = (e) => { + const element = e.target as HTMLInputElement; + const rawDate = element.value; + let dueDate; + if (rawDate) dueDate = new Date(rawDate); + db.tasks.update(task.id, { dueDate }); }; </script> <div class="flex items-center justify-between gap-2"> <div class="flex items-center gap-2"> - <input type="checkbox" class="checkbox checkbox-primary checkbox-sm" checked={task.done} /> - <div contenteditable oninput={onUpdateContent}>{task.content}</div> + <input + type="checkbox" + class="checkbox-primary checkbox checkbox-sm" + checked={task.done} + onchange={onUpdateDone} + /> + <div + contenteditable + oninput={debounce(onUpdateContent, 1000)} + class:opacity-50={task.done} + class:line-through={task.done} + > + {@html parseContent(task.content)} + </div> </div> - <input type="date" value={task.dueDate} /> + <input + type="date" + value={task.dueDate?.toISOString().split('T')[0]} + onchange={onUpdateDueDate} + class:text-red-400={task.dueDate && task.dueDate < new Date()} + class:text-primary={task.dueDate && task.dueDate >= new Date()} + /> </div>
M
tailwind.config.ts
→
tailwind.config.ts
@@ -2,15 +2,15 @@ import type { Config } from 'tailwindcss';
import daisyui from 'daisyui'; export default { - content: ['./src/**/*.{html,js,svelte,ts}'], + content: ['./src/**/*.{html,js,svelte,ts}'], - theme: { - extend: {}, - screens: { - "laptop": '512px', - "desktop": '512px' - } - }, + theme: { + extend: {}, + screens: { + laptop: '780px', + desktop: '780px' + } + }, - plugins: [daisyui] + plugins: [daisyui] } satisfies Config;