diff --git a/.npmrc b/.npmrc
new file mode 100644
index 0000000000..ae90f70514
--- /dev/null
+++ b/.npmrc
@@ -0,0 +1 @@
+ignore-workspace-root-check=true
diff --git a/components.json b/components.json
new file mode 100644
index 0000000000..5526f900d5
--- /dev/null
+++ b/components.json
@@ -0,0 +1,20 @@
+{
+ "$schema": "https://shadcn-vue.com/schema.json",
+ "style": "new-york",
+ "typescript": true,
+ "tailwind": {
+ "config": "tailwind.config.ts",
+ "css": "src/assets/css/style.css",
+ "baseColor": "stone",
+ "cssVariables": true,
+ "prefix": ""
+ },
+ "aliases": {
+ "components": "@/components",
+ "composables": "@/composables",
+ "utils": "@/utils",
+ "ui": "@/components/ui",
+ "lib": "@/lib"
+ },
+ "iconLibrary": "lucide"
+}
\ No newline at end of file
diff --git a/eslint.config.js b/eslint.config.js
index 7e3248b20a..cddba3bbd3 100644
--- a/eslint.config.js
+++ b/eslint.config.js
@@ -64,6 +64,9 @@ export default [
'vue/no-v-html': 'off',
// Enforce dark-theme: instead of dark: prefix
'vue/no-restricted-class': ['error', '/^dark:/'],
+ 'vue/multi-word-component-names': 'off', // TODO: fix
+ 'vue/no-template-shadow': 'off', // TODO: fix
+ 'vue/one-component-per-file': 'off', // TODO: fix
// Restrict deprecated PrimeVue components
'no-restricted-imports': [
'error',
diff --git a/package.json b/package.json
index f4e6035d3a..7c03496a49 100644
--- a/package.json
+++ b/package.json
@@ -83,6 +83,7 @@
"tailwindcss": "^4.1.12",
"tailwindcss-primeui": "^0.6.1",
"tsx": "^4.15.6",
+ "tw-animate-css": "^1.3.8",
"typescript": "^5.4.5",
"typescript-eslint": "^8.42.0",
"unplugin-icons": "^0.22.0",
@@ -140,6 +141,7 @@
"pinia": "^2.1.7",
"primeicons": "^7.0.0",
"primevue": "^4.2.5",
+ "reka-ui": "^2.5.0",
"semver": "^7.7.2",
"tailwind-merge": "^3.3.1",
"three": "^0.170.0",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 68fbf59b22..58c7d7aa41 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -134,6 +134,9 @@ importers:
primevue:
specifier: ^4.2.5
version: 4.2.5(vue@3.5.13(typescript@5.9.2))
+ reka-ui:
+ specifier: ^2.5.0
+ version: 2.5.0(typescript@5.9.2)(vue@3.5.13(typescript@5.9.2))
semver:
specifier: ^7.7.2
version: 7.7.2
@@ -303,6 +306,9 @@ importers:
tsx:
specifier: ^4.15.6
version: 4.19.4
+ tw-animate-css:
+ specifier: ^1.3.8
+ version: 1.3.8
typescript:
specifier: ^5.4.5
version: 5.9.2
@@ -1570,6 +1576,18 @@ packages:
'@firebase/webchannel-wrapper@1.0.3':
resolution: {integrity: sha512-2xCRM9q9FlzGZCdgDMJwc0gyUkWFtkosy7Xxr6sFgQwn+wMNIWd7xIvYNauU1r64B5L5rsGKy/n9TKJ0aAFeqQ==}
+ '@floating-ui/core@1.7.3':
+ resolution: {integrity: sha512-sGnvb5dmrJaKEZ+LDIpguvdX3bDlEllmv4/ClQ9awcmCZrlx5jQyyMWFM5kBI+EyNOCDDiKk8il0zeuX3Zlg/w==}
+
+ '@floating-ui/dom@1.7.4':
+ resolution: {integrity: sha512-OOchDgh4F2CchOX94cRVqhvy7b3AFb+/rQXyswmzmGakRfkMgoWVjfnLWkRirfLEfuD4ysVW16eXzwt3jHIzKA==}
+
+ '@floating-ui/utils@0.2.10':
+ resolution: {integrity: sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==}
+
+ '@floating-ui/vue@1.1.9':
+ resolution: {integrity: sha512-BfNqNW6KA83Nexspgb9DZuz578R7HT8MZw1CfK9I6Ah4QReNWEJsXWHN+SdmOVLNGmTPDi+fDT535Df5PzMLbQ==}
+
'@grpc/grpc-js@1.9.15':
resolution: {integrity: sha512-nqE7Hc0AzI+euzUwDAy0aY5hCp10r734gMGRdU+qOPX0XSceI2ULrcXB5U2xSc5VkWwalCj4M7GzCAygZl2KoQ==}
engines: {node: ^8.13.0 || >=10.10.0}
@@ -1610,6 +1628,12 @@ packages:
'@iconify/utils@2.3.0':
resolution: {integrity: sha512-GmQ78prtwYW6EtzXRU1rY+KwOKfz32PD7iJh6Iyqw68GiKuoZ2A6pRtzWONz5VQJbp50mEjXh/7NkumtrAgRKA==}
+ '@internationalized/date@3.9.0':
+ resolution: {integrity: sha512-yaN3brAnHRD+4KyyOsJyk49XUvj2wtbNACSqg0bz3u8t2VuzhC8Q5dfRnrSxjnnbDb+ienBnkn1TzQfE154vyg==}
+
+ '@internationalized/number@3.6.5':
+ resolution: {integrity: sha512-6hY4Kl4HPBvtfS62asS/R22JzNNy8vi/Ssev7x6EobfCp+9QIB2hKvI2EtbdJ0VSQacxVNtqhE/NmF/NZ0gm6g==}
+
'@intlify/core-base@9.14.3':
resolution: {integrity: sha512-nbJ7pKTlXFnaXPblyfiH6awAx1C0PWNNuqXAR74yRwgi5A/Re/8/5fErLY0pv4R8+EHj3ZaThMHdnuC/5OBa6g==}
engines: {node: '>= 16'}
@@ -2243,6 +2267,9 @@ packages:
storybook: ^9.1.1
vue: ^3.0.0
+ '@swc/helpers@0.5.17':
+ resolution: {integrity: sha512-5IKx/Y13RsYd+sauPb2x+U/xZikHjolzfuDgTAl/Tdf3Q8rslRvC19NKDLgAJQ6wsqADk10ntlv08nPFw/gO/A==}
+
'@tailwindcss/node@4.1.12':
resolution: {integrity: sha512-3hm9brwvQkZFe++SBt+oLjo4OLDtkvlE8q2WalaD/7QWaeM7KEJbAiY/LJZUaCs7Xa8aUu4xy3uoyX4q54UVdQ==}
@@ -2333,6 +2360,14 @@ packages:
peerDependencies:
vite: ^5.2.0 || ^6 || ^7
+ '@tanstack/virtual-core@3.13.12':
+ resolution: {integrity: sha512-1YBOJfRHV4sXUmWsFSf5rQor4Ss82G8dQWLRbnk3GA4jeP8hQt1hxXh0tmflpC0dz3VgEv/1+qwPyLeWkQuPFA==}
+
+ '@tanstack/vue-virtual@3.13.12':
+ resolution: {integrity: sha512-vhF7kEU9EXWXh+HdAwKJ2m3xaOnTTmgcdXcF2pim8g4GvI7eRrk2YRuV5nUlZnd/NbCIX4/Ja2OZu5EjJL06Ww==}
+ peerDependencies:
+ vue: ^2.7.0 || ^3.0.0
+
'@testing-library/dom@10.4.1':
resolution: {integrity: sha512-o4PXJQidqJl82ckFaXUeoAW+XysPLauYI43Abki5hABd853iMhitooc6znOnczgbTYmEP6U6/y1ZyKAIsvMKGg==}
engines: {node: '>=18'}
@@ -2609,6 +2644,9 @@ packages:
'@types/web-bluetooth@0.0.20':
resolution: {integrity: sha512-g9gZnnXVq7gM7v3tJCWV/qw7w+KeOlSHAhgF9RytFyifW6AF61hdT2ucrYhPq9hLs5JIryeupHV3qGk95dH9ow==}
+ '@types/web-bluetooth@0.0.21':
+ resolution: {integrity: sha512-oIQLCGWtcFZy2JW77j9k8nHzAOpqMHLQejDA48XXMWH6tjCQHz5RCFz1bzsmROyL6PUm+LLnUiI4BCn221inxA==}
+
'@types/webxr@0.5.20':
resolution: {integrity: sha512-JGpU6qiIJQKUuVSKx1GtQnHJGxRjtfGIhzO2ilq43VZZS//f1h1Sgexbdk+Lq+7569a6EYhOWrUpIruR/1Enmg==}
@@ -2859,12 +2897,21 @@ packages:
'@vueuse/core@11.0.0':
resolution: {integrity: sha512-shibzNGjmRjZucEm97B8V0NO5J3vPHMCE/mltxQ3vHezbDoFQBMtK11XsfwfPionxSbo+buqPmsCljtYuXIBpw==}
+ '@vueuse/core@12.8.2':
+ resolution: {integrity: sha512-HbvCmZdzAu3VGi/pWYm5Ut+Kd9mn1ZHnn4L5G8kOQTPs/IwIAmJoBrmYk2ckLArgMXZj0AW3n5CAejLUO+PhdQ==}
+
'@vueuse/metadata@11.0.0':
resolution: {integrity: sha512-0TKsAVT0iUOAPWyc9N79xWYfovJVPATiOPVKByG6jmAYdDiwvMVm9xXJ5hp4I8nZDxpCcYlLq/Rg9w1Z/jrGcg==}
+ '@vueuse/metadata@12.8.2':
+ resolution: {integrity: sha512-rAyLGEuoBJ/Il5AmFHiziCPdQzRt88VxR+Y/A/QhJ1EWtWqPBBAxTAFaSkviwEuOEZNtW8pvkPgoCZQ+HxqW1A==}
+
'@vueuse/shared@11.0.0':
resolution: {integrity: sha512-i4ZmOrIEjSsL94uAEt3hz88UCz93fMyP/fba9S+vypX90fKg3uYX9cThqvWc9aXxuTzR0UGhOKOTQd//Goh1nQ==}
+ '@vueuse/shared@12.8.2':
+ resolution: {integrity: sha512-dznP38YzxZoNloI0qpEfpkms8knDtaoQ6Y/sfS0L7Yki4zh40LFHEhur0odJC6xTHG5dxWVPiUWBXn+wCG2s5w==}
+
'@webgpu/types@0.1.51':
resolution: {integrity: sha512-ktR3u64NPjwIViNCck+z9QeyN0iPkQCUOQ07ZCV1RzlkfP+olLTeEZ95O1QHS+v4w9vJeY9xj/uJuSphsHy5rQ==}
@@ -3018,6 +3065,10 @@ packages:
argparse@2.0.1:
resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==}
+ aria-hidden@1.2.6:
+ resolution: {integrity: sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA==}
+ engines: {node: '>=10'}
+
aria-query@5.3.0:
resolution: {integrity: sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==}
@@ -3488,6 +3539,9 @@ packages:
resolution: {integrity: sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==}
engines: {node: '>=12'}
+ defu@6.1.4:
+ resolution: {integrity: sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==}
+
delayed-stream@1.0.0:
resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==}
engines: {node: '>=0.4.0'}
@@ -5105,6 +5159,9 @@ packages:
resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==}
engines: {node: '>= 0.4'}
+ ohash@2.0.11:
+ resolution: {integrity: sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ==}
+
once@1.4.0:
resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==}
@@ -5555,6 +5612,11 @@ packages:
resolution: {integrity: sha512-cnE+y8bz4NhMjISKbgeVJtqNbtf5QpjZP+Bslo+UqkIt9QPnX9q095eiRRASJG1/tz6dlNr6Z5NsBiWYokp6EQ==}
hasBin: true
+ reka-ui@2.5.0:
+ resolution: {integrity: sha512-81aMAmJeVCy2k0E6x7n1kypDY6aM1ldLis5+zcdV1/JtoAlSDck5OBsyLRJU9CfgbrQp1ImnRnBSmC4fZ2fkZQ==}
+ peerDependencies:
+ vue: '>= 3.2.0'
+
relateurl@0.2.7:
resolution: {integrity: sha512-G08Dxvm4iDN3MLM0EsP62EDV9IuhXPR6blNz6Utcp7zyV3tr4HVNINt6MpaRWbxoOHT3Q7YN2P+jaHX8vUbgog==}
engines: {node: '>= 0.10'}
@@ -5989,6 +6051,9 @@ packages:
engines: {node: '>=18.0.0'}
hasBin: true
+ tw-animate-css@1.3.8:
+ resolution: {integrity: sha512-Qrk3PZ7l7wUcGYhwZloqfkWCmaXZAoqjkdbIDvzfGshwGtexa/DAs9koXxIkrpEasyevandomzCBAV1Yyop5rw==}
+
type-check@0.4.0:
resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==}
engines: {node: '>= 0.8.0'}
@@ -7999,6 +8064,26 @@ snapshots:
'@firebase/webchannel-wrapper@1.0.3': {}
+ '@floating-ui/core@1.7.3':
+ dependencies:
+ '@floating-ui/utils': 0.2.10
+
+ '@floating-ui/dom@1.7.4':
+ dependencies:
+ '@floating-ui/core': 1.7.3
+ '@floating-ui/utils': 0.2.10
+
+ '@floating-ui/utils@0.2.10': {}
+
+ '@floating-ui/vue@1.1.9(vue@3.5.13(typescript@5.9.2))':
+ dependencies:
+ '@floating-ui/dom': 1.7.4
+ '@floating-ui/utils': 0.2.10
+ vue-demi: 0.14.10(vue@3.5.13(typescript@5.9.2))
+ transitivePeerDependencies:
+ - '@vue/composition-api'
+ - vue
+
'@grpc/grpc-js@1.9.15':
dependencies:
'@grpc/proto-loader': 0.7.13
@@ -8050,6 +8135,14 @@ snapshots:
transitivePeerDependencies:
- supports-color
+ '@internationalized/date@3.9.0':
+ dependencies:
+ '@swc/helpers': 0.5.17
+
+ '@internationalized/number@3.6.5':
+ dependencies:
+ '@swc/helpers': 0.5.17
+
'@intlify/core-base@9.14.3':
dependencies:
'@intlify/message-compiler': 9.14.3
@@ -8834,6 +8927,10 @@ snapshots:
vue: 3.5.13(typescript@5.9.2)
vue-component-type-helpers: 3.0.6
+ '@swc/helpers@0.5.17':
+ dependencies:
+ tslib: 2.8.1
+
'@tailwindcss/node@4.1.12':
dependencies:
'@jridgewell/remapping': 2.3.5
@@ -8905,6 +9002,13 @@ snapshots:
tailwindcss: 4.1.12
vite: 5.4.19(@types/node@20.14.10)(lightningcss@1.30.1)(terser@5.39.2)
+ '@tanstack/virtual-core@3.13.12': {}
+
+ '@tanstack/vue-virtual@3.13.12(vue@3.5.13(typescript@5.9.2))':
+ dependencies:
+ '@tanstack/virtual-core': 3.13.12
+ vue: 3.5.13(typescript@5.9.2)
+
'@testing-library/dom@10.4.1':
dependencies:
'@babel/code-frame': 7.27.1
@@ -9212,6 +9316,8 @@ snapshots:
'@types/web-bluetooth@0.0.20': {}
+ '@types/web-bluetooth@0.0.21': {}
+
'@types/webxr@0.5.20': {}
'@typescript-eslint/eslint-plugin@8.42.0(@typescript-eslint/parser@8.42.0(eslint@9.35.0(jiti@2.4.2))(typescript@5.9.2))(eslint@9.35.0(jiti@2.4.2))(typescript@5.9.2)':
@@ -9618,8 +9724,19 @@ snapshots:
- '@vue/composition-api'
- vue
+ '@vueuse/core@12.8.2(typescript@5.9.2)':
+ dependencies:
+ '@types/web-bluetooth': 0.0.21
+ '@vueuse/metadata': 12.8.2
+ '@vueuse/shared': 12.8.2(typescript@5.9.2)
+ vue: 3.5.13(typescript@5.9.2)
+ transitivePeerDependencies:
+ - typescript
+
'@vueuse/metadata@11.0.0': {}
+ '@vueuse/metadata@12.8.2': {}
+
'@vueuse/shared@11.0.0(vue@3.5.13(typescript@5.9.2))':
dependencies:
vue-demi: 0.14.10(vue@3.5.13(typescript@5.9.2))
@@ -9627,6 +9744,12 @@ snapshots:
- '@vue/composition-api'
- vue
+ '@vueuse/shared@12.8.2(typescript@5.9.2)':
+ dependencies:
+ vue: 3.5.13(typescript@5.9.2)
+ transitivePeerDependencies:
+ - typescript
+
'@webgpu/types@0.1.51': {}
'@xterm/addon-fit@0.10.0(@xterm/xterm@5.5.0)':
@@ -9775,6 +9898,10 @@ snapshots:
argparse@2.0.1: {}
+ aria-hidden@1.2.6:
+ dependencies:
+ tslib: 2.8.1
+
aria-query@5.3.0:
dependencies:
dequal: 2.0.3
@@ -10244,6 +10371,8 @@ snapshots:
define-lazy-prop@3.0.0: {}
+ defu@6.1.4: {}
+
delayed-stream@1.0.0: {}
dequal@2.0.3: {}
@@ -12135,6 +12264,8 @@ snapshots:
object-keys@1.1.1: {}
+ ohash@2.0.11: {}
+
once@1.4.0:
dependencies:
wrappy: 1.0.2
@@ -12711,6 +12842,23 @@ snapshots:
dependencies:
jsesc: 3.0.2
+ reka-ui@2.5.0(typescript@5.9.2)(vue@3.5.13(typescript@5.9.2)):
+ dependencies:
+ '@floating-ui/dom': 1.7.4
+ '@floating-ui/vue': 1.1.9(vue@3.5.13(typescript@5.9.2))
+ '@internationalized/date': 3.9.0
+ '@internationalized/number': 3.6.5
+ '@tanstack/vue-virtual': 3.13.12(vue@3.5.13(typescript@5.9.2))
+ '@vueuse/core': 12.8.2(typescript@5.9.2)
+ '@vueuse/shared': 12.8.2(typescript@5.9.2)
+ aria-hidden: 1.2.6
+ defu: 6.1.4
+ ohash: 2.0.11
+ vue: 3.5.13(typescript@5.9.2)
+ transitivePeerDependencies:
+ - '@vue/composition-api'
+ - typescript
+
relateurl@0.2.7: {}
remark-frontmatter@5.0.0:
@@ -13158,6 +13306,8 @@ snapshots:
optionalDependencies:
fsevents: 2.3.3
+ tw-animate-css@1.3.8: {}
+
type-check@0.4.0:
dependencies:
prelude-ls: 1.2.1
diff --git a/src/assets/css/style.css b/src/assets/css/style.css
index 3258cbba50..9c49e17046 100644
--- a/src/assets/css/style.css
+++ b/src/assets/css/style.css
@@ -2,8 +2,9 @@
@import 'tailwindcss/theme' layer(theme);
@import 'tailwindcss/utilities' layer(utilities);
+@import 'tw-animate-css';
-@plugin "tailwindcss-primeui";
+@plugin 'tailwindcss-primeui';
@config '../../../tailwind.config.ts';
@@ -114,6 +115,14 @@
--color-dark-elevation-2: rgba(from white r g b / 0.03);
}
+@theme inline {
+ --color-node-component-surface: var(--color-charcoal-300);
+ --color-node-component-surface-highlight: var(--color-slate-100);
+ --color-node-component-surface-hovered: var(--color-charcoal-500);
+ --color-node-component-surface-selected: var(--color-charcoal-700);
+ --color-node-stroke: var(--color-stone-100);
+}
+
@custom-variant dark-theme {
.dark-theme & {
@slot;
diff --git a/src/components/ui/slider/Slider.vue b/src/components/ui/slider/Slider.vue
new file mode 100644
index 0000000000..3ce2eb3d84
--- /dev/null
+++ b/src/components/ui/slider/Slider.vue
@@ -0,0 +1,78 @@
+
+
+
+