refactor: swap out dropdown with reka components (#1245)

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

- **New Features**
- Introduced a new `DropdownMenu` component in user profiles with
dynamic content rendering.
- Added a new `Popover` component with interactive Storybook demos,
improving component discoverability.
- Added a new `DropdownMenuArrow` component to enhance dropdown visuals.
- Implemented new CSS custom properties for charts, enhancing styling
capabilities in light and dark themes.
- Enhanced dropdown functionality by encapsulating dropdown logic in a
new `UpcDropdownMenu` component.
- Added a new `Select` component for improved user interaction within
the `Sheet` component.
- Introduced a new `SheetWithSelect` story to showcase selection
functionality within the `Sheet` component.
- Updated the `Sidebar` component to improve modal behavior and content
positioning.
- Enhanced `UserProfile` components with a new feedback function for
better status indication.

- **Style**
- Refined layouts by replacing fixed widths with flexible, responsive
designs.
- Updated global styling with a refreshed chart color palette and
expanded dark mode support.

- **Refactor**
- Migrated components to use a unified UI library, streamlining
interactions and boosting consistency.
- Improved type safety in `BrandLoading` component by utilizing a new
type for variants and sizes.
- Updated component imports and organization to enhance maintainability.

- **Bug Fixes**
- Removed unused promotional code and components, simplifying the
codebase and improving performance.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: mdatelle <mike@datelle.net>
Co-authored-by: Zack Spear <hi@zackspear.com>
Co-authored-by: Eli Bosley <ekbosley@gmail.com>
This commit is contained in:
Michael Datelle
2025-03-24 17:24:52 -04:00
committed by GitHub
parent cc85fba207
commit a1d02b486a
76 changed files with 838 additions and 934 deletions
+108 -104
View File
@@ -49,28 +49,28 @@ importers:
version: 3.5.1
'@nestjs/apollo':
specifier: ^13.0.3
version: 13.0.3(@apollo/server@4.11.3(graphql@16.10.0))(@as-integrations/fastify@2.1.1(@apollo/server@4.11.3(graphql@16.10.0))(fastify@5.2.1))(@nestjs/common@11.0.12(reflect-metadata@0.1.14)(rxjs@7.8.2))(@nestjs/core@11.0.12(@nestjs/common@11.0.12(reflect-metadata@0.1.14)(rxjs@7.8.2))(reflect-metadata@0.1.14)(rxjs@7.8.2))(@nestjs/graphql@13.0.3(@nestjs/common@11.0.12(reflect-metadata@0.1.14)(rxjs@7.8.2))(@nestjs/core@11.0.12(@nestjs/common@11.0.12(reflect-metadata@0.1.14)(rxjs@7.8.2))(reflect-metadata@0.1.14)(rxjs@7.8.2))(graphql@16.10.0)(reflect-metadata@0.1.14)(ts-morph@24.0.0))(graphql@16.10.0)
version: 13.0.3(@apollo/server@4.11.3(graphql@16.10.0))(@as-integrations/fastify@2.1.1(@apollo/server@4.11.3(graphql@16.10.0))(fastify@5.2.1))(@nestjs/common@11.0.11(reflect-metadata@0.1.14)(rxjs@7.8.2))(@nestjs/core@11.0.11(@nestjs/common@11.0.11(reflect-metadata@0.1.14)(rxjs@7.8.2))(reflect-metadata@0.1.14)(rxjs@7.8.2))(@nestjs/graphql@13.0.3(@nestjs/common@11.0.11(reflect-metadata@0.1.14)(rxjs@7.8.2))(@nestjs/core@11.0.11(@nestjs/common@11.0.11(reflect-metadata@0.1.14)(rxjs@7.8.2))(reflect-metadata@0.1.14)(rxjs@7.8.2))(graphql@16.10.0)(reflect-metadata@0.1.14)(ts-morph@24.0.0))(graphql@16.10.0)
'@nestjs/common':
specifier: ^11.0.11
version: 11.0.12(reflect-metadata@0.1.14)(rxjs@7.8.2)
version: 11.0.11(reflect-metadata@0.1.14)(rxjs@7.8.2)
'@nestjs/core':
specifier: ^11.0.11
version: 11.0.12(@nestjs/common@11.0.12(reflect-metadata@0.1.14)(rxjs@7.8.2))(reflect-metadata@0.1.14)(rxjs@7.8.2)
version: 11.0.11(@nestjs/common@11.0.11(reflect-metadata@0.1.14)(rxjs@7.8.2))(reflect-metadata@0.1.14)(rxjs@7.8.2)
'@nestjs/graphql':
specifier: ^13.0.3
version: 13.0.3(@nestjs/common@11.0.12(reflect-metadata@0.1.14)(rxjs@7.8.2))(@nestjs/core@11.0.12(@nestjs/common@11.0.12(reflect-metadata@0.1.14)(rxjs@7.8.2))(reflect-metadata@0.1.14)(rxjs@7.8.2))(graphql@16.10.0)(reflect-metadata@0.1.14)(ts-morph@24.0.0)
version: 13.0.3(@nestjs/common@11.0.11(reflect-metadata@0.1.14)(rxjs@7.8.2))(@nestjs/core@11.0.11(@nestjs/common@11.0.11(reflect-metadata@0.1.14)(rxjs@7.8.2))(reflect-metadata@0.1.14)(rxjs@7.8.2))(graphql@16.10.0)(reflect-metadata@0.1.14)(ts-morph@24.0.0)
'@nestjs/passport':
specifier: ^11.0.0
version: 11.0.5(@nestjs/common@11.0.12(reflect-metadata@0.1.14)(rxjs@7.8.2))(passport@0.7.0)
version: 11.0.5(@nestjs/common@11.0.11(reflect-metadata@0.1.14)(rxjs@7.8.2))(passport@0.7.0)
'@nestjs/platform-fastify':
specifier: ^11.0.11
version: 11.0.12(@nestjs/common@11.0.12(reflect-metadata@0.1.14)(rxjs@7.8.2))(@nestjs/core@11.0.12(@nestjs/common@11.0.12(reflect-metadata@0.1.14)(rxjs@7.8.2))(reflect-metadata@0.1.14)(rxjs@7.8.2))
version: 11.0.11(@nestjs/common@11.0.11(reflect-metadata@0.1.14)(rxjs@7.8.2))(@nestjs/core@11.0.11(@nestjs/common@11.0.11(reflect-metadata@0.1.14)(rxjs@7.8.2))(reflect-metadata@0.1.14)(rxjs@7.8.2))
'@nestjs/schedule':
specifier: ^5.0.0
version: 5.0.1(@nestjs/common@11.0.12(reflect-metadata@0.1.14)(rxjs@7.8.2))(@nestjs/core@11.0.12(@nestjs/common@11.0.12(reflect-metadata@0.1.14)(rxjs@7.8.2))(reflect-metadata@0.1.14)(rxjs@7.8.2))
version: 5.0.1(@nestjs/common@11.0.11(reflect-metadata@0.1.14)(rxjs@7.8.2))(@nestjs/core@11.0.11(@nestjs/common@11.0.11(reflect-metadata@0.1.14)(rxjs@7.8.2))(reflect-metadata@0.1.14)(rxjs@7.8.2))
'@nestjs/throttler':
specifier: ^6.2.1
version: 6.4.0(@nestjs/common@11.0.12(reflect-metadata@0.1.14)(rxjs@7.8.2))(@nestjs/core@11.0.12(@nestjs/common@11.0.12(reflect-metadata@0.1.14)(rxjs@7.8.2))(reflect-metadata@0.1.14)(rxjs@7.8.2))(reflect-metadata@0.1.14)
version: 6.4.0(@nestjs/common@11.0.11(reflect-metadata@0.1.14)(rxjs@7.8.2))(@nestjs/core@11.0.11(@nestjs/common@11.0.11(reflect-metadata@0.1.14)(rxjs@7.8.2))(reflect-metadata@0.1.14)(rxjs@7.8.2))(reflect-metadata@0.1.14)
'@reduxjs/toolkit':
specifier: ^2.3.0
version: 2.6.1(react@19.0.0)
@@ -166,7 +166,7 @@ importers:
version: 2.0.3
graphql-scalars:
specifier: ^1.23.0
version: 1.24.2(graphql@16.10.0)
version: 1.24.1(graphql@16.10.0)
graphql-subscriptions:
specifier: ^3.0.0
version: 3.0.0(graphql@16.10.0)
@@ -202,13 +202,13 @@ importers:
version: 4.2.0
nest-authz:
specifier: ^2.14.0
version: 2.15.0(@nestjs/common@11.0.12(reflect-metadata@0.1.14)(rxjs@7.8.2))(@nestjs/core@11.0.12(@nestjs/common@11.0.12(reflect-metadata@0.1.14)(rxjs@7.8.2))(reflect-metadata@0.1.14)(rxjs@7.8.2))(reflect-metadata@0.1.14)(rxjs@7.8.2)
version: 2.15.0(@nestjs/common@11.0.11(reflect-metadata@0.1.14)(rxjs@7.8.2))(@nestjs/core@11.0.11(@nestjs/common@11.0.11(reflect-metadata@0.1.14)(rxjs@7.8.2))(reflect-metadata@0.1.14)(rxjs@7.8.2))(reflect-metadata@0.1.14)(rxjs@7.8.2)
nest-commander:
specifier: ^3.15.0
version: 3.17.0(@nestjs/common@11.0.12(reflect-metadata@0.1.14)(rxjs@7.8.2))(@nestjs/core@11.0.12(@nestjs/common@11.0.12(reflect-metadata@0.1.14)(rxjs@7.8.2))(reflect-metadata@0.1.14)(rxjs@7.8.2))(@types/inquirer@8.2.10)(typescript@5.8.2)
version: 3.17.0(@nestjs/common@11.0.11(reflect-metadata@0.1.14)(rxjs@7.8.2))(@nestjs/core@11.0.11(@nestjs/common@11.0.11(reflect-metadata@0.1.14)(rxjs@7.8.2))(reflect-metadata@0.1.14)(rxjs@7.8.2))(@types/inquirer@8.2.10)(typescript@5.8.2)
nestjs-pino:
specifier: ^4.1.0
version: 4.4.0(@nestjs/common@11.0.12(reflect-metadata@0.1.14)(rxjs@7.8.2))(pino-http@10.4.0)(pino@9.6.0)(rxjs@7.8.2)
version: 4.3.1(@nestjs/common@11.0.11(reflect-metadata@0.1.14)(rxjs@7.8.2))(pino-http@10.4.0)(pino@9.6.0)(rxjs@7.8.2)
node-cache:
specifier: ^5.1.2
version: 5.1.2
@@ -305,7 +305,7 @@ importers:
version: 4.4.1(@vue/compiler-sfc@3.5.13)(prettier@3.5.3)
'@nestjs/testing':
specifier: ^11.0.11
version: 11.0.12(@nestjs/common@11.0.12(reflect-metadata@0.1.14)(rxjs@7.8.2))(@nestjs/core@11.0.12(@nestjs/common@11.0.12(reflect-metadata@0.1.14)(rxjs@7.8.2))(reflect-metadata@0.1.14)(rxjs@7.8.2))
version: 11.0.11(@nestjs/common@11.0.11(reflect-metadata@0.1.14)(rxjs@7.8.2))(@nestjs/core@11.0.11(@nestjs/common@11.0.11(reflect-metadata@0.1.14)(rxjs@7.8.2))(reflect-metadata@0.1.14)(rxjs@7.8.2))
'@originjs/vite-plugin-commonjs':
specifier: ^1.0.3
version: 1.0.3
@@ -527,7 +527,7 @@ importers:
specifier: ^1.9.13
version: 1.9.17(vue@3.5.13(typescript@5.8.2))
reka-ui:
specifier: ^2.0.2
specifier: ^2.1.0
version: 2.1.0(typescript@5.8.2)(vue@3.5.13(typescript@5.8.2))
shadcn-vue:
specifier: ^1.0.0
@@ -686,7 +686,7 @@ importers:
version: 3.5.1(@jsonforms/core@3.5.1)(@jsonforms/vue@3.5.1(@jsonforms/core@3.5.1)(vue@3.5.13(typescript@5.8.2)))(vue@3.5.13(typescript@5.8.2))
'@jsonforms/vue-vuetify':
specifier: ^3.5.1
version: 3.5.1(@jsonforms/core@3.5.1)(@jsonforms/vue@3.5.1(@jsonforms/core@3.5.1)(vue@3.5.13(typescript@5.8.2)))(ajv@8.17.1)(dayjs@1.11.13)(lodash@4.17.21)(maska@2.1.11)(vue@3.5.13(typescript@5.8.2))(vuetify@3.7.18)
version: 3.5.1(@jsonforms/core@3.5.1)(@jsonforms/vue@3.5.1(@jsonforms/core@3.5.1)(vue@3.5.13(typescript@5.8.2)))(ajv@8.17.1)(dayjs@1.11.13)(lodash@4.17.21)(maska@2.1.11)(vue@3.5.13(typescript@5.8.2))(vuetify@3.7.17)
'@nuxtjs/color-mode':
specifier: ^3.5.2
version: 3.5.2(magicast@0.3.5)
@@ -753,6 +753,9 @@ importers:
radix-vue:
specifier: ^1.9.13
version: 1.9.17(vue@3.5.13(typescript@5.8.2))
reka-ui:
specifier: ^2.0.2
version: 2.1.0(typescript@5.8.2)(vue@3.5.13(typescript@5.8.2))
semver:
specifier: ^7.6.3
version: 7.7.1
@@ -764,7 +767,7 @@ importers:
version: 11.1.2(vue@3.5.13(typescript@5.8.2))
vuetify:
specifier: ^3.7.14
version: 3.7.18(typescript@5.8.2)(vite-plugin-vuetify@2.1.0)(vue@3.5.13(typescript@5.8.2))
version: 3.7.17(typescript@5.8.2)(vite-plugin-vuetify@2.1.0)(vue@3.5.13(typescript@5.8.2))
wretch:
specifier: ^2.11.0
version: 2.11.0
@@ -2011,9 +2014,6 @@ packages:
'@fastify/error@4.0.0':
resolution: {integrity: sha512-OO/SA8As24JtT1usTUTKgGH7uLvhfwZPwlptRi2Dp5P4KKmJI3gvsZ8MIHnNwDs4sLf/aai5LzTyl66xr7qMxA==}
'@fastify/error@4.1.0':
resolution: {integrity: sha512-KeFcciOr1eo/YvIXHP65S94jfEEqn1RxTRBT1aJaHxY5FK0/GDXYozsQMMWlZoHgi8i0s+YtrLsgj/JkUUjSkQ==}
'@fastify/fast-json-stringify-compiler@5.0.2':
resolution: {integrity: sha512-YdR7gqlLg1xZAQa+SX4sMNzQHY5pC54fu9oC5aYSUqBhyn6fkLkrdtKlpVdCNPlwuUuXA1PjFTEmvMF6ZVXVGw==}
@@ -2600,8 +2600,8 @@ packages:
'@as-integrations/fastify':
optional: true
'@nestjs/common@11.0.12':
resolution: {integrity: sha512-6PXxmDe2iYmb57xacnxzpW1NAxRZ7Gf+acMT7/hmRB/4KpZiFU/cNvLWwgbM2BL5QSzQulOwY6ny5bbKnPpB+A==}
'@nestjs/common@11.0.11':
resolution: {integrity: sha512-b3zYiho5/XGCnLa7W2hHv5ecSBR1huQrXCHu6pxd+g2HY2B7sKP5CXHMv4gHYqpIqu4ClOb7Q4tLKXMp9LyLUg==}
peerDependencies:
class-transformer: '*'
class-validator: '*'
@@ -2613,8 +2613,8 @@ packages:
class-validator:
optional: true
'@nestjs/core@11.0.12':
resolution: {integrity: sha512-micQrbh9iL0PuYVx2vsUojuNmMUyqoMCuj7eGAUhvjiZUh4DBLPdxYmJEayCT/equHSiw9vNC95Vm0JigVZ44g==}
'@nestjs/core@11.0.11':
resolution: {integrity: sha512-jMH3jrjrPiaGrkQ5hANNcgDWN+j+hcM5GMQ3jSs4vOWNs3lmKHTVR11wJ9y5tTNnwKydzMogeju0VTUdfXDI5Q==}
engines: {node: '>= 20'}
peerDependencies:
'@nestjs/common': ^11.0.0
@@ -2671,11 +2671,11 @@ packages:
'@nestjs/common': ^10.0.0 || ^11.0.0
passport: ^0.5.0 || ^0.6.0 || ^0.7.0
'@nestjs/platform-fastify@11.0.12':
resolution: {integrity: sha512-wpUI+A5jlSTEUyc212kMG2pGVCS29A3xzn8Y73tgu+szX+womi6zXud//+GArrlUcOIaA8Z2sCJLiROkiH2D2A==}
'@nestjs/platform-fastify@11.0.11':
resolution: {integrity: sha512-Ts7jMc3GE35k8KMY8m7/qtc4/Zqo4BFSXsfUy646o+JeJSkUZOSofevxkkI2smhX6w9SKJzyfEpRHzMZNs/oRA==}
peerDependencies:
'@fastify/static': ^8.0.0
'@fastify/view': ^10.0.0 || ^11.0.0
'@fastify/view': ^10.0.0
'@nestjs/common': ^11.0.0
'@nestjs/core': ^11.0.0
peerDependenciesMeta:
@@ -2690,8 +2690,8 @@ packages:
'@nestjs/common': ^10.0.0 || ^11.0.0
'@nestjs/core': ^10.0.0 || ^11.0.0
'@nestjs/testing@11.0.12':
resolution: {integrity: sha512-jl1McTqrY+zRBFIWcFMVwesY2v++mAdHrrzXsLxatgkf6wRVh6te1MQ6LikgQ6qz4P5qzVV6EiXQVLGvARe5Xw==}
'@nestjs/testing@11.0.11':
resolution: {integrity: sha512-SoMIrhRpElV53btmGnEwpIQmXn2Xcztb9ae3lv+eVVnPHQuyB2zlgDIQVNjicbj7+3jdycX52KctOoj2eXEo1Q==}
peerDependencies:
'@nestjs/common': ^11.0.0
'@nestjs/core': ^11.0.0
@@ -6960,8 +6960,8 @@ packages:
peerDependencies:
graphql: 14 - 16
graphql-scalars@1.24.2:
resolution: {integrity: sha512-FoZ11yxIauEnH0E5rCUkhDXHVn/A6BBfovJdimRZCQlFCl+h7aVvarKmI15zG4VtQunmCDdqdtNs6ixThy3uAg==}
graphql-scalars@1.24.1:
resolution: {integrity: sha512-3L553TMPh3YpHQM4x9G4tXcyD+AX8QQOYA6tUn1nrNiWEXE0JfAnWdjoe3WGxRuGjnZrzvHDz62q8S+sSGXXwA==}
engines: {node: '>=10'}
peerDependencies:
graphql: ^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0
@@ -8404,8 +8404,8 @@ packages:
'@nestjs/core': ^8.0.0 || ^9.0.0 || ^10.0.0 || ^11.0.0
'@types/inquirer': ^8.1.3
nestjs-pino@4.4.0:
resolution: {integrity: sha512-+GMNlcNWDRrMtlQftfcxN+5pV2C25A4wsYIY7cfRJTMW4b8IFKYReDrG1lUp5LGql9fXemmnVJ2Ww10iIkCZPQ==}
nestjs-pino@4.3.1:
resolution: {integrity: sha512-Mym5k8X0prO4dqZoMC11EsZq3lggeJg9Z3gTUl4JvRXGkCz2Owu3ZUOiitDdX1znowPWVXOse/1Q+kufi2SlZA==}
engines: {node: '>= 14'}
peerDependencies:
'@nestjs/common': ^8.0.0 || ^9.0.0 || ^10.0.0 || ^11.0.0
@@ -9774,6 +9774,10 @@ packages:
resolution: {integrity: sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==}
engines: {node: '>= 4'}
reusify@1.0.4:
resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==}
engines: {iojs: '>=1.0.0', node: '>=0.10.0'}
reusify@1.1.0:
resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==}
engines: {iojs: '>=1.0.0', node: '>=0.10.0'}
@@ -11330,8 +11334,8 @@ packages:
vuetify-nuxt-module@0.18.4:
resolution: {integrity: sha512-UzpwKY5Db0sdh+J0o0uGkmVHT1MAcef7urkWsOTSzz8Z6m0iKH5JONn/yX8mUQQyquPwNMxZr/8H1DNLsVqLvQ==}
vuetify@3.7.18:
resolution: {integrity: sha512-JDkPIaug4hP9c+K/wxSgmTiLTMjBTYv2ATPvudhkRKuhsoym89aWCXb1CVbs7FRYuRsJEOGojpwpL5rBfDDy9g==}
vuetify@3.7.17:
resolution: {integrity: sha512-VUxCUwu5BT9/e0NVDAhA4Dhcx8bHeo5FtSAqraD1YdUJYxzgXQKwUUBhOLWB9UkHVNkulsfJtvZonHS3/7tRSw==}
engines: {node: ^12.20 || >=14.13}
peerDependencies:
typescript: '>=4.7'
@@ -12753,8 +12757,6 @@ snapshots:
'@fastify/error@4.0.0': {}
'@fastify/error@4.1.0': {}
'@fastify/fast-json-stringify-compiler@5.0.2':
dependencies:
fast-json-stringify: 6.0.1
@@ -12777,10 +12779,10 @@ snapshots:
'@fastify/middie@9.0.3':
dependencies:
'@fastify/error': 4.1.0
'@fastify/error': 4.0.0
fastify-plugin: 5.0.1
path-to-regexp: 8.2.0
reusify: 1.1.0
reusify: 1.0.4
'@fastify/proxy-addr@5.0.0':
dependencies:
@@ -12812,10 +12814,10 @@ snapshots:
- '@vue/composition-api'
- vue
'@golevelup/nestjs-discovery@4.0.3(@nestjs/common@11.0.12(reflect-metadata@0.1.14)(rxjs@7.8.2))(@nestjs/core@11.0.12(@nestjs/common@11.0.12(reflect-metadata@0.1.14)(rxjs@7.8.2))(reflect-metadata@0.1.14)(rxjs@7.8.2))':
'@golevelup/nestjs-discovery@4.0.3(@nestjs/common@11.0.11(reflect-metadata@0.1.14)(rxjs@7.8.2))(@nestjs/core@11.0.11(@nestjs/common@11.0.11(reflect-metadata@0.1.14)(rxjs@7.8.2))(reflect-metadata@0.1.14)(rxjs@7.8.2))':
dependencies:
'@nestjs/common': 11.0.12(reflect-metadata@0.1.14)(rxjs@7.8.2)
'@nestjs/core': 11.0.12(@nestjs/common@11.0.12(reflect-metadata@0.1.14)(rxjs@7.8.2))(reflect-metadata@0.1.14)(rxjs@7.8.2)
'@nestjs/common': 11.0.11(reflect-metadata@0.1.14)(rxjs@7.8.2)
'@nestjs/core': 11.0.11(@nestjs/common@11.0.11(reflect-metadata@0.1.14)(rxjs@7.8.2))(reflect-metadata@0.1.14)(rxjs@7.8.2)
lodash: 4.17.21
'@graphql-codegen/add@3.2.3(graphql@16.10.0)':
@@ -13278,7 +13280,7 @@ snapshots:
'@graphql-tools/optimize@1.4.0(graphql@16.10.0)':
dependencies:
graphql: 16.10.0
tslib: 2.6.3
tslib: 2.8.1
'@graphql-tools/optimize@2.0.0(graphql@16.10.0)':
dependencies:
@@ -13318,7 +13320,7 @@ snapshots:
'@ardatan/relay-compiler': 12.0.0(graphql@16.10.0)
'@graphql-tools/utils': 9.2.1(graphql@16.10.0)
graphql: 16.10.0
tslib: 2.6.3
tslib: 2.8.1
transitivePeerDependencies:
- encoding
- supports-color
@@ -13337,7 +13339,7 @@ snapshots:
'@ardatan/relay-compiler': 12.0.3(graphql@16.10.0)
'@graphql-tools/utils': 10.8.6(graphql@16.10.0)
graphql: 16.10.0
tslib: 2.6.3
tslib: 2.8.1
transitivePeerDependencies:
- encoding
@@ -13404,13 +13406,13 @@ snapshots:
'@graphql-tools/utils@8.13.1(graphql@16.10.0)':
dependencies:
graphql: 16.10.0
tslib: 2.6.3
tslib: 2.8.1
'@graphql-tools/utils@9.2.1(graphql@16.10.0)':
dependencies:
'@graphql-typed-document-node/core': 3.2.0(graphql@16.10.0)
graphql: 16.10.0
tslib: 2.6.3
tslib: 2.8.1
'@graphql-tools/wrap@10.0.30(graphql@16.10.0)':
dependencies:
@@ -13538,7 +13540,7 @@ snapshots:
lodash: 4.17.21
vue: 3.5.13(typescript@5.8.2)
'@jsonforms/vue-vuetify@3.5.1(@jsonforms/core@3.5.1)(@jsonforms/vue@3.5.1(@jsonforms/core@3.5.1)(vue@3.5.13(typescript@5.8.2)))(ajv@8.17.1)(dayjs@1.11.13)(lodash@4.17.21)(maska@2.1.11)(vue@3.5.13(typescript@5.8.2))(vuetify@3.7.18)':
'@jsonforms/vue-vuetify@3.5.1(@jsonforms/core@3.5.1)(@jsonforms/vue@3.5.1(@jsonforms/core@3.5.1)(vue@3.5.13(typescript@5.8.2)))(ajv@8.17.1)(dayjs@1.11.13)(lodash@4.17.21)(maska@2.1.11)(vue@3.5.13(typescript@5.8.2))(vuetify@3.7.17)':
dependencies:
'@jsonforms/core': 3.5.1
'@jsonforms/vue': 3.5.1(@jsonforms/core@3.5.1)(vue@3.5.13(typescript@5.8.2))
@@ -13547,7 +13549,7 @@ snapshots:
lodash: 4.17.21
maska: 2.1.11
vue: 3.5.13(typescript@5.8.2)
vuetify: 3.7.18(typescript@5.8.2)(vite-plugin-vuetify@2.1.0)(vue@3.5.13(typescript@5.8.2))
vuetify: 3.7.17(typescript@5.8.2)(vite-plugin-vuetify@2.1.0)(vue@3.5.13(typescript@5.8.2))
'@jsonforms/vue@3.5.1(@jsonforms/core@3.5.1)(vue@3.5.13(typescript@5.8.2))':
dependencies:
@@ -13665,13 +13667,13 @@ snapshots:
'@tybys/wasm-util': 0.9.0
optional: true
'@nestjs/apollo@13.0.3(@apollo/server@4.11.3(graphql@16.10.0))(@as-integrations/fastify@2.1.1(@apollo/server@4.11.3(graphql@16.10.0))(fastify@5.2.1))(@nestjs/common@11.0.12(reflect-metadata@0.1.14)(rxjs@7.8.2))(@nestjs/core@11.0.12(@nestjs/common@11.0.12(reflect-metadata@0.1.14)(rxjs@7.8.2))(reflect-metadata@0.1.14)(rxjs@7.8.2))(@nestjs/graphql@13.0.3(@nestjs/common@11.0.12(reflect-metadata@0.1.14)(rxjs@7.8.2))(@nestjs/core@11.0.12(@nestjs/common@11.0.12(reflect-metadata@0.1.14)(rxjs@7.8.2))(reflect-metadata@0.1.14)(rxjs@7.8.2))(graphql@16.10.0)(reflect-metadata@0.1.14)(ts-morph@24.0.0))(graphql@16.10.0)':
'@nestjs/apollo@13.0.3(@apollo/server@4.11.3(graphql@16.10.0))(@as-integrations/fastify@2.1.1(@apollo/server@4.11.3(graphql@16.10.0))(fastify@5.2.1))(@nestjs/common@11.0.11(reflect-metadata@0.1.14)(rxjs@7.8.2))(@nestjs/core@11.0.11(@nestjs/common@11.0.11(reflect-metadata@0.1.14)(rxjs@7.8.2))(reflect-metadata@0.1.14)(rxjs@7.8.2))(@nestjs/graphql@13.0.3(@nestjs/common@11.0.11(reflect-metadata@0.1.14)(rxjs@7.8.2))(@nestjs/core@11.0.11(@nestjs/common@11.0.11(reflect-metadata@0.1.14)(rxjs@7.8.2))(reflect-metadata@0.1.14)(rxjs@7.8.2))(graphql@16.10.0)(reflect-metadata@0.1.14)(ts-morph@24.0.0))(graphql@16.10.0)':
dependencies:
'@apollo/server': 4.11.3(graphql@16.10.0)
'@apollo/server-plugin-landing-page-graphql-playground': 4.0.1(@apollo/server@4.11.3(graphql@16.10.0))
'@nestjs/common': 11.0.12(reflect-metadata@0.1.14)(rxjs@7.8.2)
'@nestjs/core': 11.0.12(@nestjs/common@11.0.12(reflect-metadata@0.1.14)(rxjs@7.8.2))(reflect-metadata@0.1.14)(rxjs@7.8.2)
'@nestjs/graphql': 13.0.3(@nestjs/common@11.0.12(reflect-metadata@0.1.14)(rxjs@7.8.2))(@nestjs/core@11.0.12(@nestjs/common@11.0.12(reflect-metadata@0.1.14)(rxjs@7.8.2))(reflect-metadata@0.1.14)(rxjs@7.8.2))(graphql@16.10.0)(reflect-metadata@0.1.14)(ts-morph@24.0.0)
'@nestjs/common': 11.0.11(reflect-metadata@0.1.14)(rxjs@7.8.2)
'@nestjs/core': 11.0.11(@nestjs/common@11.0.11(reflect-metadata@0.1.14)(rxjs@7.8.2))(reflect-metadata@0.1.14)(rxjs@7.8.2)
'@nestjs/graphql': 13.0.3(@nestjs/common@11.0.11(reflect-metadata@0.1.14)(rxjs@7.8.2))(@nestjs/core@11.0.11(@nestjs/common@11.0.11(reflect-metadata@0.1.14)(rxjs@7.8.2))(reflect-metadata@0.1.14)(rxjs@7.8.2))(graphql@16.10.0)(reflect-metadata@0.1.14)(ts-morph@24.0.0)
graphql: 16.10.0
iterall: 1.3.0
lodash.omit: 4.5.0
@@ -13679,7 +13681,7 @@ snapshots:
optionalDependencies:
'@as-integrations/fastify': 2.1.1(@apollo/server@4.11.3(graphql@16.10.0))(fastify@5.2.1)
'@nestjs/common@11.0.12(reflect-metadata@0.1.14)(rxjs@7.8.2)':
'@nestjs/common@11.0.11(reflect-metadata@0.1.14)(rxjs@7.8.2)':
dependencies:
iterare: 1.2.1
reflect-metadata: 0.1.14
@@ -13687,9 +13689,9 @@ snapshots:
tslib: 2.8.1
uid: 2.0.2
'@nestjs/core@11.0.12(@nestjs/common@11.0.12(reflect-metadata@0.1.14)(rxjs@7.8.2))(reflect-metadata@0.1.14)(rxjs@7.8.2)':
'@nestjs/core@11.0.11(@nestjs/common@11.0.11(reflect-metadata@0.1.14)(rxjs@7.8.2))(reflect-metadata@0.1.14)(rxjs@7.8.2)':
dependencies:
'@nestjs/common': 11.0.12(reflect-metadata@0.1.14)(rxjs@7.8.2)
'@nestjs/common': 11.0.11(reflect-metadata@0.1.14)(rxjs@7.8.2)
'@nuxt/opencollective': 0.4.1
fast-safe-stringify: 2.1.1
iterare: 1.2.1
@@ -13699,14 +13701,14 @@ snapshots:
tslib: 2.8.1
uid: 2.0.2
'@nestjs/graphql@13.0.3(@nestjs/common@11.0.12(reflect-metadata@0.1.14)(rxjs@7.8.2))(@nestjs/core@11.0.12(@nestjs/common@11.0.12(reflect-metadata@0.1.14)(rxjs@7.8.2))(reflect-metadata@0.1.14)(rxjs@7.8.2))(graphql@16.10.0)(reflect-metadata@0.1.14)(ts-morph@24.0.0)':
'@nestjs/graphql@13.0.3(@nestjs/common@11.0.11(reflect-metadata@0.1.14)(rxjs@7.8.2))(@nestjs/core@11.0.11(@nestjs/common@11.0.11(reflect-metadata@0.1.14)(rxjs@7.8.2))(reflect-metadata@0.1.14)(rxjs@7.8.2))(graphql@16.10.0)(reflect-metadata@0.1.14)(ts-morph@24.0.0)':
dependencies:
'@graphql-tools/merge': 9.0.19(graphql@16.10.0)
'@graphql-tools/schema': 10.0.18(graphql@16.10.0)
'@graphql-tools/utils': 10.8.1(graphql@16.10.0)
'@nestjs/common': 11.0.12(reflect-metadata@0.1.14)(rxjs@7.8.2)
'@nestjs/core': 11.0.12(@nestjs/common@11.0.12(reflect-metadata@0.1.14)(rxjs@7.8.2))(reflect-metadata@0.1.14)(rxjs@7.8.2)
'@nestjs/mapped-types': 2.1.0(@nestjs/common@11.0.12(reflect-metadata@0.1.14)(rxjs@7.8.2))(reflect-metadata@0.1.14)
'@nestjs/common': 11.0.11(reflect-metadata@0.1.14)(rxjs@7.8.2)
'@nestjs/core': 11.0.11(@nestjs/common@11.0.11(reflect-metadata@0.1.14)(rxjs@7.8.2))(reflect-metadata@0.1.14)(rxjs@7.8.2)
'@nestjs/mapped-types': 2.1.0(@nestjs/common@11.0.11(reflect-metadata@0.1.14)(rxjs@7.8.2))(reflect-metadata@0.1.14)
chokidar: 4.0.3
fast-glob: 3.3.3
graphql: 16.10.0
@@ -13726,45 +13728,45 @@ snapshots:
- uWebSockets.js
- utf-8-validate
'@nestjs/mapped-types@2.1.0(@nestjs/common@11.0.12(reflect-metadata@0.1.14)(rxjs@7.8.2))(reflect-metadata@0.1.14)':
'@nestjs/mapped-types@2.1.0(@nestjs/common@11.0.11(reflect-metadata@0.1.14)(rxjs@7.8.2))(reflect-metadata@0.1.14)':
dependencies:
'@nestjs/common': 11.0.12(reflect-metadata@0.1.14)(rxjs@7.8.2)
'@nestjs/common': 11.0.11(reflect-metadata@0.1.14)(rxjs@7.8.2)
reflect-metadata: 0.1.14
'@nestjs/passport@11.0.5(@nestjs/common@11.0.12(reflect-metadata@0.1.14)(rxjs@7.8.2))(passport@0.7.0)':
'@nestjs/passport@11.0.5(@nestjs/common@11.0.11(reflect-metadata@0.1.14)(rxjs@7.8.2))(passport@0.7.0)':
dependencies:
'@nestjs/common': 11.0.12(reflect-metadata@0.1.14)(rxjs@7.8.2)
'@nestjs/common': 11.0.11(reflect-metadata@0.1.14)(rxjs@7.8.2)
passport: 0.7.0
'@nestjs/platform-fastify@11.0.12(@nestjs/common@11.0.12(reflect-metadata@0.1.14)(rxjs@7.8.2))(@nestjs/core@11.0.12(@nestjs/common@11.0.12(reflect-metadata@0.1.14)(rxjs@7.8.2))(reflect-metadata@0.1.14)(rxjs@7.8.2))':
'@nestjs/platform-fastify@11.0.11(@nestjs/common@11.0.11(reflect-metadata@0.1.14)(rxjs@7.8.2))(@nestjs/core@11.0.11(@nestjs/common@11.0.11(reflect-metadata@0.1.14)(rxjs@7.8.2))(reflect-metadata@0.1.14)(rxjs@7.8.2))':
dependencies:
'@fastify/cors': 11.0.0
'@fastify/formbody': 8.0.2
'@fastify/middie': 9.0.3
'@nestjs/common': 11.0.12(reflect-metadata@0.1.14)(rxjs@7.8.2)
'@nestjs/core': 11.0.12(@nestjs/common@11.0.12(reflect-metadata@0.1.14)(rxjs@7.8.2))(reflect-metadata@0.1.14)(rxjs@7.8.2)
'@nestjs/common': 11.0.11(reflect-metadata@0.1.14)(rxjs@7.8.2)
'@nestjs/core': 11.0.11(@nestjs/common@11.0.11(reflect-metadata@0.1.14)(rxjs@7.8.2))(reflect-metadata@0.1.14)(rxjs@7.8.2)
fast-querystring: 1.1.2
fastify: 5.2.1
light-my-request: 6.6.0
path-to-regexp: 8.2.0
tslib: 2.8.1
'@nestjs/schedule@5.0.1(@nestjs/common@11.0.12(reflect-metadata@0.1.14)(rxjs@7.8.2))(@nestjs/core@11.0.12(@nestjs/common@11.0.12(reflect-metadata@0.1.14)(rxjs@7.8.2))(reflect-metadata@0.1.14)(rxjs@7.8.2))':
'@nestjs/schedule@5.0.1(@nestjs/common@11.0.11(reflect-metadata@0.1.14)(rxjs@7.8.2))(@nestjs/core@11.0.11(@nestjs/common@11.0.11(reflect-metadata@0.1.14)(rxjs@7.8.2))(reflect-metadata@0.1.14)(rxjs@7.8.2))':
dependencies:
'@nestjs/common': 11.0.12(reflect-metadata@0.1.14)(rxjs@7.8.2)
'@nestjs/core': 11.0.12(@nestjs/common@11.0.12(reflect-metadata@0.1.14)(rxjs@7.8.2))(reflect-metadata@0.1.14)(rxjs@7.8.2)
'@nestjs/common': 11.0.11(reflect-metadata@0.1.14)(rxjs@7.8.2)
'@nestjs/core': 11.0.11(@nestjs/common@11.0.11(reflect-metadata@0.1.14)(rxjs@7.8.2))(reflect-metadata@0.1.14)(rxjs@7.8.2)
cron: 3.5.0
'@nestjs/testing@11.0.12(@nestjs/common@11.0.12(reflect-metadata@0.1.14)(rxjs@7.8.2))(@nestjs/core@11.0.12(@nestjs/common@11.0.12(reflect-metadata@0.1.14)(rxjs@7.8.2))(reflect-metadata@0.1.14)(rxjs@7.8.2))':
'@nestjs/testing@11.0.11(@nestjs/common@11.0.11(reflect-metadata@0.1.14)(rxjs@7.8.2))(@nestjs/core@11.0.11(@nestjs/common@11.0.11(reflect-metadata@0.1.14)(rxjs@7.8.2))(reflect-metadata@0.1.14)(rxjs@7.8.2))':
dependencies:
'@nestjs/common': 11.0.12(reflect-metadata@0.1.14)(rxjs@7.8.2)
'@nestjs/core': 11.0.12(@nestjs/common@11.0.12(reflect-metadata@0.1.14)(rxjs@7.8.2))(reflect-metadata@0.1.14)(rxjs@7.8.2)
'@nestjs/common': 11.0.11(reflect-metadata@0.1.14)(rxjs@7.8.2)
'@nestjs/core': 11.0.11(@nestjs/common@11.0.11(reflect-metadata@0.1.14)(rxjs@7.8.2))(reflect-metadata@0.1.14)(rxjs@7.8.2)
tslib: 2.8.1
'@nestjs/throttler@6.4.0(@nestjs/common@11.0.12(reflect-metadata@0.1.14)(rxjs@7.8.2))(@nestjs/core@11.0.12(@nestjs/common@11.0.12(reflect-metadata@0.1.14)(rxjs@7.8.2))(reflect-metadata@0.1.14)(rxjs@7.8.2))(reflect-metadata@0.1.14)':
'@nestjs/throttler@6.4.0(@nestjs/common@11.0.11(reflect-metadata@0.1.14)(rxjs@7.8.2))(@nestjs/core@11.0.11(@nestjs/common@11.0.11(reflect-metadata@0.1.14)(rxjs@7.8.2))(reflect-metadata@0.1.14)(rxjs@7.8.2))(reflect-metadata@0.1.14)':
dependencies:
'@nestjs/common': 11.0.12(reflect-metadata@0.1.14)(rxjs@7.8.2)
'@nestjs/core': 11.0.12(@nestjs/common@11.0.12(reflect-metadata@0.1.14)(rxjs@7.8.2))(reflect-metadata@0.1.14)(rxjs@7.8.2)
'@nestjs/common': 11.0.11(reflect-metadata@0.1.14)(rxjs@7.8.2)
'@nestjs/core': 11.0.11(@nestjs/common@11.0.11(reflect-metadata@0.1.14)(rxjs@7.8.2))(reflect-metadata@0.1.14)(rxjs@7.8.2)
reflect-metadata: 0.1.14
'@netlify/functions@3.0.0':
@@ -15650,11 +15652,11 @@ snapshots:
dependencies:
'@vue/compiler-core': 3.5.13
'@vuetify/loader-shared@2.1.0(vue@3.5.13(typescript@5.8.2))(vuetify@3.7.18)':
'@vuetify/loader-shared@2.1.0(vue@3.5.13(typescript@5.8.2))(vuetify@3.7.17)':
dependencies:
upath: 2.0.1
vue: 3.5.13(typescript@5.8.2)
vuetify: 3.7.18(typescript@5.8.2)(vite-plugin-vuetify@2.1.0)(vue@3.5.13(typescript@5.8.2))
vuetify: 3.7.17(typescript@5.8.2)(vite-plugin-vuetify@2.1.0)(vue@3.5.13(typescript@5.8.2))
'@vueuse/components@13.0.0(vue@3.5.13(typescript@5.8.2))':
dependencies:
@@ -18321,7 +18323,7 @@ snapshots:
fastq@1.19.0:
dependencies:
reusify: 1.1.0
reusify: 1.0.4
fastq@1.19.1:
dependencies:
@@ -18868,7 +18870,7 @@ snapshots:
transitivePeerDependencies:
- encoding
graphql-scalars@1.24.2(graphql@16.10.0):
graphql-scalars@1.24.1(graphql@16.10.0):
dependencies:
graphql: 16.10.0
tslib: 2.8.1
@@ -19399,7 +19401,7 @@ snapshots:
is-lower-case@2.0.2:
dependencies:
tslib: 2.6.3
tslib: 2.8.1
is-map@2.0.3: {}
@@ -19494,7 +19496,7 @@ snapshots:
is-upper-case@2.0.2:
dependencies:
tslib: 2.6.3
tslib: 2.8.1
is-utf8@0.2.1: {}
@@ -19983,11 +19985,11 @@ snapshots:
lower-case-first@2.0.2:
dependencies:
tslib: 2.6.3
tslib: 2.8.1
lower-case@2.0.2:
dependencies:
tslib: 2.6.3
tslib: 2.8.1
lowercase-keys@3.0.0: {}
@@ -20267,20 +20269,20 @@ snapshots:
neo-async@2.6.2: {}
nest-authz@2.15.0(@nestjs/common@11.0.12(reflect-metadata@0.1.14)(rxjs@7.8.2))(@nestjs/core@11.0.12(@nestjs/common@11.0.12(reflect-metadata@0.1.14)(rxjs@7.8.2))(reflect-metadata@0.1.14)(rxjs@7.8.2))(reflect-metadata@0.1.14)(rxjs@7.8.2):
nest-authz@2.15.0(@nestjs/common@11.0.11(reflect-metadata@0.1.14)(rxjs@7.8.2))(@nestjs/core@11.0.11(@nestjs/common@11.0.11(reflect-metadata@0.1.14)(rxjs@7.8.2))(reflect-metadata@0.1.14)(rxjs@7.8.2))(reflect-metadata@0.1.14)(rxjs@7.8.2):
dependencies:
'@nestjs/common': 11.0.12(reflect-metadata@0.1.14)(rxjs@7.8.2)
'@nestjs/core': 11.0.12(@nestjs/common@11.0.12(reflect-metadata@0.1.14)(rxjs@7.8.2))(reflect-metadata@0.1.14)(rxjs@7.8.2)
'@nestjs/common': 11.0.11(reflect-metadata@0.1.14)(rxjs@7.8.2)
'@nestjs/core': 11.0.11(@nestjs/common@11.0.11(reflect-metadata@0.1.14)(rxjs@7.8.2))(reflect-metadata@0.1.14)(rxjs@7.8.2)
casbin: 5.38.0
reflect-metadata: 0.1.14
rxjs: 7.8.2
nest-commander@3.17.0(@nestjs/common@11.0.12(reflect-metadata@0.1.14)(rxjs@7.8.2))(@nestjs/core@11.0.12(@nestjs/common@11.0.12(reflect-metadata@0.1.14)(rxjs@7.8.2))(reflect-metadata@0.1.14)(rxjs@7.8.2))(@types/inquirer@8.2.10)(typescript@5.8.2):
nest-commander@3.17.0(@nestjs/common@11.0.11(reflect-metadata@0.1.14)(rxjs@7.8.2))(@nestjs/core@11.0.11(@nestjs/common@11.0.11(reflect-metadata@0.1.14)(rxjs@7.8.2))(reflect-metadata@0.1.14)(rxjs@7.8.2))(@types/inquirer@8.2.10)(typescript@5.8.2):
dependencies:
'@fig/complete-commander': 3.2.0(commander@11.1.0)
'@golevelup/nestjs-discovery': 4.0.3(@nestjs/common@11.0.12(reflect-metadata@0.1.14)(rxjs@7.8.2))(@nestjs/core@11.0.12(@nestjs/common@11.0.12(reflect-metadata@0.1.14)(rxjs@7.8.2))(reflect-metadata@0.1.14)(rxjs@7.8.2))
'@nestjs/common': 11.0.12(reflect-metadata@0.1.14)(rxjs@7.8.2)
'@nestjs/core': 11.0.12(@nestjs/common@11.0.12(reflect-metadata@0.1.14)(rxjs@7.8.2))(reflect-metadata@0.1.14)(rxjs@7.8.2)
'@golevelup/nestjs-discovery': 4.0.3(@nestjs/common@11.0.11(reflect-metadata@0.1.14)(rxjs@7.8.2))(@nestjs/core@11.0.11(@nestjs/common@11.0.11(reflect-metadata@0.1.14)(rxjs@7.8.2))(reflect-metadata@0.1.14)(rxjs@7.8.2))
'@nestjs/common': 11.0.11(reflect-metadata@0.1.14)(rxjs@7.8.2)
'@nestjs/core': 11.0.11(@nestjs/common@11.0.11(reflect-metadata@0.1.14)(rxjs@7.8.2))(reflect-metadata@0.1.14)(rxjs@7.8.2)
'@types/inquirer': 8.2.10
commander: 11.1.0
cosmiconfig: 8.3.6(typescript@5.8.2)
@@ -20288,9 +20290,9 @@ snapshots:
transitivePeerDependencies:
- typescript
nestjs-pino@4.4.0(@nestjs/common@11.0.12(reflect-metadata@0.1.14)(rxjs@7.8.2))(pino-http@10.4.0)(pino@9.6.0)(rxjs@7.8.2):
nestjs-pino@4.3.1(@nestjs/common@11.0.11(reflect-metadata@0.1.14)(rxjs@7.8.2))(pino-http@10.4.0)(pino@9.6.0)(rxjs@7.8.2):
dependencies:
'@nestjs/common': 11.0.12(reflect-metadata@0.1.14)(rxjs@7.8.2)
'@nestjs/common': 11.0.11(reflect-metadata@0.1.14)(rxjs@7.8.2)
pino: 9.6.0
pino-http: 10.4.0
rxjs: 7.8.2
@@ -22013,6 +22015,8 @@ snapshots:
retry@0.13.1: {}
reusify@1.0.4: {}
reusify@1.1.0: {}
rfdc@1.4.1: {}
@@ -22480,7 +22484,7 @@ snapshots:
sponge-case@1.0.1:
dependencies:
tslib: 2.6.3
tslib: 2.8.1
sprintf-js@1.0.3: {}
@@ -22735,7 +22739,7 @@ snapshots:
swap-case@2.0.2:
dependencies:
tslib: 2.6.3
tslib: 2.8.1
symbol-observable@1.2.0: {}
@@ -22934,7 +22938,7 @@ snapshots:
title-case@3.0.3:
dependencies:
tslib: 2.6.3
tslib: 2.8.1
tldts-core@6.1.78: {}
@@ -23321,11 +23325,11 @@ snapshots:
upper-case-first@2.0.2:
dependencies:
tslib: 2.6.3
tslib: 2.8.1
upper-case@2.0.2:
dependencies:
tslib: 2.6.3
tslib: 2.8.1
uqr@0.1.2: {}
@@ -23537,14 +23541,14 @@ snapshots:
vite: 6.2.2(@types/node@22.13.10)(jiti@2.4.2)(stylus@0.57.0)(terser@5.39.0)(tsx@4.19.3)(yaml@2.7.0)
vue: 3.5.13(typescript@5.8.2)
vite-plugin-vuetify@2.1.0(vite@6.2.2(@types/node@22.13.10)(jiti@2.4.2)(stylus@0.57.0)(terser@5.39.0)(tsx@4.19.3)(yaml@2.7.0))(vue@3.5.13(typescript@5.8.2))(vuetify@3.7.18):
vite-plugin-vuetify@2.1.0(vite@6.2.2(@types/node@22.13.10)(jiti@2.4.2)(stylus@0.57.0)(terser@5.39.0)(tsx@4.19.3)(yaml@2.7.0))(vue@3.5.13(typescript@5.8.2))(vuetify@3.7.17):
dependencies:
'@vuetify/loader-shared': 2.1.0(vue@3.5.13(typescript@5.8.2))(vuetify@3.7.18)
'@vuetify/loader-shared': 2.1.0(vue@3.5.13(typescript@5.8.2))(vuetify@3.7.17)
debug: 4.4.0(supports-color@9.4.0)
upath: 2.0.1
vite: 6.2.2(@types/node@22.13.10)(jiti@2.4.2)(stylus@0.57.0)(terser@5.39.0)(tsx@4.19.3)(yaml@2.7.0)
vue: 3.5.13(typescript@5.8.2)
vuetify: 3.7.18(typescript@5.8.2)(vite-plugin-vuetify@2.1.0)(vue@3.5.13(typescript@5.8.2))
vuetify: 3.7.17(typescript@5.8.2)(vite-plugin-vuetify@2.1.0)(vue@3.5.13(typescript@5.8.2))
transitivePeerDependencies:
- supports-color
@@ -23773,8 +23777,8 @@ snapshots:
ufo: 1.5.4
unconfig: 0.5.5
upath: 2.0.1
vite-plugin-vuetify: 2.1.0(vite@6.2.2(@types/node@22.13.10)(jiti@2.4.2)(stylus@0.57.0)(terser@5.39.0)(tsx@4.19.3)(yaml@2.7.0))(vue@3.5.13(typescript@5.8.2))(vuetify@3.7.18)
vuetify: 3.7.18(typescript@5.8.2)(vite-plugin-vuetify@2.1.0)(vue@3.5.13(typescript@5.8.2))
vite-plugin-vuetify: 2.1.0(vite@6.2.2(@types/node@22.13.10)(jiti@2.4.2)(stylus@0.57.0)(terser@5.39.0)(tsx@4.19.3)(yaml@2.7.0))(vue@3.5.13(typescript@5.8.2))(vuetify@3.7.17)
vuetify: 3.7.17(typescript@5.8.2)(vite-plugin-vuetify@2.1.0)(vue@3.5.13(typescript@5.8.2))
transitivePeerDependencies:
- magicast
- supports-color
@@ -23783,12 +23787,12 @@ snapshots:
- vue
- webpack-plugin-vuetify
vuetify@3.7.18(typescript@5.8.2)(vite-plugin-vuetify@2.1.0)(vue@3.5.13(typescript@5.8.2)):
vuetify@3.7.17(typescript@5.8.2)(vite-plugin-vuetify@2.1.0)(vue@3.5.13(typescript@5.8.2)):
dependencies:
vue: 3.5.13(typescript@5.8.2)
optionalDependencies:
typescript: 5.8.2
vite-plugin-vuetify: 2.1.0(vite@6.2.2(@types/node@22.13.10)(jiti@2.4.2)(stylus@0.57.0)(terser@5.39.0)(tsx@4.19.3)(yaml@2.7.0))(vue@3.5.13(typescript@5.8.2))(vuetify@3.7.18)
vite-plugin-vuetify: 2.1.0(vite@6.2.2(@types/node@22.13.10)(jiti@2.4.2)(stylus@0.57.0)(terser@5.39.0)(tsx@4.19.3)(yaml@2.7.0))(vue@3.5.13(typescript@5.8.2))(vuetify@3.7.17)
w3c-xmlserializer@5.0.0:
dependencies:
+12
View File
@@ -14,6 +14,18 @@ const preview: Preview = {
},
},
},
// Add decorator to include modals container in every story
decorators: [
(story) => ({
components: { story },
template: `
<div>
<div id="modals"></div>
<story />
</div>
`,
}),
],
};
export default preview;
+7 -6
View File
@@ -2,17 +2,18 @@
"$schema": "https://shadcn-vue.com/schema.json",
"style": "default",
"typescript": true,
"tsConfigPath": "./tsconfig.json",
"tailwind": {
"config": "./tailwind.config.ts",
"css": "./src/styles/globals.css",
"config": "tailwind.config.ts",
"css": "src/styles/globals.css",
"baseColor": "neutral",
"cssVariables": true,
"prefix": ""
},
"framework": "vite",
"aliases": {
"components": "@/components/common",
"utils": "@/lib/utils"
}
"composables": "@/composables",
"utils": "@/lib/utils",
"lib": "@/lib"
},
"iconLibrary": "lucide"
}
+1 -1
View File
@@ -50,8 +50,8 @@
"kebab-case": "^2.0.1",
"lucide-vue-next": "^0.483.0",
"radix-vue": "^1.9.13",
"reka-ui": "^2.0.2",
"shadcn-vue": "^1.0.0",
"reka-ui": "^2.1.0",
"tailwind-merge": "^2.6.0",
"vue-sonner": "^1.3.0"
},
@@ -1,11 +1,15 @@
<script setup lang="ts">
import { cn } from '@/lib/utils';
import { computed } from 'vue';
import { brandLoadingVariants, markAnimations } from './brand-loading.variants';
import {
brandLoadingVariants,
markAnimations,
type BrandLoadingVariants,
} from './brand-loading.variants';
export interface Props {
variant?: 'default' | 'black' | 'white';
size?: 'sm' | 'md' | 'lg' | 'full';
variant?: BrandLoadingVariants['variant'];
size?: BrandLoadingVariants['size'];
class?: string;
title?: string;
}
@@ -22,7 +26,7 @@ const GRADIENT_COLORS = {
default: { start: '#e32929', stop: '#ff8d30' },
} as const;
const gradientColors = computed(() => GRADIENT_COLORS[props.variant]);
const gradientColors = computed(() => GRADIENT_COLORS[props.variant as keyof typeof GRADIENT_COLORS]);
const classes = computed(() => {
return cn(brandLoadingVariants({ variant: props.variant, size: props.size }), props.class);
@@ -1,23 +1,27 @@
import { cva } from 'class-variance-authority';
import { cva, type VariantProps } from 'class-variance-authority';
export const brandLoadingVariants = cva('inline-flex items-center justify-center w-full h-full aspect-[7/4]', {
variants: {
variant: {
default: '',
black: 'text-black fill-black',
white: 'text-white fill-white',
export const brandLoadingVariants = cva(
'inline-flex items-center justify-center w-full h-full aspect-[7/4]',
{
variants: {
variant: {
default: '',
black: 'text-black fill-black',
white: 'text-white fill-white',
},
size: {
sm: 'w-12',
md: 'w-16',
lg: 'w-20',
full: 'w-full',
custom: '',
},
},
size: {
sm: 'w-12',
md: 'w-16',
lg: 'w-20',
full: 'w-full',
defaultVariants: {
variant: 'default',
},
},
defaultVariants: {
variant: 'default',
},
});
}
);
export const markAnimations = {
mark_2_4: 'animate-mark-2',
@@ -25,3 +29,5 @@ export const markAnimations = {
mark_6_8: 'animate-mark-6',
mark_7: 'animate-mark-7',
};
export type BrandLoadingVariants = VariantProps<typeof brandLoadingVariants>;
@@ -1,15 +1,15 @@
<script setup lang="ts">
import {
DropdownMenuRoot,
useForwardPropsEmits,
type DropdownMenuRootEmits,
type DropdownMenuRootProps,
useForwardPropsEmits,
} from "radix-vue";
} from 'reka-ui';
const props = defineProps<DropdownMenuRootProps>();
const emits = defineEmits<DropdownMenuRootEmits>();
const forwarded = useForwardPropsEmits(props, emits);
const forwarded = useForwardPropsEmits<DropdownMenuRootProps, 'update:open'>(props, emits);
</script>
<template>
@@ -0,0 +1,30 @@
<script setup lang="ts">
import { cn } from '@/lib/utils';
import {
DropdownMenuArrow as RekaDropdownMenuArrow,
useForwardProps,
type DropdownMenuArrowProps,
} from 'reka-ui';
import { computed, type HTMLAttributes } from 'vue';
const props = defineProps<DropdownMenuArrowProps & { class?: HTMLAttributes['class'] }>();
const delegatedProps = computed(() => {
const { class: _, ...delegated } = props;
return delegated;
});
const forwardedProps = useForwardProps(delegatedProps);
</script>
<template>
<RekaDropdownMenuArrow
v-bind="forwardedProps"
:class="
cn(
'fill-popover data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95',
props.class
)
"
/>
</template>
@@ -1,18 +1,16 @@
<script setup lang="ts">
import { type HTMLAttributes, computed } from "vue";
import { cn } from '@/lib/utils';
import { Check } from 'lucide-vue-next';
import {
DropdownMenuCheckboxItem,
type DropdownMenuCheckboxItemEmits,
type DropdownMenuCheckboxItemProps,
DropdownMenuItemIndicator,
useForwardPropsEmits,
} from "radix-vue";
import { Check } from "lucide-vue-next";
import { cn } from "@/lib/utils";
type DropdownMenuCheckboxItemEmits,
type DropdownMenuCheckboxItemProps,
} from 'reka-ui';
import { computed, type HTMLAttributes } from 'vue';
const props = defineProps<
DropdownMenuCheckboxItemProps & { class?: HTMLAttributes["class"] }
>();
const props = defineProps<DropdownMenuCheckboxItemProps & { class?: HTMLAttributes['class'] }>();
const emits = defineEmits<DropdownMenuCheckboxItemEmits>();
const delegatedProps = computed(() => {
@@ -1,26 +1,27 @@
<script setup lang="ts">
import { type HTMLAttributes, computed } from "vue";
import useTeleport from '@/composables/useTeleport';
import { cn } from '@/lib/utils';
import {
DropdownMenuContent,
type DropdownMenuContentEmits,
type DropdownMenuContentProps,
DropdownMenuPortal,
useForwardPropsEmits,
} from "radix-vue";
import { cn } from "@/lib/utils";
type DropdownMenuContentEmits,
type DropdownMenuContentProps,
} from 'reka-ui';
import { computed, type HTMLAttributes } from 'vue';
const { teleportTarget } = useTeleport();
const props = withDefaults(
defineProps<DropdownMenuContentProps & { class?: HTMLAttributes["class"] }>(),
defineProps<DropdownMenuContentProps & { class?: HTMLAttributes['class'] }>(),
{
sideOffset: 4,
class: undefined,
}
);
const emits = defineEmits<DropdownMenuContentEmits>();
const delegatedProps = computed(() => {
const { class: _, ...delegated } = props;
return delegated;
});
@@ -28,17 +29,20 @@ const forwarded = useForwardPropsEmits(delegatedProps, emits);
</script>
<template>
<DropdownMenuPortal>
<DropdownMenuPortal :to="teleportTarget">
<DropdownMenuContent
v-bind="forwarded"
side="bottom"
:class="
cn(
'z-50 min-w-32 overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2',
'z-50 min-w-32 rounded-lg bg-popover p-1 text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2',
props.class
)
"
>
<slot />
<div class="overflow-hidden">
<slot />
</div>
</DropdownMenuContent>
</DropdownMenuPortal>
</template>
@@ -1,5 +1,5 @@
<script setup lang="ts">
import { DropdownMenuGroup, type DropdownMenuGroupProps } from "radix-vue";
import { DropdownMenuGroup, type DropdownMenuGroupProps } from 'reka-ui';
const props = defineProps<DropdownMenuGroupProps>();
</script>
@@ -1,14 +1,10 @@
<script setup lang="ts">
import { type HTMLAttributes, computed } from "vue";
import {
DropdownMenuItem,
type DropdownMenuItemProps,
useForwardProps,
} from "radix-vue";
import { cn } from "@/lib/utils";
import { cn } from '@/lib/utils';
import { DropdownMenuItem, useForwardProps, type DropdownMenuItemProps } from 'reka-ui';
import { computed, type HTMLAttributes } from 'vue';
const props = defineProps<
DropdownMenuItemProps & { class?: HTMLAttributes["class"]; inset?: boolean }
DropdownMenuItemProps & { class?: HTMLAttributes['class']; inset?: boolean }
>();
const delegatedProps = computed(() => {
@@ -25,7 +21,7 @@ const forwardedProps = useForwardProps(delegatedProps);
v-bind="forwardedProps"
:class="
cn(
'relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50',
'relative flex cursor-default select-none items-center rounded-sm gap-2 px-2 py-1.5 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&>svg]:size-4 [&>svg]:shrink-0',
inset && 'pl-8',
props.class
)
@@ -1,14 +1,10 @@
<script setup lang="ts">
import { type HTMLAttributes, computed } from "vue";
import {
DropdownMenuLabel,
type DropdownMenuLabelProps,
useForwardProps,
} from "radix-vue";
import { cn } from "@/lib/utils";
import { cn } from '@/lib/utils';
import { DropdownMenuLabel, useForwardProps, type DropdownMenuLabelProps } from 'reka-ui';
import { computed, type HTMLAttributes } from 'vue';
const props = defineProps<
DropdownMenuLabelProps & { class?: HTMLAttributes["class"]; inset?: boolean }
DropdownMenuLabelProps & { class?: HTMLAttributes['class']; inset?: boolean }
>();
const delegatedProps = computed(() => {
@@ -23,9 +19,7 @@ const forwardedProps = useForwardProps(delegatedProps);
<template>
<DropdownMenuLabel
v-bind="forwardedProps"
:class="
cn('px-2 py-1.5 text-sm font-semibold', inset && 'pl-8', props.class)
"
:class="cn('px-2 py-1.5 text-sm font-semibold', inset && 'pl-8', props.class)"
>
<slot />
</DropdownMenuLabel>
@@ -1,15 +1,15 @@
<script setup lang="ts">
import {
DropdownMenuRadioGroup,
useForwardPropsEmits,
type DropdownMenuRadioGroupEmits,
type DropdownMenuRadioGroupProps,
useForwardPropsEmits,
} from "radix-vue";
} from 'reka-ui';
const props = defineProps<DropdownMenuRadioGroupProps>();
const emits = defineEmits<DropdownMenuRadioGroupEmits>();
const forwarded = useForwardPropsEmits(props, emits);
const forwarded = useForwardPropsEmits<DropdownMenuRadioGroupProps, 'update:modelValue'>(props, emits);
</script>
<template>
@@ -1,18 +1,16 @@
<script setup lang="ts">
import { type HTMLAttributes, computed } from "vue";
import { cn } from '@/lib/utils';
import { Circle } from 'lucide-vue-next';
import {
DropdownMenuItemIndicator,
DropdownMenuRadioItem,
useForwardPropsEmits,
type DropdownMenuRadioItemEmits,
type DropdownMenuRadioItemProps,
useForwardPropsEmits,
} from "radix-vue";
import { Circle } from "lucide-vue-next";
import { cn } from "@/lib/utils";
} from 'reka-ui';
import { computed, type HTMLAttributes } from 'vue';
const props = defineProps<
DropdownMenuRadioItemProps & { class?: HTMLAttributes["class"] }
>();
const props = defineProps<DropdownMenuRadioItemProps & { class?: HTMLAttributes['class'] }>();
const emits = defineEmits<DropdownMenuRadioItemEmits>();
@@ -1,14 +1,11 @@
<script setup lang="ts">
import { type HTMLAttributes, computed } from "vue";
import {
DropdownMenuSeparator,
type DropdownMenuSeparatorProps,
} from "radix-vue";
import { cn } from "@/lib/utils";
import { cn } from '@/lib/utils';
import { DropdownMenuSeparator, type DropdownMenuSeparatorProps } from 'reka-ui';
import { computed, type HTMLAttributes } from 'vue';
const props = defineProps<
DropdownMenuSeparatorProps & {
class?: HTMLAttributes["class"];
class?: HTMLAttributes['class'];
}
>();
@@ -20,8 +17,5 @@ const delegatedProps = computed(() => {
</script>
<template>
<DropdownMenuSeparator
v-bind="delegatedProps"
:class="cn('-mx-1 my-1 h-px bg-muted', props.class)"
/>
<DropdownMenuSeparator v-bind="delegatedProps" :class="cn('-mx-1 my-1 h-px bg-muted', props.class)" />
</template>
@@ -1,9 +1,9 @@
<script setup lang="ts">
import type { HTMLAttributes } from "vue";
import { cn } from "@/lib/utils";
import { cn } from '@/lib/utils';
import type { HTMLAttributes } from 'vue';
const props = defineProps<{
class?: HTMLAttributes["class"];
class?: HTMLAttributes['class'];
}>();
</script>
@@ -1,15 +1,15 @@
<script setup lang="ts">
import {
DropdownMenuSub,
useForwardPropsEmits,
type DropdownMenuSubEmits,
type DropdownMenuSubProps,
useForwardPropsEmits,
} from "radix-vue";
} from 'reka-ui';
const props = defineProps<DropdownMenuSubProps>();
const emits = defineEmits<DropdownMenuSubEmits>();
const forwarded = useForwardPropsEmits(props, emits);
const forwarded = useForwardPropsEmits<DropdownMenuSubProps, 'update:open'>(props, emits);
</script>
<template>
@@ -1,16 +1,14 @@
<script setup lang="ts">
import { type HTMLAttributes, computed } from "vue";
import { cn } from '@/lib/utils';
import {
DropdownMenuSubContent,
useForwardPropsEmits,
type DropdownMenuSubContentEmits,
type DropdownMenuSubContentProps,
useForwardPropsEmits,
} from "radix-vue";
import { cn } from "@/lib/utils";
} from 'reka-ui';
import { computed, type HTMLAttributes } from 'vue';
const props = defineProps<
DropdownMenuSubContentProps & { class?: HTMLAttributes["class"] }
>();
const props = defineProps<DropdownMenuSubContentProps & { class?: HTMLAttributes['class'] }>();
const emits = defineEmits<DropdownMenuSubContentEmits>();
const delegatedProps = computed(() => {
@@ -1,16 +1,10 @@
<script setup lang="ts">
import { type HTMLAttributes, computed } from "vue";
import {
DropdownMenuSubTrigger,
type DropdownMenuSubTriggerProps,
useForwardProps,
} from "radix-vue";
import { ChevronRight } from "lucide-vue-next";
import { cn } from "@/lib/utils";
import { cn } from '@/lib/utils';
import { ChevronRight } from 'lucide-vue-next';
import { DropdownMenuSubTrigger, useForwardProps, type DropdownMenuSubTriggerProps } from 'reka-ui';
import { computed, type HTMLAttributes } from 'vue';
const props = defineProps<
DropdownMenuSubTriggerProps & { class?: HTMLAttributes["class"] }
>();
const props = defineProps<DropdownMenuSubTriggerProps & { class?: HTMLAttributes['class'] }>();
const delegatedProps = computed(() => {
const { class: _, ...delegated } = props;
@@ -1,9 +1,9 @@
<script setup lang="ts">
import { DropdownMenuTrigger, type DropdownMenuTriggerProps, useForwardProps } from 'radix-vue'
import { DropdownMenuTrigger, useForwardProps, type DropdownMenuTriggerProps } from 'reka-ui';
const props = defineProps<DropdownMenuTriggerProps>()
const props = defineProps<DropdownMenuTriggerProps>();
const forwardedProps = useForwardProps(props)
const forwardedProps = useForwardProps<DropdownMenuTriggerProps>(props);
</script>
<template>
@@ -1,16 +1,17 @@
export { DropdownMenuPortal } from 'radix-vue'
export { default as DropdownMenu } from './DropdownMenu.vue';
export { default as DropdownMenu } from './DropdownMenu.vue'
export { default as DropdownMenuTrigger } from './DropdownMenuTrigger.vue'
export { default as DropdownMenuContent } from './DropdownMenuContent.vue'
export { default as DropdownMenuGroup } from './DropdownMenuGroup.vue'
export { default as DropdownMenuRadioGroup } from './DropdownMenuRadioGroup.vue'
export { default as DropdownMenuItem } from './DropdownMenuItem.vue'
export { default as DropdownMenuCheckboxItem } from './DropdownMenuCheckboxItem.vue'
export { default as DropdownMenuRadioItem } from './DropdownMenuRadioItem.vue'
export { default as DropdownMenuShortcut } from './DropdownMenuShortcut.vue'
export { default as DropdownMenuSeparator } from './DropdownMenuSeparator.vue'
export { default as DropdownMenuLabel } from './DropdownMenuLabel.vue'
export { default as DropdownMenuSub } from './DropdownMenuSub.vue'
export { default as DropdownMenuSubTrigger } from './DropdownMenuSubTrigger.vue'
export { default as DropdownMenuSubContent } from './DropdownMenuSubContent.vue'
export { default as DropdownMenuCheckboxItem } from './DropdownMenuCheckboxItem.vue';
export { default as DropdownMenuContent } from './DropdownMenuContent.vue';
export { default as DropdownMenuGroup } from './DropdownMenuGroup.vue';
export { default as DropdownMenuItem } from './DropdownMenuItem.vue';
export { default as DropdownMenuLabel } from './DropdownMenuLabel.vue';
export { default as DropdownMenuRadioGroup } from './DropdownMenuRadioGroup.vue';
export { default as DropdownMenuRadioItem } from './DropdownMenuRadioItem.vue';
export { default as DropdownMenuSeparator } from './DropdownMenuSeparator.vue';
export { default as DropdownMenuShortcut } from './DropdownMenuShortcut.vue';
export { default as DropdownMenuSub } from './DropdownMenuSub.vue';
export { default as DropdownMenuSubContent } from './DropdownMenuSubContent.vue';
export { default as DropdownMenuSubTrigger } from './DropdownMenuSubTrigger.vue';
export { default as DropdownMenuTrigger } from './DropdownMenuTrigger.vue';
export { default as DropdownMenuArrow } from './DropdownMenuArrow.vue';
export { DropdownMenuPortal } from 'reka-ui';
@@ -1,11 +1,11 @@
<script setup lang="ts">
import type { PopoverRootEmits, PopoverRootProps } from 'radix-vue'
import { PopoverRoot, useForwardPropsEmits } from 'radix-vue'
import type { PopoverRootEmits, PopoverRootProps } from 'reka-ui';
import { PopoverRoot, useForwardPropsEmits } from 'reka-ui';
const props = defineProps<PopoverRootProps>()
const emits = defineEmits<PopoverRootEmits>()
const props = defineProps<PopoverRootProps>();
const emits = defineEmits<PopoverRootEmits>();
const forwarded = useForwardPropsEmits(props, emits)
const forwarded = useForwardPropsEmits<PopoverRootProps, 'update:open'>(props, emits);
</script>
<template>
@@ -1,35 +1,32 @@
<script setup lang="ts">
import type { PopoverContentEmits, PopoverContentProps } from 'radix-vue'
import type { HTMLAttributes } from 'vue'
import { cn } from '@/lib/utils'
import { cn } from '@/lib/utils';
import {
PopoverArrow,
PopoverContent,
PopoverPortal,
useForwardPropsEmits,
} from 'radix-vue'
import { computed } from 'vue'
type PopoverContentEmits,
type PopoverContentProps,
} from 'reka-ui';
import { computed, type HTMLAttributes } from 'vue';
defineOptions({
inheritAttrs: false,
})
});
const props = withDefaults(
defineProps<PopoverContentProps & { class?: HTMLAttributes['class'] }>(),
{
align: 'center',
sideOffset: 4,
},
)
const emits = defineEmits<PopoverContentEmits>()
const props = withDefaults(defineProps<PopoverContentProps & { class?: HTMLAttributes['class'] }>(), {
align: 'center',
sideOffset: 4,
});
const emits = defineEmits<PopoverContentEmits>();
const delegatedProps = computed(() => {
const { class: _, ...delegated } = props
const { class: _, ...delegated } = props;
return delegated
})
return delegated;
});
const forwarded = useForwardPropsEmits(delegatedProps, emits)
const forwarded = useForwardPropsEmits(delegatedProps, emits);
</script>
<template>
@@ -38,12 +35,13 @@ const forwarded = useForwardPropsEmits(delegatedProps, emits)
v-bind="{ ...forwarded, ...$attrs }"
:class="
cn(
'z-50 w-72 rounded-md border bg-popover p-4 text-popover-foreground shadow-md outline-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2',
props.class,
'z-50 w-72 rounded-md bg-popover p-4 text-popover-foreground shadow-md outline-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2',
props.class
)
"
>
<slot />
<PopoverArrow :rounded="true" class="fill-popover" />
</PopoverContent>
</PopoverPortal>
</template>
@@ -1,6 +1,5 @@
<script setup lang="ts">
import type { PopoverTriggerProps } from 'radix-vue'
import { PopoverTrigger } from 'radix-vue'
import { PopoverTrigger, type PopoverTriggerProps } from 'reka-ui'
const props = defineProps<PopoverTriggerProps>()
</script>
@@ -1,39 +1,30 @@
<script setup lang="ts">
import { ref, onUnmounted } from "vue";
import {
DialogRoot,
useForwardPropsEmits,
type DialogRootEmits,
type DialogRootProps,
} from "radix-vue";
import { DialogRoot, useForwardPropsEmits, type DialogRootEmits, type DialogRootProps } from 'reka-ui';
import { onUnmounted, ref } from 'vue';
const MOBILE_VIEWPORT =
"width=device-width, initial-scale=1, maximum-scale=1, user-scalable=0" as const;
const MOBILE_VIEWPORT = 'width=device-width, initial-scale=1, maximum-scale=1, user-scalable=0' as const;
const props = defineProps<DialogRootProps & { class?: string }>();
const emits = defineEmits<DialogRootEmits>();
const getViewport = (): string => {
return (
document.querySelector('meta[name="viewport"]')?.getAttribute("content") ??
"width=1300"
);
return document.querySelector('meta[name="viewport"]')?.getAttribute('content') ?? 'width=1300';
};
const updateViewport = (viewport: string): void => {
if (window.innerWidth < 500) {
const meta = document.querySelector('meta[name="viewport"]');
if (meta) {
meta.setAttribute("content", viewport);
meta.setAttribute('content', viewport);
} else {
const meta = document.createElement("meta");
meta.name = "viewport";
const meta = document.createElement('meta');
meta.name = 'viewport';
meta.content = viewport;
document.head.appendChild(meta);
}
}
};
const forwarded = useForwardPropsEmits(props, emits);
const forwarded = useForwardPropsEmits(props, emits) as any;
const initialViewport = ref(getViewport());
const openListener = (opened: boolean) => {
if (opened) {
@@ -1,7 +1,7 @@
<script setup lang="ts">
import { DialogClose, type DialogCloseProps } from 'radix-vue'
import { DialogClose, type DialogCloseProps } from 'reka-ui';
const props = defineProps<DialogCloseProps>()
const props = defineProps<DialogCloseProps>();
</script>
<template>
@@ -1,38 +1,35 @@
<script setup lang="ts">
import { type HTMLAttributes, computed } from "vue";
import { cn } from '@/lib/utils';
import { X } from 'lucide-vue-next';
import {
DialogClose,
DialogContent,
type DialogContentEmits,
DialogOverlay,
DialogPortal,
useForwardPropsEmits,
} from "radix-vue";
import { X } from "lucide-vue-next";
import { sheetVariants } from "./sheet.variants";
import { cn } from "@/lib/utils";
type DialogContentEmits,
} from 'reka-ui';
import { computed, type HTMLAttributes } from 'vue';
import { sheetVariants } from './sheet.variants';
export interface SheetContentProps {
side?: "top" | "bottom" | "left" | "right";
padding?: "none" | "md";
class?: HTMLAttributes["class"];
side?: 'top' | 'bottom' | 'left' | 'right';
padding?: 'none' | 'md';
class?: HTMLAttributes['class'];
disabled?: boolean;
forceMount?: boolean;
to?: string | HTMLElement;
}
const props = withDefaults(defineProps<SheetContentProps>(), {
side: "right",
padding: "md",
side: 'right',
padding: 'md',
});
const emits = defineEmits<DialogContentEmits>();
const sheetClass = computed(() => {
return cn(
sheetVariants({ side: props.side, padding: props.padding }),
props.class,
);
return cn(sheetVariants({ side: props.side, padding: props.padding }), props.class);
});
const delegatedProps = computed(() => {
@@ -1,11 +1,9 @@
<script setup lang="ts">
import { type HTMLAttributes, computed } from "vue";
import { DialogDescription, type DialogDescriptionProps } from "radix-vue";
import { cn } from "@/lib/utils";
import { cn } from '@/lib/utils';
import { DialogDescription, type DialogDescriptionProps } from 'reka-ui';
import { computed, type HTMLAttributes } from 'vue';
const props = defineProps<
DialogDescriptionProps & { class?: HTMLAttributes["class"] }
>();
const props = defineProps<DialogDescriptionProps & { class?: HTMLAttributes['class'] }>();
const delegatedProps = computed(() => {
const { class: _, ...delegated } = props;
@@ -15,10 +13,7 @@ const delegatedProps = computed(() => {
</script>
<template>
<DialogDescription
:class="cn('text-sm text-muted-foreground', props.class)"
v-bind="delegatedProps"
>
<DialogDescription :class="cn('text-sm text-muted-foreground', props.class)" v-bind="delegatedProps">
<slot />
</DialogDescription>
</template>
@@ -1,11 +1,9 @@
<script setup lang="ts">
import { type HTMLAttributes, computed } from "vue";
import { DialogTitle, type DialogTitleProps } from "radix-vue";
import { cn } from "@/lib/utils";
import { cn } from '@/lib/utils';
import { DialogTitle, type DialogTitleProps } from 'reka-ui';
import { computed, type HTMLAttributes } from 'vue';
const props = defineProps<
DialogTitleProps & { class?: HTMLAttributes["class"] }
>();
const props = defineProps<DialogTitleProps & { class?: HTMLAttributes['class'] }>();
const delegatedProps = computed(() => {
const { class: _, ...delegated } = props;
@@ -15,10 +13,7 @@ const delegatedProps = computed(() => {
</script>
<template>
<DialogTitle
:class="cn('text-lg font-medium text-foreground', props.class)"
v-bind="delegatedProps"
>
<DialogTitle :class="cn('text-lg font-medium text-foreground', props.class)" v-bind="delegatedProps">
<slot />
</DialogTitle>
</template>
@@ -1,7 +1,7 @@
<script setup lang="ts">
import { DialogTrigger, type DialogTriggerProps } from 'radix-vue'
import { DialogTrigger, type DialogTriggerProps } from 'reka-ui';
const props = defineProps<DialogTriggerProps>()
const props = defineProps<DialogTriggerProps>();
</script>
<template>
@@ -1,11 +1,12 @@
<script setup lang="ts">
import { TabsRoot, useForwardPropsEmits } from 'radix-vue'
import type { TabsRootEmits, TabsRootProps } from 'radix-vue'
import { TabsRoot, useForwardPropsEmits } from 'radix-vue';
import type { TabsRootEmits, TabsRootProps } from 'radix-vue';
import type { HTMLAttributes } from 'vue';
const props = defineProps<TabsRootProps>()
const emits = defineEmits<TabsRootEmits>()
const props = defineProps<TabsRootProps>();
const emits = defineEmits<TabsRootEmits>();
const forwarded = useForwardPropsEmits(props, emits)
const forwarded = useForwardPropsEmits(props, emits) as TabsRootProps & HTMLAttributes;
</script>
<template>
@@ -1,10 +1,16 @@
<script setup lang="ts">
import { TooltipRoot, type TooltipRootEmits, type TooltipRootProps, useForwardPropsEmits } from 'radix-vue'
import {
TooltipRoot,
useForwardPropsEmits,
type TooltipRootEmits,
type TooltipRootProps,
} from 'radix-vue';
import type { HTMLAttributes } from 'vue';
const props = defineProps<TooltipRootProps>()
const emits = defineEmits<TooltipRootEmits>()
const props = defineProps<TooltipRootProps>();
const emits = defineEmits<TooltipRootEmits>();
const forwarded = useForwardPropsEmits(props, emits)
const forwarded = useForwardPropsEmits(props, emits) as TooltipRootProps & HTMLAttributes;
</script>
<template>
@@ -1,11 +1,11 @@
<script setup lang="ts">
import type { SelectRootEmits, SelectRootProps } from 'radix-vue'
import { SelectRoot, useForwardPropsEmits } from 'radix-vue'
import type { SelectRootEmits, SelectRootProps } from 'reka-ui';
import { SelectRoot, useForwardPropsEmits } from 'reka-ui';
const props = defineProps<SelectRootProps>()
const emits = defineEmits<SelectRootEmits>()
const props = defineProps<SelectRootProps>();
const emits = defineEmits<SelectRootEmits>();
const forwarded = useForwardPropsEmits(props, emits)
const forwarded = useForwardPropsEmits<SelectRootProps, 'update:modelValue'>(props, emits);
</script>
<template>
@@ -1,4 +1,5 @@
<script setup lang="ts">
import useTeleport from '@/composables/useTeleport';
import { cn } from '@/lib/utils';
import {
SelectContent,
@@ -7,7 +8,7 @@ import {
useForwardPropsEmits,
type SelectContentEmits,
type SelectContentProps,
} from 'radix-vue';
} from 'reka-ui';
import { computed, type HTMLAttributes } from 'vue';
import { SelectScrollDownButton, SelectScrollUpButton } from '.';
@@ -15,21 +16,14 @@ defineOptions({
inheritAttrs: false,
});
const props = withDefaults(
defineProps<
SelectContentProps & {
class?: HTMLAttributes['class'];
disabled?: boolean;
forceMount?: boolean;
to?: string | HTMLElement | Element;
}
>(),
{
position: 'popper',
class: undefined,
to: '#modals',
}
);
const { teleportTarget } = useTeleport();
const props = withDefaults(defineProps<SelectContentProps & { class?: HTMLAttributes['class'] }>(), {
forceMount: false,
position: 'popper',
to: undefined,
});
const emits = defineEmits<SelectContentEmits>();
const delegatedProps = computed(() => {
@@ -42,7 +36,7 @@ const forwarded = useForwardPropsEmits(delegatedProps, emits);
</script>
<template>
<SelectPortal :disabled="disabled" :force-mount="forceMount" :to="to as HTMLElement">
<SelectPortal :force-mount="forceMount" :to="teleportTarget">
<SelectContent
v-bind="{ ...forwarded, ...$attrs }"
:class="
@@ -60,7 +54,7 @@ const forwarded = useForwardPropsEmits(delegatedProps, emits);
cn(
'p-1',
position === 'popper' &&
'h-[--radix-select-trigger-height] w-full min-w-[--radix-select-trigger-width]'
'h-[--reka-select-trigger-height] w-full min-w-[--reka-select-trigger-width]'
)
"
>
@@ -1,11 +1,9 @@
<script setup lang="ts">
import { type HTMLAttributes, computed } from "vue";
import { SelectGroup, type SelectGroupProps } from "radix-vue";
import { cn } from "@/lib/utils";
import { cn } from '@/lib/utils';
import { SelectGroup, type SelectGroupProps } from 'reka-ui';
import { computed, type HTMLAttributes } from 'vue';
const props = defineProps<
SelectGroupProps & { class?: HTMLAttributes["class"] }
>();
const props = defineProps<SelectGroupProps & { class?: HTMLAttributes['class'] }>();
const delegatedProps = computed(() => {
const { class: _, ...delegated } = props;
@@ -1,18 +1,16 @@
<script setup lang="ts">
import { type HTMLAttributes, computed } from "vue";
import { cn } from '@/lib/utils';
import { Check } from 'lucide-vue-next';
import {
SelectItem,
SelectItemIndicator,
type SelectItemProps,
SelectItemText,
useForwardProps,
} from "radix-vue";
import { Check } from "lucide-vue-next";
import { cn } from "@/lib/utils";
type SelectItemProps,
} from 'reka-ui';
import { computed, type HTMLAttributes } from 'vue';
const props = defineProps<
SelectItemProps & { class?: HTMLAttributes["class"] }
>();
const props = defineProps<SelectItemProps & { class?: HTMLAttributes['class'] }>();
const delegatedProps = computed(() => {
const { class: _, ...delegated } = props;
@@ -1,7 +1,7 @@
<script setup lang="ts">
import { SelectItemText, type SelectItemTextProps } from 'radix-vue'
import { SelectItemText, type SelectItemTextProps } from 'reka-ui';
const props = defineProps<SelectItemTextProps>()
const props = defineProps<SelectItemTextProps>();
</script>
<template>
@@ -1,17 +1,13 @@
<script setup lang="ts">
import type { HTMLAttributes } from "vue";
import { SelectLabel, type SelectLabelProps } from "radix-vue";
import { cn } from "@/lib/utils";
import { cn } from '@/lib/utils';
import { SelectLabel, type SelectLabelProps } from 'reka-ui';
import type { HTMLAttributes } from 'vue';
const props = defineProps<
SelectLabelProps & { class?: HTMLAttributes["class"] }
>();
const props = defineProps<SelectLabelProps & { class?: HTMLAttributes['class'] }>();
</script>
<template>
<SelectLabel
:class="cn('py-1.5 pl-8 pr-2 text-sm font-semibold', props.class)"
>
<SelectLabel :class="cn('py-1.5 pl-8 pr-2 text-sm font-semibold', props.class)">
<slot />
</SelectLabel>
</template>
@@ -1,16 +1,10 @@
<script setup lang="ts">
import { type HTMLAttributes, computed } from "vue";
import {
SelectScrollDownButton,
type SelectScrollDownButtonProps,
useForwardProps,
} from "radix-vue";
import { ChevronDown } from "lucide-vue-next";
import { cn } from "@/lib/utils";
import { cn } from '@/lib/utils';
import { ChevronDown } from 'lucide-vue-next';
import { SelectScrollDownButton, useForwardProps, type SelectScrollDownButtonProps } from 'reka-ui';
import { computed, type HTMLAttributes } from 'vue';
const props = defineProps<
SelectScrollDownButtonProps & { class?: HTMLAttributes["class"] }
>();
const props = defineProps<SelectScrollDownButtonProps & { class?: HTMLAttributes['class'] }>();
const delegatedProps = computed(() => {
const { class: _, ...delegated } = props;
@@ -24,9 +18,7 @@ const forwardedProps = useForwardProps(delegatedProps);
<template>
<SelectScrollDownButton
v-bind="forwardedProps"
:class="
cn('flex cursor-default items-center justify-center py-1', props.class)
"
:class="cn('flex cursor-default items-center justify-center py-1', props.class)"
>
<slot>
<ChevronDown class="h-4 w-4" />
@@ -1,16 +1,10 @@
<script setup lang="ts">
import { type HTMLAttributes, computed } from "vue";
import {
SelectScrollUpButton,
type SelectScrollUpButtonProps,
useForwardProps,
} from "radix-vue";
import { ChevronUp } from "lucide-vue-next";
import { cn } from "@/lib/utils";
import { cn } from '@/lib/utils';
import { ChevronUp } from 'lucide-vue-next';
import { SelectScrollUpButton, useForwardProps, type SelectScrollUpButtonProps } from 'reka-ui';
import { computed, type HTMLAttributes } from 'vue';
const props = defineProps<
SelectScrollUpButtonProps & { class?: HTMLAttributes["class"] }
>();
const props = defineProps<SelectScrollUpButtonProps & { class?: HTMLAttributes['class'] }>();
const delegatedProps = computed(() => {
const { class: _, ...delegated } = props;
@@ -24,9 +18,7 @@ const forwardedProps = useForwardProps(delegatedProps);
<template>
<SelectScrollUpButton
v-bind="forwardedProps"
:class="
cn('flex cursor-default items-center justify-center py-1', props.class)
"
:class="cn('flex cursor-default items-center justify-center py-1', props.class)"
>
<slot>
<ChevronUp class="h-4 w-4" />
@@ -1,11 +1,9 @@
<script setup lang="ts">
import { type HTMLAttributes, computed } from "vue";
import { SelectSeparator, type SelectSeparatorProps } from "radix-vue";
import { cn } from "@/lib/utils";
import { cn } from '@/lib/utils';
import { SelectSeparator, type SelectSeparatorProps } from 'reka-ui';
import { computed, type HTMLAttributes } from 'vue';
const props = defineProps<
SelectSeparatorProps & { class?: HTMLAttributes["class"] }
>();
const props = defineProps<SelectSeparatorProps & { class?: HTMLAttributes['class'] }>();
const delegatedProps = computed(() => {
const { class: _, ...delegated } = props;
@@ -15,8 +13,5 @@ const delegatedProps = computed(() => {
</script>
<template>
<SelectSeparator
v-bind="delegatedProps"
:class="cn('-mx-1 my-1 h-px bg-muted', props.class)"
/>
<SelectSeparator v-bind="delegatedProps" :class="cn('-mx-1 my-1 h-px bg-muted', props.class)" />
</template>
@@ -1,17 +1,10 @@
<script setup lang="ts">
import { type HTMLAttributes, computed } from "vue";
import {
SelectIcon,
SelectTrigger,
type SelectTriggerProps,
useForwardProps,
} from "radix-vue";
import { ChevronDown } from "lucide-vue-next";
import { cn } from "@/lib/utils";
import { cn } from '@/lib/utils';
import { ChevronDown } from 'lucide-vue-next';
import { SelectIcon, SelectTrigger, useForwardProps, type SelectTriggerProps } from 'reka-ui';
import { computed, type HTMLAttributes } from 'vue';
const props = defineProps<
SelectTriggerProps & { class?: HTMLAttributes["class"] }
>();
const props = defineProps<SelectTriggerProps & { class?: HTMLAttributes['class'] }>();
const delegatedProps = computed(() => {
const { class: _, ...delegated } = props;
@@ -27,7 +20,7 @@ const forwardedProps = useForwardProps(delegatedProps);
v-bind="forwardedProps"
:class="
cn(
'flex h-10 w-full items-center justify-between rounded-md border border-input bg-background px-4.5 py-3 text-base ring-offset-background placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 [&>span]:truncate text-start',
'flex h-10 w-full items-center justify-between rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background data-[placeholder]:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 [&>span]:truncate text-start',
props.class
)
"
@@ -1,7 +1,7 @@
<script setup lang="ts">
import { SelectValue, type SelectValueProps } from 'radix-vue'
import { SelectValue, type SelectValueProps } from 'reka-ui';
const props = defineProps<SelectValueProps>()
const props = defineProps<SelectValueProps>();
</script>
<template>
@@ -1,11 +1,11 @@
export { default as Select } from './Select.vue'
export { default as SelectValue } from './SelectValue.vue'
export { default as SelectTrigger } from './SelectTrigger.vue'
export { default as SelectContent } from './SelectContent.vue'
export { default as SelectGroup } from './SelectGroup.vue'
export { default as SelectItem } from './SelectItem.vue'
export { default as SelectItemText } from './SelectItemText.vue'
export { default as SelectLabel } from './SelectLabel.vue'
export { default as SelectSeparator } from './SelectSeparator.vue'
export { default as SelectScrollUpButton } from './SelectScrollUpButton.vue'
export { default as SelectScrollDownButton } from './SelectScrollDownButton.vue'
export { default as SelectScrollUpButton } from './SelectScrollUpButton.vue'
export { default as SelectSeparator } from './SelectSeparator.vue'
export { default as SelectTrigger } from './SelectTrigger.vue'
export { default as SelectValue } from './SelectValue.vue'
+6 -6
View File
@@ -1,17 +1,17 @@
import { ref, onMounted } from "vue";
import { onMounted, ref } from 'vue';
const useTeleport = () => {
const teleportTarget = ref<string | HTMLElement | Element>("#modals");
const teleportTarget = ref<string | HTMLElement>('#modals');
const determineTeleportTarget = () => {
const myModalsComponent = document.querySelector("unraid-modals");
const myModalsComponent = document.querySelector('unraid-modals');
if (!myModalsComponent?.shadowRoot) return;
const potentialTarget = myModalsComponent.shadowRoot.querySelector("#modals");
const potentialTarget = myModalsComponent.shadowRoot.querySelector('#modals');
if (!potentialTarget) return;
teleportTarget.value = potentialTarget;
console.log("[determineTeleportTarget] teleportTarget", teleportTarget.value);
teleportTarget.value = potentialTarget as HTMLElement;
console.log('[determineTeleportTarget] teleportTarget', teleportTarget.value);
};
onMounted(() => {
+5 -8
View File
@@ -1,6 +1,4 @@
<script setup lang="ts">
import { computed } from 'vue';
import {
Select,
SelectContent,
@@ -10,11 +8,10 @@ import {
SelectValue,
} from '@/components/form/select';
import useTeleport from '@/composables/useTeleport';
import { useJsonFormsControl } from '@jsonforms/vue';
import type { ControlElement } from '@jsonforms/core';
import { useJsonFormsControl } from '@jsonforms/vue';
import type { RendererProps } from '@jsonforms/vue';
import { computed } from 'vue';
import ControlLayout from './ControlLayout.vue';
const props = defineProps<RendererProps<ControlElement>>();
@@ -29,8 +26,8 @@ const options = computed(() => {
}));
});
const onChange = (value: string) => {
handleChange(control.value.path, value);
const onChange = (value: unknown) => {
handleChange(control.value.path, String(value));
};
// Without this, the select dropdown will not be visible, unless it's already in a teleported context.
@@ -55,7 +52,7 @@ const onSelectOpen = () => {
<span v-else>{{ control.schema.default ?? 'Select an option' }}</span>
</SelectTrigger>
<!-- The content includes the selectable options -->
<SelectContent :to="teleportTarget">
<SelectContent :to="teleportTarget as HTMLElement">
<SelectItem v-for="option in options" :key="option.value" :value="option.value">
<SelectItemText>{{ option.label }}</SelectItemText>
</SelectItem>
+13 -5
View File
@@ -14,11 +14,13 @@ import { Badge, type BadgeProps } from '@/components/common/badge';
import { Button, buttonVariants, type ButtonProps } from '@/components/common/button';
import {
DropdownMenu,
DropdownMenuArrow,
DropdownMenuCheckboxItem,
DropdownMenuContent,
DropdownMenuGroup,
DropdownMenuItem,
DropdownMenuLabel,
DropdownMenuPortal,
DropdownMenuRadioGroup,
DropdownMenuRadioItem,
DropdownMenuSeparator,
@@ -29,6 +31,7 @@ import {
DropdownMenuTrigger,
} from '@/components/common/dropdown-menu';
import { Bar, Error, Spinner } from '@/components/common/loading';
import { Popover, PopoverContent, PopoverTrigger } from '@/components/common/popover';
import { ScrollArea, ScrollBar } from '@/components/common/scroll-area';
import {
Sheet,
@@ -90,23 +93,28 @@ export {
CardWrapper,
cn,
DropdownMenu,
DropdownMenuTrigger,
DropdownMenuArrow,
DropdownMenuCheckboxItem,
DropdownMenuContent,
DropdownMenuGroup,
DropdownMenuLabel,
DropdownMenuRadioGroup,
DropdownMenuItem,
DropdownMenuCheckboxItem,
DropdownMenuRadioItem,
DropdownMenuShortcut,
DropdownMenuSeparator,
DropdownMenuLabel,
DropdownMenuShortcut,
DropdownMenuSub,
DropdownMenuSubTrigger,
DropdownMenuSubContent,
DropdownMenuSubTrigger,
DropdownMenuTrigger,
DropdownMenuPortal,
Error,
Input,
Label,
PageContainer,
Popover,
PopoverContent,
PopoverTrigger,
ScrollBar,
ScrollArea,
Select,
+3 -3
View File
@@ -1,6 +1,6 @@
import { type ClassValue, clsx } from 'clsx'
import { twMerge } from 'tailwind-merge'
import { clsx, type ClassValue } from 'clsx';
import { twMerge } from 'tailwind-merge';
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs))
return twMerge(clsx(inputs));
}
+20
View File
@@ -34,6 +34,16 @@
--ring: 0 0% 3.9%;
--radius: 0.5rem;
--chart-1: 12 76% 61%;
--chart-2: 173 58% 39%;
--chart-3: 197 37% 24%;
--chart-4: 43 74% 66%;
--chart-5: 27 87% 67%;
}
.dark {
@@ -65,6 +75,16 @@
--destructive-foreground: 0 0% 98%;
--ring: 0 0% 83.1%;
--chart-1: 220 70% 50%;
--chart-2: 160 60% 45%;
--chart-3: 30 80% 55%;
--chart-4: 280 65% 60%;
--chart-5: 340 75% 55%;
}
}
@@ -1,17 +1,24 @@
import type { Meta, StoryObj } from "@storybook/vue3";
import { MoreVertical } from "lucide-vue-next";
import Button from "../../../src/components/common/button/Button.vue";
import DropdownMenu from "../../../src/components/common/dropdown-menu/DropdownMenu.vue";
import DropdownMenuContent from "../../../src/components/common/dropdown-menu/DropdownMenuContent.vue";
import DropdownMenuItem from "../../../src/components/common/dropdown-menu/DropdownMenuItem.vue";
import DropdownMenuLabel from "../../../src/components/common/dropdown-menu/DropdownMenuLabel.vue";
import DropdownMenuSeparator from "../../../src/components/common/dropdown-menu/DropdownMenuSeparator.vue";
import DropdownMenuTrigger from "../../../src/components/common/dropdown-menu/DropdownMenuTrigger.vue";
import type { Meta, StoryObj } from '@storybook/vue3';
import { MoreVertical } from 'lucide-vue-next';
import Button from '../../../src/components/common/button/Button.vue';
import DropdownMenu from '../../../src/components/common/dropdown-menu/DropdownMenu.vue';
import DropdownMenuArrow from '../../../src/components/common/dropdown-menu/DropdownMenuArrow.vue';
import DropdownMenuContent from '../../../src/components/common/dropdown-menu/DropdownMenuContent.vue';
import DropdownMenuItem from '../../../src/components/common/dropdown-menu/DropdownMenuItem.vue';
import DropdownMenuLabel from '../../../src/components/common/dropdown-menu/DropdownMenuLabel.vue';
import DropdownMenuSeparator from '../../../src/components/common/dropdown-menu/DropdownMenuSeparator.vue';
import DropdownMenuTrigger from '../../../src/components/common/dropdown-menu/DropdownMenuTrigger.vue';
const meta = {
title: "Components/Common/DropdownMenu",
title: 'Components/Common/DropdownMenu',
component: DropdownMenu,
tags: ['autodocs'],
argTypes: {
open: {
control: 'boolean',
description: 'Controls the open state of the dropdown menu',
},
},
} satisfies Meta<typeof DropdownMenu>;
export default meta;
@@ -21,6 +28,7 @@ type Story = StoryObj<typeof meta>;
export const Dropdown: Story = {
render: () => ({
components: {
DropdownMenuArrow,
DropdownMenu,
DropdownMenuTrigger,
DropdownMenuContent,
@@ -30,18 +38,21 @@ export const Dropdown: Story = {
Button,
},
template: `
<DropdownMenu>
<DropdownMenuTrigger>
<Button variant="secondary">Open Menu</Button>
</DropdownMenuTrigger>
<DropdownMenuContent>
<DropdownMenuLabel>My Account</DropdownMenuLabel>
<DropdownMenuSeparator />
<DropdownMenuItem>Profile</DropdownMenuItem>
<DropdownMenuItem>Settings</DropdownMenuItem>
<DropdownMenuItem>Logout</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
<div class="bg-gray-200 p-4 h-screen">
<DropdownMenu>
<DropdownMenuTrigger>
<Button variant="secondary">Open Menu</Button>
</DropdownMenuTrigger>
<DropdownMenuContent>
<DropdownMenuLabel>My Account</DropdownMenuLabel>
<DropdownMenuSeparator />
<DropdownMenuItem>Profile</DropdownMenuItem>
<DropdownMenuItem>Settings</DropdownMenuItem>
<DropdownMenuItem>Logout</DropdownMenuItem>
<DropdownMenuArrow />
</DropdownMenuContent>
</DropdownMenu>
</div>
`,
}),
};
@@ -58,7 +69,7 @@ export const IconDropdown: Story = {
Button,
MoreVertical,
},
template: `
template: `
<DropdownMenu>
<DropdownMenuTrigger>
<Button variant="ghost" size="icon">
@@ -71,8 +82,9 @@ export const IconDropdown: Story = {
<DropdownMenuItem>Edit</DropdownMenuItem>
<DropdownMenuItem>Duplicate</DropdownMenuItem>
<DropdownMenuItem>Delete</DropdownMenuItem>
<DropdownMenuArrow />
</DropdownMenuContent>
</DropdownMenu>
`,
}),
};
};
@@ -0,0 +1,64 @@
import type { Meta, StoryObj } from '@storybook/vue3';
import { Button } from '../../../src/components/common/button';
import { Popover, PopoverContent, PopoverTrigger } from '../../../src/components/common/popover';
const meta = {
title: 'Components/Common/Popover',
component: Popover,
tags: ['autodocs'],
argTypes: {
open: {
control: 'boolean',
description: 'Controls the open state of the popover',
},
},
} satisfies Meta<typeof Popover>;
export default meta;
type Story = StoryObj<typeof meta>;
export const Default: Story = {
render: () => ({
components: { Popover, PopoverContent, PopoverTrigger, Button },
template: `
<div class="p-8">
<Popover>
<PopoverTrigger>
<Button>Open Popover</Button>
</PopoverTrigger>
<PopoverContent side="bottom" align="center" :side-offset="8">
<div class="space-y-4">
<h4 class="font-medium leading-none">Dimensions</h4>
<p class="text-sm text-muted-foreground">
Set the dimensions for the layer.
</p>
</div>
</PopoverContent>
</Popover>
</div>
`,
}),
};
export const WithCustomPosition: Story = {
render: () => ({
components: { Popover, PopoverContent, PopoverTrigger, Button },
template: `
<div class="p-8">
<Popover>
<PopoverTrigger>
<Button>Open Popover</Button>
</PopoverTrigger>
<PopoverContent side="right" align="start" :side-offset="8">
<div class="space-y-4">
<h4 class="font-medium leading-none">Custom Position</h4>
<p class="text-sm text-muted-foreground">
This popover is positioned on the right side with custom offset.
</p>
</div>
</PopoverContent>
</Popover>
</div>
`,
}),
};
@@ -1,24 +1,37 @@
import type { Meta, StoryObj } from "@storybook/vue3";
import SheetComponent from "../../../src/components/common/sheet/Sheet.vue";
import SheetTrigger from "../../../src/components/common/sheet/SheetTrigger.vue";
import SheetContent from "../../../src/components/common/sheet/SheetContent.vue";
import SheetHeader from "../../../src/components/common/sheet/SheetHeader.vue";
import SheetTitle from "../../../src/components/common/sheet/SheetTitle.vue";
import SheetDescription from "../../../src/components/common/sheet/SheetDescription.vue";
import SheetFooter from "../../../src/components/common/sheet/SheetFooter.vue";
import Button from "../../../src/components/common/button/Button.vue";
import type { Meta, StoryObj } from '@storybook/vue3';
import { h } from 'vue';
import Button from '../../../src/components/common/button/Button.vue';
import SheetComponent from '../../../src/components/common/sheet/Sheet.vue';
import SheetContent from '../../../src/components/common/sheet/SheetContent.vue';
import SheetDescription from '../../../src/components/common/sheet/SheetDescription.vue';
import SheetFooter from '../../../src/components/common/sheet/SheetFooter.vue';
import SheetHeader from '../../../src/components/common/sheet/SheetHeader.vue';
import SheetTitle from '../../../src/components/common/sheet/SheetTitle.vue';
import SheetTrigger from '../../../src/components/common/sheet/SheetTrigger.vue';
import Select from '../../../src/components/form/select/Select.vue';
import SelectContent from '../../../src/components/form/select/SelectContent.vue';
import SelectItem from '../../../src/components/form/select/SelectItem.vue';
import SelectTrigger from '../../../src/components/form/select/SelectTrigger.vue';
import SelectValue from '../../../src/components/form/select/SelectValue.vue';
const meta = {
title: "Components/Common",
title: 'Components/Common',
component: SheetComponent,
subcomponents: {
subcomponents: {
SheetTrigger,
SheetContent,
SheetHeader,
SheetTitle,
SheetDescription,
SheetFooter
SheetFooter,
Select,
},
decorators: [
(story) => ({
components: { story },
template: '<div style="min-height: 100vh;"><story /></div>',
}),
],
} satisfies Meta<typeof SheetComponent>;
export default meta;
@@ -82,3 +95,66 @@ export const Sheet: Story = {
`,
}),
};
export const SheetWithSelect: Story = {
render: () => ({
components: {
SheetComponent,
SheetTrigger,
SheetContent,
SheetHeader,
SheetTitle,
SheetDescription,
SheetFooter,
Button,
Select,
SelectTrigger,
SelectContent,
SelectItem,
SelectValue,
},
data() {
return {
theme: 'light',
};
},
template: `
<div class="inline-flex items-center gap-4 p-4">
<SheetComponent>
<SheetTrigger>
<Button variant="outline">Open Form Sheet</Button>
</SheetTrigger>
<SheetContent side="right">
<SheetHeader>
<SheetTitle>User Preferences</SheetTitle>
<SheetDescription>
Configure your user preferences using the form below.
</SheetDescription>
</SheetHeader>
<div class="py-6">
<div class="space-y-4">
<div class="space-y-2">
<label class="text-sm font-medium">Theme</label>
<Select v-model="theme">
<SelectTrigger>
<SelectValue placeholder="Select a theme" />
</SelectTrigger>
<SelectContent>
<SelectItem value="light">Light</SelectItem>
<SelectItem value="dark">Dark</SelectItem>
<SelectItem value="system">System</SelectItem>
</SelectContent>
</Select>
</div>
</div>
</div>
<SheetFooter>
<Button variant="outline">Cancel</Button>
<Button>Save changes</Button>
</SheetFooter>
</SheetContent>
</SheetComponent>
</div>
`,
}),
};
@@ -1,9 +1,14 @@
import type { Meta, StoryObj } from "@storybook/vue3";
import { Tooltip as TooltipComponent, TooltipTrigger, TooltipContent, TooltipProvider } from "../../../src/components/common/tooltip";
import { Button } from "../../../src/components/common/button";
import type { Meta, StoryObj } from '@storybook/vue3';
import { Button } from '../../../src/components/common/button';
import {
Tooltip as TooltipComponent,
TooltipContent,
TooltipProvider,
TooltipTrigger,
} from '../../../src/components/common/tooltip';
const meta = {
title: "Components/Common",
title: 'Components/Common',
component: TooltipComponent,
} satisfies Meta<typeof TooltipComponent>;
@@ -21,8 +26,6 @@ export const Tooltip: Story = {
return { args };
},
template: `
<div>
<div id="modals"></div>
<div class="p-20 flex items-center justify-start">
<TooltipProvider>
<TooltipComponent :default-open="args.defaultOpen">
@@ -35,7 +38,6 @@ export const Tooltip: Story = {
</TooltipComponent>
</TooltipProvider>
</div>
</div>
`,
}),
};
@@ -1,4 +1,4 @@
import type { Meta, StoryObj } from "@storybook/vue3";
import type { Meta, StoryObj } from '@storybook/vue3';
import {
Select as SelectComponent,
SelectContent,
@@ -7,10 +7,10 @@ import {
SelectLabel,
SelectTrigger,
SelectValue,
} from "../../../src/components/form/select";
} from '../../../src/components/form/select';
const meta = {
title: "Components/Form/Select",
title: 'Components/Form/Select',
component: SelectComponent,
} satisfies Meta<typeof SelectComponent>;
@@ -33,8 +33,6 @@ export const Select: Story = {
return { args };
},
template: `
<div>
<div id="modals"></div>
<SelectComponent>
<SelectTrigger class="w-[180px]">
<SelectValue placeholder="Select a fruit" />
@@ -49,7 +47,6 @@ export const Select: Story = {
</SelectGroup>
</SelectContent>
</SelectComponent>
</div>
`,
}),
};
@@ -70,7 +67,7 @@ export const Grouped: Story = {
},
template: `
<div>
<div id="modals"></div>
<unraid-modals></unraid-modals>
<SelectComponent>
<SelectTrigger class="w-[180px]">
<SelectValue placeholder="Select a food" />
+56 -4
View File
@@ -1,20 +1,20 @@
import tailwindRemToRem from '@unraid/tailwind-rem-to-rem';
import type { Config } from 'tailwindcss';
import tailwindcssAnimate from 'tailwindcss-animate';
import { unraidPreset } from './src/theme/preset';
export default {
darkMode: ['class'],
presets: [unraidPreset],
content: [
'./src/components/**/*.{js,vue,ts}',
'./src/components/**/*.ce.{js,vue,ts}',
'./src/composables/**/*.{js,vue,ts}',
'./stories/**/*.stories.{js,ts,jsx,tsx,mdx}',
'./stories/**/*.stories.{js,ts,jsx,mdx}',
'./index.html',
],
safelist: [
'dark',
'DropdownWrapper_blip',
'unraid_mark_1',
'unraid_mark_2',
'unraid_mark_3',
@@ -37,5 +37,57 @@ export default {
baseFontSize: 16,
newFontSize: Number(process.env.VITE_TAILWIND_BASE_FONT_SIZE ?? 10),
}),
tailwindcssAnimate,
],
} satisfies Partial<Config>;
theme: {
extend: {
borderRadius: {
lg: 'var(--radius)',
md: 'calc(var(--radius) - 2px)',
sm: 'calc(var(--radius) - 4px)',
},
colors: {
background: 'hsl(var(--background))',
foreground: 'hsl(var(--foreground))',
card: {
DEFAULT: 'hsl(var(--card))',
foreground: 'hsl(var(--card-foreground))',
},
popover: {
DEFAULT: 'hsl(var(--popover))',
foreground: 'hsl(var(--popover-foreground))',
},
primary: {
DEFAULT: 'hsl(var(--primary))',
foreground: 'hsl(var(--primary-foreground))',
},
secondary: {
DEFAULT: 'hsl(var(--secondary))',
foreground: 'hsl(var(--secondary-foreground))',
},
muted: {
DEFAULT: 'hsl(var(--muted))',
foreground: 'hsl(var(--muted-foreground))',
},
accent: {
DEFAULT: 'hsl(var(--accent))',
foreground: 'hsl(var(--accent-foreground))',
},
destructive: {
DEFAULT: 'hsl(var(--destructive))',
foreground: 'hsl(var(--destructive-foreground))',
},
border: 'hsl(var(--border))',
input: 'hsl(var(--input))',
ring: 'hsl(var(--ring))',
chart: {
'1': 'hsl(var(--chart-1))',
'2': 'hsl(var(--chart-2))',
'3': 'hsl(var(--chart-3))',
'4': 'hsl(var(--chart-4))',
'5': 'hsl(var(--chart-5))',
},
},
},
},
} satisfies Partial<Config>;
-1
View File
@@ -1,6 +1,5 @@
{
"compilerOptions": {
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.tsbuildinfo",
"target": "ES2020",
"useDefineForClassFields": true,
"module": "ESNext",
+9 -1
View File
@@ -28,6 +28,14 @@
"./tailwind.config.ts",
"src/theme/**/*.ts"
],
"exclude": ["node_modules", "**/*.copy.vue", "**/*copy.vue"],
"exclude": [
"node_modules",
"**/*.copy.vue",
"**/*copy.vue",
"**/*.test.ts",
"**/*.spec.ts",
"**/*.test.tsx",
"**/*.spec.tsx"
],
"references": [{ "path": "./tsconfig.test.json" }]
}
+3 -8
View File
@@ -4,14 +4,9 @@
"composite": true,
"emitDeclarationOnly": true,
"outDir": "./dist/test",
"types": [
"node",
"happy-dom",
"vitest/globals",
"@vue/test-utils",
"@testing-library/vue"
]
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.test.tsbuildinfo",
"types": ["node", "happy-dom", "vitest/globals", "@vue/test-utils", "@testing-library/vue"]
},
"include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue", "tailwind.config.ts"],
"include": ["src/**/*.test.ts", "src/**/*.spec.ts", "src/**/*.test.tsx", "src/**/*.spec.tsx"],
"exclude": ["node_modules", "**/*.copy.vue", "**/*copy.vue"]
}
-3
View File
@@ -13,9 +13,6 @@ const { callbackStatus } = storeToRefs(useCallbackActionsStore());
const { trialModalVisible } = storeToRefs(useTrialStore());
const { modalOpen: updateOsModalVisible } = storeToRefs(useUpdateOsStore());
const { releaseForUpdate: updateOsChangelogModalVisible } = storeToRefs(useUpdateOsChangelogStore());
// import { usePromoStore } from '~/store/promo';
// const { promoVisible } = storeToRefs(usePromoStore());
// <UpcPromo :t="t" :open="promoVisible" />
</script>
<template>
+6 -4
View File
@@ -121,13 +121,14 @@ const prepareToViewNotifications = () => {
</script>
<template>
<Sheet>
<Sheet :modal="false">
<SheetTrigger @click="prepareToViewNotifications">
<span class="sr-only">Notifications</span>
<NotificationsIndicator :overview="overview" :seen="haveSeenNotifications" />
</SheetTrigger>
<SheetContent
:to="teleportTarget as HTMLElement"
side="right"
class="w-full max-w-[100vw] sm:max-w-[540px] max-h-screen h-screen min-h-screen px-0 flex flex-col gap-5 pb-0"
>
<div class="relative flex flex-col h-full w-full">
@@ -177,15 +178,16 @@ const prepareToViewNotifications = () => {
<Select
@update:model-value="
(val: string) => {
importance = val === 'all' ? undefined : (val as Importance);
(val: unknown) => {
const strVal = String(val);
importance = strVal === 'all' || !strVal ? undefined : (strVal as Importance);
}
"
>
<SelectTrigger class="h-auto">
<SelectValue class="text-gray-400 leading-6" placeholder="Filter By" />
</SelectTrigger>
<SelectContent :to="teleportTarget">
<SelectContent>
<SelectGroup>
<SelectLabel>Notification Types</SelectLabel>
<SelectItem value="all">All Types</SelectItem>
+5 -41
View File
@@ -1,7 +1,6 @@
<script lang="ts" setup>
import { useI18n } from 'vue-i18n';
import { storeToRefs } from 'pinia';
import { OnClickOutside } from '@vueuse/components';
import { useClipboard } from '@vueuse/core';
import { devConfig } from '~/helpers/env';
@@ -9,7 +8,6 @@ import { devConfig } from '~/helpers/env';
import type { Server } from '~/types/server';
import { useCallbackActionsStore, useCallbackStore } from '~/store/callbackActions';
import { useDropdownStore } from '~/store/dropdown';
import { useServerStore } from '~/store/server';
import { useThemeStore } from '~/store/theme';
@@ -21,26 +19,12 @@ const props = defineProps<Props>();
const { t } = useI18n();
const callbackStore = useCallbackStore();
const dropdownStore = useDropdownStore();
const serverStore = useServerStore();
const { callbackData } = storeToRefs(useCallbackActionsStore());
const { dropdownVisible } = storeToRefs(dropdownStore);
const { name, description, guid, keyfile, lanIp, connectPluginInstalled } = storeToRefs(serverStore);
const { bannerGradient, theme } = storeToRefs(useThemeStore());
/**
* Close dropdown when clicking outside
* @note If in testing you have two variants of the component on a page the clickOutside will fire twice making it seem like it doesn't work
*/
const clickOutsideTarget = ref();
const clickOutsideIgnoreTarget = ref();
const outsideDropdown = () => {
if (dropdownVisible.value) {
return dropdownStore.dropdownToggle();
}
};
/**
* Copy LAN IP on server name click
*/
@@ -154,14 +138,11 @@ onMounted(() => {
<NotificationsSidebar />
</template>
<OnClickOutside
class="flex items-center justify-end h-full"
:options="{ ignore: [clickOutsideIgnoreTarget] }"
@trigger="outsideDropdown"
>
<UpcDropdownTrigger ref="clickOutsideIgnoreTarget" :t="t" />
<UpcDropdown ref="clickOutsideTarget" :t="t" />
</OnClickOutside>
<UpcDropdownMenu :t="t">
<template #trigger>
<UpcDropdownTrigger :t="t" />
</template>
</UpcDropdownMenu>
</div>
</div>
</template>
@@ -171,23 +152,6 @@ onMounted(() => {
@import '@unraid/ui/styles';
@import '~/assets/main.css';
.DropdownWrapper_blip {
box-shadow: var(--ring-offset-shadow), var(--ring-shadow), var(--shadow-popover-foreground);
&::before {
@apply absolute z-20 block;
content: '';
width: 0;
height: 0;
top: -10px;
right: 42px;
border-right: 11px solid transparent;
border-bottom: 11px solid var(--color-headerTextPrimary);
border-left: 11px solid transparent;
}
}
.unraid_mark_2,
.unraid_mark_4 {
animation: mark_2 1.5s ease infinite;
@@ -20,7 +20,6 @@ import type { ComposerTranslation } from 'vue-i18n';
import { useAccountStore } from '~/store/account';
import { useCallbackActionsStore } from '~/store/callbackActions';
import { useInstallKeyStore } from '~/store/installKey';
// import { usePromoStore } from '~/store/promo';
import { useServerStore } from '~/store/server';
import { useUpdateOsActionsStore } from '~/store/updateOsActions';
@@ -36,7 +35,6 @@ const props = withDefaults(defineProps<Props>(), {
const accountStore = useAccountStore();
const callbackActionsStore = useCallbackActionsStore();
const installKeyStore = useInstallKeyStore();
// const promoStore = usePromoStore();
const serverStore = useServerStore();
const updateOsActionStore = useUpdateOsActionsStore();
@@ -67,8 +65,6 @@ const {
*/
const isSettingsPage = ref<boolean>(document.location.pathname === '/Settings/ManagementAccess');
// const showPromoCta = computed(() => callbackStatus.value === 'success' && !connectPluginInstalled.value);
const heading = computed(() => {
if (updateOsStatus.value === 'confirming') {
return callbackTypeDowngrade.value
@@ -143,11 +139,6 @@ const cancelUpdateOs = () => {
callbackActionsStore.setCallbackStatus('ready');
};
// const promoClick = () => {
// promoStore.openOnNextLoad();
// close();
// };
const keyInstallStatusCopy = computed((): { text: string } => {
let txt1 = props.t('Installing');
let txt2 = props.t('Installed');
@@ -334,12 +325,6 @@ const showUpdateEligibility = computed(() => {
:error="accountActionStatus === 'failed'"
:text="accountActionStatusCopy.text"
/>
<!-- <UpcCallbackFeedbackStatus
v-if="showPromoCta"
:icon="InformationCircleIcon"
:text="t('Enhance your experience with Unraid Connect')"
/> -->
</div>
<template v-if="updateOsStatus === 'confirming' && !stateDataError">
@@ -388,12 +373,6 @@ const showUpdateEligibility = computed(() => {
:text="t('Configure Connect Features')"
/>
</template>
<!-- <BrandButton
v-if="showPromoCta"
:text="t('Learn More')"
@click="promoClick"
/> -->
</template>
<template v-if="updateOsStatus === 'confirming' && !stateDataError">
-38
View File
@@ -1,38 +0,0 @@
<script setup lang="ts">
import { storeToRefs } from 'pinia';
import { TransitionRoot } from '@headlessui/vue';
import type { ComposerTranslation } from 'vue-i18n';
import { useDropdownStore } from '~/store/dropdown';
import { useServerStore } from '~/store/server';
defineProps<{ t: ComposerTranslation }>();
const dropdownStore = useDropdownStore();
const { dropdownVisible } = storeToRefs(dropdownStore);
const { state } = storeToRefs(useServerStore());
const showLaunchpad = computed(() => state.value === 'ENOKEYFILE');
</script>
<template>
<TransitionRoot
:show="dropdownVisible"
enter="transition-all duration-200"
enter-from="opacity-0 translate-y-[16px]"
enter-to="opacity-100"
leave="transition-all duration-150"
leave-from="opacity-100"
leave-to="opacity-0 translate-y-[16px]"
>
<UpcDropdownWrapper
class="DropdownWrapper_blip text-foreground absolute z-30 top-full right-0 transition-all"
>
<UpcDropdownLaunchpad v-if="showLaunchpad" :t="t" />
<UpcDropdownContent v-else :t="t" />
</UpcDropdownWrapper>
</TransitionRoot>
</template>
@@ -15,6 +15,7 @@ const { username } = storeToRefs(useServerStore());
const unraidApiStore = useUnraidApiStore();
const { unraidApiStatus, unraidApiRestartAction } = storeToRefs(unraidApiStore);
const brandLoading = () => h(BrandLoading, { size: 'custom' });
interface StatusOutput {
icon: typeof BrandLoading | typeof ExclamationTriangleIcon | typeof CheckCircleIcon;
@@ -25,16 +26,16 @@ interface StatusOutput {
const status = computed((): StatusOutput | undefined => {
if (unraidApiStatus.value === 'connecting') {
return {
icon: BrandLoading,
iconClasses: 'w-16px',
icon: brandLoading,
iconClasses: 'w-4',
text: props.t('Loading…'),
textClasses: 'italic',
};
}
if (unraidApiStatus.value === 'restarting') {
return {
icon: BrandLoading,
iconClasses: 'w-16px',
icon: brandLoading,
iconClasses: 'w-4',
text: props.t('Restarting unraid-api…'),
textClasses: 'italic',
};
@@ -55,14 +56,16 @@ const status = computed((): StatusOutput | undefined => {
}
return undefined;
});
const statusItemClasses = "text-14px flex flex-row justify-start items-center gap-8px mt-8px px-8px";
</script>
<template>
<li v-if="username" class="flex flex-row justify-start items-center gap-8px mt-8px px-8px">
<li v-if="username" :class="statusItemClasses">
<UserCircleIcon class="w-16px h-16px" aria-hidden="true" />
{{ username }}
</li>
<li v-if="status" class="flex flex-row justify-start items-center gap-8px mt-8px px-8px">
<li v-if="status" :class="statusItemClasses">
<component :is="status.icon" :class="status.iconClasses" aria-hidden="true" />
{{ status.text }}
</li>
@@ -189,7 +189,7 @@ const unraidConnectWelcome = computed(() => {
</script>
<template>
<div class="flex flex-col gap-y-8px min-w-300px max-w-350px">
<div class="flex flex-col grow gap-y-8px">
<header
v-if="connectPluginInstalled"
class="flex flex-col items-start justify-between mt-8px mx-8px"
@@ -22,7 +22,7 @@ const showExpireTime = computed(
</script>
<template>
<div class="flex flex-col gap-y-24px w-full min-w-300px md:min-w-[500px] max-w-xl p-16px">
<div class="flex flex-col grow gap-y-24px p-16px">
<header>
<h2 class="text-24px text-center font-semibold" v-html="t(stateData.heading)" />
<div
@@ -0,0 +1,23 @@
<script lang="ts" setup>
import { ref } from 'vue';
import { DropdownMenu, DropdownMenuArrow, DropdownMenuContent, DropdownMenuTrigger } from '@unraid/ui';
import type { ComposerTranslation } from 'vue-i18n';
defineProps<{ t: ComposerTranslation }>();
const open = ref(false);
</script>
<template>
<DropdownMenu v-model:open="open">
<DropdownMenuTrigger>
<slot name="trigger" />
</DropdownMenuTrigger>
<DropdownMenuContent :side-offset="4" :align="'end'" :side="'bottom'" class="w-[350px]">
<UpcDropdownContent :t="t" />
<DropdownMenuArrow :rounded="true" class="fill-popover" :height="10" :width="16" />
</DropdownMenuContent>
</DropdownMenu>
</template>
+36 -14
View File
@@ -1,13 +1,14 @@
<script setup lang="ts">
import { storeToRefs } from 'pinia';
import {
Bars3Icon,
Bars3BottomRightIcon,
BellAlertIcon,
ExclamationTriangleIcon,
InformationCircleIcon,
ShieldExclamationIcon,
} from '@heroicons/vue/24/solid';
import type { ComposerTranslation } from 'vue-i18n';
import { useDropdownStore } from '~/store/dropdown';
@@ -15,7 +16,7 @@ import { useErrorsStore } from '~/store/errors';
import { useServerStore } from '~/store/server';
import { useUpdateOsStore } from '~/store/updateOs';
const props = defineProps<{ t: ComposerTranslation; }>();
const props = defineProps<{ t: ComposerTranslation }>();
const dropdownStore = useDropdownStore();
const { dropdownVisible } = storeToRefs(dropdownStore);
@@ -26,14 +27,22 @@ const { available: osUpdateAvailable } = storeToRefs(useUpdateOsStore());
const showErrorIcon = computed(() => errors.value.length || stateData.value.error);
const text = computed((): string => {
if ((stateData.value.error) && state.value !== 'EEXPIRED') { return props.t('Fix Error'); }
if (stateData.value.error && state.value !== 'EEXPIRED') {
return props.t('Fix Error');
}
return '';
});
const title = computed((): string => {
if (state.value === 'ENOKEYFILE') { return props.t('Get Started'); }
if (state.value === 'EEXPIRED') { return props.t('Trial Expired, see options below'); }
if (showErrorIcon.value) { return props.t('Learn more about the error'); }
if (state.value === 'ENOKEYFILE') {
return props.t('Get Started');
}
if (state.value === 'EEXPIRED') {
return props.t('Trial Expired, see options below');
}
if (showErrorIcon.value) {
return props.t('Learn more about the error');
}
return dropdownVisible.value ? props.t('Close Dropdown') : props.t('Open Dropdown');
});
</script>
@@ -45,19 +54,32 @@ const title = computed((): string => {
@click="dropdownStore.dropdownToggle()"
>
<template v-if="errors.length && errors[0].level">
<InformationCircleIcon v-if="errors[0].level === 'info'" class="text-unraid-red fill-current relative w-24px h-24px" />
<ExclamationTriangleIcon v-if="errors[0].level === 'warning'" class="text-unraid-red fill-current relative w-24px h-24px" />
<ShieldExclamationIcon v-if="errors[0].level === 'error'" class="text-unraid-red fill-current relative w-24px h-24px" />
<InformationCircleIcon
v-if="errors[0].level === 'info'"
class="text-unraid-red fill-current relative w-24px h-24px"
/>
<ExclamationTriangleIcon
v-if="errors[0].level === 'warning'"
class="text-unraid-red fill-current relative w-24px h-24px"
/>
<ShieldExclamationIcon
v-if="errors[0].level === 'error'"
class="text-unraid-red fill-current relative w-24px h-24px"
/>
</template>
<span v-if="text" class="relative leading-none ">
<span v-if="text" class="relative leading-none">
<span>{{ text }}</span>
<span class="absolute bottom-[-3px] inset-x-0 h-2px w-full bg-gradient-to-r from-unraid-red to-orange rounded opacity-0 group-hover:opacity-100 group-focus:opacity-100 transition-opacity" />
<span
class="absolute bottom-[-3px] inset-x-0 h-2px w-full bg-gradient-to-r from-unraid-red to-orange rounded opacity-0 group-hover:opacity-100 group-focus:opacity-100 transition-opacity"
/>
</span>
<BellAlertIcon v-if="osUpdateAvailable && !rebootType" class="hover:animate-pulse fill-current relative w-16px h-16px" />
<BellAlertIcon
v-if="osUpdateAvailable && !rebootType"
class="hover:animate-pulse fill-current relative w-16px h-16px"
/>
<Bars3Icon v-if="!dropdownVisible" class="w-20px" />
<Bars3BottomRightIcon v-else class="w-20px" />
<Bars3Icon class="w-20px" />
<BrandAvatar />
</button>
-159
View File
@@ -1,159 +0,0 @@
<script lang="ts" setup>
/**
* @todo future idea turn this into a carousel. each feature could have a short video if we ever them
*/
import { ArrowTopRightOnSquareIcon } from '@heroicons/vue/24/solid';
import { Switch, SwitchGroup, SwitchLabel } from '@headlessui/vue';
import { CONNECT_DOCS } from '~/helpers/urls';
import type { UserProfilePromoFeature } from '~/types/userProfile';
import type { ComposerTranslation } from 'vue-i18n';
import useInstallPlugin from '~/composables/installPlugin';
import { usePromoStore } from '~/store/promo';
export interface Props {
open?: boolean;
t: ComposerTranslation;
}
withDefaults(defineProps<Props>(), {
open: false,
});
const promoStore = usePromoStore();
/**
* These are translated in the component below. So if you add a new feature, make sure to add it to the translation file.
*/
const features = ref<UserProfilePromoFeature[]>([
{
title: 'Dynamic Remote Access',
copy: 'Toggle on/off server accessibility with dynamic remote access. Automatically turn on UPnP and open a random WAN port on your router at the click of a button and close off access in seconds.',
},
{
title: 'Manage Your Server Within Connect',
copy: 'Servers equipped with a myunraid.net certificate can be managed directly from within the Connect web UI. Manage multiple servers from your phone, tablet, laptop, or PC in the same browser window.',
},
{
title: 'Deep Linking',
copy: 'The Connect dashboard links to relevant sections of the webgui, allowing quick access to those settings and server sections.',
},
{
title: 'Online Flash Backup',
copy: 'Never ever be left without a backup of your config. If you need to change flash drives, generate a backup from Connect and be up and running in minutes.',
},
{
title: 'Real-time Monitoring',
copy: "Get an overview of your server's state, storage space, apps and VMs status, and more.",
},
{
title: 'Customizable Dashboard Tiles',
copy: "Set custom server tiles how you like and automatically display your server's banner image on your Connect Dashboard.",
},
{
title: 'License Management',
copy: 'Manage your license keys at any time via the My Keys section.',
},
{
title: 'Plus more on the way',
copy: 'All you need is an active internet connection, an Unraid.net account, and the Connect plugin. Get started by installing the plugin.',
},
]);
const staging = ref(false);
const connectPluginUrl = computed((): string => {
const url = new URL(
`https://sfo2.digitaloceanspaces.com/unraid-dl/unraid-api/dynamix.unraid.net${staging.value ? '.staging.plg' : '.plg'}`
);
return url.toString();
});
const { install } = useInstallPlugin();
</script>
<template>
<Modal
:t="t"
:title="t('Introducing Unraid Connect')"
:description="t('Enhance your Unraid experience')"
:open="open"
:show-close-x="true"
max-width="max-w-800px"
@close="promoStore.promoHide()"
>
<template #headerTitle>
<span><UpcBeta class="relative -top-1" /></span>
</template>
<template #main>
<div class="text-center relative w-full">
<div class="grid grid-cols-1 sm:grid-cols-2 justify-center p-16px md:py-24px gap-16px">
<UpcPromoFeature
v-for="(feature, index) in features"
:key="index"
:title="t(feature.title)"
:copy="t(feature.copy)"
/>
</div>
</div>
</template>
<template #footer>
<div class="w-full max-w-xs flex flex-col items-center gap-y-16px mx-auto">
<SwitchGroup v-if="import.meta.env.DEV" as="div" class="flex items-center justify-center">
<Switch
v-model="staging"
:class="[
staging ? 'bg-indigo-600' : 'bg-gray-200',
'relative inline-flex h-6 w-11 flex-shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors duration-200 ease-in-out focus:outline-none focus:ring-2 focus:ring-indigo-600 focus:ring-offset-2',
]"
>
<span
aria-hidden="true"
:class="[
staging ? 't-x-5' : 't-x-0',
'pointer-events-none inline-block h-5 w-5 transform rounded-full bg-white shadow ring-0 transition duration-200 ease-in-out',
]"
/>
</Switch>
<SwitchLabel as="span" class="ml-3 text-12px">
<span class="font-semibold">Install Staging</span>
</SwitchLabel>
</SwitchGroup>
<button
class="text-white text-14px text-center w-full flex flex-row items-center justify-center gap-x-8px px-8px py-8px cursor-pointer rounded-md bg-gradient-to-r from-unraid-red to-orange hover:from-unraid-red/60 hover:to-orange/60 focus:from-unraid-red/60 focus:to-orange/60"
@click="install({ pluginUrl: connectPluginUrl, modalTitle: t('Installing Connect') })"
>
{{ staging ? 'Install Connect Staging' : t('Install Connect') }}
</button>
<div>
<a
:href="CONNECT_DOCS.toString()"
class="text-12px tracking-wide inline-flex flex-row items-center justify-start gap-8px mx-8px opacity-60 hover:opacity-100 focus:opacity-100 underline transition"
target="_blank"
rel="noopener noreferrer"
:title="t('Checkout the Connect Documentation')"
>
{{ t('Learn More') }}
<ArrowTopRightOnSquareIcon class="w-16px" />
</a>
<button
class="text-12px tracking-wide inline-block mx-8px opacity-60 hover:opacity-100 focus:opacity-100 underline transition"
:title="t('Close')"
@click="promoStore.promoHide()"
>
{{ t('No thanks') }}
</button>
</div>
</div>
</template>
</Modal>
</template>
<style lang="postcss">
/* Import unraid-ui globals first */
@import '@unraid/ui/styles';
@import '~/assets/main.css';
</style>
@@ -1,39 +0,0 @@
<script setup lang="ts">
export interface Props {
center?: boolean;
copy?: string;
icon?: string;
title?: string;
}
defineProps<Props>();
</script>
<template>
<div class="text-left relative flex overflow-hidden">
<span v-if="!center" class="flex-shrink-0">
<slot />
</span>
<div class="inline-flex flex-col" :class="{ 'text-center': center }">
<h3
class="text-16px font-semibold"
:class="{
'mt-0 mb-4px': copy,
'my-0': !copy,
'flex flex-row justify-center items-center': center
}"
>
<span v-if="center" class="flex-shrink-0 mr-8px">
<slot />
</span>
{{ title }}
</h3>
<p
v-if="copy"
class="text-14px opacity-75 py-0"
:class="{'px-8px': center}"
v-html="copy"
/>
</div>
</div>
</template>
+1
View File
@@ -104,6 +104,7 @@
"marked-base-url": "^1.1.6",
"pinia": "^3.0.1",
"radix-vue": "^1.9.13",
"reka-ui": "^2.0.2",
"semver": "^7.6.3",
"tailwind-merge": "^2.5.5",
"vue-i18n": "^11.0.0",
+16 -9
View File
@@ -6,9 +6,9 @@ import AES from 'crypto-js/aes';
import type { SendPayloads } from '~/store/callback';
import LogViewerCe from '~/components/Logs/LogViewer.ce.vue';
import SsoButtonCe from '~/components/SsoButton.ce.vue';
import { useThemeStore } from '~/store/theme';
import LogViewerCe from '~/components/Logs/LogViewer.ce.vue';
const serverStore = useDummyServerStore();
const { serverState } = storeToRefs(serverStore);
@@ -79,12 +79,19 @@ onMounted(() => {
);
});
const bannerImage = watch(theme, () => {
if (theme.value.banner) {
return `url(https://picsum.photos/1920/200?${Math.round(Math.random() * 100)})`;
}
return 'none';
});
const bannerImage = ref<string>('none');
watch(
theme,
(newTheme) => {
if (newTheme.banner) {
bannerImage.value = `url(https://picsum.photos/1920/200?${Math.round(Math.random() * 100)})`;
} else {
bannerImage.value = 'none';
}
},
{ immediate: true }
);
</script>
<template>
@@ -96,12 +103,12 @@ const bannerImage = watch(theme, () => {
<ColorSwitcherCe />
<h2 class="text-xl font-semibold font-mono">Vue Components</h2>
<h3 class="text-lg font-semibold font-mono">UserProfileCe</h3>
<header
<header
class="bg-header-background-color flex justify-between items-center"
:style="{
backgroundImage: bannerImage,
backgroundSize: 'cover',
backgroundPosition: 'center'
backgroundPosition: 'center',
}"
>
<div class="inline-flex flex-col gap-4 items-start px-4">
+8 -23
View File
@@ -1,7 +1,6 @@
import { createPinia, defineStore, setActivePinia } from 'pinia';
import { useToggle } from '@vueuse/core';
import { defineStore, createPinia, setActivePinia } from 'pinia';
import { useServerStore } from './server';
import { useActivationCodeStore } from './activationCode';
/**
* @see https://stackoverflow.com/questions/73476371/using-pinia-with-vue-js-web-components
* @see https://github.com/vuejs/pinia/discussions/1085
@@ -11,28 +10,14 @@ setActivePinia(createPinia());
export const useDropdownStore = defineStore('dropdown', () => {
const dropdownVisible = ref<boolean>(false);
const dropdownHide = () => { dropdownVisible.value = false; };
const dropdownShow = () => { dropdownVisible.value = true; };
const dropdownHide = () => {
dropdownVisible.value = false;
};
const dropdownShow = () => {
dropdownVisible.value = true;
};
const dropdownToggle = useToggle(dropdownVisible);
/**
* Automatically open the user dropdown on first page load when ENOKEYFILE aka a new server
*/
const serverStore = useServerStore();
const activationCodeStore = useActivationCodeStore();
const { guid, state } = storeToRefs(serverStore);
const { showActivationModal } = storeToRefs(activationCodeStore);
const autoShowDropdown = computed(() => state.value === 'ENOKEYFILE' && !showActivationModal.value);
watch(autoShowDropdown, (newVal) => {
const autoOpenSessionStorage = `unraid_${guid.value.slice(-12) ?? 'NO_GUID'}_ENOKEYFILE`;
if (newVal && !sessionStorage.getItem(autoOpenSessionStorage)) {
sessionStorage.setItem(autoOpenSessionStorage, 'true');
dropdownShow();
}
});
return {
dropdownVisible,
dropdownHide,
-43
View File
@@ -1,43 +0,0 @@
import { useToggle } from '@vueuse/core';
import { defineStore, createPinia, setActivePinia } from 'pinia';
import { useDropdownStore } from '~/store/dropdown';
/**
* @see https://stackoverflow.com/questions/73476371/using-pinia-with-vue-js-web-components
* @see https://github.com/vuejs/pinia/discussions/1085
*/
setActivePinia(createPinia());
export const usePromoStore = defineStore('promo', () => {
const dropdownStore = useDropdownStore();
const promoVisible = ref<boolean>(false);
const openOnNextLoad = () => sessionStorage.setItem('unraidConnectPromo', 'show');
const promoHide = () => { promoVisible.value = false; };
const promoShow = () => { promoVisible.value = true; };
const promoToggle = useToggle(promoVisible);
watch(promoVisible, (newVal, _oldVal) => {
if (newVal) { // close the dropdown when the promo is opened
dropdownStore.dropdownHide();
}
});
onBeforeMount(() => {
if (sessionStorage.getItem('unraidConnectPromo') === 'show') {
sessionStorage.removeItem('unraidConnectPromo');
promoShow();
}
});
return {
promoVisible,
openOnNextLoad,
promoHide,
promoShow,
promoToggle,
};
});
+3 -7
View File
@@ -4,7 +4,9 @@ import type { ArrowTopRightOnSquareIcon } from '@heroicons/vue/24/solid';
// the click key can be a function that returns void or a promise that returns void
export type UserProfileLinkClickParams = string[] | number[] | undefined;
export type UserProfileLinkClick = ((...args: UserProfileLinkClickParams[]) => void | Promise<void>) | ((...args: UserProfileLinkClickParams[]) => Promise<NodeJS.Timeout | undefined>);
export type UserProfileLinkClick =
| ((...args: UserProfileLinkClickParams[]) => void | Promise<void>)
| ((...args: UserProfileLinkClickParams[]) => Promise<NodeJS.Timeout | undefined>);
export interface UserProfileLink {
click?: UserProfileLinkClick;
@@ -19,9 +21,3 @@ export interface UserProfileLink {
textParams?: string[] | number[];
title?: string;
}
export interface UserProfilePromoFeature {
copy: string;
icon?: typeof ArrowTopRightOnSquareIcon;
title: string;
}