It's a todo list.
7
fork

Configure Feed

Select the types of activity you want to include in your feed.

update stores with PersistedState, useInterval timers

+101 -131
+12
bun.lock
··· 7 7 "dependencies": { 8 8 "@tailwindcss/vite": "^4.1.13", 9 9 "oslo": "^1.2.1", 10 + "runed": "^0.37.1", 10 11 "svelte-french-toast": "^1.2.0", 11 12 "tailwindcss": "^4.1.13", 12 13 }, 13 14 "devDependencies": { 15 + "@sveltejs/adapter-netlify": "^6.0.4", 14 16 "@sveltejs/kit": "^2.43.5", 15 17 "@sveltejs/vite-plugin-svelte": "^6.2.1", 16 18 "svelte": "^5.39.6", ··· 77 79 "@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.25.10", "", { "os": "win32", "cpu": "ia32" }, "sha512-QHPDbKkrGO8/cz9LKVnJU22HOi4pxZnZhhA2HYHez5Pz4JeffhDjf85E57Oyco163GnzNCVkZK0b/n4Y0UHcSw=="], 78 80 79 81 "@esbuild/win32-x64": ["@esbuild/win32-x64@0.25.10", "", { "os": "win32", "cpu": "x64" }, "sha512-9KpxSVFCu0iK1owoez6aC/s/EdUQLDN3adTxGCqxMVhrPDj6bt5dbrHDXUuq+Bs2vATFBBrQS5vdQ/Ed2P+nbw=="], 82 + 83 + "@iarna/toml": ["@iarna/toml@2.2.5", "", {}, "sha512-trnsAYxU3xnS1gPHPyU961coFyLkh4gAD/0zQ5mymY4yOZ+CYvsPqUbOFSw0aDM4y0tV7tiFxL/1XfXPNC6IPg=="], 80 84 81 85 "@isaacs/fs-minipass": ["@isaacs/fs-minipass@4.0.1", "", { "dependencies": { "minipass": "^7.0.4" } }, "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w=="], 82 86 ··· 199 203 "@standard-schema/spec": ["@standard-schema/spec@1.0.0", "", {}, "sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA=="], 200 204 201 205 "@sveltejs/acorn-typescript": ["@sveltejs/acorn-typescript@1.0.6", "", { "peerDependencies": { "acorn": "^8.9.0" } }, "sha512-4awhxtMh4cx9blePWl10HRHj8Iivtqj+2QdDCSMDzxG+XKa9+VCNupQuCuvzEhYPzZSrX+0gC+0lHA/0fFKKQQ=="], 206 + 207 + "@sveltejs/adapter-netlify": ["@sveltejs/adapter-netlify@6.0.4", "", { "dependencies": { "@iarna/toml": "^2.2.5", "esbuild": "^0.25.4" }, "peerDependencies": { "@sveltejs/kit": "^2.31.0" } }, "sha512-Ln/vgZc1v/2JFXhl5QiVKJ61a75jKe2rdxMnDO8PPDpQN8Tq/0w4JnBGAMBqENtD+kDACyY00ZTyzP9uTP77wg=="], 202 208 203 209 "@sveltejs/kit": ["@sveltejs/kit@2.43.5", "", { "dependencies": { "@standard-schema/spec": "^1.0.0", "@sveltejs/acorn-typescript": "^1.0.5", "@types/cookie": "^0.6.0", "acorn": "^8.14.1", "cookie": "^0.6.0", "devalue": "^5.3.2", "esm-env": "^1.2.2", "kleur": "^4.1.5", "magic-string": "^0.30.5", "mrmime": "^2.0.0", "sade": "^1.8.1", "set-cookie-parser": "^2.6.0", "sirv": "^3.0.0" }, "peerDependencies": { "@opentelemetry/api": "^1.0.0", "@sveltejs/vite-plugin-svelte": "^3.0.0 || ^4.0.0-next.1 || ^5.0.0 || ^6.0.0-next.0", "svelte": "^4.0.0 || ^5.0.0-next.0", "vite": "^5.0.3 || ^6.0.0 || ^7.0.0-beta.0" }, "optionalPeers": ["@opentelemetry/api"], "bin": { "svelte-kit": "svelte-kit.js" } }, "sha512-44Mm5csR4mesKx2Eyhtk8UVrLJ4c04BT2wMTfYGKJMOkUqpHP5KLL2DPV0hXUA4t4+T3ZYe0aBygd42lVYv2cA=="], 204 210 ··· 260 266 261 267 "deepmerge": ["deepmerge@4.3.1", "", {}, "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A=="], 262 268 269 + "dequal": ["dequal@2.0.3", "", {}, "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA=="], 270 + 263 271 "detect-libc": ["detect-libc@2.1.1", "", {}, "sha512-ecqj/sy1jcK1uWrwpR67UhYrIFQ+5WlGxth34WquCbamhFA6hkkwiu37o6J5xCHdo1oixJRfVRw+ywV+Hq/0Aw=="], 264 272 265 273 "devalue": ["devalue@5.3.2", "", {}, "sha512-UDsjUbpQn9kvm68slnrs+mfxwFkIflOhkanmyabZ8zOYk8SMEIbJ3TK+88g70hSIeytu4y18f0z/hYHMTrXIWw=="], ··· 310 318 311 319 "locate-character": ["locate-character@3.0.0", "", {}, "sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA=="], 312 320 321 + "lz-string": ["lz-string@1.5.0", "", { "bin": { "lz-string": "bin/bin.js" } }, "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ=="], 322 + 313 323 "magic-string": ["magic-string@0.30.19", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.5" } }, "sha512-2N21sPY9Ws53PZvsEpVtNuSW+ScYbQdp4b9qUaL+9QkHUrGFKo56Lg9Emg5s9V/qrtNBmiR01sYhUOwu3H+VOw=="], 314 324 315 325 "memfs": ["memfs@3.5.3", "", { "dependencies": { "fs-monkey": "^1.0.4" } }, "sha512-UERzLsxzllchadvbPs5aolHh65ISpKpM+ccLbOJ8/vvpBKmAWf+la7dXFy7Mr0ySHbdHrFv5kGFCUHHe6GFEmw=="], ··· 339 349 "readdirp": ["readdirp@4.1.2", "", {}, "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg=="], 340 350 341 351 "rollup": ["rollup@4.52.3", "", { "dependencies": { "@types/estree": "1.0.8" }, "optionalDependencies": { "@rollup/rollup-android-arm-eabi": "4.52.3", "@rollup/rollup-android-arm64": "4.52.3", "@rollup/rollup-darwin-arm64": "4.52.3", "@rollup/rollup-darwin-x64": "4.52.3", "@rollup/rollup-freebsd-arm64": "4.52.3", "@rollup/rollup-freebsd-x64": "4.52.3", "@rollup/rollup-linux-arm-gnueabihf": "4.52.3", "@rollup/rollup-linux-arm-musleabihf": "4.52.3", "@rollup/rollup-linux-arm64-gnu": "4.52.3", "@rollup/rollup-linux-arm64-musl": "4.52.3", "@rollup/rollup-linux-loong64-gnu": "4.52.3", "@rollup/rollup-linux-ppc64-gnu": "4.52.3", "@rollup/rollup-linux-riscv64-gnu": "4.52.3", "@rollup/rollup-linux-riscv64-musl": "4.52.3", "@rollup/rollup-linux-s390x-gnu": "4.52.3", "@rollup/rollup-linux-x64-gnu": "4.52.3", "@rollup/rollup-linux-x64-musl": "4.52.3", "@rollup/rollup-openharmony-arm64": "4.52.3", "@rollup/rollup-win32-arm64-msvc": "4.52.3", "@rollup/rollup-win32-ia32-msvc": "4.52.3", "@rollup/rollup-win32-x64-gnu": "4.52.3", "@rollup/rollup-win32-x64-msvc": "4.52.3", "fsevents": "~2.3.2" }, "bin": { "rollup": "dist/bin/rollup" } }, "sha512-RIDh866U8agLgiIcdpB+COKnlCreHJLfIhWC3LVflku5YHfpnsIKigRZeFfMfCc4dVcqNVfQQ5gO/afOck064A=="], 352 + 353 + "runed": ["runed@0.37.1", "", { "dependencies": { "dequal": "^2.0.3", "esm-env": "^1.0.0", "lz-string": "^1.5.0" }, "peerDependencies": { "@sveltejs/kit": "^2.21.0", "svelte": "^5.7.0", "zod": "^4.1.0" }, "optionalPeers": ["@sveltejs/kit", "zod"] }, "sha512-MeFY73xBW8IueWBm012nNFIGy19WUGPLtknavyUPMpnyt350M47PhGSGrGoSLbidwn+Zlt/O0cp8/OZE3LASWA=="], 342 354 343 355 "sade": ["sade@1.8.1", "", { "dependencies": { "mri": "^1.1.0" } }, "sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A=="], 344 356
+2
package.json
··· 10 10 "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch" 11 11 }, 12 12 "devDependencies": { 13 + "@sveltejs/adapter-netlify": "^6.0.4", 13 14 "@sveltejs/kit": "^2.43.5", 14 15 "@sveltejs/vite-plugin-svelte": "^6.2.1", 15 16 "svelte": "^5.39.6", ··· 22 23 "dependencies": { 23 24 "@tailwindcss/vite": "^4.1.13", 24 25 "oslo": "^1.2.1", 26 + "runed": "^0.37.1", 25 27 "svelte-french-toast": "^1.2.0", 26 28 "tailwindcss": "^4.1.13" 27 29 }
+53
src/lib/TaskItem.svelte
··· 1 + <script lang="ts"> 2 + import { useInterval } from "runed"; 3 + import type { Task } from "./stores.svelte"; 4 + import { formatSecondsToDuration } from "./utils"; 5 + 6 + let { task = $bindable(), onDelete }: { task: Task, onDelete: (taskId: string) => void } = $props(); 7 + 8 + const interval = useInterval(1000, { 9 + immediate: false, 10 + callback: () => { 11 + task.duration++; 12 + } 13 + }); 14 + 15 + function toggleInterval() { 16 + if (interval.isActive) { 17 + interval.pause(); 18 + } 19 + else { 20 + interval.resume(); 21 + } 22 + } 23 + </script> 24 + 25 + <li class="group flex justify-between items-center gap-4"> 26 + <div class="flex w-full gap-4 items-center pr-4 py-2"> 27 + <input 28 + type="checkbox" 29 + bind:checked={task.completed} 30 + class="w-6 h-6 bg-transparent" 31 + /> 32 + <input 33 + type="text" 34 + bind:value={task.description} 35 + class={`w-full hover:underline text-ellipsis overflow-hidden bg-transparent ${task.completed && "text-white/50"}`} 36 + /> 37 + </div> 38 + 39 + <div class="flex gap-4 w-fit items-center"> 40 + <button 41 + onclick={toggleInterval} 42 + class="w-fit h-fit tabular-nums text-lg" 43 + > 44 + {formatSecondsToDuration(task.duration!)} 45 + </button> 46 + <button 47 + onclick={() => onDelete(task.id)} 48 + class="px-4 py-2 bg-red-500 rounded-xl text-white" 49 + > 50 + - 51 + </button> 52 + </div> 53 + </li>
+8 -40
src/lib/stores.svelte.ts
··· 1 1 import { generateId } from "./utils"; 2 - 3 - // Browser + Local Storage 4 - const browser_exists = (typeof window !== "undefined") && (typeof (document) !== "undefined"); 5 - const storage = browser_exists ? localStorage : null; 6 - 7 - // Generalized Local Storage 8 - export function persisted<T>(key: string, default_value: T) { 9 - let value : T | undefined = $state(); 10 - 11 - const initial_local = storage?.getItem(key); 12 - if (initial_local) { 13 - value = JSON.parse(initial_local).value as T; 14 - if (!value) { update(); } 15 - } 16 - else { 17 - value = default_value; 18 - update(); 19 - } 20 - 21 - function update() { 22 - if (browser_exists) { 23 - storage?.setItem(key, JSON.stringify({ value: value })); 24 - } 25 - } 26 - 27 - return { 28 - get value() { return value; }, 29 - set value(new_value) { value = new_value; update(); }, 30 - update 31 - } 32 - } 2 + import { PersistedState } from "runed"; 33 3 34 4 export type Task = { 35 5 id: string; 36 6 description: string; 37 - is_completed: boolean; 38 - // optional 39 - duration?: number; 40 - stopwatchInterval?: number; 7 + completed: boolean; 8 + duration: number; 41 9 } 42 10 43 11 export type List = { ··· 46 14 tasks: Task[]; 47 15 } 48 16 49 - export const local_lists = persisted<List[]>("local_lists", [ 17 + export const local_lists = new PersistedState<List[]>("local_lists", [ 50 18 { 51 19 id: generateId(), 52 20 title: "Take a Break", 53 21 tasks: [ 54 - { id: generateId(), description: "Drink water", is_completed: false }, 55 - { id: generateId(), description: "Stand up and stretch", is_completed: false }, 56 - { id: generateId(), description: "Go outside for 10 seconds", is_completed: false }, ] 22 + { id: generateId(), description: "Drink water", completed: false, duration: 0 }, 23 + { id: generateId(), description: "Stand up and stretch", completed: false, duration: 0 }, 24 + { id: generateId(), description: "Go outside for 10 seconds", completed: false, duration: 0 }, ] 57 25 } 58 26 ]); 59 27 60 - export const pinned_list = persisted<string>("pinned_list", local_lists.value![0].id); 28 + export const pinned_list = new PersistedState<string>("pinned_list", local_lists.current[0].id);
+9 -8
src/routes/+layout.svelte
··· 5 5 import { goto } from "$app/navigation"; 6 6 import { fade } from "svelte/transition"; 7 7 import toast, { Toaster } from "svelte-french-toast"; 8 - import { persisted, pinned_list } from "$lib/stores.svelte"; 8 + import { pinned_list } from "$lib/stores.svelte"; 9 + import { PersistedState } from "runed"; 9 10 10 11 interface Props { 11 12 children: Snippet ··· 13 14 14 15 let { children }: Props = $props(); 15 16 16 - let theme = persisted<string>("theme", "dark"); 17 + let theme = new PersistedState<string>("theme", "dark"); 17 18 let is_menu_open = $state(false); 18 - let theme_style = $derived(theme.value === "dark" 19 + let theme_style = $derived(theme.current === "dark" 19 20 ? "text-white absolute top-0 z-[-2] h-screen w-screen bg-[#000000] bg-[radial-gradient(#ffffff33_1px,#00091d_1px)] bg-size-[20px_20px]" 20 21 : "text-black absolute inset-0 -z-10 h-full w-full bg-white bg-[radial-gradient(#e5e7eb_1px,transparent_1px)] bg-size-[16px_16px]" 21 22 ); ··· 26 27 27 28 onMount(() => { 28 29 if (page.url.pathname === "/") { 29 - goto(`/${pinned_list.value}`); 30 + goto(`/${pinned_list.current}`); 30 31 } 31 32 }); 32 33 </script> ··· 41 42 {#if is_menu_open} 42 43 <menu 43 44 transition:fade={{ duration: 150 }} 44 - class={`${theme.value === "light" ? "border-black" : "border-[#00091d]"} w-fit border z-50 flex flex-col items-start gap-2 h-fit p-2 rounded-xl bg-white`} 45 + class={`${theme.current === "light" ? "border-black" : "border-[#00091d]"} w-fit border z-50 flex flex-col items-start gap-2 h-fit p-2 rounded-xl bg-white`} 45 46 > 46 47 <button 47 48 onclick={() => { ··· 66 67 </menu> 67 68 {/if} 68 69 69 - <nav class={`${theme.value === "light" ? "border-black" : "border-[#00091d]"} border z-50 flex self-center items-center gap-4 mx-auto w-fit h-fit p-2 rounded-xl bg-white`}> 70 + <nav class={`${theme.current === "light" ? "border-black" : "border-[#00091d]"} border z-50 flex self-center items-center gap-4 mx-auto w-fit h-fit p-2 rounded-xl bg-white`}> 70 71 <button 71 72 onclick={() => is_menu_open = !is_menu_open} 72 73 class="w-full h-fit hover:bg-slate-500/10 rounded-full" ··· 94 95 95 96 96 97 <button 97 - onclick={() => { theme.value = theme.value === "light" ? "dark" : "light" }} 98 - class={`${theme.value === "light" ? "border-black" : "border-[#00091d]"} border w-fit h-fit p-2 bg-white rounded-xl pointer-events-auto`} 98 + onclick={() => { theme.current = theme.current === "light" ? "dark" : "light" }} 99 + class={`${theme.current === "light" ? "border-black" : "border-[#00091d]"} border w-fit h-fit p-2 bg-white rounded-xl pointer-events-auto`} 99 100 > 100 101 <img 101 102 src="/light-bulb.svg"
+15 -75
src/routes/[id]/+page.svelte
··· 5 5 import toast from "svelte-french-toast"; 6 6 import { formatSecondsToDuration, generateId } from "$lib/utils"; 7 7 import { local_lists, pinned_list, type List, type Task } from "$lib/stores.svelte"; 8 + import TaskItem from "$lib/TaskItem.svelte"; 8 9 9 10 let is_menu_open = $state(false); 10 - let list : List | undefined = $state(local_lists.value!.find((l) => l.id === page.params.id)); 11 + let list : List | undefined = $derived(local_lists.current!.find((l) => l.id === page.params.id)); 11 12 let task_input = $state(""); 12 - let user_lists = $derived(local_lists.value) as List[]; 13 + let user_lists = $derived(local_lists.current) as List[]; 13 14 14 15 // since list points to something inside local_lists, 15 16 // it will run when list state changes 16 - $effect(() => local_lists.update()); 17 17 18 18 function addTask() { 19 19 if (task_input.length === 0) { ··· 24 24 list?.tasks.push({ 25 25 id: generateId(), 26 26 description: task_input, 27 - is_completed: false 27 + completed: false, 28 + duration: 0 28 29 }); 29 30 30 31 task_input = ""; ··· 36 37 } 37 38 } 38 39 39 - function toggleInterval(id: string) { 40 - if (list) { 41 - const task = list.tasks.find((t) => t.id === id) as Task; 42 - if (task.stopwatchInterval) { 43 - clearInterval(task.stopwatchInterval); 44 - task.stopwatchInterval = undefined; 45 - } 46 - else { 47 - const interval = setInterval(() => { 48 - if (!task.duration) { task.duration = 0; } 49 - task.duration += 1; 50 - }, 1000); 51 - task.stopwatchInterval = interval; 52 - } 53 - } 54 - } 55 - 56 40 function createList() { 57 41 const new_list = { 58 42 id: generateId(), ··· 60 44 tasks: [] 61 45 }; 62 46 63 - local_lists.value!.push(new_list); 64 - list = local_lists.value!.find((l) => l.id === new_list.id); 47 + local_lists.current!.push(new_list); 48 + list = local_lists.current!.find((l) => l.id === new_list.id); 65 49 goto(`/${list!.id}`); 66 50 } 67 51 68 52 function switchToList(id: string) { 69 - list = local_lists.value!.find((l) => l.id === id); 53 + list = local_lists.current!.find((l) => l.id === id); 70 54 goto(`/${list!.id}`); 71 55 } 72 56 73 57 function pinList(id: string) { 74 - pinned_list.value = id; 58 + pinned_list.current = id; 75 59 } 76 60 77 61 function deleteList() { 78 - if (pinned_list.value === page.params.id) { 62 + if (pinned_list.current === page.params.id) { 79 63 toast.error("Cannot delete pinned list"); 80 64 return; 81 65 } 82 66 83 - local_lists.value = local_lists.value!.filter((l) => l.id !== page.params.id); 84 - list = local_lists.value.find((l) => l.id === pinned_list.value); 67 + local_lists.current = local_lists.current!.filter((l) => l.id !== page.params.id); 68 + list = local_lists.current.find((l) => l.id === pinned_list.current); 85 69 goto(`/${list!.id}`); 86 70 } 87 - 88 - onMount(() => { 89 - if (list) { 90 - for (const task of list.tasks) { 91 - // if a task's stopwatch is still running 92 - // remove it so the user can start it again in one click 93 - // instead of two cause the first `toggleInterval` would 94 - // just remove the interval 95 - if (task.stopwatchInterval) { 96 - clearInterval(task.stopwatchInterval); 97 - task.stopwatchInterval = undefined; 98 - local_lists.update(); 99 - } 100 - } 101 - } 102 - }); 103 71 </script> 104 72 105 73 <main class="flex flex-col w-full px-2 pt-8 pb-28 lg:px-4 lg:pt-4 gap-8 text-xl lg:text-3xl"> ··· 115 83 </button> 116 84 <button onclick={() => pinList(list!.id)}> 117 85 <img 118 - src={pinned_list.value === list.id ? "/pin.svg" : "/pin-line.svg"} 86 + src={pinned_list.current === list.id ? "/pin.svg" : "/pin-line.svg"} 119 87 alt="Pin list button" 120 88 class="w-12 h-12 hover:bg-slate-500/10 rounded-full" 121 89 /> ··· 166 134 /> 167 135 168 136 <ul class="flex flex-col gap-4"> 169 - {#each list.tasks as task (task.id)} 170 - <li class="group flex justify-between items-center gap-4"> 171 - <div class="flex w-full gap-4 items-center pr-4 py-2"> 172 - <input 173 - type="checkbox" 174 - bind:checked={task.is_completed} 175 - class="w-6 h-6 bg-transparent" 176 - /> 177 - <input 178 - type="text" 179 - bind:value={task.description} 180 - class={`w-full hover:underline text-ellipsis overflow-hidden bg-transparent ${task.is_completed && "text-white/50"}`} 181 - /> 182 - </div> 183 - 184 - <div class="flex gap-4 w-fit items-center"> 185 - <button 186 - onclick={() => toggleInterval(task.id)} 187 - class="w-fit h-fit tabular-nums text-lg" 188 - > 189 - {formatSecondsToDuration(task.duration!)} 190 - </button> 191 - <button 192 - onclick={() => deleteTask(task.id)} 193 - class="px-4 py-2 bg-red-500 rounded-xl text-white" 194 - > 195 - - 196 - </button> 197 - </div> 198 - </li> 137 + {#each list.tasks as task, i (task.id)} 138 + <TaskItem bind:task={list.tasks[i]} onDelete={deleteTask} /> 199 139 {/each} 200 140 <li class="flex gap-4 w-full"> 201 141 <input type="text" bind:value={task_input} class="bg-transparent pr-4 py-2 border-b w-full"/>
+2 -8
svelte.config.js
··· 1 - import adapter from '@deno/svelte-adapter'; 1 + import adapter from '@sveltejs/adapter-netlify'; 2 2 import { vitePreprocess } from '@sveltejs/vite-plugin-svelte'; 3 3 4 4 /** @type {import('@sveltejs/kit').Config} */ ··· 6 6 // Consult https://kit.svelte.dev/docs/integrations#preprocessors 7 7 // for more information about preprocessors 8 8 preprocess: vitePreprocess(), 9 - 10 - kit: { 11 - // adapter-auto only supports some environments, see https://kit.svelte.dev/docs/adapter-auto for a list. 12 - // If your environment is not supported or you settled on a specific environment, switch out the adapter. 13 - // See https://kit.svelte.dev/docs/adapters for more information about adapters. 14 - adapter: adapter() 15 - } 9 + kit: { adapter: adapter() } 16 10 }; 17 11 18 12 export default config;