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 @@ -
-
- - {#if expanded} - - {monthNames[currentMonth]} {currentYear} - - {:else} - Current Week - {/if} -
- -
- {#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} +
+ Entry +
+ {:else} +
+ No image +
+ {/if} + + + {#if entry.content} +
+
+ {@html marked(entry.content)} +
+
+ {:else} +
+ No content yet +
+ {/if} +
+ + + {:else} +
+ +
+ + + {#if previewImage} +
+ Preview + +
+ {: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} + + +
+ + +
+ + 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