diff --git a/web/components.json b/web/components.json
index d5f55d3..93ec7a8 100644
--- a/web/components.json
+++ b/web/components.json
@@ -7,7 +7,7 @@
"aliases": {
"components": "$lib/components",
"utils": "$lib/utils",
- "ui": "$lib/components/ui",
+ "ui": "$lib/ui/core",
"hooks": "$lib/hooks",
"lib": "$lib"
},
diff --git a/web/package-lock.json b/web/package-lock.json
index 504f5b3..686e50e 100644
--- a/web/package-lock.json
+++ b/web/package-lock.json
@@ -18,22 +18,54 @@
},
"devDependencies": {
"@internationalized/date": "^3.12.0",
- "@lucide/svelte": "^1.7.0",
+ "@lucide/svelte": "^1.16.0",
"@sveltejs/adapter-static": "^3.0.10",
"@sveltejs/kit": "^2.50.2",
"@sveltejs/vite-plugin-svelte": "^6.2.4",
"@tailwindcss/vite": "^4.1.18",
"@types/node": "^22.15.0",
+ "formsnap": "^2.0.1",
"prettier": "^3.8.1",
"prettier-plugin-svelte": "^3.4.1",
"prettier-plugin-tailwindcss": "^0.7.2",
"svelte": "^5.54.0",
"svelte-check": "^4.4.2",
+ "sveltekit-superforms": "^2.30.1",
"tailwindcss": "^4.1.18",
"typescript": "^5.9.3",
"vite": "^7.3.1"
}
},
+ "node_modules/@ark/schema": {
+ "version": "0.56.0",
+ "resolved": "https://registry.npmjs.org/@ark/schema/-/schema-0.56.0.tgz",
+ "integrity": "sha512-ECg3hox/6Z/nLajxXqNhgPtNdHWC9zNsDyskwO28WinoFEnWow4IsERNz9AnXRhTZJnYIlAJ4uGn3nlLk65vZA==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "@ark/util": "0.56.0"
+ }
+ },
+ "node_modules/@ark/util": {
+ "version": "0.56.0",
+ "resolved": "https://registry.npmjs.org/@ark/util/-/util-0.56.0.tgz",
+ "integrity": "sha512-BghfRC8b9pNs3vBoDJhcta0/c1J1rsoS1+HgVUreMFPdhz/CRAKReAu57YEllNaSy98rWAdY1gE+gFup7OXpgA==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true
+ },
+ "node_modules/@babel/runtime": {
+ "version": "7.29.2",
+ "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.29.2.tgz",
+ "integrity": "sha512-JiDShH45zKHWyGe4ZNVRrCjBz8Nh9TMmZG1kh4QTK8hCBTWBi8Da+i7s1fJw7/lYpM4ccepSNfqzZ/QvABBi5g==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
"node_modules/@esbuild/aix-ppc64": {
"version": "0.27.7",
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.7.tgz",
@@ -450,6 +482,14 @@
"node": ">=18"
}
},
+ "node_modules/@exodus/schemasafe": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/@exodus/schemasafe/-/schemasafe-1.3.0.tgz",
+ "integrity": "sha512-5Aap/GaRupgNx/feGBwLLTVv8OQFfv3pq2lPRzPg9R+IOBnDgghTGW7l7EuVXOvg5cc/xSAlRW8rBrjIC3Nvqw==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true
+ },
"node_modules/@floating-ui/core": {
"version": "1.7.5",
"resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.7.5.tgz",
@@ -475,6 +515,25 @@
"integrity": "sha512-RiB/yIh78pcIxl6lLMG0CgBXAZ2Y0eVHqMPYugu+9U0AeT6YBeiJpf7lbdJNIugFP5SIjwNRgo4DhR1Qxi26Gg==",
"license": "MIT"
},
+ "node_modules/@hapi/hoek": {
+ "version": "9.3.0",
+ "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.3.0.tgz",
+ "integrity": "sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ==",
+ "dev": true,
+ "license": "BSD-3-Clause",
+ "optional": true
+ },
+ "node_modules/@hapi/topo": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/@hapi/topo/-/topo-5.1.0.tgz",
+ "integrity": "sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg==",
+ "dev": true,
+ "license": "BSD-3-Clause",
+ "optional": true,
+ "dependencies": {
+ "@hapi/hoek": "^9.0.0"
+ }
+ },
"node_modules/@internationalized/date": {
"version": "3.12.0",
"resolved": "https://registry.npmjs.org/@internationalized/date/-/date-3.12.0.tgz",
@@ -530,9 +589,9 @@
}
},
"node_modules/@lucide/svelte": {
- "version": "1.7.0",
- "resolved": "https://registry.npmjs.org/@lucide/svelte/-/svelte-1.7.0.tgz",
- "integrity": "sha512-YytBKOUBGox7yWcykZnYxOkn5WpR5G1qYXLYXV/j1B79SOTTEKzB+s5yF5Rq9l9OkweDStNH2b4yTqfvhEhV8g==",
+ "version": "1.16.0",
+ "resolved": "https://registry.npmjs.org/@lucide/svelte/-/svelte-1.16.0.tgz",
+ "integrity": "sha512-AvvPJnaWxeiNkAljI5MsSEc84yHPLMaWQIAJOcbX7k9au/f9ITS7cxTTQiautDiOFKVOXiYdZ+d6mtl88J+Kbg==",
"dev": true,
"license": "ISC",
"peerDependencies": {
@@ -546,6 +605,14 @@
"devOptional": true,
"license": "MIT"
},
+ "node_modules/@poppinss/macroable": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@poppinss/macroable/-/macroable-1.1.2.tgz",
+ "integrity": "sha512-FAVBRzzWhYP5mA3lCwLH1A0fKBqq5anyjGet90Z81aRK5c/+LTGUE1zJhZrErjaenBSOOI9BVUs3WVmotneFQA==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true
+ },
"node_modules/@rollup/rollup-android-arm-eabi": {
"version": "4.60.1",
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.60.1.tgz",
@@ -871,6 +938,33 @@
"win32"
]
},
+ "node_modules/@sideway/address": {
+ "version": "4.1.5",
+ "resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.5.tgz",
+ "integrity": "sha512-IqO/DUQHUkPeixNQ8n0JA6102hT9CmaljNTPmQ1u8MEhBo/R4Q8eKLN/vGZxuebwOroDB4cbpjheD4+/sKFK4Q==",
+ "dev": true,
+ "license": "BSD-3-Clause",
+ "optional": true,
+ "dependencies": {
+ "@hapi/hoek": "^9.0.0"
+ }
+ },
+ "node_modules/@sideway/formula": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/@sideway/formula/-/formula-3.0.1.tgz",
+ "integrity": "sha512-/poHZJJVjx3L+zVD6g9KgHfYnb443oi7wLu/XKojDviHy6HOEOA6z1Trk5aR1dGcmPenJEgb2sK2I80LeS3MIg==",
+ "dev": true,
+ "license": "BSD-3-Clause",
+ "optional": true
+ },
+ "node_modules/@sideway/pinpoint": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/@sideway/pinpoint/-/pinpoint-2.0.0.tgz",
+ "integrity": "sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==",
+ "dev": true,
+ "license": "BSD-3-Clause",
+ "optional": true
+ },
"node_modules/@standard-schema/spec": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz",
@@ -1301,6 +1395,49 @@
"integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==",
"license": "MIT"
},
+ "node_modules/@types/validator": {
+ "version": "13.15.10",
+ "resolved": "https://registry.npmjs.org/@types/validator/-/validator-13.15.10.tgz",
+ "integrity": "sha512-T8L6i7wCuyoK8A/ZeLYt1+q0ty3Zb9+qbSSvrIVitzT3YjZqkTZ40IbRsPanlB4h1QB3JVL1SYCdR6ngtFYcuA==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true
+ },
+ "node_modules/@typeschema/class-validator": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/@typeschema/class-validator/-/class-validator-0.3.0.tgz",
+ "integrity": "sha512-OJSFeZDIQ8EK1HTljKLT5CItM2wsbgczLN8tMEfz3I1Lmhc5TBfkZ0eikFzUC16tI3d1Nag7um6TfCgp2I2Bww==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "@typeschema/core": "0.14.0"
+ },
+ "peerDependencies": {
+ "class-validator": "^0.14.1"
+ },
+ "peerDependenciesMeta": {
+ "class-validator": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@typeschema/core": {
+ "version": "0.14.0",
+ "resolved": "https://registry.npmjs.org/@typeschema/core/-/core-0.14.0.tgz",
+ "integrity": "sha512-Ia6PtZHcL3KqsAWXjMi5xIyZ7XMH4aSnOQes8mfMLx+wGFGtGRNlwe6Y7cYvX+WfNK67OL0/HSe9t8QDygV0/w==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "peerDependencies": {
+ "@types/json-schema": "^7.0.15"
+ },
+ "peerDependenciesMeta": {
+ "@types/json-schema": {
+ "optional": true
+ }
+ }
+ },
"node_modules/@typescript-eslint/types": {
"version": "8.58.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.58.0.tgz",
@@ -1314,6 +1451,49 @@
"url": "https://opencollective.com/typescript-eslint"
}
},
+ "node_modules/@valibot/to-json-schema": {
+ "version": "1.7.0",
+ "resolved": "https://registry.npmjs.org/@valibot/to-json-schema/-/to-json-schema-1.7.0.tgz",
+ "integrity": "sha512-Y3pPVibbIOHzohrlxSINvO7w/bvXkoYS3BQHoImV9ynE+bXKf171bdMucPurV2zp7gdmt0L1HCcNAsbo7cFRQw==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "peerDependencies": {
+ "valibot": "^1.4.0"
+ }
+ },
+ "node_modules/@vinejs/compiler": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/@vinejs/compiler/-/compiler-3.0.0.tgz",
+ "integrity": "sha512-v9Lsv59nR56+bmy2p0+czjZxsLHwaibJ+SV5iK9JJfehlJMa501jUJQqqz4X/OqKXrxtE3uTQmSqjUqzF3B2mw==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "engines": {
+ "node": ">=18.0.0"
+ }
+ },
+ "node_modules/@vinejs/vine": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/@vinejs/vine/-/vine-3.0.1.tgz",
+ "integrity": "sha512-ZtvYkYpZOYdvbws3uaOAvTFuvFXoQGAtmzeiXu+XSMGxi5GVsODpoI9Xu9TplEMuD/5fmAtBbKb9cQHkWkLXDQ==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "@poppinss/macroable": "^1.0.4",
+ "@types/validator": "^13.12.2",
+ "@vinejs/compiler": "^3.0.0",
+ "camelcase": "^8.0.0",
+ "dayjs": "^1.11.13",
+ "dlv": "^1.1.3",
+ "normalize-url": "^8.0.1",
+ "validator": "^13.12.0"
+ },
+ "engines": {
+ "node": ">=18.16.0"
+ }
+ },
"node_modules/acorn": {
"version": "8.16.0",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz",
@@ -1335,6 +1515,30 @@
"node": ">= 0.4"
}
},
+ "node_modules/arkregex": {
+ "version": "0.0.5",
+ "resolved": "https://registry.npmjs.org/arkregex/-/arkregex-0.0.5.tgz",
+ "integrity": "sha512-ncYjBdLlh5/QnVsAA8De16Tc9EqmYM7y/WU9j+236KcyYNUXogpz3sC4ATIZYzzLxwI+0sEOaQLEmLmRleaEXw==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "@ark/util": "0.56.0"
+ }
+ },
+ "node_modules/arktype": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/arktype/-/arktype-2.2.0.tgz",
+ "integrity": "sha512-t54MZ7ti5BhOEvzEkgKnWvqj+UbDfWig+DHr5I34xatymPusKLS0lQpNJd8M6DzmIto2QGszHfNKoFIT8tMCZQ==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "@ark/schema": "0.56.0",
+ "@ark/util": "0.56.0",
+ "arkregex": "0.0.5"
+ }
+ },
"node_modules/axobject-query": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.1.0.tgz",
@@ -1368,6 +1572,20 @@
"svelte": "^5.33.0"
}
},
+ "node_modules/camelcase": {
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-8.0.0.tgz",
+ "integrity": "sha512-8WB3Jcas3swSvjIeA2yvCJ+Miyz5l1ZmB6HFb9R1317dt9LCQoswg/BGrmAmkWVEszSrrg4RwmO46qIm2OEnSA==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "engines": {
+ "node": ">=16"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/chokidar": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz",
@@ -1384,6 +1602,19 @@
"url": "https://paulmillr.com/funding/"
}
},
+ "node_modules/class-validator": {
+ "version": "0.14.4",
+ "resolved": "https://registry.npmjs.org/class-validator/-/class-validator-0.14.4.tgz",
+ "integrity": "sha512-AwNusCCam51q703dW82x95tOqQp6oC9HNUl724KxJJOfnKscI8dOloXFgyez7LbTTKWuRBA37FScqVbJEoq8Yw==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "@types/validator": "^13.15.3",
+ "libphonenumber-js": "^1.11.1",
+ "validator": "^13.15.22"
+ }
+ },
"node_modules/clsx": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz",
@@ -1403,6 +1634,14 @@
"node": ">= 0.6"
}
},
+ "node_modules/dayjs": {
+ "version": "1.11.20",
+ "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.20.tgz",
+ "integrity": "sha512-YbwwqR/uYpeoP4pu043q+LTDLFBLApUP6VxRihdfNTqu4ubqMlGDLd6ErXhEgsyvY0K6nCs7nggYumAN+9uEuQ==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true
+ },
"node_modules/deepmerge": {
"version": "4.3.1",
"resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz",
@@ -1438,6 +1677,26 @@
"integrity": "sha512-Gp6rDldRsFh/7XuouDbxMH3Mx8GMCcgzIb1pDTvNyn8pZGQ22u+Wa+lGV9dQCltFQ7uVw0MhRyb8XDskNFOReA==",
"license": "MIT"
},
+ "node_modules/dlv": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz",
+ "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true
+ },
+ "node_modules/effect": {
+ "version": "3.21.2",
+ "resolved": "https://registry.npmjs.org/effect/-/effect-3.21.2.tgz",
+ "integrity": "sha512-rXd2FGDM8KdjSIrc+mqEELo7ScW7xTVxEf1iInmPSpIde9/nyGuFM710cjTo7/EreGXiUX2MOonPpprbz2XHCg==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "@standard-schema/spec": "^1.0.0",
+ "fast-check": "^3.23.1"
+ }
+ },
"node_modules/enhanced-resolve": {
"version": "5.20.1",
"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.20.1.tgz",
@@ -1510,6 +1769,30 @@
"@typescript-eslint/types": "^8.2.0"
}
},
+ "node_modules/fast-check": {
+ "version": "3.23.2",
+ "resolved": "https://registry.npmjs.org/fast-check/-/fast-check-3.23.2.tgz",
+ "integrity": "sha512-h5+1OzzfCC3Ef7VbtKdcv7zsstUQwUDlYpUTvjeUsJAssPgLn7QzbboPtL5ro04Mq0rPOsMzl7q5hIbRs2wD1A==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "individual",
+ "url": "https://github.com/sponsors/dubzzz"
+ },
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/fast-check"
+ }
+ ],
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "pure-rand": "^6.1.0"
+ },
+ "engines": {
+ "node": ">=8.0.0"
+ }
+ },
"node_modules/fdir": {
"version": "6.5.0",
"resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz",
@@ -1528,6 +1811,47 @@
}
}
},
+ "node_modules/formsnap": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/formsnap/-/formsnap-2.0.1.tgz",
+ "integrity": "sha512-iJSe4YKd/W6WhLwKDVJU9FQeaJRpEFuolhju7ZXlRpUVyDdqFdMP8AUBICgnVvQPyP41IPAlBa/v0Eo35iE6wQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "svelte-toolbelt": "^0.5.0"
+ },
+ "engines": {
+ "node": ">=18",
+ "pnpm": ">=8.7.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/huntabyte"
+ },
+ "peerDependencies": {
+ "svelte": "^5.0.0",
+ "sveltekit-superforms": "^2.19.0"
+ }
+ },
+ "node_modules/formsnap/node_modules/svelte-toolbelt": {
+ "version": "0.5.0",
+ "resolved": "https://registry.npmjs.org/svelte-toolbelt/-/svelte-toolbelt-0.5.0.tgz",
+ "integrity": "sha512-t3tenZcnfQoIeRuQf/jBU7bvTeT3TGkcEE+1EUr5orp0lR7NEpprflpuie3x9Dn0W9nOKqs3HwKGJeeN5Ok1sQ==",
+ "dev": true,
+ "funding": [
+ "https://github.com/sponsors/huntabyte"
+ ],
+ "dependencies": {
+ "clsx": "^2.1.1",
+ "style-to-object": "^1.0.8"
+ },
+ "engines": {
+ "node": ">=18",
+ "pnpm": ">=8.7.0"
+ },
+ "peerDependencies": {
+ "svelte": "^5.0.0-next.126"
+ }
+ },
"node_modules/fsevents": {
"version": "2.3.3",
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
@@ -1574,6 +1898,36 @@
"jiti": "lib/jiti-cli.mjs"
}
},
+ "node_modules/joi": {
+ "version": "17.13.3",
+ "resolved": "https://registry.npmjs.org/joi/-/joi-17.13.3.tgz",
+ "integrity": "sha512-otDA4ldcIx+ZXsKHWmp0YizCweVRZG96J10b0FevjfuncLO1oX59THoAmHkNubYJ+9gWsYsp5k8v4ib6oDv1fA==",
+ "dev": true,
+ "license": "BSD-3-Clause",
+ "optional": true,
+ "dependencies": {
+ "@hapi/hoek": "^9.3.0",
+ "@hapi/topo": "^5.1.0",
+ "@sideway/address": "^4.1.5",
+ "@sideway/formula": "^3.0.1",
+ "@sideway/pinpoint": "^2.0.0"
+ }
+ },
+ "node_modules/json-schema-to-ts": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/json-schema-to-ts/-/json-schema-to-ts-3.1.1.tgz",
+ "integrity": "sha512-+DWg8jCJG2TEnpy7kOm/7/AxaYoaRbjVB4LFZLySZlWn8exGs3A4OLJR966cVvU26N7X9TWxl+Jsw7dzAqKT6g==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "@babel/runtime": "^7.18.3",
+ "ts-algebra": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=16"
+ }
+ },
"node_modules/kleur": {
"version": "4.1.5",
"resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz",
@@ -1584,6 +1938,14 @@
"node": ">=6"
}
},
+ "node_modules/libphonenumber-js": {
+ "version": "1.13.2",
+ "resolved": "https://registry.npmjs.org/libphonenumber-js/-/libphonenumber-js-1.13.2.tgz",
+ "integrity": "sha512-S3kmBrptp3yRTm83NUcHy9g1vbwiWMzI8WvY22+koBJ6zkRteLnedBL2VX0MIAGwx2yiyxX4J85pceZyQ6ffgg==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true
+ },
"node_modules/lightningcss": {
"version": "1.32.0",
"resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.32.0.tgz",
@@ -1858,6 +2220,13 @@
"@jridgewell/sourcemap-codec": "^1.5.5"
}
},
+ "node_modules/memoize-weak": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/memoize-weak/-/memoize-weak-1.0.2.tgz",
+ "integrity": "sha512-gj39xkrjEw7nCn4nJ1M5ms6+MyMlyiGmttzsqAUsAKn6bYKwuTHh/AO3cKPF8IBrTIYTxb0wWXFs3E//Y8VoWQ==",
+ "dev": true,
+ "license": "ISC"
+ },
"node_modules/mri": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/mri/-/mri-1.2.0.tgz",
@@ -1897,6 +2266,20 @@
"node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
}
},
+ "node_modules/normalize-url": {
+ "version": "8.1.1",
+ "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-8.1.1.tgz",
+ "integrity": "sha512-JYc0DPlpGWB40kH5g07gGTrYuMqV653k3uBKY6uITPWds3M0ov3GaWGp9lbE3Bzngx8+XkfzgvASb9vk9JDFXQ==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "engines": {
+ "node": ">=14.16"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/obug": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/obug/-/obug-2.1.1.tgz",
@@ -2063,6 +2446,32 @@
}
}
},
+ "node_modules/property-expr": {
+ "version": "2.0.6",
+ "resolved": "https://registry.npmjs.org/property-expr/-/property-expr-2.0.6.tgz",
+ "integrity": "sha512-SVtmxhRE/CGkn3eZY1T6pC8Nln6Fr/lu1mKSgRud0eC73whjGfoAogbn78LkD8aFL0zz3bAFerKSnOl7NlErBA==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true
+ },
+ "node_modules/pure-rand": {
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.1.0.tgz",
+ "integrity": "sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "individual",
+ "url": "https://github.com/sponsors/dubzzz"
+ },
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/fast-check"
+ }
+ ],
+ "license": "MIT",
+ "optional": true
+ },
"node_modules/readdirp": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz",
@@ -2200,6 +2609,17 @@
"inline-style-parser": "0.2.7"
}
},
+ "node_modules/superstruct": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/superstruct/-/superstruct-2.0.2.tgz",
+ "integrity": "sha512-uV+TFRZdXsqXTL2pRvujROjdZQ4RAlBUS5BTh9IGm+jTqQntYThciG/qu57Gs69yjnVUSqdxF9YLmSnpupBW9A==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "engines": {
+ "node": ">=14.0.0"
+ }
+ },
"node_modules/svelte": {
"version": "5.55.1",
"resolved": "https://registry.npmjs.org/svelte/-/svelte-5.55.1.tgz",
@@ -2299,6 +2719,104 @@
"svelte": "^5.30.2"
}
},
+ "node_modules/sveltekit-superforms": {
+ "version": "2.30.1",
+ "resolved": "https://registry.npmjs.org/sveltekit-superforms/-/sveltekit-superforms-2.30.1.tgz",
+ "integrity": "sha512-wBzyqsE0idvEJWuNJ+HCiAtdxa7Z55GZ8jmtlVHJfonrk9bRYC49MoPaloYyFoYuU3QPy6Omna/Qzn1kaIkgew==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ciscoheat"
+ },
+ {
+ "type": "ko-fi",
+ "url": "https://ko-fi.com/ciscoheat"
+ },
+ {
+ "type": "paypal",
+ "url": "https://www.paypal.com/donate/?hosted_button_id=NY7F5ALHHSVQS"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "devalue": "^5.6.4",
+ "memoize-weak": "^1.0.2",
+ "ts-deepmerge": "^7.0.3"
+ },
+ "optionalDependencies": {
+ "@exodus/schemasafe": "^1.3.0",
+ "@standard-schema/spec": "^1.1.0",
+ "@typeschema/class-validator": "^0.3.0",
+ "@valibot/to-json-schema": "^1.6.0",
+ "@vinejs/vine": "^3.0.1",
+ "arktype": "^2.2.0",
+ "class-validator": "^0.14.4",
+ "effect": "^3.21.0",
+ "joi": "^17.13.3",
+ "json-schema-to-ts": "^3.1.1",
+ "superstruct": "^2.0.2",
+ "typebox": "^1.1.6",
+ "valibot": "^1.3.1",
+ "yup": "^1.7.1",
+ "zod": "^4.3.6",
+ "zod-v3-to-json-schema": "^4.0.0"
+ },
+ "peerDependencies": {
+ "@exodus/schemasafe": "^1.3.0",
+ "@sveltejs/kit": "1.x || 2.x",
+ "@typeschema/class-validator": "^0.3.0",
+ "@vinejs/vine": "^1.8.0 || ^2.0.0 || ^3.0.0",
+ "arktype": ">=2.0.0-rc.23",
+ "class-validator": "^0.14.1",
+ "effect": "^3.21.0",
+ "joi": "^17.13.1",
+ "superstruct": "^2.0.2",
+ "svelte": "3.x || 4.x || >=5.0.0-next.51",
+ "typebox": "^1.0.36",
+ "valibot": "^1.2.0",
+ "yup": "^1.4.0",
+ "zod": "^3.25.0 || ^4.0.0"
+ },
+ "peerDependenciesMeta": {
+ "@exodus/schemasafe": {
+ "optional": true
+ },
+ "@typeschema/class-validator": {
+ "optional": true
+ },
+ "@vinejs/vine": {
+ "optional": true
+ },
+ "arktype": {
+ "optional": true
+ },
+ "class-validator": {
+ "optional": true
+ },
+ "effect": {
+ "optional": true
+ },
+ "joi": {
+ "optional": true
+ },
+ "superstruct": {
+ "optional": true
+ },
+ "typebox": {
+ "optional": true
+ },
+ "valibot": {
+ "optional": true
+ },
+ "yup": {
+ "optional": true
+ },
+ "zod": {
+ "optional": true
+ }
+ }
+ },
"node_modules/tabbable": {
"version": "6.4.0",
"resolved": "https://registry.npmjs.org/tabbable/-/tabbable-6.4.0.tgz",
@@ -2354,6 +2872,14 @@
"url": "https://opencollective.com/webpack"
}
},
+ "node_modules/tiny-case": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/tiny-case/-/tiny-case-1.0.3.tgz",
+ "integrity": "sha512-Eet/eeMhkO6TX8mnUteS9zgPbUMQa4I6Kkp5ORiBD5476/m+PIRiumP5tmh5ioJpH7k51Kehawy2UDfsnxxY8Q==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true
+ },
"node_modules/tinyglobby": {
"version": "0.2.15",
"resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz",
@@ -2371,6 +2897,14 @@
"url": "https://github.com/sponsors/SuperchupuDev"
}
},
+ "node_modules/toposort": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/toposort/-/toposort-2.0.2.tgz",
+ "integrity": "sha512-0a5EOkAUp8D4moMi2W8ZF8jcga7BgZd91O/yabJCFY8az+XSzeGyTKs0Aoo897iV1Nj6guFq8orWDS96z91oGg==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true
+ },
"node_modules/totalist": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/totalist/-/totalist-3.0.1.tgz",
@@ -2381,6 +2915,24 @@
"node": ">=6"
}
},
+ "node_modules/ts-algebra": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ts-algebra/-/ts-algebra-2.0.0.tgz",
+ "integrity": "sha512-FPAhNPFMrkwz76P7cdjdmiShwMynZYN6SgOujD1urY4oNm80Ou9oMdmbR45LotcKOXoy7wSmHkRFE6Mxbrhefw==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true
+ },
+ "node_modules/ts-deepmerge": {
+ "version": "7.0.3",
+ "resolved": "https://registry.npmjs.org/ts-deepmerge/-/ts-deepmerge-7.0.3.tgz",
+ "integrity": "sha512-Du/ZW2RfwV/D4cmA5rXafYjBQVuvu4qGiEEla4EmEHVHgRdx68Gftx7i66jn2bzHPwSVZY36Ae6OuDn9el4ZKA==",
+ "dev": true,
+ "license": "ISC",
+ "engines": {
+ "node": ">=14.13.1"
+ }
+ },
"node_modules/tslib": {
"version": "2.8.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
@@ -2396,6 +2948,28 @@
"url": "https://github.com/sponsors/Wombosvideo"
}
},
+ "node_modules/type-fest": {
+ "version": "2.19.0",
+ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz",
+ "integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==",
+ "dev": true,
+ "license": "(MIT OR CC0-1.0)",
+ "optional": true,
+ "engines": {
+ "node": ">=12.20"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/typebox": {
+ "version": "1.1.38",
+ "resolved": "https://registry.npmjs.org/typebox/-/typebox-1.1.38.tgz",
+ "integrity": "sha512-pZ0aQPmMmXoUvSbeuWf/Hzsc+avNw/Zd6VeE8CFgkVGWyuHPJvqeJJDeJqLve+K70LvjYIoleGcoJHPT17cWoA==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true
+ },
"node_modules/typescript": {
"version": "5.9.3",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz",
@@ -2417,6 +2991,33 @@
"devOptional": true,
"license": "MIT"
},
+ "node_modules/valibot": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/valibot/-/valibot-1.4.0.tgz",
+ "integrity": "sha512-iC/x7fVcSyOwlm/VSt7RlHnzNGLGvR9GnxdifUeWoCJo0q4ZZvrVkIHC6faTlkxG47I2Y4UrFquPuVHCrOnrLg==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "peerDependencies": {
+ "typescript": ">=5"
+ },
+ "peerDependenciesMeta": {
+ "typescript": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/validator": {
+ "version": "13.15.35",
+ "resolved": "https://registry.npmjs.org/validator/-/validator-13.15.35.tgz",
+ "integrity": "sha512-TQ5pAGhd5whStmqWvYF4OjQROlmv9SMFVt37qoCBdqRffuuklWYQlCNnEs2ZaIBD1kZRNnikiZOS1eqgkar0iw==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "engines": {
+ "node": ">= 0.10"
+ }
+ },
"node_modules/vite": {
"version": "7.3.1",
"resolved": "https://registry.npmjs.org/vite/-/vite-7.3.1.tgz",
@@ -2512,11 +3113,47 @@
}
}
},
+ "node_modules/yup": {
+ "version": "1.7.1",
+ "resolved": "https://registry.npmjs.org/yup/-/yup-1.7.1.tgz",
+ "integrity": "sha512-GKHFX2nXul2/4Dtfxhozv701jLQHdf6J34YDh2cEkpqoo8le5Mg6/LrdseVLrFarmFygZTlfIhHx/QKfb/QWXw==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "property-expr": "^2.0.5",
+ "tiny-case": "^1.0.3",
+ "toposort": "^2.0.2",
+ "type-fest": "^2.19.0"
+ }
+ },
"node_modules/zimmerframe": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/zimmerframe/-/zimmerframe-1.1.4.tgz",
"integrity": "sha512-B58NGBEoc8Y9MWWCQGl/gq9xBCe4IiKM0a2x7GZdQKOW5Exr8S1W24J6OgM1njK8xCRGvAJIL/MxXHf6SkmQKQ==",
"license": "MIT"
+ },
+ "node_modules/zod": {
+ "version": "4.4.3",
+ "resolved": "https://registry.npmjs.org/zod/-/zod-4.4.3.tgz",
+ "integrity": "sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "funding": {
+ "url": "https://github.com/sponsors/colinhacks"
+ }
+ },
+ "node_modules/zod-v3-to-json-schema": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/zod-v3-to-json-schema/-/zod-v3-to-json-schema-4.0.0.tgz",
+ "integrity": "sha512-KixLrhX/uPmRFnDgsZrzrk4x5SSJA+PmaE5adbfID9+3KPJcdxqRobaHU397EfWBqfQircrjKqvEqZ/mW5QH6w==",
+ "dev": true,
+ "license": "ISC",
+ "optional": true,
+ "peerDependencies": {
+ "zod": "^3.25 || ^4.0.14"
+ }
}
}
}
diff --git a/web/package.json b/web/package.json
index b8945a2..a1c12c9 100644
--- a/web/package.json
+++ b/web/package.json
@@ -15,17 +15,19 @@
},
"devDependencies": {
"@internationalized/date": "^3.12.0",
- "@lucide/svelte": "^1.7.0",
+ "@lucide/svelte": "^1.16.0",
"@sveltejs/adapter-static": "^3.0.10",
"@sveltejs/kit": "^2.50.2",
"@sveltejs/vite-plugin-svelte": "^6.2.4",
"@tailwindcss/vite": "^4.1.18",
"@types/node": "^22.15.0",
+ "formsnap": "^2.0.1",
"prettier": "^3.8.1",
"prettier-plugin-svelte": "^3.4.1",
"prettier-plugin-tailwindcss": "^0.7.2",
"svelte": "^5.54.0",
"svelte-check": "^4.4.2",
+ "sveltekit-superforms": "^2.30.1",
"tailwindcss": "^4.1.18",
"typescript": "^5.9.3",
"vite": "^7.3.1"
diff --git a/web/src/lib/AppShell.svelte b/web/src/lib/AppShell.svelte
index 0053f08..d49f066 100644
--- a/web/src/lib/AppShell.svelte
+++ b/web/src/lib/AppShell.svelte
@@ -2,8 +2,7 @@
import { resolve } from '$app/paths';
import { page } from '$app/state';
import { cn } from '$lib/utils.js';
- import { Button } from '$lib/components/ui/button/index.js';
- import { buttonVariants } from '$lib/components/ui/button/button.svelte';
+ import { Button, buttonVariants } from '$lib/components/ui/button/index.js';
import {
DropdownMenu,
DropdownMenuContent,
diff --git a/web/src/lib/components/ui/alert-dialog/index.ts b/web/src/lib/components/ui/alert-dialog/index.ts
index ca81c2a..18f963c 100644
--- a/web/src/lib/components/ui/alert-dialog/index.ts
+++ b/web/src/lib/components/ui/alert-dialog/index.ts
@@ -1,40 +1 @@
-import Root from "./alert-dialog.svelte";
-import Portal from "./alert-dialog-portal.svelte";
-import Trigger from "./alert-dialog-trigger.svelte";
-import Title from "./alert-dialog-title.svelte";
-import Action from "./alert-dialog-action.svelte";
-import Cancel from "./alert-dialog-cancel.svelte";
-import Footer from "./alert-dialog-footer.svelte";
-import Header from "./alert-dialog-header.svelte";
-import Overlay from "./alert-dialog-overlay.svelte";
-import Content from "./alert-dialog-content.svelte";
-import Description from "./alert-dialog-description.svelte";
-import Media from "./alert-dialog-media.svelte";
-
-export {
- Root,
- Title,
- Action,
- Cancel,
- Portal,
- Footer,
- Header,
- Trigger,
- Overlay,
- Content,
- Description,
- Media,
- //
- Root as AlertDialog,
- Title as AlertDialogTitle,
- Action as AlertDialogAction,
- Cancel as AlertDialogCancel,
- Portal as AlertDialogPortal,
- Footer as AlertDialogFooter,
- Header as AlertDialogHeader,
- Trigger as AlertDialogTrigger,
- Overlay as AlertDialogOverlay,
- Content as AlertDialogContent,
- Description as AlertDialogDescription,
- Media as AlertDialogMedia,
-};
+export * from '$lib/ui/core/alert-dialog/index.js';
diff --git a/web/src/lib/components/ui/alert/index.ts b/web/src/lib/components/ui/alert/index.ts
index 071b113..099653e 100644
--- a/web/src/lib/components/ui/alert/index.ts
+++ b/web/src/lib/components/ui/alert/index.ts
@@ -1,17 +1 @@
-import Root from "./alert.svelte";
-import Description from "./alert-description.svelte";
-import Title from "./alert-title.svelte";
-import Action from "./alert-action.svelte";
-export { alertVariants, type AlertVariant } from "./alert.svelte";
-
-export {
- Root,
- Description,
- Title,
- Action,
- //
- Root as Alert,
- Description as AlertDescription,
- Title as AlertTitle,
- Action as AlertAction,
-};
+export * from '$lib/ui/core/alert/index.js';
diff --git a/web/src/lib/components/ui/badge/index.ts b/web/src/lib/components/ui/badge/index.ts
index 64e0aa9..a274438 100644
--- a/web/src/lib/components/ui/badge/index.ts
+++ b/web/src/lib/components/ui/badge/index.ts
@@ -1,2 +1 @@
-export { default as Badge } from "./badge.svelte";
-export { badgeVariants, type BadgeVariant } from "./badge.svelte";
+export * from '$lib/ui/core/badge/index.js';
diff --git a/web/src/lib/components/ui/button/index.ts b/web/src/lib/components/ui/button/index.ts
index fb585d7..06ff5d3 100644
--- a/web/src/lib/components/ui/button/index.ts
+++ b/web/src/lib/components/ui/button/index.ts
@@ -1,17 +1 @@
-import Root, {
- type ButtonProps,
- type ButtonSize,
- type ButtonVariant,
- buttonVariants,
-} from "./button.svelte";
-
-export {
- Root,
- type ButtonProps as Props,
- //
- Root as Button,
- buttonVariants,
- type ButtonProps,
- type ButtonSize,
- type ButtonVariant,
-};
+export * from '$lib/ui/core/button/index.js';
diff --git a/web/src/lib/components/ui/card/index.ts b/web/src/lib/components/ui/card/index.ts
index 4d3fce4..7ddc276 100644
--- a/web/src/lib/components/ui/card/index.ts
+++ b/web/src/lib/components/ui/card/index.ts
@@ -1,25 +1 @@
-import Root from "./card.svelte";
-import Content from "./card-content.svelte";
-import Description from "./card-description.svelte";
-import Footer from "./card-footer.svelte";
-import Header from "./card-header.svelte";
-import Title from "./card-title.svelte";
-import Action from "./card-action.svelte";
-
-export {
- Root,
- Content,
- Description,
- Footer,
- Header,
- Title,
- Action,
- //
- Root as Card,
- Content as CardContent,
- Description as CardDescription,
- Footer as CardFooter,
- Header as CardHeader,
- Title as CardTitle,
- Action as CardAction,
-};
+export * from '$lib/ui/core/card/index.js';
diff --git a/web/src/lib/components/ui/checkbox/index.ts b/web/src/lib/components/ui/checkbox/index.ts
new file mode 100644
index 0000000..c89e035
--- /dev/null
+++ b/web/src/lib/components/ui/checkbox/index.ts
@@ -0,0 +1 @@
+export * from '$lib/ui/core/checkbox/index.js';
diff --git a/web/src/lib/components/ui/data-table/index.ts b/web/src/lib/components/ui/data-table/index.ts
index 5f4e77e..12c5fb1 100644
--- a/web/src/lib/components/ui/data-table/index.ts
+++ b/web/src/lib/components/ui/data-table/index.ts
@@ -1,3 +1 @@
-export { default as FlexRender } from "./flex-render.svelte";
-export { renderComponent, renderSnippet } from "./render-helpers.js";
-export { createSvelteTable } from "./data-table.svelte.js";
+export * from '$lib/ui/core/data-table/index.js';
diff --git a/web/src/lib/components/ui/dialog/index.ts b/web/src/lib/components/ui/dialog/index.ts
index 076cef5..767e160 100644
--- a/web/src/lib/components/ui/dialog/index.ts
+++ b/web/src/lib/components/ui/dialog/index.ts
@@ -1,34 +1 @@
-import Root from "./dialog.svelte";
-import Portal from "./dialog-portal.svelte";
-import Title from "./dialog-title.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";
-import Trigger from "./dialog-trigger.svelte";
-import Close from "./dialog-close.svelte";
-
-export {
- Root,
- Title,
- Portal,
- Footer,
- Header,
- Trigger,
- Overlay,
- Content,
- Description,
- Close,
- //
- 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,
- Close as DialogClose,
-};
+export * from '$lib/ui/core/dialog/index.js';
diff --git a/web/src/lib/components/ui/dropdown-menu/index.ts b/web/src/lib/components/ui/dropdown-menu/index.ts
index 7850c6a..c6bae74 100644
--- a/web/src/lib/components/ui/dropdown-menu/index.ts
+++ b/web/src/lib/components/ui/dropdown-menu/index.ts
@@ -1,54 +1 @@
-import Root from "./dropdown-menu.svelte";
-import Sub from "./dropdown-menu-sub.svelte";
-import CheckboxGroup from "./dropdown-menu-checkbox-group.svelte";
-import CheckboxItem from "./dropdown-menu-checkbox-item.svelte";
-import Content from "./dropdown-menu-content.svelte";
-import Group from "./dropdown-menu-group.svelte";
-import Item from "./dropdown-menu-item.svelte";
-import Label from "./dropdown-menu-label.svelte";
-import RadioGroup from "./dropdown-menu-radio-group.svelte";
-import RadioItem from "./dropdown-menu-radio-item.svelte";
-import Separator from "./dropdown-menu-separator.svelte";
-import Shortcut from "./dropdown-menu-shortcut.svelte";
-import Trigger from "./dropdown-menu-trigger.svelte";
-import SubContent from "./dropdown-menu-sub-content.svelte";
-import SubTrigger from "./dropdown-menu-sub-trigger.svelte";
-import GroupHeading from "./dropdown-menu-group-heading.svelte";
-import Portal from "./dropdown-menu-portal.svelte";
-
-export {
- CheckboxGroup,
- CheckboxItem,
- Content,
- Portal,
- Root as DropdownMenu,
- CheckboxGroup as DropdownMenuCheckboxGroup,
- CheckboxItem as DropdownMenuCheckboxItem,
- Content as DropdownMenuContent,
- Portal as DropdownMenuPortal,
- Group as DropdownMenuGroup,
- Item as DropdownMenuItem,
- Label as DropdownMenuLabel,
- RadioGroup as DropdownMenuRadioGroup,
- RadioItem as DropdownMenuRadioItem,
- Separator as DropdownMenuSeparator,
- Shortcut as DropdownMenuShortcut,
- Sub as DropdownMenuSub,
- SubContent as DropdownMenuSubContent,
- SubTrigger as DropdownMenuSubTrigger,
- Trigger as DropdownMenuTrigger,
- GroupHeading as DropdownMenuGroupHeading,
- Group,
- GroupHeading,
- Item,
- Label,
- RadioGroup,
- RadioItem,
- Root,
- Separator,
- Shortcut,
- Sub,
- SubContent,
- SubTrigger,
- Trigger,
-};
+export * from '$lib/ui/core/dropdown-menu/index.js';
diff --git a/web/src/lib/components/ui/form/index.ts b/web/src/lib/components/ui/form/index.ts
new file mode 100644
index 0000000..bf35b9b
--- /dev/null
+++ b/web/src/lib/components/ui/form/index.ts
@@ -0,0 +1 @@
+export * from '$lib/ui/core/form/index.js';
diff --git a/web/src/lib/components/ui/input/index.ts b/web/src/lib/components/ui/input/index.ts
index f47b6d3..d660ada 100644
--- a/web/src/lib/components/ui/input/index.ts
+++ b/web/src/lib/components/ui/input/index.ts
@@ -1,7 +1 @@
-import Root from "./input.svelte";
-
-export {
- Root,
- //
- Root as Input,
-};
+export * from '$lib/ui/core/input/index.js';
diff --git a/web/src/lib/components/ui/label/index.ts b/web/src/lib/components/ui/label/index.ts
index 8bfca0b..729cf3b 100644
--- a/web/src/lib/components/ui/label/index.ts
+++ b/web/src/lib/components/ui/label/index.ts
@@ -1,7 +1 @@
-import Root from "./label.svelte";
-
-export {
- Root,
- //
- Root as Label,
-};
+export * from '$lib/ui/core/label/index.js';
diff --git a/web/src/lib/components/ui/popover/index.ts b/web/src/lib/components/ui/popover/index.ts
index 5f18036..857995c 100644
--- a/web/src/lib/components/ui/popover/index.ts
+++ b/web/src/lib/components/ui/popover/index.ts
@@ -1,28 +1 @@
-import Root from "./popover.svelte";
-import Close from "./popover-close.svelte";
-import Content from "./popover-content.svelte";
-import Description from "./popover-description.svelte";
-import Header from "./popover-header.svelte";
-import Title from "./popover-title.svelte";
-import Trigger from "./popover-trigger.svelte";
-import Portal from "./popover-portal.svelte";
-
-export {
- Root,
- Content,
- Description,
- Header,
- Title,
- Trigger,
- Close,
- Portal,
- //
- Root as Popover,
- Content as PopoverContent,
- Description as PopoverDescription,
- Header as PopoverHeader,
- Title as PopoverTitle,
- Trigger as PopoverTrigger,
- Close as PopoverClose,
- Portal as PopoverPortal,
-};
+export * from '$lib/ui/core/popover/index.js';
diff --git a/web/src/lib/components/ui/scroll-area/index.ts b/web/src/lib/components/ui/scroll-area/index.ts
index e86a25b..4f5f5a7 100644
--- a/web/src/lib/components/ui/scroll-area/index.ts
+++ b/web/src/lib/components/ui/scroll-area/index.ts
@@ -1,10 +1 @@
-import Scrollbar from "./scroll-area-scrollbar.svelte";
-import Root from "./scroll-area.svelte";
-
-export {
- Root,
- Scrollbar,
- //,
- Root as ScrollArea,
- Scrollbar as ScrollAreaScrollbar,
-};
+export * from '$lib/ui/core/scroll-area/index.js';
diff --git a/web/src/lib/components/ui/select/index.ts b/web/src/lib/components/ui/select/index.ts
index 4dec358..a428280 100644
--- a/web/src/lib/components/ui/select/index.ts
+++ b/web/src/lib/components/ui/select/index.ts
@@ -1,37 +1 @@
-import Root from "./select.svelte";
-import Group from "./select-group.svelte";
-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";
-import ScrollDownButton from "./select-scroll-down-button.svelte";
-import ScrollUpButton from "./select-scroll-up-button.svelte";
-import GroupHeading from "./select-group-heading.svelte";
-import Portal from "./select-portal.svelte";
-
-export {
- Root,
- Group,
- Label,
- Item,
- Content,
- Trigger,
- Separator,
- ScrollDownButton,
- ScrollUpButton,
- GroupHeading,
- Portal,
- //
- Root as Select,
- Group as SelectGroup,
- Label as SelectLabel,
- Item as SelectItem,
- Content as SelectContent,
- Trigger as SelectTrigger,
- Separator as SelectSeparator,
- ScrollDownButton as SelectScrollDownButton,
- ScrollUpButton as SelectScrollUpButton,
- GroupHeading as SelectGroupHeading,
- Portal as SelectPortal,
-};
+export * from '$lib/ui/core/select/index.js';
diff --git a/web/src/lib/components/ui/separator/index.ts b/web/src/lib/components/ui/separator/index.ts
index 82442d2..e7333ee 100644
--- a/web/src/lib/components/ui/separator/index.ts
+++ b/web/src/lib/components/ui/separator/index.ts
@@ -1,7 +1 @@
-import Root from "./separator.svelte";
-
-export {
- Root,
- //
- Root as Separator,
-};
+export * from '$lib/ui/core/separator/index.js';
diff --git a/web/src/lib/components/ui/sheet/index.ts b/web/src/lib/components/ui/sheet/index.ts
new file mode 100644
index 0000000..e23e688
--- /dev/null
+++ b/web/src/lib/components/ui/sheet/index.ts
@@ -0,0 +1 @@
+export * from '$lib/ui/core/sheet/index.js';
diff --git a/web/src/lib/components/ui/skeleton/index.ts b/web/src/lib/components/ui/skeleton/index.ts
new file mode 100644
index 0000000..d05becd
--- /dev/null
+++ b/web/src/lib/components/ui/skeleton/index.ts
@@ -0,0 +1 @@
+export * from '$lib/ui/core/skeleton/index.js';
diff --git a/web/src/lib/components/ui/switch/index.ts b/web/src/lib/components/ui/switch/index.ts
index f5533db..8d48016 100644
--- a/web/src/lib/components/ui/switch/index.ts
+++ b/web/src/lib/components/ui/switch/index.ts
@@ -1,7 +1 @@
-import Root from "./switch.svelte";
-
-export {
- Root,
- //
- Root as Switch,
-};
+export * from '$lib/ui/core/switch/index.js';
diff --git a/web/src/lib/components/ui/table/index.ts b/web/src/lib/components/ui/table/index.ts
index 14695c8..71ac428 100644
--- a/web/src/lib/components/ui/table/index.ts
+++ b/web/src/lib/components/ui/table/index.ts
@@ -1,28 +1 @@
-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,
-};
+export * from '$lib/ui/core/table/index.js';
diff --git a/web/src/lib/components/ui/tabs/index.ts b/web/src/lib/components/ui/tabs/index.ts
index 31267e5..c26ef99 100644
--- a/web/src/lib/components/ui/tabs/index.ts
+++ b/web/src/lib/components/ui/tabs/index.ts
@@ -1,18 +1 @@
-import Root from "./tabs.svelte";
-import Content from "./tabs-content.svelte";
-import List, { tabsListVariants, type TabsListVariant } from "./tabs-list.svelte";
-import Trigger from "./tabs-trigger.svelte";
-
-export {
- Root,
- Content,
- List,
- Trigger,
- tabsListVariants,
- type TabsListVariant,
- //
- Root as Tabs,
- Content as TabsContent,
- List as TabsList,
- Trigger as TabsTrigger,
-};
+export * from '$lib/ui/core/tabs/index.js';
diff --git a/web/src/lib/components/ui/textarea/index.ts b/web/src/lib/components/ui/textarea/index.ts
index ace797a..3ece123 100644
--- a/web/src/lib/components/ui/textarea/index.ts
+++ b/web/src/lib/components/ui/textarea/index.ts
@@ -1,7 +1 @@
-import Root from "./textarea.svelte";
-
-export {
- Root,
- //
- Root as Textarea,
-};
+export * from '$lib/ui/core/textarea/index.js';
diff --git a/web/src/lib/components/ui/tooltip/index.ts b/web/src/lib/components/ui/tooltip/index.ts
index 1718604..e6a87c4 100644
--- a/web/src/lib/components/ui/tooltip/index.ts
+++ b/web/src/lib/components/ui/tooltip/index.ts
@@ -1,19 +1 @@
-import Root from "./tooltip.svelte";
-import Trigger from "./tooltip-trigger.svelte";
-import Content from "./tooltip-content.svelte";
-import Provider from "./tooltip-provider.svelte";
-import Portal from "./tooltip-portal.svelte";
-
-export {
- Root,
- Trigger,
- Content,
- Provider,
- Portal,
- //
- Root as Tooltip,
- Content as TooltipContent,
- Trigger as TooltipTrigger,
- Provider as TooltipProvider,
- Portal as TooltipPortal,
-};
+export * from '$lib/ui/core/tooltip/index.js';
diff --git a/web/src/lib/ui/app/toast.ts b/web/src/lib/ui/app/toast.ts
new file mode 100644
index 0000000..bab5cfc
--- /dev/null
+++ b/web/src/lib/ui/app/toast.ts
@@ -0,0 +1,20 @@
+import { toast } from 'svelte-sonner';
+
+export const notify = {
+ success: (message: string, description?: string) =>
+ toast.success(message, description ? { description } : undefined),
+ error: (message: string, description?: string) =>
+ toast.error(message, description ? { description } : undefined),
+ info: (message: string, description?: string) =>
+ toast.info(message, description ? { description } : undefined),
+ warning: (message: string, description?: string) =>
+ toast.warning(message, description ? { description } : undefined),
+ promise: toast.promise,
+ dismiss: toast.dismiss,
+ message: toast.message
+};
+
+export function notifyApiError(e: unknown, fallback = 'Ошибка запроса') {
+ const message = e instanceof Error ? e.message : String(e);
+ notify.error(message || fallback);
+}
diff --git a/web/src/lib/components/ui/alert-dialog/alert-dialog-action.svelte b/web/src/lib/ui/core/alert-dialog/alert-dialog-action.svelte
similarity index 92%
rename from web/src/lib/components/ui/alert-dialog/alert-dialog-action.svelte
rename to web/src/lib/ui/core/alert-dialog/alert-dialog-action.svelte
index 7e63004..60cb405 100644
--- a/web/src/lib/components/ui/alert-dialog/alert-dialog-action.svelte
+++ b/web/src/lib/ui/core/alert-dialog/alert-dialog-action.svelte
@@ -4,7 +4,7 @@
buttonVariants,
type ButtonVariant,
type ButtonSize,
- } from "$lib/components/ui/button/index.js";
+ } from "$lib/ui/core/button/index.js";
import { cn } from "$lib/utils.js";
let {
diff --git a/web/src/lib/components/ui/alert-dialog/alert-dialog-cancel.svelte b/web/src/lib/ui/core/alert-dialog/alert-dialog-cancel.svelte
similarity index 92%
rename from web/src/lib/components/ui/alert-dialog/alert-dialog-cancel.svelte
rename to web/src/lib/ui/core/alert-dialog/alert-dialog-cancel.svelte
index a4ce03c..5f5a293 100644
--- a/web/src/lib/components/ui/alert-dialog/alert-dialog-cancel.svelte
+++ b/web/src/lib/ui/core/alert-dialog/alert-dialog-cancel.svelte
@@ -4,7 +4,7 @@
buttonVariants,
type ButtonVariant,
type ButtonSize,
- } from "$lib/components/ui/button/index.js";
+ } from "$lib/ui/core/button/index.js";
import { cn } from "$lib/utils.js";
let {
diff --git a/web/src/lib/components/ui/alert-dialog/alert-dialog-content.svelte b/web/src/lib/ui/core/alert-dialog/alert-dialog-content.svelte
similarity index 100%
rename from web/src/lib/components/ui/alert-dialog/alert-dialog-content.svelte
rename to web/src/lib/ui/core/alert-dialog/alert-dialog-content.svelte
diff --git a/web/src/lib/components/ui/alert-dialog/alert-dialog-description.svelte b/web/src/lib/ui/core/alert-dialog/alert-dialog-description.svelte
similarity index 100%
rename from web/src/lib/components/ui/alert-dialog/alert-dialog-description.svelte
rename to web/src/lib/ui/core/alert-dialog/alert-dialog-description.svelte
diff --git a/web/src/lib/components/ui/alert-dialog/alert-dialog-footer.svelte b/web/src/lib/ui/core/alert-dialog/alert-dialog-footer.svelte
similarity index 100%
rename from web/src/lib/components/ui/alert-dialog/alert-dialog-footer.svelte
rename to web/src/lib/ui/core/alert-dialog/alert-dialog-footer.svelte
diff --git a/web/src/lib/components/ui/alert-dialog/alert-dialog-header.svelte b/web/src/lib/ui/core/alert-dialog/alert-dialog-header.svelte
similarity index 100%
rename from web/src/lib/components/ui/alert-dialog/alert-dialog-header.svelte
rename to web/src/lib/ui/core/alert-dialog/alert-dialog-header.svelte
diff --git a/web/src/lib/components/ui/alert-dialog/alert-dialog-media.svelte b/web/src/lib/ui/core/alert-dialog/alert-dialog-media.svelte
similarity index 100%
rename from web/src/lib/components/ui/alert-dialog/alert-dialog-media.svelte
rename to web/src/lib/ui/core/alert-dialog/alert-dialog-media.svelte
diff --git a/web/src/lib/components/ui/alert-dialog/alert-dialog-overlay.svelte b/web/src/lib/ui/core/alert-dialog/alert-dialog-overlay.svelte
similarity index 100%
rename from web/src/lib/components/ui/alert-dialog/alert-dialog-overlay.svelte
rename to web/src/lib/ui/core/alert-dialog/alert-dialog-overlay.svelte
diff --git a/web/src/lib/components/ui/alert-dialog/alert-dialog-portal.svelte b/web/src/lib/ui/core/alert-dialog/alert-dialog-portal.svelte
similarity index 100%
rename from web/src/lib/components/ui/alert-dialog/alert-dialog-portal.svelte
rename to web/src/lib/ui/core/alert-dialog/alert-dialog-portal.svelte
diff --git a/web/src/lib/components/ui/alert-dialog/alert-dialog-title.svelte b/web/src/lib/ui/core/alert-dialog/alert-dialog-title.svelte
similarity index 100%
rename from web/src/lib/components/ui/alert-dialog/alert-dialog-title.svelte
rename to web/src/lib/ui/core/alert-dialog/alert-dialog-title.svelte
diff --git a/web/src/lib/components/ui/alert-dialog/alert-dialog-trigger.svelte b/web/src/lib/ui/core/alert-dialog/alert-dialog-trigger.svelte
similarity index 100%
rename from web/src/lib/components/ui/alert-dialog/alert-dialog-trigger.svelte
rename to web/src/lib/ui/core/alert-dialog/alert-dialog-trigger.svelte
diff --git a/web/src/lib/components/ui/alert-dialog/alert-dialog.svelte b/web/src/lib/ui/core/alert-dialog/alert-dialog.svelte
similarity index 100%
rename from web/src/lib/components/ui/alert-dialog/alert-dialog.svelte
rename to web/src/lib/ui/core/alert-dialog/alert-dialog.svelte
diff --git a/web/src/lib/ui/core/alert-dialog/index.ts b/web/src/lib/ui/core/alert-dialog/index.ts
new file mode 100644
index 0000000..ca81c2a
--- /dev/null
+++ b/web/src/lib/ui/core/alert-dialog/index.ts
@@ -0,0 +1,40 @@
+import Root from "./alert-dialog.svelte";
+import Portal from "./alert-dialog-portal.svelte";
+import Trigger from "./alert-dialog-trigger.svelte";
+import Title from "./alert-dialog-title.svelte";
+import Action from "./alert-dialog-action.svelte";
+import Cancel from "./alert-dialog-cancel.svelte";
+import Footer from "./alert-dialog-footer.svelte";
+import Header from "./alert-dialog-header.svelte";
+import Overlay from "./alert-dialog-overlay.svelte";
+import Content from "./alert-dialog-content.svelte";
+import Description from "./alert-dialog-description.svelte";
+import Media from "./alert-dialog-media.svelte";
+
+export {
+ Root,
+ Title,
+ Action,
+ Cancel,
+ Portal,
+ Footer,
+ Header,
+ Trigger,
+ Overlay,
+ Content,
+ Description,
+ Media,
+ //
+ Root as AlertDialog,
+ Title as AlertDialogTitle,
+ Action as AlertDialogAction,
+ Cancel as AlertDialogCancel,
+ Portal as AlertDialogPortal,
+ Footer as AlertDialogFooter,
+ Header as AlertDialogHeader,
+ Trigger as AlertDialogTrigger,
+ Overlay as AlertDialogOverlay,
+ Content as AlertDialogContent,
+ Description as AlertDialogDescription,
+ Media as AlertDialogMedia,
+};
diff --git a/web/src/lib/components/ui/alert/alert-action.svelte b/web/src/lib/ui/core/alert/alert-action.svelte
similarity index 100%
rename from web/src/lib/components/ui/alert/alert-action.svelte
rename to web/src/lib/ui/core/alert/alert-action.svelte
diff --git a/web/src/lib/components/ui/alert/alert-description.svelte b/web/src/lib/ui/core/alert/alert-description.svelte
similarity index 100%
rename from web/src/lib/components/ui/alert/alert-description.svelte
rename to web/src/lib/ui/core/alert/alert-description.svelte
diff --git a/web/src/lib/components/ui/alert/alert-title.svelte b/web/src/lib/ui/core/alert/alert-title.svelte
similarity index 100%
rename from web/src/lib/components/ui/alert/alert-title.svelte
rename to web/src/lib/ui/core/alert/alert-title.svelte
diff --git a/web/src/lib/components/ui/alert/alert.svelte b/web/src/lib/ui/core/alert/alert.svelte
similarity index 100%
rename from web/src/lib/components/ui/alert/alert.svelte
rename to web/src/lib/ui/core/alert/alert.svelte
diff --git a/web/src/lib/ui/core/alert/index.ts b/web/src/lib/ui/core/alert/index.ts
new file mode 100644
index 0000000..071b113
--- /dev/null
+++ b/web/src/lib/ui/core/alert/index.ts
@@ -0,0 +1,17 @@
+import Root from "./alert.svelte";
+import Description from "./alert-description.svelte";
+import Title from "./alert-title.svelte";
+import Action from "./alert-action.svelte";
+export { alertVariants, type AlertVariant } from "./alert.svelte";
+
+export {
+ Root,
+ Description,
+ Title,
+ Action,
+ //
+ Root as Alert,
+ Description as AlertDescription,
+ Title as AlertTitle,
+ Action as AlertAction,
+};
diff --git a/web/src/lib/components/ui/badge/badge.svelte b/web/src/lib/ui/core/badge/badge.svelte
similarity index 100%
rename from web/src/lib/components/ui/badge/badge.svelte
rename to web/src/lib/ui/core/badge/badge.svelte
diff --git a/web/src/lib/ui/core/badge/index.ts b/web/src/lib/ui/core/badge/index.ts
new file mode 100644
index 0000000..64e0aa9
--- /dev/null
+++ b/web/src/lib/ui/core/badge/index.ts
@@ -0,0 +1,2 @@
+export { default as Badge } from "./badge.svelte";
+export { badgeVariants, type BadgeVariant } from "./badge.svelte";
diff --git a/web/src/lib/components/ui/button/button.svelte b/web/src/lib/ui/core/button/button.svelte
similarity index 100%
rename from web/src/lib/components/ui/button/button.svelte
rename to web/src/lib/ui/core/button/button.svelte
diff --git a/web/src/lib/ui/core/button/index.ts b/web/src/lib/ui/core/button/index.ts
new file mode 100644
index 0000000..fb585d7
--- /dev/null
+++ b/web/src/lib/ui/core/button/index.ts
@@ -0,0 +1,17 @@
+import Root, {
+ type ButtonProps,
+ type ButtonSize,
+ type ButtonVariant,
+ buttonVariants,
+} from "./button.svelte";
+
+export {
+ Root,
+ type ButtonProps as Props,
+ //
+ Root as Button,
+ buttonVariants,
+ type ButtonProps,
+ type ButtonSize,
+ type ButtonVariant,
+};
diff --git a/web/src/lib/components/ui/card/card-action.svelte b/web/src/lib/ui/core/card/card-action.svelte
similarity index 100%
rename from web/src/lib/components/ui/card/card-action.svelte
rename to web/src/lib/ui/core/card/card-action.svelte
diff --git a/web/src/lib/components/ui/card/card-content.svelte b/web/src/lib/ui/core/card/card-content.svelte
similarity index 100%
rename from web/src/lib/components/ui/card/card-content.svelte
rename to web/src/lib/ui/core/card/card-content.svelte
diff --git a/web/src/lib/components/ui/card/card-description.svelte b/web/src/lib/ui/core/card/card-description.svelte
similarity index 100%
rename from web/src/lib/components/ui/card/card-description.svelte
rename to web/src/lib/ui/core/card/card-description.svelte
diff --git a/web/src/lib/components/ui/card/card-footer.svelte b/web/src/lib/ui/core/card/card-footer.svelte
similarity index 100%
rename from web/src/lib/components/ui/card/card-footer.svelte
rename to web/src/lib/ui/core/card/card-footer.svelte
diff --git a/web/src/lib/components/ui/card/card-header.svelte b/web/src/lib/ui/core/card/card-header.svelte
similarity index 100%
rename from web/src/lib/components/ui/card/card-header.svelte
rename to web/src/lib/ui/core/card/card-header.svelte
diff --git a/web/src/lib/components/ui/card/card-title.svelte b/web/src/lib/ui/core/card/card-title.svelte
similarity index 100%
rename from web/src/lib/components/ui/card/card-title.svelte
rename to web/src/lib/ui/core/card/card-title.svelte
diff --git a/web/src/lib/components/ui/card/card.svelte b/web/src/lib/ui/core/card/card.svelte
similarity index 100%
rename from web/src/lib/components/ui/card/card.svelte
rename to web/src/lib/ui/core/card/card.svelte
diff --git a/web/src/lib/ui/core/card/index.ts b/web/src/lib/ui/core/card/index.ts
new file mode 100644
index 0000000..4d3fce4
--- /dev/null
+++ b/web/src/lib/ui/core/card/index.ts
@@ -0,0 +1,25 @@
+import Root from "./card.svelte";
+import Content from "./card-content.svelte";
+import Description from "./card-description.svelte";
+import Footer from "./card-footer.svelte";
+import Header from "./card-header.svelte";
+import Title from "./card-title.svelte";
+import Action from "./card-action.svelte";
+
+export {
+ Root,
+ Content,
+ Description,
+ Footer,
+ Header,
+ Title,
+ Action,
+ //
+ Root as Card,
+ Content as CardContent,
+ Description as CardDescription,
+ Footer as CardFooter,
+ Header as CardHeader,
+ Title as CardTitle,
+ Action as CardAction,
+};
diff --git a/web/src/lib/ui/core/checkbox/checkbox.svelte b/web/src/lib/ui/core/checkbox/checkbox.svelte
new file mode 100644
index 0000000..27b0da6
--- /dev/null
+++ b/web/src/lib/ui/core/checkbox/checkbox.svelte
@@ -0,0 +1,39 @@
+
+
+