diff --git a/components.json b/components.json
new file mode 100644
index 0000000..1e6a638
--- /dev/null
+++ b/components.json
@@ -0,0 +1,16 @@
+{
+ "$schema": "https://shadcn-svelte.com/schema.json",
+ "tailwind": {
+ "css": "src/routes/layout.css",
+ "baseColor": "neutral"
+ },
+ "aliases": {
+ "components": "$lib/components",
+ "utils": "$lib/utils",
+ "ui": "$lib/components/ui",
+ "hooks": "$lib/hooks",
+ "lib": "$lib"
+ },
+ "typescript": true,
+ "registry": "https://shadcn-svelte.com/registry"
+}
diff --git a/package.json b/package.json
index 812044b..b37068f 100644
--- a/package.json
+++ b/package.json
@@ -17,17 +17,24 @@
"db:studio": "drizzle-kit studio"
},
"devDependencies": {
+ "@internationalized/date": "^3.11.0",
+ "@lucide/svelte": "^0.561.0",
"@sveltejs/adapter-node": "^5.5.2",
"@sveltejs/kit": "^2.50.1",
"@sveltejs/vite-plugin-svelte": "^6.2.4",
"@tailwindcss/forms": "^0.5.11",
"@tailwindcss/vite": "^4.1.18",
"@types/node": "^22",
+ "bits-ui": "^2.15.5",
+ "clsx": "^2.1.1",
"drizzle-kit": "^0.31.8",
"drizzle-orm": "^0.45.1",
"svelte": "^5.48.2",
"svelte-check": "^4.3.5",
+ "tailwind-merge": "^3.4.0",
+ "tailwind-variants": "^3.2.2",
"tailwindcss": "^4.1.18",
+ "tw-animate-css": "^1.4.0",
"typescript": "^5.9.3",
"vite": "^7.3.1"
},
@@ -41,6 +48,7 @@
"@tiptap/pm": "^3.18.0",
"@tiptap/starter-kit": "^3.18.0",
"marked": "^17.0.1",
+ "mode-watcher": "^1.1.0",
"postgres": "^3.4.8",
"tiptap": "^1.32.2"
}
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index e966e63..9488228 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -35,6 +35,9 @@ importers:
marked:
specifier: ^17.0.1
version: 17.0.1
+ mode-watcher:
+ specifier: ^1.1.0
+ version: 1.1.0(svelte@5.49.0)
postgres:
specifier: ^3.4.8
version: 3.4.8
@@ -42,6 +45,12 @@ importers:
specifier: ^1.32.2
version: 1.32.2(vue-template-compiler@2.7.16)(vue@2.7.16)
devDependencies:
+ '@internationalized/date':
+ specifier: ^3.11.0
+ version: 3.11.0
+ '@lucide/svelte':
+ specifier: ^0.561.0
+ version: 0.561.0(svelte@5.49.0)
'@sveltejs/adapter-node':
specifier: ^5.5.2
version: 5.5.2(@sveltejs/kit@2.50.1(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.49.0)(vite@7.3.1(@types/node@22.19.7)(jiti@2.6.1)(lightningcss@1.30.2)))(svelte@5.49.0)(typescript@5.9.3)(vite@7.3.1(@types/node@22.19.7)(jiti@2.6.1)(lightningcss@1.30.2)))
@@ -60,6 +69,12 @@ importers:
'@types/node':
specifier: ^22
version: 22.19.7
+ bits-ui:
+ specifier: ^2.15.5
+ version: 2.15.5(@internationalized/date@3.11.0)(@sveltejs/kit@2.50.1(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.49.0)(vite@7.3.1(@types/node@22.19.7)(jiti@2.6.1)(lightningcss@1.30.2)))(svelte@5.49.0)(typescript@5.9.3)(vite@7.3.1(@types/node@22.19.7)(jiti@2.6.1)(lightningcss@1.30.2)))(svelte@5.49.0)
+ clsx:
+ specifier: ^2.1.1
+ version: 2.1.1
drizzle-kit:
specifier: ^0.31.8
version: 0.31.8
@@ -72,9 +87,18 @@ importers:
svelte-check:
specifier: ^4.3.5
version: 4.3.5(picomatch@4.0.3)(svelte@5.49.0)(typescript@5.9.3)
+ tailwind-merge:
+ specifier: ^3.4.0
+ version: 3.4.0
+ tailwind-variants:
+ specifier: ^3.2.2
+ version: 3.2.2(tailwind-merge@3.4.0)(tailwindcss@4.1.18)
tailwindcss:
specifier: ^4.1.18
version: 4.1.18
+ tw-animate-css:
+ specifier: ^1.4.0
+ version: 1.4.0
typescript:
specifier: ^5.9.3
version: 5.9.3
@@ -578,6 +602,9 @@ packages:
peerDependencies:
'@fullcalendar/core': ~6.1.20
+ '@internationalized/date@3.11.0':
+ resolution: {integrity: sha512-BOx5huLAWhicM9/ZFs84CzP+V3gBW6vlpM02yzsdYC7TGlZJX1OJiEEHcSayF00Z+3jLlm4w79amvSt6RqKN3Q==}
+
'@jridgewell/gen-mapping@0.3.13':
resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==}
@@ -594,6 +621,11 @@ packages:
'@jridgewell/trace-mapping@0.3.31':
resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==}
+ '@lucide/svelte@0.561.0':
+ resolution: {integrity: sha512-vofKV2UFVrKE6I4ewKJ3dfCXSV6iP6nWVmiM83MLjsU91EeJcEg7LoWUABLp/aOTxj1HQNbJD1f3g3L0JQgH9A==}
+ peerDependencies:
+ svelte: ^5
+
'@polka/url@1.0.0-next.29':
resolution: {integrity: sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==}
@@ -805,6 +837,9 @@ packages:
svelte: ^5.0.0
vite: ^6.3.0 || ^7.0.0
+ '@swc/helpers@0.5.18':
+ resolution: {integrity: sha512-TXTnIcNJQEKwThMMqBXsZ4VGAza6bvN4pa41Rkqoio6QBKMvo+5lexeTMScGCIxtzgQJzElcvIltani+adC5PQ==}
+
'@tailwindcss/forms@0.5.11':
resolution: {integrity: sha512-h9wegbZDPurxG22xZSoWtdzc41/OlNEUQERNqI/0fOwa2aVlWGu7C35E/x6LDyD3lgtztFSSjKZyuVM0hxhbgA==}
peerDependencies:
@@ -1085,6 +1120,13 @@ packages:
resolution: {integrity: sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==}
engines: {node: '>= 0.4'}
+ bits-ui@2.15.5:
+ resolution: {integrity: sha512-WhS+P+E//ClLfKU6KqjKC17nGDRLnz+vkwoP6ClFUPd5m1fFVDxTElPX8QVsduLj5V1KFDxlnv6sW2G5Lqk+vw==}
+ engines: {node: '>=20'}
+ peerDependencies:
+ '@internationalized/date': ^3.8.1
+ svelte: ^5.33.0
+
buffer-from@1.1.2:
resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==}
@@ -1125,6 +1167,10 @@ packages:
resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==}
engines: {node: '>=0.10.0'}
+ dequal@2.0.3:
+ resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==}
+ engines: {node: '>=6'}
+
detect-libc@2.1.2:
resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==}
engines: {node: '>=8'}
@@ -1304,6 +1350,9 @@ packages:
resolution: {integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==}
hasBin: true
+ inline-style-parser@0.2.7:
+ resolution: {integrity: sha512-Nb2ctOyNR8DqQoR0OwRG95uNWIC0C1lCgf5Naz5H6Ji72KZ8OcFZLz2P5sNgwlyoJ8Yif11oMuYs5pBQa86csA==}
+
is-core-module@2.16.1:
resolution: {integrity: sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==}
engines: {node: '>= 0.4'}
@@ -1404,6 +1453,10 @@ packages:
locate-character@3.0.0:
resolution: {integrity: sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA==}
+ lz-string@1.5.0:
+ resolution: {integrity: sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==}
+ hasBin: true
+
magic-string@0.30.21:
resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==}
@@ -1423,6 +1476,11 @@ packages:
resolution: {integrity: sha512-r9deDe9p5FJUPZAk3A59wGH7Ii9YrjjWw0jmw/liSbHl2CHiyXj6FcDXDu2K3TjVAXqiJdaw3xxwlZZr9E6nHg==}
hasBin: true
+ mode-watcher@1.1.0:
+ resolution: {integrity: sha512-mUT9RRGPDYenk59qJauN1rhsIMKBmWA3xMF+uRwE8MW/tjhaDSCCARqkSuDTq8vr4/2KcAxIGVjACxTjdk5C3g==}
+ peerDependencies:
+ svelte: ^5.27.0
+
mri@1.2.0:
resolution: {integrity: sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==}
engines: {node: '>=4'}
@@ -1553,6 +1611,25 @@ packages:
rope-sequence@1.3.4:
resolution: {integrity: sha512-UT5EDe2cu2E/6O4igUr5PSFs23nvvukicWHx6GnOPlHAiiYbzNuCRQCuiUdHJQcqKalLKlrYJnjY0ySGsXNQXQ==}
+ runed@0.23.4:
+ resolution: {integrity: sha512-9q8oUiBYeXIDLWNK5DfCWlkL0EW3oGbk845VdKlPeia28l751VpfesaB/+7pI6rnbx1I6rqoZ2fZxptOJLxILA==}
+ peerDependencies:
+ svelte: ^5.7.0
+
+ runed@0.25.0:
+ resolution: {integrity: sha512-7+ma4AG9FT2sWQEA0Egf6mb7PBT2vHyuHail1ie8ropfSjvZGtEAx8YTmUjv/APCsdRRxEVvArNjALk9zFSOrg==}
+ peerDependencies:
+ svelte: ^5.7.0
+
+ runed@0.35.1:
+ resolution: {integrity: sha512-2F4Q/FZzbeJTFdIS/PuOoPRSm92sA2LhzTnv6FXhCoENb3huf5+fDuNOg1LNvGOouy3u/225qxmuJvcV3IZK5Q==}
+ peerDependencies:
+ '@sveltejs/kit': ^2.21.0
+ svelte: ^5.7.0
+ peerDependenciesMeta:
+ '@sveltejs/kit':
+ optional: true
+
sade@1.8.1:
resolution: {integrity: sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==}
engines: {node: '>=6'}
@@ -1575,6 +1652,9 @@ packages:
resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==}
engines: {node: '>=0.10.0'}
+ style-to-object@1.0.14:
+ resolution: {integrity: sha512-LIN7rULI0jBscWQYaSswptyderlarFkjQ+t79nzty8tcIAceVomEVlLzH5VP4Cmsv6MtKhs7qaAiwlcp+Mgaxw==}
+
supports-preserve-symlinks-flag@1.0.0:
resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==}
engines: {node: '>= 0.4'}
@@ -1587,10 +1667,38 @@ packages:
svelte: ^4.0.0 || ^5.0.0-next.0
typescript: '>=5.0.0'
+ svelte-toolbelt@0.10.6:
+ resolution: {integrity: sha512-YWuX+RE+CnWYx09yseAe4ZVMM7e7GRFZM6OYWpBKOb++s+SQ8RBIMMe+Bs/CznBMc0QPLjr+vDBxTAkozXsFXQ==}
+ engines: {node: '>=18', pnpm: '>=8.7.0'}
+ peerDependencies:
+ svelte: ^5.30.2
+
+ svelte-toolbelt@0.7.1:
+ resolution: {integrity: sha512-HcBOcR17Vx9bjaOceUvxkY3nGmbBmCBBbuWLLEWO6jtmWH8f/QoWmbyUfQZrpDINH39en1b8mptfPQT9VKQ1xQ==}
+ engines: {node: '>=18', pnpm: '>=8.7.0'}
+ peerDependencies:
+ svelte: ^5.0.0
+
svelte@5.49.0:
resolution: {integrity: sha512-Fn2mCc3XX0gnnbBYzWOTrZHi5WnF9KvqmB1+KGlUWoJkdioPmFYtg2ALBr6xl2dcnFTz3Vi7/mHpbKSVg/imVg==}
engines: {node: '>=18'}
+ tabbable@6.4.0:
+ resolution: {integrity: sha512-05PUHKSNE8ou2dwIxTngl4EzcnsCDZGJ/iCLtDflR/SHB/ny14rXc+qU5P4mG9JkusiV7EivzY9Mhm55AzAvCg==}
+
+ tailwind-merge@3.4.0:
+ resolution: {integrity: sha512-uSaO4gnW+b3Y2aWoWfFpX62vn2sR3skfhbjsEnaBI81WD1wBLlHZe5sWf0AqjksNdYTbGBEd0UasQMT3SNV15g==}
+
+ tailwind-variants@3.2.2:
+ resolution: {integrity: sha512-Mi4kHeMTLvKlM98XPnK+7HoBPmf4gygdFmqQPaDivc3DpYS6aIY6KiG/PgThrGvii5YZJqRsPz0aPyhoFzmZgg==}
+ engines: {node: '>=16.x', pnpm: '>=7.x'}
+ peerDependencies:
+ tailwind-merge: '>=3.0.0'
+ tailwindcss: '*'
+ peerDependenciesMeta:
+ tailwind-merge:
+ optional: true
+
tailwindcss@4.1.18:
resolution: {integrity: sha512-4+Z+0yiYyEtUVCScyfHCxOYP06L5Ne+JiHhY2IjR2KWMIWhJOYZKLSGZaP5HkZ8+bY0cxfzwDE5uOmzFXyIwxw==}
@@ -1618,6 +1726,12 @@ packages:
resolution: {integrity: sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==}
engines: {node: '>=6'}
+ tslib@2.8.1:
+ resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==}
+
+ tw-animate-css@1.4.0:
+ resolution: {integrity: sha512-7bziOlRqH0hJx80h/3mbicLW7o8qLsH5+RaLR2t+OHM3D0JlWGODQKQ4cxbK7WlvmUxpcj6Kgu6EKqjrGFe3QQ==}
+
typescript@5.9.3:
resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==}
engines: {node: '>=14.17'}
@@ -1979,6 +2093,10 @@ snapshots:
'@fullcalendar/core': 6.1.20
'@fullcalendar/daygrid': 6.1.20(@fullcalendar/core@6.1.20)
+ '@internationalized/date@3.11.0':
+ dependencies:
+ '@swc/helpers': 0.5.18
+
'@jridgewell/gen-mapping@0.3.13':
dependencies:
'@jridgewell/sourcemap-codec': 1.5.5
@@ -1998,6 +2116,10 @@ snapshots:
'@jridgewell/resolve-uri': 3.1.2
'@jridgewell/sourcemap-codec': 1.5.5
+ '@lucide/svelte@0.561.0(svelte@5.49.0)':
+ dependencies:
+ svelte: 5.49.0
+
'@polka/url@1.0.0-next.29': {}
'@remirror/core-constants@3.0.0': {}
@@ -2165,6 +2287,10 @@ snapshots:
vite: 7.3.1(@types/node@22.19.7)(jiti@2.6.1)(lightningcss@1.30.2)
vitefu: 1.1.1(vite@7.3.1(@types/node@22.19.7)(jiti@2.6.1)(lightningcss@1.30.2))
+ '@swc/helpers@0.5.18':
+ dependencies:
+ tslib: 2.8.1
+
'@tailwindcss/forms@0.5.11(tailwindcss@4.1.18)':
dependencies:
mini-svg-data-uri: 1.4.4
@@ -2437,6 +2563,19 @@ snapshots:
axobject-query@4.1.0: {}
+ bits-ui@2.15.5(@internationalized/date@3.11.0)(@sveltejs/kit@2.50.1(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.49.0)(vite@7.3.1(@types/node@22.19.7)(jiti@2.6.1)(lightningcss@1.30.2)))(svelte@5.49.0)(typescript@5.9.3)(vite@7.3.1(@types/node@22.19.7)(jiti@2.6.1)(lightningcss@1.30.2)))(svelte@5.49.0):
+ dependencies:
+ '@floating-ui/core': 1.7.4
+ '@floating-ui/dom': 1.7.5
+ '@internationalized/date': 3.11.0
+ esm-env: 1.2.2
+ runed: 0.35.1(@sveltejs/kit@2.50.1(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.49.0)(vite@7.3.1(@types/node@22.19.7)(jiti@2.6.1)(lightningcss@1.30.2)))(svelte@5.49.0)(typescript@5.9.3)(vite@7.3.1(@types/node@22.19.7)(jiti@2.6.1)(lightningcss@1.30.2)))(svelte@5.49.0)
+ svelte: 5.49.0
+ svelte-toolbelt: 0.10.6(@sveltejs/kit@2.50.1(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.49.0)(vite@7.3.1(@types/node@22.19.7)(jiti@2.6.1)(lightningcss@1.30.2)))(svelte@5.49.0)(typescript@5.9.3)(vite@7.3.1(@types/node@22.19.7)(jiti@2.6.1)(lightningcss@1.30.2)))(svelte@5.49.0)
+ tabbable: 6.4.0
+ transitivePeerDependencies:
+ - '@sveltejs/kit'
+
buffer-from@1.1.2: {}
chokidar@4.0.3:
@@ -2461,6 +2600,8 @@ snapshots:
deepmerge@4.3.1: {}
+ dequal@2.0.3: {}
+
detect-libc@2.1.2: {}
devalue@5.6.2: {}
@@ -2618,6 +2759,8 @@ snapshots:
he@1.2.0: {}
+ inline-style-parser@0.2.7: {}
+
is-core-module@2.16.1:
dependencies:
hasown: 2.0.2
@@ -2693,6 +2836,8 @@ snapshots:
locate-character@3.0.0: {}
+ lz-string@1.5.0: {}
+
magic-string@0.30.21:
dependencies:
'@jridgewell/sourcemap-codec': 1.5.5
@@ -2712,6 +2857,12 @@ snapshots:
mini-svg-data-uri@1.4.4: {}
+ mode-watcher@1.1.0(svelte@5.49.0):
+ dependencies:
+ runed: 0.25.0(svelte@5.49.0)
+ svelte: 5.49.0
+ svelte-toolbelt: 0.7.1(svelte@5.49.0)
+
mri@1.2.0: {}
mrmime@2.0.1: {}
@@ -2891,6 +3042,25 @@ snapshots:
rope-sequence@1.3.4: {}
+ runed@0.23.4(svelte@5.49.0):
+ dependencies:
+ esm-env: 1.2.2
+ svelte: 5.49.0
+
+ runed@0.25.0(svelte@5.49.0):
+ dependencies:
+ esm-env: 1.2.2
+ svelte: 5.49.0
+
+ runed@0.35.1(@sveltejs/kit@2.50.1(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.49.0)(vite@7.3.1(@types/node@22.19.7)(jiti@2.6.1)(lightningcss@1.30.2)))(svelte@5.49.0)(typescript@5.9.3)(vite@7.3.1(@types/node@22.19.7)(jiti@2.6.1)(lightningcss@1.30.2)))(svelte@5.49.0):
+ dependencies:
+ dequal: 2.0.3
+ esm-env: 1.2.2
+ lz-string: 1.5.0
+ svelte: 5.49.0
+ optionalDependencies:
+ '@sveltejs/kit': 2.50.1(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.49.0)(vite@7.3.1(@types/node@22.19.7)(jiti@2.6.1)(lightningcss@1.30.2)))(svelte@5.49.0)(typescript@5.9.3)(vite@7.3.1(@types/node@22.19.7)(jiti@2.6.1)(lightningcss@1.30.2))
+
sade@1.8.1:
dependencies:
mri: 1.2.0
@@ -2912,6 +3082,10 @@ snapshots:
source-map@0.6.1: {}
+ style-to-object@1.0.14:
+ dependencies:
+ inline-style-parser: 0.2.7
+
supports-preserve-symlinks-flag@1.0.0: {}
svelte-check@4.3.5(picomatch@4.0.3)(svelte@5.49.0)(typescript@5.9.3):
@@ -2926,6 +3100,22 @@ snapshots:
transitivePeerDependencies:
- picomatch
+ svelte-toolbelt@0.10.6(@sveltejs/kit@2.50.1(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.49.0)(vite@7.3.1(@types/node@22.19.7)(jiti@2.6.1)(lightningcss@1.30.2)))(svelte@5.49.0)(typescript@5.9.3)(vite@7.3.1(@types/node@22.19.7)(jiti@2.6.1)(lightningcss@1.30.2)))(svelte@5.49.0):
+ dependencies:
+ clsx: 2.1.1
+ runed: 0.35.1(@sveltejs/kit@2.50.1(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.49.0)(vite@7.3.1(@types/node@22.19.7)(jiti@2.6.1)(lightningcss@1.30.2)))(svelte@5.49.0)(typescript@5.9.3)(vite@7.3.1(@types/node@22.19.7)(jiti@2.6.1)(lightningcss@1.30.2)))(svelte@5.49.0)
+ style-to-object: 1.0.14
+ svelte: 5.49.0
+ transitivePeerDependencies:
+ - '@sveltejs/kit'
+
+ svelte-toolbelt@0.7.1(svelte@5.49.0):
+ dependencies:
+ clsx: 2.1.1
+ runed: 0.23.4(svelte@5.49.0)
+ style-to-object: 1.0.14
+ svelte: 5.49.0
+
svelte@5.49.0:
dependencies:
'@jridgewell/remapping': 2.3.5
@@ -2944,6 +3134,16 @@ snapshots:
magic-string: 0.30.21
zimmerframe: 1.1.4
+ tabbable@6.4.0: {}
+
+ tailwind-merge@3.4.0: {}
+
+ tailwind-variants@3.2.2(tailwind-merge@3.4.0)(tailwindcss@4.1.18):
+ dependencies:
+ tailwindcss: 4.1.18
+ optionalDependencies:
+ tailwind-merge: 3.4.0
+
tailwindcss@4.1.18: {}
tapable@2.3.0: {}
@@ -2986,6 +3186,10 @@ snapshots:
totalist@3.0.1: {}
+ tslib@2.8.1: {}
+
+ tw-animate-css@1.4.0: {}
+
typescript@5.9.3: {}
uc.micro@2.1.0: {}
diff --git a/src/lib/components/ThemeModeButton.svelte b/src/lib/components/ThemeModeButton.svelte
new file mode 100644
index 0000000..20bfad5
--- /dev/null
+++ b/src/lib/components/ThemeModeButton.svelte
@@ -0,0 +1,17 @@
+
+
+
\ No newline at end of file
diff --git a/src/lib/components/calendar.svelte b/src/lib/components/calendar.svelte
index 46ba066..2d3dd33 100644
--- a/src/lib/components/calendar.svelte
+++ b/src/lib/components/calendar.svelte
@@ -1,309 +1,67 @@
-
-
-
-
- {#each days as day, index}
-
- {/each}
-
-
-
-
+
+ {#snippet day({ day })}
+
+ {@const img = getImageForDate(day)}
+ {#if img}
+
+ {/if}
+ {day.day}
+
+ {/snippet}
+
diff --git a/src/lib/components/editor.svelte b/src/lib/components/editor.svelte
new file mode 100644
index 0000000..62f0518
--- /dev/null
+++ b/src/lib/components/editor.svelte
@@ -0,0 +1,319 @@
+
+
+
+
+
+
{formatDate(entry.date)}
+
+
+ {#if !edit}
+
+ {:else}
+
+
+
+ {/if}
+
+
+
+
+ {#if error}
+
+ {error}
+
+ {/if}
+
+
+ {#if !edit}
+
+
+ {#if entry.image}
+
+ {:else}
+
+ No image
+
+ {/if}
+
+
+ {#if entry.content}
+
+ {:else}
+
+ No content yet
+
+ {/if}
+
+
+
+ {:else}
+
+
+
+
+
+ {#if previewImage}
+
+ {:else}
+
{
+ if (e.key === "Enter" || e.key === " ") {
+ fileInput?.click();
+ }
+ }}
+ onclick={() => fileInput?.click()}
+ >
+
+
+ Click to upload or drag and drop
+
+
+ PNG, JPG, GIF up to 5MB
+
+
+ {/if}
+
+
+
+
+
+
+
+
+
+ {editingEntry.content.length} characters
+
+
+
+ {/if}
+
diff --git a/src/lib/components/entrySummaryView.svelte b/src/lib/components/entrySummaryView.svelte
index f0e0a75..cdf394f 100644
--- a/src/lib/components/entrySummaryView.svelte
+++ b/src/lib/components/entrySummaryView.svelte
@@ -1,24 +1,36 @@
-
+
\ No newline at end of file
diff --git a/src/lib/components/header.svelte b/src/lib/components/header.svelte
index 17289f5..2cc387a 100644
--- a/src/lib/components/header.svelte
+++ b/src/lib/components/header.svelte
@@ -1,3 +1,9 @@
+
+
\ No newline at end of file
diff --git a/src/lib/components/ui/button/button.svelte b/src/lib/components/ui/button/button.svelte
new file mode 100644
index 0000000..a8296ae
--- /dev/null
+++ b/src/lib/components/ui/button/button.svelte
@@ -0,0 +1,82 @@
+
+
+
+
+{#if href}
+
+ {@render children?.()}
+
+{:else}
+
+{/if}
diff --git a/src/lib/components/ui/button/index.ts b/src/lib/components/ui/button/index.ts
new file mode 100644
index 0000000..fb585d7
--- /dev/null
+++ b/src/lib/components/ui/button/index.ts
@@ -0,0 +1,17 @@
+import Root, {
+ type ButtonProps,
+ type ButtonSize,
+ type ButtonVariant,
+ buttonVariants,
+} from "./button.svelte";
+
+export {
+ Root,
+ type ButtonProps as Props,
+ //
+ Root as Button,
+ buttonVariants,
+ type ButtonProps,
+ type ButtonSize,
+ type ButtonVariant,
+};
diff --git a/src/lib/components/ui/calendar/calendar-caption.svelte b/src/lib/components/ui/calendar/calendar-caption.svelte
new file mode 100644
index 0000000..5c93037
--- /dev/null
+++ b/src/lib/components/ui/calendar/calendar-caption.svelte
@@ -0,0 +1,76 @@
+
+
+{#snippet MonthSelect()}
+ {
+ if (!placeholder) return;
+ const v = Number.parseInt(e.currentTarget.value);
+ const newPlaceholder = placeholder.set({ month: v });
+ placeholder = newPlaceholder.subtract({ months: monthIndex });
+ }}
+ />
+{/snippet}
+
+{#snippet YearSelect()}
+
+{/snippet}
+
+{#if captionLayout === "dropdown"}
+ {@render MonthSelect()}
+ {@render YearSelect()}
+{:else if captionLayout === "dropdown-months"}
+ {@render MonthSelect()}
+ {#if placeholder}
+ {formatYear(placeholder)}
+ {/if}
+{:else if captionLayout === "dropdown-years"}
+ {#if placeholder}
+ {formatMonth(placeholder)}
+ {/if}
+ {@render YearSelect()}
+{:else}
+ {formatMonth(month)} {formatYear(month)}
+{/if}
diff --git a/src/lib/components/ui/calendar/calendar-cell.svelte b/src/lib/components/ui/calendar/calendar-cell.svelte
new file mode 100644
index 0000000..441eb4a
--- /dev/null
+++ b/src/lib/components/ui/calendar/calendar-cell.svelte
@@ -0,0 +1,19 @@
+
+
+
diff --git a/src/lib/components/ui/calendar/calendar-day.svelte b/src/lib/components/ui/calendar/calendar-day.svelte
new file mode 100644
index 0000000..89664cf
--- /dev/null
+++ b/src/lib/components/ui/calendar/calendar-day.svelte
@@ -0,0 +1,35 @@
+
+
+span]:text-xs [&>span]:opacity-70",
+ className
+ )}
+ {...restProps}
+/>
diff --git a/src/lib/components/ui/calendar/calendar-grid-body.svelte b/src/lib/components/ui/calendar/calendar-grid-body.svelte
new file mode 100644
index 0000000..8cd86de
--- /dev/null
+++ b/src/lib/components/ui/calendar/calendar-grid-body.svelte
@@ -0,0 +1,12 @@
+
+
+
diff --git a/src/lib/components/ui/calendar/calendar-grid-head.svelte b/src/lib/components/ui/calendar/calendar-grid-head.svelte
new file mode 100644
index 0000000..333edc4
--- /dev/null
+++ b/src/lib/components/ui/calendar/calendar-grid-head.svelte
@@ -0,0 +1,12 @@
+
+
+
diff --git a/src/lib/components/ui/calendar/calendar-grid-row.svelte b/src/lib/components/ui/calendar/calendar-grid-row.svelte
new file mode 100644
index 0000000..e03aaf6
--- /dev/null
+++ b/src/lib/components/ui/calendar/calendar-grid-row.svelte
@@ -0,0 +1,12 @@
+
+
+
diff --git a/src/lib/components/ui/calendar/calendar-grid.svelte b/src/lib/components/ui/calendar/calendar-grid.svelte
new file mode 100644
index 0000000..e0c8627
--- /dev/null
+++ b/src/lib/components/ui/calendar/calendar-grid.svelte
@@ -0,0 +1,16 @@
+
+
+
diff --git a/src/lib/components/ui/calendar/calendar-head-cell.svelte b/src/lib/components/ui/calendar/calendar-head-cell.svelte
new file mode 100644
index 0000000..131807e
--- /dev/null
+++ b/src/lib/components/ui/calendar/calendar-head-cell.svelte
@@ -0,0 +1,19 @@
+
+
+
diff --git a/src/lib/components/ui/calendar/calendar-header.svelte b/src/lib/components/ui/calendar/calendar-header.svelte
new file mode 100644
index 0000000..c39e955
--- /dev/null
+++ b/src/lib/components/ui/calendar/calendar-header.svelte
@@ -0,0 +1,19 @@
+
+
+
diff --git a/src/lib/components/ui/calendar/calendar-heading.svelte b/src/lib/components/ui/calendar/calendar-heading.svelte
new file mode 100644
index 0000000..a9b9810
--- /dev/null
+++ b/src/lib/components/ui/calendar/calendar-heading.svelte
@@ -0,0 +1,16 @@
+
+
+
diff --git a/src/lib/components/ui/calendar/calendar-month-select.svelte b/src/lib/components/ui/calendar/calendar-month-select.svelte
new file mode 100644
index 0000000..664afab
--- /dev/null
+++ b/src/lib/components/ui/calendar/calendar-month-select.svelte
@@ -0,0 +1,48 @@
+
+
+
+
+ {#snippet child({ props, monthItems, selectedMonthItem })}
+
+
+ {monthItems.find((item) => item.value === value)?.label || selectedMonthItem.label}
+
+
+ {/snippet}
+
+
diff --git a/src/lib/components/ui/calendar/calendar-month.svelte b/src/lib/components/ui/calendar/calendar-month.svelte
new file mode 100644
index 0000000..f098396
--- /dev/null
+++ b/src/lib/components/ui/calendar/calendar-month.svelte
@@ -0,0 +1,15 @@
+
+
+
+ {@render children?.()}
+
diff --git a/src/lib/components/ui/calendar/calendar-months.svelte b/src/lib/components/ui/calendar/calendar-months.svelte
new file mode 100644
index 0000000..f717a9d
--- /dev/null
+++ b/src/lib/components/ui/calendar/calendar-months.svelte
@@ -0,0 +1,19 @@
+
+
+
+ {@render children?.()}
+
diff --git a/src/lib/components/ui/calendar/calendar-nav.svelte b/src/lib/components/ui/calendar/calendar-nav.svelte
new file mode 100644
index 0000000..27f33d7
--- /dev/null
+++ b/src/lib/components/ui/calendar/calendar-nav.svelte
@@ -0,0 +1,19 @@
+
+
+
diff --git a/src/lib/components/ui/calendar/calendar-next-button.svelte b/src/lib/components/ui/calendar/calendar-next-button.svelte
new file mode 100644
index 0000000..5c5a78d
--- /dev/null
+++ b/src/lib/components/ui/calendar/calendar-next-button.svelte
@@ -0,0 +1,31 @@
+
+
+{#snippet Fallback()}
+
+{/snippet}
+
+
diff --git a/src/lib/components/ui/calendar/calendar-prev-button.svelte b/src/lib/components/ui/calendar/calendar-prev-button.svelte
new file mode 100644
index 0000000..33cfd63
--- /dev/null
+++ b/src/lib/components/ui/calendar/calendar-prev-button.svelte
@@ -0,0 +1,31 @@
+
+
+{#snippet Fallback()}
+
+{/snippet}
+
+
diff --git a/src/lib/components/ui/calendar/calendar-year-select.svelte b/src/lib/components/ui/calendar/calendar-year-select.svelte
new file mode 100644
index 0000000..33cc961
--- /dev/null
+++ b/src/lib/components/ui/calendar/calendar-year-select.svelte
@@ -0,0 +1,47 @@
+
+
+
+
+ {#snippet child({ props, yearItems, selectedYearItem })}
+
+
+ {yearItems.find((item) => item.value === value)?.label || selectedYearItem.label}
+
+
+ {/snippet}
+
+
diff --git a/src/lib/components/ui/calendar/calendar.svelte b/src/lib/components/ui/calendar/calendar.svelte
new file mode 100644
index 0000000..2971f22
--- /dev/null
+++ b/src/lib/components/ui/calendar/calendar.svelte
@@ -0,0 +1,115 @@
+
+
+
+
+ {#snippet children({ months, weekdays })}
+
+
+
+
+
+ {#each months as month, monthIndex (month)}
+
+
+
+
+
+
+
+ {#each weekdays as weekday (weekday)}
+
+ {weekday.slice(0, 2)}
+
+ {/each}
+
+
+
+ {#each month.weeks as weekDates (weekDates)}
+
+ {#each weekDates as date (date)}
+
+ {#if day}
+ {@render day({
+ day: date,
+ outsideMonth: !isEqualMonth(date, month.value),
+ })}
+ {:else}
+
+ {/if}
+
+ {/each}
+
+ {/each}
+
+
+
+ {/each}
+
+ {/snippet}
+
diff --git a/src/lib/components/ui/calendar/index.ts b/src/lib/components/ui/calendar/index.ts
new file mode 100644
index 0000000..f3a16d2
--- /dev/null
+++ b/src/lib/components/ui/calendar/index.ts
@@ -0,0 +1,40 @@
+import Root from "./calendar.svelte";
+import Cell from "./calendar-cell.svelte";
+import Day from "./calendar-day.svelte";
+import Grid from "./calendar-grid.svelte";
+import Header from "./calendar-header.svelte";
+import Months from "./calendar-months.svelte";
+import GridRow from "./calendar-grid-row.svelte";
+import Heading from "./calendar-heading.svelte";
+import GridBody from "./calendar-grid-body.svelte";
+import GridHead from "./calendar-grid-head.svelte";
+import HeadCell from "./calendar-head-cell.svelte";
+import NextButton from "./calendar-next-button.svelte";
+import PrevButton from "./calendar-prev-button.svelte";
+import MonthSelect from "./calendar-month-select.svelte";
+import YearSelect from "./calendar-year-select.svelte";
+import Month from "./calendar-month.svelte";
+import Nav from "./calendar-nav.svelte";
+import Caption from "./calendar-caption.svelte";
+
+export {
+ Day,
+ Cell,
+ Grid,
+ Header,
+ Months,
+ GridRow,
+ Heading,
+ GridBody,
+ GridHead,
+ HeadCell,
+ NextButton,
+ PrevButton,
+ Nav,
+ Month,
+ YearSelect,
+ MonthSelect,
+ Caption,
+ //
+ Root as Calendar,
+};
diff --git a/src/lib/components/ui/input/index.ts b/src/lib/components/ui/input/index.ts
new file mode 100644
index 0000000..ed380dd
--- /dev/null
+++ b/src/lib/components/ui/input/index.ts
@@ -0,0 +1,2 @@
+export { default as Input } from "./input.svelte";
+export type { InputProps } from "./input.svelte";
diff --git a/src/lib/components/ui/input/input.svelte b/src/lib/components/ui/input/input.svelte
new file mode 100644
index 0000000..678dee7
--- /dev/null
+++ b/src/lib/components/ui/input/input.svelte
@@ -0,0 +1,25 @@
+
+
+
+
+
diff --git a/src/lib/components/ui/item/index.ts b/src/lib/components/ui/item/index.ts
new file mode 100644
index 0000000..168bc3e
--- /dev/null
+++ b/src/lib/components/ui/item/index.ts
@@ -0,0 +1,34 @@
+import Root from "./item.svelte";
+import Group from "./item-group.svelte";
+import Separator from "./item-separator.svelte";
+import Header from "./item-header.svelte";
+import Footer from "./item-footer.svelte";
+import Content from "./item-content.svelte";
+import Title from "./item-title.svelte";
+import Description from "./item-description.svelte";
+import Actions from "./item-actions.svelte";
+import Media from "./item-media.svelte";
+
+export {
+ Root,
+ Group,
+ Separator,
+ Header,
+ Footer,
+ Content,
+ Title,
+ Description,
+ Actions,
+ Media,
+ //
+ Root as Item,
+ Group as ItemGroup,
+ Separator as ItemSeparator,
+ Header as ItemHeader,
+ Footer as ItemFooter,
+ Content as ItemContent,
+ Title as ItemTitle,
+ Description as ItemDescription,
+ Actions as ItemActions,
+ Media as ItemMedia,
+};
diff --git a/src/lib/components/ui/item/item-actions.svelte b/src/lib/components/ui/item/item-actions.svelte
new file mode 100644
index 0000000..83a6bb2
--- /dev/null
+++ b/src/lib/components/ui/item/item-actions.svelte
@@ -0,0 +1,20 @@
+
+
+
+ {@render children?.()}
+
diff --git a/src/lib/components/ui/item/item-content.svelte b/src/lib/components/ui/item/item-content.svelte
new file mode 100644
index 0000000..55516f2
--- /dev/null
+++ b/src/lib/components/ui/item/item-content.svelte
@@ -0,0 +1,20 @@
+
+
+
+ {@render children?.()}
+
diff --git a/src/lib/components/ui/item/item-description.svelte b/src/lib/components/ui/item/item-description.svelte
new file mode 100644
index 0000000..65e6e7d
--- /dev/null
+++ b/src/lib/components/ui/item/item-description.svelte
@@ -0,0 +1,24 @@
+
+
+a:hover]:text-primary [&>a]:underline [&>a]:underline-offset-4",
+ className
+ )}
+ {...restProps}
+>
+ {@render children?.()}
+
diff --git a/src/lib/components/ui/item/item-footer.svelte b/src/lib/components/ui/item/item-footer.svelte
new file mode 100644
index 0000000..c998caa
--- /dev/null
+++ b/src/lib/components/ui/item/item-footer.svelte
@@ -0,0 +1,20 @@
+
+
+
+ {@render children?.()}
+
diff --git a/src/lib/components/ui/item/item-group.svelte b/src/lib/components/ui/item/item-group.svelte
new file mode 100644
index 0000000..57ebbd5
--- /dev/null
+++ b/src/lib/components/ui/item/item-group.svelte
@@ -0,0 +1,21 @@
+
+
+
+ {@render children?.()}
+
diff --git a/src/lib/components/ui/item/item-header.svelte b/src/lib/components/ui/item/item-header.svelte
new file mode 100644
index 0000000..1afe1fa
--- /dev/null
+++ b/src/lib/components/ui/item/item-header.svelte
@@ -0,0 +1,20 @@
+
+
+
+ {@render children?.()}
+
diff --git a/src/lib/components/ui/item/item-media.svelte b/src/lib/components/ui/item/item-media.svelte
new file mode 100644
index 0000000..78490fd
--- /dev/null
+++ b/src/lib/components/ui/item/item-media.svelte
@@ -0,0 +1,42 @@
+
+
+
+
+
+ {@render children?.()}
+
diff --git a/src/lib/components/ui/item/item-separator.svelte b/src/lib/components/ui/item/item-separator.svelte
new file mode 100644
index 0000000..6f2f51a
--- /dev/null
+++ b/src/lib/components/ui/item/item-separator.svelte
@@ -0,0 +1,19 @@
+
+
+
diff --git a/src/lib/components/ui/item/item-title.svelte b/src/lib/components/ui/item/item-title.svelte
new file mode 100644
index 0000000..8d13d5e
--- /dev/null
+++ b/src/lib/components/ui/item/item-title.svelte
@@ -0,0 +1,20 @@
+
+
+
+ {@render children?.()}
+
diff --git a/src/lib/components/ui/item/item.svelte b/src/lib/components/ui/item/item.svelte
new file mode 100644
index 0000000..77f8ce6
--- /dev/null
+++ b/src/lib/components/ui/item/item.svelte
@@ -0,0 +1,60 @@
+
+
+
+
+{#if child}
+ {@render child({ props: mergedProps })}
+{:else}
+
+ {@render mergedProps.children?.()}
+
+{/if}
diff --git a/src/lib/components/ui/separator/index.ts b/src/lib/components/ui/separator/index.ts
new file mode 100644
index 0000000..82442d2
--- /dev/null
+++ b/src/lib/components/ui/separator/index.ts
@@ -0,0 +1,7 @@
+import Root from "./separator.svelte";
+
+export {
+ Root,
+ //
+ Root as Separator,
+};
diff --git a/src/lib/components/ui/separator/separator.svelte b/src/lib/components/ui/separator/separator.svelte
new file mode 100644
index 0000000..f40999f
--- /dev/null
+++ b/src/lib/components/ui/separator/separator.svelte
@@ -0,0 +1,21 @@
+
+
+
diff --git a/src/lib/components/ui/textarea/index.ts b/src/lib/components/ui/textarea/index.ts
new file mode 100644
index 0000000..9cfe382
--- /dev/null
+++ b/src/lib/components/ui/textarea/index.ts
@@ -0,0 +1,2 @@
+export { default as Textarea } from "./textarea.svelte";
+export type { TextareaProps } from "./textarea.svelte";
diff --git a/src/lib/components/ui/textarea/textarea.svelte b/src/lib/components/ui/textarea/textarea.svelte
new file mode 100644
index 0000000..d671e1b
--- /dev/null
+++ b/src/lib/components/ui/textarea/textarea.svelte
@@ -0,0 +1,28 @@
+
+
+
+
+
diff --git a/src/lib/server/db/schema.ts b/src/lib/server/db/schema.ts
index f62c925..2bd1ecc 100644
--- a/src/lib/server/db/schema.ts
+++ b/src/lib/server/db/schema.ts
@@ -1,8 +1,8 @@
-import { text, integer, pgTable, json, timestamp } from "drizzle-orm/pg-core";
+import { text, integer, pgTable, json, date } from "drizzle-orm/pg-core";
export const entryTable = pgTable("entries", {
id: integer().primaryKey().generatedAlwaysAsIdentity(),
- date: timestamp({ mode: 'date', withTimezone: true }).notNull().defaultNow(),
+ date: date().notNull().defaultNow(),
location: json(),
content: text(),
image: text()
diff --git a/src/lib/upload.ts b/src/lib/upload.ts
index 909a120..9f2aac9 100644
--- a/src/lib/upload.ts
+++ b/src/lib/upload.ts
@@ -55,3 +55,13 @@ export async function updateEntry(entry) {
body: JSON.stringify(entry),
});
}
+
+export async function deleteEntry(entry) {
+ await fetch(`/api/entry/delete`, {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json'
+ },
+ body: JSON.stringify({ id: entry.id })
+ });
+}
\ No newline at end of file
diff --git a/src/lib/utils.ts b/src/lib/utils.ts
new file mode 100644
index 0000000..55b3a91
--- /dev/null
+++ b/src/lib/utils.ts
@@ -0,0 +1,13 @@
+import { clsx, type ClassValue } from "clsx";
+import { twMerge } from "tailwind-merge";
+
+export function cn(...inputs: ClassValue[]) {
+ return twMerge(clsx(inputs));
+}
+
+// eslint-disable-next-line @typescript-eslint/no-explicit-any
+export type WithoutChild = T extends { child?: any } ? Omit : T;
+// eslint-disable-next-line @typescript-eslint/no-explicit-any
+export type WithoutChildren = T extends { children?: any } ? Omit : T;
+export type WithoutChildrenOrChild = WithoutChildren>;
+export type WithElementRef = T & { ref?: U | null };
diff --git a/src/params/date.ts b/src/params/date.ts
new file mode 100644
index 0000000..810216e
--- /dev/null
+++ b/src/params/date.ts
@@ -0,0 +1,4 @@
+
+export function match(value) {
+ return /^\d{4}-\d{2}-\d{2}$/.test(value)
+}
\ No newline at end of file
diff --git a/src/routes/+layout.svelte b/src/routes/+layout.svelte
index 7ad0b04..726b0ea 100644
--- a/src/routes/+layout.svelte
+++ b/src/routes/+layout.svelte
@@ -1,14 +1,59 @@
-
+
+ {title}
+
+
+
-
-
- {@render children()}
+
+
+
+
+ {#key dateValue}
+ {@render children()}
+ {/key}
+
+
+
+
+
+ {#each entries as entry}
+
+ {/each}
+
+
diff --git a/src/routes/+layout.ts b/src/routes/+layout.ts
new file mode 100644
index 0000000..f36ae19
--- /dev/null
+++ b/src/routes/+layout.ts
@@ -0,0 +1,22 @@
+import { today, getLocalTimeZone, CalendarDate } from "@internationalized/date";
+
+export async function load({ params, fetch }) {
+ let dateValue;
+
+ if (params.date) {
+ const [year, month, day] = params.date.split("-").map(Number);
+ dateValue = new CalendarDate(year, month, day);
+ } else {
+ dateValue = today(getLocalTimeZone());
+ }
+
+ const res = await fetch(
+ `/api/entry?month=${dateValue.year}-${dateValue.month}`,
+ );
+ const entries = await res.json();
+
+ return {
+ entries: entries,
+ date: dateValue,
+ };
+}
diff --git a/src/routes/+page.svelte b/src/routes/+page.svelte
index bb3f765..a33d3d9 100644
--- a/src/routes/+page.svelte
+++ b/src/routes/+page.svelte
@@ -1,54 +1,43 @@
-
+
-
+
+ Click on a date to view or edit an entry.
+
+
+
+
diff --git a/src/routes/+page.ts b/src/routes/+page.ts
deleted file mode 100644
index 5b64fe7..0000000
--- a/src/routes/+page.ts
+++ /dev/null
@@ -1,13 +0,0 @@
-export const load = async ({ fetch, params }) => {
- const res = await fetch("/api/entry/all");
- const allEntries = await res.json();
-
- const today = new Date().toISOString().split('T')[0];
- const todayEntry = await fetch(`/api/entry?date=${today}`);
- const todayEntryData = await todayEntry.json();
-
- return {
- all: allEntries,
- today: todayEntryData,
- };
-};
diff --git a/src/routes/[date=date]/+page.svelte b/src/routes/[date=date]/+page.svelte
new file mode 100644
index 0000000..a438931
--- /dev/null
+++ b/src/routes/[date=date]/+page.svelte
@@ -0,0 +1,10 @@
+
+
+
\ No newline at end of file
diff --git a/src/routes/[date=date]/+page.ts b/src/routes/[date=date]/+page.ts
new file mode 100644
index 0000000..ab1af8c
--- /dev/null
+++ b/src/routes/[date=date]/+page.ts
@@ -0,0 +1,6 @@
+
+export async function load({ params, fetch }) {
+ const res = await fetch(`/api/entry?date=${params.date}`);
+ const entries = await res.json();
+ return { entry: entries[0] };
+}
diff --git a/src/routes/api/entry/+server.ts b/src/routes/api/entry/+server.ts
index da28694..c0992e0 100644
--- a/src/routes/api/entry/+server.ts
+++ b/src/routes/api/entry/+server.ts
@@ -61,7 +61,7 @@ async function getEntryByMonth(monthString: string) {
const endDate = new Date(year, month, 1, 0, 0, 0, 0)
const entries = await db.select().from(entryTable).where(
- sql`${entryTable.date} >= ${startDate.toISOString()}::timestamp AND ${entryTable.date} < ${endDate.toISOString()}::timestamp`
+ sql`${entryTable.date} >= ${startDate.toISOString()}::timestamp AND ${entryTable.date} < ${endDate.toISOString()}::timestamp ORDER BY ${entryTable.date} DESC`
)
return httpResponse(entries, 200)
diff --git a/src/routes/api/entry/new/+server.ts b/src/routes/api/entry/new/+server.ts
index d422e9c..062fced 100644
--- a/src/routes/api/entry/new/+server.ts
+++ b/src/routes/api/entry/new/+server.ts
@@ -9,7 +9,6 @@ export async function POST({ request }) {
try {
const body = await request.json();
const entry: typeof entryTable.$inferInsert = body
- entry.date = new Date(body.date)
await db.insert(entryTable).values(entry)
diff --git a/src/routes/layout.css b/src/routes/layout.css
index 613cb8b..afdb0f3 100644
--- a/src/routes/layout.css
+++ b/src/routes/layout.css
@@ -1,16 +1,121 @@
-@import 'tailwindcss';
-@plugin '@tailwindcss/forms';
+@import "tailwindcss";
-/*@import 'quill/dist/quill.core.css';
-@import 'quill/dist/quill.bubble.css';
-@import 'quill/dist/quill.snow.css';*/
+@import "tw-animate-css";
-html {
- @apply py-3 px-4;
- @apply bg-[#252525] text-white
+@custom-variant dark (&:is(.dark *));
+
+:root {
+ --radius: 0.625rem;
+ --background: oklch(1 0 0);
+ --foreground: oklch(0.145 0 0);
+ --card: oklch(1 0 0);
+ --card-foreground: oklch(0.145 0 0);
+ --popover: oklch(1 0 0);
+ --popover-foreground: oklch(0.145 0 0);
+ --primary: oklch(0.205 0 0);
+ --primary-foreground: oklch(0.985 0 0);
+ --secondary: oklch(0.97 0 0);
+ --secondary-foreground: oklch(0.205 0 0);
+ --muted: oklch(0.97 0 0);
+ --muted-foreground: oklch(0.556 0 0);
+ --accent: oklch(0.97 0 0);
+ --accent-foreground: oklch(0.205 0 0);
+--destructive: oklch(0.577 0.245 27.325);
+ --border: oklch(0.922 0 0);
+ --input: oklch(0.922 0 0);
+ --ring: oklch(0.708 0 0);
+ --chart-1: oklch(0.646 0.222 41.116);
+ --chart-2: oklch(0.6 0.118 184.704);
+ --chart-3: oklch(0.398 0.07 227.392);
+ --chart-4: oklch(0.828 0.189 84.429);
+ --chart-5: oklch(0.769 0.188 70.08);
+ --sidebar: oklch(0.985 0 0);
+ --sidebar-foreground: oklch(0.145 0 0);
+ --sidebar-primary: oklch(0.205 0 0);
+ --sidebar-primary-foreground: oklch(0.985 0 0);
+ --sidebar-accent: oklch(0.97 0 0);
+ --sidebar-accent-foreground: oklch(0.205 0 0);
+ --sidebar-border: oklch(0.922 0 0);
+ --sidebar-ring: oklch(0.708 0 0);
}
- html body {
- /*@apply font-[AmericanTypewriter];*/
- /* @apply w-full md:w-[68%] mx-auto h-full; */
- }
\ No newline at end of file
+.dark {
+ --background: oklch(0.145 0 0);
+ --foreground: oklch(0.985 0 0);
+ --card: oklch(0.205 0 0);
+ --card-foreground: oklch(0.985 0 0);
+ --popover: oklch(0.205 0 0);
+ --popover-foreground: oklch(0.985 0 0);
+ --primary: oklch(0.922 0 0);
+ --primary-foreground: oklch(0.205 0 0);
+ --secondary: oklch(0.269 0 0);
+ --secondary-foreground: oklch(0.985 0 0);
+ --muted: oklch(0.269 0 0);
+ --muted-foreground: oklch(0.708 0 0);
+ --accent: oklch(0.269 0 0);
+ --accent-foreground: oklch(0.985 0 0);
+ --destructive: oklch(0.704 0.191 22.216);
+ --border: oklch(1 0 0 / 10%);
+ --input: oklch(1 0 0 / 15%);
+ --ring: oklch(0.556 0 0);
+ --chart-1: oklch(0.488 0.243 264.376);
+ --chart-2: oklch(0.696 0.17 162.48);
+ --chart-3: oklch(0.769 0.188 70.08);
+ --chart-4: oklch(0.627 0.265 303.9);
+ --chart-5: oklch(0.645 0.246 16.439);
+ --sidebar: oklch(0.205 0 0);
+ --sidebar-foreground: oklch(0.985 0 0);
+ --sidebar-primary: oklch(0.488 0.243 264.376);
+ --sidebar-primary-foreground: oklch(0.985 0 0);
+ --sidebar-accent: oklch(0.269 0 0);
+ --sidebar-accent-foreground: oklch(0.985 0 0);
+ --sidebar-border: oklch(1 0 0 / 10%);
+ --sidebar-ring: oklch(0.556 0 0);
+}
+
+@theme inline {
+ --radius-sm: calc(var(--radius) - 4px);
+ --radius-md: calc(var(--radius) - 2px);
+ --radius-lg: var(--radius);
+ --radius-xl: calc(var(--radius) + 4px);
+ --color-background: var(--background);
+ --color-foreground: var(--foreground);
+ --color-card: var(--card);
+ --color-card-foreground: var(--card-foreground);
+ --color-popover: var(--popover);
+ --color-popover-foreground: var(--popover-foreground);
+ --color-primary: var(--primary);
+ --color-primary-foreground: var(--primary-foreground);
+ --color-secondary: var(--secondary);
+ --color-secondary-foreground: var(--secondary-foreground);
+ --color-muted: var(--muted);
+ --color-muted-foreground: var(--muted-foreground);
+ --color-accent: var(--accent);
+ --color-accent-foreground: var(--accent-foreground);
+ --color-destructive: var(--destructive);
+ --color-border: var(--border);
+ --color-input: var(--input);
+ --color-ring: var(--ring);
+ --color-chart-1: var(--chart-1);
+ --color-chart-2: var(--chart-2);
+ --color-chart-3: var(--chart-3);
+ --color-chart-4: var(--chart-4);
+ --color-chart-5: var(--chart-5);
+ --color-sidebar: var(--sidebar);
+ --color-sidebar-foreground: var(--sidebar-foreground);
+ --color-sidebar-primary: var(--sidebar-primary);
+ --color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
+ --color-sidebar-accent: var(--sidebar-accent);
+ --color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
+ --color-sidebar-border: var(--sidebar-border);
+ --color-sidebar-ring: var(--sidebar-ring);
+}
+
+@layer base {
+ * {
+ @apply border-border outline-ring/50;
+ }
+ body {
+ @apply bg-background text-foreground;
+ }
+}
\ No newline at end of file