mirror of
https://github.com/bartvdbraak/omnidash.git
synced 2025-06-28 04:09:13 +00:00
feat: add dashboard and settings pages and components
This commit is contained in:
parent
cb51a4507d
commit
39a36462bb
109 changed files with 3770 additions and 116 deletions
|
@ -29,19 +29,24 @@
|
||||||
"prettier-plugin-tailwindcss": "^0.5.9",
|
"prettier-plugin-tailwindcss": "^0.5.9",
|
||||||
"svelte": "^4.2.7",
|
"svelte": "^4.2.7",
|
||||||
"svelte-check": "^3.6.0",
|
"svelte-check": "^3.6.0",
|
||||||
|
"sveltekit-superforms": "^1.13.4",
|
||||||
"tailwindcss": "^3.3.6",
|
"tailwindcss": "^3.3.6",
|
||||||
"tslib": "^2.4.1",
|
"tslib": "^2.4.1",
|
||||||
"typescript": "^5.0.0",
|
"typescript": "^5.0.0",
|
||||||
"vite": "^5.0.3"
|
"vite": "^5.0.3",
|
||||||
|
"zod": "^3.22.4"
|
||||||
},
|
},
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"bits-ui": "^0.15.1",
|
"bits-ui": "^0.15.1",
|
||||||
"clsx": "^2.1.0",
|
"clsx": "^2.1.0",
|
||||||
|
"cmdk-sv": "^0.0.13",
|
||||||
|
"formsnap": "^0.4.3",
|
||||||
"lucide-svelte": "^0.316.0",
|
"lucide-svelte": "^0.316.0",
|
||||||
"mode-watcher": "^0.1.2",
|
"mode-watcher": "^0.1.2",
|
||||||
"pocketbase": "^0.21.0",
|
"pocketbase": "^0.21.0",
|
||||||
"radix-icons-svelte": "^1.2.1",
|
"radix-icons-svelte": "^1.2.1",
|
||||||
|
"svelte-headless-table": "^0.18.1",
|
||||||
"tailwind-merge": "^2.2.1",
|
"tailwind-merge": "^2.2.1",
|
||||||
"tailwind-variants": "^0.1.20"
|
"tailwind-variants": "^0.1.20"
|
||||||
}
|
}
|
||||||
|
|
186
apps/web/pnpm-lock.yaml
generated
186
apps/web/pnpm-lock.yaml
generated
|
@ -11,6 +11,12 @@ dependencies:
|
||||||
clsx:
|
clsx:
|
||||||
specifier: ^2.1.0
|
specifier: ^2.1.0
|
||||||
version: 2.1.0
|
version: 2.1.0
|
||||||
|
cmdk-sv:
|
||||||
|
specifier: ^0.0.13
|
||||||
|
version: 0.0.13(svelte@4.2.9)
|
||||||
|
formsnap:
|
||||||
|
specifier: ^0.4.3
|
||||||
|
version: 0.4.3(svelte@4.2.9)(sveltekit-superforms@1.13.4)(zod@3.22.4)
|
||||||
lucide-svelte:
|
lucide-svelte:
|
||||||
specifier: ^0.316.0
|
specifier: ^0.316.0
|
||||||
version: 0.316.0(svelte@4.2.9)
|
version: 0.316.0(svelte@4.2.9)
|
||||||
|
@ -23,6 +29,9 @@ dependencies:
|
||||||
radix-icons-svelte:
|
radix-icons-svelte:
|
||||||
specifier: ^1.2.1
|
specifier: ^1.2.1
|
||||||
version: 1.2.1
|
version: 1.2.1
|
||||||
|
svelte-headless-table:
|
||||||
|
specifier: ^0.18.1
|
||||||
|
version: 0.18.1(svelte@4.2.9)
|
||||||
tailwind-merge:
|
tailwind-merge:
|
||||||
specifier: ^2.2.1
|
specifier: ^2.2.1
|
||||||
version: 2.2.1
|
version: 2.2.1
|
||||||
|
@ -82,6 +91,9 @@ devDependencies:
|
||||||
svelte-check:
|
svelte-check:
|
||||||
specifier: ^3.6.0
|
specifier: ^3.6.0
|
||||||
version: 3.6.3(postcss-load-config@5.0.2)(postcss@8.4.33)(svelte@4.2.9)
|
version: 3.6.3(postcss-load-config@5.0.2)(postcss@8.4.33)(svelte@4.2.9)
|
||||||
|
sveltekit-superforms:
|
||||||
|
specifier: ^1.13.4
|
||||||
|
version: 1.13.4(@sveltejs/kit@2.5.0)(svelte@4.2.9)(zod@3.22.4)
|
||||||
tailwindcss:
|
tailwindcss:
|
||||||
specifier: ^3.3.6
|
specifier: ^3.3.6
|
||||||
version: 3.4.1
|
version: 3.4.1
|
||||||
|
@ -94,6 +106,9 @@ devDependencies:
|
||||||
vite:
|
vite:
|
||||||
specifier: ^5.0.3
|
specifier: ^5.0.3
|
||||||
version: 5.0.12
|
version: 5.0.12
|
||||||
|
zod:
|
||||||
|
specifier: ^3.22.4
|
||||||
|
version: 3.22.4
|
||||||
|
|
||||||
packages:
|
packages:
|
||||||
|
|
||||||
|
@ -126,7 +141,6 @@ packages:
|
||||||
cpu: [ppc64]
|
cpu: [ppc64]
|
||||||
os: [aix]
|
os: [aix]
|
||||||
requiresBuild: true
|
requiresBuild: true
|
||||||
dev: true
|
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
/@esbuild/android-arm64@0.19.12:
|
/@esbuild/android-arm64@0.19.12:
|
||||||
|
@ -135,7 +149,6 @@ packages:
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [android]
|
os: [android]
|
||||||
requiresBuild: true
|
requiresBuild: true
|
||||||
dev: true
|
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
/@esbuild/android-arm@0.19.12:
|
/@esbuild/android-arm@0.19.12:
|
||||||
|
@ -144,7 +157,6 @@ packages:
|
||||||
cpu: [arm]
|
cpu: [arm]
|
||||||
os: [android]
|
os: [android]
|
||||||
requiresBuild: true
|
requiresBuild: true
|
||||||
dev: true
|
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
/@esbuild/android-x64@0.19.12:
|
/@esbuild/android-x64@0.19.12:
|
||||||
|
@ -153,7 +165,6 @@ packages:
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [android]
|
os: [android]
|
||||||
requiresBuild: true
|
requiresBuild: true
|
||||||
dev: true
|
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
/@esbuild/darwin-arm64@0.19.12:
|
/@esbuild/darwin-arm64@0.19.12:
|
||||||
|
@ -162,7 +173,6 @@ packages:
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [darwin]
|
os: [darwin]
|
||||||
requiresBuild: true
|
requiresBuild: true
|
||||||
dev: true
|
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
/@esbuild/darwin-x64@0.19.12:
|
/@esbuild/darwin-x64@0.19.12:
|
||||||
|
@ -171,7 +181,6 @@ packages:
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [darwin]
|
os: [darwin]
|
||||||
requiresBuild: true
|
requiresBuild: true
|
||||||
dev: true
|
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
/@esbuild/freebsd-arm64@0.19.12:
|
/@esbuild/freebsd-arm64@0.19.12:
|
||||||
|
@ -180,7 +189,6 @@ packages:
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [freebsd]
|
os: [freebsd]
|
||||||
requiresBuild: true
|
requiresBuild: true
|
||||||
dev: true
|
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
/@esbuild/freebsd-x64@0.19.12:
|
/@esbuild/freebsd-x64@0.19.12:
|
||||||
|
@ -189,7 +197,6 @@ packages:
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [freebsd]
|
os: [freebsd]
|
||||||
requiresBuild: true
|
requiresBuild: true
|
||||||
dev: true
|
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
/@esbuild/linux-arm64@0.19.12:
|
/@esbuild/linux-arm64@0.19.12:
|
||||||
|
@ -198,7 +205,6 @@ packages:
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
requiresBuild: true
|
requiresBuild: true
|
||||||
dev: true
|
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
/@esbuild/linux-arm@0.19.12:
|
/@esbuild/linux-arm@0.19.12:
|
||||||
|
@ -207,7 +213,6 @@ packages:
|
||||||
cpu: [arm]
|
cpu: [arm]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
requiresBuild: true
|
requiresBuild: true
|
||||||
dev: true
|
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
/@esbuild/linux-ia32@0.19.12:
|
/@esbuild/linux-ia32@0.19.12:
|
||||||
|
@ -216,7 +221,6 @@ packages:
|
||||||
cpu: [ia32]
|
cpu: [ia32]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
requiresBuild: true
|
requiresBuild: true
|
||||||
dev: true
|
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
/@esbuild/linux-loong64@0.19.12:
|
/@esbuild/linux-loong64@0.19.12:
|
||||||
|
@ -225,7 +229,6 @@ packages:
|
||||||
cpu: [loong64]
|
cpu: [loong64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
requiresBuild: true
|
requiresBuild: true
|
||||||
dev: true
|
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
/@esbuild/linux-mips64el@0.19.12:
|
/@esbuild/linux-mips64el@0.19.12:
|
||||||
|
@ -234,7 +237,6 @@ packages:
|
||||||
cpu: [mips64el]
|
cpu: [mips64el]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
requiresBuild: true
|
requiresBuild: true
|
||||||
dev: true
|
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
/@esbuild/linux-ppc64@0.19.12:
|
/@esbuild/linux-ppc64@0.19.12:
|
||||||
|
@ -243,7 +245,6 @@ packages:
|
||||||
cpu: [ppc64]
|
cpu: [ppc64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
requiresBuild: true
|
requiresBuild: true
|
||||||
dev: true
|
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
/@esbuild/linux-riscv64@0.19.12:
|
/@esbuild/linux-riscv64@0.19.12:
|
||||||
|
@ -252,7 +253,6 @@ packages:
|
||||||
cpu: [riscv64]
|
cpu: [riscv64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
requiresBuild: true
|
requiresBuild: true
|
||||||
dev: true
|
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
/@esbuild/linux-s390x@0.19.12:
|
/@esbuild/linux-s390x@0.19.12:
|
||||||
|
@ -261,7 +261,6 @@ packages:
|
||||||
cpu: [s390x]
|
cpu: [s390x]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
requiresBuild: true
|
requiresBuild: true
|
||||||
dev: true
|
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
/@esbuild/linux-x64@0.19.12:
|
/@esbuild/linux-x64@0.19.12:
|
||||||
|
@ -270,7 +269,6 @@ packages:
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
requiresBuild: true
|
requiresBuild: true
|
||||||
dev: true
|
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
/@esbuild/netbsd-x64@0.19.12:
|
/@esbuild/netbsd-x64@0.19.12:
|
||||||
|
@ -279,7 +277,6 @@ packages:
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [netbsd]
|
os: [netbsd]
|
||||||
requiresBuild: true
|
requiresBuild: true
|
||||||
dev: true
|
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
/@esbuild/openbsd-x64@0.19.12:
|
/@esbuild/openbsd-x64@0.19.12:
|
||||||
|
@ -288,7 +285,6 @@ packages:
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [openbsd]
|
os: [openbsd]
|
||||||
requiresBuild: true
|
requiresBuild: true
|
||||||
dev: true
|
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
/@esbuild/sunos-x64@0.19.12:
|
/@esbuild/sunos-x64@0.19.12:
|
||||||
|
@ -297,7 +293,6 @@ packages:
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [sunos]
|
os: [sunos]
|
||||||
requiresBuild: true
|
requiresBuild: true
|
||||||
dev: true
|
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
/@esbuild/win32-arm64@0.19.12:
|
/@esbuild/win32-arm64@0.19.12:
|
||||||
|
@ -306,7 +301,6 @@ packages:
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [win32]
|
os: [win32]
|
||||||
requiresBuild: true
|
requiresBuild: true
|
||||||
dev: true
|
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
/@esbuild/win32-ia32@0.19.12:
|
/@esbuild/win32-ia32@0.19.12:
|
||||||
|
@ -315,7 +309,6 @@ packages:
|
||||||
cpu: [ia32]
|
cpu: [ia32]
|
||||||
os: [win32]
|
os: [win32]
|
||||||
requiresBuild: true
|
requiresBuild: true
|
||||||
dev: true
|
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
/@esbuild/win32-x64@0.19.12:
|
/@esbuild/win32-x64@0.19.12:
|
||||||
|
@ -324,7 +317,6 @@ packages:
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [win32]
|
os: [win32]
|
||||||
requiresBuild: true
|
requiresBuild: true
|
||||||
dev: true
|
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
/@eslint-community/eslint-utils@4.4.0(eslint@8.56.0):
|
/@eslint-community/eslint-utils@4.4.0(eslint@8.56.0):
|
||||||
|
@ -443,6 +435,20 @@ packages:
|
||||||
'@jridgewell/resolve-uri': 3.1.1
|
'@jridgewell/resolve-uri': 3.1.1
|
||||||
'@jridgewell/sourcemap-codec': 1.4.15
|
'@jridgewell/sourcemap-codec': 1.4.15
|
||||||
|
|
||||||
|
/@melt-ui/svelte@0.61.2(svelte@4.2.9):
|
||||||
|
resolution: {integrity: sha512-BHkD9G31zQBToA4euDRBgTQRvWxT9scufOVCXgDO6HKTvyxFspbWT2bgiSFqAK4BbAGDn9Ao36Q8F9O71KN4OQ==}
|
||||||
|
peerDependencies:
|
||||||
|
svelte: '>=3 <5'
|
||||||
|
dependencies:
|
||||||
|
'@floating-ui/core': 1.6.0
|
||||||
|
'@floating-ui/dom': 1.6.1
|
||||||
|
'@internationalized/date': 3.5.1
|
||||||
|
dequal: 2.0.3
|
||||||
|
focus-trap: 7.5.4
|
||||||
|
nanoid: 4.0.2
|
||||||
|
svelte: 4.2.9
|
||||||
|
dev: false
|
||||||
|
|
||||||
/@melt-ui/svelte@0.68.0(svelte@4.2.9):
|
/@melt-ui/svelte@0.68.0(svelte@4.2.9):
|
||||||
resolution: {integrity: sha512-/QvA98hnYEodZtHJ71+ocum/WWp30hVNt3F8uiZKnNYwZDaiQYjlyR9AaGKYcZLCe6R68op1mfCzc0kTzJilyA==}
|
resolution: {integrity: sha512-/QvA98hnYEodZtHJ71+ocum/WWp30hVNt3F8uiZKnNYwZDaiQYjlyR9AaGKYcZLCe6R68op1mfCzc0kTzJilyA==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
|
@ -483,14 +489,12 @@ packages:
|
||||||
|
|
||||||
/@polka/url@1.0.0-next.24:
|
/@polka/url@1.0.0-next.24:
|
||||||
resolution: {integrity: sha512-2LuNTFBIO0m7kKIQvvPHN6UE63VjpmL9rnEEaOOaiSPbZK+zUOYIzBAWcED+3XYzhYsd/0mD57VdxAEqqV52CQ==}
|
resolution: {integrity: sha512-2LuNTFBIO0m7kKIQvvPHN6UE63VjpmL9rnEEaOOaiSPbZK+zUOYIzBAWcED+3XYzhYsd/0mD57VdxAEqqV52CQ==}
|
||||||
dev: true
|
|
||||||
|
|
||||||
/@rollup/rollup-android-arm-eabi@4.9.6:
|
/@rollup/rollup-android-arm-eabi@4.9.6:
|
||||||
resolution: {integrity: sha512-MVNXSSYN6QXOulbHpLMKYi60ppyO13W9my1qogeiAqtjb2yR4LSmfU2+POvDkLzhjYLXz9Rf9+9a3zFHW1Lecg==}
|
resolution: {integrity: sha512-MVNXSSYN6QXOulbHpLMKYi60ppyO13W9my1qogeiAqtjb2yR4LSmfU2+POvDkLzhjYLXz9Rf9+9a3zFHW1Lecg==}
|
||||||
cpu: [arm]
|
cpu: [arm]
|
||||||
os: [android]
|
os: [android]
|
||||||
requiresBuild: true
|
requiresBuild: true
|
||||||
dev: true
|
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
/@rollup/rollup-android-arm64@4.9.6:
|
/@rollup/rollup-android-arm64@4.9.6:
|
||||||
|
@ -498,7 +502,6 @@ packages:
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [android]
|
os: [android]
|
||||||
requiresBuild: true
|
requiresBuild: true
|
||||||
dev: true
|
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
/@rollup/rollup-darwin-arm64@4.9.6:
|
/@rollup/rollup-darwin-arm64@4.9.6:
|
||||||
|
@ -506,7 +509,6 @@ packages:
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [darwin]
|
os: [darwin]
|
||||||
requiresBuild: true
|
requiresBuild: true
|
||||||
dev: true
|
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
/@rollup/rollup-darwin-x64@4.9.6:
|
/@rollup/rollup-darwin-x64@4.9.6:
|
||||||
|
@ -514,7 +516,6 @@ packages:
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [darwin]
|
os: [darwin]
|
||||||
requiresBuild: true
|
requiresBuild: true
|
||||||
dev: true
|
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
/@rollup/rollup-linux-arm-gnueabihf@4.9.6:
|
/@rollup/rollup-linux-arm-gnueabihf@4.9.6:
|
||||||
|
@ -522,7 +523,6 @@ packages:
|
||||||
cpu: [arm]
|
cpu: [arm]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
requiresBuild: true
|
requiresBuild: true
|
||||||
dev: true
|
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
/@rollup/rollup-linux-arm64-gnu@4.9.6:
|
/@rollup/rollup-linux-arm64-gnu@4.9.6:
|
||||||
|
@ -530,7 +530,6 @@ packages:
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
requiresBuild: true
|
requiresBuild: true
|
||||||
dev: true
|
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
/@rollup/rollup-linux-arm64-musl@4.9.6:
|
/@rollup/rollup-linux-arm64-musl@4.9.6:
|
||||||
|
@ -538,7 +537,6 @@ packages:
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
requiresBuild: true
|
requiresBuild: true
|
||||||
dev: true
|
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
/@rollup/rollup-linux-riscv64-gnu@4.9.6:
|
/@rollup/rollup-linux-riscv64-gnu@4.9.6:
|
||||||
|
@ -546,7 +544,6 @@ packages:
|
||||||
cpu: [riscv64]
|
cpu: [riscv64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
requiresBuild: true
|
requiresBuild: true
|
||||||
dev: true
|
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
/@rollup/rollup-linux-x64-gnu@4.9.6:
|
/@rollup/rollup-linux-x64-gnu@4.9.6:
|
||||||
|
@ -554,7 +551,6 @@ packages:
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
requiresBuild: true
|
requiresBuild: true
|
||||||
dev: true
|
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
/@rollup/rollup-linux-x64-musl@4.9.6:
|
/@rollup/rollup-linux-x64-musl@4.9.6:
|
||||||
|
@ -562,7 +558,6 @@ packages:
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
requiresBuild: true
|
requiresBuild: true
|
||||||
dev: true
|
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
/@rollup/rollup-win32-arm64-msvc@4.9.6:
|
/@rollup/rollup-win32-arm64-msvc@4.9.6:
|
||||||
|
@ -570,7 +565,6 @@ packages:
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [win32]
|
os: [win32]
|
||||||
requiresBuild: true
|
requiresBuild: true
|
||||||
dev: true
|
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
/@rollup/rollup-win32-ia32-msvc@4.9.6:
|
/@rollup/rollup-win32-ia32-msvc@4.9.6:
|
||||||
|
@ -578,7 +572,6 @@ packages:
|
||||||
cpu: [ia32]
|
cpu: [ia32]
|
||||||
os: [win32]
|
os: [win32]
|
||||||
requiresBuild: true
|
requiresBuild: true
|
||||||
dev: true
|
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
/@rollup/rollup-win32-x64-msvc@4.9.6:
|
/@rollup/rollup-win32-x64-msvc@4.9.6:
|
||||||
|
@ -586,7 +579,6 @@ packages:
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [win32]
|
os: [win32]
|
||||||
requiresBuild: true
|
requiresBuild: true
|
||||||
dev: true
|
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
/@sveltejs/adapter-auto@3.1.1(@sveltejs/kit@2.5.0):
|
/@sveltejs/adapter-auto@3.1.1(@sveltejs/kit@2.5.0):
|
||||||
|
@ -623,7 +615,6 @@ packages:
|
||||||
svelte: 4.2.9
|
svelte: 4.2.9
|
||||||
tiny-glob: 0.2.9
|
tiny-glob: 0.2.9
|
||||||
vite: 5.0.12
|
vite: 5.0.12
|
||||||
dev: true
|
|
||||||
|
|
||||||
/@sveltejs/vite-plugin-svelte-inspector@2.0.0(@sveltejs/vite-plugin-svelte@3.0.2)(svelte@4.2.9)(vite@5.0.12):
|
/@sveltejs/vite-plugin-svelte-inspector@2.0.0(@sveltejs/vite-plugin-svelte@3.0.2)(svelte@4.2.9)(vite@5.0.12):
|
||||||
resolution: {integrity: sha512-gjr9ZFg1BSlIpfZ4PRewigrvYmHWbDrq2uvvPB1AmTWKuM+dI1JXQSUu2pIrYLb/QncyiIGkFDFKTwJ0XqQZZg==}
|
resolution: {integrity: sha512-gjr9ZFg1BSlIpfZ4PRewigrvYmHWbDrq2uvvPB1AmTWKuM+dI1JXQSUu2pIrYLb/QncyiIGkFDFKTwJ0XqQZZg==}
|
||||||
|
@ -639,7 +630,6 @@ packages:
|
||||||
vite: 5.0.12
|
vite: 5.0.12
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
dev: true
|
|
||||||
|
|
||||||
/@sveltejs/vite-plugin-svelte@3.0.2(svelte@4.2.9)(vite@5.0.12):
|
/@sveltejs/vite-plugin-svelte@3.0.2(svelte@4.2.9)(vite@5.0.12):
|
||||||
resolution: {integrity: sha512-MpmF/cju2HqUls50WyTHQBZUV3ovV/Uk8k66AN2gwHogNAG8wnW8xtZDhzNBsFJJuvmq1qnzA5kE7YfMJNFv2Q==}
|
resolution: {integrity: sha512-MpmF/cju2HqUls50WyTHQBZUV3ovV/Uk8k66AN2gwHogNAG8wnW8xtZDhzNBsFJJuvmq1qnzA5kE7YfMJNFv2Q==}
|
||||||
|
@ -659,7 +649,6 @@ packages:
|
||||||
vitefu: 0.2.5(vite@5.0.12)
|
vitefu: 0.2.5(vite@5.0.12)
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
dev: true
|
|
||||||
|
|
||||||
/@swc/helpers@0.5.3:
|
/@swc/helpers@0.5.3:
|
||||||
resolution: {integrity: sha512-FaruWX6KdudYloq1AHD/4nU+UsMTdNE8CKyrseXWEcgjDAbvkwJg2QGPAnfIJLIWsjZOSPLOAykK6fuYp4vp4A==}
|
resolution: {integrity: sha512-FaruWX6KdudYloq1AHD/4nU+UsMTdNE8CKyrseXWEcgjDAbvkwJg2QGPAnfIJLIWsjZOSPLOAykK6fuYp4vp4A==}
|
||||||
|
@ -669,7 +658,6 @@ packages:
|
||||||
|
|
||||||
/@types/cookie@0.6.0:
|
/@types/cookie@0.6.0:
|
||||||
resolution: {integrity: sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==}
|
resolution: {integrity: sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==}
|
||||||
dev: true
|
|
||||||
|
|
||||||
/@types/eslint@8.56.0:
|
/@types/eslint@8.56.0:
|
||||||
resolution: {integrity: sha512-FlsN0p4FhuYRjIxpbdXovvHQhtlG05O1GG/RNWvdAxTboR438IOTwmrY/vLA+Xfgg06BTkP045M3vpFwTMv1dg==}
|
resolution: {integrity: sha512-FlsN0p4FhuYRjIxpbdXovvHQhtlG05O1GG/RNWvdAxTboR438IOTwmrY/vLA+Xfgg06BTkP045M3vpFwTMv1dg==}
|
||||||
|
@ -935,6 +923,16 @@ packages:
|
||||||
svelte: 4.2.9
|
svelte: 4.2.9
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/bits-ui@0.9.9(svelte@4.2.9):
|
||||||
|
resolution: {integrity: sha512-LkdkyTtpXdkjBzPZJVJgpcre4fut6DONoprMfadHFo82HNUhph+02CxDjYEcZcThb5z4YjSxMlCYvQPZm+YtfQ==}
|
||||||
|
peerDependencies:
|
||||||
|
svelte: ^4.0.0
|
||||||
|
dependencies:
|
||||||
|
'@melt-ui/svelte': 0.61.2(svelte@4.2.9)
|
||||||
|
nanoid: 5.0.4
|
||||||
|
svelte: 4.2.9
|
||||||
|
dev: false
|
||||||
|
|
||||||
/brace-expansion@1.1.11:
|
/brace-expansion@1.1.11:
|
||||||
resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==}
|
resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==}
|
||||||
dependencies:
|
dependencies:
|
||||||
|
@ -1008,6 +1006,16 @@ packages:
|
||||||
engines: {node: '>=6'}
|
engines: {node: '>=6'}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/cmdk-sv@0.0.13(svelte@4.2.9):
|
||||||
|
resolution: {integrity: sha512-WrYn0MMdVyzJx+KuOQy028/7mv+uMwO1cxVBM0uJ4KA+50PX792epsj8Yw3It8WfWR8Rae7siBCg54mIAlKsiw==}
|
||||||
|
peerDependencies:
|
||||||
|
svelte: ^4.0.0
|
||||||
|
dependencies:
|
||||||
|
bits-ui: 0.9.9(svelte@4.2.9)
|
||||||
|
nanoid: 5.0.4
|
||||||
|
svelte: 4.2.9
|
||||||
|
dev: false
|
||||||
|
|
||||||
/code-red@1.0.4:
|
/code-red@1.0.4:
|
||||||
resolution: {integrity: sha512-7qJWqItLA8/VPVlKJlFXU+NBlo/qyfs39aJcuMT/2ere32ZqvF5OSxgdM5xOfJJ7O429gg2HM47y8v9P+9wrNw==}
|
resolution: {integrity: sha512-7qJWqItLA8/VPVlKJlFXU+NBlo/qyfs39aJcuMT/2ere32ZqvF5OSxgdM5xOfJJ7O429gg2HM47y8v9P+9wrNw==}
|
||||||
dependencies:
|
dependencies:
|
||||||
|
@ -1037,7 +1045,6 @@ packages:
|
||||||
/cookie@0.6.0:
|
/cookie@0.6.0:
|
||||||
resolution: {integrity: sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==}
|
resolution: {integrity: sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==}
|
||||||
engines: {node: '>= 0.6'}
|
engines: {node: '>= 0.6'}
|
||||||
dev: true
|
|
||||||
|
|
||||||
/cross-spawn@7.0.3:
|
/cross-spawn@7.0.3:
|
||||||
resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==}
|
resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==}
|
||||||
|
@ -1069,7 +1076,6 @@ packages:
|
||||||
optional: true
|
optional: true
|
||||||
dependencies:
|
dependencies:
|
||||||
ms: 2.1.2
|
ms: 2.1.2
|
||||||
dev: true
|
|
||||||
|
|
||||||
/deep-is@0.1.4:
|
/deep-is@0.1.4:
|
||||||
resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==}
|
resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==}
|
||||||
|
@ -1078,7 +1084,6 @@ packages:
|
||||||
/deepmerge@4.3.1:
|
/deepmerge@4.3.1:
|
||||||
resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==}
|
resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==}
|
||||||
engines: {node: '>=0.10.0'}
|
engines: {node: '>=0.10.0'}
|
||||||
dev: true
|
|
||||||
|
|
||||||
/dequal@2.0.3:
|
/dequal@2.0.3:
|
||||||
resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==}
|
resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==}
|
||||||
|
@ -1091,7 +1096,6 @@ packages:
|
||||||
|
|
||||||
/devalue@4.3.2:
|
/devalue@4.3.2:
|
||||||
resolution: {integrity: sha512-KqFl6pOgOW+Y6wJgu80rHpo2/3H07vr8ntR9rkkFIRETewbf5GaYYcakYfiKz89K+sLsuPkQIZaXDMjUObZwWg==}
|
resolution: {integrity: sha512-KqFl6pOgOW+Y6wJgu80rHpo2/3H07vr8ntR9rkkFIRETewbf5GaYYcakYfiKz89K+sLsuPkQIZaXDMjUObZwWg==}
|
||||||
dev: true
|
|
||||||
|
|
||||||
/didyoumean@1.2.2:
|
/didyoumean@1.2.2:
|
||||||
resolution: {integrity: sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==}
|
resolution: {integrity: sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==}
|
||||||
|
@ -1159,7 +1163,6 @@ packages:
|
||||||
'@esbuild/win32-arm64': 0.19.12
|
'@esbuild/win32-arm64': 0.19.12
|
||||||
'@esbuild/win32-ia32': 0.19.12
|
'@esbuild/win32-ia32': 0.19.12
|
||||||
'@esbuild/win32-x64': 0.19.12
|
'@esbuild/win32-x64': 0.19.12
|
||||||
dev: true
|
|
||||||
|
|
||||||
/escalade@3.1.1:
|
/escalade@3.1.1:
|
||||||
resolution: {integrity: sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==}
|
resolution: {integrity: sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==}
|
||||||
|
@ -1280,7 +1283,6 @@ packages:
|
||||||
|
|
||||||
/esm-env@1.0.0:
|
/esm-env@1.0.0:
|
||||||
resolution: {integrity: sha512-Cf6VksWPsTuW01vU9Mk/3vRue91Zevka5SjyNf3nEpokFRuqt/KjUQoGAwq9qMmhpLTHmXzSIrFRw8zxWzmFBA==}
|
resolution: {integrity: sha512-Cf6VksWPsTuW01vU9Mk/3vRue91Zevka5SjyNf3nEpokFRuqt/KjUQoGAwq9qMmhpLTHmXzSIrFRw8zxWzmFBA==}
|
||||||
dev: true
|
|
||||||
|
|
||||||
/espree@9.6.1:
|
/espree@9.6.1:
|
||||||
resolution: {integrity: sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==}
|
resolution: {integrity: sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==}
|
||||||
|
@ -1394,6 +1396,18 @@ packages:
|
||||||
cross-spawn: 7.0.3
|
cross-spawn: 7.0.3
|
||||||
signal-exit: 4.1.0
|
signal-exit: 4.1.0
|
||||||
|
|
||||||
|
/formsnap@0.4.3(svelte@4.2.9)(sveltekit-superforms@1.13.4)(zod@3.22.4):
|
||||||
|
resolution: {integrity: sha512-PWVq78XVUHhAU1tcVGKeGamk6B4Opkk1uVNRW2YofiQpnA5Bry1c3TQjB9cVDw5u4oAwmDvIoAzVHlrAIgc+tw==}
|
||||||
|
peerDependencies:
|
||||||
|
svelte: ^4.0.0
|
||||||
|
sveltekit-superforms: ^1.7.1
|
||||||
|
zod: ^3.22.2
|
||||||
|
dependencies:
|
||||||
|
svelte: 4.2.9
|
||||||
|
sveltekit-superforms: 1.13.4(@sveltejs/kit@2.5.0)(svelte@4.2.9)(zod@3.22.4)
|
||||||
|
zod: 3.22.4
|
||||||
|
dev: false
|
||||||
|
|
||||||
/fraction.js@4.3.7:
|
/fraction.js@4.3.7:
|
||||||
resolution: {integrity: sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==}
|
resolution: {integrity: sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==}
|
||||||
dev: true
|
dev: true
|
||||||
|
@ -1455,7 +1469,6 @@ packages:
|
||||||
|
|
||||||
/globalyzer@0.1.0:
|
/globalyzer@0.1.0:
|
||||||
resolution: {integrity: sha512-40oNTM9UfG6aBmuKxk/giHn5nQ8RVz/SS4Ir6zgzOv9/qC3kKZ9v4etGTcJbEl/NyVQH7FGU7d+X1egr57Md2Q==}
|
resolution: {integrity: sha512-40oNTM9UfG6aBmuKxk/giHn5nQ8RVz/SS4Ir6zgzOv9/qC3kKZ9v4etGTcJbEl/NyVQH7FGU7d+X1egr57Md2Q==}
|
||||||
dev: true
|
|
||||||
|
|
||||||
/globby@11.1.0:
|
/globby@11.1.0:
|
||||||
resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==}
|
resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==}
|
||||||
|
@ -1471,7 +1484,6 @@ packages:
|
||||||
|
|
||||||
/globrex@0.1.2:
|
/globrex@0.1.2:
|
||||||
resolution: {integrity: sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==}
|
resolution: {integrity: sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==}
|
||||||
dev: true
|
|
||||||
|
|
||||||
/graceful-fs@4.2.11:
|
/graceful-fs@4.2.11:
|
||||||
resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==}
|
resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==}
|
||||||
|
@ -1507,7 +1519,6 @@ packages:
|
||||||
|
|
||||||
/import-meta-resolve@4.0.0:
|
/import-meta-resolve@4.0.0:
|
||||||
resolution: {integrity: sha512-okYUR7ZQPH+efeuMJGlq4f8ubUgO50kByRPyt/Cy1Io4PSRsPjxME+YlVaCOx+NIToW7hCsZNFJyTPFFKepRSA==}
|
resolution: {integrity: sha512-okYUR7ZQPH+efeuMJGlq4f8ubUgO50kByRPyt/Cy1Io4PSRsPjxME+YlVaCOx+NIToW7hCsZNFJyTPFFKepRSA==}
|
||||||
dev: true
|
|
||||||
|
|
||||||
/imurmurhash@0.1.4:
|
/imurmurhash@0.1.4:
|
||||||
resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==}
|
resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==}
|
||||||
|
@ -1607,7 +1618,10 @@ packages:
|
||||||
/kleur@4.1.5:
|
/kleur@4.1.5:
|
||||||
resolution: {integrity: sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==}
|
resolution: {integrity: sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==}
|
||||||
engines: {node: '>=6'}
|
engines: {node: '>=6'}
|
||||||
dev: true
|
|
||||||
|
/klona@2.0.6:
|
||||||
|
resolution: {integrity: sha512-dhG34DXATL5hSxJbIexCft8FChFXtmskoZYnoPWjXQuebWYCNkVeV3KkGegCK9CP1oswI/vQibS2GY7Em/sJJA==}
|
||||||
|
engines: {node: '>= 8'}
|
||||||
|
|
||||||
/known-css-properties@0.29.0:
|
/known-css-properties@0.29.0:
|
||||||
resolution: {integrity: sha512-Ne7wqW7/9Cz54PDt4I3tcV+hAyat8ypyOGzYRJQfdxnnjeWsTxt1cy8pjvvKeI5kfXuyvULyeeAvwvvtAX3ayQ==}
|
resolution: {integrity: sha512-Ne7wqW7/9Cz54PDt4I3tcV+hAyat8ypyOGzYRJQfdxnnjeWsTxt1cy8pjvvKeI5kfXuyvULyeeAvwvvtAX3ayQ==}
|
||||||
|
@ -1728,16 +1742,13 @@ packages:
|
||||||
/mri@1.2.0:
|
/mri@1.2.0:
|
||||||
resolution: {integrity: sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==}
|
resolution: {integrity: sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==}
|
||||||
engines: {node: '>=4'}
|
engines: {node: '>=4'}
|
||||||
dev: true
|
|
||||||
|
|
||||||
/mrmime@2.0.0:
|
/mrmime@2.0.0:
|
||||||
resolution: {integrity: sha512-eu38+hdgojoyq63s+yTpN4XMBdt5l8HhMhc4VKLO9KM5caLIBvUm4thi7fFaxyTmCKeNnXZ5pAlBwCUnhA09uw==}
|
resolution: {integrity: sha512-eu38+hdgojoyq63s+yTpN4XMBdt5l8HhMhc4VKLO9KM5caLIBvUm4thi7fFaxyTmCKeNnXZ5pAlBwCUnhA09uw==}
|
||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
dev: true
|
|
||||||
|
|
||||||
/ms@2.1.2:
|
/ms@2.1.2:
|
||||||
resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==}
|
resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==}
|
||||||
dev: true
|
|
||||||
|
|
||||||
/mz@2.7.0:
|
/mz@2.7.0:
|
||||||
resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==}
|
resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==}
|
||||||
|
@ -1751,6 +1762,12 @@ packages:
|
||||||
engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
|
engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
|
/nanoid@4.0.2:
|
||||||
|
resolution: {integrity: sha512-7ZtY5KTCNheRGfEFxnedV5zFiORN1+Y1N6zvPTnHQd8ENUvfaDBeuJDZb2bN/oXwXxu3qkTXDzy57W5vAmDTBw==}
|
||||||
|
engines: {node: ^14 || ^16 || >=18}
|
||||||
|
hasBin: true
|
||||||
|
dev: false
|
||||||
|
|
||||||
/nanoid@5.0.4:
|
/nanoid@5.0.4:
|
||||||
resolution: {integrity: sha512-vAjmBf13gsmhXSgBrtIclinISzFFy22WwCYoyilZlsrRXNIHSwgFQ1bEdjRwMT3aoadeIF6HMuDRlOxzfXV8ig==}
|
resolution: {integrity: sha512-vAjmBf13gsmhXSgBrtIclinISzFFy22WwCYoyilZlsrRXNIHSwgFQ1bEdjRwMT3aoadeIF6HMuDRlOxzfXV8ig==}
|
||||||
engines: {node: ^18 || >=20}
|
engines: {node: ^18 || >=20}
|
||||||
|
@ -2144,7 +2161,6 @@ packages:
|
||||||
'@rollup/rollup-win32-ia32-msvc': 4.9.6
|
'@rollup/rollup-win32-ia32-msvc': 4.9.6
|
||||||
'@rollup/rollup-win32-x64-msvc': 4.9.6
|
'@rollup/rollup-win32-x64-msvc': 4.9.6
|
||||||
fsevents: 2.3.3
|
fsevents: 2.3.3
|
||||||
dev: true
|
|
||||||
|
|
||||||
/run-parallel@1.2.0:
|
/run-parallel@1.2.0:
|
||||||
resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==}
|
resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==}
|
||||||
|
@ -2156,7 +2172,6 @@ packages:
|
||||||
engines: {node: '>=6'}
|
engines: {node: '>=6'}
|
||||||
dependencies:
|
dependencies:
|
||||||
mri: 1.2.0
|
mri: 1.2.0
|
||||||
dev: true
|
|
||||||
|
|
||||||
/sander@0.5.1:
|
/sander@0.5.1:
|
||||||
resolution: {integrity: sha512-3lVqBir7WuKDHGrKRDn/1Ye3kwpXaDOMsiRP1wd6wpZW56gJhsbp5RqQpA6JG/P+pkXizygnr1dKR8vzWaVsfA==}
|
resolution: {integrity: sha512-3lVqBir7WuKDHGrKRDn/1Ye3kwpXaDOMsiRP1wd6wpZW56gJhsbp5RqQpA6JG/P+pkXizygnr1dKR8vzWaVsfA==}
|
||||||
|
@ -2177,7 +2192,6 @@ packages:
|
||||||
|
|
||||||
/set-cookie-parser@2.6.0:
|
/set-cookie-parser@2.6.0:
|
||||||
resolution: {integrity: sha512-RVnVQxTXuerk653XfuliOxBP81Sf0+qfQE73LIYKcyMYHG94AuH0kgrQpRDuTZnSmjpysHmzxJXKNfa6PjFhyQ==}
|
resolution: {integrity: sha512-RVnVQxTXuerk653XfuliOxBP81Sf0+qfQE73LIYKcyMYHG94AuH0kgrQpRDuTZnSmjpysHmzxJXKNfa6PjFhyQ==}
|
||||||
dev: true
|
|
||||||
|
|
||||||
/shebang-command@2.0.0:
|
/shebang-command@2.0.0:
|
||||||
resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==}
|
resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==}
|
||||||
|
@ -2200,7 +2214,6 @@ packages:
|
||||||
'@polka/url': 1.0.0-next.24
|
'@polka/url': 1.0.0-next.24
|
||||||
mrmime: 2.0.0
|
mrmime: 2.0.0
|
||||||
totalist: 3.0.1
|
totalist: 3.0.1
|
||||||
dev: true
|
|
||||||
|
|
||||||
/slash@3.0.0:
|
/slash@3.0.0:
|
||||||
resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==}
|
resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==}
|
||||||
|
@ -2329,6 +2342,17 @@ packages:
|
||||||
svelte: 4.2.9
|
svelte: 4.2.9
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/svelte-headless-table@0.18.1(svelte@4.2.9):
|
||||||
|
resolution: {integrity: sha512-pcZIi36u8RV9B3m0oG6000az7tvT6CCK+c8qBUuNUQSChsfJySC5ryGdJSTFlAYBVRGUgZlqYOKGUgSbOfIrnA==}
|
||||||
|
peerDependencies:
|
||||||
|
svelte: ^4.0.0
|
||||||
|
dependencies:
|
||||||
|
svelte: 4.2.9
|
||||||
|
svelte-keyed: 2.0.0(svelte@4.2.9)
|
||||||
|
svelte-render: 2.0.0(svelte@4.2.9)
|
||||||
|
svelte-subscribe: 2.0.1(svelte@4.2.9)
|
||||||
|
dev: false
|
||||||
|
|
||||||
/svelte-hmr@0.15.3(svelte@4.2.9):
|
/svelte-hmr@0.15.3(svelte@4.2.9):
|
||||||
resolution: {integrity: sha512-41snaPswvSf8TJUhlkoJBekRrABDXDMdpNpT2tfHIv4JuhgvHqLMhEPGtaQn0BmbNSTkuz2Ed20DF2eHw0SmBQ==}
|
resolution: {integrity: sha512-41snaPswvSf8TJUhlkoJBekRrABDXDMdpNpT2tfHIv4JuhgvHqLMhEPGtaQn0BmbNSTkuz2Ed20DF2eHw0SmBQ==}
|
||||||
engines: {node: ^12.20 || ^14.13.1 || >= 16}
|
engines: {node: ^12.20 || ^14.13.1 || >= 16}
|
||||||
|
@ -2336,7 +2360,14 @@ packages:
|
||||||
svelte: ^3.19.0 || ^4.0.0
|
svelte: ^3.19.0 || ^4.0.0
|
||||||
dependencies:
|
dependencies:
|
||||||
svelte: 4.2.9
|
svelte: 4.2.9
|
||||||
dev: true
|
|
||||||
|
/svelte-keyed@2.0.0(svelte@4.2.9):
|
||||||
|
resolution: {integrity: sha512-7TeEn+QbJC2OJrHiuM0T8vMBkms3DNpTE+Ir+NtnVBnBMA78aL4f1ft9t0Hn/pBbD/TnIXi4YfjFRAgtN+DZ5g==}
|
||||||
|
peerDependencies:
|
||||||
|
svelte: ^4.0.0
|
||||||
|
dependencies:
|
||||||
|
svelte: 4.2.9
|
||||||
|
dev: false
|
||||||
|
|
||||||
/svelte-preprocess@5.1.3(postcss-load-config@5.0.2)(postcss@8.4.33)(svelte@4.2.9)(typescript@5.3.3):
|
/svelte-preprocess@5.1.3(postcss-load-config@5.0.2)(postcss@8.4.33)(svelte@4.2.9)(typescript@5.3.3):
|
||||||
resolution: {integrity: sha512-xxAkmxGHT+J/GourS5mVJeOXZzne1FR5ljeOUAMXUkfEhkLEllRreXpbl3dIYJlcJRfL1LO1uIAPpBpBfiqGPw==}
|
resolution: {integrity: sha512-xxAkmxGHT+J/GourS5mVJeOXZzne1FR5ljeOUAMXUkfEhkLEllRreXpbl3dIYJlcJRfL1LO1uIAPpBpBfiqGPw==}
|
||||||
|
@ -2387,6 +2418,23 @@ packages:
|
||||||
typescript: 5.3.3
|
typescript: 5.3.3
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/svelte-render@2.0.0(svelte@4.2.9):
|
||||||
|
resolution: {integrity: sha512-YWMwXGlUlnlb8QhEd138Kmay2KfU6sE7jj3epoYZuHe3M2voGdXfgqYJY7gGizW55N0zDWtuRaY3Rh6PGcGQyQ==}
|
||||||
|
peerDependencies:
|
||||||
|
svelte: ^4.0.0
|
||||||
|
dependencies:
|
||||||
|
svelte: 4.2.9
|
||||||
|
svelte-subscribe: 2.0.1(svelte@4.2.9)
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/svelte-subscribe@2.0.1(svelte@4.2.9):
|
||||||
|
resolution: {integrity: sha512-eKXIjLxB4C7eQWPqKEdxcGfNXm2g/qJ67zmEZK/GigCZMfrTR3m7DPY93R6MX+5uoqM1FRYxl8LZ1oy4URWi2A==}
|
||||||
|
peerDependencies:
|
||||||
|
svelte: ^4.0.0
|
||||||
|
dependencies:
|
||||||
|
svelte: 4.2.9
|
||||||
|
dev: false
|
||||||
|
|
||||||
/svelte@4.2.9:
|
/svelte@4.2.9:
|
||||||
resolution: {integrity: sha512-hsoB/WZGEPFXeRRLPhPrbRz67PhP6sqYgvwcAs+gWdSQSvNDw+/lTeUJSWe5h2xC97Fz/8QxAOqItwBzNJPU8w==}
|
resolution: {integrity: sha512-hsoB/WZGEPFXeRRLPhPrbRz67PhP6sqYgvwcAs+gWdSQSvNDw+/lTeUJSWe5h2xC97Fz/8QxAOqItwBzNJPU8w==}
|
||||||
engines: {node: '>=16'}
|
engines: {node: '>=16'}
|
||||||
|
@ -2406,6 +2454,19 @@ packages:
|
||||||
magic-string: 0.30.5
|
magic-string: 0.30.5
|
||||||
periscopic: 3.1.0
|
periscopic: 3.1.0
|
||||||
|
|
||||||
|
/sveltekit-superforms@1.13.4(@sveltejs/kit@2.5.0)(svelte@4.2.9)(zod@3.22.4):
|
||||||
|
resolution: {integrity: sha512-rM2+Ictaw7OAIorCLmvg82orci/mtO9ZouI4emtx8SyYngx9aED+eNZlHPLufgB6D7geL2a+hMSFtM3zmMQixQ==}
|
||||||
|
peerDependencies:
|
||||||
|
'@sveltejs/kit': 1.x || 2.x
|
||||||
|
svelte: 3.x || 4.x
|
||||||
|
zod: 3.x
|
||||||
|
dependencies:
|
||||||
|
'@sveltejs/kit': 2.5.0(@sveltejs/vite-plugin-svelte@3.0.2)(svelte@4.2.9)(vite@5.0.12)
|
||||||
|
devalue: 4.3.2
|
||||||
|
klona: 2.0.6
|
||||||
|
svelte: 4.2.9
|
||||||
|
zod: 3.22.4
|
||||||
|
|
||||||
/tabbable@6.2.0:
|
/tabbable@6.2.0:
|
||||||
resolution: {integrity: sha512-Cat63mxsVJlzYvN51JmVXIgNoUokrIaT2zLclCXjRd8boZ0004U4KCs/sToJ75C6sdlByWxpYnb5Boif1VSFew==}
|
resolution: {integrity: sha512-Cat63mxsVJlzYvN51JmVXIgNoUokrIaT2zLclCXjRd8boZ0004U4KCs/sToJ75C6sdlByWxpYnb5Boif1VSFew==}
|
||||||
dev: false
|
dev: false
|
||||||
|
@ -2480,7 +2541,6 @@ packages:
|
||||||
dependencies:
|
dependencies:
|
||||||
globalyzer: 0.1.0
|
globalyzer: 0.1.0
|
||||||
globrex: 0.1.2
|
globrex: 0.1.2
|
||||||
dev: true
|
|
||||||
|
|
||||||
/to-regex-range@5.0.1:
|
/to-regex-range@5.0.1:
|
||||||
resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==}
|
resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==}
|
||||||
|
@ -2491,7 +2551,6 @@ packages:
|
||||||
/totalist@3.0.1:
|
/totalist@3.0.1:
|
||||||
resolution: {integrity: sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==}
|
resolution: {integrity: sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==}
|
||||||
engines: {node: '>=6'}
|
engines: {node: '>=6'}
|
||||||
dev: true
|
|
||||||
|
|
||||||
/ts-api-utils@1.0.3(typescript@5.3.3):
|
/ts-api-utils@1.0.3(typescript@5.3.3):
|
||||||
resolution: {integrity: sha512-wNMeqtMz5NtwpT/UZGY5alT+VoKdSsOOP/kqHFcUW1P/VRhH2wJ48+DN2WwUliNbQ976ETwDL0Ifd2VVvgonvg==}
|
resolution: {integrity: sha512-wNMeqtMz5NtwpT/UZGY5alT+VoKdSsOOP/kqHFcUW1P/VRhH2wJ48+DN2WwUliNbQ976ETwDL0Ifd2VVvgonvg==}
|
||||||
|
@ -2579,7 +2638,6 @@ packages:
|
||||||
rollup: 4.9.6
|
rollup: 4.9.6
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
fsevents: 2.3.3
|
fsevents: 2.3.3
|
||||||
dev: true
|
|
||||||
|
|
||||||
/vitefu@0.2.5(vite@5.0.12):
|
/vitefu@0.2.5(vite@5.0.12):
|
||||||
resolution: {integrity: sha512-SgHtMLoqaeeGnd2evZ849ZbACbnwQCIwRH57t18FxcXoZop0uQu0uzlIhJBlF/eWVzuce0sHeqPcDo+evVcg8Q==}
|
resolution: {integrity: sha512-SgHtMLoqaeeGnd2evZ849ZbACbnwQCIwRH57t18FxcXoZop0uQu0uzlIhJBlF/eWVzuce0sHeqPcDo+evVcg8Q==}
|
||||||
|
@ -2590,7 +2648,6 @@ packages:
|
||||||
optional: true
|
optional: true
|
||||||
dependencies:
|
dependencies:
|
||||||
vite: 5.0.12
|
vite: 5.0.12
|
||||||
dev: true
|
|
||||||
|
|
||||||
/which@2.0.2:
|
/which@2.0.2:
|
||||||
resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==}
|
resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==}
|
||||||
|
@ -2636,3 +2693,6 @@ packages:
|
||||||
resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==}
|
resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==}
|
||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/zod@3.22.4:
|
||||||
|
resolution: {integrity: sha512-iC+8Io04lddc+mVqQ9AZ7OQ2MrUKGN+oIQyq1vemgt46jwCwLfhq7/pwnBnNXXXZb8VTVLKwp9EDkx+ryxIWmg==}
|
||||||
|
|
|
@ -23,7 +23,7 @@
|
||||||
--border: 0 0% 89.8%;
|
--border: 0 0% 89.8%;
|
||||||
--input: 0 0% 89.8%;
|
--input: 0 0% 89.8%;
|
||||||
--ring: 0 72.2% 50.6%;
|
--ring: 0 72.2% 50.6%;
|
||||||
--radius: 0rem;
|
--radius: 0.5rem;
|
||||||
}
|
}
|
||||||
.dark {
|
.dark {
|
||||||
--background: 0 0% 3.9%;
|
--background: 0 0% 3.9%;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import type { Icon as LucideIcon } from 'lucide-svelte';
|
import type { Icon as LucideIcon } from 'lucide-svelte';
|
||||||
import { Loader2 } from 'lucide-svelte';
|
import { ArrowRight, Loader2 } from 'lucide-svelte';
|
||||||
import { GithubLogo, VercelLogo, LinkedinLogo } from 'radix-icons-svelte';
|
import { GithubLogo, VercelLogo, LinkedinLogo } from 'radix-icons-svelte';
|
||||||
import Logo from './logo.svelte';
|
import Logo from './logo.svelte';
|
||||||
import Svelte from './svelte.svelte';
|
import Svelte from './svelte.svelte';
|
||||||
|
@ -14,5 +14,6 @@ export const Icons = {
|
||||||
svelte: Svelte,
|
svelte: Svelte,
|
||||||
vercel: VercelLogo,
|
vercel: VercelLogo,
|
||||||
linkedIn: LinkedinLogo,
|
linkedIn: LinkedinLogo,
|
||||||
spinner: Loader2
|
spinner: Loader2,
|
||||||
|
arrowRight: ArrowRight,
|
||||||
};
|
};
|
||||||
|
|
16
apps/web/src/lib/components/ui/avatar/avatar-fallback.svelte
Normal file
16
apps/web/src/lib/components/ui/avatar/avatar-fallback.svelte
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { Avatar as AvatarPrimitive } from "bits-ui";
|
||||||
|
import { cn } from "$lib/utils";
|
||||||
|
|
||||||
|
type $$Props = AvatarPrimitive.FallbackProps;
|
||||||
|
|
||||||
|
let className: $$Props["class"] = undefined;
|
||||||
|
export { className as class };
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<AvatarPrimitive.Fallback
|
||||||
|
class={cn("flex h-full w-full items-center justify-center rounded-full bg-muted", className)}
|
||||||
|
{...$$restProps}
|
||||||
|
>
|
||||||
|
<slot />
|
||||||
|
</AvatarPrimitive.Fallback>
|
18
apps/web/src/lib/components/ui/avatar/avatar-image.svelte
Normal file
18
apps/web/src/lib/components/ui/avatar/avatar-image.svelte
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { Avatar as AvatarPrimitive } from "bits-ui";
|
||||||
|
import { cn } from "$lib/utils";
|
||||||
|
|
||||||
|
type $$Props = AvatarPrimitive.ImageProps;
|
||||||
|
|
||||||
|
let className: $$Props["class"] = undefined;
|
||||||
|
export let src: $$Props["src"] = undefined;
|
||||||
|
export let alt: $$Props["alt"] = undefined;
|
||||||
|
export { className as class };
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<AvatarPrimitive.Image
|
||||||
|
{src}
|
||||||
|
{alt}
|
||||||
|
class={cn("aspect-square h-full w-full", className)}
|
||||||
|
{...$$restProps}
|
||||||
|
/>
|
18
apps/web/src/lib/components/ui/avatar/avatar.svelte
Normal file
18
apps/web/src/lib/components/ui/avatar/avatar.svelte
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { Avatar as AvatarPrimitive } from "bits-ui";
|
||||||
|
import { cn } from "$lib/utils";
|
||||||
|
|
||||||
|
type $$Props = AvatarPrimitive.Props;
|
||||||
|
|
||||||
|
let className: $$Props["class"] = undefined;
|
||||||
|
export let delayMs: $$Props["delayMs"] = undefined;
|
||||||
|
export { className as class };
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<AvatarPrimitive.Root
|
||||||
|
{delayMs}
|
||||||
|
class={cn("relative flex h-10 w-10 shrink-0 overflow-hidden rounded-full", className)}
|
||||||
|
{...$$restProps}
|
||||||
|
>
|
||||||
|
<slot />
|
||||||
|
</AvatarPrimitive.Root>
|
13
apps/web/src/lib/components/ui/avatar/index.ts
Normal file
13
apps/web/src/lib/components/ui/avatar/index.ts
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
import Root from "./avatar.svelte";
|
||||||
|
import Image from "./avatar-image.svelte";
|
||||||
|
import Fallback from "./avatar-fallback.svelte";
|
||||||
|
|
||||||
|
export {
|
||||||
|
Root,
|
||||||
|
Image,
|
||||||
|
Fallback,
|
||||||
|
//
|
||||||
|
Root as Avatar,
|
||||||
|
Image as AvatarImage,
|
||||||
|
Fallback as AvatarFallback
|
||||||
|
};
|
18
apps/web/src/lib/components/ui/badge/badge.svelte
Normal file
18
apps/web/src/lib/components/ui/badge/badge.svelte
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { cn } from "$lib/utils";
|
||||||
|
import { badgeVariants, type Variant } from ".";
|
||||||
|
|
||||||
|
let className: string | undefined | null = undefined;
|
||||||
|
export let href: string | undefined = undefined;
|
||||||
|
export let variant: Variant = "default";
|
||||||
|
export { className as class };
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<svelte:element
|
||||||
|
this={href ? "a" : "span"}
|
||||||
|
{href}
|
||||||
|
class={cn(badgeVariants({ variant, className }))}
|
||||||
|
{...$$restProps}
|
||||||
|
>
|
||||||
|
<slot />
|
||||||
|
</svelte:element>
|
22
apps/web/src/lib/components/ui/badge/index.ts
Normal file
22
apps/web/src/lib/components/ui/badge/index.ts
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
import { tv, type VariantProps } from "tailwind-variants";
|
||||||
|
|
||||||
|
export { default as Badge } from "./badge.svelte";
|
||||||
|
export const badgeVariants = tv({
|
||||||
|
base: "inline-flex items-center rounded-md border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 select-none",
|
||||||
|
variants: {
|
||||||
|
variant: {
|
||||||
|
default:
|
||||||
|
"border-transparent bg-primary text-primary-foreground shadow hover:bg-primary/80",
|
||||||
|
secondary:
|
||||||
|
"border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80",
|
||||||
|
destructive:
|
||||||
|
"border-transparent bg-destructive text-destructive-foreground shadow hover:bg-destructive/80",
|
||||||
|
outline: "text-foreground"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
defaultVariants: {
|
||||||
|
variant: "default"
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
export type Variant = VariantProps<typeof badgeVariants>["variant"];
|
34
apps/web/src/lib/components/ui/checkbox/checkbox.svelte
Normal file
34
apps/web/src/lib/components/ui/checkbox/checkbox.svelte
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { Checkbox as CheckboxPrimitive } from "bits-ui";
|
||||||
|
import { Check, Minus } from "radix-icons-svelte";
|
||||||
|
import { cn } from "$lib/utils";
|
||||||
|
|
||||||
|
type $$Props = CheckboxPrimitive.Props;
|
||||||
|
type $$Events = CheckboxPrimitive.Events;
|
||||||
|
|
||||||
|
let className: $$Props["class"] = undefined;
|
||||||
|
export let checked: $$Props["checked"] = false;
|
||||||
|
export { className as class };
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<CheckboxPrimitive.Root
|
||||||
|
class={cn(
|
||||||
|
"box-content peer h-4 w-4 shrink-0 rounded-sm border border-primary shadow focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground data-[disabled=true]:cursor-not-allowed data-[disabled=true]:opacity-50",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
bind:checked
|
||||||
|
on:click
|
||||||
|
{...$$restProps}
|
||||||
|
>
|
||||||
|
<CheckboxPrimitive.Indicator
|
||||||
|
class={cn("flex items-center justify-center text-current h-4 w-4")}
|
||||||
|
let:isChecked
|
||||||
|
let:isIndeterminate
|
||||||
|
>
|
||||||
|
{#if isIndeterminate}
|
||||||
|
<Minus class="h-3.5 w-3.5" />
|
||||||
|
{:else}
|
||||||
|
<Check class={cn("h-3.5 w-3.5", !isChecked && "text-transparent")} />
|
||||||
|
{/if}
|
||||||
|
</CheckboxPrimitive.Indicator>
|
||||||
|
</CheckboxPrimitive.Root>
|
6
apps/web/src/lib/components/ui/checkbox/index.ts
Normal file
6
apps/web/src/lib/components/ui/checkbox/index.ts
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
import Root from "./checkbox.svelte";
|
||||||
|
export {
|
||||||
|
Root,
|
||||||
|
//
|
||||||
|
Root as Checkbox
|
||||||
|
};
|
23
apps/web/src/lib/components/ui/command/command-dialog.svelte
Normal file
23
apps/web/src/lib/components/ui/command/command-dialog.svelte
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import Command from "./command.svelte";
|
||||||
|
import * as Dialog from "$lib/components/ui/dialog";
|
||||||
|
import type { Dialog as DialogPrimitive } from "bits-ui";
|
||||||
|
import type { Command as CommandPrimitive } from "cmdk-sv";
|
||||||
|
|
||||||
|
type $$Props = DialogPrimitive.Props & CommandPrimitive.CommandProps;
|
||||||
|
|
||||||
|
export let open: $$Props["open"] = false;
|
||||||
|
export let value: $$Props["value"] = undefined;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<Dialog.Root bind:open {...$$restProps}>
|
||||||
|
<Dialog.Content class="overflow-hidden p-0">
|
||||||
|
<Command
|
||||||
|
class="[&_[data-cmdk-group-heading]]:px-2 [&_[data-cmdk-group-heading]]:font-medium [&_[data-cmdk-group-heading]]:text-muted-foreground [&_[data-cmdk-group]:not([hidden])_~[data-cmdk-group]]:pt-0 [&_[data-cmdk-group]]:px-2 [&_[data-cmdk-input-wrapper]_svg]:h-5 [&_[data-cmdk-input-wrapper]_svg]:w-5 [&_[data-cmdk-input]]:h-12 [&_[data-cmdk-item]]:px-2 [&_[data-cmdk-item]]:py-3 [&_[data-cmdk-item]_svg]:h-5 [&_[data-cmdk-item]_svg]:w-5"
|
||||||
|
{...$$restProps}
|
||||||
|
bind:value
|
||||||
|
>
|
||||||
|
<slot />
|
||||||
|
</Command>
|
||||||
|
</Dialog.Content>
|
||||||
|
</Dialog.Root>
|
12
apps/web/src/lib/components/ui/command/command-empty.svelte
Normal file
12
apps/web/src/lib/components/ui/command/command-empty.svelte
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { Command as CommandPrimitive } from "cmdk-sv";
|
||||||
|
import { cn } from "$lib/utils";
|
||||||
|
|
||||||
|
type $$Props = CommandPrimitive.EmptyProps;
|
||||||
|
let className: string | undefined | null = undefined;
|
||||||
|
export { className as class };
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<CommandPrimitive.Empty class={cn("py-6 text-center text-sm", className)} {...$$restProps}>
|
||||||
|
<slot />
|
||||||
|
</CommandPrimitive.Empty>
|
18
apps/web/src/lib/components/ui/command/command-group.svelte
Normal file
18
apps/web/src/lib/components/ui/command/command-group.svelte
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { Command as CommandPrimitive } from "cmdk-sv";
|
||||||
|
import { cn } from "$lib/utils";
|
||||||
|
type $$Props = CommandPrimitive.GroupProps;
|
||||||
|
|
||||||
|
let className: string | undefined | null = undefined;
|
||||||
|
export { className as class };
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<CommandPrimitive.Group
|
||||||
|
class={cn(
|
||||||
|
"overflow-hidden p-1 text-foreground [&_[data-cmdk-group-heading]]:px-2 [&_[data-cmdk-group-heading]]:py-1.5 [&_[data-cmdk-group-heading]]:text-xs [&_[data-cmdk-group-heading]]:font-medium [&_[data-cmdk-group-heading]]:text-muted-foreground",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...$$restProps}
|
||||||
|
>
|
||||||
|
<slot />
|
||||||
|
</CommandPrimitive.Group>
|
23
apps/web/src/lib/components/ui/command/command-input.svelte
Normal file
23
apps/web/src/lib/components/ui/command/command-input.svelte
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { Command as CommandPrimitive } from "cmdk-sv";
|
||||||
|
import { MagnifyingGlass } from "radix-icons-svelte";
|
||||||
|
import { cn } from "$lib/utils";
|
||||||
|
|
||||||
|
type $$Props = CommandPrimitive.InputProps;
|
||||||
|
|
||||||
|
let className: string | undefined | null = undefined;
|
||||||
|
export { className as class };
|
||||||
|
export let value: string = "";
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="flex items-center border-b px-3" data-cmdk-input-wrapper="">
|
||||||
|
<MagnifyingGlass class="mr-2 h-4 w-4 shrink-0 opacity-50" />
|
||||||
|
<CommandPrimitive.Input
|
||||||
|
class={cn(
|
||||||
|
"flex h-10 w-full rounded-md bg-transparent py-3 text-sm outline-none placeholder:text-muted-foreground disabled:cursor-not-allowed disabled:opacity-50",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...$$restProps}
|
||||||
|
bind:value
|
||||||
|
/>
|
||||||
|
</div>
|
19
apps/web/src/lib/components/ui/command/command-item.svelte
Normal file
19
apps/web/src/lib/components/ui/command/command-item.svelte
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { Command as CommandPrimitive } from "cmdk-sv";
|
||||||
|
import { cn } from "$lib/utils";
|
||||||
|
|
||||||
|
type $$Props = CommandPrimitive.ItemProps;
|
||||||
|
|
||||||
|
let className: string | undefined | null = undefined;
|
||||||
|
export { className as class };
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<CommandPrimitive.Item
|
||||||
|
class={cn(
|
||||||
|
"relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none aria-selected:bg-accent aria-selected:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...$$restProps}
|
||||||
|
>
|
||||||
|
<slot />
|
||||||
|
</CommandPrimitive.Item>
|
15
apps/web/src/lib/components/ui/command/command-list.svelte
Normal file
15
apps/web/src/lib/components/ui/command/command-list.svelte
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { Command as CommandPrimitive } from "cmdk-sv";
|
||||||
|
import { cn } from "$lib/utils";
|
||||||
|
|
||||||
|
type $$Props = CommandPrimitive.ListProps;
|
||||||
|
let className: string | undefined | null = undefined;
|
||||||
|
export { className as class };
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<CommandPrimitive.List
|
||||||
|
class={cn("max-h-[300px] overflow-y-auto overflow-x-hidden", className)}
|
||||||
|
{...$$restProps}
|
||||||
|
>
|
||||||
|
<slot />
|
||||||
|
</CommandPrimitive.List>
|
|
@ -0,0 +1,10 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { Command as CommandPrimitive } from "cmdk-sv";
|
||||||
|
import { cn } from "$lib/utils";
|
||||||
|
|
||||||
|
type $$Props = CommandPrimitive.SeparatorProps;
|
||||||
|
let className: string | undefined | null = undefined;
|
||||||
|
export { className as class };
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<CommandPrimitive.Separator class={cn("-mx-1 h-px bg-border", className)} {...$$restProps} />
|
|
@ -0,0 +1,16 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { cn } from "$lib/utils";
|
||||||
|
import type { HTMLAttributes } from "svelte/elements";
|
||||||
|
|
||||||
|
type $$Props = HTMLAttributes<HTMLSpanElement>;
|
||||||
|
|
||||||
|
let className: string | undefined | null = undefined;
|
||||||
|
export { className as class };
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<span
|
||||||
|
class={cn("ml-auto text-xs tracking-widest text-muted-foreground", className)}
|
||||||
|
{...$$restProps}
|
||||||
|
>
|
||||||
|
<slot />
|
||||||
|
</span>
|
22
apps/web/src/lib/components/ui/command/command.svelte
Normal file
22
apps/web/src/lib/components/ui/command/command.svelte
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { Command as CommandPrimitive } from "cmdk-sv";
|
||||||
|
import { cn } from "$lib/utils";
|
||||||
|
|
||||||
|
type $$Props = CommandPrimitive.CommandProps;
|
||||||
|
|
||||||
|
export let value: $$Props["value"] = undefined;
|
||||||
|
|
||||||
|
let className: string | undefined | null = undefined;
|
||||||
|
export { className as class };
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<CommandPrimitive.Root
|
||||||
|
class={cn(
|
||||||
|
"flex h-full w-full flex-col overflow-hidden rounded-md bg-popover text-popover-foreground",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
bind:value
|
||||||
|
{...$$restProps}
|
||||||
|
>
|
||||||
|
<slot />
|
||||||
|
</CommandPrimitive.Root>
|
37
apps/web/src/lib/components/ui/command/index.ts
Normal file
37
apps/web/src/lib/components/ui/command/index.ts
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
import { Command as CommandPrimitive } from "cmdk-sv";
|
||||||
|
|
||||||
|
import Root from "./command.svelte";
|
||||||
|
import Dialog from "./command-dialog.svelte";
|
||||||
|
import Empty from "./command-empty.svelte";
|
||||||
|
import Group from "./command-group.svelte";
|
||||||
|
import Item from "./command-item.svelte";
|
||||||
|
import Input from "./command-input.svelte";
|
||||||
|
import List from "./command-list.svelte";
|
||||||
|
import Separator from "./command-separator.svelte";
|
||||||
|
import Shortcut from "./command-shortcut.svelte";
|
||||||
|
|
||||||
|
const Loading = CommandPrimitive.Loading;
|
||||||
|
|
||||||
|
export {
|
||||||
|
Root,
|
||||||
|
Dialog,
|
||||||
|
Empty,
|
||||||
|
Group,
|
||||||
|
Item,
|
||||||
|
Input,
|
||||||
|
List,
|
||||||
|
Separator,
|
||||||
|
Shortcut,
|
||||||
|
Loading,
|
||||||
|
//
|
||||||
|
Root as Command,
|
||||||
|
Dialog as CommandDialog,
|
||||||
|
Empty as CommandEmpty,
|
||||||
|
Group as CommandGroup,
|
||||||
|
Item as CommandItem,
|
||||||
|
Input as CommandInput,
|
||||||
|
List as CommandList,
|
||||||
|
Separator as CommandSeparator,
|
||||||
|
Shortcut as CommandShortcut,
|
||||||
|
Loading as CommandLoading
|
||||||
|
};
|
36
apps/web/src/lib/components/ui/dialog/dialog-content.svelte
Normal file
36
apps/web/src/lib/components/ui/dialog/dialog-content.svelte
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { Dialog as DialogPrimitive } from "bits-ui";
|
||||||
|
import * as Dialog from ".";
|
||||||
|
import { cn, flyAndScale } from "$lib/utils";
|
||||||
|
import { Cross2 } from "radix-icons-svelte";
|
||||||
|
|
||||||
|
type $$Props = DialogPrimitive.ContentProps;
|
||||||
|
|
||||||
|
let className: $$Props["class"] = undefined;
|
||||||
|
export let transition: $$Props["transition"] = flyAndScale;
|
||||||
|
export let transitionConfig: $$Props["transitionConfig"] = {
|
||||||
|
duration: 200
|
||||||
|
};
|
||||||
|
export { className as class };
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<Dialog.Portal>
|
||||||
|
<Dialog.Overlay />
|
||||||
|
<DialogPrimitive.Content
|
||||||
|
{transition}
|
||||||
|
{transitionConfig}
|
||||||
|
class={cn(
|
||||||
|
"fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg sm:rounded-lg md:w-full",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...$$restProps}
|
||||||
|
>
|
||||||
|
<slot />
|
||||||
|
<DialogPrimitive.Close
|
||||||
|
class="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground"
|
||||||
|
>
|
||||||
|
<Cross2 class="h-4 w-4" />
|
||||||
|
<span class="sr-only">Close</span>
|
||||||
|
</DialogPrimitive.Close>
|
||||||
|
</DialogPrimitive.Content>
|
||||||
|
</Dialog.Portal>
|
|
@ -0,0 +1,16 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { Dialog as DialogPrimitive } from "bits-ui";
|
||||||
|
import { cn } from "$lib/utils";
|
||||||
|
|
||||||
|
type $$Props = DialogPrimitive.DescriptionProps;
|
||||||
|
|
||||||
|
let className: $$Props["class"] = undefined;
|
||||||
|
export { className as class };
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<DialogPrimitive.Description
|
||||||
|
class={cn("text-sm text-muted-foreground", className)}
|
||||||
|
{...$$restProps}
|
||||||
|
>
|
||||||
|
<slot />
|
||||||
|
</DialogPrimitive.Description>
|
16
apps/web/src/lib/components/ui/dialog/dialog-footer.svelte
Normal file
16
apps/web/src/lib/components/ui/dialog/dialog-footer.svelte
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { cn } from "$lib/utils";
|
||||||
|
import type { HTMLAttributes } from "svelte/elements";
|
||||||
|
|
||||||
|
type $$Props = HTMLAttributes<HTMLDivElement>;
|
||||||
|
|
||||||
|
let className: $$Props["class"] = undefined;
|
||||||
|
export { className as class };
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div
|
||||||
|
class={cn("flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2", className)}
|
||||||
|
{...$$restProps}
|
||||||
|
>
|
||||||
|
<slot />
|
||||||
|
</div>
|
13
apps/web/src/lib/components/ui/dialog/dialog-header.svelte
Normal file
13
apps/web/src/lib/components/ui/dialog/dialog-header.svelte
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { cn } from "$lib/utils";
|
||||||
|
import type { HTMLAttributes } from "svelte/elements";
|
||||||
|
|
||||||
|
type $$Props = HTMLAttributes<HTMLDivElement>;
|
||||||
|
|
||||||
|
let className: $$Props["class"] = undefined;
|
||||||
|
export { className as class };
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class={cn("flex flex-col space-y-1.5 text-center sm:text-left", className)} {...$$restProps}>
|
||||||
|
<slot />
|
||||||
|
</div>
|
21
apps/web/src/lib/components/ui/dialog/dialog-overlay.svelte
Normal file
21
apps/web/src/lib/components/ui/dialog/dialog-overlay.svelte
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { Dialog as DialogPrimitive } from "bits-ui";
|
||||||
|
import { cn } from "$lib/utils";
|
||||||
|
import { fade } from "svelte/transition";
|
||||||
|
|
||||||
|
type $$Props = DialogPrimitive.OverlayProps;
|
||||||
|
|
||||||
|
let className: $$Props["class"] = undefined;
|
||||||
|
export let transition: $$Props["transition"] = fade;
|
||||||
|
export let transitionConfig: $$Props["transitionConfig"] = {
|
||||||
|
duration: 150
|
||||||
|
};
|
||||||
|
export { className as class };
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<DialogPrimitive.Overlay
|
||||||
|
{transition}
|
||||||
|
{transitionConfig}
|
||||||
|
class={cn("fixed inset-0 z-50 bg-background/80 backdrop-blur-sm ", className)}
|
||||||
|
{...$$restProps}
|
||||||
|
/>
|
|
@ -0,0 +1,9 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { Dialog as DialogPrimitive } from "bits-ui";
|
||||||
|
|
||||||
|
type $$Props = DialogPrimitive.PortalProps;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<DialogPrimitive.Portal {...$$restProps}>
|
||||||
|
<slot />
|
||||||
|
</DialogPrimitive.Portal>
|
16
apps/web/src/lib/components/ui/dialog/dialog-title.svelte
Normal file
16
apps/web/src/lib/components/ui/dialog/dialog-title.svelte
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { Dialog as DialogPrimitive } from "bits-ui";
|
||||||
|
import { cn } from "$lib/utils";
|
||||||
|
|
||||||
|
type $$Props = DialogPrimitive.TitleProps;
|
||||||
|
|
||||||
|
let className: $$Props["class"] = undefined;
|
||||||
|
export { className as class };
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<DialogPrimitive.Title
|
||||||
|
class={cn("text-lg font-semibold leading-none tracking-tight", className)}
|
||||||
|
{...$$restProps}
|
||||||
|
>
|
||||||
|
<slot />
|
||||||
|
</DialogPrimitive.Title>
|
34
apps/web/src/lib/components/ui/dialog/index.ts
Normal file
34
apps/web/src/lib/components/ui/dialog/index.ts
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
import { Dialog as DialogPrimitive } from "bits-ui";
|
||||||
|
|
||||||
|
const Root = DialogPrimitive.Root;
|
||||||
|
const Trigger = DialogPrimitive.Trigger;
|
||||||
|
|
||||||
|
import Title from "./dialog-title.svelte";
|
||||||
|
import Portal from "./dialog-portal.svelte";
|
||||||
|
import Footer from "./dialog-footer.svelte";
|
||||||
|
import Header from "./dialog-header.svelte";
|
||||||
|
import Overlay from "./dialog-overlay.svelte";
|
||||||
|
import Content from "./dialog-content.svelte";
|
||||||
|
import Description from "./dialog-description.svelte";
|
||||||
|
|
||||||
|
export {
|
||||||
|
Root,
|
||||||
|
Title,
|
||||||
|
Portal,
|
||||||
|
Footer,
|
||||||
|
Header,
|
||||||
|
Trigger,
|
||||||
|
Overlay,
|
||||||
|
Content,
|
||||||
|
Description,
|
||||||
|
//
|
||||||
|
Root as Dialog,
|
||||||
|
Title as DialogTitle,
|
||||||
|
Portal as DialogPortal,
|
||||||
|
Footer as DialogFooter,
|
||||||
|
Header as DialogHeader,
|
||||||
|
Trigger as DialogTrigger,
|
||||||
|
Overlay as DialogOverlay,
|
||||||
|
Content as DialogContent,
|
||||||
|
Description as DialogDescription
|
||||||
|
};
|
9
apps/web/src/lib/components/ui/form/form-button.svelte
Normal file
9
apps/web/src/lib/components/ui/form/form-button.svelte
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import * as Button from "$lib/components/ui/button";
|
||||||
|
type $$Props = Button.Props;
|
||||||
|
type $$Events = Button.Events;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<Button.Root type="submit" {...$$restProps} on:click on:keydown>
|
||||||
|
<slot />
|
||||||
|
</Button.Root>
|
26
apps/web/src/lib/components/ui/form/form-checkbox.svelte
Normal file
26
apps/web/src/lib/components/ui/form/form-checkbox.svelte
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { getFormField } from "formsnap";
|
||||||
|
import type { Checkbox as CheckboxPrimitive } from "bits-ui";
|
||||||
|
import { Checkbox } from "$lib/components/ui/checkbox";
|
||||||
|
type $$Props = CheckboxPrimitive.Props;
|
||||||
|
type $$Events = CheckboxPrimitive.Events;
|
||||||
|
|
||||||
|
export let onCheckedChange: $$Props["onCheckedChange"] = undefined;
|
||||||
|
|
||||||
|
const { name, setValue, attrStore, value } = getFormField();
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
|
const { name: nameAttr, value: valueAttr, ...rest } = $attrStore;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<Checkbox
|
||||||
|
{...rest}
|
||||||
|
checked={typeof $value === "boolean" ? $value : false}
|
||||||
|
onCheckedChange={(v) => {
|
||||||
|
onCheckedChange?.(v);
|
||||||
|
setValue(v);
|
||||||
|
}}
|
||||||
|
{...$$restProps}
|
||||||
|
on:click
|
||||||
|
on:keydown
|
||||||
|
/>
|
||||||
|
<input hidden {name} value={$value} />
|
16
apps/web/src/lib/components/ui/form/form-description.svelte
Normal file
16
apps/web/src/lib/components/ui/form/form-description.svelte
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { Form as FormPrimitive } from "formsnap";
|
||||||
|
import { cn } from "$lib/utils";
|
||||||
|
import type { HTMLAttributes } from "svelte/elements";
|
||||||
|
|
||||||
|
type $$Props = HTMLAttributes<HTMLSpanElement>;
|
||||||
|
let className: string | undefined | null = undefined;
|
||||||
|
export { className as class };
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<FormPrimitive.Description
|
||||||
|
class={cn("text-[0.8rem] text-muted-foreground", className)}
|
||||||
|
{...$$restProps}
|
||||||
|
>
|
||||||
|
<slot />
|
||||||
|
</FormPrimitive.Description>
|
28
apps/web/src/lib/components/ui/form/form-input.svelte
Normal file
28
apps/web/src/lib/components/ui/form/form-input.svelte
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { getFormField } from "formsnap";
|
||||||
|
import type { HTMLInputAttributes } from "svelte/elements";
|
||||||
|
import { Input, type InputEvents } from "$lib/components/ui/input";
|
||||||
|
|
||||||
|
type $$Props = HTMLInputAttributes;
|
||||||
|
type $$Events = InputEvents;
|
||||||
|
|
||||||
|
const { attrStore, value } = getFormField();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<Input
|
||||||
|
{...$attrStore}
|
||||||
|
bind:value={$value}
|
||||||
|
{...$$restProps}
|
||||||
|
on:blur
|
||||||
|
on:change
|
||||||
|
on:click
|
||||||
|
on:focus
|
||||||
|
on:keydown
|
||||||
|
on:keypress
|
||||||
|
on:keyup
|
||||||
|
on:mouseover
|
||||||
|
on:mouseenter
|
||||||
|
on:mouseleave
|
||||||
|
on:paste
|
||||||
|
on:input
|
||||||
|
/>
|
12
apps/web/src/lib/components/ui/form/form-item.svelte
Normal file
12
apps/web/src/lib/components/ui/form/form-item.svelte
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { cn } from "$lib/utils";
|
||||||
|
import type { HTMLAttributes } from "svelte/elements";
|
||||||
|
|
||||||
|
type $$Props = HTMLAttributes<HTMLDivElement>;
|
||||||
|
let className: string | undefined | null = undefined;
|
||||||
|
export { className as class };
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class={cn("space-y-2", className)} {...$$restProps}>
|
||||||
|
<slot />
|
||||||
|
</div>
|
17
apps/web/src/lib/components/ui/form/form-label.svelte
Normal file
17
apps/web/src/lib/components/ui/form/form-label.svelte
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import type { Label as LabelPrimitive } from "bits-ui";
|
||||||
|
import { getFormField } from "formsnap";
|
||||||
|
import { cn } from "$lib/utils";
|
||||||
|
import { Label } from "$lib/components/ui/label";
|
||||||
|
|
||||||
|
type $$Props = LabelPrimitive.Props;
|
||||||
|
|
||||||
|
let className: $$Props["class"] = undefined;
|
||||||
|
export { className as class };
|
||||||
|
|
||||||
|
const { errors, ids } = getFormField();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<Label for={$ids.input} class={cn($errors && "text-destructive", className)} {...$$restProps}>
|
||||||
|
<slot />
|
||||||
|
</Label>
|
|
@ -0,0 +1,26 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { Form as FormPrimitive } from "formsnap";
|
||||||
|
import { buttonVariants } from "$lib/components/ui/button";
|
||||||
|
import { cn } from "$lib/utils";
|
||||||
|
import { CaretSort } from "radix-icons-svelte";
|
||||||
|
import type { HTMLSelectAttributes } from "svelte/elements";
|
||||||
|
|
||||||
|
type $$Props = HTMLSelectAttributes;
|
||||||
|
|
||||||
|
let className: string | undefined | null = undefined;
|
||||||
|
export { className as class };
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="relative">
|
||||||
|
<FormPrimitive.Select
|
||||||
|
class={cn(
|
||||||
|
buttonVariants({ variant: "outline" }),
|
||||||
|
"appearance-none bg-transparent font-normal",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...$$restProps}
|
||||||
|
>
|
||||||
|
<slot />
|
||||||
|
</FormPrimitive.Select>
|
||||||
|
<CaretSort class="absolute right-3 top-2.5 h-4 w-4 opacity-50" />
|
||||||
|
</div>
|
22
apps/web/src/lib/components/ui/form/form-radio-group.svelte
Normal file
22
apps/web/src/lib/components/ui/form/form-radio-group.svelte
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { getFormField } from "formsnap";
|
||||||
|
import type { RadioGroup as RadioGroupPrimitive } from "bits-ui";
|
||||||
|
import * as RadioGroup from "$lib/components/ui/radio-group";
|
||||||
|
|
||||||
|
type $$Props = RadioGroupPrimitive.Props;
|
||||||
|
const { attrStore, setValue, name, value } = getFormField();
|
||||||
|
|
||||||
|
export let onValueChange: $$Props["onValueChange"] = undefined;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<RadioGroup.Root
|
||||||
|
{...$attrStore}
|
||||||
|
onValueChange={(v) => {
|
||||||
|
onValueChange?.(v);
|
||||||
|
setValue(v);
|
||||||
|
}}
|
||||||
|
{...$$restProps}
|
||||||
|
>
|
||||||
|
<slot />
|
||||||
|
<input hidden {name} value={$value} />
|
||||||
|
</RadioGroup.Root>
|
|
@ -0,0 +1,18 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import * as Select from "$lib/components/ui/select";
|
||||||
|
import type { Select as SelectPrimitive } from "bits-ui";
|
||||||
|
import { getFormField } from "formsnap";
|
||||||
|
|
||||||
|
type $$Props = SelectPrimitive.TriggerProps & {
|
||||||
|
placeholder?: string;
|
||||||
|
};
|
||||||
|
type $$Events = SelectPrimitive.TriggerEvents;
|
||||||
|
const { attrStore, value } = getFormField();
|
||||||
|
export let placeholder = "";
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<Select.Trigger {...$$restProps} {...$attrStore} on:click on:keydown>
|
||||||
|
<slot value={$value}>
|
||||||
|
<Select.Value {placeholder} />
|
||||||
|
</slot>
|
||||||
|
</Select.Trigger>
|
20
apps/web/src/lib/components/ui/form/form-select.svelte
Normal file
20
apps/web/src/lib/components/ui/form/form-select.svelte
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import * as Select from "$lib/components/ui/select";
|
||||||
|
import { getFormField } from "formsnap";
|
||||||
|
import type { Select as SelectPrimitive } from "bits-ui";
|
||||||
|
|
||||||
|
type $$Props = SelectPrimitive.Props<unknown>;
|
||||||
|
const { setValue, name, value } = getFormField();
|
||||||
|
export let onSelectedChange: $$Props["onSelectedChange"] = undefined;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<Select.Root
|
||||||
|
onSelectedChange={(v) => {
|
||||||
|
onSelectedChange?.(v);
|
||||||
|
setValue(v ? v.value : undefined);
|
||||||
|
}}
|
||||||
|
{...$$restProps}
|
||||||
|
>
|
||||||
|
<slot />
|
||||||
|
<input hidden {name} value={$value} />
|
||||||
|
</Select.Root>
|
24
apps/web/src/lib/components/ui/form/form-switch.svelte
Normal file
24
apps/web/src/lib/components/ui/form/form-switch.svelte
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { getFormField } from "formsnap";
|
||||||
|
import type { Switch as SwitchPrimitive } from "bits-ui";
|
||||||
|
import { Switch } from "$lib/components/ui/switch";
|
||||||
|
type $$Props = SwitchPrimitive.Props;
|
||||||
|
type $$Events = SwitchPrimitive.Events;
|
||||||
|
|
||||||
|
export let onCheckedChange: $$Props["onCheckedChange"] = undefined;
|
||||||
|
|
||||||
|
const { name, setValue, attrStore, value } = getFormField();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<Switch
|
||||||
|
{...$attrStore}
|
||||||
|
checked={typeof $value === "boolean" ? $value : false}
|
||||||
|
onCheckedChange={(v) => {
|
||||||
|
onCheckedChange?.(v);
|
||||||
|
setValue(v);
|
||||||
|
}}
|
||||||
|
{...$$restProps}
|
||||||
|
on:click
|
||||||
|
on:keydown
|
||||||
|
/>
|
||||||
|
<input hidden {name} value={$value} />
|
29
apps/web/src/lib/components/ui/form/form-textarea.svelte
Normal file
29
apps/web/src/lib/components/ui/form/form-textarea.svelte
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { getFormField } from "formsnap";
|
||||||
|
import type { HTMLTextareaAttributes } from "svelte/elements";
|
||||||
|
import type { TextareaGetFormField } from ".";
|
||||||
|
import { Textarea, type TextareaEvents } from "$lib/components/ui/textarea";
|
||||||
|
|
||||||
|
type $$Props = HTMLTextareaAttributes;
|
||||||
|
type $$Events = TextareaEvents;
|
||||||
|
|
||||||
|
const { attrStore, value } = getFormField() as TextareaGetFormField;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<Textarea
|
||||||
|
{...$attrStore}
|
||||||
|
bind:value={$value}
|
||||||
|
{...$$restProps}
|
||||||
|
on:blur
|
||||||
|
on:change
|
||||||
|
on:click
|
||||||
|
on:focus
|
||||||
|
on:keydown
|
||||||
|
on:keypress
|
||||||
|
on:keyup
|
||||||
|
on:mouseover
|
||||||
|
on:mouseenter
|
||||||
|
on:mouseleave
|
||||||
|
on:paste
|
||||||
|
on:input
|
||||||
|
/>
|
14
apps/web/src/lib/components/ui/form/form-validation.svelte
Normal file
14
apps/web/src/lib/components/ui/form/form-validation.svelte
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { Form as FormPrimitive } from "formsnap";
|
||||||
|
import { cn } from "$lib/utils";
|
||||||
|
import type { HTMLAttributes } from "svelte/elements";
|
||||||
|
|
||||||
|
type $$Props = HTMLAttributes<HTMLParagraphElement>;
|
||||||
|
let className: string | undefined | null = undefined;
|
||||||
|
export { className as class };
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<FormPrimitive.Validation
|
||||||
|
class={cn("text-[0.8rem] font-medium text-destructive", className)}
|
||||||
|
{...$$restProps}
|
||||||
|
/>
|
82
apps/web/src/lib/components/ui/form/index.ts
Normal file
82
apps/web/src/lib/components/ui/form/index.ts
Normal file
|
@ -0,0 +1,82 @@
|
||||||
|
import { Form as FormPrimitive, getFormField } from "formsnap";
|
||||||
|
import type { Writable } from "svelte/store";
|
||||||
|
import * as RadioGroupComp from "$lib/components/ui/radio-group";
|
||||||
|
import * as SelectComp from "$lib/components/ui/select";
|
||||||
|
import Item from "./form-item.svelte";
|
||||||
|
import Input from "./form-input.svelte";
|
||||||
|
import Textarea from "./form-textarea.svelte";
|
||||||
|
import Description from "./form-description.svelte";
|
||||||
|
import Label from "./form-label.svelte";
|
||||||
|
import Validation from "./form-validation.svelte";
|
||||||
|
import Checkbox from "./form-checkbox.svelte";
|
||||||
|
import Switch from "./form-switch.svelte";
|
||||||
|
import NativeSelect from "./form-native-select.svelte";
|
||||||
|
import RadioGroup from "./form-radio-group.svelte";
|
||||||
|
import Select from "./form-select.svelte";
|
||||||
|
import SelectTrigger from "./form-select-trigger.svelte";
|
||||||
|
import Button from "./form-button.svelte";
|
||||||
|
|
||||||
|
const Root = FormPrimitive.Root;
|
||||||
|
const Field = FormPrimitive.Field;
|
||||||
|
const Control = FormPrimitive.Control;
|
||||||
|
const RadioItem = RadioGroupComp.Item;
|
||||||
|
const NativeRadio = FormPrimitive.Radio;
|
||||||
|
const SelectContent = SelectComp.Content;
|
||||||
|
const SelectLabel = SelectComp.Label;
|
||||||
|
const SelectGroup = SelectComp.Group;
|
||||||
|
const SelectItem = SelectComp.Item;
|
||||||
|
const SelectSeparator = SelectComp.Separator;
|
||||||
|
|
||||||
|
export type TextareaGetFormField = Omit<ReturnType<typeof getFormField>, "value"> & {
|
||||||
|
value: Writable<string>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export {
|
||||||
|
Root,
|
||||||
|
Field,
|
||||||
|
Control,
|
||||||
|
Item,
|
||||||
|
Input,
|
||||||
|
Label,
|
||||||
|
Button,
|
||||||
|
Switch,
|
||||||
|
Select,
|
||||||
|
Checkbox,
|
||||||
|
Textarea,
|
||||||
|
Validation,
|
||||||
|
RadioGroup,
|
||||||
|
RadioItem,
|
||||||
|
Description,
|
||||||
|
SelectContent,
|
||||||
|
SelectLabel,
|
||||||
|
SelectGroup,
|
||||||
|
SelectItem,
|
||||||
|
SelectSeparator,
|
||||||
|
SelectTrigger,
|
||||||
|
NativeSelect,
|
||||||
|
NativeRadio,
|
||||||
|
//
|
||||||
|
Root as Form,
|
||||||
|
Field as FormField,
|
||||||
|
Control as FormControl,
|
||||||
|
Item as FormItem,
|
||||||
|
Input as FormInput,
|
||||||
|
Textarea as FormTextarea,
|
||||||
|
Description as FormDescription,
|
||||||
|
Label as FormLabel,
|
||||||
|
Validation as FormValidation,
|
||||||
|
NativeSelect as FormNativeSelect,
|
||||||
|
NativeRadio as FormNativeRadio,
|
||||||
|
Checkbox as FormCheckbox,
|
||||||
|
Switch as FormSwitch,
|
||||||
|
RadioGroup as FormRadioGroup,
|
||||||
|
RadioItem as FormRadioItem,
|
||||||
|
Select as FormSelect,
|
||||||
|
SelectContent as FormSelectContent,
|
||||||
|
SelectLabel as FormSelectLabel,
|
||||||
|
SelectGroup as FormSelectGroup,
|
||||||
|
SelectItem as FormSelectItem,
|
||||||
|
SelectSeparator as FormSelectSeparator,
|
||||||
|
SelectTrigger as FormSelectTrigger,
|
||||||
|
Button as FormButton
|
||||||
|
};
|
14
apps/web/src/lib/components/ui/popover/index.ts
Normal file
14
apps/web/src/lib/components/ui/popover/index.ts
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
import { Popover as PopoverPrimitive } from "bits-ui";
|
||||||
|
import Content from "./popover-content.svelte";
|
||||||
|
const Root = PopoverPrimitive.Root;
|
||||||
|
const Trigger = PopoverPrimitive.Trigger;
|
||||||
|
|
||||||
|
export {
|
||||||
|
Root,
|
||||||
|
Content,
|
||||||
|
Trigger,
|
||||||
|
//
|
||||||
|
Root as Popover,
|
||||||
|
Content as PopoverContent,
|
||||||
|
Trigger as PopoverTrigger
|
||||||
|
};
|
|
@ -0,0 +1,27 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { Popover as PopoverPrimitive } from "bits-ui";
|
||||||
|
import { cn, flyAndScale } from "$lib/utils";
|
||||||
|
|
||||||
|
type $$Props = PopoverPrimitive.ContentProps;
|
||||||
|
|
||||||
|
let className: $$Props["class"] = undefined;
|
||||||
|
export let transition: $$Props["transition"] = flyAndScale;
|
||||||
|
export let transitionConfig: $$Props["transitionConfig"] = undefined;
|
||||||
|
export let align: $$Props["align"] = "center";
|
||||||
|
export let sideOffset: $$Props["sideOffset"] = 4;
|
||||||
|
export { className as class };
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<PopoverPrimitive.Content
|
||||||
|
{transition}
|
||||||
|
{transitionConfig}
|
||||||
|
{align}
|
||||||
|
{sideOffset}
|
||||||
|
{...$$restProps}
|
||||||
|
class={cn(
|
||||||
|
"z-50 w-72 rounded-md border bg-popover p-4 text-popover-foreground shadow-md outline-none",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<slot />
|
||||||
|
</PopoverPrimitive.Content>
|
15
apps/web/src/lib/components/ui/radio-group/index.ts
Normal file
15
apps/web/src/lib/components/ui/radio-group/index.ts
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
import { RadioGroup as RadioGroupPrimitive } from "bits-ui";
|
||||||
|
|
||||||
|
import Root from "./radio-group.svelte";
|
||||||
|
import Item from "./radio-group-item.svelte";
|
||||||
|
const Input = RadioGroupPrimitive.Input;
|
||||||
|
|
||||||
|
export {
|
||||||
|
Root,
|
||||||
|
Input,
|
||||||
|
Item,
|
||||||
|
//
|
||||||
|
Root as RadioGroup,
|
||||||
|
Input as RadioGroupInput,
|
||||||
|
Item as RadioGroupItem
|
||||||
|
};
|
|
@ -0,0 +1,30 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { RadioGroup as RadioGroupPrimitive } from "bits-ui";
|
||||||
|
import { Check } from "radix-icons-svelte";
|
||||||
|
import { cn } from "$lib/utils";
|
||||||
|
|
||||||
|
type $$Props = RadioGroupPrimitive.ItemProps & {
|
||||||
|
value: string;
|
||||||
|
};
|
||||||
|
type $$Events = RadioGroupPrimitive.ItemEvents;
|
||||||
|
|
||||||
|
let className: $$Props["class"] = undefined;
|
||||||
|
export let value: $$Props["value"];
|
||||||
|
export { className as class };
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<RadioGroupPrimitive.Item
|
||||||
|
{value}
|
||||||
|
class={cn(
|
||||||
|
"aspect-square h-4 w-4 rounded-full border border-primary text-primary shadow focus:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...$$restProps}
|
||||||
|
on:click
|
||||||
|
>
|
||||||
|
<div class="flex items-center justify-center">
|
||||||
|
<RadioGroupPrimitive.ItemIndicator>
|
||||||
|
<Check class="h-3.5 w-3.5 fill-primary" />
|
||||||
|
</RadioGroupPrimitive.ItemIndicator>
|
||||||
|
</div>
|
||||||
|
</RadioGroupPrimitive.Item>
|
|
@ -0,0 +1,14 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { RadioGroup as RadioGroupPrimitive } from "bits-ui";
|
||||||
|
import { cn } from "$lib/utils";
|
||||||
|
|
||||||
|
type $$Props = RadioGroupPrimitive.Props;
|
||||||
|
|
||||||
|
let className: $$Props["class"] = undefined;
|
||||||
|
export let value: $$Props["value"] = undefined;
|
||||||
|
export { className as class };
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<RadioGroupPrimitive.Root bind:value class={cn("grid gap-2", className)} {...$$restProps}>
|
||||||
|
<slot />
|
||||||
|
</RadioGroupPrimitive.Root>
|
34
apps/web/src/lib/components/ui/select/index.ts
Normal file
34
apps/web/src/lib/components/ui/select/index.ts
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
import { Select as SelectPrimitive } from "bits-ui";
|
||||||
|
|
||||||
|
import Label from "./select-label.svelte";
|
||||||
|
import Item from "./select-item.svelte";
|
||||||
|
import Content from "./select-content.svelte";
|
||||||
|
import Trigger from "./select-trigger.svelte";
|
||||||
|
import Separator from "./select-separator.svelte";
|
||||||
|
|
||||||
|
const Root = SelectPrimitive.Root;
|
||||||
|
const Group = SelectPrimitive.Group;
|
||||||
|
const Input = SelectPrimitive.Input;
|
||||||
|
const Value = SelectPrimitive.Value;
|
||||||
|
|
||||||
|
export {
|
||||||
|
Root,
|
||||||
|
Item,
|
||||||
|
Group,
|
||||||
|
Input,
|
||||||
|
Label,
|
||||||
|
Value,
|
||||||
|
Content,
|
||||||
|
Trigger,
|
||||||
|
Separator,
|
||||||
|
//
|
||||||
|
Root as Select,
|
||||||
|
Item as SelectItem,
|
||||||
|
Group as SelectGroup,
|
||||||
|
Input as SelectInput,
|
||||||
|
Label as SelectLabel,
|
||||||
|
Value as SelectValue,
|
||||||
|
Content as SelectContent,
|
||||||
|
Trigger as SelectTrigger,
|
||||||
|
Separator as SelectSeparator
|
||||||
|
};
|
36
apps/web/src/lib/components/ui/select/select-content.svelte
Normal file
36
apps/web/src/lib/components/ui/select/select-content.svelte
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { Select as SelectPrimitive } from "bits-ui";
|
||||||
|
import { cn, flyAndScale } from "$lib/utils";
|
||||||
|
import { scale } from "svelte/transition";
|
||||||
|
|
||||||
|
type $$Props = SelectPrimitive.ContentProps;
|
||||||
|
|
||||||
|
let className: $$Props["class"] = undefined;
|
||||||
|
export let sideOffset: $$Props["sideOffset"] = 4;
|
||||||
|
export let inTransition: $$Props["inTransition"] = flyAndScale;
|
||||||
|
export let inTransitionConfig: $$Props["inTransitionConfig"] = undefined;
|
||||||
|
export let outTransition: $$Props["outTransition"] = scale;
|
||||||
|
export let outTransitionConfig: $$Props["outTransitionConfig"] = {
|
||||||
|
start: 0.95,
|
||||||
|
opacity: 0,
|
||||||
|
duration: 50
|
||||||
|
};
|
||||||
|
export { className as class };
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<SelectPrimitive.Content
|
||||||
|
{inTransition}
|
||||||
|
{inTransitionConfig}
|
||||||
|
{outTransition}
|
||||||
|
{outTransitionConfig}
|
||||||
|
{sideOffset}
|
||||||
|
class={cn(
|
||||||
|
"relative z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover text-popover-foreground shadow-md focus:outline-none",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...$$restProps}
|
||||||
|
>
|
||||||
|
<div class="w-full p-1">
|
||||||
|
<slot />
|
||||||
|
</div>
|
||||||
|
</SelectPrimitive.Content>
|
35
apps/web/src/lib/components/ui/select/select-item.svelte
Normal file
35
apps/web/src/lib/components/ui/select/select-item.svelte
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { cn } from "$lib/utils";
|
||||||
|
import { Select as SelectPrimitive } from "bits-ui";
|
||||||
|
import { Check } from "radix-icons-svelte";
|
||||||
|
|
||||||
|
type $$Props = SelectPrimitive.ItemProps;
|
||||||
|
type $$Events = Required<SelectPrimitive.ItemEvents>;
|
||||||
|
|
||||||
|
let className: $$Props["class"] = undefined;
|
||||||
|
export let value: $$Props["value"];
|
||||||
|
export let label: $$Props["label"] = undefined;
|
||||||
|
export let disabled: $$Props["disabled"] = undefined;
|
||||||
|
export { className as class };
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<SelectPrimitive.Item
|
||||||
|
{value}
|
||||||
|
{disabled}
|
||||||
|
{label}
|
||||||
|
class={cn(
|
||||||
|
"relative flex w-full cursor-default select-none items-center rounded-sm py-1.5 pl-2 pr-8 text-sm outline-none data-[highlighted]:bg-accent data-[highlighted]:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...$$restProps}
|
||||||
|
on:click
|
||||||
|
on:pointermove
|
||||||
|
on:focusin
|
||||||
|
>
|
||||||
|
<span class="absolute right-2 flex h-3.5 w-3.5 items-center justify-center">
|
||||||
|
<SelectPrimitive.ItemIndicator>
|
||||||
|
<Check class="h-4 w-4" />
|
||||||
|
</SelectPrimitive.ItemIndicator>
|
||||||
|
</span>
|
||||||
|
<slot />
|
||||||
|
</SelectPrimitive.Item>
|
13
apps/web/src/lib/components/ui/select/select-label.svelte
Normal file
13
apps/web/src/lib/components/ui/select/select-label.svelte
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { Select as SelectPrimitive } from "bits-ui";
|
||||||
|
import { cn } from "$lib/utils";
|
||||||
|
|
||||||
|
type $$Props = SelectPrimitive.LabelProps;
|
||||||
|
|
||||||
|
let className: $$Props["class"] = undefined;
|
||||||
|
export { className as class };
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<SelectPrimitive.Label class={cn("px-2 py-1.5 text-sm font-semibold", className)} {...$$restProps}>
|
||||||
|
<slot />
|
||||||
|
</SelectPrimitive.Label>
|
|
@ -0,0 +1,11 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { Select as SelectPrimitive } from "bits-ui";
|
||||||
|
import { cn } from "$lib/utils";
|
||||||
|
|
||||||
|
type $$Props = SelectPrimitive.SeparatorProps;
|
||||||
|
|
||||||
|
let className: $$Props["class"] = undefined;
|
||||||
|
export { className as class };
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<SelectPrimitive.Separator class={cn("-mx-1 my-1 h-px bg-muted", className)} {...$$restProps} />
|
22
apps/web/src/lib/components/ui/select/select-trigger.svelte
Normal file
22
apps/web/src/lib/components/ui/select/select-trigger.svelte
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { Select as SelectPrimitive } from 'bits-ui';
|
||||||
|
import { CaretSort } from 'radix-icons-svelte';
|
||||||
|
import { cn } from '$lib/utils';
|
||||||
|
|
||||||
|
type $$Props = SelectPrimitive.TriggerProps;
|
||||||
|
type $$Events = SelectPrimitive.TriggerEvents;
|
||||||
|
|
||||||
|
let className: $$Props['class'] = undefined;
|
||||||
|
export { className as class };
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<SelectPrimitive.Trigger
|
||||||
|
class={cn(
|
||||||
|
'border-input ring-offset-background placeholder:text-muted-foreground focus:ring-ring line-clamp-1 flex h-9 w-full items-center justify-between truncate rounded-md border bg-transparent px-3 py-2 text-sm shadow-sm focus:outline-none focus:ring-1 disabled:cursor-not-allowed disabled:opacity-50 [&>span]:line-clamp-1',
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...$$restProps}
|
||||||
|
>
|
||||||
|
<slot />
|
||||||
|
<CaretSort class="h-4 w-4 opacity-50" />
|
||||||
|
</SelectPrimitive.Trigger>
|
7
apps/web/src/lib/components/ui/separator/index.ts
Normal file
7
apps/web/src/lib/components/ui/separator/index.ts
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
import Root from "./separator.svelte";
|
||||||
|
|
||||||
|
export {
|
||||||
|
Root,
|
||||||
|
//
|
||||||
|
Root as Separator
|
||||||
|
};
|
22
apps/web/src/lib/components/ui/separator/separator.svelte
Normal file
22
apps/web/src/lib/components/ui/separator/separator.svelte
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { Separator as SeparatorPrimitive } from "bits-ui";
|
||||||
|
import { cn } from "$lib/utils";
|
||||||
|
|
||||||
|
type $$Props = SeparatorPrimitive.Props;
|
||||||
|
|
||||||
|
let className: $$Props["class"] = undefined;
|
||||||
|
export let orientation: $$Props["orientation"] = "horizontal";
|
||||||
|
export let decorative: $$Props["decorative"] = undefined;
|
||||||
|
export { className as class };
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<SeparatorPrimitive.Root
|
||||||
|
class={cn(
|
||||||
|
"shrink-0 bg-border",
|
||||||
|
orientation === "horizontal" ? "h-[1px] w-full" : "h-full w-[1px]",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{orientation}
|
||||||
|
{decorative}
|
||||||
|
{...$$restProps}
|
||||||
|
/>
|
7
apps/web/src/lib/components/ui/switch/index.ts
Normal file
7
apps/web/src/lib/components/ui/switch/index.ts
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
import Root from "./switch.svelte";
|
||||||
|
|
||||||
|
export {
|
||||||
|
Root,
|
||||||
|
//
|
||||||
|
Root as Switch
|
||||||
|
};
|
28
apps/web/src/lib/components/ui/switch/switch.svelte
Normal file
28
apps/web/src/lib/components/ui/switch/switch.svelte
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { Switch as SwitchPrimitive } from "bits-ui";
|
||||||
|
import { cn } from "$lib/utils";
|
||||||
|
|
||||||
|
type $$Props = SwitchPrimitive.Props;
|
||||||
|
type $$Events = SwitchPrimitive.Events;
|
||||||
|
|
||||||
|
let className: $$Props["class"] = undefined;
|
||||||
|
export let checked: $$Props["checked"] = undefined;
|
||||||
|
export { className as class };
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<SwitchPrimitive.Root
|
||||||
|
bind:checked
|
||||||
|
class={cn(
|
||||||
|
"peer inline-flex h-[20px] w-[36px] shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent shadow-sm transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=unchecked]:bg-input",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...$$restProps}
|
||||||
|
on:click
|
||||||
|
on:keydown
|
||||||
|
>
|
||||||
|
<SwitchPrimitive.Thumb
|
||||||
|
class={cn(
|
||||||
|
"pointer-events-none block h-4 w-4 rounded-full bg-background shadow-lg ring-0 transition-transform data-[state=checked]:translate-x-4 data-[state=unchecked]:translate-x-0"
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</SwitchPrimitive.Root>
|
28
apps/web/src/lib/components/ui/table/index.ts
Normal file
28
apps/web/src/lib/components/ui/table/index.ts
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
import Root from "./table.svelte";
|
||||||
|
import Body from "./table-body.svelte";
|
||||||
|
import Caption from "./table-caption.svelte";
|
||||||
|
import Cell from "./table-cell.svelte";
|
||||||
|
import Footer from "./table-footer.svelte";
|
||||||
|
import Head from "./table-head.svelte";
|
||||||
|
import Header from "./table-header.svelte";
|
||||||
|
import Row from "./table-row.svelte";
|
||||||
|
|
||||||
|
export {
|
||||||
|
Root,
|
||||||
|
Body,
|
||||||
|
Caption,
|
||||||
|
Cell,
|
||||||
|
Footer,
|
||||||
|
Head,
|
||||||
|
Header,
|
||||||
|
Row,
|
||||||
|
//
|
||||||
|
Root as Table,
|
||||||
|
Body as TableBody,
|
||||||
|
Caption as TableCaption,
|
||||||
|
Cell as TableCell,
|
||||||
|
Footer as TableFooter,
|
||||||
|
Head as TableHead,
|
||||||
|
Header as TableHeader,
|
||||||
|
Row as TableRow
|
||||||
|
};
|
13
apps/web/src/lib/components/ui/table/table-body.svelte
Normal file
13
apps/web/src/lib/components/ui/table/table-body.svelte
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { cn } from "$lib/utils";
|
||||||
|
import type { HTMLAttributes } from "svelte/elements";
|
||||||
|
|
||||||
|
type $$Props = HTMLAttributes<HTMLTableSectionElement>;
|
||||||
|
|
||||||
|
let className: $$Props["class"] = undefined;
|
||||||
|
export { className as class };
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<tbody class={cn("[&_tr:last-child]:border-0", className)} {...$$restProps}>
|
||||||
|
<slot />
|
||||||
|
</tbody>
|
13
apps/web/src/lib/components/ui/table/table-caption.svelte
Normal file
13
apps/web/src/lib/components/ui/table/table-caption.svelte
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { cn } from "$lib/utils";
|
||||||
|
import type { HTMLAttributes } from "svelte/elements";
|
||||||
|
|
||||||
|
type $$Props = HTMLAttributes<HTMLTableCaptionElement>;
|
||||||
|
|
||||||
|
let className: $$Props["class"] = undefined;
|
||||||
|
export { className as class };
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<caption class={cn("mt-4 text-sm text-muted-foreground", className)} {...$$restProps}>
|
||||||
|
<slot />
|
||||||
|
</caption>
|
21
apps/web/src/lib/components/ui/table/table-cell.svelte
Normal file
21
apps/web/src/lib/components/ui/table/table-cell.svelte
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { cn } from "$lib/utils";
|
||||||
|
import type { HTMLTdAttributes } from "svelte/elements";
|
||||||
|
|
||||||
|
type $$Props = HTMLTdAttributes;
|
||||||
|
|
||||||
|
let className: $$Props["class"] = undefined;
|
||||||
|
export { className as class };
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<td
|
||||||
|
class={cn(
|
||||||
|
"p-2 align-middle [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px]",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...$$restProps}
|
||||||
|
on:click
|
||||||
|
on:keydown
|
||||||
|
>
|
||||||
|
<slot />
|
||||||
|
</td>
|
13
apps/web/src/lib/components/ui/table/table-footer.svelte
Normal file
13
apps/web/src/lib/components/ui/table/table-footer.svelte
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { cn } from "$lib/utils";
|
||||||
|
import type { HTMLAttributes } from "svelte/elements";
|
||||||
|
|
||||||
|
type $$Props = HTMLAttributes<HTMLTableSectionElement>;
|
||||||
|
|
||||||
|
let className: $$Props["class"] = undefined;
|
||||||
|
export { className as class };
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<tfoot class={cn("bg-primary font-medium text-primary-foreground", className)} {...$$restProps}>
|
||||||
|
<slot />
|
||||||
|
</tfoot>
|
19
apps/web/src/lib/components/ui/table/table-head.svelte
Normal file
19
apps/web/src/lib/components/ui/table/table-head.svelte
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { cn } from "$lib/utils";
|
||||||
|
import type { HTMLThAttributes } from "svelte/elements";
|
||||||
|
|
||||||
|
type $$Props = HTMLThAttributes;
|
||||||
|
|
||||||
|
let className: $$Props["class"] = undefined;
|
||||||
|
export { className as class };
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<th
|
||||||
|
class={cn(
|
||||||
|
"h-10 px-2 text-left align-middle font-medium text-muted-foreground [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px]",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...$$restProps}
|
||||||
|
>
|
||||||
|
<slot />
|
||||||
|
</th>
|
14
apps/web/src/lib/components/ui/table/table-header.svelte
Normal file
14
apps/web/src/lib/components/ui/table/table-header.svelte
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { cn } from "$lib/utils";
|
||||||
|
import type { HTMLAttributes } from "svelte/elements";
|
||||||
|
|
||||||
|
type $$Props = HTMLAttributes<HTMLTableSectionElement>;
|
||||||
|
|
||||||
|
let className: $$Props["class"] = undefined;
|
||||||
|
export { className as class };
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!-- svelte-ignore a11y-no-noninteractive-element-interactions -->
|
||||||
|
<thead class={cn("[&_tr]:border-b", className)} {...$$restProps} on:click on:keydown>
|
||||||
|
<slot />
|
||||||
|
</thead>
|
23
apps/web/src/lib/components/ui/table/table-row.svelte
Normal file
23
apps/web/src/lib/components/ui/table/table-row.svelte
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { cn } from "$lib/utils";
|
||||||
|
import type { HTMLAttributes } from "svelte/elements";
|
||||||
|
|
||||||
|
type $$Props = HTMLAttributes<HTMLTableRowElement> & {
|
||||||
|
"data-state"?: unknown;
|
||||||
|
};
|
||||||
|
|
||||||
|
let className: $$Props["class"] = undefined;
|
||||||
|
export { className as class };
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<tr
|
||||||
|
class={cn(
|
||||||
|
"border-b transition-colors hover:bg-muted/50 data-[state=selected]:bg-muted",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...$$restProps}
|
||||||
|
on:click
|
||||||
|
on:keydown
|
||||||
|
>
|
||||||
|
<slot />
|
||||||
|
</tr>
|
15
apps/web/src/lib/components/ui/table/table.svelte
Normal file
15
apps/web/src/lib/components/ui/table/table.svelte
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { cn } from "$lib/utils";
|
||||||
|
import type { HTMLTableAttributes } from "svelte/elements";
|
||||||
|
|
||||||
|
type $$Props = HTMLTableAttributes;
|
||||||
|
|
||||||
|
let className: $$Props["class"] = undefined;
|
||||||
|
export { className as class };
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="w-full overflow-auto">
|
||||||
|
<table class={cn("w-full caption-bottom text-sm", className)} {...$$restProps}>
|
||||||
|
<slot />
|
||||||
|
</table>
|
||||||
|
</div>
|
28
apps/web/src/lib/components/ui/textarea/index.ts
Normal file
28
apps/web/src/lib/components/ui/textarea/index.ts
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
import Root from "./textarea.svelte";
|
||||||
|
|
||||||
|
type FormTextareaEvent<T extends Event = Event> = T & {
|
||||||
|
currentTarget: EventTarget & HTMLTextAreaElement;
|
||||||
|
};
|
||||||
|
|
||||||
|
type TextareaEvents = {
|
||||||
|
blur: FormTextareaEvent<FocusEvent>;
|
||||||
|
change: FormTextareaEvent<Event>;
|
||||||
|
click: FormTextareaEvent<MouseEvent>;
|
||||||
|
focus: FormTextareaEvent<FocusEvent>;
|
||||||
|
keydown: FormTextareaEvent<KeyboardEvent>;
|
||||||
|
keypress: FormTextareaEvent<KeyboardEvent>;
|
||||||
|
keyup: FormTextareaEvent<KeyboardEvent>;
|
||||||
|
mouseover: FormTextareaEvent<MouseEvent>;
|
||||||
|
mouseenter: FormTextareaEvent<MouseEvent>;
|
||||||
|
mouseleave: FormTextareaEvent<MouseEvent>;
|
||||||
|
paste: FormTextareaEvent<ClipboardEvent>;
|
||||||
|
input: FormTextareaEvent<InputEvent>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export {
|
||||||
|
Root,
|
||||||
|
//
|
||||||
|
Root as Textarea,
|
||||||
|
type TextareaEvents,
|
||||||
|
type FormTextareaEvent
|
||||||
|
};
|
33
apps/web/src/lib/components/ui/textarea/textarea.svelte
Normal file
33
apps/web/src/lib/components/ui/textarea/textarea.svelte
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import type { HTMLTextareaAttributes } from "svelte/elements";
|
||||||
|
import { cn } from "$lib/utils";
|
||||||
|
import type { TextareaEvents } from ".";
|
||||||
|
|
||||||
|
type $$Props = HTMLTextareaAttributes;
|
||||||
|
type $$Events = TextareaEvents;
|
||||||
|
|
||||||
|
let className: $$Props["class"] = undefined;
|
||||||
|
export let value: $$Props["value"] = undefined;
|
||||||
|
export { className as class };
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<textarea
|
||||||
|
class={cn(
|
||||||
|
"flex min-h-[60px] w-full rounded-md border border-input bg-transparent px-3 py-2 text-sm shadow-sm placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
bind:value
|
||||||
|
on:blur
|
||||||
|
on:change
|
||||||
|
on:click
|
||||||
|
on:focus
|
||||||
|
on:keydown
|
||||||
|
on:keypress
|
||||||
|
on:keyup
|
||||||
|
on:mouseover
|
||||||
|
on:mouseenter
|
||||||
|
on:mouseleave
|
||||||
|
on:paste
|
||||||
|
on:input
|
||||||
|
{...$$restProps}
|
||||||
|
/>
|
|
@ -1,9 +1,10 @@
|
||||||
import { error, redirect } from '@sveltejs/kit';
|
import { error, redirect } from '@sveltejs/kit';
|
||||||
|
import type { Actions } from './$types';
|
||||||
|
|
||||||
export const actions = {
|
export const actions = {
|
||||||
default: async ({ request, locals }: { request: Request; locals: App.Locals }) => {
|
default: async ({ request, locals }: { request: Request; locals: App.Locals }) => {
|
||||||
const body = Object.fromEntries(await request.formData());
|
const body = Object.fromEntries(await request.formData());
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const email = body.email.toString();
|
const email = body.email.toString();
|
||||||
const password = body.password.toString();
|
const password = body.password.toString();
|
||||||
|
@ -20,5 +21,15 @@ export const actions = {
|
||||||
}
|
}
|
||||||
|
|
||||||
throw redirect(303, '/');
|
throw redirect(303, '/');
|
||||||
}
|
},
|
||||||
};
|
// TODO: Implement MS Auth
|
||||||
|
// msauth: async ({ request, cookies }) => {
|
||||||
|
// const form = await request.formData();
|
||||||
|
// const token = form.get('token');
|
||||||
|
// if (!token || typeof token !== 'string') {
|
||||||
|
// throw redirect(303, '/login');
|
||||||
|
// }
|
||||||
|
// cookies.set('pb_auth', JSON.stringify({ token: token }), { path: '/' });
|
||||||
|
// throw redirect(303, '/');
|
||||||
|
// }
|
||||||
|
} satisfies Actions;
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
import { enhance } from '$app/forms';
|
||||||
import { Icons } from '$lib/components/site/icons';
|
import { Icons } from '$lib/components/site/icons';
|
||||||
import { Button } from '$lib/components/ui/button';
|
import { Button } from '$lib/components/ui/button';
|
||||||
import { Input } from '$lib/components/ui/input';
|
import { Input } from '$lib/components/ui/input';
|
||||||
import { Label } from '$lib/components/ui/label';
|
import { Label } from '$lib/components/ui/label';
|
||||||
import * as Alert from "$lib/components/ui/alert";
|
import * as Alert from '$lib/components/ui/alert';
|
||||||
import { cn } from '$lib/utils';
|
import { cn } from '$lib/utils';
|
||||||
|
|
||||||
export let form;
|
export let form;
|
||||||
|
@ -19,7 +20,7 @@
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div class={cn('grid gap-6')} {...$$restProps}>
|
<div class={cn('grid gap-6')} {...$$restProps}>
|
||||||
<form method="POST">
|
<form method="POST" use:enhance={() => { isLoading = true; }}>
|
||||||
<div class="grid gap-2">
|
<div class="grid gap-2">
|
||||||
<div class="grid gap-1">
|
<div class="grid gap-1">
|
||||||
<Label class="sr-only" for="email">Email</Label>
|
<Label class="sr-only" for="email">Email</Label>
|
||||||
|
@ -36,7 +37,13 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="grid gap-1">
|
<div class="grid gap-1">
|
||||||
<Label class="sr-only" for="password">Password</Label>
|
<Label class="sr-only" for="password">Password</Label>
|
||||||
<Input id="password" name="password" type="password" disabled={isLoading} placeholder="Password" />
|
<Input
|
||||||
|
id="password"
|
||||||
|
name="password"
|
||||||
|
type="password"
|
||||||
|
disabled={isLoading}
|
||||||
|
placeholder="Password"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<Button type="submit" disabled={isLoading}>
|
<Button type="submit" disabled={isLoading}>
|
||||||
{#if isLoading}
|
{#if isLoading}
|
||||||
|
@ -48,9 +55,7 @@
|
||||||
{#if form?.notVerified}
|
{#if form?.notVerified}
|
||||||
<Alert.Root>
|
<Alert.Root>
|
||||||
<Alert.Title></Alert.Title>
|
<Alert.Title></Alert.Title>
|
||||||
<Alert.Description>
|
<Alert.Description>You must verify your email before you can login.</Alert.Description>
|
||||||
You must verify your email before you can login.
|
|
||||||
</Alert.Description>
|
|
||||||
</Alert.Root>
|
</Alert.Root>
|
||||||
{/if}
|
{/if}
|
||||||
</form>
|
</form>
|
||||||
|
@ -62,15 +67,17 @@
|
||||||
<span class="bg-background text-muted-foreground px-2"> Or continue with </span>
|
<span class="bg-background text-muted-foreground px-2"> Or continue with </span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<Button variant="outline" type="button" disabled={isLoading}>
|
<form action="/?msauth" method="POST">
|
||||||
{#if isLoading}
|
<Button type="submit" variant="outline" disabled={true} class="w-full">
|
||||||
<Icons.spinner class="mr-2 h-4 w-4 animate-spin" />
|
{#if isLoading}
|
||||||
{:else}
|
<Icons.spinner class="mr-2 h-4 w-4 animate-spin" />
|
||||||
<Icons.microsoft class="mr-2 h-4 w-4" />
|
{:else}
|
||||||
{/if}
|
<Icons.microsoft class="mr-2 h-4 w-4" />
|
||||||
{' '}
|
{/if}
|
||||||
Microsoft
|
{' '}
|
||||||
</Button>
|
Microsoft
|
||||||
|
</Button>
|
||||||
|
</form>
|
||||||
</div>
|
</div>
|
||||||
<p class="text-muted-foreground px-8 text-center text-sm">
|
<p class="text-muted-foreground px-8 text-center text-sm">
|
||||||
Don't have an account? <a class="text-primary underline" href="/register">Sign up.</a> <br />
|
Don't have an account? <a class="text-primary underline" href="/register">Sign up.</a> <br />
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
import { enhance } from '$app/forms';
|
||||||
import { Icons } from '$lib/components/site/icons';
|
import { Icons } from '$lib/components/site/icons';
|
||||||
import { Button } from '$lib/components/ui/button';
|
import { Button } from '$lib/components/ui/button';
|
||||||
import { Input } from '$lib/components/ui/input';
|
import { Input } from '$lib/components/ui/input';
|
||||||
|
@ -17,7 +18,7 @@
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div class={cn('grid gap-6')} {...$$restProps}>
|
<div class={cn('grid gap-6')} {...$$restProps}>
|
||||||
<form method="POST">
|
<form method="POST" use:enhance={() => { isLoading = true; }}>
|
||||||
<div class="grid gap-2">
|
<div class="grid gap-2">
|
||||||
<div class="grid gap-1">
|
<div class="grid gap-1">
|
||||||
<Label class="sr-only" for="email">Name</Label>
|
<Label class="sr-only" for="email">Name</Label>
|
||||||
|
@ -50,7 +51,7 @@
|
||||||
<Label class="sr-only" for="password">Confirm Password</Label>
|
<Label class="sr-only" for="password">Confirm Password</Label>
|
||||||
<Input id="password" name="passwordConfirm" type="password" disabled={isLoading} placeholder="Confirm password" />
|
<Input id="password" name="passwordConfirm" type="password" disabled={isLoading} placeholder="Confirm password" />
|
||||||
</div>
|
</div>
|
||||||
<Button type="submit" disabled={isLoading}>
|
<Button type="submit" disabled={isLoading} on:click={() => isLoading = true}>
|
||||||
{#if isLoading}
|
{#if isLoading}
|
||||||
<Icons.spinner class="mr-2 h-4 w-4 animate-spin" />
|
<Icons.spinner class="mr-2 h-4 w-4 animate-spin" />
|
||||||
{/if}
|
{/if}
|
||||||
|
@ -66,7 +67,7 @@
|
||||||
<span class="bg-background text-muted-foreground px-2"> Or continue with </span>
|
<span class="bg-background text-muted-foreground px-2"> Or continue with </span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<Button variant="outline" type="button" disabled={isLoading}>
|
<Button variant="outline" type="button" disabled={true}>
|
||||||
{#if isLoading}
|
{#if isLoading}
|
||||||
<Icons.spinner class="mr-2 h-4 w-4 animate-spin" />
|
<Icons.spinner class="mr-2 h-4 w-4 animate-spin" />
|
||||||
{:else}
|
{:else}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
import { enhance } from '$app/forms';
|
||||||
import { Icons } from '$lib/components/site/icons';
|
import { Icons } from '$lib/components/site/icons';
|
||||||
import { Button } from '$lib/components/ui/button';
|
import { Button } from '$lib/components/ui/button';
|
||||||
import { Input } from '$lib/components/ui/input';
|
import { Input } from '$lib/components/ui/input';
|
||||||
|
@ -20,7 +21,11 @@
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div class={cn('grid gap-6')} {...$$restProps}>
|
<div class={cn('grid gap-6')} {...$$restProps}>
|
||||||
<form method="POST">
|
<form method="POST" use:enhance={() => { isLoading = true;
|
||||||
|
return async ({ update }) => {
|
||||||
|
isLoading = false;
|
||||||
|
update();
|
||||||
|
}; }}>
|
||||||
<div class="grid gap-2">
|
<div class="grid gap-2">
|
||||||
<div class="grid gap-1">
|
<div class="grid gap-1">
|
||||||
<Label class="sr-only" for="email">Email</Label>
|
<Label class="sr-only" for="email">Email</Label>
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { Checkbox } from "$lib/components/ui/checkbox";
|
||||||
|
import type { HTMLButtonAttributes } from "svelte/elements";
|
||||||
|
import type { Writable } from "svelte/store";
|
||||||
|
|
||||||
|
type $$Props = HTMLButtonAttributes & {
|
||||||
|
checked: Writable<boolean>;
|
||||||
|
};
|
||||||
|
export let checked: Writable<boolean>;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<Checkbox bind:checked={$checked} {...$$restProps} />
|
|
@ -0,0 +1,62 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { ArrowDown, ArrowUp, CaretSort } from "radix-icons-svelte";
|
||||||
|
import { cn } from "$lib/utils";
|
||||||
|
import { Button } from "$lib/components/ui/button";
|
||||||
|
import * as DropdownMenu from "$lib/components/ui/dropdown-menu";
|
||||||
|
|
||||||
|
let className: string | undefined | null = undefined;
|
||||||
|
export { className as class };
|
||||||
|
export let props: {
|
||||||
|
select: never;
|
||||||
|
sort: {
|
||||||
|
order: "desc" | "asc" | undefined;
|
||||||
|
toggle: (event: Event) => void;
|
||||||
|
clear: () => void;
|
||||||
|
disabled: boolean;
|
||||||
|
};
|
||||||
|
filter: never;
|
||||||
|
};
|
||||||
|
|
||||||
|
function handleAscSort(e: Event) {
|
||||||
|
if (props.sort.order === "asc") {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
props.sort.toggle(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleDescSort(e: Event) {
|
||||||
|
if (props.sort.order === "desc") {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
props.sort.toggle(e);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{#if !props.sort.disabled}
|
||||||
|
<div class={cn("flex items-center", className)}>
|
||||||
|
<DropdownMenu.Root>
|
||||||
|
<DropdownMenu.Trigger asChild let:builder>
|
||||||
|
<Button
|
||||||
|
variant="ghost"
|
||||||
|
builders={[builder]}
|
||||||
|
class="-ml-3 h-8 data-[state=open]:bg-accent"
|
||||||
|
>
|
||||||
|
<slot />
|
||||||
|
{#if props.sort.order === "desc"}
|
||||||
|
<ArrowDown class="ml-2 h-4 w-4" />
|
||||||
|
{:else if props.sort.order === "asc"}
|
||||||
|
<ArrowUp class="ml-2 h-4 w-4" />
|
||||||
|
{:else}
|
||||||
|
<CaretSort class="ml-2 h-4 w-4" />
|
||||||
|
{/if}
|
||||||
|
</Button>
|
||||||
|
</DropdownMenu.Trigger>
|
||||||
|
<DropdownMenu.Content align="start">
|
||||||
|
<DropdownMenu.Item on:click={handleAscSort}>Asc</DropdownMenu.Item>
|
||||||
|
<DropdownMenu.Item on:click={handleDescSort}>Desc</DropdownMenu.Item>
|
||||||
|
</DropdownMenu.Content>
|
||||||
|
</DropdownMenu.Root>
|
||||||
|
</div>
|
||||||
|
{:else}
|
||||||
|
<slot />
|
||||||
|
{/if}
|
|
@ -0,0 +1,96 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { PlusCircled, Check } from "radix-icons-svelte";
|
||||||
|
import * as Command from "$lib/components/ui/command";
|
||||||
|
import * as Popover from "$lib/components/ui/popover";
|
||||||
|
import { Button } from "$lib/components/ui/button";
|
||||||
|
import { cn } from "$lib/utils";
|
||||||
|
import Separator from "$lib/components/ui/separator/separator.svelte";
|
||||||
|
import Badge from "$lib/components/ui/badge/badge.svelte";
|
||||||
|
import type { statuses } from "../(data)/data";
|
||||||
|
|
||||||
|
export let filterValues: string[] = [];
|
||||||
|
export let title: string;
|
||||||
|
export let options = [] as typeof statuses;
|
||||||
|
|
||||||
|
let open = false;
|
||||||
|
|
||||||
|
const handleSelect = (currentValue: string) => {
|
||||||
|
if (Array.isArray(filterValues) && filterValues.includes(currentValue)) {
|
||||||
|
filterValues = filterValues.filter((v) => v !== currentValue);
|
||||||
|
} else {
|
||||||
|
filterValues = [...(Array.isArray(filterValues) ? filterValues : []), currentValue];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<Popover.Root bind:open>
|
||||||
|
<Popover.Trigger asChild let:builder>
|
||||||
|
<Button builders={[builder]} variant="outline" size="sm" class="h-8 border-dashed">
|
||||||
|
<PlusCircled class="mr-2 h-4 w-4" />
|
||||||
|
{title}
|
||||||
|
|
||||||
|
{#if filterValues.length > 0}
|
||||||
|
<Separator orientation="vertical" class="mx-2 h-4" />
|
||||||
|
<Badge variant="secondary" class="rounded-sm px-1 font-normal lg:hidden">
|
||||||
|
{filterValues.length}
|
||||||
|
</Badge>
|
||||||
|
<div class="hidden space-x-1 lg:flex">
|
||||||
|
{#if filterValues.length > 2}
|
||||||
|
<Badge variant="secondary" class="rounded-sm px-1 font-normal">
|
||||||
|
{filterValues.length} Selected
|
||||||
|
</Badge>
|
||||||
|
{:else}
|
||||||
|
{#each filterValues as option}
|
||||||
|
<Badge variant="secondary" class="rounded-sm px-1 font-normal">
|
||||||
|
{option}
|
||||||
|
</Badge>
|
||||||
|
{/each}
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
</Button>
|
||||||
|
</Popover.Trigger>
|
||||||
|
<Popover.Content class="w-[200px] p-0" align="start" side="bottom">
|
||||||
|
<Command.Root>
|
||||||
|
<Command.Input placeholder={title} />
|
||||||
|
<Command.List>
|
||||||
|
<Command.Empty>No results found.</Command.Empty>
|
||||||
|
<Command.Group>
|
||||||
|
{#each options as option}
|
||||||
|
<Command.Item
|
||||||
|
value={option.value}
|
||||||
|
onSelect={(currentValue) => {
|
||||||
|
handleSelect(currentValue);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class={cn(
|
||||||
|
"mr-2 flex h-4 w-4 items-center justify-center rounded-sm border border-primary",
|
||||||
|
filterValues.includes(option.value)
|
||||||
|
? "bg-primary text-primary-foreground"
|
||||||
|
: "opacity-50 [&_svg]:invisible"
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<Check className={cn("h-4 w-4")} />
|
||||||
|
</div>
|
||||||
|
<span>
|
||||||
|
{option.label}
|
||||||
|
</span>
|
||||||
|
</Command.Item>
|
||||||
|
{/each}
|
||||||
|
</Command.Group>
|
||||||
|
{#if filterValues.length > 0}
|
||||||
|
<Command.Separator />
|
||||||
|
<Command.Item
|
||||||
|
class="justify-center text-center"
|
||||||
|
onSelect={() => {
|
||||||
|
filterValues = [];
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Clear filters
|
||||||
|
</Command.Item>
|
||||||
|
{/if}
|
||||||
|
</Command.List>
|
||||||
|
</Command.Root>
|
||||||
|
</Popover.Content>
|
||||||
|
</Popover.Root>
|
|
@ -0,0 +1,89 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { Button } from "$lib/components/ui/button";
|
||||||
|
import {
|
||||||
|
ChevronRight,
|
||||||
|
ChevronLeft,
|
||||||
|
DoubleArrowRight,
|
||||||
|
DoubleArrowLeft
|
||||||
|
} from "radix-icons-svelte";
|
||||||
|
import * as Select from "$lib/components/ui/select";
|
||||||
|
import type { Task } from "../(data)/schemas";
|
||||||
|
import type { AnyPlugins } from "svelte-headless-table/plugins";
|
||||||
|
import type { TableViewModel } from "svelte-headless-table";
|
||||||
|
|
||||||
|
export let tableModel: TableViewModel<Task, AnyPlugins>;
|
||||||
|
|
||||||
|
const { pageRows, pluginStates, rows } = tableModel;
|
||||||
|
|
||||||
|
const { hasNextPage, hasPreviousPage, pageIndex, pageCount, pageSize } = pluginStates.page;
|
||||||
|
|
||||||
|
const { selectedDataIds } = pluginStates.select;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="flex items-center justify-between px-2">
|
||||||
|
<div class="flex-1 text-sm text-muted-foreground">
|
||||||
|
{Object.keys($selectedDataIds).length} of{" "}
|
||||||
|
{$rows.length} row(s) selected.
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center space-x-6 lg:space-x-8">
|
||||||
|
<div class="flex items-center space-x-2">
|
||||||
|
<p class="text-sm font-medium">Rows per page</p>
|
||||||
|
<Select.Root
|
||||||
|
onSelectedChange={(selected) => pageSize.set(Number(selected?.value))}
|
||||||
|
selected={{ value: 10, label: "10" }}
|
||||||
|
>
|
||||||
|
<Select.Trigger class="w-[180px]">
|
||||||
|
<Select.Value placeholder="Select page size" />
|
||||||
|
</Select.Trigger>
|
||||||
|
<Select.Content>
|
||||||
|
<Select.Item value="10">10</Select.Item>
|
||||||
|
<Select.Item value="20">20</Select.Item>
|
||||||
|
<Select.Item value="30">30</Select.Item>
|
||||||
|
<Select.Item value="40">40</Select.Item>
|
||||||
|
<Select.Item value="50">50</Select.Item>
|
||||||
|
</Select.Content>
|
||||||
|
</Select.Root>
|
||||||
|
</div>
|
||||||
|
<div class="flex w-[100px] items-center justify-center text-sm font-medium">
|
||||||
|
Page {$pageIndex + 1} of {$pageCount}
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center space-x-2">
|
||||||
|
<Button
|
||||||
|
variant="outline"
|
||||||
|
class="hidden h-8 w-8 p-0 lg:flex"
|
||||||
|
on:click={() => ($pageIndex = 0)}
|
||||||
|
disabled={!$hasPreviousPage}
|
||||||
|
>
|
||||||
|
<span class="sr-only">Go to first page</span>
|
||||||
|
<DoubleArrowLeft size={15} />
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
variant="outline"
|
||||||
|
class="p-0 w-8 h-8"
|
||||||
|
on:click={() => ($pageIndex = $pageIndex - 1)}
|
||||||
|
disabled={!$hasPreviousPage}
|
||||||
|
>
|
||||||
|
<span class="sr-only">Go to previous page</span>
|
||||||
|
<ChevronLeft size={15} />
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
variant="outline"
|
||||||
|
class="p-0 w-8 h-8"
|
||||||
|
disabled={!$hasNextPage}
|
||||||
|
on:click={() => ($pageIndex = $pageIndex + 1)}
|
||||||
|
>
|
||||||
|
<span class="sr-only">Go to next page</span>
|
||||||
|
<ChevronRight size={15} />
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
variant="outline"
|
||||||
|
class="hidden h-8 w-8 p-0 lg:flex"
|
||||||
|
disabled={!$hasNextPage}
|
||||||
|
on:click={() => ($pageIndex = Math.ceil($rows.length / $pageRows.length) - 1)}
|
||||||
|
>
|
||||||
|
<span class="sr-only">Go to last page</span>
|
||||||
|
<DoubleArrowRight size={15} />
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
|
@ -0,0 +1,15 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { priorities } from "../(data)/data";
|
||||||
|
export let value: string;
|
||||||
|
const priority = priorities.find((priority) => priority.value === value);
|
||||||
|
const Icon = priority?.icon;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{#if priority}
|
||||||
|
<div class="flex items-center">
|
||||||
|
{#if Icon}
|
||||||
|
<Icon class="mr-2 h-4 w-4 text-muted-foreground" />
|
||||||
|
{/if}
|
||||||
|
<span>{priority.label}</span>
|
||||||
|
</div>
|
||||||
|
{/if}
|
|
@ -0,0 +1,46 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { DotsHorizontal } from "radix-icons-svelte";
|
||||||
|
import { Button } from "$lib/components/ui/button";
|
||||||
|
import * as DropdownMenu from "$lib/components/ui/dropdown-menu";
|
||||||
|
import { labels } from "../(data)/data";
|
||||||
|
import { taskSchema, type Task } from "../(data)/schemas";
|
||||||
|
|
||||||
|
export let row: Task;
|
||||||
|
const task = taskSchema.parse(row);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<DropdownMenu.Root>
|
||||||
|
<DropdownMenu.Trigger asChild let:builder>
|
||||||
|
<Button
|
||||||
|
variant="ghost"
|
||||||
|
builders={[builder]}
|
||||||
|
class="flex h-8 w-8 p-0 data-[state=open]:bg-muted"
|
||||||
|
>
|
||||||
|
<DotsHorizontal class="h-4 w-4" />
|
||||||
|
<span class="sr-only">Open menu</span>
|
||||||
|
</Button>
|
||||||
|
</DropdownMenu.Trigger>
|
||||||
|
<DropdownMenu.Content class="w-[160px]" align="end">
|
||||||
|
<DropdownMenu.Item>Edit</DropdownMenu.Item>
|
||||||
|
<DropdownMenu.Item>Make a copy</DropdownMenu.Item>
|
||||||
|
<DropdownMenu.Item>Favorite</DropdownMenu.Item>
|
||||||
|
<DropdownMenu.Separator />
|
||||||
|
<DropdownMenu.Sub>
|
||||||
|
<DropdownMenu.SubTrigger>Labels</DropdownMenu.SubTrigger>
|
||||||
|
<DropdownMenu.SubContent>
|
||||||
|
<DropdownMenu.RadioGroup value={task.label}>
|
||||||
|
{#each labels as label}
|
||||||
|
<DropdownMenu.RadioItem value={label.value}>
|
||||||
|
{label.label}
|
||||||
|
</DropdownMenu.RadioItem>
|
||||||
|
{/each}
|
||||||
|
</DropdownMenu.RadioGroup>
|
||||||
|
</DropdownMenu.SubContent>
|
||||||
|
</DropdownMenu.Sub>
|
||||||
|
<DropdownMenu.Separator />
|
||||||
|
<DropdownMenu.Item>
|
||||||
|
Delete
|
||||||
|
<DropdownMenu.Shortcut>⌘⌫</DropdownMenu.Shortcut>
|
||||||
|
</DropdownMenu.Item>
|
||||||
|
</DropdownMenu.Content>
|
||||||
|
</DropdownMenu.Root>
|
|
@ -0,0 +1,16 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { statuses } from "../(data)/data";
|
||||||
|
|
||||||
|
export let value: string;
|
||||||
|
const status = statuses.find((status) => status.value === value);
|
||||||
|
const Icon = status?.icon;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{#if status}
|
||||||
|
<div class="flex w-[100px] items-center">
|
||||||
|
{#if Icon}
|
||||||
|
<Icon class="mr-2 h-4 w-4 text-muted-foreground" />
|
||||||
|
{/if}
|
||||||
|
<span>{status.label}</span>
|
||||||
|
</div>
|
||||||
|
{/if}
|
|
@ -0,0 +1,17 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { Badge } from "$lib/components/ui/badge";
|
||||||
|
import { labels } from "../(data)/data";
|
||||||
|
|
||||||
|
export let value: string;
|
||||||
|
export let labelValue: string;
|
||||||
|
const label = labels.find((label) => label.value === labelValue);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="flex space-x-2">
|
||||||
|
{#if label}
|
||||||
|
<Badge variant="outline">{label.label}</Badge>
|
||||||
|
{/if}
|
||||||
|
<span class="max-w-[500px] truncate font-medium">
|
||||||
|
{value}
|
||||||
|
</span>
|
||||||
|
</div>
|
|
@ -0,0 +1,69 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { Input } from "$lib/components/ui/input";
|
||||||
|
import { DataTableFacetedFilter, DataTableViewOptions } from ".";
|
||||||
|
import type { AnyPlugins } from "svelte-headless-table/lib/types/TablePlugin";
|
||||||
|
import type { Task } from "../(data)/schemas";
|
||||||
|
import type { TableViewModel } from "svelte-headless-table/lib/createViewModel";
|
||||||
|
import Button from "$lib/components/ui/button/button.svelte";
|
||||||
|
import { Cross2 } from "radix-icons-svelte";
|
||||||
|
import { statuses, priorities } from "../(data)/data";
|
||||||
|
import type { Writable } from "svelte/store";
|
||||||
|
|
||||||
|
export let tableModel: TableViewModel<Task, AnyPlugins>;
|
||||||
|
|
||||||
|
const { pluginStates } = tableModel;
|
||||||
|
const {
|
||||||
|
filterValue
|
||||||
|
}: {
|
||||||
|
filterValue: Writable<string>;
|
||||||
|
} = pluginStates.filter;
|
||||||
|
|
||||||
|
const {
|
||||||
|
filterValues
|
||||||
|
}: {
|
||||||
|
filterValues: Writable<{
|
||||||
|
status: string[];
|
||||||
|
priority: string[];
|
||||||
|
}>;
|
||||||
|
} = pluginStates.colFilter;
|
||||||
|
|
||||||
|
$: showReset = Object.values({ ...$filterValues, $filterValue }).some((v) => v.length > 0);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="flex items-center justify-between">
|
||||||
|
<div class="flex flex-1 items-center space-x-2">
|
||||||
|
<Input
|
||||||
|
placeholder="Filter tasks..."
|
||||||
|
class="h-8 w-[150px] lg:w-[250px]"
|
||||||
|
type="search"
|
||||||
|
bind:value={$filterValue}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<DataTableFacetedFilter
|
||||||
|
bind:filterValues={$filterValues.status}
|
||||||
|
title="Status"
|
||||||
|
options={statuses}
|
||||||
|
/>
|
||||||
|
<DataTableFacetedFilter
|
||||||
|
bind:filterValues={$filterValues.priority}
|
||||||
|
title="Priority"
|
||||||
|
options={priorities}
|
||||||
|
/>
|
||||||
|
{#if showReset}
|
||||||
|
<Button
|
||||||
|
on:click={() => {
|
||||||
|
$filterValue = "";
|
||||||
|
$filterValues.status = [];
|
||||||
|
$filterValues.priority = [];
|
||||||
|
}}
|
||||||
|
variant="ghost"
|
||||||
|
class="h-8 px-2 lg:px-3"
|
||||||
|
>
|
||||||
|
Reset
|
||||||
|
<Cross2 class="ml-2 h-4 w-4" />
|
||||||
|
</Button>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<DataTableViewOptions {tableModel} />
|
||||||
|
</div>
|
|
@ -0,0 +1,42 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { MixerHorizontal } from "radix-icons-svelte";
|
||||||
|
import { Button } from "$lib/components/ui/button";
|
||||||
|
import * as DropdownMenu from "$lib/components/ui/dropdown-menu";
|
||||||
|
import type { AnyPlugins } from "svelte-headless-table/lib/types/TablePlugin";
|
||||||
|
import type { Task } from "../(data)/schemas";
|
||||||
|
import type { TableViewModel } from "svelte-headless-table/lib/createViewModel";
|
||||||
|
|
||||||
|
export let tableModel: TableViewModel<Task, AnyPlugins>;
|
||||||
|
const { pluginStates, flatColumns } = tableModel;
|
||||||
|
const { hiddenColumnIds } = pluginStates.hide;
|
||||||
|
|
||||||
|
const ids = flatColumns.map((col: { id: string }) => col.id);
|
||||||
|
|
||||||
|
let hideForId = Object.fromEntries(ids.map((id: string) => [id, true]));
|
||||||
|
|
||||||
|
$: $hiddenColumnIds = Object.entries(hideForId)
|
||||||
|
.filter(([, hide]) => !hide)
|
||||||
|
.map(([id]) => id);
|
||||||
|
|
||||||
|
const hidableCols = ["title", "status", "priority"];
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<DropdownMenu.Root>
|
||||||
|
<DropdownMenu.Trigger asChild let:builder>
|
||||||
|
<Button variant="outline" size="sm" class="ml-auto hidden h-8 lg:flex" builders={[builder]}>
|
||||||
|
<MixerHorizontal class="mr-2 h-4 w-4" />
|
||||||
|
View
|
||||||
|
</Button>
|
||||||
|
</DropdownMenu.Trigger>
|
||||||
|
<DropdownMenu.Content>
|
||||||
|
<DropdownMenu.Label>Toggle columns</DropdownMenu.Label>
|
||||||
|
<DropdownMenu.Separator />
|
||||||
|
{#each flatColumns as col}
|
||||||
|
{#if hidableCols.includes(col.id)}
|
||||||
|
<DropdownMenu.CheckboxItem bind:checked={hideForId[col.id]}>
|
||||||
|
{col.header}
|
||||||
|
</DropdownMenu.CheckboxItem>
|
||||||
|
{/if}
|
||||||
|
{/each}
|
||||||
|
</DropdownMenu.Content>
|
||||||
|
</DropdownMenu.Root>
|
|
@ -0,0 +1,222 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { get, readable } from "svelte/store";
|
||||||
|
import { Render, Subscribe, createRender, createTable } from "svelte-headless-table";
|
||||||
|
import * as Table from "$lib/components/ui/table";
|
||||||
|
import {
|
||||||
|
addColumnFilters,
|
||||||
|
addHiddenColumns,
|
||||||
|
addPagination,
|
||||||
|
addSelectedRows,
|
||||||
|
addSortBy,
|
||||||
|
addTableFilter
|
||||||
|
} from "svelte-headless-table/plugins";
|
||||||
|
import {
|
||||||
|
DataTableCheckbox,
|
||||||
|
DataTableTitleCell,
|
||||||
|
DataTableStatusCell,
|
||||||
|
DataTableRowActions,
|
||||||
|
DataTablePriorityCell,
|
||||||
|
DataTableColumnHeader,
|
||||||
|
DataTableToolbar,
|
||||||
|
DataTablePagination
|
||||||
|
} from ".";
|
||||||
|
|
||||||
|
import type { Task } from "../(data)/schemas";
|
||||||
|
|
||||||
|
export let data: Task[];
|
||||||
|
|
||||||
|
const table = createTable(readable(data), {
|
||||||
|
select: addSelectedRows(),
|
||||||
|
sort: addSortBy({
|
||||||
|
toggleOrder: ["asc", "desc"]
|
||||||
|
}),
|
||||||
|
page: addPagination(),
|
||||||
|
filter: addTableFilter({
|
||||||
|
fn: ({ filterValue, value }) => {
|
||||||
|
return value.toLowerCase().includes(filterValue.toLowerCase());
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
colFilter: addColumnFilters(),
|
||||||
|
hide: addHiddenColumns()
|
||||||
|
});
|
||||||
|
|
||||||
|
const columns = table.createColumns([
|
||||||
|
table.display({
|
||||||
|
id: "select",
|
||||||
|
header: (_, { pluginStates }) => {
|
||||||
|
const { allPageRowsSelected } = pluginStates.select;
|
||||||
|
return createRender(DataTableCheckbox, {
|
||||||
|
checked: allPageRowsSelected,
|
||||||
|
"aria-label": "Select all"
|
||||||
|
});
|
||||||
|
},
|
||||||
|
cell: ({ row }, { pluginStates }) => {
|
||||||
|
const { getRowState } = pluginStates.select;
|
||||||
|
const { isSelected } = getRowState(row);
|
||||||
|
return createRender(DataTableCheckbox, {
|
||||||
|
checked: isSelected,
|
||||||
|
"aria-label": "Select row",
|
||||||
|
class: "translate-y-[2px]"
|
||||||
|
});
|
||||||
|
},
|
||||||
|
plugins: {
|
||||||
|
sort: {
|
||||||
|
disable: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
table.column({
|
||||||
|
accessor: "id",
|
||||||
|
header: () => {
|
||||||
|
return "Task";
|
||||||
|
},
|
||||||
|
id: "task",
|
||||||
|
plugins: {
|
||||||
|
sort: {
|
||||||
|
disable: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
table.column({
|
||||||
|
accessor: "title",
|
||||||
|
header: "Title",
|
||||||
|
id: "title",
|
||||||
|
cell: ({ value, row }) => {
|
||||||
|
if (row.isData()) {
|
||||||
|
return createRender(DataTableTitleCell, {
|
||||||
|
value,
|
||||||
|
labelValue: row.original.label
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
table.column({
|
||||||
|
accessor: "status",
|
||||||
|
header: "Status",
|
||||||
|
id: "status",
|
||||||
|
cell: ({ value }) => {
|
||||||
|
return createRender(DataTableStatusCell, {
|
||||||
|
value
|
||||||
|
});
|
||||||
|
},
|
||||||
|
plugins: {
|
||||||
|
colFilter: {
|
||||||
|
fn: ({ filterValue, value }) => {
|
||||||
|
if (filterValue.length === 0) return true;
|
||||||
|
if (!Array.isArray(filterValue) || typeof value !== "string") return true;
|
||||||
|
return filterValue.some((filter) => {
|
||||||
|
return value.includes(filter);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
initialFilterValue: [],
|
||||||
|
render: ({ filterValue }) => {
|
||||||
|
return get(filterValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
table.column({
|
||||||
|
accessor: "priority",
|
||||||
|
id: "priority",
|
||||||
|
header: "Priority",
|
||||||
|
cell: ({ value }) => {
|
||||||
|
return createRender(DataTablePriorityCell, {
|
||||||
|
value
|
||||||
|
});
|
||||||
|
},
|
||||||
|
plugins: {
|
||||||
|
colFilter: {
|
||||||
|
fn: ({ filterValue, value }) => {
|
||||||
|
if (filterValue.length === 0) return true;
|
||||||
|
if (!Array.isArray(filterValue) || typeof value !== "string") return true;
|
||||||
|
|
||||||
|
return filterValue.some((filter) => {
|
||||||
|
return value.includes(filter);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
initialFilterValue: [],
|
||||||
|
render: ({ filterValue }) => {
|
||||||
|
return get(filterValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
table.display({
|
||||||
|
id: "actions",
|
||||||
|
header: () => {
|
||||||
|
return "";
|
||||||
|
},
|
||||||
|
cell: ({ row }) => {
|
||||||
|
if (row.isData() && row.original) {
|
||||||
|
return createRender(DataTableRowActions, {
|
||||||
|
row: row.original
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
})
|
||||||
|
]);
|
||||||
|
|
||||||
|
const tableModel = table.createViewModel(columns);
|
||||||
|
|
||||||
|
const { headerRows, pageRows, tableAttrs, tableBodyAttrs } = tableModel;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="space-y-4">
|
||||||
|
<DataTableToolbar {tableModel} />
|
||||||
|
<div class="rounded-md border">
|
||||||
|
<Table.Root {...$tableAttrs}>
|
||||||
|
<Table.Header>
|
||||||
|
{#each $headerRows as headerRow}
|
||||||
|
<Subscribe rowAttrs={headerRow.attrs()}>
|
||||||
|
<Table.Row>
|
||||||
|
{#each headerRow.cells as cell (cell.id)}
|
||||||
|
<Subscribe
|
||||||
|
attrs={cell.attrs()}
|
||||||
|
let:attrs
|
||||||
|
props={cell.props()}
|
||||||
|
let:props
|
||||||
|
>
|
||||||
|
<Table.Head {...attrs}>
|
||||||
|
{#if cell.id !== "select" && cell.id !== "actions"}
|
||||||
|
<DataTableColumnHeader {props}
|
||||||
|
><Render
|
||||||
|
of={cell.render()}
|
||||||
|
/></DataTableColumnHeader
|
||||||
|
>
|
||||||
|
{:else}
|
||||||
|
<Render of={cell.render()} />
|
||||||
|
{/if}
|
||||||
|
</Table.Head>
|
||||||
|
</Subscribe>
|
||||||
|
{/each}
|
||||||
|
</Table.Row>
|
||||||
|
</Subscribe>
|
||||||
|
{/each}
|
||||||
|
</Table.Header>
|
||||||
|
<Table.Body {...$tableBodyAttrs}>
|
||||||
|
{#each $pageRows as row (row.id)}
|
||||||
|
<Subscribe rowAttrs={row.attrs()} let:rowAttrs>
|
||||||
|
<Table.Row {...rowAttrs}>
|
||||||
|
{#each row.cells as cell (cell.id)}
|
||||||
|
<Subscribe attrs={cell.attrs()} let:attrs>
|
||||||
|
<Table.Cell {...attrs}>
|
||||||
|
{#if cell.id === "task"}
|
||||||
|
<div class="w-[80px]">
|
||||||
|
<Render of={cell.render()} />
|
||||||
|
</div>
|
||||||
|
{:else}
|
||||||
|
<Render of={cell.render()} />
|
||||||
|
{/if}
|
||||||
|
</Table.Cell>
|
||||||
|
</Subscribe>
|
||||||
|
{/each}
|
||||||
|
</Table.Row>
|
||||||
|
</Subscribe>
|
||||||
|
{/each}
|
||||||
|
</Table.Body>
|
||||||
|
</Table.Root>
|
||||||
|
</div>
|
||||||
|
<DataTablePagination {tableModel} />
|
||||||
|
</div>
|
|
@ -0,0 +1,10 @@
|
||||||
|
export { default as DataTableCheckbox } from "./data-table-checkbox.svelte";
|
||||||
|
export { default as DataTableTitleCell } from "./data-table-title-cell.svelte";
|
||||||
|
export { default as DataTableStatusCell } from "./data-table-status-cell.svelte";
|
||||||
|
export { default as DataTableRowActions } from "./data-table-row-actions.svelte";
|
||||||
|
export { default as DataTablePriorityCell } from "./data-table-priority-cell.svelte";
|
||||||
|
export { default as DataTableColumnHeader } from "./data-table-column-header.svelte";
|
||||||
|
export { default as DataTableToolbar } from "./data-table-toolbar.svelte";
|
||||||
|
export { default as DataTablePagination } from "./data-table-pagination.svelte";
|
||||||
|
export { default as DataTableViewOptions } from "./data-table-view-options.svelte";
|
||||||
|
export { default as DataTableFacetedFilter } from "./data-table-faceted-filter.svelte";
|
|
@ -0,0 +1,45 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import * as Avatar from "$lib/components/ui/avatar";
|
||||||
|
import { Button } from "$lib/components/ui/button";
|
||||||
|
import * as DropdownMenu from "$lib/components/ui/dropdown-menu";
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<DropdownMenu.Root>
|
||||||
|
<DropdownMenu.Trigger asChild let:builder>
|
||||||
|
<Button variant="ghost" builders={[builder]} class="relative h-8 w-8 rounded-full">
|
||||||
|
<Avatar.Root class="h-9 w-9">
|
||||||
|
<Avatar.Image src="/avatars/03.png" alt="@shadcn" />
|
||||||
|
<Avatar.Fallback>SC</Avatar.Fallback>
|
||||||
|
</Avatar.Root>
|
||||||
|
</Button>
|
||||||
|
</DropdownMenu.Trigger>
|
||||||
|
<DropdownMenu.Content class="w-56" align="end">
|
||||||
|
<DropdownMenu.Label class="font-normal">
|
||||||
|
<div class="flex flex-col space-y-1">
|
||||||
|
<p class="text-sm font-medium leading-none">shadcn</p>
|
||||||
|
<p class="text-xs leading-none text-muted-foreground">m@example.com</p>
|
||||||
|
</div>
|
||||||
|
</DropdownMenu.Label>
|
||||||
|
<DropdownMenu.Separator />
|
||||||
|
<DropdownMenu.Group>
|
||||||
|
<DropdownMenu.Item>
|
||||||
|
Profile
|
||||||
|
<DropdownMenu.Shortcut>⇧⌘P</DropdownMenu.Shortcut>
|
||||||
|
</DropdownMenu.Item>
|
||||||
|
<DropdownMenu.Item>
|
||||||
|
Billing
|
||||||
|
<DropdownMenu.Shortcut>⌘B</DropdownMenu.Shortcut>
|
||||||
|
</DropdownMenu.Item>
|
||||||
|
<DropdownMenu.Item>
|
||||||
|
Settings
|
||||||
|
<DropdownMenu.Shortcut>⌘S</DropdownMenu.Shortcut>
|
||||||
|
</DropdownMenu.Item>
|
||||||
|
<DropdownMenu.Item>New Team</DropdownMenu.Item>
|
||||||
|
</DropdownMenu.Group>
|
||||||
|
<DropdownMenu.Separator />
|
||||||
|
<DropdownMenu.Item>
|
||||||
|
Log out
|
||||||
|
<DropdownMenu.Shortcut>⇧⌘Q</DropdownMenu.Shortcut>
|
||||||
|
</DropdownMenu.Item>
|
||||||
|
</DropdownMenu.Content>
|
||||||
|
</DropdownMenu.Root>
|
71
apps/web/src/routes/(dashboard)/dashboard/(data)/data.ts
Normal file
71
apps/web/src/routes/(dashboard)/dashboard/(data)/data.ts
Normal file
|
@ -0,0 +1,71 @@
|
||||||
|
import {
|
||||||
|
ArrowDown,
|
||||||
|
ArrowRight,
|
||||||
|
ArrowUp,
|
||||||
|
CheckCircled,
|
||||||
|
Circle,
|
||||||
|
CrossCircled,
|
||||||
|
QuestionMarkCircled,
|
||||||
|
Stopwatch
|
||||||
|
} from "radix-icons-svelte";
|
||||||
|
|
||||||
|
export const labels = [
|
||||||
|
{
|
||||||
|
value: "bug",
|
||||||
|
label: "Bug"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: "feature",
|
||||||
|
label: "Feature"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: "documentation",
|
||||||
|
label: "Documentation"
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
export const statuses = [
|
||||||
|
{
|
||||||
|
value: "backlog",
|
||||||
|
label: "Backlog",
|
||||||
|
icon: QuestionMarkCircled
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: "todo",
|
||||||
|
label: "Todo",
|
||||||
|
icon: Circle
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: "in progress",
|
||||||
|
label: "In Progress",
|
||||||
|
icon: Stopwatch
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: "done",
|
||||||
|
label: "Done",
|
||||||
|
icon: CheckCircled
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: "canceled",
|
||||||
|
label: "Canceled",
|
||||||
|
icon: CrossCircled
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
export const priorities = [
|
||||||
|
{
|
||||||
|
label: "Low",
|
||||||
|
value: "low",
|
||||||
|
icon: ArrowDown
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Medium",
|
||||||
|
value: "medium",
|
||||||
|
icon: ArrowRight
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "High",
|
||||||
|
value: "high",
|
||||||
|
icon: ArrowUp
|
||||||
|
}
|
||||||
|
];
|
13
apps/web/src/routes/(dashboard)/dashboard/(data)/schemas.ts
Normal file
13
apps/web/src/routes/(dashboard)/dashboard/(data)/schemas.ts
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
import { z } from "zod";
|
||||||
|
|
||||||
|
// We're keeping a simple non-relational schema here.
|
||||||
|
// IRL, you will have a schema for your data models.
|
||||||
|
export const taskSchema = z.object({
|
||||||
|
id: z.string(),
|
||||||
|
title: z.string(),
|
||||||
|
status: z.string(),
|
||||||
|
label: z.string(),
|
||||||
|
priority: z.string()
|
||||||
|
});
|
||||||
|
|
||||||
|
export type Task = z.infer<typeof taskSchema>;
|
702
apps/web/src/routes/(dashboard)/dashboard/(data)/tasks.json
Normal file
702
apps/web/src/routes/(dashboard)/dashboard/(data)/tasks.json
Normal file
|
@ -0,0 +1,702 @@
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"id": "TASK-8782",
|
||||||
|
"title": "You can't compress the program without quantifying the open-source SSD pixel!",
|
||||||
|
"status": "in progress",
|
||||||
|
"label": "documentation",
|
||||||
|
"priority": "medium"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "TASK-7878",
|
||||||
|
"title": "Try to calculate the EXE feed, maybe it will index the multi-byte pixel!",
|
||||||
|
"status": "backlog",
|
||||||
|
"label": "documentation",
|
||||||
|
"priority": "medium"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "TASK-7839",
|
||||||
|
"title": "We need to bypass the neural TCP card!",
|
||||||
|
"status": "todo",
|
||||||
|
"label": "bug",
|
||||||
|
"priority": "high"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "TASK-5562",
|
||||||
|
"title": "The SAS interface is down, bypass the open-source pixel so we can back up the PNG bandwidth!",
|
||||||
|
"status": "backlog",
|
||||||
|
"label": "feature",
|
||||||
|
"priority": "medium"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "TASK-8686",
|
||||||
|
"title": "I'll parse the wireless SSL protocol, that should driver the API panel!",
|
||||||
|
"status": "canceled",
|
||||||
|
"label": "feature",
|
||||||
|
"priority": "medium"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "TASK-1280",
|
||||||
|
"title": "Use the digital TLS panel, then you can transmit the haptic system!",
|
||||||
|
"status": "done",
|
||||||
|
"label": "bug",
|
||||||
|
"priority": "high"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "TASK-7262",
|
||||||
|
"title": "The UTF8 application is down, parse the neural bandwidth so we can back up the PNG firewall!",
|
||||||
|
"status": "done",
|
||||||
|
"label": "feature",
|
||||||
|
"priority": "high"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "TASK-1138",
|
||||||
|
"title": "Generating the driver won't do anything, we need to quantify the 1080p SMTP bandwidth!",
|
||||||
|
"status": "in progress",
|
||||||
|
"label": "feature",
|
||||||
|
"priority": "medium"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "TASK-7184",
|
||||||
|
"title": "We need to program the back-end THX pixel!",
|
||||||
|
"status": "todo",
|
||||||
|
"label": "feature",
|
||||||
|
"priority": "low"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "TASK-5160",
|
||||||
|
"title": "Calculating the bus won't do anything, we need to navigate the back-end JSON protocol!",
|
||||||
|
"status": "in progress",
|
||||||
|
"label": "documentation",
|
||||||
|
"priority": "high"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "TASK-5618",
|
||||||
|
"title": "Generating the driver won't do anything, we need to index the online SSL application!",
|
||||||
|
"status": "done",
|
||||||
|
"label": "documentation",
|
||||||
|
"priority": "medium"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "TASK-6699",
|
||||||
|
"title": "I'll transmit the wireless JBOD capacitor, that should hard drive the SSD feed!",
|
||||||
|
"status": "backlog",
|
||||||
|
"label": "documentation",
|
||||||
|
"priority": "medium"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "TASK-2858",
|
||||||
|
"title": "We need to override the online UDP bus!",
|
||||||
|
"status": "backlog",
|
||||||
|
"label": "bug",
|
||||||
|
"priority": "medium"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "TASK-9864",
|
||||||
|
"title": "I'll reboot the 1080p FTP panel, that should matrix the HEX hard drive!",
|
||||||
|
"status": "done",
|
||||||
|
"label": "bug",
|
||||||
|
"priority": "high"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "TASK-8404",
|
||||||
|
"title": "We need to generate the virtual HEX alarm!",
|
||||||
|
"status": "in progress",
|
||||||
|
"label": "bug",
|
||||||
|
"priority": "low"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "TASK-5365",
|
||||||
|
"title": "Backing up the pixel won't do anything, we need to transmit the primary IB array!",
|
||||||
|
"status": "in progress",
|
||||||
|
"label": "documentation",
|
||||||
|
"priority": "low"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "TASK-1780",
|
||||||
|
"title": "The CSS feed is down, index the bluetooth transmitter so we can compress the CLI protocol!",
|
||||||
|
"status": "todo",
|
||||||
|
"label": "documentation",
|
||||||
|
"priority": "high"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "TASK-6938",
|
||||||
|
"title": "Use the redundant SCSI application, then you can hack the optical alarm!",
|
||||||
|
"status": "todo",
|
||||||
|
"label": "documentation",
|
||||||
|
"priority": "high"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "TASK-9885",
|
||||||
|
"title": "We need to compress the auxiliary VGA driver!",
|
||||||
|
"status": "backlog",
|
||||||
|
"label": "bug",
|
||||||
|
"priority": "high"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "TASK-3216",
|
||||||
|
"title": "Transmitting the transmitter won't do anything, we need to compress the virtual HDD sensor!",
|
||||||
|
"status": "backlog",
|
||||||
|
"label": "documentation",
|
||||||
|
"priority": "medium"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "TASK-9285",
|
||||||
|
"title": "The IP monitor is down, copy the haptic alarm so we can generate the HTTP transmitter!",
|
||||||
|
"status": "todo",
|
||||||
|
"label": "bug",
|
||||||
|
"priority": "high"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "TASK-1024",
|
||||||
|
"title": "Overriding the microchip won't do anything, we need to transmit the digital OCR transmitter!",
|
||||||
|
"status": "in progress",
|
||||||
|
"label": "documentation",
|
||||||
|
"priority": "low"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "TASK-7068",
|
||||||
|
"title": "You can't generate the capacitor without indexing the wireless HEX pixel!",
|
||||||
|
"status": "canceled",
|
||||||
|
"label": "bug",
|
||||||
|
"priority": "low"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "TASK-6502",
|
||||||
|
"title": "Navigating the microchip won't do anything, we need to bypass the back-end SQL bus!",
|
||||||
|
"status": "todo",
|
||||||
|
"label": "bug",
|
||||||
|
"priority": "high"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "TASK-5326",
|
||||||
|
"title": "We need to hack the redundant UTF8 transmitter!",
|
||||||
|
"status": "todo",
|
||||||
|
"label": "bug",
|
||||||
|
"priority": "low"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "TASK-6274",
|
||||||
|
"title": "Use the virtual PCI circuit, then you can parse the bluetooth alarm!",
|
||||||
|
"status": "canceled",
|
||||||
|
"label": "documentation",
|
||||||
|
"priority": "low"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "TASK-1571",
|
||||||
|
"title": "I'll input the neural DRAM circuit, that should protocol the SMTP interface!",
|
||||||
|
"status": "in progress",
|
||||||
|
"label": "feature",
|
||||||
|
"priority": "medium"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "TASK-9518",
|
||||||
|
"title": "Compressing the interface won't do anything, we need to compress the online SDD matrix!",
|
||||||
|
"status": "canceled",
|
||||||
|
"label": "documentation",
|
||||||
|
"priority": "medium"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "TASK-5581",
|
||||||
|
"title": "I'll synthesize the digital COM pixel, that should transmitter the UTF8 protocol!",
|
||||||
|
"status": "backlog",
|
||||||
|
"label": "documentation",
|
||||||
|
"priority": "high"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "TASK-2197",
|
||||||
|
"title": "Parsing the feed won't do anything, we need to copy the bluetooth DRAM bus!",
|
||||||
|
"status": "todo",
|
||||||
|
"label": "documentation",
|
||||||
|
"priority": "low"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "TASK-8484",
|
||||||
|
"title": "We need to parse the solid state UDP firewall!",
|
||||||
|
"status": "in progress",
|
||||||
|
"label": "bug",
|
||||||
|
"priority": "low"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "TASK-9892",
|
||||||
|
"title": "If we back up the application, we can get to the UDP application through the multi-byte THX capacitor!",
|
||||||
|
"status": "done",
|
||||||
|
"label": "documentation",
|
||||||
|
"priority": "high"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "TASK-9616",
|
||||||
|
"title": "We need to synthesize the cross-platform ASCII pixel!",
|
||||||
|
"status": "in progress",
|
||||||
|
"label": "feature",
|
||||||
|
"priority": "medium"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "TASK-9744",
|
||||||
|
"title": "Use the back-end IP card, then you can input the solid state hard drive!",
|
||||||
|
"status": "done",
|
||||||
|
"label": "documentation",
|
||||||
|
"priority": "low"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "TASK-1376",
|
||||||
|
"title": "Generating the alarm won't do anything, we need to generate the mobile IP capacitor!",
|
||||||
|
"status": "backlog",
|
||||||
|
"label": "documentation",
|
||||||
|
"priority": "low"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "TASK-7382",
|
||||||
|
"title": "If we back up the firewall, we can get to the RAM alarm through the primary UTF8 pixel!",
|
||||||
|
"status": "todo",
|
||||||
|
"label": "feature",
|
||||||
|
"priority": "low"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "TASK-2290",
|
||||||
|
"title": "I'll compress the virtual JSON panel, that should application the UTF8 bus!",
|
||||||
|
"status": "canceled",
|
||||||
|
"label": "documentation",
|
||||||
|
"priority": "high"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "TASK-1533",
|
||||||
|
"title": "You can't input the firewall without overriding the wireless TCP firewall!",
|
||||||
|
"status": "done",
|
||||||
|
"label": "bug",
|
||||||
|
"priority": "high"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "TASK-4920",
|
||||||
|
"title": "Bypassing the hard drive won't do anything, we need to input the bluetooth JSON program!",
|
||||||
|
"status": "in progress",
|
||||||
|
"label": "bug",
|
||||||
|
"priority": "high"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "TASK-5168",
|
||||||
|
"title": "If we synthesize the bus, we can get to the IP panel through the virtual TLS array!",
|
||||||
|
"status": "in progress",
|
||||||
|
"label": "feature",
|
||||||
|
"priority": "low"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "TASK-7103",
|
||||||
|
"title": "We need to parse the multi-byte EXE bandwidth!",
|
||||||
|
"status": "canceled",
|
||||||
|
"label": "feature",
|
||||||
|
"priority": "low"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "TASK-4314",
|
||||||
|
"title": "If we compress the program, we can get to the XML alarm through the multi-byte COM matrix!",
|
||||||
|
"status": "in progress",
|
||||||
|
"label": "bug",
|
||||||
|
"priority": "high"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "TASK-3415",
|
||||||
|
"title": "Use the cross-platform XML application, then you can quantify the solid state feed!",
|
||||||
|
"status": "todo",
|
||||||
|
"label": "feature",
|
||||||
|
"priority": "high"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "TASK-8339",
|
||||||
|
"title": "Try to calculate the DNS interface, maybe it will input the bluetooth capacitor!",
|
||||||
|
"status": "in progress",
|
||||||
|
"label": "feature",
|
||||||
|
"priority": "low"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "TASK-6995",
|
||||||
|
"title": "Try to hack the XSS bandwidth, maybe it will override the bluetooth matrix!",
|
||||||
|
"status": "todo",
|
||||||
|
"label": "feature",
|
||||||
|
"priority": "high"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "TASK-8053",
|
||||||
|
"title": "If we connect the program, we can get to the UTF8 matrix through the digital UDP protocol!",
|
||||||
|
"status": "todo",
|
||||||
|
"label": "feature",
|
||||||
|
"priority": "medium"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "TASK-4336",
|
||||||
|
"title": "If we synthesize the microchip, we can get to the SAS sensor through the optical UDP program!",
|
||||||
|
"status": "todo",
|
||||||
|
"label": "documentation",
|
||||||
|
"priority": "low"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "TASK-8790",
|
||||||
|
"title": "I'll back up the optical COM alarm, that should alarm the RSS capacitor!",
|
||||||
|
"status": "done",
|
||||||
|
"label": "bug",
|
||||||
|
"priority": "medium"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "TASK-8980",
|
||||||
|
"title": "Try to navigate the SQL transmitter, maybe it will back up the virtual firewall!",
|
||||||
|
"status": "canceled",
|
||||||
|
"label": "bug",
|
||||||
|
"priority": "low"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "TASK-7342",
|
||||||
|
"title": "Use the neural CLI card, then you can parse the online port!",
|
||||||
|
"status": "backlog",
|
||||||
|
"label": "documentation",
|
||||||
|
"priority": "low"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "TASK-5608",
|
||||||
|
"title": "I'll hack the haptic SSL program, that should bus the UDP transmitter!",
|
||||||
|
"status": "canceled",
|
||||||
|
"label": "documentation",
|
||||||
|
"priority": "low"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "TASK-1606",
|
||||||
|
"title": "I'll generate the bluetooth PNG firewall, that should pixel the SSL driver!",
|
||||||
|
"status": "done",
|
||||||
|
"label": "feature",
|
||||||
|
"priority": "medium"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "TASK-7872",
|
||||||
|
"title": "Transmitting the circuit won't do anything, we need to reboot the 1080p RSS monitor!",
|
||||||
|
"status": "canceled",
|
||||||
|
"label": "feature",
|
||||||
|
"priority": "medium"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "TASK-4167",
|
||||||
|
"title": "Use the cross-platform SMS circuit, then you can synthesize the optical feed!",
|
||||||
|
"status": "canceled",
|
||||||
|
"label": "bug",
|
||||||
|
"priority": "medium"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "TASK-9581",
|
||||||
|
"title": "You can't index the port without hacking the cross-platform XSS monitor!",
|
||||||
|
"status": "backlog",
|
||||||
|
"label": "documentation",
|
||||||
|
"priority": "low"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "TASK-8806",
|
||||||
|
"title": "We need to bypass the back-end SSL panel!",
|
||||||
|
"status": "done",
|
||||||
|
"label": "bug",
|
||||||
|
"priority": "medium"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "TASK-6542",
|
||||||
|
"title": "Try to quantify the RSS firewall, maybe it will quantify the open-source system!",
|
||||||
|
"status": "done",
|
||||||
|
"label": "feature",
|
||||||
|
"priority": "low"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "TASK-6806",
|
||||||
|
"title": "The VGA protocol is down, reboot the back-end matrix so we can parse the CSS panel!",
|
||||||
|
"status": "canceled",
|
||||||
|
"label": "documentation",
|
||||||
|
"priority": "low"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "TASK-9549",
|
||||||
|
"title": "You can't bypass the bus without connecting the neural JBOD bus!",
|
||||||
|
"status": "todo",
|
||||||
|
"label": "feature",
|
||||||
|
"priority": "high"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "TASK-1075",
|
||||||
|
"title": "Backing up the driver won't do anything, we need to parse the redundant RAM pixel!",
|
||||||
|
"status": "done",
|
||||||
|
"label": "feature",
|
||||||
|
"priority": "medium"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "TASK-1427",
|
||||||
|
"title": "Use the auxiliary PCI circuit, then you can calculate the cross-platform interface!",
|
||||||
|
"status": "done",
|
||||||
|
"label": "documentation",
|
||||||
|
"priority": "high"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "TASK-1907",
|
||||||
|
"title": "Hacking the circuit won't do anything, we need to back up the online DRAM system!",
|
||||||
|
"status": "todo",
|
||||||
|
"label": "documentation",
|
||||||
|
"priority": "high"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "TASK-4309",
|
||||||
|
"title": "If we generate the system, we can get to the TCP sensor through the optical GB pixel!",
|
||||||
|
"status": "backlog",
|
||||||
|
"label": "bug",
|
||||||
|
"priority": "medium"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "TASK-3973",
|
||||||
|
"title": "I'll parse the back-end ADP array, that should bandwidth the RSS bandwidth!",
|
||||||
|
"status": "todo",
|
||||||
|
"label": "feature",
|
||||||
|
"priority": "medium"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "TASK-7962",
|
||||||
|
"title": "Use the wireless RAM program, then you can hack the cross-platform feed!",
|
||||||
|
"status": "canceled",
|
||||||
|
"label": "bug",
|
||||||
|
"priority": "low"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "TASK-3360",
|
||||||
|
"title": "You can't quantify the program without synthesizing the neural OCR interface!",
|
||||||
|
"status": "done",
|
||||||
|
"label": "feature",
|
||||||
|
"priority": "medium"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "TASK-9887",
|
||||||
|
"title": "Use the auxiliary ASCII sensor, then you can connect the solid state port!",
|
||||||
|
"status": "backlog",
|
||||||
|
"label": "bug",
|
||||||
|
"priority": "medium"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "TASK-3649",
|
||||||
|
"title": "I'll input the virtual USB system, that should circuit the DNS monitor!",
|
||||||
|
"status": "in progress",
|
||||||
|
"label": "feature",
|
||||||
|
"priority": "medium"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "TASK-3586",
|
||||||
|
"title": "If we quantify the circuit, we can get to the CLI feed through the mobile SMS hard drive!",
|
||||||
|
"status": "in progress",
|
||||||
|
"label": "bug",
|
||||||
|
"priority": "low"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "TASK-5150",
|
||||||
|
"title": "I'll hack the wireless XSS port, that should transmitter the IP interface!",
|
||||||
|
"status": "canceled",
|
||||||
|
"label": "feature",
|
||||||
|
"priority": "medium"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "TASK-3652",
|
||||||
|
"title": "The SQL interface is down, override the optical bus so we can program the ASCII interface!",
|
||||||
|
"status": "backlog",
|
||||||
|
"label": "feature",
|
||||||
|
"priority": "low"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "TASK-6884",
|
||||||
|
"title": "Use the digital PCI circuit, then you can synthesize the multi-byte microchip!",
|
||||||
|
"status": "canceled",
|
||||||
|
"label": "feature",
|
||||||
|
"priority": "high"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "TASK-1591",
|
||||||
|
"title": "We need to connect the mobile XSS driver!",
|
||||||
|
"status": "in progress",
|
||||||
|
"label": "feature",
|
||||||
|
"priority": "high"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "TASK-3802",
|
||||||
|
"title": "Try to override the ASCII protocol, maybe it will parse the virtual matrix!",
|
||||||
|
"status": "in progress",
|
||||||
|
"label": "feature",
|
||||||
|
"priority": "low"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "TASK-7253",
|
||||||
|
"title": "Programming the capacitor won't do anything, we need to bypass the neural IB hard drive!",
|
||||||
|
"status": "backlog",
|
||||||
|
"label": "bug",
|
||||||
|
"priority": "high"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "TASK-9739",
|
||||||
|
"title": "We need to hack the multi-byte HDD bus!",
|
||||||
|
"status": "done",
|
||||||
|
"label": "documentation",
|
||||||
|
"priority": "medium"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "TASK-4424",
|
||||||
|
"title": "Try to hack the HEX alarm, maybe it will connect the optical pixel!",
|
||||||
|
"status": "in progress",
|
||||||
|
"label": "documentation",
|
||||||
|
"priority": "medium"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "TASK-3922",
|
||||||
|
"title": "You can't back up the capacitor without generating the wireless PCI program!",
|
||||||
|
"status": "backlog",
|
||||||
|
"label": "bug",
|
||||||
|
"priority": "low"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "TASK-4921",
|
||||||
|
"title": "I'll index the open-source IP feed, that should system the GB application!",
|
||||||
|
"status": "canceled",
|
||||||
|
"label": "bug",
|
||||||
|
"priority": "low"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "TASK-5814",
|
||||||
|
"title": "We need to calculate the 1080p AGP feed!",
|
||||||
|
"status": "backlog",
|
||||||
|
"label": "bug",
|
||||||
|
"priority": "high"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "TASK-2645",
|
||||||
|
"title": "Synthesizing the system won't do anything, we need to navigate the multi-byte HDD firewall!",
|
||||||
|
"status": "todo",
|
||||||
|
"label": "documentation",
|
||||||
|
"priority": "medium"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "TASK-4535",
|
||||||
|
"title": "Try to copy the JSON circuit, maybe it will connect the wireless feed!",
|
||||||
|
"status": "in progress",
|
||||||
|
"label": "feature",
|
||||||
|
"priority": "low"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "TASK-4463",
|
||||||
|
"title": "We need to copy the solid state AGP monitor!",
|
||||||
|
"status": "done",
|
||||||
|
"label": "documentation",
|
||||||
|
"priority": "low"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "TASK-9745",
|
||||||
|
"title": "If we connect the protocol, we can get to the GB system through the bluetooth PCI microchip!",
|
||||||
|
"status": "canceled",
|
||||||
|
"label": "feature",
|
||||||
|
"priority": "high"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "TASK-2080",
|
||||||
|
"title": "If we input the bus, we can get to the RAM matrix through the auxiliary RAM card!",
|
||||||
|
"status": "todo",
|
||||||
|
"label": "bug",
|
||||||
|
"priority": "medium"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "TASK-3838",
|
||||||
|
"title": "I'll bypass the online TCP application, that should panel the AGP system!",
|
||||||
|
"status": "backlog",
|
||||||
|
"label": "bug",
|
||||||
|
"priority": "high"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "TASK-1340",
|
||||||
|
"title": "We need to navigate the virtual PNG circuit!",
|
||||||
|
"status": "todo",
|
||||||
|
"label": "bug",
|
||||||
|
"priority": "medium"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "TASK-6665",
|
||||||
|
"title": "If we parse the monitor, we can get to the SSD hard drive through the cross-platform AGP alarm!",
|
||||||
|
"status": "canceled",
|
||||||
|
"label": "feature",
|
||||||
|
"priority": "low"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "TASK-7585",
|
||||||
|
"title": "If we calculate the hard drive, we can get to the SSL program through the multi-byte CSS microchip!",
|
||||||
|
"status": "backlog",
|
||||||
|
"label": "feature",
|
||||||
|
"priority": "low"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "TASK-6319",
|
||||||
|
"title": "We need to copy the multi-byte SCSI program!",
|
||||||
|
"status": "backlog",
|
||||||
|
"label": "bug",
|
||||||
|
"priority": "high"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "TASK-4369",
|
||||||
|
"title": "Try to input the SCSI bus, maybe it will generate the 1080p pixel!",
|
||||||
|
"status": "backlog",
|
||||||
|
"label": "bug",
|
||||||
|
"priority": "high"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "TASK-9035",
|
||||||
|
"title": "We need to override the solid state PNG array!",
|
||||||
|
"status": "canceled",
|
||||||
|
"label": "documentation",
|
||||||
|
"priority": "low"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "TASK-3970",
|
||||||
|
"title": "You can't index the transmitter without quantifying the haptic ASCII card!",
|
||||||
|
"status": "todo",
|
||||||
|
"label": "documentation",
|
||||||
|
"priority": "medium"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "TASK-4473",
|
||||||
|
"title": "You can't bypass the protocol without overriding the neural RSS program!",
|
||||||
|
"status": "todo",
|
||||||
|
"label": "documentation",
|
||||||
|
"priority": "low"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "TASK-4136",
|
||||||
|
"title": "You can't hack the hard drive without hacking the primary JSON program!",
|
||||||
|
"status": "canceled",
|
||||||
|
"label": "bug",
|
||||||
|
"priority": "medium"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "TASK-3939",
|
||||||
|
"title": "Use the back-end SQL firewall, then you can connect the neural hard drive!",
|
||||||
|
"status": "done",
|
||||||
|
"label": "feature",
|
||||||
|
"priority": "low"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "TASK-2007",
|
||||||
|
"title": "I'll input the back-end USB protocol, that should bandwidth the PCI system!",
|
||||||
|
"status": "backlog",
|
||||||
|
"label": "bug",
|
||||||
|
"priority": "high"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "TASK-7516",
|
||||||
|
"title": "Use the primary SQL program, then you can generate the auxiliary transmitter!",
|
||||||
|
"status": "done",
|
||||||
|
"label": "documentation",
|
||||||
|
"priority": "medium"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "TASK-6906",
|
||||||
|
"title": "Try to back up the DRAM system, maybe it will reboot the online transmitter!",
|
||||||
|
"status": "done",
|
||||||
|
"label": "feature",
|
||||||
|
"priority": "high"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "TASK-5207",
|
||||||
|
"title": "The SMS interface is down, copy the bluetooth bus so we can quantify the VGA card!",
|
||||||
|
"status": "in progress",
|
||||||
|
"label": "bug",
|
||||||
|
"priority": "low"
|
||||||
|
}
|
||||||
|
]
|
|
@ -1,8 +1,18 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
import DataTable from "./(components)/data-table.svelte";
|
||||||
|
import UserNav from "./(components)/user-nav.svelte";
|
||||||
|
import data from "./(data)/tasks.json";
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<h1>Create a new dashboard</h1>
|
<div class="hidden h-full flex-1 flex-col space-y-8 p-8 md:flex">
|
||||||
|
<div class="flex items-center justify-between space-y-2">
|
||||||
<form method="POST">
|
<div>
|
||||||
<button type="submit">Create dashboard</button>
|
<h2 class="text-2xl font-bold tracking-tight">Welcome back!</h2>
|
||||||
</form>
|
<p class="text-muted-foreground">Here's a list of your tasks for this month!</p>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center space-x-2">
|
||||||
|
<UserNav />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<DataTable {data} />
|
||||||
|
</div>
|
||||||
|
|
|
@ -0,0 +1,43 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { cn } from "$lib/utils";
|
||||||
|
import { page } from "$app/stores";
|
||||||
|
import { Button } from "$lib/components/ui/button";
|
||||||
|
import { cubicInOut } from "svelte/easing";
|
||||||
|
import { crossfade } from "svelte/transition";
|
||||||
|
|
||||||
|
let className: string | undefined | null = undefined;
|
||||||
|
export let items: { href: string; title: string }[];
|
||||||
|
export { className as class };
|
||||||
|
|
||||||
|
const [send, receive] = crossfade({
|
||||||
|
duration: 250,
|
||||||
|
easing: cubicInOut
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<nav class={cn("flex space-x-2 lg:flex-col lg:space-x-0 lg:space-y-1", className)}>
|
||||||
|
{#each items as item}
|
||||||
|
{@const isActive = $page.url.pathname === item.href}
|
||||||
|
|
||||||
|
<Button
|
||||||
|
href={item.href}
|
||||||
|
variant="ghost"
|
||||||
|
class={cn(
|
||||||
|
!isActive && "hover:underline",
|
||||||
|
"relative justify-start hover:bg-transparent"
|
||||||
|
)}
|
||||||
|
data-sveltekit-noscroll
|
||||||
|
>
|
||||||
|
{#if isActive}
|
||||||
|
<div
|
||||||
|
class="absolute inset-0 rounded-md bg-muted"
|
||||||
|
in:send={{ key: "active-sidebar-tab" }}
|
||||||
|
out:receive={{ key: "active-sidebar-tab" }}
|
||||||
|
/>
|
||||||
|
{/if}
|
||||||
|
<div class="relative">
|
||||||
|
{item.title}
|
||||||
|
</div>
|
||||||
|
</Button>
|
||||||
|
{/each}
|
||||||
|
</nav>
|
41
apps/web/src/routes/(dashboard)/settings/+layout.svelte
Normal file
41
apps/web/src/routes/(dashboard)/settings/+layout.svelte
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { Separator } from "$lib/components/ui/separator";
|
||||||
|
import SidebarNav from "./(components)/sidebar-nav.svelte";
|
||||||
|
|
||||||
|
const sidebarNavItems = [
|
||||||
|
{
|
||||||
|
title: "Profile",
|
||||||
|
href: "/settings"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Account",
|
||||||
|
href: "/settings/account"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Appearance",
|
||||||
|
href: "/settings/appearance"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Notifications",
|
||||||
|
href: "/settings/notifications"
|
||||||
|
}
|
||||||
|
];
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="hidden space-y-6 p-10 pb-16 md:block">
|
||||||
|
<div class="space-y-0.5">
|
||||||
|
<h2 class="text-2xl font-bold tracking-tight">Settings</h2>
|
||||||
|
<p class="text-muted-foreground">
|
||||||
|
Manage your account settings and set e-mail preferences.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<Separator class="my-6" />
|
||||||
|
<div class="flex flex-col space-y-8 lg:flex-row lg:space-x-12 lg:space-y-0">
|
||||||
|
<aside class="-mx-4 lg:w-1/5">
|
||||||
|
<SidebarNav items={sidebarNavItems} />
|
||||||
|
</aside>
|
||||||
|
<div class="flex-1 lg:max-w-2xl">
|
||||||
|
<slot />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
24
apps/web/src/routes/(dashboard)/settings/+page.server.ts
Normal file
24
apps/web/src/routes/(dashboard)/settings/+page.server.ts
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
import type { PageServerLoad } from "./$types";
|
||||||
|
import { superValidate } from "sveltekit-superforms/server";
|
||||||
|
import { profileFormSchema } from "./profile-form.svelte";
|
||||||
|
import { fail, type Actions } from "@sveltejs/kit";
|
||||||
|
|
||||||
|
export const load: PageServerLoad = async () => {
|
||||||
|
return {
|
||||||
|
form: await superValidate(profileFormSchema)
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export const actions: Actions = {
|
||||||
|
default: async (event) => {
|
||||||
|
const form = await superValidate(event, profileFormSchema);
|
||||||
|
if (!form.valid) {
|
||||||
|
return fail(400, {
|
||||||
|
form
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
form
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
15
apps/web/src/routes/(dashboard)/settings/+page.svelte
Normal file
15
apps/web/src/routes/(dashboard)/settings/+page.svelte
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import type { PageData } from "./$types";
|
||||||
|
import ProfileForm from "./profile-form.svelte";
|
||||||
|
import { Separator } from "$lib/components/ui/separator";
|
||||||
|
export let data: PageData;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="space-y-6">
|
||||||
|
<div>
|
||||||
|
<h3 class="text-lg font-medium">Profile</h3>
|
||||||
|
<p class="text-sm text-muted-foreground">This is how others will see you on the site.</p>
|
||||||
|
</div>
|
||||||
|
<Separator />
|
||||||
|
<ProfileForm data={data.form} />
|
||||||
|
</div>
|
|
@ -0,0 +1,24 @@
|
||||||
|
import { superValidate } from "sveltekit-superforms/server";
|
||||||
|
import type { PageServerLoad } from "./$types";
|
||||||
|
import { accountFormSchema } from "./account-form.svelte";
|
||||||
|
import { fail, type Actions } from "@sveltejs/kit";
|
||||||
|
|
||||||
|
export const load: PageServerLoad = async () => {
|
||||||
|
return {
|
||||||
|
form: await superValidate(accountFormSchema)
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export const actions: Actions = {
|
||||||
|
default: async (event) => {
|
||||||
|
const form = await superValidate(event, accountFormSchema);
|
||||||
|
if (!form.valid) {
|
||||||
|
return fail(400, {
|
||||||
|
form
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
form
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
|
@ -0,0 +1,18 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { Separator } from "$lib/components/ui/separator";
|
||||||
|
import AccountForm from "./account-form.svelte";
|
||||||
|
import type { PageData } from "./$types";
|
||||||
|
|
||||||
|
export let data: PageData;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="space-y-6">
|
||||||
|
<div>
|
||||||
|
<h3 class="text-lg font-medium">Account</h3>
|
||||||
|
<p class="text-sm text-muted-foreground">
|
||||||
|
Update your account settings. Set your preferred language and timezone.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<Separator />
|
||||||
|
<AccountForm data={data.form} />
|
||||||
|
</div>
|
|
@ -0,0 +1,85 @@
|
||||||
|
<script lang="ts" context="module">
|
||||||
|
import { z } from "zod";
|
||||||
|
|
||||||
|
const languages = {
|
||||||
|
en: "English",
|
||||||
|
fr: "French",
|
||||||
|
de: "German",
|
||||||
|
es: "Spanish",
|
||||||
|
pt: "Portuguese",
|
||||||
|
ru: "Russian",
|
||||||
|
ja: "Japanese",
|
||||||
|
ko: "Korean",
|
||||||
|
zh: "Chinese"
|
||||||
|
} as const;
|
||||||
|
|
||||||
|
type Language = keyof typeof languages;
|
||||||
|
|
||||||
|
export const accountFormSchema = z.object({
|
||||||
|
name: z
|
||||||
|
.string({
|
||||||
|
required_error: "Required."
|
||||||
|
})
|
||||||
|
.min(2, "Name must be at least 2 characters.")
|
||||||
|
.max(30, "Name must not be longer than 30 characters"),
|
||||||
|
// Hack: https://github.com/colinhacks/zod/issues/2280
|
||||||
|
language: z.enum(Object.keys(languages) as [Language, ...Language[]])
|
||||||
|
});
|
||||||
|
|
||||||
|
export type AccountFormSchema = typeof accountFormSchema;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import * as Form from "$lib/components/ui/form";
|
||||||
|
import type { SuperValidated } from "sveltekit-superforms";
|
||||||
|
import { cn } from "$lib/utils";
|
||||||
|
|
||||||
|
export let data: SuperValidated<AccountFormSchema>;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<Form.Root
|
||||||
|
method="POST"
|
||||||
|
class="space-y-8"
|
||||||
|
let:config
|
||||||
|
schema={accountFormSchema}
|
||||||
|
form={data}
|
||||||
|
debug={true}
|
||||||
|
>
|
||||||
|
<Form.Item>
|
||||||
|
<Form.Field name="name" {config}>
|
||||||
|
<Form.Label>Name</Form.Label>
|
||||||
|
<Form.Input placeholder="Your name" />
|
||||||
|
<Form.Description>
|
||||||
|
This is the name that will be displayed on your profile and in emails.
|
||||||
|
</Form.Description>
|
||||||
|
<Form.Validation />
|
||||||
|
</Form.Field>
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item>
|
||||||
|
<Form.Field {config} name="language" let:attrs>
|
||||||
|
{@const { value } = attrs.input}
|
||||||
|
<Form.Label>Language</Form.Label>
|
||||||
|
<Form.Select selected={{ value, label: languages[value] }}>
|
||||||
|
<Form.SelectTrigger
|
||||||
|
placeholder="Select language"
|
||||||
|
class={cn(
|
||||||
|
"w-[200px] justify-between",
|
||||||
|
!attrs.input.value && "text-muted-foreground"
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
<Form.SelectContent class="h-52 overflow-y-auto">
|
||||||
|
{#each Object.entries(languages) as [value, lang]}
|
||||||
|
<Form.SelectItem {value}>
|
||||||
|
{lang}
|
||||||
|
</Form.SelectItem>
|
||||||
|
{/each}
|
||||||
|
</Form.SelectContent>
|
||||||
|
</Form.Select>
|
||||||
|
<Form.Description>
|
||||||
|
This is the language that will be used in the dashboard.
|
||||||
|
</Form.Description>
|
||||||
|
<Form.Validation />
|
||||||
|
</Form.Field>
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Button>Update account</Form.Button>
|
||||||
|
</Form.Root>
|
|
@ -0,0 +1,24 @@
|
||||||
|
import { superValidate } from "sveltekit-superforms/server";
|
||||||
|
import type { PageServerLoad } from "../$types";
|
||||||
|
import { appearanceFormSchema } from "./appearance-form.svelte";
|
||||||
|
import { fail, type Actions } from "@sveltejs/kit";
|
||||||
|
|
||||||
|
export const load: PageServerLoad = async () => {
|
||||||
|
return {
|
||||||
|
form: await superValidate(appearanceFormSchema)
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export const actions: Actions = {
|
||||||
|
default: async (event) => {
|
||||||
|
const form = await superValidate(event, appearanceFormSchema);
|
||||||
|
if (!form.valid) {
|
||||||
|
return fail(400, {
|
||||||
|
form
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
form
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
|
@ -0,0 +1,18 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { Separator } from "$lib/components/ui/separator";
|
||||||
|
import type { PageData } from "./$types";
|
||||||
|
import AppearanceForm from "./appearance-form.svelte";
|
||||||
|
|
||||||
|
export let data: PageData;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="space-y-6">
|
||||||
|
<div>
|
||||||
|
<h3 class="text-lg font-medium">Appearance</h3>
|
||||||
|
<p class="text-sm text-muted-foreground">
|
||||||
|
Customize the appearance of the app. Automatically switch between day and night themes.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<Separator />
|
||||||
|
<AppearanceForm data={data.form} />
|
||||||
|
</div>
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue