From 2fa72ac13735f8b8222792c35639dfbec12cffaf Mon Sep 17 00:00:00 2001 From: pd0a6847 Date: Fri, 13 Jun 2025 14:10:30 +0900 Subject: [PATCH] Update user greeting to display email, add schemas for data validation, and enhance layout with new components --- package-lock.json | 251 ++++++- package.json | 7 + src/lib/components/app-sidebar.svelte | 164 +++++ .../components/chart-area-interactive.svelte | 253 ++++++++ .../components/data-table-cell-viewer.svelte | 189 ++++++ src/lib/components/data-table-checkbox.svelte | 12 + src/lib/components/data-table-reviewer.svelte | 29 + src/lib/components/data-table.svelte | 547 ++++++++++++++++ src/lib/components/nav-documents.svelte | 67 ++ src/lib/components/nav-main.svelte | 43 ++ src/lib/components/nav-secondary.svelte | 30 + src/lib/components/nav-user.svelte | 80 +++ src/lib/components/schemas.ts | 11 + src/lib/components/section-cards.svelte | 90 +++ src/lib/components/site-header.svelte | 26 + src/routes/+layout.svelte | 21 +- src/routes/+page.svelte | 13 +- src/routes/data.ts | 614 ++++++++++++++++++ src/routes/demo/lucia/+page.svelte | 2 +- src/routes/register/+page.server.ts | 42 +- src/routes/register/register-form.svelte | 2 +- 21 files changed, 2450 insertions(+), 43 deletions(-) create mode 100644 src/lib/components/app-sidebar.svelte create mode 100644 src/lib/components/chart-area-interactive.svelte create mode 100644 src/lib/components/data-table-cell-viewer.svelte create mode 100644 src/lib/components/data-table-checkbox.svelte create mode 100644 src/lib/components/data-table-reviewer.svelte create mode 100644 src/lib/components/data-table.svelte create mode 100644 src/lib/components/nav-documents.svelte create mode 100644 src/lib/components/nav-main.svelte create mode 100644 src/lib/components/nav-secondary.svelte create mode 100644 src/lib/components/nav-user.svelte create mode 100644 src/lib/components/schemas.ts create mode 100644 src/lib/components/section-cards.svelte create mode 100644 src/lib/components/site-header.svelte create mode 100644 src/routes/data.ts diff --git a/package-lock.json b/package-lock.json index 2422414..00304b3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,10 +8,16 @@ "name": "frovide", "version": "0.0.1", "dependencies": { + "@dnd-kit-svelte/core": "^0.0.8", + "@dnd-kit-svelte/modifiers": "^0.0.8", + "@dnd-kit-svelte/sortable": "^0.0.8", "@node-rs/argon2": "^2.0.2", "@oslojs/crypto": "^1.0.1", "@oslojs/encoding": "^1.1.0", "@sveltejs/adapter-node": "^5.2.12", + "@tabler/icons-svelte": "^3.34.0", + "d3-scale": "^4.0.2", + "d3-shape": "^3.2.0", "dotenv": "^16.5.0", "drizzle-orm": "^0.40.0", "lucide": "^0.513.0", @@ -27,6 +33,7 @@ "@sveltejs/vite-plugin-svelte": "^5.0.0", "@tailwindcss/vite": "^4.0.0", "@tanstack/table-core": "^8.21.3", + "@types/d3-scale": "^4.0.9", "@types/node": "^22", "bits-ui": "^2.4.1", "clsx": "^2.1.1", @@ -113,6 +120,195 @@ "node": ">17.0.0" } }, + "node_modules/@dnd-kit-svelte/accessibility": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/@dnd-kit-svelte/accessibility/-/accessibility-0.0.8.tgz", + "integrity": "sha512-Dm+6jTIuorEI4fkOh9ZcbVeJfUAPQGdseT2HfG9gu30PtxHTd9offH5cGWKxsdxjKZjkr5OH2O3DVeNtFjOPxQ==", + "license": "MIT", + "dependencies": { + "@dnd-kit-svelte/utilities": "latest", + "esm-env": "^1.2.2", + "runed": "^0.23.0" + }, + "peerDependencies": { + "svelte": "^5.0.0" + } + }, + "node_modules/@dnd-kit-svelte/accessibility/node_modules/runed": { + "version": "0.23.4", + "resolved": "https://registry.npmjs.org/runed/-/runed-0.23.4.tgz", + "integrity": "sha512-9q8oUiBYeXIDLWNK5DfCWlkL0EW3oGbk845VdKlPeia28l751VpfesaB/+7pI6rnbx1I6rqoZ2fZxptOJLxILA==", + "funding": [ + "https://github.com/sponsors/huntabyte", + "https://github.com/sponsors/tglide" + ], + "dependencies": { + "esm-env": "^1.0.0" + }, + "peerDependencies": { + "svelte": "^5.7.0" + } + }, + "node_modules/@dnd-kit-svelte/core": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/@dnd-kit-svelte/core/-/core-0.0.8.tgz", + "integrity": "sha512-c77kG70L2DX+af9NW7EbbByKXcHF4y+8sqbZjj81N6QnAtdqrfZdQug/39qSMC3hxLkiS1UowVhSQRJgpdFWGA==", + "license": "MIT", + "dependencies": { + "@dnd-kit-svelte/accessibility": "latest", + "@dnd-kit-svelte/utilities": "latest", + "runed": "^0.23.0", + "svelte-toolbelt": "^0.7.0" + }, + "peerDependencies": { + "svelte": "^5.0.0" + } + }, + "node_modules/@dnd-kit-svelte/core/node_modules/runed": { + "version": "0.23.4", + "resolved": "https://registry.npmjs.org/runed/-/runed-0.23.4.tgz", + "integrity": "sha512-9q8oUiBYeXIDLWNK5DfCWlkL0EW3oGbk845VdKlPeia28l751VpfesaB/+7pI6rnbx1I6rqoZ2fZxptOJLxILA==", + "funding": [ + "https://github.com/sponsors/huntabyte", + "https://github.com/sponsors/tglide" + ], + "dependencies": { + "esm-env": "^1.0.0" + }, + "peerDependencies": { + "svelte": "^5.7.0" + } + }, + "node_modules/@dnd-kit-svelte/core/node_modules/svelte-toolbelt": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/svelte-toolbelt/-/svelte-toolbelt-0.7.1.tgz", + "integrity": "sha512-HcBOcR17Vx9bjaOceUvxkY3nGmbBmCBBbuWLLEWO6jtmWH8f/QoWmbyUfQZrpDINH39en1b8mptfPQT9VKQ1xQ==", + "funding": [ + "https://github.com/sponsors/huntabyte" + ], + "dependencies": { + "clsx": "^2.1.1", + "runed": "^0.23.2", + "style-to-object": "^1.0.8" + }, + "engines": { + "node": ">=18", + "pnpm": ">=8.7.0" + }, + "peerDependencies": { + "svelte": "^5.0.0" + } + }, + "node_modules/@dnd-kit-svelte/modifiers": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/@dnd-kit-svelte/modifiers/-/modifiers-0.0.8.tgz", + "integrity": "sha512-EZyRNNm5yVl/ws86oLt1pJGNiB1QX1/xlHusL6yqtMylk9y486cp5C/BPdpvEtd6arK8XpuhNXV1dJAyYVsNrQ==", + "license": "MIT", + "dependencies": { + "@dnd-kit-svelte/core": "latest", + "@dnd-kit-svelte/utilities": "latest" + }, + "peerDependencies": { + "svelte": "^5.0.0" + } + }, + "node_modules/@dnd-kit-svelte/sortable": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/@dnd-kit-svelte/sortable/-/sortable-0.0.8.tgz", + "integrity": "sha512-4lHgd7ttFqQqfuxeg2GofqnM2nHrAqtFsxqXf/Vr7/s4rEusPO8cZkQ6n2KTr08lvHGpQM2l8aLBUDyQtWtCVQ==", + "license": "MIT", + "dependencies": { + "@dnd-kit-svelte/core": "latest", + "@dnd-kit-svelte/utilities": "latest", + "runed": "^0.23.0", + "svelte-toolbelt": "^0.7.0" + }, + "peerDependencies": { + "svelte": "^5.0.0" + } + }, + "node_modules/@dnd-kit-svelte/sortable/node_modules/runed": { + "version": "0.23.4", + "resolved": "https://registry.npmjs.org/runed/-/runed-0.23.4.tgz", + "integrity": "sha512-9q8oUiBYeXIDLWNK5DfCWlkL0EW3oGbk845VdKlPeia28l751VpfesaB/+7pI6rnbx1I6rqoZ2fZxptOJLxILA==", + "funding": [ + "https://github.com/sponsors/huntabyte", + "https://github.com/sponsors/tglide" + ], + "dependencies": { + "esm-env": "^1.0.0" + }, + "peerDependencies": { + "svelte": "^5.7.0" + } + }, + "node_modules/@dnd-kit-svelte/sortable/node_modules/svelte-toolbelt": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/svelte-toolbelt/-/svelte-toolbelt-0.7.1.tgz", + "integrity": "sha512-HcBOcR17Vx9bjaOceUvxkY3nGmbBmCBBbuWLLEWO6jtmWH8f/QoWmbyUfQZrpDINH39en1b8mptfPQT9VKQ1xQ==", + "funding": [ + "https://github.com/sponsors/huntabyte" + ], + "dependencies": { + "clsx": "^2.1.1", + "runed": "^0.23.2", + "style-to-object": "^1.0.8" + }, + "engines": { + "node": ">=18", + "pnpm": ">=8.7.0" + }, + "peerDependencies": { + "svelte": "^5.0.0" + } + }, + "node_modules/@dnd-kit-svelte/utilities": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/@dnd-kit-svelte/utilities/-/utilities-0.0.8.tgz", + "integrity": "sha512-fiBPmbHS94cuigysqyRA7T8WpNP94uEw2DsYX9En81mOkAN9UH9RU2DlJ63luZwn4BG9k+DjYT0jt2AEaRuYIg==", + "license": "MIT", + "dependencies": { + "svelte-toolbelt": "^0.7.0" + }, + "peerDependencies": { + "svelte": "^5.0.0" + } + }, + "node_modules/@dnd-kit-svelte/utilities/node_modules/runed": { + "version": "0.23.4", + "resolved": "https://registry.npmjs.org/runed/-/runed-0.23.4.tgz", + "integrity": "sha512-9q8oUiBYeXIDLWNK5DfCWlkL0EW3oGbk845VdKlPeia28l751VpfesaB/+7pI6rnbx1I6rqoZ2fZxptOJLxILA==", + "funding": [ + "https://github.com/sponsors/huntabyte", + "https://github.com/sponsors/tglide" + ], + "dependencies": { + "esm-env": "^1.0.0" + }, + "peerDependencies": { + "svelte": "^5.7.0" + } + }, + "node_modules/@dnd-kit-svelte/utilities/node_modules/svelte-toolbelt": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/svelte-toolbelt/-/svelte-toolbelt-0.7.1.tgz", + "integrity": "sha512-HcBOcR17Vx9bjaOceUvxkY3nGmbBmCBBbuWLLEWO6jtmWH8f/QoWmbyUfQZrpDINH39en1b8mptfPQT9VKQ1xQ==", + "funding": [ + "https://github.com/sponsors/huntabyte" + ], + "dependencies": { + "clsx": "^2.1.1", + "runed": "^0.23.2", + "style-to-object": "^1.0.8" + }, + "engines": { + "node": ">=18", + "pnpm": ">=8.7.0" + }, + "peerDependencies": { + "svelte": "^5.0.0" + } + }, "node_modules/@drizzle-team/brocli": { "version": "0.10.2", "resolved": "https://registry.npmjs.org/@drizzle-team/brocli/-/brocli-0.10.2.tgz", @@ -2077,6 +2273,32 @@ "tslib": "^2.8.0" } }, + "node_modules/@tabler/icons": { + "version": "3.34.0", + "resolved": "https://registry.npmjs.org/@tabler/icons/-/icons-3.34.0.tgz", + "integrity": "sha512-jtVqv0JC1WU2TTEBN32D9+R6mc1iEBuPwLnBsWaR02SIEciu9aq5806AWkCHuObhQ4ERhhXErLEK7Fs+tEZxiA==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/codecalm" + } + }, + "node_modules/@tabler/icons-svelte": { + "version": "3.34.0", + "resolved": "https://registry.npmjs.org/@tabler/icons-svelte/-/icons-svelte-3.34.0.tgz", + "integrity": "sha512-GK361EswvIZaXY0Eoa4V3lu7qAUQ7XXiPDEkS7+ZeNR5CULD8JkMUG15UITHSmUtu/q2RhCuhgtkW5rdZeIpFQ==", + "license": "MIT", + "dependencies": { + "@tabler/icons": "3.34.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/codecalm" + }, + "peerDependencies": { + "svelte": ">=3 <6 || >=5.0.0-next.0" + } + }, "node_modules/@tailwindcss/node": { "version": "4.1.8", "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.1.8.tgz", @@ -2384,6 +2606,23 @@ "integrity": "sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==", "license": "MIT" }, + "node_modules/@types/d3-scale": { + "version": "4.0.9", + "resolved": "https://registry.npmjs.org/@types/d3-scale/-/d3-scale-4.0.9.tgz", + "integrity": "sha512-dLmtwB8zkAeO/juAMfnV+sItKjlsw2lKdZVVy6LRr0cBmegxSABiLEpGVmSJJ8O08i4+sGR6qQtb6WtuwJdvVw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/d3-time": "*" + } + }, + "node_modules/@types/d3-time": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-time/-/d3-time-3.0.4.tgz", + "integrity": "sha512-yuzZug1nkAAaBlBBikKZTgzCeA+k1uy4ZFwWANOfKw5z5LRhV0gNA7gNkKm7HoK+HRN0wX3EkxGk0fpbWhmB7g==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/estree": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.7.tgz", @@ -2687,7 +2926,6 @@ "version": "3.2.4", "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.4.tgz", "integrity": "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==", - "dev": true, "license": "ISC", "dependencies": { "internmap": "1 - 2" @@ -2700,7 +2938,6 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz", "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==", - "dev": true, "license": "ISC", "engines": { "node": ">=12" @@ -2774,7 +3011,6 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.1.0.tgz", "integrity": "sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA==", - "dev": true, "license": "ISC", "engines": { "node": ">=12" @@ -2823,7 +3059,6 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz", "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==", - "dev": true, "license": "ISC", "dependencies": { "d3-color": "1 - 3" @@ -2843,7 +3078,6 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-3.1.0.tgz", "integrity": "sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==", - "dev": true, "license": "ISC", "engines": { "node": ">=12" @@ -2918,7 +3152,6 @@ "version": "4.0.2", "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-4.0.2.tgz", "integrity": "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==", - "dev": true, "license": "ISC", "dependencies": { "d3-array": "2.10.0 - 3", @@ -2949,7 +3182,6 @@ "version": "3.2.0", "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-3.2.0.tgz", "integrity": "sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==", - "dev": true, "license": "ISC", "dependencies": { "d3-path": "^3.1.0" @@ -2969,7 +3201,6 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-3.1.0.tgz", "integrity": "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==", - "dev": true, "license": "ISC", "dependencies": { "d3-array": "2 - 3" @@ -2982,7 +3213,6 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-4.1.0.tgz", "integrity": "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==", - "dev": true, "license": "ISC", "dependencies": { "d3-time": "1 - 3" @@ -3626,14 +3856,12 @@ "version": "0.2.4", "resolved": "https://registry.npmjs.org/inline-style-parser/-/inline-style-parser-0.2.4.tgz", "integrity": "sha512-0aO8FkhNZlj/ZIbNi7Lxxr12obT7cL1moPfE4tg1LkX7LlLfC6DeX4l2ZEud1ukP9jNQyNnfzQVqwbwmAATY4Q==", - "dev": true, "license": "MIT" }, "node_modules/internmap": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz", "integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==", - "dev": true, "license": "ISC", "engines": { "node": ">=12" @@ -4634,7 +4862,6 @@ "version": "1.0.8", "resolved": "https://registry.npmjs.org/style-to-object/-/style-to-object-1.0.8.tgz", "integrity": "sha512-xT47I/Eo0rwJmaXC4oilDGDWLohVhR6o/xAQcPQN8q6QBuZVL8qMYL85kLmST5cPjAorwvqIA4qXTRQoYHaL6g==", - "dev": true, "license": "MIT", "dependencies": { "inline-style-parser": "0.2.4" diff --git a/package.json b/package.json index 47d4685..e244b5b 100644 --- a/package.json +++ b/package.json @@ -22,6 +22,7 @@ "@sveltejs/vite-plugin-svelte": "^5.0.0", "@tailwindcss/vite": "^4.0.0", "@tanstack/table-core": "^8.21.3", + "@types/d3-scale": "^4.0.9", "@types/node": "^22", "bits-ui": "^2.4.1", "clsx": "^2.1.1", @@ -45,10 +46,16 @@ "vite": "^6.2.6" }, "dependencies": { + "@dnd-kit-svelte/core": "^0.0.8", + "@dnd-kit-svelte/modifiers": "^0.0.8", + "@dnd-kit-svelte/sortable": "^0.0.8", "@node-rs/argon2": "^2.0.2", "@oslojs/crypto": "^1.0.1", "@oslojs/encoding": "^1.1.0", "@sveltejs/adapter-node": "^5.2.12", + "@tabler/icons-svelte": "^3.34.0", + "d3-scale": "^4.0.2", + "d3-shape": "^3.2.0", "dotenv": "^16.5.0", "drizzle-orm": "^0.40.0", "lucide": "^0.513.0", diff --git a/src/lib/components/app-sidebar.svelte b/src/lib/components/app-sidebar.svelte new file mode 100644 index 0000000..2d8bc7a --- /dev/null +++ b/src/lib/components/app-sidebar.svelte @@ -0,0 +1,164 @@ + + + + + + + {#snippet child({ props })} + + + Acme Inc. + + {/snippet} + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/lib/components/chart-area-interactive.svelte b/src/lib/components/chart-area-interactive.svelte new file mode 100644 index 0000000..e1b95f0 --- /dev/null +++ b/src/lib/components/chart-area-interactive.svelte @@ -0,0 +1,253 @@ + + + + Total Visitors + + + Last 3 months + + + + + + + {selectedLabel} + + + + Last 3 months + Last 30 days + Last 7 days + + + + + + + { + return v.toLocaleDateString("en-US", { + month: "short", + day: "numeric", + }); + }, + }, + yAxis: { format: () => "" }, + }} + > + {#snippet marks({series, getAreaProps})} + + + + + + + + + + + {#each series as s, i (s.key)} + + {/each} + {/snippet} + {#snippet tooltip()} + { + return v.toLocaleDateString("en-US", { + month: "short", + day: "numeric", + }); + }} + indicator="line" + /> + {/snippet} + + + + \ No newline at end of file diff --git a/src/lib/components/data-table-cell-viewer.svelte b/src/lib/components/data-table-cell-viewer.svelte new file mode 100644 index 0000000..fa572af --- /dev/null +++ b/src/lib/components/data-table-cell-viewer.svelte @@ -0,0 +1,189 @@ + + + + {#snippet child({ props })} + + {/snippet} + + + + {item.header} + Showing total visitors for the last 6 months + +
+ {#if !isMobile.current} + + v.toLocaleDateString("en-US", { month: "short" }), + }, + yAxis: { ticks: [0, 300, 600] }, + }} + > + {#snippet tooltip()} + { + return v.toLocaleDateString("en-US", { + month: "long", + }); + }} + indicator="dot" + /> + {/snippet} + + + +
+
+ Trending up by 5.2% this month + +
+
+ Showing total visitors for the last 6 months. This is just some random text + to test the layout. It spans multiple lines and should wrap around. +
+
+ + {/if} +
+
+ + +
+
+
+ + + + {type ?? "Select a type"} + + + Table of Contents + Executive Summary + + Technical Approach + + Design + Capabilities + Focus Documents + Narrative + Cover Page + + +
+
+ + + + {status ?? "Select a status"} + + + Done + In Progress + Not Started + + +
+
+
+
+ + +
+
+ + +
+
+
+ + + + {reviewer ?? "Select a reviewer"} + + + Eddie Lake + Jamik Tashpulatov + Emily Whalen + + +
+
+
+ + + + {#snippet child({ props })} + + {/snippet} + + +
+
\ No newline at end of file diff --git a/src/lib/components/data-table-checkbox.svelte b/src/lib/components/data-table-checkbox.svelte new file mode 100644 index 0000000..68498b5 --- /dev/null +++ b/src/lib/components/data-table-checkbox.svelte @@ -0,0 +1,12 @@ + +
+ checked, onCheckedChange} {...restProps} /> +
\ No newline at end of file diff --git a/src/lib/components/data-table-reviewer.svelte b/src/lib/components/data-table-reviewer.svelte new file mode 100644 index 0000000..f8c2701 --- /dev/null +++ b/src/lib/components/data-table-reviewer.svelte @@ -0,0 +1,29 @@ + +{#if isAssigned} + {row.original.reviewer} +{:else} + + + + + {reviewer ?? "Assign reviewer"} + + + + Eddie Lake + Jamik Tashpulatov + + +{/if} \ No newline at end of file diff --git a/src/lib/components/data-table.svelte b/src/lib/components/data-table.svelte new file mode 100644 index 0000000..806424a --- /dev/null +++ b/src/lib/components/data-table.svelte @@ -0,0 +1,547 @@ + + + +
+ + + + {viewLabel} + + + {#each views as view (view.id)} + {view.label} + {/each} + + + +
+ + + {#snippet child({props})} + + {/snippet} + + + {#each table + .getAllColumns() + .filter((col) => typeof col.accessorFn !== "undefined" && col.getCanHide()) as column (column.id)} + column.toggleVisibility(!!value)} + > + {column.id} + + {/each} + + + +
+
+ +
+ + + + {#each table.getHeaderGroups() as headerGroup (headerGroup.id)} + + {#each headerGroup.headers as header (header.id)} + + {#if !header.isPlaceholder} + + {/if} + + {/each} + + {/each} + + + {#if table.getRowModel().rows?.length} + + {#each table.getRowModel().rows as row (row.id)} + {@render DraggableRow({row})} + {/each} + + {:else} + + + No results. + + + {/if} + + + +
+
+ +
+ +
+ Page {table.getState().pagination.pageIndex + 1} of + {table.getPageCount()} +
+
+ + + + +
+
+
+
+ +
+
+ +
+
+ +
+
+
+{#snippet DataTableLimit({row}: { row: Row })} +
{ + e.preventDefault(); + toast.promise(new Promise((resolve) => setTimeout(resolve, 1000)), { + loading: `Saving ${row.original.header}`, + success: "Done", + error: "Error", + }); + }} + > + + +
+{/snippet} +{#snippet DataTableTarget({row}: { row: Row })} +
{ + e.preventDefault(); + toast.promise(new Promise((resolve) => setTimeout(resolve, 1000)), { + loading: `Saving ${row.original.header}`, + success: "Done", + error: "Error", + }); + }} + > + + +
+{/snippet} +{#snippet DataTableType({row}: { row: Row })} +
+ + {row.original.type} + +
+{/snippet} +{#snippet DataTableStatus({row}: { row: Row })} + + {#if row.original.status === "Done"} + + {:else} + + {/if} + {row.original.status} + +{/snippet} +{#snippet DataTableActions()} + + + {#snippet child({props})} + + {/snippet} + + + Edit + Make a copy + Favorite + + Delete + + +{/snippet} +{#snippet DraggableRow({row}: { row: Row })} + {@const {transform, transition, node, isDragging} = useSortable({ + id: () => row.original.id, + })} + + {#each row.getVisibleCells() as cell (cell.id)} + + + + {/each} + +{/snippet} +{#snippet DragHandle({id}: { id: number })} + {@const {attributes, listeners} = useSortable({id: () => id})} + +{/snippet} \ No newline at end of file diff --git a/src/lib/components/nav-documents.svelte b/src/lib/components/nav-documents.svelte new file mode 100644 index 0000000..d1b51ef --- /dev/null +++ b/src/lib/components/nav-documents.svelte @@ -0,0 +1,67 @@ + + + Documents + + {#each items as item (item.name)} + + + {#snippet child({ props })} + + + {item.name} + + {/snippet} + + + + {#snippet child({ props })} + + + More + + {/snippet} + + + + + Open + + + + Share + + + + + Delete + + + + + {/each} + + + + More + + + + \ No newline at end of file diff --git a/src/lib/components/nav-main.svelte b/src/lib/components/nav-main.svelte new file mode 100644 index 0000000..308a473 --- /dev/null +++ b/src/lib/components/nav-main.svelte @@ -0,0 +1,43 @@ + + + + + + + + Quick Create + + + + + + {#each items as item (item.title)} + + + {#if item.icon} + + {/if} + {item.title} + + + {/each} + + + \ No newline at end of file diff --git a/src/lib/components/nav-secondary.svelte b/src/lib/components/nav-secondary.svelte new file mode 100644 index 0000000..d49c86a --- /dev/null +++ b/src/lib/components/nav-secondary.svelte @@ -0,0 +1,30 @@ + + + + + {#each items as item (item.title)} + + + {#snippet child({ props })} + + + {item.title} + + {/snippet} + + + {/each} + + + \ No newline at end of file diff --git a/src/lib/components/nav-user.svelte b/src/lib/components/nav-user.svelte new file mode 100644 index 0000000..3d86d93 --- /dev/null +++ b/src/lib/components/nav-user.svelte @@ -0,0 +1,80 @@ + + + + + + {#snippet child({ props })} + + + + CN + +
+ {user.name} + + {user.email} + +
+ +
+ {/snippet} +
+ + +
+ + + CN + +
+ {user.name} + + {user.email} + +
+
+
+ + + + + Account + + + + Billing + + + + Notifications + + + + + + Log out + +
+
+
+
\ No newline at end of file diff --git a/src/lib/components/schemas.ts b/src/lib/components/schemas.ts new file mode 100644 index 0000000..ec2b27a --- /dev/null +++ b/src/lib/components/schemas.ts @@ -0,0 +1,11 @@ +import { z } from "zod/v4"; +export const schema = z.object({ + id: z.number(), + header: z.string(), + type: z.string(), + status: z.string(), + target: z.string(), + limit: z.string(), + reviewer: z.string(), +}); +export type Schema = z.infer; \ No newline at end of file diff --git a/src/lib/components/section-cards.svelte b/src/lib/components/section-cards.svelte new file mode 100644 index 0000000..a9bab0c --- /dev/null +++ b/src/lib/components/section-cards.svelte @@ -0,0 +1,90 @@ + +
+ + + Total Revenue + + $1,250.00 + + + + + +12.5% + + + + +
+ Trending up this month +
+
Visitors for the last 6 months
+
+
+ + + New Customers + + 1,234 + + + + + -20% + + + + +
+ Down 20% this period +
+
Acquisition needs attention
+
+
+ + + Active Accounts + + 45,678 + + + + + +12.5% + + + + +
+ Strong user retention +
+
Engagement exceed targets
+
+
+ + + Growth Rate + + 4.5% + + + + + +4.5% + + + + +
+ Steady performance increase +
+
Meets growth projections
+
+
+
\ No newline at end of file diff --git a/src/lib/components/site-header.svelte b/src/lib/components/site-header.svelte new file mode 100644 index 0000000..662ba9f --- /dev/null +++ b/src/lib/components/site-header.svelte @@ -0,0 +1,26 @@ + +
+
+ + +

Documents

+
+ +
+
+
\ No newline at end of file diff --git a/src/routes/+layout.svelte b/src/routes/+layout.svelte index e98e847..3e215ea 100644 --- a/src/routes/+layout.svelte +++ b/src/routes/+layout.svelte @@ -2,6 +2,25 @@ import '../app.css'; import { Toaster } from "$lib/components/ui/sonner/index.js"; let { children } = $props(); + import * as Sidebar from "$lib/components/ui/sidebar/index.js"; + import AppSidebar from "$lib/components/app-sidebar.svelte"; + import SiteHeader from "$lib/components/site-header.svelte"; + -{@render children()} + + + + +
+
+
+ {@render children()} +
+
+
+
+
+ diff --git a/src/routes/+page.svelte b/src/routes/+page.svelte index a8f10f3..0c490e9 100644 --- a/src/routes/+page.svelte +++ b/src/routes/+page.svelte @@ -1,10 +1,13 @@ -
-

FROVIDE.COM

-

안녕하세요 반갑습니다.

- + +
+
+ diff --git a/src/routes/data.ts b/src/routes/data.ts new file mode 100644 index 0000000..4c8447a --- /dev/null +++ b/src/routes/data.ts @@ -0,0 +1,614 @@ +export default [ + { + id: 1, + header: "Cover page", + type: "Cover page", + status: "In Process", + target: "18", + limit: "5", + reviewer: "Eddie Lake", + }, + { + id: 2, + header: "Table of contents", + type: "Table of contents", + status: "Done", + target: "29", + limit: "24", + reviewer: "Eddie Lake", + }, + { + id: 3, + header: "Executive summary", + type: "Narrative", + status: "Done", + target: "10", + limit: "13", + reviewer: "Eddie Lake", + }, + { + id: 4, + header: "Technical approach", + type: "Narrative", + status: "Done", + target: "27", + limit: "23", + reviewer: "Jamik Tashpulatov", + }, + { + id: 5, + header: "Design", + type: "Narrative", + status: "In Process", + target: "2", + limit: "16", + reviewer: "Jamik Tashpulatov", + }, + { + id: 6, + header: "Capabilities", + type: "Narrative", + status: "In Process", + target: "20", + limit: "8", + reviewer: "Jamik Tashpulatov", + }, + { + id: 7, + header: "Integration with existing systems", + type: "Narrative", + status: "In Process", + target: "19", + limit: "21", + reviewer: "Jamik Tashpulatov", + }, + { + id: 8, + header: "Innovation and Advantages", + type: "Narrative", + status: "Done", + target: "25", + limit: "26", + reviewer: "Assign reviewer", + }, + { + id: 9, + header: "Overview of EMR's Innovative Solutions", + type: "Technical content", + status: "Done", + target: "7", + limit: "23", + reviewer: "Assign reviewer", + }, + { + id: 10, + header: "Advanced Algorithms and Machine Learning", + type: "Narrative", + status: "Done", + target: "30", + limit: "28", + reviewer: "Assign reviewer", + }, + { + id: 11, + header: "Adaptive Communication Protocols", + type: "Narrative", + status: "Done", + target: "9", + limit: "31", + reviewer: "Assign reviewer", + }, + { + id: 12, + header: "Advantages Over Current Technologies", + type: "Narrative", + status: "Done", + target: "12", + limit: "0", + reviewer: "Assign reviewer", + }, + { + id: 13, + header: "Past Performance", + type: "Narrative", + status: "Done", + target: "22", + limit: "33", + reviewer: "Assign reviewer", + }, + { + id: 14, + header: "Customer Feedback and Satisfaction Levels", + type: "Narrative", + status: "Done", + target: "15", + limit: "34", + reviewer: "Assign reviewer", + }, + { + id: 15, + header: "Implementation Challenges and Solutions", + type: "Narrative", + status: "Done", + target: "3", + limit: "35", + reviewer: "Assign reviewer", + }, + { + id: 16, + header: "Security Measures and Data Protection Policies", + type: "Narrative", + status: "In Process", + target: "6", + limit: "36", + reviewer: "Assign reviewer", + }, + { + id: 17, + header: "Scalability and Future Proofing", + type: "Narrative", + status: "Done", + target: "4", + limit: "37", + reviewer: "Assign reviewer", + }, + { + id: 18, + header: "Cost-Benefit Analysis", + type: "Plain language", + status: "Done", + target: "14", + limit: "38", + reviewer: "Assign reviewer", + }, + { + id: 19, + header: "User Training and Onboarding Experience", + type: "Narrative", + status: "Done", + target: "17", + limit: "39", + reviewer: "Assign reviewer", + }, + { + id: 20, + header: "Future Development Roadmap", + type: "Narrative", + status: "Done", + target: "11", + limit: "40", + reviewer: "Assign reviewer", + }, + { + id: 21, + header: "System Architecture Overview", + type: "Technical content", + status: "In Process", + target: "24", + limit: "18", + reviewer: "Maya Johnson", + }, + { + id: 22, + header: "Risk Management Plan", + type: "Narrative", + status: "Done", + target: "15", + limit: "22", + reviewer: "Carlos Rodriguez", + }, + { + id: 23, + header: "Compliance Documentation", + type: "Legal", + status: "In Process", + target: "31", + limit: "27", + reviewer: "Sarah Chen", + }, + { + id: 24, + header: "API Documentation", + type: "Technical content", + status: "Done", + target: "8", + limit: "12", + reviewer: "Raj Patel", + }, + { + id: 25, + header: "User Interface Mockups", + type: "Visual", + status: "In Process", + target: "19", + limit: "25", + reviewer: "Leila Ahmadi", + }, + { + id: 26, + header: "Database Schema", + type: "Technical content", + status: "Done", + target: "22", + limit: "20", + reviewer: "Thomas Wilson", + }, + { + id: 27, + header: "Testing Methodology", + type: "Technical content", + status: "In Process", + target: "17", + limit: "14", + reviewer: "Assign reviewer", + }, + { + id: 28, + header: "Deployment Strategy", + type: "Narrative", + status: "Done", + target: "26", + limit: "30", + reviewer: "Eddie Lake", + }, + { + id: 29, + header: "Budget Breakdown", + type: "Financial", + status: "In Process", + target: "13", + limit: "16", + reviewer: "Jamik Tashpulatov", + }, + { + id: 30, + header: "Market Analysis", + type: "Research", + status: "Done", + target: "29", + limit: "32", + reviewer: "Sophia Martinez", + }, + { + id: 31, + header: "Competitor Comparison", + type: "Research", + status: "In Process", + target: "21", + limit: "19", + reviewer: "Assign reviewer", + }, + { + id: 32, + header: "Maintenance Plan", + type: "Technical content", + status: "Done", + target: "16", + limit: "23", + reviewer: "Alex Thompson", + }, + { + id: 33, + header: "User Personas", + type: "Research", + status: "In Process", + target: "27", + limit: "24", + reviewer: "Nina Patel", + }, + { + id: 34, + header: "Accessibility Compliance", + type: "Legal", + status: "Done", + target: "18", + limit: "21", + reviewer: "Assign reviewer", + }, + { + id: 35, + header: "Performance Metrics", + type: "Technical content", + status: "In Process", + target: "23", + limit: "26", + reviewer: "David Kim", + }, + { + id: 36, + header: "Disaster Recovery Plan", + type: "Technical content", + status: "Done", + target: "14", + limit: "17", + reviewer: "Jamik Tashpulatov", + }, + { + id: 37, + header: "Third-party Integrations", + type: "Technical content", + status: "In Process", + target: "25", + limit: "28", + reviewer: "Eddie Lake", + }, + { + id: 38, + header: "User Feedback Summary", + type: "Research", + status: "Done", + target: "20", + limit: "15", + reviewer: "Assign reviewer", + }, + { + id: 39, + header: "Localization Strategy", + type: "Narrative", + status: "In Process", + target: "12", + limit: "19", + reviewer: "Maria Garcia", + }, + { + id: 40, + header: "Mobile Compatibility", + type: "Technical content", + status: "Done", + target: "28", + limit: "31", + reviewer: "James Wilson", + }, + { + id: 41, + header: "Data Migration Plan", + type: "Technical content", + status: "In Process", + target: "19", + limit: "22", + reviewer: "Assign reviewer", + }, + { + id: 42, + header: "Quality Assurance Protocols", + type: "Technical content", + status: "Done", + target: "30", + limit: "33", + reviewer: "Priya Singh", + }, + { + id: 43, + header: "Stakeholder Analysis", + type: "Research", + status: "In Process", + target: "11", + limit: "14", + reviewer: "Eddie Lake", + }, + { + id: 44, + header: "Environmental Impact Assessment", + type: "Research", + status: "Done", + target: "24", + limit: "27", + reviewer: "Assign reviewer", + }, + { + id: 45, + header: "Intellectual Property Rights", + type: "Legal", + status: "In Process", + target: "17", + limit: "20", + reviewer: "Sarah Johnson", + }, + { + id: 46, + header: "Customer Support Framework", + type: "Narrative", + status: "Done", + target: "22", + limit: "25", + reviewer: "Jamik Tashpulatov", + }, + { + id: 47, + header: "Version Control Strategy", + type: "Technical content", + status: "In Process", + target: "15", + limit: "18", + reviewer: "Assign reviewer", + }, + { + id: 48, + header: "Continuous Integration Pipeline", + type: "Technical content", + status: "Done", + target: "26", + limit: "29", + reviewer: "Michael Chen", + }, + { + id: 49, + header: "Regulatory Compliance", + type: "Legal", + status: "In Process", + target: "13", + limit: "16", + reviewer: "Assign reviewer", + }, + { + id: 50, + header: "User Authentication System", + type: "Technical content", + status: "Done", + target: "28", + limit: "31", + reviewer: "Eddie Lake", + }, + { + id: 51, + header: "Data Analytics Framework", + type: "Technical content", + status: "In Process", + target: "21", + limit: "24", + reviewer: "Jamik Tashpulatov", + }, + { + id: 52, + header: "Cloud Infrastructure", + type: "Technical content", + status: "Done", + target: "16", + limit: "19", + reviewer: "Assign reviewer", + }, + { + id: 53, + header: "Network Security Measures", + type: "Technical content", + status: "In Process", + target: "29", + limit: "32", + reviewer: "Lisa Wong", + }, + { + id: 54, + header: "Project Timeline", + type: "Planning", + status: "Done", + target: "14", + limit: "17", + reviewer: "Eddie Lake", + }, + { + id: 55, + header: "Resource Allocation", + type: "Planning", + status: "In Process", + target: "27", + limit: "30", + reviewer: "Assign reviewer", + }, + { + id: 56, + header: "Team Structure and Roles", + type: "Planning", + status: "Done", + target: "20", + limit: "23", + reviewer: "Jamik Tashpulatov", + }, + { + id: 57, + header: "Communication Protocols", + type: "Planning", + status: "In Process", + target: "15", + limit: "18", + reviewer: "Assign reviewer", + }, + { + id: 58, + header: "Success Metrics", + type: "Planning", + status: "Done", + target: "30", + limit: "33", + reviewer: "Eddie Lake", + }, + { + id: 59, + header: "Internationalization Support", + type: "Technical content", + status: "In Process", + target: "23", + limit: "26", + reviewer: "Jamik Tashpulatov", + }, + { + id: 60, + header: "Backup and Recovery Procedures", + type: "Technical content", + status: "Done", + target: "18", + limit: "21", + reviewer: "Assign reviewer", + }, + { + id: 61, + header: "Monitoring and Alerting System", + type: "Technical content", + status: "In Process", + target: "25", + limit: "28", + reviewer: "Daniel Park", + }, + { + id: 62, + header: "Code Review Guidelines", + type: "Technical content", + status: "Done", + target: "12", + limit: "15", + reviewer: "Eddie Lake", + }, + { + id: 63, + header: "Documentation Standards", + type: "Technical content", + status: "In Process", + target: "27", + limit: "30", + reviewer: "Jamik Tashpulatov", + }, + { + id: 64, + header: "Release Management Process", + type: "Planning", + status: "Done", + target: "22", + limit: "25", + reviewer: "Assign reviewer", + }, + { + id: 65, + header: "Feature Prioritization Matrix", + type: "Planning", + status: "In Process", + target: "19", + limit: "22", + reviewer: "Emma Davis", + }, + { + id: 66, + header: "Technical Debt Assessment", + type: "Technical content", + status: "Done", + target: "24", + limit: "27", + reviewer: "Eddie Lake", + }, + { + id: 67, + header: "Capacity Planning", + type: "Planning", + status: "In Process", + target: "21", + limit: "24", + reviewer: "Jamik Tashpulatov", + }, + { + id: 68, + header: "Service Level Agreements", + type: "Legal", + status: "Done", + target: "26", + limit: "29", + reviewer: "Assign reviewer", + }, +]; \ No newline at end of file diff --git a/src/routes/demo/lucia/+page.svelte b/src/routes/demo/lucia/+page.svelte index a5308cb..1a46dc2 100644 --- a/src/routes/demo/lucia/+page.svelte +++ b/src/routes/demo/lucia/+page.svelte @@ -5,7 +5,7 @@ let { data }: { data: PageServerData } = $props(); -

Hi, {data.user.username}!

+

Hi, {data.user.email}!

Your user ID is {data.user.id}.

diff --git a/src/routes/register/+page.server.ts b/src/routes/register/+page.server.ts index 7ccfa69..35e3d43 100644 --- a/src/routes/register/+page.server.ts +++ b/src/routes/register/+page.server.ts @@ -22,46 +22,42 @@ export const load: PageServerLoad = async (event) => { }; export const actions: Actions = { - login: async (event) => { + register: async (event) => { const form = await superValidate(event, zod(formSchema)); if (!form.valid) { return fail(400, { form, }); } - const email = form.data.email; const password = form.data.password; - const results = await db - .select() - .from(table.user) - .where(eq(table.user.email, email)); - - const existingUser = results.at(0); - if (!existingUser) { - return setError(form, 'email', '등록된 이메일이 아닙니다.'); - } - - const validPassword = await verify(existingUser.passwordHash, password, { + const userId = generateUserId(); + const passwordHash = await hash(password, { + // recommended minimum parameters memoryCost: 19456, timeCost: 2, outputLen: 32, parallelism: 1, }); - if (!validPassword) { - return setError(form, 'password', '비밀번호가 일치하지 않습니다.'); + + try { + await db.insert(table.user).values({ id: userId, email, passwordHash }); + + const sessionToken = auth.generateSessionToken(); + const session = await auth.createSession(sessionToken, userId); + auth.setSessionTokenCookie(event, sessionToken, session.expiresAt); + } catch (e) { + return fail(500, { message: 'An error has occurred' }); } - - const sessionToken = auth.generateSessionToken(); - const session = await auth.createSession(sessionToken, existingUser.id); - auth.setSessionTokenCookie(event, sessionToken, session.expiresAt); - return redirect(302, '/demo/lucia'); - }, }; - - +function generateUserId() { + // ID with 120 bits of entropy, or about the same as UUID v4. + const bytes = crypto.getRandomValues(new Uint8Array(15)); + const id = encodeBase32LowerCase(bytes); + return id; +} diff --git a/src/routes/register/register-form.svelte b/src/routes/register/register-form.svelte index 28336a9..fad0b46 100644 --- a/src/routes/register/register-form.svelte +++ b/src/routes/register/register-form.svelte @@ -9,7 +9,7 @@ superForm, } from "sveltekit-superforms"; import {zodClient} from "sveltekit-superforms/adapters"; - import { dev } from '$app/environment'; + import {dev} from '$app/environment'; import {Label} from "@/components/ui/label"; import {Switch} from "@/components/ui/switch"; import {cn} from "@/utils.js";