From 118472945ffb10bd4e39d421fd3b1f9d55ce4563 Mon Sep 17 00:00:00 2001 From: Caleb Burke Date: Fri, 19 Jun 2026 23:55:39 -0700 Subject: [PATCH] basic tempate of web --- web/.browserslistrc | 4 + web/.eslintrc.cjs | 43 + web/.gitignore | 30 + web/.prettierrc.test.yaml | 9 + web/README.md | 18 + web/development.Dockerfile | 11 + web/index.html | 37 + web/package-lock.json | 6003 +++++++++++++++++ web/package.json | 63 + web/public/Logo.png | Bin 0 -> 6791 bytes web/public/Logo.svg | 9 + web/public/SplashImage.png | Bin 0 -> 17414 bytes web/public/favicon.ico | Bin 0 -> 202582 bytes web/public/yukon.svg | 8 + web/src/App.vue | 113 + web/src/api/api-error.ts | 12 + web/src/api/base-api.ts | 44 + web/src/api/current-user-api.ts | 23 + web/src/api/http-client.ts | 46 + web/src/api/status-api.ts | 18 + web/src/api/users-api.ts | 81 + web/src/assets/app_logo_big.png | Bin 0 -> 5133 bytes web/src/assets/app_logo_small.png | Bin 0 -> 2132 bytes web/src/assets/app_logo_splash.png | Bin 0 -> 3874 bytes web/src/components/common/AppBreadcrumbs.vue | 55 + web/src/components/common/AppCard.vue | 46 + web/src/components/common/AppLogo.vue | 50 + web/src/components/common/AppSnackbar.vue | 82 + web/src/components/common/CollapsibleCard.vue | 50 + web/src/components/common/ConfirmDialog.vue | 77 + .../components/common/DescriptionElement.vue | 76 + .../components/common/HeaderActionsCard.vue | 73 + .../common/HeaderActionsCardBody.vue | 74 + .../common/HeaderActionsFormCard.vue | 101 + web/src/components/common/PageLoader.vue | 17 + .../components/common/PercentageTextField.vue | 85 + .../components/common/ResponsiveDialog.vue | 83 + web/src/components/common/StringDateInput.vue | 70 + web/src/components/layout/DefaultAppBar.vue | 40 + web/src/components/layout/DefaultSideBar.vue | 70 + .../components/layout/ExactingBreadcrumbs.vue | 69 + web/src/components/layout/ProfileMenu.vue | 160 + web/src/components/layout/SearchMenu.vue | 59 + web/src/components/users/UserEditCardForm.vue | 196 + web/src/components/users/UserProfileCard.vue | 86 + web/src/components/users/UserRoleSelect.vue | 30 + .../components/users/UsersDataTableServer.vue | 107 + web/src/config.ts | 47 + web/src/directives/index.ts | 5 + web/src/directives/visible.ts | 27 + web/src/layouts/AdministrationLayout.vue | 49 + web/src/layouts/DefaultLayout.vue | 22 + web/src/layouts/LayoutWithBreadcrumbs.vue | 69 + web/src/layouts/ProfileLayout.vue | 33 + web/src/layouts/logo/AppLogo.vue | 50 + web/src/locales/en.js | 8 + web/src/main.ts | 25 + web/src/pages/CallbackPage.vue | 23 + web/src/pages/DashboardPage.vue | 16 + web/src/pages/ProfilePage.vue | 27 + web/src/pages/SignInPage.vue | 115 + web/src/pages/StatusPage.vue | 93 + .../AdministrationDashboardPage.vue | 118 + web/src/pages/administration/SettingsPage.vue | 14 + web/src/pages/administration/UsersPage.vue | 46 + .../administration/users/UserEditPage.vue | 70 + .../administration/users/UserNewPage.vue | 353 + web/src/pages/errors/ForbiddenPage.vue | 79 + .../pages/errors/InternalServerErrorPage.vue | 79 + web/src/pages/errors/NotFoundPage.vue | 79 + web/src/pages/errors/UnauthorizedPage.vue | 79 + web/src/pages/profile/ProfileEditPage.vue | 46 + web/src/plugins/auth0-plugin.ts | 14 + web/src/plugins/vue-i18n-plugin.ts | 13 + web/src/plugins/vuetify-plugin.ts | 86 + web/src/router.ts | 152 + web/src/routes/administration-routes.ts | 50 + web/src/scss/_override.scss | 204 + web/src/scss/_variables.scss | 150 + web/src/scss/components/_VAlert.scss | 24 + web/src/scss/components/_VBreadcrumb.scss | 9 + web/src/scss/components/_VButtons.scss | 22 + web/src/scss/components/_VCard.scss | 69 + web/src/scss/components/_VCarousel.scss | 3 + web/src/scss/components/_VDatatable.scss | 3 + web/src/scss/components/_VDatatables.scss | 99 + web/src/scss/components/_VExpansionpanel.scss | 6 + web/src/scss/components/_VField.scss | 29 + web/src/scss/components/_VInput.scss | 35 + web/src/scss/components/_VLabs.scss | 18 + web/src/scss/components/_VList.scss | 34 + .../scss/components/_VNavigationDrawer.scss | 3 + .../scss/components/_VSelectionControl.scss | 6 + web/src/scss/components/_VShadow.scss | 33 + web/src/scss/components/_VStepper.scss | 8 + web/src/scss/components/_VSwitch.scss | 48 + web/src/scss/components/_VTable.scss | 99 + web/src/scss/components/_VTabs.scss | 14 + web/src/scss/components/_VTextField.scss | 13 + web/src/scss/components/_VTextarea.scss | 7 + web/src/scss/front/_general.scss | 597 ++ web/src/scss/front/_header.scss | 104 + web/src/scss/layout/_container.scss | 40 + web/src/scss/layout/_customizer.scss | 93 + web/src/scss/layout/_dark.scss | 81 + web/src/scss/layout/_horizontal.scss | 231 + web/src/scss/layout/_reboot.scss | 109 + web/src/scss/layout/_rtl.scss | 341 + web/src/scss/layout/_sidebar.scss | 374 + web/src/scss/layout/_text.scss | 98 + web/src/scss/layout/_topbar.scss | 110 + web/src/scss/pages/_apps.scss | 240 + web/src/scss/pages/_authentication.scss | 90 + web/src/scss/pages/_dashboards.scss | 227 + web/src/scss/pages/_datatable.scss | 48 + web/src/scss/pages/_editor.scss | 61 + web/src/scss/style.scss | 91 + web/src/scss/theme/_themeColors.scss | 59 + web/src/theme/DarkTheme.ts | 191 + web/src/theme/LightTheme.ts | 40 + web/src/theme/ThemeTypes.ts | 33 + web/src/use/use-breadcrumbs.ts | 95 + web/src/use/use-current-user.ts | 74 + web/src/use/use-interface.ts | 46 + web/src/use/use-notifications.ts | 71 + web/src/use/use-snack.ts | 69 + web/src/use/use-status.ts | 47 + web/src/use/use-user.ts | 113 + web/src/use/use-users.ts | 62 + web/src/use/utils/use-page-title.ts | 22 + web/src/use/utils/use-route-query-enhanced.ts | 32 + .../use/utils/use-route-query-pagination.ts | 41 + ...color-classes-as-specific-color-classes.ts | 25 + .../use-vuetify-color-name-to-hex-value.ts | 12 + .../use-vuetify-slot-names-pass-through.ts | 26 + ...use-vuetify-sort-by-to-safe-route-query.ts | 53 + ...vuetify-sort-by-to-sequelize-safe-order.ts | 61 + .../authorization-guard.ts | 37 + web/src/utils/authorization-guards/index.ts | 2 + .../utils/authorization-guards/user-guards.ts | 6 + web/src/utils/debounce-with-args-cache.ts | 57 + web/src/utils/formatters/format-bytes.ts | 13 + web/src/utils/formatters/format-date-long.ts | 21 + web/src/utils/formatters/format-date-words.ts | 16 + web/src/utils/formatters/format-date.ts | 18 + ...ormat-number-in-string-to-fixed-decimal.ts | 24 + web/src/utils/formatters/format-relative.ts | 16 + web/src/utils/formatters/index.ts | 6 + web/src/utils/safe-json-parse.ts | 14 + web/src/utils/sleep.ts | 3 + web/src/utils/strip-trailing-slash.ts | 3 + .../boolean-transformer.ts | 22 + .../use-route-query-transformers/index.ts | 4 + .../integer-transformer-legacy.ts | 9 + .../integer-transformer.ts | 27 + .../string-transformer.ts | 16 + web/src/utils/utility-types.ts | 5 + web/src/utils/validators/email.ts | 7 + web/src/utils/validators/index.ts | 4 + web/src/utils/validators/minimum.ts | 13 + web/src/utils/validators/required-file.ts | 20 + web/src/utils/validators/required.ts | 15 + web/src/vite-env.d.ts | 1 + web/tests/setup.ts | 7 + web/tests/support/index.ts | 2 + web/tests/support/mock-current-user-api.ts | 54 + web/tests/support/mock-http-client.ts | 40 + web/tests/tsconfig.json | 12 + .../authorization-guard.test.ts | 41 + web/tsconfig.json | 29 + web/tsconfig.node.json | 11 + web/vite.config.js | 45 + 172 files changed, 15878 insertions(+) create mode 100644 web/.browserslistrc create mode 100644 web/.eslintrc.cjs create mode 100644 web/.gitignore create mode 100644 web/.prettierrc.test.yaml create mode 100644 web/README.md create mode 100644 web/development.Dockerfile create mode 100644 web/index.html create mode 100644 web/package-lock.json create mode 100644 web/package.json create mode 100644 web/public/Logo.png create mode 100644 web/public/Logo.svg create mode 100644 web/public/SplashImage.png create mode 100644 web/public/favicon.ico create mode 100644 web/public/yukon.svg create mode 100644 web/src/App.vue create mode 100644 web/src/api/api-error.ts create mode 100644 web/src/api/base-api.ts create mode 100644 web/src/api/current-user-api.ts create mode 100644 web/src/api/http-client.ts create mode 100644 web/src/api/status-api.ts create mode 100644 web/src/api/users-api.ts create mode 100644 web/src/assets/app_logo_big.png create mode 100644 web/src/assets/app_logo_small.png create mode 100644 web/src/assets/app_logo_splash.png create mode 100644 web/src/components/common/AppBreadcrumbs.vue create mode 100644 web/src/components/common/AppCard.vue create mode 100644 web/src/components/common/AppLogo.vue create mode 100644 web/src/components/common/AppSnackbar.vue create mode 100644 web/src/components/common/CollapsibleCard.vue create mode 100644 web/src/components/common/ConfirmDialog.vue create mode 100644 web/src/components/common/DescriptionElement.vue create mode 100644 web/src/components/common/HeaderActionsCard.vue create mode 100644 web/src/components/common/HeaderActionsCardBody.vue create mode 100644 web/src/components/common/HeaderActionsFormCard.vue create mode 100644 web/src/components/common/PageLoader.vue create mode 100644 web/src/components/common/PercentageTextField.vue create mode 100644 web/src/components/common/ResponsiveDialog.vue create mode 100644 web/src/components/common/StringDateInput.vue create mode 100644 web/src/components/layout/DefaultAppBar.vue create mode 100644 web/src/components/layout/DefaultSideBar.vue create mode 100644 web/src/components/layout/ExactingBreadcrumbs.vue create mode 100644 web/src/components/layout/ProfileMenu.vue create mode 100644 web/src/components/layout/SearchMenu.vue create mode 100644 web/src/components/users/UserEditCardForm.vue create mode 100644 web/src/components/users/UserProfileCard.vue create mode 100644 web/src/components/users/UserRoleSelect.vue create mode 100644 web/src/components/users/UsersDataTableServer.vue create mode 100644 web/src/config.ts create mode 100644 web/src/directives/index.ts create mode 100644 web/src/directives/visible.ts create mode 100644 web/src/layouts/AdministrationLayout.vue create mode 100644 web/src/layouts/DefaultLayout.vue create mode 100644 web/src/layouts/LayoutWithBreadcrumbs.vue create mode 100644 web/src/layouts/ProfileLayout.vue create mode 100644 web/src/layouts/logo/AppLogo.vue create mode 100644 web/src/locales/en.js create mode 100644 web/src/main.ts create mode 100644 web/src/pages/CallbackPage.vue create mode 100644 web/src/pages/DashboardPage.vue create mode 100644 web/src/pages/ProfilePage.vue create mode 100644 web/src/pages/SignInPage.vue create mode 100644 web/src/pages/StatusPage.vue create mode 100644 web/src/pages/administration/AdministrationDashboardPage.vue create mode 100644 web/src/pages/administration/SettingsPage.vue create mode 100644 web/src/pages/administration/UsersPage.vue create mode 100644 web/src/pages/administration/users/UserEditPage.vue create mode 100644 web/src/pages/administration/users/UserNewPage.vue create mode 100644 web/src/pages/errors/ForbiddenPage.vue create mode 100644 web/src/pages/errors/InternalServerErrorPage.vue create mode 100644 web/src/pages/errors/NotFoundPage.vue create mode 100644 web/src/pages/errors/UnauthorizedPage.vue create mode 100644 web/src/pages/profile/ProfileEditPage.vue create mode 100644 web/src/plugins/auth0-plugin.ts create mode 100644 web/src/plugins/vue-i18n-plugin.ts create mode 100644 web/src/plugins/vuetify-plugin.ts create mode 100644 web/src/router.ts create mode 100644 web/src/routes/administration-routes.ts create mode 100644 web/src/scss/_override.scss create mode 100644 web/src/scss/_variables.scss create mode 100644 web/src/scss/components/_VAlert.scss create mode 100644 web/src/scss/components/_VBreadcrumb.scss create mode 100644 web/src/scss/components/_VButtons.scss create mode 100644 web/src/scss/components/_VCard.scss create mode 100644 web/src/scss/components/_VCarousel.scss create mode 100644 web/src/scss/components/_VDatatable.scss create mode 100644 web/src/scss/components/_VDatatables.scss create mode 100644 web/src/scss/components/_VExpansionpanel.scss create mode 100644 web/src/scss/components/_VField.scss create mode 100644 web/src/scss/components/_VInput.scss create mode 100644 web/src/scss/components/_VLabs.scss create mode 100644 web/src/scss/components/_VList.scss create mode 100644 web/src/scss/components/_VNavigationDrawer.scss create mode 100644 web/src/scss/components/_VSelectionControl.scss create mode 100644 web/src/scss/components/_VShadow.scss create mode 100644 web/src/scss/components/_VStepper.scss create mode 100644 web/src/scss/components/_VSwitch.scss create mode 100644 web/src/scss/components/_VTable.scss create mode 100644 web/src/scss/components/_VTabs.scss create mode 100644 web/src/scss/components/_VTextField.scss create mode 100644 web/src/scss/components/_VTextarea.scss create mode 100644 web/src/scss/front/_general.scss create mode 100644 web/src/scss/front/_header.scss create mode 100644 web/src/scss/layout/_container.scss create mode 100644 web/src/scss/layout/_customizer.scss create mode 100644 web/src/scss/layout/_dark.scss create mode 100644 web/src/scss/layout/_horizontal.scss create mode 100644 web/src/scss/layout/_reboot.scss create mode 100644 web/src/scss/layout/_rtl.scss create mode 100644 web/src/scss/layout/_sidebar.scss create mode 100644 web/src/scss/layout/_text.scss create mode 100644 web/src/scss/layout/_topbar.scss create mode 100644 web/src/scss/pages/_apps.scss create mode 100644 web/src/scss/pages/_authentication.scss create mode 100644 web/src/scss/pages/_dashboards.scss create mode 100644 web/src/scss/pages/_datatable.scss create mode 100644 web/src/scss/pages/_editor.scss create mode 100644 web/src/scss/style.scss create mode 100644 web/src/scss/theme/_themeColors.scss create mode 100644 web/src/theme/DarkTheme.ts create mode 100644 web/src/theme/LightTheme.ts create mode 100644 web/src/theme/ThemeTypes.ts create mode 100644 web/src/use/use-breadcrumbs.ts create mode 100644 web/src/use/use-current-user.ts create mode 100644 web/src/use/use-interface.ts create mode 100644 web/src/use/use-notifications.ts create mode 100644 web/src/use/use-snack.ts create mode 100644 web/src/use/use-status.ts create mode 100644 web/src/use/use-user.ts create mode 100644 web/src/use/use-users.ts create mode 100644 web/src/use/utils/use-page-title.ts create mode 100644 web/src/use/utils/use-route-query-enhanced.ts create mode 100644 web/src/use/utils/use-route-query-pagination.ts create mode 100644 web/src/use/utils/use-vuetify-color-classes-as-specific-color-classes.ts create mode 100644 web/src/use/utils/use-vuetify-color-name-to-hex-value.ts create mode 100644 web/src/use/utils/use-vuetify-slot-names-pass-through.ts create mode 100644 web/src/use/utils/use-vuetify-sort-by-to-safe-route-query.ts create mode 100644 web/src/use/utils/use-vuetify-sort-by-to-sequelize-safe-order.ts create mode 100644 web/src/utils/authorization-guards/authorization-guard.ts create mode 100644 web/src/utils/authorization-guards/index.ts create mode 100644 web/src/utils/authorization-guards/user-guards.ts create mode 100644 web/src/utils/debounce-with-args-cache.ts create mode 100644 web/src/utils/formatters/format-bytes.ts create mode 100644 web/src/utils/formatters/format-date-long.ts create mode 100644 web/src/utils/formatters/format-date-words.ts create mode 100644 web/src/utils/formatters/format-date.ts create mode 100644 web/src/utils/formatters/format-number-in-string-to-fixed-decimal.ts create mode 100644 web/src/utils/formatters/format-relative.ts create mode 100644 web/src/utils/formatters/index.ts create mode 100644 web/src/utils/safe-json-parse.ts create mode 100644 web/src/utils/sleep.ts create mode 100644 web/src/utils/strip-trailing-slash.ts create mode 100644 web/src/utils/use-route-query-transformers/boolean-transformer.ts create mode 100644 web/src/utils/use-route-query-transformers/index.ts create mode 100644 web/src/utils/use-route-query-transformers/integer-transformer-legacy.ts create mode 100644 web/src/utils/use-route-query-transformers/integer-transformer.ts create mode 100644 web/src/utils/use-route-query-transformers/string-transformer.ts create mode 100644 web/src/utils/utility-types.ts create mode 100644 web/src/utils/validators/email.ts create mode 100644 web/src/utils/validators/index.ts create mode 100644 web/src/utils/validators/minimum.ts create mode 100644 web/src/utils/validators/required-file.ts create mode 100644 web/src/utils/validators/required.ts create mode 100644 web/src/vite-env.d.ts create mode 100644 web/tests/setup.ts create mode 100644 web/tests/support/index.ts create mode 100644 web/tests/support/mock-current-user-api.ts create mode 100644 web/tests/support/mock-http-client.ts create mode 100644 web/tests/tsconfig.json create mode 100644 web/tests/utils/authorization-guards/authorization-guard.test.ts create mode 100644 web/tsconfig.json create mode 100644 web/tsconfig.node.json create mode 100644 web/vite.config.js diff --git a/web/.browserslistrc b/web/.browserslistrc new file mode 100644 index 0000000..dc3bc09 --- /dev/null +++ b/web/.browserslistrc @@ -0,0 +1,4 @@ +> 1% +last 2 versions +not dead +not ie 11 diff --git a/web/.eslintrc.cjs b/web/.eslintrc.cjs new file mode 100644 index 0000000..9a89770 --- /dev/null +++ b/web/.eslintrc.cjs @@ -0,0 +1,43 @@ +// https://github.com/typescript-eslint/typescript-eslint/issues/251 +module.exports = { + root: true, + env: { + browser: true, + es2021: true, + node: true, + }, + extends: [ + "eslint:recommended", + "plugin:vue/vue3-recommended", + "plugin:@typescript-eslint/recommended", + "plugin:prettier/recommended", + ], + overrides: [], + parser: "vue-eslint-parser", + parserOptions: { + ecmaVersion: "latest", + extraFileExtensions: [".vue"], + parser: "@typescript-eslint/parser", + tsconfigRootDir: __dirname, + project: ["./tsconfig.node.json", "./tsconfig.json", "./tests/tsconfig.json"], + sourceType: "module", + }, + plugins: ["vue", "@typescript-eslint", "prettier"], + rules: { + // Override/add rules' settings here + "vue/valid-v-slot": [ + "error", + { + allowModifiers: true, + }, + ], + "@typescript-eslint/no-unused-vars": [ + "error", + { + argsIgnorePattern: "^_", + varsIgnorePattern: "^_", + caughtErrorsIgnorePattern: "^_", + }, + ], + }, +} diff --git a/web/.gitignore b/web/.gitignore new file mode 100644 index 0000000..8ee54e8 --- /dev/null +++ b/web/.gitignore @@ -0,0 +1,30 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +.DS_Store +dist +dist-ssr +coverage +*.local + +/cypress/videos/ +/cypress/screenshots/ + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? + +*.tsbuildinfo diff --git a/web/.prettierrc.test.yaml b/web/.prettierrc.test.yaml new file mode 100644 index 0000000..5dfa752 --- /dev/null +++ b/web/.prettierrc.test.yaml @@ -0,0 +1,9 @@ +$schema: "https://json.schemastore.org/prettierrc" +embeddedLanguageFormatting: "auto" +trailingComma: "es5" +tabWidth: 2 +semi: false +singleQuote: false +singleAttributePerLine: true +useTabs: false +printWidth: 100 diff --git a/web/README.md b/web/README.md new file mode 100644 index 0000000..ef72fd5 --- /dev/null +++ b/web/README.md @@ -0,0 +1,18 @@ +# Vue 3 + TypeScript + Vite + +This template should help get you started developing with Vue 3 and TypeScript in Vite. The template uses Vue 3 ` + + diff --git a/web/package-lock.json b/web/package-lock.json new file mode 100644 index 0000000..c43b330 --- /dev/null +++ b/web/package-lock.json @@ -0,0 +1,6003 @@ +{ + "name": "alphane-web", + "version": "0.1.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "alphane-web", + "version": "0.1.0", + "dependencies": { + "@auth0/auth0-vue": "^2.5.0", + "@mdi/font": "^7.4.47", + "@tabler/icons-vue": "^3.36.0", + "@vueuse/core": "^13.9.0", + "@vueuse/router": "^13.9.0", + "axios": "^1.13.2", + "dompurify": "^3.3.3", + "grid-layout-plus": "^1.1.1", + "js-yaml": "^4.1.0", + "lodash": "^4.17.21", + "luxon": "^3.7.2", + "marked": "^17.0.5", + "md5": "^2.3.0", + "qs": "^6.14.0", + "validator": "^13.15.26", + "vue": "^3.4.21", + "vue-draggable-next": "^2.3.0", + "vue-i18n": "^11.3.0", + "vue-router": "^4.6.4", + "vue-scrollto": "^2.20.0", + "vuetify": "^3.11.4" + }, + "devDependencies": { + "@types/dompurify": "^3.0.5", + "@types/js-yaml": "^4.0.9", + "@types/lodash": "^4.17.21", + "@types/luxon": "^3.7.1", + "@types/md5": "^2.3.6", + "@types/qs": "^6.14.0", + "@types/validator": "^13.15.10", + "@typescript-eslint/eslint-plugin": "^8.50.1", + "@typescript-eslint/parser": "^8.50.1", + "@vitejs/plugin-vue": "^6.0.3", + "eslint": "^8.57.1", + "eslint-config-prettier": "^10.1.8", + "eslint-plugin-prettier": "^5.5.4", + "eslint-plugin-vue": "^9.33.0", + "jsdom": "^26.1.0", + "prettier": "^3.7.4", + "prettier-plugin-embed": "^0.5.1", + "prettier-plugin-sql": "^0.19.2", + "sass": "^1.97.1", + "typescript": "^5.9.3", + "vite": "^7.3.0", + "vite-plugin-vuetify": "^2.1.2", + "vitest": "^3.2.4", + "vue-tsc": "^3.2.1" + } + }, + "node_modules/@asamuzakjp/css-color": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/@asamuzakjp/css-color/-/css-color-3.2.0.tgz", + "integrity": "sha512-K1A6z8tS3XsmCMM86xoWdn7Fkdn9m6RSVtocUrJYIwZnFVkng/PvkEoWtOWmP+Scc6saYWHWZYbndEEXxl24jw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@csstools/css-calc": "^2.1.3", + "@csstools/css-color-parser": "^3.0.9", + "@csstools/css-parser-algorithms": "^3.0.4", + "@csstools/css-tokenizer": "^3.0.3", + "lru-cache": "^10.4.3" + } + }, + "node_modules/@auth0/auth0-auth-js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/@auth0/auth0-auth-js/-/auth0-auth-js-1.9.1.tgz", + "integrity": "sha512-YY8/We7NpJyN8aDlYZI0ENRFlPsuFQ5NGETI4dkJa+BEwCibNTRlM1E9O9qc77K4TpOANZsmaADSMde2If+Alg==", + "license": "MIT", + "dependencies": { + "jose": "^6.0.8", + "openid-client": "^6.8.0" + } + }, + "node_modules/@auth0/auth0-spa-js": { + "version": "2.21.2", + "resolved": "https://registry.npmjs.org/@auth0/auth0-spa-js/-/auth0-spa-js-2.21.2.tgz", + "integrity": "sha512-CkIzlTJeae0LbYluXgNRPs7X8+Yd7W8ya/d1Cq/AGZ0d5/gfWwgDdFv9tCQR59KhRqdmvESSJUaIQjcjD0B1aA==", + "license": "MIT", + "dependencies": { + "@auth0/auth0-auth-js": "1.9.1", + "browser-tabs-lock": "1.3.0", + "dpop": "2.1.1", + "es-cookie": "1.3.2" + } + }, + "node_modules/@auth0/auth0-vue": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/@auth0/auth0-vue/-/auth0-vue-2.7.0.tgz", + "integrity": "sha512-7Jw8jCNH0rQQkBP31QUKQDaMXHMcS3Qg3g7Ia6deYKe9/jDgYbMFBus/R8dcq8WZLAuI+06yTcvMzUi7w3WHNQ==", + "license": "MIT", + "dependencies": { + "@auth0/auth0-spa-js": "^2.10.0", + "vue": "^3.5.21" + }, + "peerDependencies": { + "vue-router": "^4.0.12 || ^5.0.0" + }, + "peerDependenciesMeta": { + "vue-router": { + "optional": true + } + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.29.7.tgz", + "integrity": "sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz", + "integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.7.tgz", + "integrity": "sha512-hnORnjP/1P/zFEndoeX+n+t1RwWRJiJpM/jO7FW32Kn9r5+sJB2JWOdYo4L6k78j15eCwY3Gm/7364B1EMwtNg==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.7" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/types": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.7.tgz", + "integrity": "sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA==", + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@csstools/color-helpers": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@csstools/color-helpers/-/color-helpers-5.1.0.tgz", + "integrity": "sha512-S11EXWJyy0Mz5SYvRmY8nJYTFFd1LCNV+7cXyAgQtOOuzb4EsgfqDufL+9esx72/eLhsRdGZwaldu/h+E4t4BA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "engines": { + "node": ">=18" + } + }, + "node_modules/@csstools/css-calc": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@csstools/css-calc/-/css-calc-2.1.4.tgz", + "integrity": "sha512-3N8oaj+0juUw/1H3YwmDDJXCgTB1gKU6Hc/bB502u9zR0q2vd786XJH9QfrKIEgFlZmhZiq6epXl4rHqhzsIgQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4" + } + }, + "node_modules/@csstools/css-color-parser": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@csstools/css-color-parser/-/css-color-parser-3.1.0.tgz", + "integrity": "sha512-nbtKwh3a6xNVIp/VRuXV64yTKnb1IjTAEEh3irzS+HkKjAOYLTGNb9pmVNntZ8iVBHcWDA2Dof0QtPgFI1BaTA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "dependencies": { + "@csstools/color-helpers": "^5.1.0", + "@csstools/css-calc": "^2.1.4" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4" + } + }, + "node_modules/@csstools/css-parser-algorithms": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-3.0.5.tgz", + "integrity": "sha512-DaDeUkXZKjdGhgYaHNJTV9pV7Y9B3b644jCLs9Upc3VeNGg6LWARAT6O+Q+/COo+2gg/bM5rhpMAtf70WqfBdQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@csstools/css-tokenizer": "^3.0.4" + } + }, + "node_modules/@csstools/css-tokenizer": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@csstools/css-tokenizer/-/css-tokenizer-3.0.4.tgz", + "integrity": "sha512-Vd/9EVDiu6PPJt9yAh6roZP6El1xHrdvIVGjyBsHR0RYwNHgL7FJPyIIW4fANJNG6FtyZfvlRPpFI4ZM/lubvw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.7.tgz", + "integrity": "sha512-EKX3Qwmhz1eMdEJokhALr0YiD0lhQNwDqkPYyPhiSwKrh7/4KRjQc04sZ8db+5DVVnZ1LmbNDI1uAMPEUBnQPg==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.7.tgz", + "integrity": "sha512-jbPXvB4Yj2yBV7HUfE2KHe4GJX51QplCN1pGbYjvsyCZbQmies29EoJbkEc+vYuU5o45AfQn37vZlyXy4YJ8RQ==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.7.tgz", + "integrity": "sha512-62dPZHpIXzvChfvfLJow3q5dDtiNMkwiRzPylSCfriLvZeq0a1bWChrGx/BbUbPwOrsWKMn8idSllklzBy+dgQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.7.tgz", + "integrity": "sha512-x5VpMODneVDb70PYV2VQOmIUUiBtY3D3mPBG8NxVk5CogneYhkR7MmM3yR/uMdITLrC1ml/NV1rj4bMJuy9MCg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.7.tgz", + "integrity": "sha512-5lckdqeuBPlKUwvoCXIgI2D9/ABmPq3Rdp7IfL70393YgaASt7tbju3Ac+ePVi3KDH6N2RqePfHnXkaDtY9fkw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.7.tgz", + "integrity": "sha512-rYnXrKcXuT7Z+WL5K980jVFdvVKhCHhUwid+dDYQpH+qu+TefcomiMAJpIiC2EM3Rjtq0sO3StMV/+3w3MyyqQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.7.tgz", + "integrity": "sha512-B48PqeCsEgOtzME2GbNM2roU29AMTuOIN91dsMO30t+Ydis3z/3Ngoj5hhnsOSSwNzS+6JppqWsuhTp6E82l2w==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.7.tgz", + "integrity": "sha512-jOBDK5XEjA4m5IJK3bpAQF9/Lelu/Z9ZcdhTRLf4cajlB+8VEhFFRjWgfy3M1O4rO2GQ/b2dLwCUGpiF/eATNQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.7.tgz", + "integrity": "sha512-RkT/YXYBTSULo3+af8Ib0ykH8u2MBh57o7q/DAs3lTJlyVQkgQvlrPTnjIzzRPQyavxtPtfg0EopvDyIt0j1rA==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.7.tgz", + "integrity": "sha512-RZPHBoxXuNnPQO9rvjh5jdkRmVizktkT7TCDkDmQ0W2SwHInKCAV95GRuvdSvA7w4VMwfCjUiPwDi0ZO6Nfe9A==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.7.tgz", + "integrity": "sha512-GA48aKNkyQDbd3KtkplYWT102C5sn/EZTY4XROkxONgruHPU72l+gW+FfF8tf2cFjeHaRbWpOYa/uRBz/Xq1Pg==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.7.tgz", + "integrity": "sha512-a4POruNM2oWsD4WKvBSEKGIiWQF8fZOAsycHOt6JBpZ+JN2n2JH9WAv56SOyu9X5IqAjqSIPTaJkqN8F7XOQ5Q==", + "cpu": [ + "loong64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.7.tgz", + "integrity": "sha512-KabT5I6StirGfIz0FMgl1I+R1H73Gp0ofL9A3nG3i/cYFJzKHhouBV5VWK1CSgKvVaG4q1RNpCTR2LuTVB3fIw==", + "cpu": [ + "mips64el" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.7.tgz", + "integrity": "sha512-gRsL4x6wsGHGRqhtI+ifpN/vpOFTQtnbsupUF5R5YTAg+y/lKelYR1hXbnBdzDjGbMYjVJLJTd2OFmMewAgwlQ==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.7.tgz", + "integrity": "sha512-hL25LbxO1QOngGzu2U5xeXtxXcW+/GvMN3ejANqXkxZ/opySAZMrc+9LY/WyjAan41unrR3YrmtTsUpwT66InQ==", + "cpu": [ + "riscv64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.7.tgz", + "integrity": "sha512-2k8go8Ycu1Kb46vEelhu1vqEP+UeRVj2zY1pSuPdgvbd5ykAw82Lrro28vXUrRmzEsUV0NzCf54yARIK8r0fdw==", + "cpu": [ + "s390x" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.7.tgz", + "integrity": "sha512-hzznmADPt+OmsYzw1EE33ccA+HPdIqiCRq7cQeL1Jlq2gb1+OyWBkMCrYGBJ+sxVzve2ZJEVeePbLM2iEIZSxA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.7.tgz", + "integrity": "sha512-b6pqtrQdigZBwZxAn1UpazEisvwaIDvdbMbmrly7cDTMFnw/+3lVxxCTGOrkPVnsYIosJJXAsILG9XcQS+Yu6w==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.7.tgz", + "integrity": "sha512-OfatkLojr6U+WN5EDYuoQhtM+1xco+/6FSzJJnuWiUw5eVcicbyK3dq5EeV/QHT1uy6GoDhGbFpprUiHUYggrw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.7.tgz", + "integrity": "sha512-AFuojMQTxAz75Fo8idVcqoQWEHIXFRbOc1TrVcFSgCZtQfSdc1RXgB3tjOn/krRHENUB4j00bfGjyl2mJrU37A==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.7.tgz", + "integrity": "sha512-+A1NJmfM8WNDv5CLVQYJ5PshuRm/4cI6WMZRg1by1GwPIQPCTs1GLEUHwiiQGT5zDdyLiRM/l1G0Pv54gvtKIg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.7.tgz", + "integrity": "sha512-+KrvYb/C8zA9CU/g0sR6w2RBw7IGc5J2BPnc3dYc5VJxHCSF1yNMxTV5LQ7GuKteQXZtspjFbiuW5/dOj7H4Yw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.7.tgz", + "integrity": "sha512-ikktIhFBzQNt/QDyOL580ti9+5mL/YZeUPKU2ivGtGjdTYoqz6jObj6nOMfhASpS4GU4Q/Clh1QtxWAvcYKamA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.7.tgz", + "integrity": "sha512-7yRhbHvPqSpRUV7Q20VuDwbjW5kIMwTHpptuUzV+AA46kiPze5Z7qgt6CLCK3pWFrHeNfDd1VKgyP4O+ng17CA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.7.tgz", + "integrity": "sha512-SmwKXe6VHIyZYbBLJrhOoCJRB/Z1tckzmgTLfFYOfpMAx63BJEaL9ExI8x7v0oAO3Zh6D/Oi1gVxEYr5oUCFhw==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.7.tgz", + "integrity": "sha512-56hiAJPhwQ1R4i+21FVF7V8kSD5zZTdHcVuRFMW0hn753vVfQN8xlx4uOPT4xoGH0Z/oVATuR82AiqSTDIpaHg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.9.1", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz", + "integrity": "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz", + "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", + "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.6.0", + "globals": "^13.19.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.15.tgz", + "integrity": "sha512-EwOCDEex4quD37XhqM3omwtMoJjr//isUZz1JopUNWms+4Z2ViyM/k1YIRePpoVNnQhENnxtFjLaxNHrT7xIUg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@eslint/eslintrc/node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/@eslint/eslintrc/node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@eslint/js": { + "version": "8.57.1", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.1.tgz", + "integrity": "sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/@floating-ui/core": { + "version": "1.7.5", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.7.5.tgz", + "integrity": "sha512-1Ih4WTWyw0+lKyFMcBHGbb5U5FtuHJuujoyyr5zTaWS5EYMeT6Jb2AuDeftsCsEuchO+mM2ij5+q9crhydzLhQ==", + "license": "MIT", + "dependencies": { + "@floating-ui/utils": "^0.2.11" + } + }, + "node_modules/@floating-ui/dom": { + "version": "1.7.6", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.7.6.tgz", + "integrity": "sha512-9gZSAI5XM36880PPMm//9dfiEngYoC6Am2izES1FF406YFsjvyBMmeJ2g4SAju3xWwtuynNRFL2s9hgxpLI5SQ==", + "license": "MIT", + "dependencies": { + "@floating-ui/core": "^1.7.5", + "@floating-ui/utils": "^0.2.11" + } + }, + "node_modules/@floating-ui/utils": { + "version": "0.2.11", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.11.tgz", + "integrity": "sha512-RiB/yIh78pcIxl6lLMG0CgBXAZ2Y0eVHqMPYugu+9U0AeT6YBeiJpf7lbdJNIugFP5SIjwNRgo4DhR1Qxi26Gg==", + "license": "MIT" + }, + "node_modules/@humanwhocodes/config-array": { + "version": "0.13.0", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz", + "integrity": "sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==", + "deprecated": "Use @eslint/config-array instead", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanwhocodes/object-schema": "^2.0.3", + "debug": "^4.3.1", + "minimatch": "^3.0.5" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/@humanwhocodes/config-array/node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@humanwhocodes/config-array/node_modules/brace-expansion": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.15.tgz", + "integrity": "sha512-EwOCDEex4quD37XhqM3omwtMoJjr//isUZz1JopUNWms+4Z2ViyM/k1YIRePpoVNnQhENnxtFjLaxNHrT7xIUg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@humanwhocodes/config-array/node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/object-schema": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", + "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", + "deprecated": "Use @eslint/object-schema instead", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/@interactjs/types": { + "version": "1.10.27", + "resolved": "https://registry.npmjs.org/@interactjs/types/-/types-1.10.27.tgz", + "integrity": "sha512-BUdv0cvs4H5ODuwft2Xp4eL8Vmi3LcihK42z0Ft/FbVJZoRioBsxH+LlsBdK4tAie7PqlKGy+1oyOncu1nQ6eA==", + "license": "MIT" + }, + "node_modules/@intlify/core-base": { + "version": "11.4.6", + "resolved": "https://registry.npmjs.org/@intlify/core-base/-/core-base-11.4.6.tgz", + "integrity": "sha512-EOeHO95XESK9IFHgHeZXunsM/WBAoCA0DlaWODvx14vKmetAuS97t+l6Xe9hTUqntPpF93vtVSjjUDafw3wXMw==", + "license": "MIT", + "dependencies": { + "@intlify/devtools-types": "11.4.6", + "@intlify/message-compiler": "11.4.6", + "@intlify/shared": "11.4.6" + }, + "engines": { + "node": ">= 22" + }, + "funding": { + "url": "https://github.com/sponsors/kazupon" + } + }, + "node_modules/@intlify/devtools-types": { + "version": "11.4.6", + "resolved": "https://registry.npmjs.org/@intlify/devtools-types/-/devtools-types-11.4.6.tgz", + "integrity": "sha512-wowQPpNem56b2d43IJmqbrzG2FeBKe5f/kUGlpNuBmXs6OSqncF8m1+1lxHuW8ISZJF0ma2RkW3iLkw0g0G4VA==", + "license": "MIT", + "dependencies": { + "@intlify/core-base": "11.4.6", + "@intlify/shared": "11.4.6" + }, + "engines": { + "node": ">= 22" + }, + "funding": { + "url": "https://github.com/sponsors/kazupon" + } + }, + "node_modules/@intlify/message-compiler": { + "version": "11.4.6", + "resolved": "https://registry.npmjs.org/@intlify/message-compiler/-/message-compiler-11.4.6.tgz", + "integrity": "sha512-5nj3jULqeTAC1WovwMs1LQWgatTa2pM/rXN9T3XW8rdOtXW9ZF6/GLSNFTKDQmPLwclhPdgUWLJ/4w3fMeeC/Q==", + "license": "MIT", + "dependencies": { + "@intlify/shared": "11.4.6", + "source-map-js": "^1.0.2" + }, + "engines": { + "node": ">= 22" + }, + "funding": { + "url": "https://github.com/sponsors/kazupon" + } + }, + "node_modules/@intlify/shared": { + "version": "11.4.6", + "resolved": "https://registry.npmjs.org/@intlify/shared/-/shared-11.4.6.tgz", + "integrity": "sha512-m1p1HHAMLhqSpTRH7VnXdrN0CQ4y+9vunFkpLkbD8soIuBsnQdawZXqMCgvwI2UVF9Ww7sVaw7g9tV2VO7shoA==", + "license": "MIT", + "engines": { + "node": ">= 22" + }, + "funding": { + "url": "https://github.com/sponsors/kazupon" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "license": "MIT" + }, + "node_modules/@juggle/resize-observer": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/@juggle/resize-observer/-/resize-observer-3.4.0.tgz", + "integrity": "sha512-dfLbk+PwWvFzSxwk3n5ySL0hfBog779o8h68wK/7/APo/7cgyWp5jcXockbxdk5kFRkbeXWm4Fbi9FrdN381sA==", + "license": "Apache-2.0" + }, + "node_modules/@mdi/font": { + "version": "7.4.47", + "resolved": "https://registry.npmjs.org/@mdi/font/-/font-7.4.47.tgz", + "integrity": "sha512-43MtGpd585SNzHZPcYowu/84Vz2a2g31TvPMTm9uTiCSWzaheQySUcSyUH/46fPnuPQWof2yd0pGBtzee/IQWw==", + "license": "Apache-2.0" + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@parcel/watcher": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.5.6.tgz", + "integrity": "sha512-tmmZ3lQxAe/k/+rNnXQRawJ4NjxO2hqiOLTHvWchtGZULp4RyFeh6aU4XdOYBFe2KE1oShQTv4AblOs2iOrNnQ==", + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "dependencies": { + "detect-libc": "^2.0.3", + "is-glob": "^4.0.3", + "node-addon-api": "^7.0.0", + "picomatch": "^4.0.3" + }, + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "@parcel/watcher-android-arm64": "2.5.6", + "@parcel/watcher-darwin-arm64": "2.5.6", + "@parcel/watcher-darwin-x64": "2.5.6", + "@parcel/watcher-freebsd-x64": "2.5.6", + "@parcel/watcher-linux-arm-glibc": "2.5.6", + "@parcel/watcher-linux-arm-musl": "2.5.6", + "@parcel/watcher-linux-arm64-glibc": "2.5.6", + "@parcel/watcher-linux-arm64-musl": "2.5.6", + "@parcel/watcher-linux-x64-glibc": "2.5.6", + "@parcel/watcher-linux-x64-musl": "2.5.6", + "@parcel/watcher-win32-arm64": "2.5.6", + "@parcel/watcher-win32-ia32": "2.5.6", + "@parcel/watcher-win32-x64": "2.5.6" + } + }, + "node_modules/@parcel/watcher-android-arm64": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.5.6.tgz", + "integrity": "sha512-YQxSS34tPF/6ZG7r/Ih9xy+kP/WwediEUsqmtf0cuCV5TPPKw/PQHRhueUo6JdeFJaqV3pyjm0GdYjZotbRt/A==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-darwin-arm64": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.5.6.tgz", + "integrity": "sha512-Z2ZdrnwyXvvvdtRHLmM4knydIdU9adO3D4n/0cVipF3rRiwP+3/sfzpAwA/qKFL6i1ModaabkU7IbpeMBgiVEA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-darwin-x64": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.5.6.tgz", + "integrity": "sha512-HgvOf3W9dhithcwOWX9uDZyn1lW9R+7tPZ4sug+NGrGIo4Rk1hAXLEbcH1TQSqxts0NYXXlOWqVpvS1SFS4fRg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-freebsd-x64": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.5.6.tgz", + "integrity": "sha512-vJVi8yd/qzJxEKHkeemh7w3YAn6RJCtYlE4HPMoVnCpIXEzSrxErBW5SJBgKLbXU3WdIpkjBTeUNtyBVn8TRng==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm-glibc": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.5.6.tgz", + "integrity": "sha512-9JiYfB6h6BgV50CCfasfLf/uvOcJskMSwcdH1PHH9rvS1IrNy8zad6IUVPVUfmXr+u+Km9IxcfMLzgdOudz9EQ==", + "cpu": [ + "arm" + ], + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm-musl": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-musl/-/watcher-linux-arm-musl-2.5.6.tgz", + "integrity": "sha512-Ve3gUCG57nuUUSyjBq/MAM0CzArtuIOxsBdQ+ftz6ho8n7s1i9E1Nmk/xmP323r2YL0SONs1EuwqBp2u1k5fxg==", + "cpu": [ + "arm" + ], + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm64-glibc": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.5.6.tgz", + "integrity": "sha512-f2g/DT3NhGPdBmMWYoxixqYr3v/UXcmLOYy16Bx0TM20Tchduwr4EaCbmxh1321TABqPGDpS8D/ggOTaljijOA==", + "cpu": [ + "arm64" + ], + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm64-musl": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.5.6.tgz", + "integrity": "sha512-qb6naMDGlbCwdhLj6hgoVKJl2odL34z2sqkC7Z6kzir8b5W65WYDpLB6R06KabvZdgoHI/zxke4b3zR0wAbDTA==", + "cpu": [ + "arm64" + ], + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-x64-glibc": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.5.6.tgz", + "integrity": "sha512-kbT5wvNQlx7NaGjzPFu8nVIW1rWqV780O7ZtkjuWaPUgpv2NMFpjYERVi0UYj1msZNyCzGlaCWEtzc+exjMGbQ==", + "cpu": [ + "x64" + ], + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-x64-musl": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.5.6.tgz", + "integrity": "sha512-1JRFeC+h7RdXwldHzTsmdtYR/Ku8SylLgTU/reMuqdVD7CtLwf0VR1FqeprZ0eHQkO0vqsbvFLXUmYm/uNKJBg==", + "cpu": [ + "x64" + ], + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-win32-arm64": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.5.6.tgz", + "integrity": "sha512-3ukyebjc6eGlw9yRt678DxVF7rjXatWiHvTXqphZLvo7aC5NdEgFufVwjFfY51ijYEWpXbqF5jtrK275z52D4Q==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-win32-ia32": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.5.6.tgz", + "integrity": "sha512-k35yLp1ZMwwee3Ez/pxBi5cf4AoBKYXj00CZ80jUz5h8prpiaQsiRPKQMxoLstNuqe2vR4RNPEAEcjEFzhEz/g==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-win32-x64": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.5.6.tgz", + "integrity": "sha512-hbQlYcCq5dlAX9Qx+kFb0FHue6vbjlf0FrNzSKdYK2APUf7tGfGxQCk2ihEREmbR6ZMc0MVAD5RIX/41gpUzTw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@pkgr/core": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.3.6.tgz", + "integrity": "sha512-SEeaJLb3qBNF/OaXnaR1NmmBbFYk1zC0ZH/52fATcRPLFg/p791YrcyFFy44Bo9sLaGuSuLp5Q6axbb/O+v/RA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/pkgr" + } + }, + "node_modules/@rolldown/pluginutils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.1.tgz", + "integrity": "sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.62.2.tgz", + "integrity": "sha512-6o7ZLZK+BeenkZCFNDXqpbjw9bD6nuWonvS/lwQJp7NoVVxm6p3qE7qQ5jGuBjiFsgvqjD8mZAU5oWxTmbOeOg==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.62.2.tgz", + "integrity": "sha512-BaH7BllCACHoH1LguOU56UItGfUWjujlO65kS9LAodViaN4bwIKd7oeW/ZHJ/4ljr/7MIiENnNy3HJ0zXv8Zkw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.62.2.tgz", + "integrity": "sha512-v39RCCvj4He82I9sFmk+M1VZ0PLM9sfsLVikjfx2hYBNALhrrOR2D3JjQA6AhlaSOgcR+RzrKY7e1+bT6SUO/A==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.62.2.tgz", + "integrity": "sha512-yl0y2vq3S3lHeuXhEdss6TWfKW8vkujImO12tn4ZkG/4oghr09LvdYm2RElVjokTQiUvDUGXLGsYeLqUMCKpGA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.62.2.tgz", + "integrity": "sha512-tT4pvt4qXD+vEoezupCWi+a1F0vvDiksiHc+PxRlYTOH1I6/X4id9jPxTP+Fg+545euaFT1jJVs4CEdHZAU1vw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.62.2.tgz", + "integrity": "sha512-6nU5F2wCW+qvCBhTn1pdIU3bzsIoF7EUwsCDRxilWGprQR6yd508YnH9+OKFCwpfS8pjZqDUmnCAr7exax0XCg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.62.2.tgz", + "integrity": "sha512-n1GJHPOvpIfhi3TmrCeh6S6URt9BFCt0KQE3qvexyGCTAKpR4Lg+eWvNZEqu7epxwus/8ElT3hacYEucm49SZg==", + "cpu": [ + "arm" + ], + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.62.2.tgz", + "integrity": "sha512-JqgflS8wEB+UXV/vS1RpRbifGBeN4D5lz8D8oOFbFZw4vedvdOgCFAjfBmIMdW3yL10XpQQ0Ambepw6MXrhOnA==", + "cpu": [ + "arm" + ], + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.62.2.tgz", + "integrity": "sha512-wnFJkogWvN4jm/hQRF2UBaeUmk20j5+DmHvoyWii2b8HJDyvz1MF2OU/6ynXt2KR63rbZLWkFpoytpdc/yBuSA==", + "cpu": [ + "arm64" + ], + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.62.2.tgz", + "integrity": "sha512-HVu2bp0zhvJ8xHEV9+UUs7S90VadmBSY3LcIMvozbPo4AuMGDWlz3ymHLHZPX4hR67TKTt8Qp5PJ5RBg/i+RMQ==", + "cpu": [ + "arm64" + ], + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-gnu": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.62.2.tgz", + "integrity": "sha512-mQqqAV8QaoSgr9I2fKDLY2BAVvmKjWoGiu/cSYQonsLvtqwEn1E4QYfnCOcp5zoEqNhsDYin1s6jx/VJmrxlZg==", + "cpu": [ + "loong64" + ], + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-musl": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.62.2.tgz", + "integrity": "sha512-IxKLoxCQ2IWi6bT2akyDUBGsOImDKB+sPp4EsTmwFQ/fMwpCKm8uLSSgP/Kx/QYUgKis6SEZ5/Nlhup0DIA0PQ==", + "cpu": [ + "loong64" + ], + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.62.2.tgz", + "integrity": "sha512-Mk5ha2RQSgyFfmYYLkBpPnUk8D8FriBxesO1u9O75X0mHgXL1UQcH5Itl2lurWL2tj0RxV9b9tJgipac0hRY9A==", + "cpu": [ + "ppc64" + ], + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-musl": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.62.2.tgz", + "integrity": "sha512-CjvEnqJL/0/TQ3TXX3OPIJ/kmBellrWd4heXUmHeJlTnmwjKpSJzoehLaL6Xk0ZnMHBu9dZuFADNOrtjF4v+2w==", + "cpu": [ + "ppc64" + ], + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.62.2.tgz", + "integrity": "sha512-1SiZbzwdkaDURsew/tSOrooKiYy7EQGT6m8ufavAi9NEyQb/6VuIxFXAL1fqa4iZe3g4NbNk4P7J32z2tw5Mgg==", + "cpu": [ + "riscv64" + ], + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.62.2.tgz", + "integrity": "sha512-nQts12zJ3NQRoE6uYljOH89v7szzLDvG2JD/vsX+vGXU8w/At1GowTZ5/7qeFQ8m7L55rpR8Okugnuo5bgjy2Q==", + "cpu": [ + "riscv64" + ], + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.62.2.tgz", + "integrity": "sha512-E9/ll019jhPIJgpzfZoIkBGhcz+kKNgVWYRY0zr9srBdPPFVpvOKW8VaJKUbeK+eZXyQF9ltME+Kk6affeaPgg==", + "cpu": [ + "s390x" + ], + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.62.2.tgz", + "integrity": "sha512-5BqxR/pshjey51iliyzTD5Xi3EN0aLmQ2lZ3lvefVV9c82BvrLo2/6OT55iifpWBufs6kdwWbuOKS841DrmK9A==", + "cpu": [ + "x64" + ], + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.62.2.tgz", + "integrity": "sha512-uNN83XxQrRAh/w0/pmAfibcwyb6YWt4gP+dpnQKPVJshAloQ785ii8CT8ZCIxkGg9opVsvAlGhFitSm6D1Jjpg==", + "cpu": [ + "x64" + ], + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-openbsd-x64": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.62.2.tgz", + "integrity": "sha512-srjEIxSH3LRnJN6THczDHWQplqEMFiAJrTab0msUryh9kwNpkICf3Ea6q6MN/2cZwRFUNx5w+h6Hpi4QuHS6Zg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ] + }, + "node_modules/@rollup/rollup-openharmony-arm64": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.62.2.tgz", + "integrity": "sha512-8hOJnxgbyObnCm5AlRA3A931xX19xq80RjVTKgJOvEKWqJruP/Uf12IbAOaDjjEXYRewwHLfmF0YRIdK3OwKWA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.62.2.tgz", + "integrity": "sha512-mmF4AY1i0hG/bLWUctUq59gtmgaSIRa3cu/A3JFRp/sCNEme2bgDEiDS22P9FbnJB8NJNF4jPJiSP5RHQpUTDg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.62.2.tgz", + "integrity": "sha512-DZgkknc6jhHrk46V25vbAM0zZkyP0nSDkJB8/dRkLTxv470dOmWDqGoEJl/9A0dFfS7yE3REOwNDxpHwSLSt0Q==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-gnu": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.62.2.tgz", + "integrity": "sha512-T6xr6ucWSFto+VGajA8YH26LdpHRuP4YLHEKAtCWvJDOlnmWcDZVCI2Jmjr+IFHDlt2zRaTAKE4tfjTaWLgJBg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.62.2.tgz", + "integrity": "sha512-BfzEnDJOt9T8M989/lA37EcJgat01wLRnoi5dQf3QzOH7jzpqTAzdDbVfRljVr5r+jzKqpbHeyOfAaXxAd0PAA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@tabler/icons": { + "version": "3.44.0", + "resolved": "https://registry.npmjs.org/@tabler/icons/-/icons-3.44.0.tgz", + "integrity": "sha512-Wn0AOZG9sg0L+bjfMqq4eNhC6pQjIrk94LvvWYNYkY8KH8wC3YILRzQlrnVJc4FUeMxH/AK97QsYCX35H3LndA==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/codecalm" + } + }, + "node_modules/@tabler/icons-vue": { + "version": "3.44.0", + "resolved": "https://registry.npmjs.org/@tabler/icons-vue/-/icons-vue-3.44.0.tgz", + "integrity": "sha512-mABxdhq3SWo2ZI77w/t0reiOGNim/SEDSlfMT5PeiWA3cZwnZoQUYRiq/X6SgeTaA7LzCTX0IuvQWVf4RWOvsg==", + "license": "MIT", + "dependencies": { + "@tabler/icons": "3.44.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/codecalm" + }, + "peerDependencies": { + "vue": ">=3.0.1" + } + }, + "node_modules/@types/chai": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.2.3.tgz", + "integrity": "sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/deep-eql": "*", + "assertion-error": "^2.0.1" + } + }, + "node_modules/@types/deep-eql": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/deep-eql/-/deep-eql-4.0.2.tgz", + "integrity": "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/dompurify": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@types/dompurify/-/dompurify-3.0.5.tgz", + "integrity": "sha512-1Wg0g3BtQF7sSb27fJQAKck1HECM6zV1EB66j8JH9i3LCjYabJa0FSdiSgsD5K/RbrsR0SiraKacLB+T8ZVYAg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/trusted-types": "*" + } + }, + "node_modules/@types/estree": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.9.tgz", + "integrity": "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/@types/js-yaml": { + "version": "4.0.9", + "resolved": "https://registry.npmjs.org/@types/js-yaml/-/js-yaml-4.0.9.tgz", + "integrity": "sha512-k4MGaQl5TGo/iipqb2UDG2UwjXziSWkh0uysQelTlJpX1qGlpUZYm8PnO4DxG1qBomtJUdYJ6qR6xdIah10JLg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/lodash": { + "version": "4.17.24", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.24.tgz", + "integrity": "sha512-gIW7lQLZbue7lRSWEFql49QJJWThrTFFeIMJdp3eH4tKoxm1OvEPg02rm4wCCSHS0cL3/Fizimb35b7k8atwsQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/luxon": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/@types/luxon/-/luxon-3.7.2.tgz", + "integrity": "sha512-gW+Oib+vUtGJBtNC8V9Reww0oIpusw+4m81uncg9REGZAJfqOQHfo/nkabnc7w0QReXyPqjrbWMJk6NuAkiX3Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/md5": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/@types/md5/-/md5-2.3.6.tgz", + "integrity": "sha512-WD69gNXtRBnpknfZcb4TRQ0XJQbUPZcai/Qdhmka3sxUR3Et8NrXoeAoknG/LghYHTf4ve795rInVYHBTQdNVA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/pegjs": { + "version": "0.10.6", + "resolved": "https://registry.npmjs.org/@types/pegjs/-/pegjs-0.10.6.tgz", + "integrity": "sha512-eLYXDbZWXh2uxf+w8sXS8d6KSoXTswfps6fvCUuVAGN8eRpfe7h9eSRydxiSJvo9Bf+GzifsDOr9TMQlmJdmkw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/qs": { + "version": "6.15.1", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.15.1.tgz", + "integrity": "sha512-GZHUBZR9hckSUhrxmp1nG6NwdpM9fCunJwyThLW1X3AyHgd9IlHb6VANpQQqDr2o/qQp6McZ3y/IA2rVzKzSbw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/trusted-types": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz", + "integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/@types/validator": { + "version": "13.15.10", + "resolved": "https://registry.npmjs.org/@types/validator/-/validator-13.15.10.tgz", + "integrity": "sha512-T8L6i7wCuyoK8A/ZeLYt1+q0ty3Zb9+qbSSvrIVitzT3YjZqkTZ40IbRsPanlB4h1QB3JVL1SYCdR6ngtFYcuA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/web-bluetooth": { + "version": "0.0.21", + "resolved": "https://registry.npmjs.org/@types/web-bluetooth/-/web-bluetooth-0.0.21.tgz", + "integrity": "sha512-oIQLCGWtcFZy2JW77j9k8nHzAOpqMHLQejDA48XXMWH6tjCQHz5RCFz1bzsmROyL6PUm+LLnUiI4BCn221inxA==", + "license": "MIT" + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "8.61.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.61.1.tgz", + "integrity": "sha512-ZPlVl3PB3et/59Ne0fv/sci6ZXz4T4Hp4nTJ56i/Y0gR89ARb+KphojTq6j+56E5PIezmOIOOWyY+aWQFd+IkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/regexpp": "^4.12.2", + "@typescript-eslint/scope-manager": "8.61.1", + "@typescript-eslint/type-utils": "8.61.1", + "@typescript-eslint/utils": "8.61.1", + "@typescript-eslint/visitor-keys": "8.61.1", + "ignore": "^7.0.5", + "natural-compare": "^1.4.0", + "ts-api-utils": "^2.5.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^8.61.1", + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "8.61.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.61.1.tgz", + "integrity": "sha512-PJ5vePq5/ognBbrIcoC5+SHO5dfpeLPzP9FpLkzWrguoYQEeeSjlJpVwOpo1JRSTEi7dRcwNy4h4dzV70PqHcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/scope-manager": "8.61.1", + "@typescript-eslint/types": "8.61.1", + "@typescript-eslint/typescript-estree": "8.61.1", + "@typescript-eslint/visitor-keys": "8.61.1", + "debug": "^4.4.3" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/project-service": { + "version": "8.61.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.61.1.tgz", + "integrity": "sha512-PrC4JYGmR241lYnfhmKGTXkFqv8+ymbTFgSAY0fVXpY82/QkMw5TZPl+vGzuDDU2QYJk9fIDOBTntF+yDv9LEA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/tsconfig-utils": "^8.61.1", + "@typescript-eslint/types": "^8.61.1", + "debug": "^4.4.3" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "8.61.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.61.1.tgz", + "integrity": "sha512-L2bdIeoQS8FlKAvONAr20w6OcLXeB+qiDKbAooS9A0Ben+iSIkBef0FxqwKWYqt5sa0i4KJtxVyVmhMylKzF5w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.61.1", + "@typescript-eslint/visitor-keys": "8.61.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/tsconfig-utils": { + "version": "8.61.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.61.1.tgz", + "integrity": "sha512-UN/H4di+OO7EWx2ovME+8t31YO+KVnK0RRKEHR3kOt21/Ay8BOq3M1OMvWs5vNiqcFCYGYoxK3MXPZzmMUE+yg==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "8.61.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.61.1.tgz", + "integrity": "sha512-GYRicKmVK0C4fsKgaACaknOUAq9Oa2kwsjnpFhFcS/5p4Ht5IP9OVLbgIgcK4SRk92nVHFluurg1lumD9dBcLw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.61.1", + "@typescript-eslint/typescript-estree": "8.61.1", + "@typescript-eslint/utils": "8.61.1", + "debug": "^4.4.3", + "ts-api-utils": "^2.5.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/types": { + "version": "8.61.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.61.1.tgz", + "integrity": "sha512-G+CRlPqLv7Bz1IZVs03x5K59F1veqL0EJUROAdGhKsEq8qOiRiZbI+HUojPq5l0fEGOKModD9br6lObhB8zkoA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "8.61.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.61.1.tgz", + "integrity": "sha512-u+oQD3BqYWPc8YV9Zab4vaJElJuwOLPRc10Jm1o/qS+6Qwen14HCWwx0Seo4LnSn2wxea2Ik8DxPt2/FHmuhrg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/project-service": "8.61.1", + "@typescript-eslint/tsconfig-utils": "8.61.1", + "@typescript-eslint/types": "8.61.1", + "@typescript-eslint/visitor-keys": "8.61.1", + "debug": "^4.4.3", + "minimatch": "^10.2.2", + "semver": "^7.7.3", + "tinyglobby": "^0.2.15", + "ts-api-utils": "^2.5.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "8.61.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.61.1.tgz", + "integrity": "sha512-1+P/3Dj6jvtybE1q0HQ6yBt/gq+oKJyLdEv4HdnqasaEXRSYCAsD59mXEVQnM/ULNdQxbX77tdG4jPRjIS6knA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.9.1", + "@typescript-eslint/scope-manager": "8.61.1", + "@typescript-eslint/types": "8.61.1", + "@typescript-eslint/typescript-estree": "8.61.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "8.61.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.61.1.tgz", + "integrity": "sha512-6fJ9MHWtK14C1DSkiMlHUSOmrVebL7150xZJBlJiL62jjhIA4JmOq6flwBgDxIdBKKdoiZRel+dfPD5MLfny3w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.61.1", + "eslint-visitor-keys": "^5.0.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz", + "integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@ungap/structured-clone": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.1.tgz", + "integrity": "sha512-mUFwbeTqrVgDQxFveS+df2yfap6iuP20NAKAsBt5jDEoOTDew+zwLAOilHCeQJOVSvmgCX4ogqIrA0mnyr08yQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/@vexip-ui/hooks": { + "version": "2.9.4", + "resolved": "https://registry.npmjs.org/@vexip-ui/hooks/-/hooks-2.9.4.tgz", + "integrity": "sha512-dGUiBAeHIsnSVigGSPHcuHBVqrSGW8LV+zGohvOpBfXs8Ynn5ZcSmybIWJ3G826NsicPu9rqwcJG8uvSgG4k4Q==", + "license": "MIT", + "dependencies": { + "@floating-ui/dom": "^1.7.0", + "@juggle/resize-observer": "^3.4.0", + "@vexip-ui/utils": "2.16.4" + }, + "peerDependencies": { + "vue": "^3.2.25" + } + }, + "node_modules/@vexip-ui/utils": { + "version": "2.16.4", + "resolved": "https://registry.npmjs.org/@vexip-ui/utils/-/utils-2.16.4.tgz", + "integrity": "sha512-KX+Q4EsuwDp6ZlRJ7OAkiYxu52D5CVM8zpqQz/FXYV+JUtzl9T3dvxgtA8gQ0wm5Sh/xT6jp8Wo4X7tLAzRh/A==", + "license": "MIT" + }, + "node_modules/@vitejs/plugin-vue": { + "version": "6.0.7", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-6.0.7.tgz", + "integrity": "sha512-km+p+XdSz9Sxm5rqUbqcSfZYaAniKxWBj1KURl+Jr7UaPvvX7BmaWMdP69I5rrFDeQGyxAG7NXdc57vz+snhWg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@rolldown/pluginutils": "^1.0.1" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "peerDependencies": { + "vite": "^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0", + "vue": "^3.2.25" + } + }, + "node_modules/@vitest/expect": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-3.2.6.tgz", + "integrity": "sha512-1+7q9BtaKzEmO+fmNT3kYvoNn5Y71XWAx2Q5HRim4tTVRQVRv4uJFAQ5FbK0OPUeNP/WmVCpxYxoJdvuHVjzBQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/chai": "^5.2.2", + "@vitest/spy": "3.2.6", + "@vitest/utils": "3.2.6", + "chai": "^5.2.0", + "tinyrainbow": "^2.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/mocker": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-3.2.6.tgz", + "integrity": "sha512-EZOrpDbkKotFAP7wPAQV1UIyoGOk4oX7ynWhBhLB7v+meMHbQhU16oPpIYGTTe4oFlhpryGpgpcZP/sin3hYuw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/spy": "3.2.6", + "estree-walker": "^3.0.3", + "magic-string": "^0.30.17" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "msw": "^2.4.9", + "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0" + }, + "peerDependenciesMeta": { + "msw": { + "optional": true + }, + "vite": { + "optional": true + } + } + }, + "node_modules/@vitest/pretty-format": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-3.2.6.tgz", + "integrity": "sha512-lb7XXXzmm2h2ASzFnRvQpDo6onT1NmMJA3tkGTWiBFtRJ9lxGY3d3mm/Apt36gej2bkkOVLL/yTOtufDaFa/jA==", + "dev": true, + "license": "MIT", + "dependencies": { + "tinyrainbow": "^2.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/runner": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-3.2.6.tgz", + "integrity": "sha512-HYcoSj1w5tcgUnzoF0HcyaAQjpA1gj9ftUJ7iSJSuipc02jW9gKkigwZbjFldAfYHA1fa8UZVRftdMY5msWM9Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/utils": "3.2.6", + "pathe": "^2.0.3", + "strip-literal": "^3.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/snapshot": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-3.2.6.tgz", + "integrity": "sha512-H+ZjNTWGpObenh0YnlBctAPnJSI20P81PL8BPzWpx54YXLLTm8hEsWawtcYLMrwvpK48hGxLLbCS+1KRXhsKhw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "3.2.6", + "magic-string": "^0.30.17", + "pathe": "^2.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/spy": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-3.2.6.tgz", + "integrity": "sha512-oq6BbH68WzcWmwtBrU9nqLeaXTR4XwJF7FSLkKEZo4i6eoXcrxjcwSuTvWBIRUTC6VC72nXYunzqgZA+IKdtxg==", + "dev": true, + "license": "MIT", + "dependencies": { + "tinyspy": "^4.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/utils": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-3.2.6.tgz", + "integrity": "sha512-lI23nIs4bnT3T8NIoh+vFaz5s2/DdP0Jgt2jxwgWljvwn82cLJtyi/If+fjFyoLMGIOz0U/fKvWE0d4jsNQEfg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "3.2.6", + "loupe": "^3.1.4", + "tinyrainbow": "^2.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@volar/language-core": { + "version": "2.4.28", + "resolved": "https://registry.npmjs.org/@volar/language-core/-/language-core-2.4.28.tgz", + "integrity": "sha512-w4qhIJ8ZSitgLAkVay6AbcnC7gP3glYM3fYwKV3srj8m494E3xtrCv6E+bWviiK/8hs6e6t1ij1s2Endql7vzQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@volar/source-map": "2.4.28" + } + }, + "node_modules/@volar/source-map": { + "version": "2.4.28", + "resolved": "https://registry.npmjs.org/@volar/source-map/-/source-map-2.4.28.tgz", + "integrity": "sha512-yX2BDBqJkRXfKw8my8VarTyjv48QwxdJtvRgUpNE5erCsgEUdI2DsLbpa+rOQVAJYshY99szEcRDmyHbF10ggQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@volar/typescript": { + "version": "2.4.28", + "resolved": "https://registry.npmjs.org/@volar/typescript/-/typescript-2.4.28.tgz", + "integrity": "sha512-Ja6yvWrbis2QtN4ClAKreeUZPVYMARDYZl9LMEv1iQ1QdepB6wn0jTRxA9MftYmYa4DQ4k/DaSZpFPUfxl8giw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@volar/language-core": "2.4.28", + "path-browserify": "^1.0.1", + "vscode-uri": "^3.0.8" + } + }, + "node_modules/@vue/compiler-core": { + "version": "3.5.38", + "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.38.tgz", + "integrity": "sha512-s99aGxWYig9ErHbct27KXEGhrBYlRI6c4MwAgXErOAbX9xiW37/uMa+XUDO69zLz83dng8UUZ70CTOJrLrYrEQ==", + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.29.7", + "@vue/shared": "3.5.38", + "entities": "^7.0.1", + "estree-walker": "^2.0.2", + "source-map-js": "^1.2.1" + } + }, + "node_modules/@vue/compiler-core/node_modules/entities": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-7.0.1.tgz", + "integrity": "sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/@vue/compiler-core/node_modules/estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", + "license": "MIT" + }, + "node_modules/@vue/compiler-dom": { + "version": "3.5.38", + "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.38.tgz", + "integrity": "sha512-JTqp25l8aFfJYF7/KmsXZjAxJz7T+SjmTJLoXVjHtc2BrSgSiW2n9Aem/cWq1OPe68A8JL06B3eVdhlP0H4TVw==", + "license": "MIT", + "dependencies": { + "@vue/compiler-core": "3.5.38", + "@vue/shared": "3.5.38" + } + }, + "node_modules/@vue/compiler-sfc": { + "version": "3.5.38", + "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.38.tgz", + "integrity": "sha512-DuA2GiZawSEW442iw/9+Fkol8hTgb4Ke5KkhmSry65QA7YuyMbIdy8p0XZRMvNwJdgRz307W8g1CSzdvS4nuNg==", + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.29.7", + "@vue/compiler-core": "3.5.38", + "@vue/compiler-dom": "3.5.38", + "@vue/compiler-ssr": "3.5.38", + "@vue/shared": "3.5.38", + "estree-walker": "^2.0.2", + "magic-string": "^0.30.21", + "postcss": "^8.5.15", + "source-map-js": "^1.2.1" + } + }, + "node_modules/@vue/compiler-sfc/node_modules/estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", + "license": "MIT" + }, + "node_modules/@vue/compiler-ssr": { + "version": "3.5.38", + "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.38.tgz", + "integrity": "sha512-7s+W5Gc42FGxZMcuwl8H5B29T8BJPMdBT7KHFE+BbAuZ/iTEdTtv7z2XiMjiaUUw4w3ZcCEdHs36RuYJ2VA7bA==", + "license": "MIT", + "dependencies": { + "@vue/compiler-dom": "3.5.38", + "@vue/shared": "3.5.38" + } + }, + "node_modules/@vue/devtools-api": { + "version": "6.6.4", + "resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-6.6.4.tgz", + "integrity": "sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g==", + "license": "MIT" + }, + "node_modules/@vue/language-core": { + "version": "3.3.5", + "resolved": "https://registry.npmjs.org/@vue/language-core/-/language-core-3.3.5.tgz", + "integrity": "sha512-UkKu5nhX89fg4VhlG/FOeI10G3cj/7radKT/cy9BT4Q9qJmJlSTAc/dP63Xqs29aypN4f39xUV6PsLNk/dcD6g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@volar/language-core": "2.4.28", + "@vue/compiler-dom": "^3.5.0", + "@vue/shared": "^3.5.0", + "alien-signals": "^3.2.0", + "muggle-string": "^0.4.1", + "path-browserify": "^1.0.1", + "picomatch": "^4.0.4" + } + }, + "node_modules/@vue/reactivity": { + "version": "3.5.38", + "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.38.tgz", + "integrity": "sha512-pG6LV/NDNRbKizcUjFFLAfjaL8mcv4DmR9avNcUw2gDHBzZneuS2TWCmp633ynzxz9YYKNeEPK2I8Wraqy2HUQ==", + "license": "MIT", + "dependencies": { + "@vue/shared": "3.5.38" + } + }, + "node_modules/@vue/runtime-core": { + "version": "3.5.38", + "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.5.38.tgz", + "integrity": "sha512-iyW8WVfF1CpCXxncZY5Ei6rSd6oZr5DgEom//fUjRBRl56AXPD+s9ATvukRt77ZFTuYlnVA1bxY+dJB94tWVYw==", + "license": "MIT", + "dependencies": { + "@vue/reactivity": "3.5.38", + "@vue/shared": "3.5.38" + } + }, + "node_modules/@vue/runtime-dom": { + "version": "3.5.38", + "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.5.38.tgz", + "integrity": "sha512-apX2wt9sdfDshS+a2xueFZLVpt0GkRJZSoPmrW/SA4yzXTznhfcMVW59gr7h4YQeY0vJhdJkk2rsIDwgfFgC5A==", + "license": "MIT", + "dependencies": { + "@vue/reactivity": "3.5.38", + "@vue/runtime-core": "3.5.38", + "@vue/shared": "3.5.38", + "csstype": "^3.2.3" + } + }, + "node_modules/@vue/server-renderer": { + "version": "3.5.38", + "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.5.38.tgz", + "integrity": "sha512-vue8vbf2QlV4quHqzwmJy6dWfmRhP1J8l4wtZg60CL6VoKqcPY2oe7may3+1d9qfpedjK5PRLFqd5k3Isj9mUw==", + "license": "MIT", + "dependencies": { + "@vue/compiler-ssr": "3.5.38", + "@vue/shared": "3.5.38" + }, + "peerDependencies": { + "vue": "3.5.38" + } + }, + "node_modules/@vue/shared": { + "version": "3.5.38", + "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.38.tgz", + "integrity": "sha512-FTW0AFZNaK5/mOqvGBwVfUlNLU38TiQn4+DQgIFUnrBBJQ1crMJ82yeGQLV5jyKFsO8yRukpbuP7x+nRbH6aug==", + "license": "MIT" + }, + "node_modules/@vuetify/loader-shared": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@vuetify/loader-shared/-/loader-shared-2.1.2.tgz", + "integrity": "sha512-X+1jBLmXHkpQEnC0vyOb4rtX2QSkBiFhaFXz8yhQqN2A4vQ6k2nChxN4Ol7VAY5KoqMdFoRMnmNdp/1qYXDQig==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "upath": "^2.0.1" + }, + "peerDependencies": { + "vue": "^3.0.0", + "vuetify": ">=3" + } + }, + "node_modules/@vueuse/core": { + "version": "13.9.0", + "resolved": "https://registry.npmjs.org/@vueuse/core/-/core-13.9.0.tgz", + "integrity": "sha512-ts3regBQyURfCE2BcytLqzm8+MmLlo5Ln/KLoxDVcsZ2gzIwVNnQpQOL/UKV8alUqjSZOlpFZcRNsLRqj+OzyA==", + "license": "MIT", + "dependencies": { + "@types/web-bluetooth": "^0.0.21", + "@vueuse/metadata": "13.9.0", + "@vueuse/shared": "13.9.0" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "vue": "^3.5.0" + } + }, + "node_modules/@vueuse/metadata": { + "version": "13.9.0", + "resolved": "https://registry.npmjs.org/@vueuse/metadata/-/metadata-13.9.0.tgz", + "integrity": "sha512-1AFRvuiGphfF7yWixZa0KwjYH8ulyjDCC0aFgrGRz8+P4kvDFSdXLVfTk5xAN9wEuD1J6z4/myMoYbnHoX07zg==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/@vueuse/router": { + "version": "13.9.0", + "resolved": "https://registry.npmjs.org/@vueuse/router/-/router-13.9.0.tgz", + "integrity": "sha512-7AYay8Pv/0fC4D0eygbIyZuLyVs+9D7dsnO5D8aqat9qcOz91v/XFWR667WE1+p+OkU0ib+FjQUdnTVBNoIw8g==", + "license": "MIT", + "dependencies": { + "@vueuse/shared": "13.9.0" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "vue": "^3.5.0", + "vue-router": "^4.0.0" + } + }, + "node_modules/@vueuse/shared": { + "version": "13.9.0", + "resolved": "https://registry.npmjs.org/@vueuse/shared/-/shared-13.9.0.tgz", + "integrity": "sha512-e89uuTLMh0U5cZ9iDpEI2senqPGfbPRTHM/0AaQkcxnpqjkZqDYP8rpfm7edOz8s+pOCOROEy1PIveSW8+fL5g==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "vue": "^3.5.0" + } + }, + "node_modules/acorn": { + "version": "8.17.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.17.0.tgz", + "integrity": "sha512-xRQbDb9BnwDafYNn6Vwl839DYVjqXYb1XVGtWAZ1kcDc6iwAL4hg3B1dZlRiuENFeO2H53gFG3in621AdERVAg==", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "license": "MIT", + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/ajv": { + "version": "6.15.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.15.0.tgz", + "integrity": "sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/alien-signals": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/alien-signals/-/alien-signals-3.2.1.tgz", + "integrity": "sha512-I8FjmltrfnDFoZedi5CG8DghVYNhzb/Ijluz7tCSJH0xpd0484Kowhbb1XDYOxfJpU1p5wnM2X54dA+IfGyD1g==", + "dev": true, + "license": "MIT" + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "license": "Python-2.0" + }, + "node_modules/assertion-error": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", + "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + } + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "license": "MIT" + }, + "node_modules/axios": { + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.18.0.tgz", + "integrity": "sha512-E32NzpYKp++W7XRe52rHiXV2ehxmh3wbdgO7MHeFM+vqxLBYHzt0ElkiImtOBxtOmyp0yoC8C6uESVV84Y2/hw==", + "license": "MIT", + "dependencies": { + "follow-redirects": "^1.16.0", + "form-data": "^4.0.5", + "https-proxy-agent": "^5.0.1", + "proxy-from-env": "^2.1.0" + } + }, + "node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/bezier-easing": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/bezier-easing/-/bezier-easing-2.1.0.tgz", + "integrity": "sha512-gbIqZ/eslnUFC1tjEvtz0sgx+xTK20wDnYMIA27VA04R7w6xxXQPZDbibjA9DTWZRA2CXtwHykkVzlCaAJAZig==", + "license": "MIT" + }, + "node_modules/big-integer": { + "version": "1.6.52", + "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.52.tgz", + "integrity": "sha512-QxD8cf2eVqJOOz63z6JIN9BzvVs/dlySa5HGSBH5xtR8dPteIRQnBxxKqkNTiT6jbDTF6jAfrd4oMcND9RGbQg==", + "dev": true, + "license": "Unlicense", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", + "dev": true, + "license": "ISC" + }, + "node_modules/brace-expansion": { + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.6.tgz", + "integrity": "sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/browser-tabs-lock": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/browser-tabs-lock/-/browser-tabs-lock-1.3.0.tgz", + "integrity": "sha512-g6nHaobTiT0eMZ7jh16YpD2kcjAp+PInbiVq3M1x6KKaEIVhT4v9oURNIpZLOZ3LQbQ3XYfNhMAb/9hzNLIWrw==", + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "lodash": ">=4.17.21" + } + }, + "node_modules/cac": { + "version": "6.7.14", + "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz", + "integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/chai": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/chai/-/chai-5.3.3.tgz", + "integrity": "sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw==", + "dev": true, + "license": "MIT", + "dependencies": { + "assertion-error": "^2.0.1", + "check-error": "^2.1.1", + "deep-eql": "^5.0.1", + "loupe": "^3.1.0", + "pathval": "^2.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/charenc": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/charenc/-/charenc-0.0.2.tgz", + "integrity": "sha512-yrLQ/yVUFXkzg7EDQsPieE/53+0RlaWTs+wBrvW36cyilJ2SaDWfl4Yj7MtLTXleV9uEKefbAGUPv2/iWSooRA==", + "license": "BSD-3-Clause", + "engines": { + "node": "*" + } + }, + "node_modules/check-error": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-2.1.3.tgz", + "integrity": "sha512-PAJdDJusoxnwm1VwW07VWwUN1sl7smmC3OKggvndJFadxxDRyFJBX/ggnu/KE4kQAB7a3Dp8f/YXC1FlUprWmA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 16" + } + }, + "node_modules/chokidar": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-5.0.0.tgz", + "integrity": "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "readdirp": "^5.0.0" + }, + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "license": "MIT", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true, + "license": "MIT" + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/crypt": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/crypt/-/crypt-0.0.2.tgz", + "integrity": "sha512-mCxBlsHFYh9C+HVpiEacem8FEBnMXgU9gy4zmNC+SXAZNB/1idgp/aulFJ4FgCi7GPEVbfyng092GqL2k2rmow==", + "license": "BSD-3-Clause", + "engines": { + "node": "*" + } + }, + "node_modules/cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "dev": true, + "license": "MIT", + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/cssstyle": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-4.6.0.tgz", + "integrity": "sha512-2z+rWdzbbSZv6/rhtvzvqeZQHrBaqgogqt85sqFNbabZOuFbCVFb8kPeEtZjiKkbrm395irpNKiYeFeLiQnFPg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@asamuzakjp/css-color": "^3.2.0", + "rrweb-cssom": "^0.8.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/csstype": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", + "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", + "license": "MIT" + }, + "node_modules/data-urls": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-5.0.0.tgz", + "integrity": "sha512-ZYP5VBHshaDAiVZxjbRVcFJpc+4xGgT0bK3vzy1HLN8jTO975HEbuYzZJcHoQEY5K1a0z8YayJkyVETa08eNTg==", + "dev": true, + "license": "MIT", + "dependencies": { + "whatwg-mimetype": "^4.0.0", + "whatwg-url": "^14.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decimal.js": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.6.0.tgz", + "integrity": "sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==", + "dev": true, + "license": "MIT" + }, + "node_modules/dedent": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.7.2.tgz", + "integrity": "sha512-WzMx3mW98SN+zn3hgemf4OzdmyNhhhKz5Ay0pUfQiMQ3e1g+xmTJWp/pKdwKVXhdSkAEGIIzqeuWrL3mV/AXbA==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "babel-plugin-macros": "^3.1.0" + }, + "peerDependenciesMeta": { + "babel-plugin-macros": { + "optional": true + } + } + }, + "node_modules/deep-eql": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-5.0.2.tgz", + "integrity": "sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/detect-libc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "license": "Apache-2.0", + "optional": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/discontinuous-range": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/discontinuous-range/-/discontinuous-range-1.0.0.tgz", + "integrity": "sha512-c68LpLbO+7kP/b1Hr1qs8/BJ09F5khZGTxqxZuhzxpmwJKOgRFHJWIb9/KmqnqHhLdO55aOxFH/EGBvUQbL/RQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/dompurify": { + "version": "3.4.11", + "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.4.11.tgz", + "integrity": "sha512-zhlUV12GsaRzMsf9q5M254YhA4+VuF0fG+QFqu6aYpoGlKtz+w8//jBcGVYBgQkR5GHjUomejY84AV+/uPbWdw==", + "license": "(MPL-2.0 OR Apache-2.0)", + "optionalDependencies": { + "@types/trusted-types": "^2.0.7" + } + }, + "node_modules/dpop": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/dpop/-/dpop-2.1.1.tgz", + "integrity": "sha512-J0Of2JTiM4h5si0tlbPQ/lkqfZ5wAEVkKYBhkwyyANnPJfWH4VsR5uIkZ+T+OSPIwDYUg1fbd5Mmodd25HjY1w==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/panva" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/entities": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz", + "integrity": "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/es-cookie": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/es-cookie/-/es-cookie-1.3.2.tgz", + "integrity": "sha512-UTlYYhXGLOy05P/vKVT2Ui7WtC7NiRzGtJyAKKn32g5Gvcjn7KAClLPWlipCtxIus934dFg9o9jXiBL0nP+t9Q==", + "license": "MIT" + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-module-lexer": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.7.0.tgz", + "integrity": "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==", + "dev": true, + "license": "MIT" + }, + "node_modules/es-object-atoms": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.2.tgz", + "integrity": "sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/esbuild": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.7.tgz", + "integrity": "sha512-IxpibTjyVnmrIQo5aqNpCgoACA/dTKLTlhMHihVHhdkxKyPO1uBBthumT0rdHmcsk9uMonIWS0m4FljWzILh3w==", + "devOptional": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.27.7", + "@esbuild/android-arm": "0.27.7", + "@esbuild/android-arm64": "0.27.7", + "@esbuild/android-x64": "0.27.7", + "@esbuild/darwin-arm64": "0.27.7", + "@esbuild/darwin-x64": "0.27.7", + "@esbuild/freebsd-arm64": "0.27.7", + "@esbuild/freebsd-x64": "0.27.7", + "@esbuild/linux-arm": "0.27.7", + "@esbuild/linux-arm64": "0.27.7", + "@esbuild/linux-ia32": "0.27.7", + "@esbuild/linux-loong64": "0.27.7", + "@esbuild/linux-mips64el": "0.27.7", + "@esbuild/linux-ppc64": "0.27.7", + "@esbuild/linux-riscv64": "0.27.7", + "@esbuild/linux-s390x": "0.27.7", + "@esbuild/linux-x64": "0.27.7", + "@esbuild/netbsd-arm64": "0.27.7", + "@esbuild/netbsd-x64": "0.27.7", + "@esbuild/openbsd-arm64": "0.27.7", + "@esbuild/openbsd-x64": "0.27.7", + "@esbuild/openharmony-arm64": "0.27.7", + "@esbuild/sunos-x64": "0.27.7", + "@esbuild/win32-arm64": "0.27.7", + "@esbuild/win32-ia32": "0.27.7", + "@esbuild/win32-x64": "0.27.7" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "8.57.1", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.1.tgz", + "integrity": "sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==", + "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.6.1", + "@eslint/eslintrc": "^2.1.4", + "@eslint/js": "8.57.1", + "@humanwhocodes/config-array": "^0.13.0", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "@ungap/structured-clone": "^1.2.0", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.2.2", + "eslint-visitor-keys": "^3.4.3", + "espree": "^9.6.1", + "esquery": "^1.4.2", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "globals": "^13.19.0", + "graphemer": "^1.4.0", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3", + "strip-ansi": "^6.0.1", + "text-table": "^0.2.0" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-config-prettier": { + "version": "10.1.8", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-10.1.8.tgz", + "integrity": "sha512-82GZUjRS0p/jganf6q1rEO25VSoHH0hKPCTrgillPjdI/3bgBhAE1QzHrHTizjpRvy6pGAvKjDJtk2pF9NDq8w==", + "dev": true, + "license": "MIT", + "bin": { + "eslint-config-prettier": "bin/cli.js" + }, + "funding": { + "url": "https://opencollective.com/eslint-config-prettier" + }, + "peerDependencies": { + "eslint": ">=7.0.0" + } + }, + "node_modules/eslint-plugin-prettier": { + "version": "5.5.6", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.5.6.tgz", + "integrity": "sha512-ifetmTcxWfz+4qRW3pH/ujdTq2jQIj59AxJMIN26K5avYgU8dxycUETQonWiW+wPrYXA0j3Try0l1CnwVQtDqQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "prettier-linter-helpers": "^1.0.1", + "synckit": "^0.11.13" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint-plugin-prettier" + }, + "peerDependencies": { + "@types/eslint": ">=8.0.0", + "eslint": ">=8.0.0", + "eslint-config-prettier": ">= 7.0.0 <10.0.0 || >=10.1.0", + "prettier": ">=3.0.0" + }, + "peerDependenciesMeta": { + "@types/eslint": { + "optional": true + }, + "eslint-config-prettier": { + "optional": true + } + } + }, + "node_modules/eslint-plugin-vue": { + "version": "9.33.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-9.33.0.tgz", + "integrity": "sha512-174lJKuNsuDIlLpjeXc5E2Tss8P44uIimAfGD0b90k0NoirJqpG7stLuU9Vp/9ioTOrQdWVREc4mRd1BD+CvGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.4.0", + "globals": "^13.24.0", + "natural-compare": "^1.4.0", + "nth-check": "^2.1.1", + "postcss-selector-parser": "^6.0.15", + "semver": "^7.6.3", + "vue-eslint-parser": "^9.4.3", + "xml-name-validator": "^4.0.0" + }, + "engines": { + "node": "^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^6.2.0 || ^7.0.0 || ^8.0.0 || ^9.0.0" + } + }, + "node_modules/eslint-scope": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", + "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/eslint/node_modules/brace-expansion": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.15.tgz", + "integrity": "sha512-EwOCDEex4quD37XhqM3omwtMoJjr//isUZz1JopUNWms+4Z2ViyM/k1YIRePpoVNnQhENnxtFjLaxNHrT7xIUg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/eslint/node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/eslint/node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/espree": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.9.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esquery": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.7.0.tgz", + "integrity": "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estree-walker": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/expect-type": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.3.0.tgz", + "integrity": "sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-diff": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz", + "integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/fast-equals": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/fast-equals/-/fast-equals-5.4.0.tgz", + "integrity": "sha512-jt2DW/aNFNwke7AUd+Z+e6pz39KO5rzdbbFCg2sGafS4mk13MI7Z8O5z9cADNn5lhGODIgLwug6TZO2ctf7kcw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-stringify": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fast-stringify/-/fast-stringify-4.0.0.tgz", + "integrity": "sha512-lE2DIivBaLysf6hK5WH/VfMgqRbvBVHcpGVVTmA5Zi8oWIjq9YxIt6lYGdUgP1HNSXxTIat7HEIDnrSvXSeKQw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fastq": { + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz", + "integrity": "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==", + "dev": true, + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "license": "MIT", + "dependencies": { + "flat-cache": "^3.0.4" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/find-up-simple": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/find-up-simple/-/find-up-simple-1.0.1.tgz", + "integrity": "sha512-afd4O7zpqHeRyg4PfDQsXmlDe2PfdHtJt6Akt8jOWaApLOZk5JXs6VMR29lz03pRe9mpykrRCYIYxaJYcfpncQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", + "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", + "dev": true, + "license": "MIT", + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.3", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/flatted": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.2.tgz", + "integrity": "sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==", + "dev": true, + "license": "ISC" + }, + "node_modules/follow-redirects": { + "version": "1.16.0", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.16.0.tgz", + "integrity": "sha512-y5rN/uOsadFT/JfYwhxRS5R7Qce+g3zG97+JrtFZlC9klX/W5hD7iiLzScI4nZqUS7DNUdhPgw4xI8W2LuXlUw==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "license": "MIT", + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/form-data": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.6.tgz", + "integrity": "sha512-vKatAh4SlVfgbv+YtmhiRjhEMJsYpsG1Y2rMQtR+SVSbytsSD1YGzDIcrAJmdFec88u/+VoGmxnl+80gL1tRCQ==", + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "hasown": "^2.0.4", + "mime-types": "^2.1.35" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true, + "license": "ISC" + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/glob/node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/glob/node_modules/brace-expansion": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.15.tgz", + "integrity": "sha512-EwOCDEex4quD37XhqM3omwtMoJjr//isUZz1JopUNWms+4Z2ViyM/k1YIRePpoVNnQhENnxtFjLaxNHrT7xIUg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/glob/node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/globals": { + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "dev": true, + "license": "MIT" + }, + "node_modules/grid-layout-plus": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/grid-layout-plus/-/grid-layout-plus-1.1.1.tgz", + "integrity": "sha512-7CWehJubrVC8Ps5QFUlnDsp0kiREvKfi3Pdjp21EyY8BNzSusqI3Utcxvu1Y9UUKe3YExvbhJzIxHK6rorbRaQ==", + "license": "MIT", + "dependencies": { + "@vexip-ui/hooks": "^2.8.0", + "@vexip-ui/utils": "^2.16.1", + "interactjs": "^1.10.27" + }, + "peerDependencies": { + "vue": "^3.0.0" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.4.tgz", + "integrity": "sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/html-encoding-sniffer": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-4.0.0.tgz", + "integrity": "sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "whatwg-encoding": "^3.1.1" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/http-proxy-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", + "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/http-proxy-agent/node_modules/agent-base": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", + "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, + "node_modules/https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "license": "MIT", + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ignore": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", + "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/immutable": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-5.1.6.tgz", + "integrity": "sha512-q1swsS8K7L8usSHuOqF2TAoCCkonYz0SG38wLAggaa4Wml70zixIvt2ql4coQ2C2B3hTjltJry4r6bULwgAXLQ==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/import-fresh": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "dev": true, + "license": "ISC", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/interactjs": { + "version": "1.10.27", + "resolved": "https://registry.npmjs.org/interactjs/-/interactjs-1.10.27.tgz", + "integrity": "sha512-y/8RcCftGAF24gSp76X2JS3XpHiUvDQyhF8i7ujemBz77hwiHDuJzftHx7thY8cxGogwGiPJ+o97kWB6eAXnsA==", + "license": "MIT", + "dependencies": { + "@interactjs/types": "1.10.27" + } + }, + "node_modules/is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "license": "MIT" + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-potential-custom-element-name": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", + "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/jose": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/jose/-/jose-6.2.3.tgz", + "integrity": "sha512-YYVDInQKFJfR/xa3ojUTl8c2KoTwiL1R5Wg9YCydwH0x0B9grbzlg5HC7mMjCtUJjbQ/YnGEZIhI5tCgfTb4Hw==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/panva" + } + }, + "node_modules/js-tokens": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-9.0.1.tgz", + "integrity": "sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.2.0.tgz", + "integrity": "sha512-ePWsvanv0DWuDRsW8dnt+R4jQ31SCRCQ7hhNcPXZPsoBZiemuZNYGf7adZdqX2D86j6rvKp3RpCxVTSb8WQlOw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/puzrin" + }, + { + "type": "github", + "url": "https://github.com/sponsors/nodeca" + } + ], + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsdom": { + "version": "26.1.0", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-26.1.0.tgz", + "integrity": "sha512-Cvc9WUhxSMEo4McES3P7oK3QaXldCfNWp7pl2NNeiIFlCoLr3kfq9kb1fxftiwk1FLV7CvpvDfonxtzUDeSOPg==", + "dev": true, + "license": "MIT", + "dependencies": { + "cssstyle": "^4.2.1", + "data-urls": "^5.0.0", + "decimal.js": "^10.5.0", + "html-encoding-sniffer": "^4.0.0", + "http-proxy-agent": "^7.0.2", + "https-proxy-agent": "^7.0.6", + "is-potential-custom-element-name": "^1.0.1", + "nwsapi": "^2.2.16", + "parse5": "^7.2.1", + "rrweb-cssom": "^0.8.0", + "saxes": "^6.0.0", + "symbol-tree": "^3.2.4", + "tough-cookie": "^5.1.1", + "w3c-xmlserializer": "^5.0.0", + "webidl-conversions": "^7.0.0", + "whatwg-encoding": "^3.1.1", + "whatwg-mimetype": "^4.0.0", + "whatwg-url": "^14.1.1", + "ws": "^8.18.0", + "xml-name-validator": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "canvas": "^3.0.0" + }, + "peerDependenciesMeta": { + "canvas": { + "optional": true + } + } + }, + "node_modules/jsdom/node_modules/agent-base": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", + "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, + "node_modules/jsdom/node_modules/https-proxy-agent": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", + "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/jsdom/node_modules/xml-name-validator": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-5.0.0.tgz", + "integrity": "sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/jsox": { + "version": "1.2.125", + "resolved": "https://registry.npmjs.org/jsox/-/jsox-1.2.125.tgz", + "integrity": "sha512-HIf1uwublnXZsy7p3yHTrhzMzrLO6xKnqXytT9pEil5QxaXi8eyer7Is4luF5hYSV4kD3v03Y32FWoAeVYTghQ==", + "dev": true, + "license": "MIT", + "bin": { + "jsox": "lib/cli.js" + } + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash": { + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.18.1.tgz", + "integrity": "sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==", + "license": "MIT" + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/loupe": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/loupe/-/loupe-3.2.1.tgz", + "integrity": "sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/luxon": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/luxon/-/luxon-3.7.2.tgz", + "integrity": "sha512-vtEhXh/gNjI9Yg1u4jX/0YVPMvxzHuGgCm6tC5kZyb08yjGWGnqAjGJvcXbqQR2P3MyMEFnRbpcdFS6PBcLqew==", + "license": "MIT", + "engines": { + "node": ">=12" + } + }, + "node_modules/magic-string": { + "version": "0.30.21", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, + "node_modules/marked": { + "version": "17.0.6", + "resolved": "https://registry.npmjs.org/marked/-/marked-17.0.6.tgz", + "integrity": "sha512-gB0gkNafnonOw0obSTEGZTT86IuhILt2Wfx0mWH/1Au83kybTayroZ/V6nS25mN7u8ASy+5fMhgB3XPNrOZdmA==", + "license": "MIT", + "bin": { + "marked": "bin/marked.js" + }, + "engines": { + "node": ">= 20" + } + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/md5": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/md5/-/md5-2.3.0.tgz", + "integrity": "sha512-T1GITYmFaKuO91vxyoQMFETst+O71VUPEU3ze5GNzDm0OWdP8v1ziTaAEPUr/3kLsY3Sftgz242A1SetQiDL7g==", + "license": "BSD-3-Clause", + "dependencies": { + "charenc": "0.0.2", + "crypt": "0.0.2", + "is-buffer": "~1.1.6" + } + }, + "node_modules/micro-memoize": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/micro-memoize/-/micro-memoize-5.1.1.tgz", + "integrity": "sha512-QDwluos8YeMijiKxZGwaV4f4tzj0soS6+xcsJhJ3+4wdEIHMyKbIKVUziebOgWX3e6yiijdoaHo+9tyhbnaWXA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-equals": "^5.3.3", + "fast-stringify": "^4.0.0" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/minimatch": { + "version": "10.2.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", + "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.5" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/moo": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/moo/-/moo-0.5.3.tgz", + "integrity": "sha512-m2fmM2dDm7GZQsY7KK2cme8agi+AAljILjQnof7p1ZMDe6dQ4bdnSMx0cPppudoeNv5hEFQirN6u+O4fDE0IWA==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/muggle-string": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/muggle-string/-/muggle-string-0.4.1.tgz", + "integrity": "sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/nanoid": { + "version": "3.3.13", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.13.tgz", + "integrity": "sha512-sPdqC6ByMVVGvF1ynvvMo0/o+oD1VX7DaHhijt1bFgjvBkHBib4t49GoNDhf2NDta4oeUNlaGbSt5K7qjZ955Q==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true, + "license": "MIT" + }, + "node_modules/nearley": { + "version": "2.20.1", + "resolved": "https://registry.npmjs.org/nearley/-/nearley-2.20.1.tgz", + "integrity": "sha512-+Mc8UaAebFzgV+KpI5n7DasuuQCHA89dmwm7JXw3TV43ukfNQ9DnBH3Mdb2g/I4Fdxc26pwimBWvjIw0UAILSQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "commander": "^2.19.0", + "moo": "^0.5.0", + "railroad-diagrams": "^1.0.0", + "randexp": "0.4.6" + }, + "bin": { + "nearley-railroad": "bin/nearley-railroad.js", + "nearley-test": "bin/nearley-test.js", + "nearley-unparse": "bin/nearley-unparse.js", + "nearleyc": "bin/nearleyc.js" + }, + "funding": { + "type": "individual", + "url": "https://nearley.js.org/#give-to-nearley" + } + }, + "node_modules/node-addon-api": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz", + "integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==", + "license": "MIT", + "optional": true + }, + "node_modules/node-sql-parser": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/node-sql-parser/-/node-sql-parser-5.4.0.tgz", + "integrity": "sha512-jVe6Z61gPcPjCElPZ6j8llB3wnqGcuQzefim1ERsqIakxnEy5JlzV7XKdO1KmacRG5TKwPc4vJTgSRQ0LfkbFw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@types/pegjs": "^0.10.0", + "big-integer": "^1.6.48" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/nth-check": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", + "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "boolbase": "^1.0.0" + }, + "funding": { + "url": "https://github.com/fb55/nth-check?sponsor=1" + } + }, + "node_modules/nwsapi": { + "version": "2.2.24", + "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.24.tgz", + "integrity": "sha512-7YRhZ3jS45LwmSCT4b2sVFHt/WuovaktDU07QrtOBY2PXskss5a9jfmR9jptyumwXST+rFjrmppMY1KT/yn35A==", + "dev": true, + "license": "MIT" + }, + "node_modules/oauth4webapi": { + "version": "3.8.6", + "resolved": "https://registry.npmjs.org/oauth4webapi/-/oauth4webapi-3.8.6.tgz", + "integrity": "sha512-iwemM91xz8nryHti2yTmg5fhyEMVOkOXwHNqbvcATjyajb5oQxCQzrNOA6uElRHuMhQQTKUyFKV9y/CNyg25BQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/panva" + } + }, + "node_modules/object-inspect": { + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/openid-client": { + "version": "6.8.4", + "resolved": "https://registry.npmjs.org/openid-client/-/openid-client-6.8.4.tgz", + "integrity": "sha512-QSw0BA08piujetEwfZsHoTrDpMEha7GDZDicQqVwX4u0ChCjefvjDB++TZ8BTg76UpwhzIQgdvvfgfl3HpCSAw==", + "license": "MIT", + "dependencies": { + "jose": "^6.2.2", + "oauth4webapi": "^3.8.5" + }, + "funding": { + "url": "https://github.com/sponsors/panva" + } + }, + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/package-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/package-up/-/package-up-5.0.0.tgz", + "integrity": "sha512-MQEgDUvXCa3sGvqHg3pzHO8e9gqTCMPVrWUko3vPQGntwegmFo52mZb2abIVTjFnUcW0BcPz0D93jV5Cas1DWA==", + "dev": true, + "license": "MIT", + "dependencies": { + "find-up-simple": "^1.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse5": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.3.0.tgz", + "integrity": "sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==", + "dev": true, + "license": "MIT", + "dependencies": { + "entities": "^6.0.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/path-browserify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz", + "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==", + "dev": true, + "license": "MIT" + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/pathe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", + "dev": true, + "license": "MIT" + }, + "node_modules/pathval": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-2.0.1.tgz", + "integrity": "sha512-//nshmD55c46FuFw26xV/xFAaB5HF9Xdap7HJBBnrKdAd6/GxDBaNA1870O79+9ueg61cZLSVc+OaFlfmObYVQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14.16" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/postcss": { + "version": "8.5.15", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.15.tgz", + "integrity": "sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.12", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/postcss-selector-parser": { + "version": "6.1.4", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.4.tgz", + "integrity": "sha512-bIoJLOmjCO1S9XdY/DcnR5hJxvrDir1PbGChrzXG3vw0/FOliy/fA3dmdhQ441kah4gKv+TwckGzex6wNS5cnQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prettier": { + "version": "3.8.4", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.8.4.tgz", + "integrity": "sha512-N2MylSdi48+5N/6S5j+maeHbUSIzzZ5uOcX5Hm4QpV8Dkb1HFjfAKTKX6yNPJQD9AhcT3ifHNB66tWTTJDi11Q==", + "dev": true, + "license": "MIT", + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/prettier-linter-helpers": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.1.tgz", + "integrity": "sha512-SxToR7P8Y2lWmv/kTzVLC1t/GDI2WGjMwNhLLE9qtH8Q13C+aEmuRlzDst4Up4s0Wc8sF2M+J57iB3cMLqftfg==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-diff": "^1.1.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/prettier-plugin-embed": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/prettier-plugin-embed/-/prettier-plugin-embed-0.5.1.tgz", + "integrity": "sha512-2Ege8gIlLNTvHElUeU5XcFsD7/dbDXkQA6H9TczHSJAGxB58nNjjifk/dlRMS5E29eqQx/z+ToA4ZVMWzjME/A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.8", + "dedent": "^1.7.1", + "micro-memoize": "^5.1.1", + "package-up": "^5.0.0", + "tiny-jsonc": "^1.0.2", + "type-fest": "^5.3.1" + } + }, + "node_modules/prettier-plugin-embed/node_modules/type-fest": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-5.7.0.tgz", + "integrity": "sha512-1URUxUqfHFM1c+zfSPsa3gnkO7Aq21qyH75SIduNYz4SzY964rn1X2vCMQaHSHhktiw+0kPa2iyb6PUpXqB6Vg==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "dependencies": { + "tagged-tag": "^1.0.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/prettier-plugin-sql": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/prettier-plugin-sql/-/prettier-plugin-sql-0.19.2.tgz", + "integrity": "sha512-DAu1Jcanpvs32OAOXsqaVXOpPs4nFLVkB3XwzRiZZVNL5/c+XdlNxWFMiMpMhYhmCG5BW3srK8mhikCOv5tPfg==", + "dev": true, + "license": "MIT", + "dependencies": { + "jsox": "^1.2.123", + "node-sql-parser": "^5.3.10", + "sql-formatter": "^15.6.5", + "tslib": "^2.8.1" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/unts" + }, + "peerDependencies": { + "prettier": "^3.0.3" + } + }, + "node_modules/proxy-from-env": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-2.1.0.tgz", + "integrity": "sha512-cJ+oHTW1VAEa8cJslgmUZrc+sjRKgAKl3Zyse6+PV38hZe/V6Z14TbCuXcan9F9ghlz4QrFr2c92TNF82UkYHA==", + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/qs": { + "version": "6.15.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.15.2.tgz", + "integrity": "sha512-Rzq0KEyX/w/tEybncDgdkZrJgVUsUMk3xjh3t5bv3S1HTAtg+uOYt72+ZfwiQwKdysThkTBdL/rTi6HDmX9Ddw==", + "license": "BSD-3-Clause", + "dependencies": { + "side-channel": "^1.1.0" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/railroad-diagrams": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/railroad-diagrams/-/railroad-diagrams-1.0.0.tgz", + "integrity": "sha512-cz93DjNeLY0idrCNOH6PviZGRN9GJhsdm9hpn1YCS879fj4W+x5IFJhhkRZcwVgMmFF7R82UA/7Oh+R8lLZg6A==", + "dev": true, + "license": "CC0-1.0" + }, + "node_modules/randexp": { + "version": "0.4.6", + "resolved": "https://registry.npmjs.org/randexp/-/randexp-0.4.6.tgz", + "integrity": "sha512-80WNmd9DA0tmZrw9qQa62GPPWfuXJknrmVmLcxvq4uZBdYqb1wYoKTmnlGUchvVWe0XiLupYkBoXVOxz3C8DYQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "discontinuous-range": "1.0.0", + "ret": "~0.1.10" + }, + "engines": { + "node": ">=0.12" + } + }, + "node_modules/readdirp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-5.0.0.tgz", + "integrity": "sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/ret": { + "version": "0.1.15", + "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", + "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12" + } + }, + "node_modules/reusify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", + "dev": true, + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "dev": true, + "license": "ISC", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rollup": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.62.2.tgz", + "integrity": "sha512-RFnrW4lhXA3s3eqHDZvN654g8OTjzRfqpIRJYczCGB6HzphckVAi/Qh4tbPUbRuDi7s1Llv8g/NspLkttY3gTA==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.9" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.62.2", + "@rollup/rollup-android-arm64": "4.62.2", + "@rollup/rollup-darwin-arm64": "4.62.2", + "@rollup/rollup-darwin-x64": "4.62.2", + "@rollup/rollup-freebsd-arm64": "4.62.2", + "@rollup/rollup-freebsd-x64": "4.62.2", + "@rollup/rollup-linux-arm-gnueabihf": "4.62.2", + "@rollup/rollup-linux-arm-musleabihf": "4.62.2", + "@rollup/rollup-linux-arm64-gnu": "4.62.2", + "@rollup/rollup-linux-arm64-musl": "4.62.2", + "@rollup/rollup-linux-loong64-gnu": "4.62.2", + "@rollup/rollup-linux-loong64-musl": "4.62.2", + "@rollup/rollup-linux-ppc64-gnu": "4.62.2", + "@rollup/rollup-linux-ppc64-musl": "4.62.2", + "@rollup/rollup-linux-riscv64-gnu": "4.62.2", + "@rollup/rollup-linux-riscv64-musl": "4.62.2", + "@rollup/rollup-linux-s390x-gnu": "4.62.2", + "@rollup/rollup-linux-x64-gnu": "4.62.2", + "@rollup/rollup-linux-x64-musl": "4.62.2", + "@rollup/rollup-openbsd-x64": "4.62.2", + "@rollup/rollup-openharmony-arm64": "4.62.2", + "@rollup/rollup-win32-arm64-msvc": "4.62.2", + "@rollup/rollup-win32-ia32-msvc": "4.62.2", + "@rollup/rollup-win32-x64-gnu": "4.62.2", + "@rollup/rollup-win32-x64-msvc": "4.62.2", + "fsevents": "~2.3.2" + } + }, + "node_modules/rrweb-cssom": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.8.0.tgz", + "integrity": "sha512-guoltQEx+9aMf2gDZ0s62EcV8lsXR+0w8915TC3ITdn2YueuNjdAYh/levpU9nFaoChh9RUS5ZdQMrKfVEN9tw==", + "dev": true, + "license": "MIT" + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true, + "license": "MIT" + }, + "node_modules/sass": { + "version": "1.101.0", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.101.0.tgz", + "integrity": "sha512-OL3GoQyoUdDt843DpVmDO6y2k1sc5IhUDSpu8XucEI+35neq5QivZ1iuegnpraEVTJXlQGK1gl27zKcTLEPbQw==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "chokidar": "^5.0.0", + "immutable": "^5.1.5", + "source-map-js": ">=0.6.2 <2.0.0" + }, + "bin": { + "sass": "sass.js" + }, + "engines": { + "node": ">=20.19.0" + }, + "optionalDependencies": { + "@parcel/watcher": "^2.4.1" + } + }, + "node_modules/saxes": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz", + "integrity": "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==", + "dev": true, + "license": "ISC", + "dependencies": { + "xmlchars": "^2.2.0" + }, + "engines": { + "node": ">=v12.22.7" + } + }, + "node_modules/semver": { + "version": "7.8.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/side-channel": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.1.tgz", + "integrity": "sha512-6x6dK6zJdpTzF4sQeNYxwtvBzf6Eg4GtlesS94HOvTudUeyK2WXAaIfmDgsyslYrRBeFIlsi54AYsFGUuhmvrQ==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.4", + "side-channel-list": "^1.0.1", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-list": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.1.tgz", + "integrity": "sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-weakmap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/siginfo": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", + "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==", + "dev": true, + "license": "ISC" + }, + "node_modules/sortablejs": { + "version": "1.15.7", + "resolved": "https://registry.npmjs.org/sortablejs/-/sortablejs-1.15.7.tgz", + "integrity": "sha512-Kk8wLQPlS+yi1ZEf48a4+fzHa4yxjC30M/Sr2AnQu+f/MPwvvX9XjZ6OWejiz8crBsLwSq8GHqaxaET7u6ux0A==", + "license": "MIT", + "peer": true + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sql-formatter": { + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/sql-formatter/-/sql-formatter-15.8.1.tgz", + "integrity": "sha512-nT2r90kTEYBuse9fe4r1Rp78v1mOBD35KsGc07Vo9eQSVa1TcTSnCS0zouf6BCmdzvmqBsBW+cYuBoYkHO/OWg==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1", + "nearley": "^2.20.1" + }, + "bin": { + "sql-formatter": "bin/sql-formatter-cli.cjs" + } + }, + "node_modules/stackback": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", + "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==", + "dev": true, + "license": "MIT" + }, + "node_modules/std-env": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.10.0.tgz", + "integrity": "sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==", + "dev": true, + "license": "MIT" + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/strip-literal": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/strip-literal/-/strip-literal-3.1.0.tgz", + "integrity": "sha512-8r3mkIM/2+PpjHoOtiAW8Rg3jJLHaV7xPwG+YRGrv6FP0wwk/toTpATxWYOW0BKdWwl82VT2tFYi5DlROa0Mxg==", + "dev": true, + "license": "MIT", + "dependencies": { + "js-tokens": "^9.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/symbol-tree": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", + "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", + "dev": true, + "license": "MIT" + }, + "node_modules/synckit": { + "version": "0.11.13", + "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.11.13.tgz", + "integrity": "sha512-eNRKgb3z66Yp3D2CixVujOUvXLFUTij/zVnV8KRyvFdQwpz7I5DS8UfRkTeLzb64u+dkzDSdelE24izu+zSSUg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@pkgr/core": "^0.3.6" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/synckit" + } + }, + "node_modules/tagged-tag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/tagged-tag/-/tagged-tag-1.0.0.tgz", + "integrity": "sha512-yEFYrVhod+hdNyx7g5Bnkkb0G6si8HJurOoOEgC8B/O0uXLHlaey/65KRv6cuWBNhBgHKAROVpc7QyYqE5gFng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true, + "license": "MIT" + }, + "node_modules/tiny-jsonc": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/tiny-jsonc/-/tiny-jsonc-1.0.2.tgz", + "integrity": "sha512-f5QDAfLq6zIVSyCZQZhhyl0QS6MvAyTxgz4X4x3+EoCktNWEYJ6PeoEA97fyb98njpBNNi88ybpD7m+BDFXaCw==", + "dev": true, + "license": "MIT" + }, + "node_modules/tinybench": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz", + "integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==", + "dev": true, + "license": "MIT" + }, + "node_modules/tinyexec": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-0.3.2.tgz", + "integrity": "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==", + "dev": true, + "license": "MIT" + }, + "node_modules/tinyglobby": { + "version": "0.2.17", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz", + "integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.4" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tinypool": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-1.1.1.tgz", + "integrity": "sha512-Zba82s87IFq9A9XmjiX5uZA/ARWDrB03OHlq+Vw1fSdt0I+4/Kutwy8BP4Y/y/aORMo61FQ0vIb5j44vSo5Pkg==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.0.0 || >=20.0.0" + } + }, + "node_modules/tinyrainbow": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-2.0.0.tgz", + "integrity": "sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/tinyspy": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-4.0.4.tgz", + "integrity": "sha512-azl+t0z7pw/z958Gy9svOTuzqIk6xq+NSheJzn5MMWtWTFywIacg2wUlzKFGtt3cthx0r2SxMK0yzJOR0IES7Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/tldts": { + "version": "6.1.86", + "resolved": "https://registry.npmjs.org/tldts/-/tldts-6.1.86.tgz", + "integrity": "sha512-WMi/OQ2axVTf/ykqCQgXiIct+mSQDFdH2fkwhPwgEwvJ1kSzZRiinb0zF2Xb8u4+OqPChmyI6MEu4EezNJz+FQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "tldts-core": "^6.1.86" + }, + "bin": { + "tldts": "bin/cli.js" + } + }, + "node_modules/tldts-core": { + "version": "6.1.86", + "resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-6.1.86.tgz", + "integrity": "sha512-Je6p7pkk+KMzMv2XXKmAE3McmolOQFdxkKw0R8EYNr7sELW46JqnNeTX8ybPiQgvg1ymCoF8LXs5fzFaZvJPTA==", + "dev": true, + "license": "MIT" + }, + "node_modules/tough-cookie": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-5.1.2.tgz", + "integrity": "sha512-FVDYdxtnj0G6Qm/DhNPSb8Ju59ULcup3tuJxkFb5K8Bv2pUXILbf0xZWU8PX8Ov19OXljbUyveOFwRMwkXzO+A==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "tldts": "^6.1.32" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/tr46": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-5.1.1.tgz", + "integrity": "sha512-hdF5ZgjTqgAntKkklYw0R03MG2x/bSzTtkxmIRw/sTNV8YXsCJ1tfLAX23lhxhHJlEf3CRCOCGGWw3vI3GaSPw==", + "dev": true, + "license": "MIT", + "dependencies": { + "punycode": "^2.3.1" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/ts-api-utils": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.5.0.tgz", + "integrity": "sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.12" + }, + "peerDependencies": { + "typescript": ">=4.8.4" + } + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "dev": true, + "license": "0BSD" + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "devOptional": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/upath": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/upath/-/upath-2.0.1.tgz", + "integrity": "sha512-1uEe95xksV1O0CYKXo8vQvN1JEbtJp7lb7C5U9HMsIp6IVwntkH/oNUzyVNQSd4S1sYk2FpSSW44FqMc8qee5w==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": ">=4", + "yarn": "*" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true, + "license": "MIT" + }, + "node_modules/validator": { + "version": "13.15.35", + "resolved": "https://registry.npmjs.org/validator/-/validator-13.15.35.tgz", + "integrity": "sha512-TQ5pAGhd5whStmqWvYF4OjQROlmv9SMFVt37qoCBdqRffuuklWYQlCNnEs2ZaIBD1kZRNnikiZOS1eqgkar0iw==", + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/vite": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.5.tgz", + "integrity": "sha512-KuOaNhcnGFN2zIPGA7wRmzF+lJA1sea7rHq17aiJ++9lzY1WWG6Jpwqwe1KNbRVPIqHmr8GLYx7jbrQcN/7/ww==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "esbuild": "^0.27.0", + "fdir": "^6.5.0", + "picomatch": "^4.0.3", + "postcss": "^8.5.6", + "rollup": "^4.43.0", + "tinyglobby": "^0.2.15" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^20.19.0 || >=22.12.0", + "jiti": ">=1.21.0", + "less": "^4.0.0", + "lightningcss": "^1.21.0", + "sass": "^1.70.0", + "sass-embedded": "^1.70.0", + "stylus": ">=0.54.8", + "sugarss": "^5.0.0", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/vite-node": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-3.2.4.tgz", + "integrity": "sha512-EbKSKh+bh1E1IFxeO0pg1n4dvoOTt0UDiXMd/qn++r98+jPO1xtJilvXldeuQ8giIB5IkpjCgMleHMNEsGH6pg==", + "dev": true, + "license": "MIT", + "dependencies": { + "cac": "^6.7.14", + "debug": "^4.4.1", + "es-module-lexer": "^1.7.0", + "pathe": "^2.0.3", + "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0" + }, + "bin": { + "vite-node": "vite-node.mjs" + }, + "engines": { + "node": "^18.0.0 || ^20.0.0 || >=22.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/vite-plugin-vuetify": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/vite-plugin-vuetify/-/vite-plugin-vuetify-2.1.3.tgz", + "integrity": "sha512-Q4SC/4TqbNvaZIFb9YsfBqkGlYHbJJJ6uU3CnRBZqLUF3s5eCMVZAaV4GkTbehIH/bhSj42lMXztOwc71u6rVw==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "@vuetify/loader-shared": "^2.1.2", + "debug": "^4.3.3", + "upath": "^2.0.1" + }, + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "peerDependencies": { + "vite": ">=5", + "vue": "^3.0.0", + "vuetify": ">=3" + } + }, + "node_modules/vitest": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-3.2.6.tgz", + "integrity": "sha512-xejya+bT/j/+R/AGa1XOfRxLmNUlLtlwjRsFUILF+xHfzElmGcmFydy2gqqIrd62ptIEfwVMofd19uNWD9L7Nw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/chai": "^5.2.2", + "@vitest/expect": "3.2.6", + "@vitest/mocker": "3.2.6", + "@vitest/pretty-format": "^3.2.6", + "@vitest/runner": "3.2.6", + "@vitest/snapshot": "3.2.6", + "@vitest/spy": "3.2.6", + "@vitest/utils": "3.2.6", + "chai": "^5.2.0", + "debug": "^4.4.1", + "expect-type": "^1.2.1", + "magic-string": "^0.30.17", + "pathe": "^2.0.3", + "picomatch": "^4.0.2", + "std-env": "^3.9.0", + "tinybench": "^2.9.0", + "tinyexec": "^0.3.2", + "tinyglobby": "^0.2.14", + "tinypool": "^1.1.1", + "tinyrainbow": "^2.0.0", + "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0", + "vite-node": "3.2.4", + "why-is-node-running": "^2.3.0" + }, + "bin": { + "vitest": "vitest.mjs" + }, + "engines": { + "node": "^18.0.0 || ^20.0.0 || >=22.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "@edge-runtime/vm": "*", + "@types/debug": "^4.1.12", + "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", + "@vitest/browser": "3.2.6", + "@vitest/ui": "3.2.6", + "happy-dom": "*", + "jsdom": "*" + }, + "peerDependenciesMeta": { + "@edge-runtime/vm": { + "optional": true + }, + "@types/debug": { + "optional": true + }, + "@types/node": { + "optional": true + }, + "@vitest/browser": { + "optional": true + }, + "@vitest/ui": { + "optional": true + }, + "happy-dom": { + "optional": true + }, + "jsdom": { + "optional": true + } + } + }, + "node_modules/vscode-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-3.1.0.tgz", + "integrity": "sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/vue": { + "version": "3.5.38", + "resolved": "https://registry.npmjs.org/vue/-/vue-3.5.38.tgz", + "integrity": "sha512-vAMKHfImQlYSy0C+PBue4s3ERZ2xGKfgZg5GXAsLInq1dyh2H78ILVP5sK0KPFPVW4kv+OGCIvBEondcjpZp7A==", + "license": "MIT", + "dependencies": { + "@vue/compiler-dom": "3.5.38", + "@vue/compiler-sfc": "3.5.38", + "@vue/runtime-dom": "3.5.38", + "@vue/server-renderer": "3.5.38", + "@vue/shared": "3.5.38" + }, + "peerDependencies": { + "typescript": "*" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/vue-draggable-next": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/vue-draggable-next/-/vue-draggable-next-2.3.0.tgz", + "integrity": "sha512-ymbY0UIwfSdg0iDN/iyNNwUrTqZ/6KbPryzsvTNXBLuDCuOBdNijSK8yynNtmiSj6RapTPQfjLGQdJrZkzBd2w==", + "license": "MIT", + "peerDependencies": { + "sortablejs": "^1.14.0", + "vue": "^3.5.17" + } + }, + "node_modules/vue-eslint-parser": { + "version": "9.4.3", + "resolved": "https://registry.npmjs.org/vue-eslint-parser/-/vue-eslint-parser-9.4.3.tgz", + "integrity": "sha512-2rYRLWlIpaiN8xbPiDyXZXRgLGOtWxERV7ND5fFAv5qo1D2N9Fu9MNajBNc6o13lZ+24DAWCkQCvj4klgmcITg==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.3.4", + "eslint-scope": "^7.1.1", + "eslint-visitor-keys": "^3.3.0", + "espree": "^9.3.1", + "esquery": "^1.4.0", + "lodash": "^4.17.21", + "semver": "^7.3.6" + }, + "engines": { + "node": "^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + }, + "peerDependencies": { + "eslint": ">=6.0.0" + } + }, + "node_modules/vue-i18n": { + "version": "11.4.6", + "resolved": "https://registry.npmjs.org/vue-i18n/-/vue-i18n-11.4.6.tgz", + "integrity": "sha512-l0gE7Rfy0phCa5ChKYkOq543Wgd39BCK6hkktfr1Ed4D99oRkgPK9ffShASZdeC8OJxGfdWmpYoAaAH6iLEuIg==", + "license": "MIT", + "dependencies": { + "@intlify/core-base": "11.4.6", + "@intlify/devtools-types": "11.4.6", + "@intlify/shared": "11.4.6", + "@vue/devtools-api": "^6.5.0" + }, + "engines": { + "node": ">= 22" + }, + "funding": { + "url": "https://github.com/sponsors/kazupon" + }, + "peerDependencies": { + "vue": "^3.0.0" + } + }, + "node_modules/vue-router": { + "version": "4.6.4", + "resolved": "https://registry.npmjs.org/vue-router/-/vue-router-4.6.4.tgz", + "integrity": "sha512-Hz9q5sa33Yhduglwz6g9skT8OBPii+4bFn88w6J+J4MfEo4KRRpmiNG/hHHkdbRFlLBOqxN8y8gf2Fb0MTUgVg==", + "license": "MIT", + "dependencies": { + "@vue/devtools-api": "^6.6.4" + }, + "funding": { + "url": "https://github.com/sponsors/posva" + }, + "peerDependencies": { + "vue": "^3.5.0" + } + }, + "node_modules/vue-scrollto": { + "version": "2.20.0", + "resolved": "https://registry.npmjs.org/vue-scrollto/-/vue-scrollto-2.20.0.tgz", + "integrity": "sha512-7i+AGKJTThZnMEkhIPgrZjyAX+fXV7/rGdg+CV283uZZwCxwiMXaBLTmIc5RTA4uwGnT+E6eJle3mXQfM2OD3A==", + "license": "MIT", + "dependencies": { + "bezier-easing": "2.1.0" + } + }, + "node_modules/vue-tsc": { + "version": "3.3.5", + "resolved": "https://registry.npmjs.org/vue-tsc/-/vue-tsc-3.3.5.tgz", + "integrity": "sha512-Rzh/G2MmNlMSAMTiQEjDrsb4dgB/jbtEM47rVN2NtidF1dfb/q4w4QvpQBtW5+y3y5H27Hjh7deVwk+YB02fNg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@volar/typescript": "2.4.28", + "@vue/language-core": "3.3.5" + }, + "bin": { + "vue-tsc": "bin/vue-tsc.js" + }, + "peerDependencies": { + "typescript": ">=5.0.0" + } + }, + "node_modules/vuetify": { + "version": "3.12.8", + "resolved": "https://registry.npmjs.org/vuetify/-/vuetify-3.12.8.tgz", + "integrity": "sha512-gvmOWeLd6CG7LVh2Qonft5YrIb7MpbKZglRjg0ItEloSbu6hfUII2RZmRSVxGKYdiXTf7J1hI3BRSHr8J9LkxA==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/johnleider" + }, + "peerDependencies": { + "typescript": ">=4.7", + "vite-plugin-vuetify": ">=2.1.0", + "vue": "^3.5.0", + "webpack-plugin-vuetify": ">=3.1.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + }, + "vite-plugin-vuetify": { + "optional": true + }, + "webpack-plugin-vuetify": { + "optional": true + } + } + }, + "node_modules/w3c-xmlserializer": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-5.0.0.tgz", + "integrity": "sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==", + "dev": true, + "license": "MIT", + "dependencies": { + "xml-name-validator": "^5.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/w3c-xmlserializer/node_modules/xml-name-validator": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-5.0.0.tgz", + "integrity": "sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18" + } + }, + "node_modules/webidl-conversions": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", + "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + } + }, + "node_modules/whatwg-encoding": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-3.1.1.tgz", + "integrity": "sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==", + "deprecated": "Use @exodus/bytes instead for a more spec-conformant and faster implementation", + "dev": true, + "license": "MIT", + "dependencies": { + "iconv-lite": "0.6.3" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/whatwg-mimetype": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-4.0.0.tgz", + "integrity": "sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/whatwg-url": { + "version": "14.2.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-14.2.0.tgz", + "integrity": "sha512-De72GdQZzNTUBBChsXueQUnPKDkg/5A5zp7pFDuQAj5UFoENpiACU0wlCvzpAGnTkj++ihpKwKyYewn/XNUbKw==", + "dev": true, + "license": "MIT", + "dependencies": { + "tr46": "^5.1.0", + "webidl-conversions": "^7.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/why-is-node-running": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz", + "integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==", + "dev": true, + "license": "MIT", + "dependencies": { + "siginfo": "^2.0.0", + "stackback": "0.0.2" + }, + "bin": { + "why-is-node-running": "cli.js" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/ws": { + "version": "8.21.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.21.0.tgz", + "integrity": "sha512-Vsp28b7DRcimFQvrqu2Wek3z1iYxDCWqHYB8Qsnk/S4RfaCQzPGPyBNuVjJV3cd6UiKtUtp6sNM77gWvzcCH+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/xml-name-validator": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-4.0.0.tgz", + "integrity": "sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12" + } + }, + "node_modules/xmlchars": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", + "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", + "dev": true, + "license": "MIT" + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + } +} diff --git a/web/package.json b/web/package.json new file mode 100644 index 0000000..eb4167f --- /dev/null +++ b/web/package.json @@ -0,0 +1,63 @@ +{ + "name": "alphane-web", + "private": true, + "version": "0.1.0", + "type": "module", + "scripts": { + "start": "vite", + "build": "vue-tsc && vite build", + "preview": "vite preview", + "test": "vitest", + "lint": "eslint . --ext .js,.ts,.vue --ignore-path ../.gitignore", + "check-types": "vue-tsc --noEmit" + }, + "dependencies": { + "@auth0/auth0-vue": "^2.5.0", + "@mdi/font": "^7.4.47", + "@tabler/icons-vue": "^3.36.0", + "@vueuse/core": "^13.9.0", + "@vueuse/router": "^13.9.0", + "axios": "^1.13.2", + "dompurify": "^3.3.3", + "grid-layout-plus": "^1.1.1", + "js-yaml": "^4.1.0", + "lodash": "^4.17.21", + "luxon": "^3.7.2", + "marked": "^17.0.5", + "md5": "^2.3.0", + "qs": "^6.14.0", + "validator": "^13.15.26", + "vue": "^3.4.21", + "vue-draggable-next": "^2.3.0", + "vue-i18n": "^11.3.0", + "vue-router": "^4.6.4", + "vue-scrollto": "^2.20.0", + "vuetify": "^3.11.4" + }, + "devDependencies": { + "@types/dompurify": "^3.0.5", + "@types/js-yaml": "^4.0.9", + "@types/lodash": "^4.17.21", + "@types/luxon": "^3.7.1", + "@types/md5": "^2.3.6", + "@types/qs": "^6.14.0", + "@types/validator": "^13.15.10", + "@typescript-eslint/eslint-plugin": "^8.50.1", + "@typescript-eslint/parser": "^8.50.1", + "@vitejs/plugin-vue": "^6.0.3", + "eslint": "^8.57.1", + "eslint-config-prettier": "^10.1.8", + "eslint-plugin-prettier": "^5.5.4", + "eslint-plugin-vue": "^9.33.0", + "jsdom": "^26.1.0", + "prettier": "^3.7.4", + "prettier-plugin-embed": "^0.5.1", + "prettier-plugin-sql": "^0.19.2", + "sass": "^1.97.1", + "typescript": "^5.9.3", + "vite": "^7.3.0", + "vite-plugin-vuetify": "^2.1.2", + "vitest": "^3.2.4", + "vue-tsc": "^3.2.1" + } +} \ No newline at end of file diff --git a/web/public/Logo.png b/web/public/Logo.png new file mode 100644 index 0000000000000000000000000000000000000000..df593a1af6a388eb4f9f9aa93f18701e04dce83c GIT binary patch literal 6791 zcmV;28hGW2P)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D8XQSPK~#8N?VSmD zR7JMOD2o7$zpdx~TAS$A$i2LZcuj4Xr+_&dAI&a41xyCT=*NT_Ft`X18Ul)1R;cz${j`k-m@!Pj=hB#+Pt{BxnBl1dY ztf*=b4}V-K?wMT~dBx#yI2?}lBPQ|7&rB89jm{It?vfpOrEM%;T`z8WbFFwudV>y! z!{KnW7oihg_UV%$UOcTNVZsM}3(~~I2}RVdR;^;cz${$)#2CJ9t2*xMzIwh3SYLvz!1r91e%0T?iDv9lNEA zyV_BZ5I`3KbvPUjN3sbNzdw)37nx}(k!S4#A<#p%%Zxm8I2;a#Bk}l(-}ysx#h$%7 zN1nAWSMTqst|2;Lg zT3qqcYW25EM|2UtmELZ8r{K2c|7z+tish9X#HUN@#FJlCi`hTcM*bQe%JC=Z(HF>j z3|x2GSL?*@o-bF=!|?i<-Nb-MI|NbRAjI0*2JwAay?AM1jd=X?D%IW&hr_X{@$~#o z-6JPy!dG7LL*%z$P9K~b`7N=$ySP>fh=zLZ(j)kE8aQr^J_ob4C##JRV^3XX0;7MD~&bVZVp1ALDiiE+ePmbkA)TO@tQ# zZYvpSDPp|z;wDWf3N3*9$g=F+yK|EeYkEpiKW69TiV~m6zRnvD$``+p-nYZyaBNCC zcU z90@gM$e+Kg-5}C@ygdVO^+{@)`{g+4JzzOxKf8mxn{5YG|^4g=e2KJ zZ>RJ2&Q3b~uaM_QKd*0m;zPYG)-&_gMLk&iy!eH3apXT&iqoc)iEmdme?ta3 zc)+%qt)8<=SrFQY#)>sH4PwEHX0h)rz1Vm|k_e_*-lx8(7T3MHMx6U>nHYB8a`p~eD9L1w*aZ}yPJ@>vK3 zi9>!MA`cx?q`X@{j*{X&>8K(#AtnlprZK+?CtQSk?;KYkddNP3M|}F8IjY=ax62B( z?z}m$ThDayuj7lw%V(5CJ*J;lq68gr-&`0X@6E%<7KuNM&X2sZWx!nYm~7*qzT8oX zWxTaU3-Rk;9GlqqC9v>%knr{EIZ7O`=k<|i{xCTt13WN1F%6y_9-a-KZ+dU#)eTYJ zTV6)07~0!gc(_qIaR{MBa1q|N!dF5qt!VaK5iV0?Z4jCL`elgph}%cTCE1r8C{DOn z(@)kFkxT}kEv*yl4Wl71BSlW6;gf8BUb8_>3MA}!fq^o#cZN79U|@`v;+`wp;w!`B zZBIBY>62g9i?g386BkY^7biTiDyk1|3FLH66@3fS#K&?BO!}a*>G7=e_*oXXe?p5{y%fL5lQ>{K67eKq$BPkC z+`nE~CyM0+>?M%gkL|jqEAiP>bdsZOOA|XUFy!n|Hv)6Ulrr&O&zCEs=BfmRrow<> z=eKO}#OKv&ylyEF=_2of?NAtMWZpZHLksaEojwd?Y|i=mktPpMXK*5fi4r~tTb@|4 zL!XG4SLoC9-s+@Ed?E$x{U2+^%Bp7ZVGYZkaFdngsnH21VL;H#I=m$(1HIpF%9qhz zx5=Vkt8b0>J-yb5`5Sv++mektb5X5))TjyEMz42LAHC*jL)obp zW6=w|JRJ_C{aR~Ru4O*w`g)C(w!2KW1^;u~p#|#R`a!>--Sm6eFHC!JolAyyiM-1j z+SA-y9K_KB8_U2tIrGz~{@(qJ&!ryJhkEc;bCfNpU3I4pU*b^?#bw{8Ii3)iFgLJFB=9|kJ zr0K<)(4i1CO=)F=ctwhY=F=tXRR~KrGj%yK3F1e4=@f0cvqgxzw)9NE6+`fL~&%&e>ZWlTX+hVg*nG%@kWLbdM6^~nm}r%&gm z$EHrY zPwK1bAtx=?bov!~PhNO=Ji@}YOs|mZv&PCd)jW1wvDmA39V;%M<^1V%Mnh z!0-3%B3?YbMD-8)3H_Li=V_;usD5>T)gNt$yf6+2b_-tDWxkwgfB@WJYu=^vPy!(<9NMsYztW6H5%shP6gbsq{i;eCO>|a-xfVF9Juo z5j>MOzN=9uv1oRc9X;M}>9=9x!63>ttKnh6Y{+nX4Ejtn(n? zW)c#fVgJIkrjREC<ivg3x1WqVi<-8>pc>XUx-DR&^cMIVlMj8-grp|Z2ryxr%AmWJiIbmN6?r8-I1iW*^|DAr zf$}0iSG~Mi)r0y_uj8LsDT=aF<4#D4wOuugS0Xcazh5bie|)9-A2O3KnO-iomSS^? zAvR2|CrJb8@z1JN|Dd1nIOxGrB~FJ(fzTP$ejG7*g&2D8a@9A3z-XcE2qOb0FA>Tg zy{-3HB+(7AOclSwXuOAo{ z%&kW~)_5OzkQG0E@=7s%L1R1m(L94jAh93__U7$A;8gW9Eb$5-{F21IU|ylmK}NVG zD#v$Unh6(9#DVkwOkr!73#G}kur0<;9U0J^7@oh|s(-+3Rf0O%#$eG~~ z!ed+Kr!^TD)CErquShdYzMosH4TN#qXNn5h79>O10{p*ktyNa5eYpBsX@pIl6MQ@y zp%xAupgh;Sx~9ociUkHU_xDjb8QAxf>plKil^87Bn|gCEv!%(+|7f`9g;}ZMc{y>i zrxIgHgAi^jJ+E1Dlq)QF8+ed-;M_0D$vArY%jy;e!#A?eP5huz^pS>zS%+l9IA{EF zJfR8gOPgyi3Md!-fqr4bv50e*t#3*sYYP}n`%A-w&ob{jeRlhjbkFwTW2Z=gu=^SR zf8Xqu?TVODUb`;z>1$qDtwe~iq2c-%Np?FiHojR^uj+3@X1Bi1BXYd(yPbqapI}VB zCi?@QP5BW&o7q3ES7q4NGT=<|GEziUT}y`z121T-LJRRT_kQ_7mS$K1Y>V&#-c~a4 z3VmX2*xnlnCgyrkQ0UVXO@uX;kSFVegsbcaop`5i=}{uWwcnNA(9IEx%mx8N$TSEX z;^4(hIg#pZ4|F&>r{B7ZiMFD>%FHCl@n%|lfye^;7QH-=FmS(E@6?_hR&l*_CGiS1 z915_j6n!QXz%%@Db$!#M!Zr&IH1NA8^W@(UFw<+|Fas=oKbZ6`i& zY(-VGcd557*xuWBa-y^+Y_HI#Et-i8d79w4JSr`#^QM-0S~%LeGL2F~kBhI|%Jacu zHlBi}TP_0Aa=^t46C#ty@1~Wvuq0!F`&BLLtGAczEe94JgehcX_hEeCi8Fz1Q_z^2 zui+kV2o}Skjg4S!(^izyt3^3gfsn?9Nx~W96!=!+X=$EM;7_H`<r zl`pSW1{Q0!A6?KxKDw&}oz{e~MNMbMkQN*yfNd2%c++PcE0J&m@XR!b1zQ(P?+uR# z3&zGP^vU9Fydh8En-D5x$F(24t|0_F`O|7~{p)LdCrPX;1T0<%-v#v0xOpQ*#Uv_qAw2m2ps ztK#fVt*$$T0gvDxA61HhcP?#u4F3BvwJbp7#9Tkt<@B3WsVDU{_nY!O&4_TAn8sYP zp{-cwC6m|>l32_{u6Q7-!)GigZEPzWjtRubw!?>+vRFawN?WlWs=+|l-{#^4V}gXZ zAQ%&jjn=NCGsrQ5Sl{1Q_D}jI(Ff*L^Vmw(RhcKpK3v+g#?9kjpH(Y^vNc$%X3ciQ z{maEpvM=8CUZvWz-P(4W7BwJ@5)|IC@e;s92p>G(%7SI0utT4C3fwHsO6h%?lc&Zj z^oivbZ^#q)`X6&r(GS*ow3SEbljFg>Qknt5;%{wTi|Cctsm0ot4MNO`GktGa67|^T z)+J)cJC=$)<)lag1^cZMg&F!}aIk1@!+Y?EFk%)PAx|JA$tf>h?T5#PXwHdYKj07Y zp0QAmA;Mt)>$?@o5ITQoaHg6U7z#{Merv9WN)G{X(PNap^_>)$ky707>=v$Qt}EqX z-DGH=&T8$CaHwC{yRGn9_kUO^dP(s!>rFW+FXi@vdQxBN4Xg(kxmUIC|o@9~?@7$7C)=6iDF<+pfTLKp*jnN-!1} z6Jf&jj19&}*z0iaa9&1=TKiYgho#X;cZ4@N=hrsm`xbPH%YYQ#Em<{8My6bEEdCl=~=Q|b3lP2Y! zbtN(#dE7stNL(~5SG*)6*iX;4m7j)M*Ff95w`RX;N8PeR;|-O|)`gYXnTthHDZ5)i%1PFR!>;e$!iifk|J z(5DHVC1@Sg4t<)$8uAQ+NrWTY>&^Fk}xvdN2WagD< z!SxBXeSBf#wf`awm_(l6%9@g1S2|;GjyjVS!98zkxe9l;M$kS##unp^_4^=n_;7Up z#!cr?C#M3EtB7!XaDMlucIBF6d)n;^WLQ#W+LQOwzHHjZn`2CvMwK6wg)u@zg}svc zI(HvYs1lpJu7iQb_8p=W+*=c}Mky2H@9lHDi}!!qUF}tTQyK&;U-&`a#;YU>ru!8S z_6KsD;%#qxCjx3bzsVg47fm^-Yvft`!akkLUTplP^Y((xqE|`lM~5smgd;9^t~|q89OZL?_HQq}$)*PRBa%!BX|R7cABg$bM z6+*@&luVsp?Z#>ZPtOnV7O*PX8`66JG$UBClYt%j)C7e*HD>5jlgN;#$-T2H)OB@e zlB_C(TZ<8?|7HjvXnTVn=C%jGvh><#ll``FI5uy5#SiXy zr$W4Bg;A2t<@E^ z_=Y_-WC%?@u2`i~CmX_xtT{Ox4#(yMUf#h2vQ#1kOAd%0nUsmlVvYrjQI@9o{4m+% zB*t+F0Z}8rqxm`-t%@HYfE=rJh{yNcB?3GwHb0vOE;}3!hr^L90>hpfQn|@&O2!%> z8)G?$)Cr%%;cz(Gi%_1Q39j}f!@ESC{v8h_gxvjJg}8V2mh~;m4u`|x*z$>4{4|`K zNDNtjlR;S68!~0?I<>E5QzW)H91e%W5x4khILC5SzYMhjcZZU6b+#YpzH#zA-@QiG z(Z!{KoJC*j1;;cz${9S$dc p4u`|x=x{jkb2uChM+ZZQ{|Bm#?+p$Z@tObt002ovPDHLkV1i(7UMK(n literal 0 HcmV?d00001 diff --git a/web/public/Logo.svg b/web/public/Logo.svg new file mode 100644 index 0000000..571edb1 --- /dev/null +++ b/web/public/Logo.svg @@ -0,0 +1,9 @@ + +WRAP + +Workflow : Routing : Approvals + + + diff --git a/web/public/SplashImage.png b/web/public/SplashImage.png new file mode 100644 index 0000000000000000000000000000000000000000..af851459424c7ad77b7aab2ea15eb9be97b82ca0 GIT binary patch literal 17414 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%0A3b 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

)!-_)P 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≪m+27Xdu|BWMoA|+7 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%0D*7}_+3X;1H#e9n5+C#iWM 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 + + + + + + + diff --git a/web/src/App.vue b/web/src/App.vue new file mode 100644 index 0000000..3327592 --- /dev/null +++ b/web/src/App.vue @@ -0,0 +1,113 @@ + + + diff --git a/web/src/api/api-error.ts b/web/src/api/api-error.ts new file mode 100644 index 0000000..3c80112 --- /dev/null +++ b/web/src/api/api-error.ts @@ -0,0 +1,12 @@ +export class ApiError extends Error { + public readonly name = "ApiError" + + constructor( + message: string, + public readonly status: number + ) { + super(message) + } +} + +export default ApiError diff --git a/web/src/api/base-api.ts b/web/src/api/base-api.ts new file mode 100644 index 0000000..625d8dc --- /dev/null +++ b/web/src/api/base-api.ts @@ -0,0 +1,44 @@ +/** Keep in sync with api/src/controllers/base-controller.ts#ModelOrder */ +export type ModelOrder = + | [string, string] + | [string, string, string] + | [string, string, string, string] + | [string, string, string, string, string] + | [string, string, string, string, string, string] + +export type Policy = { + show: boolean + create: boolean + update: boolean + destroy: boolean +} + +export type WhereOptions = { + [K in Attributes]?: Model[K] | Model[K][] +} + +export type FiltersOptions = Partial + +export type QueryOptions = Partial<{ + where: WhereOptions + filters: FiltersOptions + order: ModelOrder[] + page: number + perPage: number +}> + +// Keep in sync with api/src/controllers/base-controller.ts +export const MAX_PER_PAGE = 1000 + +export type ApiResponseError = { field?: string; text: string } + +export type ApiResponseLegacy = { + data: T + errors: ApiResponseError[] + messages?: string[] +} + +export type ApiResponse = { + errors: ApiResponseError[] + messages?: string[] +} & TPayload diff --git a/web/src/api/current-user-api.ts b/web/src/api/current-user-api.ts new file mode 100644 index 0000000..ce67e1b --- /dev/null +++ b/web/src/api/current-user-api.ts @@ -0,0 +1,23 @@ +import http from "@/api/http-client" + +import { type Policy } from "@/api/base-api" +import { UserRoles, type User } from "@/api/users-api" + +export { UserRoles } + +export type UserAsShow = Pick< + User, + "id" | "email" | "firstName" | "lastName" | "displayName" | "roles" | "createdAt" | "updatedAt" +> + +export const currentUserApi = { + async get(): Promise<{ + user: UserAsShow + policy: Policy + }> { + const { data } = await http.get(`/api/current-user`) + return data + }, +} + +export default currentUserApi diff --git a/web/src/api/http-client.ts b/web/src/api/http-client.ts new file mode 100644 index 0000000..3556ae9 --- /dev/null +++ b/web/src/api/http-client.ts @@ -0,0 +1,46 @@ +import qs from "qs" +import axios from "axios" + +import { API_BASE_URL } from "@/config" +import auth0 from "@/plugins/auth0-plugin" +import ApiError from "@/api/api-error" + +export const httpClient = axios.create({ + baseURL: API_BASE_URL, + headers: { + "Content-Type": "application/json", + }, + paramsSerializer: { + serialize: (params) => { + return qs.stringify(params, { + arrayFormat: "indices", + strictNullHandling: true, + }) + }, + }, +}) + +httpClient.interceptors.request.use(async (config) => { + // Only add the Authorization header to requests that start with "/api" + if (config.url?.startsWith("/api")) { + const accessToken = await auth0.getAccessTokenSilently() + config.headers["Authorization"] = `Bearer ${accessToken}` + } + + return config +}) + +// Any status codes that falls outside the range of 2xx causes this function to trigger +httpClient.interceptors.response.use(null, async (error) => { + if (error?.error === "login_required") { + throw new ApiError("You must be logged in to access this endpoint", 401) + } else if (error?.response?.data?.message) { + throw new ApiError(error.response.data.message, error.response.status) + } else if (error.message) { + throw new ApiError(error.message, error.response?.status || 500) + } else { + throw new ApiError("An unknown error occurred", error.response?.status || 500) + } +}) + +export default httpClient diff --git a/web/src/api/status-api.ts b/web/src/api/status-api.ts new file mode 100644 index 0000000..bced29f --- /dev/null +++ b/web/src/api/status-api.ts @@ -0,0 +1,18 @@ +import http from "@/api/http-client" + +export type Status = { + RELEASE_TAG: string + GIT_COMMIT_HASH: string +} + +export const statusApi = { + /** + * Note: This is a public API route, and not protected by authentication + */ + async get(): Promise { + const { data } = await http.get("/_status") + return data + }, +} + +export default statusApi diff --git a/web/src/api/users-api.ts b/web/src/api/users-api.ts new file mode 100644 index 0000000..960890c --- /dev/null +++ b/web/src/api/users-api.ts @@ -0,0 +1,81 @@ +import http from "@/api/http-client" +import { + type FiltersOptions, + type ModelOrder, + type Policy, + type WhereOptions, +} from "@/api/base-api" + +/** Keep in sync with api/src/models/user.ts */ +export enum UserRoles { + SYSTEM_ADMIN = "system_admin", + USER = "user", +} + +export type User = { + id: number + email: string + firstName: string + lastName: string + displayName: string + roles: UserRoles[] + createdAt: string + updatedAt: string +} + +export type UserAsShow = Omit & {} + +export type UserWhereOptions = WhereOptions + +export type UserFiltersOptions = FiltersOptions<{ + search: string | string[] +}> + +export type UserQueryOptions = { + where?: UserWhereOptions + filters?: UserFiltersOptions + order?: ModelOrder[] + page?: number + perPage?: number +} + +export const usersApi = { + UserRoles, + async list(params: UserQueryOptions = {}): Promise<{ + users: User[] + totalCount: number + }> { + const { data } = await http.get("/api/users", { + params, + }) + return data + }, + async get(userId: number): Promise<{ + user: User + policy: Policy + }> { + const { data } = await http.get(`/api/users/${userId}`) + return data + }, + async create(attributes: Partial): Promise<{ + user: User + }> { + const { data } = await http.post("/api/users", attributes) + return data + }, + async update( + userId: number, + attributes: Partial + ): Promise<{ + user: User + }> { + const { data } = await http.patch(`/api/users/${userId}`, attributes) + return data + }, + async delete(userId: number): Promise { + const { data } = await http.delete(`/api/users/${userId}`) + return data + }, +} + +export default usersApi diff --git a/web/src/assets/app_logo_big.png b/web/src/assets/app_logo_big.png new file mode 100644 index 0000000000000000000000000000000000000000..64d19e5bdb55fa1c4054bfe248cd6d36b380d43a GIT binary patch literal 5133 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 COCY-d literal 0 HcmV?d00001 diff --git a/web/src/assets/app_logo_small.png b/web/src/assets/app_logo_small.png new file mode 100644 index 0000000000000000000000000000000000000000..713f514d4d84d070fdc35d32c8a90d0c852ac88c GIT binary patch literal 2132 zcma)7dpy(q7yr((5h5vNQAtvIu%$*5FSoSJ3Moo%GfOeFv}wj%x+qkrw&l_*OhhjA z%V=0G(@^SBbD3*}@L(8n-EVrH=l|#Rxt?=gug^K}_vgIMNjQadP+70F9smFp^l>{E z003>0-Tf6HvORaXK%IgE(K2Bj!P?0h07~yEE&IyLW0eJxBnsp>Az~ z8bhA@%aqWoXeWE<2o$CPIv8$So+Z;T(010RDP7||mv8Hw-Nu`e65I5GSxKGu-*o7) zyb`w@I`$+7x$%y{<`WINf9{WccIM};0{3&de^5X*^#!Nw)NY(hi`6tpik%}Cxm@1k z)^+=EDI5-g2eRDTokX;i(BzVyqlCGtmKM~^gcLe6s7EqtMa{I}TU+RQ=#>9Fwb*dm zPi8M-kaA;mMV~z-%4Qq3gOh=iU@9FO*BGWHzV3tDUf1M4rz^Jc%mmNzOP3oNFGjrX zz<7TRo>v*|%jdcARO#S^>Y+!`U{!FIoDk`=J(UOjZZ-!xcr+2OpS-e{mlspS#a za!`3-)VGb52m2A=Zg9}HS~H_$bbqcoA5Jw_hy-^KTkr@p3`$INsK5%EmBqAvw?m2F zKk#;MPV}9aw#6Bx3L*(|^IuEA6JVqKi^|RP;(F?i46R3wi4mv+@b)hON5wlsvG1hj zkmUn9Q)F-}KYJvBl2HROL-o3HlsUI0P7)Q~3UA4ehW7w>_cUN%A>T;1ij_;Ol5tw@ z_MCwVNQW|4r2~@w`1!D6|7Uw0QbfS?dP0Nt0rF`PIC7nPFRqHvSepL+3rdBXmje%4 zx9VbYa}!USCr=aBC~_2ktrQ-ydi{PaR>Snyys8_;^QG3U|C9ga%3jS5gKn+&w_eGh z*!78pL)0P`Viw6+6ft1h8=LLUS1zn!%ybVf*f$TZ0~cTi|`@yuoTVc?7TZe z&&SY^NXa~rD&v+(0E@2--H!5Y2$t%;3X6Wzcs(jTe|T7BrO08|5Q5o4at!!h`Qqjq zB%!Of$5wkd;95&Qr|qz_NCpS(GST{cvLLYgEn?jJ%iv-;L0D7tt|t7qZQ9FrA|iE) z#i!Y_RlO(tdf@%1{CXb8w3|xEGS}xrx; zB-qR}j)-vnGnYBtC+xUIh^b4ME{YHQW^dG*)`x2`yjvl#Lx&h}*e~05sN)@vTR{(= zpD0~~CPm=kNT$I^w_RtnVq5Xp>le3HKU|AqOW*!&xtOU~YdTi3L7fO`4~%AWe^xxm zjrYhQjc>D&YC5(!>7Qt-(i>jbB^h*QN0#|ypljod z!n!o~UkuS6DQ_avPfDEo5I!O7YH*r#t^|>S{++zSq8~M1mjvn}b1((bCM<@U?f2GM zVil011q1`U-an7+-MAVgYboA$2|!#2mH}cFNKN9RV zrH_~<&+8G$QD%H+ZpNL*Ri_UoMJjWc;zD#DAKwVjepiZpTz}33@la9OlB`l&&rVKt z*sSjEadOnpR+j-R!$OIMf#59Ague6_)$Q^7$vqbJXWW9M8@kaECk@Mw%4&(mIS_XT z$8f@;=MB}OSCx}#GDBi~gc5ZvDnygXi;>)rFq9ZxKvP|#AdIhU{T(A0qKmo7+R258 ze^6Y-TgAq;;9zMMMpz$wY4?Dr<}yxtmhYGpSQ}q9!nnF&WAEs-lK31h184M~8{W;K ZXb?AY^*&9oCvM-Z$ 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 gsT + + + + + + + diff --git a/web/src/components/common/AppCard.vue b/web/src/components/common/AppCard.vue new file mode 100644 index 0000000..51c3d3e --- /dev/null +++ b/web/src/components/common/AppCard.vue @@ -0,0 +1,46 @@ + + + diff --git a/web/src/components/common/AppLogo.vue b/web/src/components/common/AppLogo.vue new file mode 100644 index 0000000..75426c4 --- /dev/null +++ b/web/src/components/common/AppLogo.vue @@ -0,0 +1,50 @@ + + + + + diff --git a/web/src/components/common/AppSnackbar.vue b/web/src/components/common/AppSnackbar.vue new file mode 100644 index 0000000..49e3112 --- /dev/null +++ b/web/src/components/common/AppSnackbar.vue @@ -0,0 +1,82 @@ + + + diff --git a/web/src/components/common/CollapsibleCard.vue b/web/src/components/common/CollapsibleCard.vue new file mode 100644 index 0000000..a4d7fa9 --- /dev/null +++ b/web/src/components/common/CollapsibleCard.vue @@ -0,0 +1,50 @@ + + + diff --git a/web/src/components/common/ConfirmDialog.vue b/web/src/components/common/ConfirmDialog.vue new file mode 100644 index 0000000..5a0044d --- /dev/null +++ b/web/src/components/common/ConfirmDialog.vue @@ -0,0 +1,77 @@ + + + diff --git a/web/src/components/common/DescriptionElement.vue b/web/src/components/common/DescriptionElement.vue new file mode 100644 index 0000000..65e4f5b --- /dev/null +++ b/web/src/components/common/DescriptionElement.vue @@ -0,0 +1,76 @@ + + + + + diff --git a/web/src/components/common/HeaderActionsCard.vue b/web/src/components/common/HeaderActionsCard.vue new file mode 100644 index 0000000..547a2d0 --- /dev/null +++ b/web/src/components/common/HeaderActionsCard.vue @@ -0,0 +1,73 @@ + + + diff --git a/web/src/components/common/HeaderActionsCardBody.vue b/web/src/components/common/HeaderActionsCardBody.vue new file mode 100644 index 0000000..09e9f75 --- /dev/null +++ b/web/src/components/common/HeaderActionsCardBody.vue @@ -0,0 +1,74 @@ + + + diff --git a/web/src/components/common/HeaderActionsFormCard.vue b/web/src/components/common/HeaderActionsFormCard.vue new file mode 100644 index 0000000..b2ea960 --- /dev/null +++ b/web/src/components/common/HeaderActionsFormCard.vue @@ -0,0 +1,101 @@ + + + diff --git a/web/src/components/common/PageLoader.vue b/web/src/components/common/PageLoader.vue new file mode 100644 index 0000000..fcb2961 --- /dev/null +++ b/web/src/components/common/PageLoader.vue @@ -0,0 +1,17 @@ + + + diff --git a/web/src/components/common/PercentageTextField.vue b/web/src/components/common/PercentageTextField.vue new file mode 100644 index 0000000..47cfb9b --- /dev/null +++ b/web/src/components/common/PercentageTextField.vue @@ -0,0 +1,85 @@ + + + diff --git a/web/src/components/common/ResponsiveDialog.vue b/web/src/components/common/ResponsiveDialog.vue new file mode 100644 index 0000000..b8d5d00 --- /dev/null +++ b/web/src/components/common/ResponsiveDialog.vue @@ -0,0 +1,83 @@ + + + diff --git a/web/src/components/common/StringDateInput.vue b/web/src/components/common/StringDateInput.vue new file mode 100644 index 0000000..178eb8f --- /dev/null +++ b/web/src/components/common/StringDateInput.vue @@ -0,0 +1,70 @@ + + + diff --git a/web/src/components/layout/DefaultAppBar.vue b/web/src/components/layout/DefaultAppBar.vue new file mode 100644 index 0000000..2a9a279 --- /dev/null +++ b/web/src/components/layout/DefaultAppBar.vue @@ -0,0 +1,40 @@ + + + diff --git a/web/src/components/layout/DefaultSideBar.vue b/web/src/components/layout/DefaultSideBar.vue new file mode 100644 index 0000000..100d1cd --- /dev/null +++ b/web/src/components/layout/DefaultSideBar.vue @@ -0,0 +1,70 @@ + + + diff --git a/web/src/components/layout/ExactingBreadcrumbs.vue b/web/src/components/layout/ExactingBreadcrumbs.vue new file mode 100644 index 0000000..53716e3 --- /dev/null +++ b/web/src/components/layout/ExactingBreadcrumbs.vue @@ -0,0 +1,69 @@ + + + + + + + diff --git a/web/src/components/layout/ProfileMenu.vue b/web/src/components/layout/ProfileMenu.vue new file mode 100644 index 0000000..6a0e913 --- /dev/null +++ b/web/src/components/layout/ProfileMenu.vue @@ -0,0 +1,160 @@ + + + diff --git a/web/src/components/layout/SearchMenu.vue b/web/src/components/layout/SearchMenu.vue new file mode 100644 index 0000000..46c2304 --- /dev/null +++ b/web/src/components/layout/SearchMenu.vue @@ -0,0 +1,59 @@ + + + diff --git a/web/src/components/users/UserEditCardForm.vue b/web/src/components/users/UserEditCardForm.vue new file mode 100644 index 0000000..ea12861 --- /dev/null +++ b/web/src/components/users/UserEditCardForm.vue @@ -0,0 +1,196 @@ + + + diff --git a/web/src/components/users/UserProfileCard.vue b/web/src/components/users/UserProfileCard.vue new file mode 100644 index 0000000..247d7d6 --- /dev/null +++ b/web/src/components/users/UserProfileCard.vue @@ -0,0 +1,86 @@ + + + diff --git a/web/src/components/users/UserRoleSelect.vue b/web/src/components/users/UserRoleSelect.vue new file mode 100644 index 0000000..b3e51ff --- /dev/null +++ b/web/src/components/users/UserRoleSelect.vue @@ -0,0 +1,30 @@ + + + diff --git a/web/src/components/users/UsersDataTableServer.vue b/web/src/components/users/UsersDataTableServer.vue new file mode 100644 index 0000000..33741fb --- /dev/null +++ b/web/src/components/users/UsersDataTableServer.vue @@ -0,0 +1,107 @@ + + + + + diff --git a/web/src/config.ts b/web/src/config.ts new file mode 100644 index 0000000..1f98d72 --- /dev/null +++ b/web/src/config.ts @@ -0,0 +1,47 @@ +import { stripTrailingSlash } from "@/utils/strip-trailing-slash" + +export const ENVIRONMENT = import.meta.env.MODE + +const prodConfig = { + domain: "https://dev-7mdjzcgwirhocfwm.ca.auth0.com", + clientId: "TRlKzdNBynpo9tU1RSmnF0p8d3IEam4J", + audience: "alphane-api", + apiBaseUrl: "", + webSocketBaseUrl: "", + applicationName: "ALPHANE", +} + +const devConfig = { + domain: "https://dev-7mdjzcgwirhocfwm.ca.auth0.com", + clientId: "TRlKzdNBynpo9tU1RSmnF0p8d3IEam4J", + audience: "alphane-api", + apiBaseUrl: "http://localhost:3000", + webSocketBaseUrl: "ws://localhost:3000", + applicationName: "ALPHANE", +} + +const localProductionConfig = { + domain: "https://dev-7mdjzcgwirhocfwm.ca.auth0.com", + clientId: "TRlKzdNBynpo9tU1RSmnF0p8d3IEam4J", + audience: "alphane-api", + apiBaseUrl: "http://localhost:8080", + webSocketBaseUrl: "ws://localhost:8080", + applicationName: "ALPHANE (production)", +} + +let config = prodConfig + +if (ENVIRONMENT === "production" && window.location.host === "localhost:8080") { + config = localProductionConfig +} else if (window.location.host === "localhost:8080") { + config = devConfig +} + +export const APPLICATION_NAME = config.applicationName + +export const API_BASE_URL = config.apiBaseUrl +export const WEB_SOCKET_BASE_URL = config.webSocketBaseUrl + +export const AUTH0_DOMAIN = stripTrailingSlash(config.domain) +export const AUTH0_AUDIENCE = config.audience +export const AUTH0_CLIENT_ID = config.clientId diff --git a/web/src/directives/index.ts b/web/src/directives/index.ts new file mode 100644 index 0000000..6e3408c --- /dev/null +++ b/web/src/directives/index.ts @@ -0,0 +1,5 @@ +import { visible } from "./visible" + +export default { + visible, +} diff --git a/web/src/directives/visible.ts b/web/src/directives/visible.ts new file mode 100644 index 0000000..41a1b65 --- /dev/null +++ b/web/src/directives/visible.ts @@ -0,0 +1,27 @@ +import { DirectiveBinding } from "vue" + +/** + * Shows or hides an element using visibility property based on a boolean value. + * + * This makes helps loaders avoid downshift flickering when they trigger. + * + * See https://vuejs.org/guide/reusability/custom-directives.html#function-shorthand + * + * @usage + * ```html + * + * ``` + */ +export function visible(el: HTMLElement, binding: DirectiveBinding) { + if (binding.value) { + el.style.visibility = "visible" + } else { + el.style.visibility = "hidden" + } +} + +export default visible diff --git a/web/src/layouts/AdministrationLayout.vue b/web/src/layouts/AdministrationLayout.vue new file mode 100644 index 0000000..e8789e6 --- /dev/null +++ b/web/src/layouts/AdministrationLayout.vue @@ -0,0 +1,49 @@ + + + diff --git a/web/src/layouts/DefaultLayout.vue b/web/src/layouts/DefaultLayout.vue new file mode 100644 index 0000000..96aea7d --- /dev/null +++ b/web/src/layouts/DefaultLayout.vue @@ -0,0 +1,22 @@ + + + diff --git a/web/src/layouts/LayoutWithBreadcrumbs.vue b/web/src/layouts/LayoutWithBreadcrumbs.vue new file mode 100644 index 0000000..aa81ecd --- /dev/null +++ b/web/src/layouts/LayoutWithBreadcrumbs.vue @@ -0,0 +1,69 @@ + + + diff --git a/web/src/layouts/ProfileLayout.vue b/web/src/layouts/ProfileLayout.vue new file mode 100644 index 0000000..463b357 --- /dev/null +++ b/web/src/layouts/ProfileLayout.vue @@ -0,0 +1,33 @@ + + + + + diff --git a/web/src/layouts/logo/AppLogo.vue b/web/src/layouts/logo/AppLogo.vue new file mode 100644 index 0000000..9985c18 --- /dev/null +++ b/web/src/layouts/logo/AppLogo.vue @@ -0,0 +1,50 @@ + + + + + diff --git a/web/src/locales/en.js b/web/src/locales/en.js new file mode 100644 index 0000000..e146645 --- /dev/null +++ b/web/src/locales/en.js @@ -0,0 +1,8 @@ +export default { + user: { + roles: { + system_admin: "System Admin", + user: "User", + }, + }, +} diff --git a/web/src/main.ts b/web/src/main.ts new file mode 100644 index 0000000..a28f7a1 --- /dev/null +++ b/web/src/main.ts @@ -0,0 +1,25 @@ +import { createApp } from "vue" + +// Plugins +import vuetify from "@/plugins/vuetify-plugin" +import auth0 from "@/plugins/auth0-plugin" +import vueI18nPlugin from "@/plugins/vue-i18n-plugin" + +import "@/scss/style.scss" +import VueScrollTo from "vue-scrollto" +import directives from "@/directives" +import router from "@/router" + +import App from "@/App.vue" + +const app = createApp(App) +app.use(router).use(vuetify).use(auth0).use(vueI18nPlugin) + +app.directive("visible", directives.visible) + +app.mount("#app") + +app.use(VueScrollTo, { + duration: 1000, + easing: "ease", +}) diff --git a/web/src/pages/CallbackPage.vue b/web/src/pages/CallbackPage.vue new file mode 100644 index 0000000..28a099a --- /dev/null +++ b/web/src/pages/CallbackPage.vue @@ -0,0 +1,23 @@ + + + diff --git a/web/src/pages/DashboardPage.vue b/web/src/pages/DashboardPage.vue new file mode 100644 index 0000000..114c46a --- /dev/null +++ b/web/src/pages/DashboardPage.vue @@ -0,0 +1,16 @@ + + + diff --git a/web/src/pages/ProfilePage.vue b/web/src/pages/ProfilePage.vue new file mode 100644 index 0000000..5ee1be1 --- /dev/null +++ b/web/src/pages/ProfilePage.vue @@ -0,0 +1,27 @@ + + + + + diff --git a/web/src/pages/SignInPage.vue b/web/src/pages/SignInPage.vue new file mode 100644 index 0000000..1122518 --- /dev/null +++ b/web/src/pages/SignInPage.vue @@ -0,0 +1,115 @@ + + + diff --git a/web/src/pages/StatusPage.vue b/web/src/pages/StatusPage.vue new file mode 100644 index 0000000..8bf3efb --- /dev/null +++ b/web/src/pages/StatusPage.vue @@ -0,0 +1,93 @@ + + + diff --git a/web/src/pages/administration/AdministrationDashboardPage.vue b/web/src/pages/administration/AdministrationDashboardPage.vue new file mode 100644 index 0000000..9a9dc8e --- /dev/null +++ b/web/src/pages/administration/AdministrationDashboardPage.vue @@ -0,0 +1,118 @@ + + + diff --git a/web/src/pages/administration/SettingsPage.vue b/web/src/pages/administration/SettingsPage.vue new file mode 100644 index 0000000..25f351b --- /dev/null +++ b/web/src/pages/administration/SettingsPage.vue @@ -0,0 +1,14 @@ + + + diff --git a/web/src/pages/administration/UsersPage.vue b/web/src/pages/administration/UsersPage.vue new file mode 100644 index 0000000..7dedbee --- /dev/null +++ b/web/src/pages/administration/UsersPage.vue @@ -0,0 +1,46 @@ + + + diff --git a/web/src/pages/administration/users/UserEditPage.vue b/web/src/pages/administration/users/UserEditPage.vue new file mode 100644 index 0000000..d68a3e3 --- /dev/null +++ b/web/src/pages/administration/users/UserEditPage.vue @@ -0,0 +1,70 @@ + + + + + diff --git a/web/src/pages/administration/users/UserNewPage.vue b/web/src/pages/administration/users/UserNewPage.vue new file mode 100644 index 0000000..3ee6a05 --- /dev/null +++ b/web/src/pages/administration/users/UserNewPage.vue @@ -0,0 +1,353 @@ + + + diff --git a/web/src/pages/errors/ForbiddenPage.vue b/web/src/pages/errors/ForbiddenPage.vue new file mode 100644 index 0000000..a8baa60 --- /dev/null +++ b/web/src/pages/errors/ForbiddenPage.vue @@ -0,0 +1,79 @@ + + + + + diff --git a/web/src/pages/errors/InternalServerErrorPage.vue b/web/src/pages/errors/InternalServerErrorPage.vue new file mode 100644 index 0000000..f0af657 --- /dev/null +++ b/web/src/pages/errors/InternalServerErrorPage.vue @@ -0,0 +1,79 @@ + + + + + diff --git a/web/src/pages/errors/NotFoundPage.vue b/web/src/pages/errors/NotFoundPage.vue new file mode 100644 index 0000000..9ab6e0c --- /dev/null +++ b/web/src/pages/errors/NotFoundPage.vue @@ -0,0 +1,79 @@ + + + + + diff --git a/web/src/pages/errors/UnauthorizedPage.vue b/web/src/pages/errors/UnauthorizedPage.vue new file mode 100644 index 0000000..91ff9de --- /dev/null +++ b/web/src/pages/errors/UnauthorizedPage.vue @@ -0,0 +1,79 @@ + + + + + diff --git a/web/src/pages/profile/ProfileEditPage.vue b/web/src/pages/profile/ProfileEditPage.vue new file mode 100644 index 0000000..f49184a --- /dev/null +++ b/web/src/pages/profile/ProfileEditPage.vue @@ -0,0 +1,46 @@ + + + + + diff --git a/web/src/plugins/auth0-plugin.ts b/web/src/plugins/auth0-plugin.ts new file mode 100644 index 0000000..ca8e12f --- /dev/null +++ b/web/src/plugins/auth0-plugin.ts @@ -0,0 +1,14 @@ +import { createAuth0 } from "@auth0/auth0-vue" + +import { AUTH0_AUDIENCE, AUTH0_CLIENT_ID, AUTH0_DOMAIN, ENVIRONMENT } from "@/config" + +// See https://auth0.github.io/auth0-vue/#md:add-login-to-your-application +export default createAuth0({ + domain: AUTH0_DOMAIN, + clientId: AUTH0_CLIENT_ID, + authorizationParams: { + audience: AUTH0_AUDIENCE, + redirect_uri: `${window.location.origin}/callback`, + }, + cacheLocation: ENVIRONMENT === "development" ? "localstorage" : "memory", +}) diff --git a/web/src/plugins/vue-i18n-plugin.ts b/web/src/plugins/vue-i18n-plugin.ts new file mode 100644 index 0000000..741d0e5 --- /dev/null +++ b/web/src/plugins/vue-i18n-plugin.ts @@ -0,0 +1,13 @@ +import { createI18n } from "vue-i18n" + +// I'd prefer to use yaml, or even json, but I can't get them to import at the moment +// This might be a TypeScript issue, or I might need a yaml plugin. +import en from "@/locales/en.js" + +export default createI18n({ + legacy: false, // support composition api + locale: "en", + messages: { + en, + }, +}) diff --git a/web/src/plugins/vuetify-plugin.ts b/web/src/plugins/vuetify-plugin.ts new file mode 100644 index 0000000..d0c9cee --- /dev/null +++ b/web/src/plugins/vuetify-plugin.ts @@ -0,0 +1,86 @@ +/** + * plugins/vuetify.js + * + * Framework documentation: https://vuetifyjs.com` + */ + +// Styles +import "@mdi/font/css/materialdesignicons.css" +import "vuetify/styles" + +// ComposablesF +import { createVuetify } from "vuetify" +import * as components from "vuetify/components" +import * as directives from "vuetify/directives" +import * as labsComponents from "vuetify/labs/components" + +import { + DARK_BLUE_THEME, + DARK_AQUA_THEME, + DARK_ORANGE_THEME, + DARK_PURPLE_THEME, + DARK_GREEN_THEME, + DARK_CYAN_THEME, +} from "@/theme/DarkTheme" + +// https://vuetifyjs.com/en/introduction/why-vuetify/#feature-guides +export default createVuetify({ + components: { + ...components, + ...labsComponents, + }, + directives, + theme: { + defaultTheme: "DARK_AQUA_THEME", + themes: { + DARK_BLUE_THEME, + DARK_AQUA_THEME, + DARK_ORANGE_THEME, + DARK_PURPLE_THEME, + DARK_GREEN_THEME, + DARK_CYAN_THEME, + }, + }, + defaults: { + VCard: { + rounded: "md", + }, + VTextField: { + variant: "outlined", + density: "comfortable", + color: "primary", + }, + VTextarea: { + variant: "outlined", + density: "comfortable", + color: "primary", + }, + VFileInput: { + variant: "outlined", + density: "comfortable", + color: "primary", + prependIcon: null, + }, + VSelect: { + variant: "outlined", + density: "comfortable", + color: "primary", + }, + VCombobox: { + variant: "outlined", + density: "comfortable", + color: "primary", + }, + VAutocomplete: { + variant: "outlined", + density: "comfortable", + color: "primary", + }, + VListItem: { + minHeight: "45px", + }, + VTooltip: { + location: "top", + }, + }, +}) diff --git a/web/src/router.ts b/web/src/router.ts new file mode 100644 index 0000000..b26128e --- /dev/null +++ b/web/src/router.ts @@ -0,0 +1,152 @@ +import { createRouter, createWebHistory, type RouteRecordRaw } from "vue-router" +import { authGuard } from "@auth0/auth0-vue" + +import { APPLICATION_NAME } from "@/config" +import administrationRoutes from "@/routes/administration-routes" +import { authorizationGuard } from "@/utils/authorization-guards" + +const routes: RouteRecordRaw[] = [ + { + path: "/", + name: "SignInPage", + component: () => import("@/pages/SignInPage.vue"), + meta: { requiresAuth: false }, + }, + { + path: "/callback", + name: "CallbackPage", + component: () => import("@/pages/CallbackPage.vue"), + meta: { requiresAuth: false }, + }, + { + path: "/", + component: () => import("@/layouts/DefaultLayout.vue"), + children: [ + { + path: "", + redirect: "sign-in", + }, + { + name: "DashboardPage", + path: "dashboard", + component: () => import("@/pages/DashboardPage.vue"), + meta: { + title: "Dashboard", + }, + }, + { + path: "", + component: () => import("@/layouts/LayoutWithBreadcrumbs.vue"), + children: [ + { + path: "profile", + component: () => import("@/layouts/ProfileLayout.vue"), + meta: { + title: "Profile", + }, + children: [ + { + path: "", + name: "ProfilePage", + redirect: { name: "profile/ProfileEditPage" }, + }, + ], + }, + + { + path: "profile/edit", + name: "profile/ProfileEditPage", + component: () => import("@/pages/profile/ProfileEditPage.vue"), + meta: { + title: "Edit Profile", + }, + }, + ], + }, + ], + }, + ...administrationRoutes, + { + name: "StatusPage", + path: "/status", + component: () => import("@/pages/StatusPage.vue"), + meta: { + title: "Status", + requiresAuth: false, + }, + }, + { + path: "/errors/unauthorized", + name: "errors/UnauthorizedPage", + component: () => import("@/pages/errors/UnauthorizedPage.vue"), + meta: { + title: "Unauthorized", + requiresAuth: false, + }, + }, + { + path: "/errors/forbidden", + name: "errors/ForbiddenPage", + component: () => import("@/pages/errors/ForbiddenPage.vue"), + meta: { + title: "Forbidden", + requiresAuth: false, + }, + }, + { + path: "/errors/internal-server-error", + name: "errors/InternalServerErrorPage", + component: () => import("@/pages/errors/InternalServerErrorPage.vue"), + meta: { + title: "Internal Server Error", + requiresAuth: false, + }, + }, + { + path: "/errors/not-found", + name: "errors/NotFoundPage", + component: () => import("@/pages/errors/NotFoundPage.vue"), + meta: { + title: "Not Found", + requiresAuth: false, + }, + }, + { + path: "/:pathMatch(.*)*", + redirect: "/errors/not-found", + }, +] + +const router = createRouter({ + history: createWebHistory(), + routes, +}) + +router.onError((error, to) => { + if ( + error.message.includes("Failed to fetch dynamically imported module") || + error.message.includes("Importing a module script failed") + ) { + window.location.href = to.fullPath + } +}) + +router.beforeEach(async (to) => { + if (to.meta && to.meta.title) { + document.title = `${APPLICATION_NAME} - ${to.meta.title}` + } else { + document.title = APPLICATION_NAME + } + + if (to.meta.requiresAuth === false) return true + + const isAuthenticated = await authGuard(to) + if (!isAuthenticated) return false + + const isAuthorized = await authorizationGuard(to) + if (!isAuthorized) return "/errors/forbidden" + + return true +}) + +export default router diff --git a/web/src/routes/administration-routes.ts b/web/src/routes/administration-routes.ts new file mode 100644 index 0000000..2e38182 --- /dev/null +++ b/web/src/routes/administration-routes.ts @@ -0,0 +1,50 @@ +import { RouteRecordRaw } from "vue-router" + +import { isSystemAdmin } from "@/utils/authorization-guards" + +export const administrationRoutes: Readonly = [ + { + path: "/administration", + component: () => import("@/layouts/AdministrationLayout.vue"), + meta: { + guards: [isSystemAdmin], + }, + children: [ + { + path: "", + name: "administration/AdministrationDashboardPage", + component: () => import("@/pages/administration/AdministrationDashboardPage.vue"), + }, + { + path: "users", + name: "administration/UsersPage", + component: () => import("@/pages/administration/UsersPage.vue"), + }, + { + path: "users/new", + name: "administration/users/UserNewPage", + component: () => import("@/pages/administration/users/UserNewPage.vue"), + props: true, + }, + { + path: "users/:userId", + name: "administration/users/UserPage", + component: () => import("@/pages/administration/users/UserEditPage.vue"), + props: true, + }, + { + path: "users/:userId/edit", + name: "administration/users/UserEditPage", + component: () => import("@/pages/administration/users/UserEditPage.vue"), + props: true, + }, + { + path: "settings", + name: "administration/SettingsPage", + component: () => import("@/pages/administration/SettingsPage.vue"), + }, + ], + }, +] + +export default administrationRoutes diff --git a/web/src/scss/_override.scss b/web/src/scss/_override.scss new file mode 100644 index 0000000..c9e294c --- /dev/null +++ b/web/src/scss/_override.scss @@ -0,0 +1,204 @@ +@use "./variables" as *; + +html { + .bg-success { + color: $white !important; + } + + .bg-primary { + color: $white !important; + } + + .bg-secondary { + color: $white !important; + } + + .bg-warning { + color: $white !important; + } + + .bg-secondary-gradient { + background: linear-gradient(287deg, rgb(var(--v-theme-primary)) .54%, #1bcaff 100.84%); + } +} + + + + +.border, +.v-divider { + border-color: rgba(var(--v-border-color)) !important; +} + +.avtar-border { + border: 2px solid rgb(var(--v-theme-surface)) !important; +} + +.subtext { + font-size: $font-size-root; + line-height: 1.75rem; +} + +.v-dialog { + &.dialog-mw { + max-width: 800px; + } +} + +.round-40 { + height: 40px; + width: 40px; +} + +.round-56 { + height: 56px; + width: 56px; +} + +.round-48 { + height: 48px; + width: 48px; +} + +.round-30 { + height: 30px; + width: 30px; +} + +.lh-0 { + line-height: 0 !important; +} + + +.lh-28 { + line-height: 28px !important; +} + +.lh-32 { + line-height: 32px !important; +} + +.space-p-96 { + padding: 96px 0 !important; + +} + +.ps-96 { + padding-inline-start: 96px !important; +} + +.pt-96 { + padding-top: 96px !important; +} + +.end-0 { + inset-inline-end: 0; +} + +.top-0 { + top: 0; +} + +.no-scrollbar { + height: calc(100vh - 350px); +} + +.msg-chat-height { + height: calc(-500px + 100vh); +} + +@media screen and (max-width:991px) { + .overflow-x-reposive { + overflow-x: scroll; + overflow-y: hidden; + } + + .border-m-none { + border: 0 !important + } +} + +@media screen and (max-height:767px) { + .msg-chat-height { + height: calc(-315px + 100vh); + } + +} + +.max-h-600 { + max-height: 600px; + height: calc(100vh - 100px); +} + + +.custom-hover-primary { + .iconify { + color: rgb(255, 255, 255) !important; + + @media screen and (max-width:991px) { + color: rgba(var(--v-theme-textPrimary), 0.8) !important + } + } + + &:hover { + background-color: rgba(var(--v-theme-lightprimary), 0.1); + + .iconify { + @media screen and (max-width:991px) { + color: rgb(var(--v-theme-primary)) !important + } + } + } +} +.custom-hover-primary-white { + .iconify { + color: rgb(255, 255, 255) !important; + + + } + + &:hover { + background-color: rgba(var(--v-theme-lightprimary), 0.1); + + } +} + +.no-icon { + + .v-input__prepend, + .v-input__append { + display: none !important; + } +} + +.bg-white { + background-color: rgb(255, 255, 255) !important; +} + +.v-badge { + &.x-small-badge { + .v-badge__badge { + height: 6px !important; + width: 6px !important; + } + + } +} + +.one-line { + overflow: hidden; + display: -webkit-box; + -webkit-box-orient: vertical; + -webkit-line-clamp: 1; +} + +.two-line { + overflow: hidden; + display: -webkit-box; + -webkit-box-orient: vertical; + -webkit-line-clamp: 2; +} + +.z-1 { + z-index: 1; +} \ No newline at end of file diff --git a/web/src/scss/_variables.scss b/web/src/scss/_variables.scss new file mode 100644 index 0000000..7fe2161 --- /dev/null +++ b/web/src/scss/_variables.scss @@ -0,0 +1,150 @@ +@use "sass:math"; +@use "sass:map"; +@use "sass:meta"; +@use "vuetify/lib/styles/tools/functions" as *; + +// Custom Variables +// colors +$white: #fff !default; + +// cards +$card-title-size: 18px !default; + +$body-font-family: "Overpass", sans-serif !default; +$border-radius-root: 10px; +$btn-font-weight: 400 !default; +$btn-letter-spacing: 0 !default; + +// Global Shadow +$box-shadow: + rgba(145 158 171 / 30%) 0px 0px 2px 0px, + rgba(145 158 171 / 12%) 0px 12px 24px -4px; + +// Global Radius as per breakeven point + +@forward "vuetify/settings" with ( + $color-pack: false !default, + // Global font size and border radius + $font-size-root: 1rem, + $border-radius-root: $border-radius-root, + $body-font-family: $body-font-family, + $heading-font-family: $body-font-family !default, + $button-height: 40px, + // 👉 Typography + $typography: ( + "h1": ( + "size": 2.25rem, + "weight": 600, + "line-height": 2.75rem, + "font-family": inherit, + ), + "h2": ( + "size": 1.875rem, + "weight": 500, + "line-height": 2.25rem, + "font-family": inherit, + ), + "h3": ( + "size": 1.5rem, + "weight": 500, + "line-height": 2rem, + "font-family": inherit, + ), + "h4": ( + "size": 1.3125rem, + "weight": 500, + "line-height": 1.6rem, + "font-family": inherit, + ), + "h5": ( + "size": 1.125rem, + "weight": 500, + "line-height": 1.6rem, + "font-family": inherit, + ), + "h6": ( + "size": 1rem, + "weight": 500, + "line-height": 1.2rem, + "font-family": inherit, + ), + "subtitle-1": ( + "size": 0.875rem, + "weight": 400, + "line-height": 1.1rem, + "font-family": inherit, + ), + "subtitle-2": ( + "size": 0.75rem, + "weight": 400, + "line-height": 1rem, + "font-family": inherit, + ), + "body-1": ( + "size": 0.875rem, + "weight": 400, + "font-family": inherit, + ), + "body-2": ( + "size": 0.75rem, + "weight": 400, + "font-family": inherit, + ), + "button": ( + "size": 0.875rem, + "weight": 500, + "font-family": inherit, + "text-transform": capitalize, + ), + "caption": ( + "size": 0.75rem, + "weight": 400, + "font-family": inherit, + ), + "overline": ( + "size": 0.75rem, + "weight": 500, + "font-family": inherit, + "text-transform": uppercase, + ), + ) + !default, + // 👉 Button + $button-border-radius: $border-radius-root !default, + $button-text-letter-spacing: 0 !default, + $button-text-transform: capitalize, + $button-elevation: ( + "default": 0, + "hover": 4, + "active": 8, + ) + !default, + + // 👉 Tooltip + $tooltip-background-color: #212121 !default, + $tooltip-text-color: rgb(var(--v-theme-on-primary)) !default, + $tooltip-font-size: 0.75rem !default, + $tooltip-border-radius: 4px !default, + $tooltip-padding: 4px 8px !default, + + // 👉 Rounded + $rounded: ( + 0: 0, + "sm": $border-radius-root * 0.5, + null: $border-radius-root, + "md": $border-radius-root * 1, + "lg": $border-radius-root * 2, + "xl": $border-radius-root * 6, + "pill": 9999px, + "circle": 50%, + ), + + // 👉 Card + // $card-color: rgba(var(--v-theme-on-surface), var(--v-medium-emphasis-opacity)) !default, + $card-elevation: 10 !default, + $card-title-line-height: 1.6 !default, + $card-text-padding: 24px !default, + $card-item-padding: 30px 30px 24px !default, + $card-actions-padding: 10px 24px 24px !default, + $card-subtitle-opacity: 1 !default // $card-border-color $border-color-root +); diff --git a/web/src/scss/components/_VAlert.scss b/web/src/scss/components/_VAlert.scss new file mode 100644 index 0000000..8415aed --- /dev/null +++ b/web/src/scss/components/_VAlert.scss @@ -0,0 +1,24 @@ +.single-line-alert { + .v-alert__close, + .v-alert__prepend { + align-self: center !important; + } +} + +@media (max-width: 500px) { + .single-line-alert { + display: flex; + flex-wrap: wrap; + + .v-alert__append { + margin-inline-start: 0px; + } + .v-alert__close { + margin-left: auto; + } + .v-alert__content { + width: 100%; + margin-top: 5px; + } + } +} diff --git a/web/src/scss/components/_VBreadcrumb.scss b/web/src/scss/components/_VBreadcrumb.scss new file mode 100644 index 0000000..81b4ad1 --- /dev/null +++ b/web/src/scss/components/_VBreadcrumb.scss @@ -0,0 +1,9 @@ + +.v-breadcrumbs{ + .v-breadcrumbs-divider{ + padding: 0 0 !important; + } + .v-breadcrumbs-item--link{ + text-decoration: none; + } +} diff --git a/web/src/scss/components/_VButtons.scss b/web/src/scss/components/_VButtons.scss new file mode 100644 index 0000000..dd2183e --- /dev/null +++ b/web/src/scss/components/_VButtons.scss @@ -0,0 +1,22 @@ +.v-btn-group .v-btn { + height: inherit !important; +} + +.v-btn-group { + border-color: rgb(var(--v-theme-borderColor)) !important; +} +.v-btn{ + text-transform: capitalize; + letter-spacing: 0; + border-radius: 30px; + + &.v-btn--variant-elevated{ + box-shadow: none !important; + } + .v-btn--slim{ + padding: 0 15px; + } +} +.v-btn--elevated:hover{ + box-shadow: none; +} diff --git a/web/src/scss/components/_VCard.scss b/web/src/scss/components/_VCard.scss new file mode 100644 index 0000000..3bf5eb6 --- /dev/null +++ b/web/src/scss/components/_VCard.scss @@ -0,0 +1,69 @@ +// Outline Card +.v-card--variant-outlined { + border-color: rgba(var(--v-theme-borderColor)) !important; +} + +.v-card--variant-elevated, +.v-card--variant-flat { + color: rgb(var(--v-theme-textPrimary)); +} + +.card-hover { + transition: box-shadow 300ms cubic-bezier(0.4, 0, 0.2, 1) 0ms; + &:hover { + scale: 1.01; + transition: all 0.1s ease-in 0s; + } +} + +.v-card { + width: 100%; + overflow: visible; + .color-inherits { + color: inherit; + } + .feature-card { + .v-responsive__content { + height: 100%; + } + } + .v-timeline-divider__before,.v-timeline-divider__after { + background: rgba(var(--v-border-color), 1); + } + .v-card-text{ + padding: 24px 24px; + } + .v-card-item{ + padding: 24px 24px; + } +} + +// Theme cards +.cardBordered { + .v-card { + box-shadow: none !important; + border: 1px solid rgb(var(--v-theme-borderColor)); + } +} + +.elevation-o-card{ + .v-card-item{ + padding: 0.625rem 1rem; + } +} + +.card-title{ + font-size: 18px; + font-weight: 500; + color:rgb(var(--v-theme-textPrimary)); +} +.card-subtitle{ + font-size: 14px; + font-weight: 400; + color:rgb(var(--v-theme-textSecondary)); +} +.dark-card-title{ + font-size: 18px; + font-weight: 500; + color:rgb(var(--v-theme-textPrimary)); +} \ No newline at end of file diff --git a/web/src/scss/components/_VCarousel.scss b/web/src/scss/components/_VCarousel.scss new file mode 100644 index 0000000..42306be --- /dev/null +++ b/web/src/scss/components/_VCarousel.scss @@ -0,0 +1,3 @@ +.theme-carousel .v-carousel__progress { + position: absolute; +} diff --git a/web/src/scss/components/_VDatatable.scss b/web/src/scss/components/_VDatatable.scss new file mode 100644 index 0000000..a2c9214 --- /dev/null +++ b/web/src/scss/components/_VDatatable.scss @@ -0,0 +1,3 @@ +.v-pagination__item--is-active .v-btn__overlay { + opacity: 0.15 !important; +} \ No newline at end of file diff --git a/web/src/scss/components/_VDatatables.scss b/web/src/scss/components/_VDatatables.scss new file mode 100644 index 0000000..0ccafd9 --- /dev/null +++ b/web/src/scss/components/_VDatatables.scss @@ -0,0 +1,99 @@ +.v-table { + + &.datatabels { + + &.productlist { + .v-data-table-header__content span { + color: rgb(var(--v-theme-textPrimary)); + } + + .v-toolbar { + .v-input__control { + max-width: 300px; + } + + .v-toolbar__content { + height: auto !important; + } + } + + thead tr th:first-child { + padding-left: 0px !important; + } + + tbody tr td:first-child { + padding-left: 0px !important; + } + tbody tr td{ + padding: 15px; + } + + } + + .v-selection-control--dirty .v-selection-control__input>.v-icon { + color: rgb(var(--v-theme-primary)); + } + } + +} + + +@media screen and (max-width:1368px) { + + .v-table { + + &.datatabels { + + &.productlist { + .v-data-table-header__content span { + color: rgb(var(--v-theme-textPrimary)); + } + + table { + tbody { + tr { + + td { + padding: 14px 5px !important; + + &:first-child { + padding-left: 15px !important; + } + } + } + } + + thead { + tr { + th { + padding: 14px 5px !important; + + &:first-child { + padding-left: 15px !important; + } + } + } + } + } + + + } + } + + } + +} + +.v-pagination { + .v-pagination__list { + .v-pagination__item--is-active { + .v-btn { + .v-btn__overlay { + opacity: 0; + } + + background-color: rgb(var(--v-theme-grey100)) !important; + } + } + } +} \ No newline at end of file diff --git a/web/src/scss/components/_VExpansionpanel.scss b/web/src/scss/components/_VExpansionpanel.scss new file mode 100644 index 0000000..de59dc7 --- /dev/null +++ b/web/src/scss/components/_VExpansionpanel.scss @@ -0,0 +1,6 @@ +.v-expansion-panel-title__overlay{ + background: rgba(var(--v-theme-primary)); +} +.v-expansion-panel:not(:first-child)::after { + border-color: transparent !important; +} \ No newline at end of file diff --git a/web/src/scss/components/_VField.scss b/web/src/scss/components/_VField.scss new file mode 100644 index 0000000..a3dad00 --- /dev/null +++ b/web/src/scss/components/_VField.scss @@ -0,0 +1,29 @@ +@use "../variables" as *; + +.v-field--variant-outlined .v-field__outline__start.v-locale--is-ltr, +.v-locale--is-ltr .v-field--variant-outlined .v-field__outline__start { + border-radius: $border-radius-root 0 0 $border-radius-root; +} + +.v-field--variant-outlined .v-field__outline__end.v-locale--is-ltr, +.v-locale--is-ltr .v-field--variant-outlined .v-field__outline__end { + border-radius: 0 $border-radius-root $border-radius-root 0; +} + +.v-field { + font-size: 14px; + color: rgba(var(--v-theme-textPrimary)); +} + +// select outlined +.v-field--variant-outlined .v-field__outline__start, +.v-field--variant-outlined .v-field__outline__notch::before, +.v-field--variant-outlined .v-field__outline__notch::after, +.v-field--variant-outlined .v-field__outline__end { + opacity: 1; +} + + +.v-field--active .v-label.v-field-label{ + color: rgb(var(--v-theme-textPrimary)); +} \ No newline at end of file diff --git a/web/src/scss/components/_VInput.scss b/web/src/scss/components/_VInput.scss new file mode 100644 index 0000000..77ad91a --- /dev/null +++ b/web/src/scss/components/_VInput.scss @@ -0,0 +1,35 @@ +// variant +.v-input--density-default, +.v-field--variant-solo, +.v-field--variant-filled { + --v-input-control-height: 51px; + --v-input-padding-top: 14px; +} + +// comfortable +.v-input--density-comfortable { + --v-input-control-height: 44px; +} + +// compact +.v-input--density-compact { + --v-input-padding-top: 10px; +} +.v-label { + font-size: 14px; + opacity: 0.7; + font-weight: 500 !important; +} +.v-switch .v-label, +.v-checkbox .v-label { + opacity: 1; +} + +.v-text-field__suffix { + opacity: 1; + padding-left: 20px; +} + +.shadow-none .v-field--variant-solo { + box-shadow: none !important; +} diff --git a/web/src/scss/components/_VLabs.scss b/web/src/scss/components/_VLabs.scss new file mode 100644 index 0000000..633d421 --- /dev/null +++ b/web/src/scss/components/_VLabs.scss @@ -0,0 +1,18 @@ +.v-time-picker-clock{ + background: rgb(var(--v-theme-grey100)) ; +} +.v-time-picker-controls__ampm__btn.v-btn.v-btn--density-default{ + border: 0 !important; +} +.v-stepper-header,.v-stepper.v-sheet{ + box-shadow: none !important; +} + +.v-time-picker-controls__time__btn.v-btn--density-default.v-btn { + width: 55px !important; + height: 55px !important; + font-size: 30px; +} +.v-time-picker-controls__time__separator { + font-size: 36px !important; +} \ No newline at end of file diff --git a/web/src/scss/components/_VList.scss b/web/src/scss/components/_VList.scss new file mode 100644 index 0000000..1f88ca7 --- /dev/null +++ b/web/src/scss/components/_VList.scss @@ -0,0 +1,34 @@ +.v-list.theme-list { + .v-list-item:hover > .v-list-item__overlay { + opacity: 1; + z-index: 1; + } + .v-list-item--variant-text { + .v-list-item__overlay { + background: rgb(var(--v-theme-hoverColor)); + } + } + + .v-list-item__prepend, + .v-list-item__content { + z-index: 2; + } + + .v-list-item__overlay { + background-color: rgb(var(--v-theme-hoverColor)); + } + .v-list-item.v-list-item--active{ + .v-list-item__overlay{ + opacity: 1; + } + } + + .mail-items{ + min-height: 40px !important; + margin-bottom: 5px !important; + } +} + +.v-list-item-title{ + font-size: 14px; +} diff --git a/web/src/scss/components/_VNavigationDrawer.scss b/web/src/scss/components/_VNavigationDrawer.scss new file mode 100644 index 0000000..9994ae9 --- /dev/null +++ b/web/src/scss/components/_VNavigationDrawer.scss @@ -0,0 +1,3 @@ +.v-navigation-drawer__scrim.fade-transition-leave-to { + display: none; +} diff --git a/web/src/scss/components/_VSelectionControl.scss b/web/src/scss/components/_VSelectionControl.scss new file mode 100644 index 0000000..5c080a9 --- /dev/null +++ b/web/src/scss/components/_VSelectionControl.scss @@ -0,0 +1,6 @@ +// For checkbox & radios +.v-selection-control__input > .v-icon.mdi-checkbox-blank-outline, +.v-selection-control__input > .v-icon.mdi-radiobox-blank { + color: rgb(var(--v-theme-inputBorder)); + opacity: 1; +} diff --git a/web/src/scss/components/_VShadow.scss b/web/src/scss/components/_VShadow.scss new file mode 100644 index 0000000..e834869 --- /dev/null +++ b/web/src/scss/components/_VShadow.scss @@ -0,0 +1,33 @@ +@use "../variables" as *; + +.elevation-9 { + box-shadow: rgb(0 0 0 / 5%) 0px 9px 17.5px !important; +} + +.elevation-10 { + box-shadow: $box-shadow !important; +} +.elevation-1 { + box-shadow:0px 12px 30px -2px rgba(58,75,116,0.14) !important +} +.elevation-2 { + box-shadow:0px 24px 24px -12px rgba(0, 0, 0, .05) !important +} +.elevation-3 { + box-shadow: rgba(145,158,171,0.2) 0px 0px 2px 0px, rgba(145,158,171,0.12) 0px 12px 24px -4px !important; +} +.elevation-4{ + box-shadow: 0px 12px 12px -6px rgba(0,0,0,0.15) !important; +} +.elevation-5 +{ + box-shadow: 1px 0 7px rgba(0, 0, 0, .05)!important; +} + +.primary-shadow { + box-shadow: rgba(var(--v-theme-primary), 0.30) 0px 12px 14px 0px; + &:hover { + box-shadow: none; + } +} + diff --git a/web/src/scss/components/_VStepper.scss b/web/src/scss/components/_VStepper.scss new file mode 100644 index 0000000..06e5f17 --- /dev/null +++ b/web/src/scss/components/_VStepper.scss @@ -0,0 +1,8 @@ +.v-stepper-item--selected .v-stepper-item__avatar.v-avatar, .v-stepper-item--complete .v-stepper-item__avatar.v-avatar { + background: rgb(var(--v-theme-primary)) !important; +} + +.v-stepper-item__avatar.v-avatar { + background: rgba(var(--v-theme-primary), var(--v-medium-emphasis-opacity)) !important; + color: rgb(var(--v-theme-on-primary)) !important; +} \ No newline at end of file diff --git a/web/src/scss/components/_VSwitch.scss b/web/src/scss/components/_VSwitch.scss new file mode 100644 index 0000000..ce58d9b --- /dev/null +++ b/web/src/scss/components/_VSwitch.scss @@ -0,0 +1,48 @@ +.v-selection-control.v-selection-control--density-default { + .v-switch__track, + .v-switch__thumb { + background-color: rgb(var(--v-theme-grey200)); + } + &.v-selection-control--dirty { + .v-selection-control__wrapper.text-primary { + .v-switch__track { + background-color: rgba(var(--v-theme-primary), 0.6); + } + .v-switch__thumb { + background-color: rgb(var(--v-theme-primary)); + } + } + .v-selection-control__wrapper.text-secondary { + .v-switch__track { + background-color: rgba(var(--v-theme-secondary), 0.6); + } + .v-switch__thumb { + background-color: rgb(var(--v-theme-secondary)); + } + } + .v-selection-control__wrapper.text-warning { + .v-switch__track { + background-color: rgba(var(--v-theme-warning), 0.6); + } + .v-switch__thumb { + background-color: rgb(var(--v-theme-warning)); + } + } + .v-selection-control__wrapper.text-error { + .v-switch__track { + background-color: rgba(var(--v-theme-error), 0.6); + } + .v-switch__thumb { + background-color: rgb(var(--v-theme-error)); + } + } + .v-selection-control__wrapper.text-success { + .v-switch__track { + background-color: rgba(var(--v-theme-success), 0.6); + } + .v-switch__thumb { + background-color: rgb(var(--v-theme-success)); + } + } + } +} diff --git a/web/src/scss/components/_VTable.scss b/web/src/scss/components/_VTable.scss new file mode 100644 index 0000000..61a5c0b --- /dev/null +++ b/web/src/scss/components/_VTable.scss @@ -0,0 +1,99 @@ +.v-table .v-table__wrapper > table > tbody > tr:not(:last-child) > td, +.v-table .v-table__wrapper > table > tbody > tr:not(:last-child) > th, +.v-table .v-table__wrapper > table > thead > tr:last-child > th { + border-bottom: thin solid rgba(var(--v-border-color)) !important; +} + +.v-data-table{ + th.v-data-table__th{ + font-size:16px; + color: rgba(var(--v-theme-on-surface), var(--v-medium-emphasis-opacity)); + } + td.v-data-table__td{ + font-size: 14px; + text-wrap: nowrap; + } + .v-data-table-footer{ + padding: 15px 8px; + } + .v-data-table-header__sort-badge{ + background-color:rgb(var(--v-theme-borderColor)) !important; + } + .tdhead{ + font-size:16px; + } +} +@media screen and (max-width:767px) { + .v-data-table-footer{ + justify-content: center; + } +} + +.v-table { + + + &.ticket-table { + + table { + thead { + th { + font-weight: 600 !important; + } + } + + tbody { + tr { + + td { + padding: 16px 16px !important; + } + } + } + } + + } + + &.invoice-table { + .v-table__wrapper { + table { + thead { + th { + font-weight: 600 !important; + padding: 0px 24px !important; + + &:first-child { + padding-left: 0 !important; + } + + &:last-child { + padding-right: 0 !important; + } + + } + } + + tbody { + tr { + + td { + padding: 8px 24px !important; + + &:first-child { + padding-left: 0 !important; + } + + &:last-child { + padding-right: 0 !important; + } + } + } + } + } + } + + + } + + + +} \ No newline at end of file diff --git a/web/src/scss/components/_VTabs.scss b/web/src/scss/components/_VTabs.scss new file mode 100644 index 0000000..9932645 --- /dev/null +++ b/web/src/scss/components/_VTabs.scss @@ -0,0 +1,14 @@ +@use "../variables" as *; + +.theme-tab { + &.v-tabs { + .v-tab { + border-radius: $border-radius-root !important; + min-width: auto !important; + &.v-slide-group-item--active { + background: rgb(var(--v-theme-primary)); + + } + } + } +} \ No newline at end of file diff --git a/web/src/scss/components/_VTextField.scss b/web/src/scss/components/_VTextField.scss new file mode 100644 index 0000000..bbc52a7 --- /dev/null +++ b/web/src/scss/components/_VTextField.scss @@ -0,0 +1,13 @@ +.v-text-field input { + font-size: 0.875rem; +} +.v-field__outline { + color: rgb(var(--v-theme-inputBorder)); + --v-field-border-opacity: 1 !important; +} +.input { + .v-field--variant-outlined { + background-color: rgba(0, 0, 0, 0.025); + } +} + diff --git a/web/src/scss/components/_VTextarea.scss b/web/src/scss/components/_VTextarea.scss new file mode 100644 index 0000000..b611c41 --- /dev/null +++ b/web/src/scss/components/_VTextarea.scss @@ -0,0 +1,7 @@ +.v-textarea input { + font-size: 0.875rem; + font-weight: 500; + &::placeholder { + color: rgba(0, 0, 0, 0.38); + } +} diff --git a/web/src/scss/front/_general.scss b/web/src/scss/front/_general.scss new file mode 100644 index 0000000..46d795b --- /dev/null +++ b/web/src/scss/front/_general.scss @@ -0,0 +1,597 @@ +@use "../variables" as *; + +@keyframes slideup { + 0% { + transform: translate3d(0, 0, 0); + } + + 100% { + transform: translate3d(0px, -100%, 0px); + } +} + +.animateDown { + animation: 35s linear 0s infinite normal none running slideDown; +} + +@keyframes slideDown { + 0% { + transform: translate3d(0, -100%, 0); + } + + 100% { + transform: translate3d(0px, 0, 0px); + } +} + +// OfferBar +.offerbar { + position: relative; + top: 0; + width: 100%; + z-index: 999; + + .white-btn { + background-color: rgba(var(--v-theme-surface), 0.15); + font-weight: 700; + height: 25px; + } + + + + &:before { + background-repeat: no-repeat; + content: ''; + position: absolute; + background-image: url('@/assets/images/front-pages/background/left-shape.png'); + bottom: 0; + height: 40px; + left: 0; + width: 325px; + } + + &:after { + background-repeat: no-repeat; + content: ''; + position: absolute; + background-image: url('@/assets/images/front-pages/background/right-shape.png'); + bottom: 0; + right: 17%; + width: 325px; + top: 0; + background-size: contain; + } +} + +// +// frameworks +// +.slider-group { + animation: slide 45s linear infinite; +} + +.marquee1-group { + animation: marquee 45s linear infinite; +} + +.marquee2-group { + animation: marquee2 45s linear infinite; +} + + +@keyframes slide { + 0% { + transform: translate3d(0, 0, 0); + } + + 100% { + transform: translate3d(-100%, 0, 0); + } +} + +@keyframes marquee { + 0% { + transform: translate3d(0, 0, 0); + } + + 100% { + transform: translate3d(-2086px, 0, 0); + } +} + +@keyframes marquee2 { + 0% { + transform: translate3d(-2086px, 0, 0) + } + + 100% { + transform: translate3d(0, 0, 0) + } +} + +.front-wraper { + overflow: hidden; + + .underline-link { + text-underline-offset: 4px; + } + + .underline-link-6 { + text-underline-offset: 6px; + text-decoration-thickness: 2px; + } + + .main-banner { + min-width: 1300px; + overflow: hidden; + max-height: 700px; + height: calc(100vh - 100px); + + img { + max-width: 100%; + height: auto; + + } + } + + .team { + &:hover { + .intro { + opacity: 1; + } + } + + .intro { + opacity: 0; + bottom: 16px; + inset-inline-start: .75rem; + inset-inline-end: .75rem; + transition: 0.5s; + } + } + + // Revenue Products + .feature-tabs { + .v-slide-group__content { + gap: 16px; + padding-bottom: 56px; + } + + + + .v-btn { + background-color: rgba(var(--v-theme-surface)); + padding: 16px 24px; + border-radius: 12px !important; + font-size: 16px; + box-shadow: 0px 24px 24px -12px rgba(0, 0, 0, .05); + } + + .v-tab--selected { + background-color: rgba(var(--v-theme-primary)); + box-shadow: 0px 24px 24px -12px rgba(99, 91, 255, .15); + + .v-btn__content { + color: #fff; + + .v-tab__slider { + display: none; + } + } + } + } + + .v-container { + &.max-width-1218 { + max-width: 1218px !important; + } + + } + + .v-container { + &.max-width-800 { + max-width: 800px !important; + } + + &.max-width-1000 { + max-width: 1000px !important; + } + } + + .max-w-600 { + max-width: 600px !important; + } + + .template { + .left-widget { + position: absolute; + top: 96px; + inset-inline-start: -40px; + max-height: 400px; + width: auto; + } + + .right-widget { + position: absolute; + top: 96px; + inset-inline-end: -40px; + max-height: 400px; + width: auto; + } + } + + + .feature-tabs { + .v-tab__slider { + top: 0; + bottom: unset; + } + + &.v-tabs--density-default { + --v-tabs-height: auto; + } + } + + .feature-tabs-expansion { + + .v-expansion-panel-text__wrapper { + padding: 0px 0px 16px; + } + + .v-expansion-panel-title { + padding: 16px 0px; + } + + .v-expansion-panel { + background-color: transparent !important; + } + + .v-expansion-panel--active:not(:first-child), + .v-expansion-panel--active+.v-expansion-panel { + margin-top: 0; + } + } + + .leader-slider { + .carousel__slide { + padding: 0 15px; + } + + .carousel__viewport { + margin: 0 -15px; + padding-bottom: 30px; + } + + .carousel__prev, + .carousel__next { + top: -85px; + width: 100%; + justify-content: end; + margin: 0; + transform: none; + display: flex; + justify-content: center + } + + .carousel__next { + height: 48px; + width: 48px; + border-radius: 50%; + background: rgb(var(--v-theme-lightprimary)); + + } + + .carousel__prev { + height: 48px; + width: 48px; + border-radius: 50%; + background: rgb(var(--v-theme-lightprimary)); + right: 65px; + left: unset; + } + } + + .our-template { + .carousel__slide { + padding: 0 15px 40px; + } + + .carousel__viewport { + margin: 0 -106px; + } + } + + .testimonials { + + .carousel__prev, + .carousel__next { + width: 100%; + justify-content: end; + margin: 0; + transform: translateY(75px); + display: flex; + justify-content: center; + bottom: 0; + } + + .carousel__next { + height: 32px; + width: 32px; + border-radius: 50%; + background: rgb(var(--v-theme-background)); + left: -60%; + } + + .carousel__prev { + height: 32px; + width: 32px; + border-radius: 50%; + background: rgb(var(--v-theme-background)); + right: 65px; + left: -74%; + } + + .carousel { + padding-bottom: 25px; + } + + .slide-counter { + position: relative; + bottom: -4px; + left: 50px; + z-index: 2; + font-size: 15px; + opacity: 0.7; + } + } + + .social-icon { + svg { + path { + fill: rgb(255, 255, 255); + + &:hover { + fill: rgb(var(--v-theme-primary)); + } + } + } + } + + .package { + .v-list-item { + min-height: 35px !important; + } + } + + .lp-faq { + .v-expansion-panel-title__icon { + .v-icon { + font-size: 20px; + opacity: 0.5 + } + } + + .v-expansion-panels:not(.v-expansion-panels--variant-accordion)> :first-child:not(:last-child):not(.v-expansion-panel--active):not(.v-expansion-panel--before-active) { + border-bottom-left-radius: 8px !important; + border-bottom-right-radius: 8px !important; + } + + .v-expansion-panels:not(.v-expansion-panels--variant-accordion)> :not(:first-child):not(:last-child):not(.v-expansion-panel--active):not(.v-expansion-panel--after-active) { + border-top-left-radius: 8px !important; + border-top-right-radius: 8px !important; + } + + .v-expansion-panels:not(.v-expansion-panels--variant-accordion)> :not(:first-child):not(:last-child):not(.v-expansion-panel--active):not(.v-expansion-panel--before-active) { + border-bottom-left-radius: 8px !important; + border-bottom-right-radius: 8px !important; + } + + .v-expansion-panel--active:not(:first-child), + .v-expansion-panel--active+.v-expansion-panel { + margin-top: 0px !important; + } + } + + + .animted-img { + position: absolute; + z-index: 9; + top: 0%; + animation: mover 5s infinite alternate; + } + + .animted-img-2 { + position: absolute; + z-index: 9; + top: -35px; + inset-inline-end: 15px; + animation: mover 5s infinite alternate; + } + + @keyframes mover { + 0% { + transform: translateY(0); + } + + 100% { + transform: translateY(-10px); + } + } + + .carousel__pagination { + .carousel__pagination-button { + padding: 6px; + + &::after { + height: 8px; + width: 8px; + border-radius: 50%; + background-color: transparent; + background-color: rgb(var(--v-theme-textPrimary)); + opacity: 0.25; + } + + &:hover { + &::after { + background-color: #000; + opacity: 1; + } + } + } + + .carousel__pagination-button--active { + &::after { + background-color: #000; + opacity: 1; + } + } + } + + .carousel { + z-index: 2; + } +} + + + +.v-btn--size-default { + &.nav-links { + font-size: $font-size-root !important; + + .v-btn__overlay { + display: none; + } + + &:hover { + color: rgb(var(--v-theme-primary)) !important; + } + } +} + + + +.light-primary { + background-color: rgb(var(--v-theme-primary), 0.1); +} + +.announce-close { + position: absolute; + right: 15px; + +} + +.text-align-start{ + text-align: start; +} + +@media screen and (max-width:1199px) { + .ps-96 { + padding-inline-start: 60px !important; + } + + .space-p-96 { + padding: 55px 0 !important; + } + + .pt-96 { + padding-top: 55px !important; + } + + .offerbar { + &:after { + background-image: none; + } + } + + .offerbar:after, + .offerbar:before { + display: none; + } + +} + +@media screen and (max-width:1024px) { + .front-wraper .testimonials .slide-counter { + left: 67px; + } + + .space-p-96 { + padding: 40px 0 !important; + } + + .pt-96 { + padding-top: 40px !important; + } + + .front-wraper .bg-collection { + background-image: none; + } + + + + .front-wraper .our-template .carousel__viewport { + margin: 0 0px; + } + + .ps-96 { + padding-inline-start: 20px !important; + padding-inline-end: 20px !important; + } + +} + +@media screen and (max-width:991px) { + .text-align-start{ + text-align: center; + } +} + +@media screen and (max-width:767px) { + .technology { + .round-54 { + height: 45px; + width: 45px; + + img { + height: 22px; + } + } + } + + .front-wraper { + .display-2 { + font-size: 32px; + line-height: normal; + } + + .display-1 { + font-size: 32px; + line-height: normal; + } + } + + .front-wraper .leader-slider .carousel__viewport { + margin: 0 0px; + } + + .announce-close { + bottom: 8px; + } + + .text-48 { + font-size: 30px !important; + line-height: 40px !important; + } + + .text-56 { + font-size: 35px !important; + line-height: 40px !important; + } + + .team { + .intro { + opacity: 1 !important; + } + } + +} \ No newline at end of file diff --git a/web/src/scss/front/_header.scss b/web/src/scss/front/_header.scss new file mode 100644 index 0000000..0952c88 --- /dev/null +++ b/web/src/scss/front/_header.scss @@ -0,0 +1,104 @@ +@use "../variables" as *; + +.front-lp-header { + + .v-toolbar{ + background: rgb(var(--v-theme-surface)); + } + + &.v-app-bar .v-toolbar__content { + padding: 0; + + } + + .v-toolbar__content { + background: transparent !important; + box-shadow: none !important; + } + + &.v-toolbar { + background: transparent !important; + top: 0 !important; + } + + .v-toolbar { + background: transparent !important; + } + + &.sticky-header { + position: fixed !important; + top: 0 !important; + transition: 0.5s; + background-color: rgba(var(--v-theme-surface)) !important; + box-shadow: 0 4px 29px -11px #3a4b7424 !important; + + } + +} +// +// mega menu +// +.white-btn{ + background-color: #769CFF; +} +.front_wrapper { + + &.v-menu .v-overlay__content { + margin: 0 auto; + left: 0 !important; + right: 0; + } + .megamenu { + &::before { + content: ''; + position: absolute; + top: 0px; + left: 0px; + width: 100%; + height: 96%; + background-color: rgba(55, 114, 255, 0.2); + border-radius: 7px; + opacity: 0; + } + .v-btn { + top: 50%; + transform: translateY(-50%); + z-index: 1; + left: 0; + right: 0; + min-width: 100px; + opacity: 0; + font-size: 13px; + } + &:hover { + &::before, + .v-btn { + opacity: 1; + } + } + } +} +.lp-drawer { + &.v-navigation-drawer { + top: 0 !important; + height: 100% !important; + z-index: 1007 !important; + } +} + +.lp-mobile-sidebar { + .v-list { + .v-list-item__content { + overflow: inherit; + } + } + .v-list-group__items .v-list-item { + padding-inline-start: 25px !important; + } +} + +.v-btn--size-default { + &.nav-links { + font-size: $font-size-root !important; + } +} \ No newline at end of file diff --git a/web/src/scss/layout/_container.scss b/web/src/scss/layout/_container.scss new file mode 100644 index 0000000..d9fc39a --- /dev/null +++ b/web/src/scss/layout/_container.scss @@ -0,0 +1,40 @@ +html { + overflow-y: auto; +} +.v-main{ + background:rgb(var(--v-theme-background)) !important; ; +} +@media (max-width: 1279px) { + .v-main { + margin: 0 10px; + } +} + +.cursor-pointer { + cursor: pointer; +} + +.page-wrapper { + min-height: calc(100vh - 100px); + padding: 24px; + // border-radius: $border-radius-root; + @media screen and (max-width: 767px) { + padding: 20px 10px; + } +} + +.maxWidth { + max-width: 1200px; + margin: 0 auto; +} + +.fixed-width { + max-width: 1300px; +} + +.right-pos-img { + position: absolute; + right: 0; + top: 0; + height: 100%; +} diff --git a/web/src/scss/layout/_customizer.scss b/web/src/scss/layout/_customizer.scss new file mode 100644 index 0000000..1e3b9af --- /dev/null +++ b/web/src/scss/layout/_customizer.scss @@ -0,0 +1,93 @@ +.v-btn.customizer-btn { + position: fixed; + bottom: 30px; + right: 30px; + border-radius: 50%; + // .icon-tabler-settings { + // animation: progress-circular-rotate 1.4s linear infinite; + // transform-origin: center center; + // transition: all 0.2s ease-in-out; + // } +} + +.btn-group-custom { + &.v-btn-group { + height: 66px !important; + overflow: unset !important; + .v-btn { + height: 66px !important; + padding: 0 20px; + border: 1px solid rgb(var(--v-theme-borderColor), 0.7) !important; + transition: all 0.1s ease-in 0s; + &:hover { + transform: scale(1.05); + } + &.text-primary { + .v-btn__overlay { + background: transparent !important; + } + .icon { + color: rgb(var(--v-theme-primary)) !important; + fill: rgb(var(--v-theme-primary), 0.2); + } + color: rgb(var(--v-theme-primary)) !important; + } + } + } +} + +.hover-btns { + transition: all 0.1s ease-in 0s; + &:hover { + transform: scale(1.05); + } +} +// all theme colors +.v-avatar.themeBlue, +.v-avatar.themeDarkBlue { + background: #1e88e5; +} +.v-avatar.themeAqua, +.v-avatar.themeDarkAqua { + background: #0074ba; +} + +.v-avatar.themePurple, +.v-avatar.themeDarkPurple { + background: #763ebd; +} +.v-avatar.themeGreen, +.v-avatar.themeDarkGreen { + background: #0a7ea4; +} + +.v-avatar.themeCyan, +.v-avatar.themeDarkCyan { + background: #01c0c8; +} + +.v-avatar.themeOrange, +.v-avatar.themeDarkOrange { + background: #fa896b; +} + + +.DARK_BLUE_THEME, .DARK_AQUA_THEME, .DARK_ORANGE_THEME, .DARK_PURPLE_THEME, .DARK_GREEN_THEME, .DARK_CYAN_THEME { + .togglethemeBlue { + display: block !important; + } + + .togglethemeDarkBlue { + display: none !important; + } +} + +.BLUE_THEME, .AQUA_THEME, .ORANGE_THEME, .PURPLE_THEME, .GREEN_THEME, .CYAN_THEME { + .togglethemeDarkBlue { + display: block !important; + } + + .togglethemeBlue { + display: none !important; + } +} \ No newline at end of file diff --git a/web/src/scss/layout/_dark.scss b/web/src/scss/layout/_dark.scss new file mode 100644 index 0000000..feb2a94 --- /dev/null +++ b/web/src/scss/layout/_dark.scss @@ -0,0 +1,81 @@ +// theme : dark +div[class*='v-theme--DARK_'] { + .smallCap { + color: rgb(var(--v-theme-textSecondary)); + } + + .elevation-10 { + box-shadow: rgb(145 158 171 / 30%) 0px 0px 2px 0px, rgb(145 158 171 / 2%) 0px 12px 24px -4px !important; + } + .v-field__outline{ + --v-field-border-opacity: 0.38 !important; + } + + .front-wraper{ + .bg-background{ + background-color: rgb(var(--v-theme-hoverColor)) !important; + } + + .front-dark{ + &.bg-textPrimary{ + background-color: rgb(var(--v-theme-surface)) !important; + } + } + .bg-textPrimary{ + background-color: rgb(var(--v-theme-textSecondary)) !important; + } + } + + + #vector-map .dxm-layers path { + fill: #7C8FAC !important; + } + + .svgMap-map-wrapper { + .svgMap-country { + stroke: #878585; + fill: #1A2537 !important; + + &#svgMap-map-country-IN { + fill: rgb(var(--v-theme-secondary)) !important; + } + + &#svgMap-map-country-AF { + fill: rgb(var(--v-theme-purple)) !important; + } + + &#svgMap-map-country-US { + fill: rgb(var(--v-theme-primary)) !important; + } + } + + .svgMap-map-controls-zoom { + background: #c9d6de !important; + } + .svgMap-control-button{ + background-color: rgb(var(--v-theme-textSecondary)) !important; + } + + } + .dark-card-title{ + color:rgb(var(--v-theme-surface)); + } + + .fc{ + .fc-button-primary:not(:disabled).fc-button-active { + background-color: rgb(var(--v-theme-grey100)); + } + .fc-button-group { + >.fc-button { + &:hover,&:focus{ + background-color: rgba(var(--v-theme-grey100)); + color: #fff; + .fc-icon{ + color: #fff; + } + } + } + } + } + +} diff --git a/web/src/scss/layout/_horizontal.scss b/web/src/scss/layout/_horizontal.scss new file mode 100644 index 0000000..87273e0 --- /dev/null +++ b/web/src/scss/layout/_horizontal.scss @@ -0,0 +1,231 @@ +@use "../variables" as *; + +.horizontalLayout { + .v-main { + margin: 0 16px !important; + + @media screen and (max-width: 767px) { + margin: 0 10px !important; + } + } +} + +.horizontal-header { + &.v-app-bar .v-toolbar__content { + padding: 0; + display: flex; + justify-content: space-between; + } + + .maxWidth { + @media screen and (max-width: 1199px) { + padding: 0 8px !important; + } + } + +} + +.ddMenu { + &.ddLevel-1 { + .navItem { + .navItemLink { + .dot { + height: 6px; + width: 6px; + background-color: rgb(var(--v-theme-textSecondary)); + border-radius: 50%; + margin-inline-end: 8px !important; + } + } + + &:hover { + .dot { + background-color: rgb(var(--v-theme-secondary)); + } + } + } + } + + &.ddLevel-2 { + .navItem { + .navItemLink { + .dot { + height: 6px; + width: 6px; + background-color: rgb(var(--v-theme-textSecondary)); + border-radius: 50%; + margin-inline-end: 8px !important; + } + } + + &:hover { + .dot { + background-color: rgb(var(--v-theme-secondary)); + } + } + } + } +} + + +.horizontalMenu { + .v-toolbar__content { + max-width: 1270px; + margin: 0 auto; + } + + .navItem:has(.ddMenu.ddLevel-1 li a.router-link-active) { + background-color: rgb(var(--v-theme-secondary)) !important; + border-radius: 9999px; + + .navcollapse { + color: rgba(255, 255, 255); + } + } + +} + +.mobile-menu { + .v-navigation-drawer { + margin-top: -70px !important; + height: 100vh !important; + z-index: 2000 !important; + } +} + +@media (min-width: 960px) { + .horizontalMenu { + margin-top: 65px; + margin-bottom: -70px; + + .maxWidth { + .horizontal-navbar { + max-width: 1160px; + } + } + } + + .horizontal-navbar { + padding: 16px 0; + margin: 0px auto; + align-items: center; + display: flex; + z-index: 11; + font-size: 0.875rem; + position: relative; + + ul { + padding: 0px; + margin: 0px; + } + + .ddMenu { + li { + a { + color: rgb(var(--v-theme-textPrimary)) !important; + } + } + } + + li { + list-style: none; + + a { + text-decoration: none; + display: flex; + align-items: center; + padding: 10px 13px; + height: 40px; + + .navIcon { + margin-right: 10px; + display: flex; + } + + .ddIcon { + margin-top: 2px; + } + + &.router-link-exact-active { + background-color: transparent; + color: rgba(var(--v-theme-secondary)) !important; + + .dot { + background-color: rgb(var(--v-theme-secondary)) !important; + } + + } + + } + } + + .navItem { + position: relative; + + .single-link { + &:hover { + color: rgb(var(--v-theme-secondary)) !important; + } + } + + + .ddMenu { + .navItem { + .navcollapse { + &:hover { + color: rgb(var(--v-theme-secondary)) !important; + } + } + } + } + + + } + + .ddMenu { + position: absolute; + width: 230px; + display: none; + top: 40px; + padding: 10px; + z-index: 1; + background-color: rgb(var(--v-theme-surface)); + box-shadow: $box-shadow; + border-radius: $border-radius-root; + + li { + margin-bottom: 3px; + } + } + + .ddLevel-2, + .ddLevel-3 { + top: -5px; + left: 212px; + } + + .navItem:hover { + + >.ddMenu { + display: block; + } + } + + >li:hover { + background-color: rgb(var(--v-theme-lightprimary)); + border-radius: 9999px; + + >.navItemLink { + color: rgb(var(--v-theme-secondary)); + opacity: 1; + } + } + + .router-link-exact-active { + color: rgb(var(--v-theme-secondary)); + font-weight: 500; + background-color: rgb(var(--v-theme-lightprimary)); + border-radius: $border-radius-root; + } + } +} \ No newline at end of file diff --git a/web/src/scss/layout/_reboot.scss b/web/src/scss/layout/_reboot.scss new file mode 100644 index 0000000..f4e4321 --- /dev/null +++ b/web/src/scss/layout/_reboot.scss @@ -0,0 +1,109 @@ +.h-100 { + height: 100%; +} + +.w-100 { + width: 100%; +} + +.h-100vh { + height: 100vh; +} + +.gap-2 { + gap: 8px; +} + +.gap-3 { + gap: 16px; +} + +.gap-4 { + gap: 24px; +} + +.text-white { + color: rgb(255, 255, 255) !important; +} + +// border +.border-bottom { + border-bottom: 1px solid rgba(0, 0, 0, .05); +} + +.opacity-1 { + opacity: 1 !important; +} + +.opacity-50 { + opacity: 0.5; +} + +.z-auto.v-card { + z-index: auto; +} + +.obj-cover { + object-fit: cover; +} + +.cursor-move { + cursor: move; +} + +body { + cursor: default; +} + +input:not([type="checkbox"]):not([type="radio"]):not([type="button"]):not([type="submit"]):not([type="reset"]):not([type="file"]):not([type="range"]):not([type="color"]), +textarea, +[contenteditable="true"] { + cursor: text; +} + +//Date time picker +input[type="date"], +input[type="time"] { + display: block !important; +} + +input[type="date"]::-webkit-calendar-picker-indicator, +input[type="time"]::-webkit-calendar-picker-indicator { + display: block !important; +} + +.ProseMirror { + min-height: 150px; +} + +.upload-btn-wrapper { + width: 150px; + height: 140px; + margin: 0 auto; + box-shadow: 0 0.5rem 1.5rem 0.5rem rgba(0, 0, 0, 0.075); + + input[type=file] { + position: absolute; + left: 0; + top: 0; + opacity: 0; + height: 100%; + width: 100%; + } +} + +.bg-transparent { + background-color: transparent !important; +} +.bg-dark{ + background-color: rgba(0, 0, 0, .08); +} +.bg-white-opacity{ + background-color: rgba(255, 255, 255, 0.2); +} + +@media screen and (max-width:1368px) and (min-width:1200px) { + .space-20 { + padding: 30px 20px !important; + } +} \ No newline at end of file diff --git a/web/src/scss/layout/_rtl.scss b/web/src/scss/layout/_rtl.scss new file mode 100644 index 0000000..b245ee8 --- /dev/null +++ b/web/src/scss/layout/_rtl.scss @@ -0,0 +1,341 @@ +.v-locale--is-rtl { + .customizer-btn { + left: 30px; + right: unset; + } + + .horizontal-navbar .icon-box { + margin-left: 12px; + } + + + + .bg-img-1 { + position: absolute; + bottom: 0; + left: 0; + right: unset !important; + transform: scaleX(-1); + } + + .ml-1 { + margin-left: unset !important; + margin-right: 4px; + } + + .ml-2 { + margin-left: unset !important; + margin-right: 8px; + } + + .mr-1 { + margin-right: unset !important; + margin-left: 4px; + } + + .mr-2 { + margin-right: unset !important; + margin-left: 8px; + } + + .mr-sm-2 { + margin-right: unset !important; + margin-left: 8px; + } + + .mr-3 { + margin-right: unset !important; + margin-left: 12px !important; + } + + .mr-4 { + margin-right: unset !important; + margin-left: 16px !important; + } + + .ml-3 { + margin-left: unset !important; + margin-right: 12px !important; + } + + .mr-auto { + margin-left: auto !important; + margin-right: unset !important; + } + + .ml-4 { + margin-left: unset !important; + margin-right: 16px; + } + + .ml-sm-4 { + margin-left: unset !important; + margin-right: 16px; + } + + .ml-md-4 { + margin-left: unset !important; + margin-right: 16px; + } + + .ml-sm-3 { + margin-left: unset !important; + margin-right: 12px; + } + + + .ml-5 { + margin-left: unset !important; + margin-right: 20px; + } + + .ml-6 { + margin-left: unset !important; + margin-right: 24px; + } + + .ml-10 { + margin-left: unset !important; + margin-right: 40px; + } + + .pl-1 { + padding-left: unset !important; + padding-right: 4px !important; + } + + .pl-2 { + padding-left: unset !important; + padding-right: 8px !important; + } + + .pr-2 { + padding-left: 8px !important; + } + + .pr-4 { + padding-left: 16px !important; + padding-right: unset !important; + } + + .pl-4 { + padding-left: unset !important; + padding-right: 16px !important; + } + + .right-pos-img { + right: unset; + left: 0; + transform: scaleX(-1); + top: 0; + } + + .badg-dotDetail { + left: 0; + right: -8px; + } + + .text-right { + text-align: left !important; + } + + .text-sm-right, + .text-md-right { + text-align: left !important; + } + + .text-sm-left { + text-align: right !important; + } + + .text-left { + text-align: right !important; + } + + .ml-auto, + .ml-sm-auto { + margin-left: unset !important; + margin-right: auto !important; + } + + .justify-start { + justify-content: flex-end !important; + } + + .vertical-table .v-table>.v-table__wrapper>table>tbody>tr>th { + border-left: thin solid rgba(var(--v-border-color), 1) !important; + } + + .authentication .auth-header { + left: unset; + right: 0; + } + + .horizontal-navbar li a { + padding: 10px 13px; + } + + .horizontal-navbar { + li { + margin-right: 0; + margin-left: 15px; + } + } + + // &.v-menu .v-overlay__content, + // &.search_popup .v-overlay__content, + // &.language_dropdown .v-overlay__content, + // &.notification_popup .v-overlay__content, + // &.profile_popup .v-overlay__content { + // left: inherit; + // } + + .related-Product { + .carousel__prev.navarrow { + top: 0; + right: unset !important; + left: 0; + } + + .carousel__next.navarrow { + top: 0; + right: unset !important; + left: 45px; + } + } + + //RTL mode minisidebar hover to active scrollbar + .ps--active-y>.ps__rail-y { + right: unset !important; + left: 0; + } + + //RTL mode sidebar scrollbar on right side + .left-customizer { + .ps__rail-y { + right: 0 !important; + } + } + + .horizontal-navbar .ddMenu { + padding: 10px 15px 10px 0px; + } + + .v-list-group__items { + .iconClass { + position: relative; + left: unset; + right: -2px; + } + } + + @media (min-width: 960px) { + + .horizontal-navbar .ddLevel-2, + .horizontal-navbar .ddLevel-3 { + top: -5px; + right: 212px; + } + + .horizontal-navbar li a .navIcon { + margin-right: 0; + margin-left: 10px; + } + } + + .leftSidebar .profile-name h5 { + direction: ltr; + } + + .horizontal-navbar { + .ddMenu { + .navItemLink { + padding-right: 15px; + } + } + } + + @media screen and (max-width:1279px) { + .mini-sidebar { + .v-navigation-drawer.v-navigation-drawer--right { + width: 270px !important; + } + + .v-navigation-drawer.v-navigation-drawer--left { + width: 320px !important; + } + } + + } + + .rtlImg { + transform: scaleX(-1); + } + + .marquee1-group { + animation: marquee-rtl 45s linear infinite; + } + + .marquee2-group { + animation: marquee2-rtl 45s linear infinite; + } + + @keyframes marquee-rtl { + 0% { + transform: translate3d(0, 0, 0); + } + + 100% { + transform: translate3d(2086px, 0, 0); + } + } + + @keyframes marquee2-rtl { + 0% { + transform: translate3d(2086px, 0, 0); + } + + 100% { + transform: translate3d(0, 0, 0); + } + } + + .front-wraper { + .testimonials { + .slide-counter { + left: -50px; + } + + .carousel__prev { + right: -74%; + left: unset; + + .rtlnav { + transform: scaleX(-1); + } + } + + .carousel__next { + right: -60%; + left: unset; + + .rtlnav { + transform: scaleX(-1); + } + + } + } + } + + //For Rtl Chart + .rtl-me-n7 { + margin-inline-start: -28px !important; + margin-inline-end: unset !important; + } + + .profile-img::before { + left: unset; + right: 14px; + } + +} \ No newline at end of file diff --git a/web/src/scss/layout/_sidebar.scss b/web/src/scss/layout/_sidebar.scss new file mode 100644 index 0000000..b1d279c --- /dev/null +++ b/web/src/scss/layout/_sidebar.scss @@ -0,0 +1,374 @@ +@use "../variables" as *; + +/*This is for the logo*/ +.leftSidebar { + box-shadow: 0 3px 4px 0 rgba(0, 0, 0, .03), 0 0 1px 0 rgba(0, 0, 0, .1); + + .logo { + padding-left: 7px; + } + + .mini-icon { + display: none; + } + + .mini-text { + display: block; + } + + .profile { + background: url("@/assets/images/backgrounds/user-info.jpg") no-repeat; + } + + .profile-name { + background: rgba(0, 0, 0, 0.5); + margin-top: -6px; + height: 35px; + + h5 { + text-overflow: ellipsis; + white-space: nowrap; + overflow: hidden; + } + } + + .v-list--density-default .v-list-subheader { + padding-inline-start: 0 !important; + } +} + +.verticalLayout { + .logo { + width: 250px; + + @media screen and (max-width:1024px) { + width: auto; + } + } +} + +/*This is for the Vertical sidebar*/ +.scrollnavbar { + height: 100%; + + .userbottom { + position: fixed; + bottom: 0px; + width: 100%; + } + + .smallCap { + padding: 3px 12px 12px 0px !important; + font-size: 0.875rem; + font-weight: 500; + margin-top: 24px; + color: rgb(var(--v-theme-textPrimary)); + + &:first-child { + margin-top: 0 !important; + } + } + + + + /*General Menu css*/ + .v-list-group__items .v-list-item, + .v-list-item { + border-radius: $border-radius-root; + padding-inline-start: calc(14px + var(--indent-padding) / 10) !important; + + margin: 0 0 2px; + + + + &:hover { + color: rgb(var(--v-theme-secondary)); + + } + + + + .v-list-item__prepend { + margin-inline-end: 13px; + } + + .v-list-item__append { + font-size: 0.875rem; + + .v-icon { + margin-inline-start: 13px; + } + } + + .v-list-item-title { + font-size: 0.875rem; + } + } + + .v-list-group__items { + .v-list-item { + min-height: 35px !important; + padding-inline-start: calc(12px + var(--indent-padding) / 10) !important; + + .v-list-item__prepend .dot { + height: 6px; + width: 6px; + background-color: rgb(var(--v-theme-textSecondary)); + border-radius: 50%; + margin-inline-end: 8px !important; + opacity: 0; + } + + .v-list-item-title { + font-size: 14px !important; + } + + &:hover { + color: rgb(var(--v-theme-secondary)); + + .v-list-item__prepend .dot { + background-color: rgb(var(--v-theme-secondary)); + } + } + + &.v-list-item--active { + .v-list-item__prepend .dot { + background-color: rgb(var(--v-theme-secondary)); + } + } + + } + } + + /*This is for the dropdown*/ + .v-list { + color: rgb(var(--v-theme-textPrimary)); + + >.v-list-item.v-list-item--active, + .v-list-item--active>.v-list-item__overlay { + background: rgb(var(--v-theme-secondary)); + color: white; + } + + >.v-list-group { + position: relative; + + >.v-list-item--active, + >.v-list-item--active:hover { + background: rgb(var(--v-theme-secondary)); + color: white; + } + + .v-list-group__items .v-list-item.v-list-item--active, + .v-list-group__items .v-list-item.v-list-item--active>.v-list-item__overlay { + background: transparent; + color: rgb(var(--v-theme-secondary)); + } + } + } +} + +.v-navigation-drawer--rail { + + .scrollnavbar .v-list .v-list-group__items, + .hide-menu { + opacity: 1; + } + + .leftPadding { + margin-left: 0px; + } +} + +@media only screen and (min-width: 1170px) { + .mini-sidebar { + .logo { + width: 40px; + overflow: hidden; + padding-left: 0; + } + + .profile-logout { + opacity: 0; + width: 0; + } + + .scrollnavbar { + .smallCap { + padding: 3px 12px 12px 12px !important; + } + } + + .leftSidebar .v-list--density-default .v-list-subheader { + padding-inline-start: 15px !important; + } + + .mini-icon { + display: block; + } + + .sidebarchip.hide-menu { + opacity: 0; + } + + .mini-text { + display: none; + } + + .v-list { + padding: 14px !important; + } + + .v-list-group__items { + .iconClass { + position: relative; + left: -2px; + } + } + + .leftSidebar:hover { + box-shadow: $box-shadow !important; + + .mini-icon { + display: none; + } + + .sidebarchip.hide-menu { + opacity: 1; + } + + .mini-text { + display: block; + } + + .profile-logout { + opacity: 1; + width: auto; + } + + .scrollnavbar { + .smallCap { + padding: 3px 12px 12px 0px !important; + } + } + + .v-list-group__items { + .iconClass { + position: relative; + left: 0px; + } + } + + .v-list--density-default .v-list-subheader { + padding-inline-start: 0px !important; + } + .v-list-group__items { + .v-list-item { + .v-list-item__prepend .dot { + opacity:0; + } + } + } + } + + .v-navigation-drawer--expand-on-hover:hover { + .logo { + width: 100%; + } + + .v-list .v-list-group__items, + .hide-menu { + opacity: 1; + } + } + + .profile-img { + margin-left: 0; + + &::before { + left: 12px; + } + } + + .menu-toggle { + margin-left: 24px; + } + + .v-list-group__items { + .v-list-item { + .v-list-item__prepend .dot { + opacity: 1; + } + } + } + + } +} + +// scrollbar +.ps__rail-y { + z-index: 9; +} + +.profile-img { + margin-left: 14px; + + &::before { + -webkit-animation: 2.5s blow 0s linear infinite; + animation: 2.5s blow 0s linear infinite; + position: absolute; + content: ""; + width: 50px; + height: 50px; + top: 40px; + border-radius: 50%; + z-index: 0; + left: 26px; + } + + @-webkit-keyframes blow { + 0% { + box-shadow: 0 0 0 0px rgba(0, 0, 0, 0.1); + opacity: 1; + -webkit-transform: scale3d(1, 1, 0.5); + transform: scale3d(1, 1, 0.5); + } + + 50% { + box-shadow: 0 0 0 10px rgba(0, 0, 0, 0.1); + opacity: 1; + -webkit-transform: scale3d(1, 1, 0.5); + transform: scale3d(1, 1, 0.5); + } + + 100% { + box-shadow: 0 0 0 20px rgba(0, 0, 0, 0.1); + opacity: 0; + -webkit-transform: scale3d(1, 1, 0.5); + transform: scale3d(1, 1, 0.5); + } + } + + @keyframes blow { + 0% { + box-shadow: 0 0 0 0px rgba(0, 0, 0, 0.1); + opacity: 1; + -webkit-transform: scale3d(1, 1, 0.5); + transform: scale3d(1, 1, 0.5); + } + + 50% { + box-shadow: 0 0 0 10px rgba(0, 0, 0, 0.1); + opacity: 1; + -webkit-transform: scale3d(1, 1, 0.5); + transform: scale3d(1, 1, 0.5); + } + + 100% { + box-shadow: 0 0 0 20px rgba(0, 0, 0, 0.1); + opacity: 0; + -webkit-transform: scale3d(1, 1, 0.5); + transform: scale3d(1, 1, 0.5); + } + } +} \ No newline at end of file diff --git a/web/src/scss/layout/_text.scss b/web/src/scss/layout/_text.scss new file mode 100644 index 0000000..0c58315 --- /dev/null +++ b/web/src/scss/layout/_text.scss @@ -0,0 +1,98 @@ +$sizes: ( + 'display-1': 44px, + 'display-2': 40px, + 'display-3': 30px, + 'h1': 36px, + 'h2': 30px, + 'h3': 21px, + 'h4': 18px, + 'h5': 16px, + 'h6': 14px, + 'text-10': 10px, + 'text-12': 12px, + 'text-13': 13px, + 'text-14': 14px, + 'text-15': 15px, + 'text-16': 16px, + 'text-17': 17px, + 'text-18': 18px, + 'text-20': 20px, + 'text-22': 22px, + 'text-24': 24px, + 'text-28': 28px, + 'text-34': 34px, + 'text-40': 40px, + 'text-44': 44px, + 'text-48': 48px, + 'text-50': 50px, + 'text-52': 52px, + 'text-56': 56px, + 'text-64': 64px, + 'body-text-1': 10px +); + +@each $pixel, $size in $sizes { + .#{$pixel} { + font-size: $size; + line-height: $size + 10; + } +} + +$height: ( + 'h-10': 10px, + 'h-12': 12px, + 'h-15': 15px, +); + +@each $pixel, $size in $height { + .#{$pixel} { + height: $size; + width: $size ; + } +} + +.textSecondary { + color: rgb(var(--v-theme-textSecondary)) !important; +} + +.textPrimary { + color: rgb(var(--v-theme-textPrimary)) !important; +} + +// line height + +.lh-md { + line-height: 1.57; +} +.lh-normal{ + line-height: normal; +} + +.font-weight-semibold { + font-weight: 600; +} + +// hover text +.text-hover-primary { + color: rgb(var(--v-theme-textPrimary)); + + &:hover { + color: rgb(var(--v-theme-primary)); + } +} + +.link { + color: rgb(var(--v-theme-textSecondary)); + text-decoration: none; + + &:hover { + color: rgb(var(--v-theme-primary)); + } +} + +.hover-primary { + &:hover { + color: rgb(var(--v-theme-primary)) !important; + opacity: 1; + } +} \ No newline at end of file diff --git a/web/src/scss/layout/_topbar.scss b/web/src/scss/layout/_topbar.scss new file mode 100644 index 0000000..762e4f2 --- /dev/null +++ b/web/src/scss/layout/_topbar.scss @@ -0,0 +1,110 @@ +.v-app-bar { + .v-toolbar__content { + padding: 0 15px; + > .v-btn:first-child { + margin-inline-start: 0; + } + .v-btn { + color: rgba(var(--v-theme-textsurface)) !important; + } + } +} + +.custom-text-primary { + &.v-list-item:hover > .v-list-item__overlay { + display: none; + } + .custom-title { + color: rgb(var(--v-theme-textPrimary)) !important; + } + &:hover { + .custom-title { + color: rgb(var(--v-theme-primary)) !important; + } + } +} +@media screen and (max-width:1279px) { + .mini-sidebar { + .v-navigation-drawer.v-navigation-drawer--left { + width: 270px !important; + } + } +} + + +.notify { + position: relative; + top: -20px; + right: -8px; + + .heartbit { + position: absolute; + top: -5px; + right: -2px; + height: 18px; + width: 18px; + z-index: 10; + border: 2px solid rgb(var(--v-theme-error)); + border-radius: 70px; + animation: heartbit 1s ease-out; + -moz-animation: heartbit 1s ease-out; + -moz-animation-iteration-count: infinite; + -o-animation: heartbit 1s ease-out; + -o-animation-iteration-count: infinite; + -webkit-animation: heartbit 1s ease-out; + -webkit-animation-iteration-count: infinite; + animation-iteration-count: infinite; + } + + .point { + width: 4px; + height: 4px; + border-radius: 30px; + position: absolute; + right: 5px; + top: 2px; + background-color: rgb(var(--v-theme-error)); + position: absolute; + } + } + + @keyframes heartbit { + 0% { + transform: scale(0); + opacity: 0; + } + + 25% { + transform: scale(0.1); + opacity: 0.1; + } + + 50% { + transform: scale(0.5); + opacity: 0.3; + } + + 75% { + transform: scale(0.8); + opacity: 0.5; + } + + 100% { + transform: scale(1); + opacity: 0; + } + } + + .v-menu.mobile_popup .v-overlay__content { + width: 100%; +} + + @media (max-width: 1199px) { + .main-head{ + &.v-app-bar .v-toolbar__content{ + width: 100%; + justify-content: space-between; + padding: 0 10px; + } + } +} \ No newline at end of file diff --git a/web/src/scss/pages/_apps.scss b/web/src/scss/pages/_apps.scss new file mode 100644 index 0000000..7825ec5 --- /dev/null +++ b/web/src/scss/pages/_apps.scss @@ -0,0 +1,240 @@ +// +// common +// + +.inside-left-sidebar { + .left-part { + width: 240px; + } +} + +// +//Full Calendar +.fc { + .fc-button-group { + >.fc-button { + display: flex; + align-items: center; + padding: 7px 10px; + border: 0; + font-size: 14px; + background-color: rgba(var(--v-theme-grey200)); + color: rgba(var(--v-theme-textPrimary)); + .fc-icon{ + color: rgba(var(--v-theme-textPrimary)); + font-size: 20px; + } + &:hover,&:focus{ + background-color: rgba(var(--v-theme-textPrimary)); + color: #fff; + .fc-icon{ + color: #fff; + } + } + } + .fc-button-primary:not(:disabled):active{ + background-color: rgba(var(--v-theme-textPrimary)); + } + .fc-button-primary:not(:disabled).fc-button-active { + background-color: rgb(var(--v-theme-textPrimary)); + } + } + .fc-today-button{ + padding: 7px 20px; + border: 0; + background-color: rgba(var(--v-theme-primary)); + } + + .fc-prev-button{ + border-radius: 30px 0 0 30px; + } + .fc-toolbar-title{ + font-weight: 600; + } + .fc-event-title{ + font-size: 14px; + padding: 3px 6px; + } + + .fc-button { + font-size: 14px; + font-weight: 500; + text-transform: capitalize; + + .fc-icon { + font-size: 1.5em; + vertical-align: unset; + } + } + .fc-daygrid-day-number{ + color: rgba(var(--v-theme-textSecondary)); + font-size: 15px; + } + + .fc-button-primary { + background: rgb(var(--v-theme-primary)); + border-color: rgb(var(--v-theme-primary)); + + color: #fff; + + &:hover { + background-color: rgb(var(--v-theme-primary)); + border-color: rgb(var(--v-theme-primary)); + } + + &:not(:disabled).fc-button-active { + background-color: rgb(var(--v-theme-primary)); + border-color: rgb(var(--v-theme-primary)); + + &:focus { + box-shadow: none; + } + } + + &:not(:disabled) { + &:active { + background-color: rgb(var(--v-theme-primary)); + border-color: rgb(var(--v-theme-primary)); + + &:focus { + box-shadow: none; + } + } + } + + &:disabled { + background-color: rgb(var(--v-theme-primary)); + border-color: rgb(var(--v-theme-primary)); + opacity: 1; + } + } + + .fc-col-header-cell-cushion { + display: inline-block; + padding: 10px 5px; + font-size: 14px; + font-weight: 600; + } + .fc-button-primary:not(:disabled).fc-button-active{ + background-color: rgb(var(--v-theme-textPrimary)); + } +} + +.fc-theme-standard { + td { + border: 1px solid rgba(var(--v-border-color), 1) !important; + } + + th { + border: 1px solid rgba(var(--v-border-color), 1) !important; + border-bottom: 0 !important; + background-color: rgba(var(--v-theme-grey200)); + height: 56px; + vertical-align: middle; + color: rgba(var(--v-theme-textSecondary)); + } + + .fc-scrollgrid { + border: 0 !important; + } +} + +.fc-h-event { + background-color: rgb(var(--v-theme-primary)); + border: 0; + display: block; +} + +.fc-direction-ltr { + .fc-button-group { + >.fc-button { + &:not(:last-child) { + border-bottom-left-radius: 30px; + border-top-left-radius: 30px; + } + + &:not(:first-child) { + border-bottom-right-radius: 30px; + border-top-right-radius: 30px; + margin-left: -1px; + } + } + } +} + +.fc-button-group { + .fc-dayGridMonth-button { + border-bottom-right-radius: 0px !important; + border-top-right-radius: 0px !important; + padding: 7px 20px !important; + } + + .fc-timeGridDay-button { + border-bottom-left-radius: 0px !important; + border-top-left-radius: 0px !important; + padding: 7px 20px !important; + } + + .fc-timeGridWeek-button { + border-radius: 0 !important; + padding: 7px 20px !important; + } +} + +.fc-today-button { + border-radius: 30px !important; + font-size: 14px; +} + +@media screen and (max-width:600px) { + .fc { + .fc-toolbar { + display: block; + text-align: center; + } + } + + .fc-toolbar-chunk { + .fc-toolbar-title { + margin: 15px 0; + } + } +} + +.customTab { + .v-btn { + &.v-tab-item--selected { + background-color: rgb(var(--v-theme-lightprimary)) !important; + + .icon { + background-color: rgb(var(--v-theme-primary)) !important; + color: #fff !important; + } + } + } +} + +.email-items { + padding: 0px 24px 12px; + + &.selected-email { + .email-title { + color: rgb(var(--v-theme-primary)) !important; + } + } + + &:hover { + background-color: rgb(var(--v-theme-hoverColor)); + + .email-title { + color: rgb(var(--v-theme-primary)) !important; + } + + } +} + +.email-content { + p { + margin: 10px 0; + } +} \ No newline at end of file diff --git a/web/src/scss/pages/_authentication.scss b/web/src/scss/pages/_authentication.scss new file mode 100644 index 0000000..63f6b3a --- /dev/null +++ b/web/src/scss/pages/_authentication.scss @@ -0,0 +1,90 @@ +.authentication{ + &::before{ + content: ""; + position: absolute; + height: 100%; + width: 100%; + opacity: 0.3; + left: 0; + top: 0; + bottom: 0; + background: radial-gradient(rgb(210, 241, 223), rgb(211, 215, 250), rgb(186, 216, 244)) 0% 0% / 400% 400%; + } + + @media screen and (max-width:1280px){ + .auth-header{ + position: unset; + } + } +} +.mw-450{ + max-width: 450px; + width: 100%;; +} +.auth-header{ + position: absolute; + top: 0; + left: 0; +} +.verification{ + .v-field__input{ + text-align: center; + } +} +.auth-divider{ + span{ + z-index: 1; + } + &::before{ + position: absolute; + width: 100%; + border-top: thin solid rgb(var(--v-theme-borderColor)); + top: 50%; + content: ""; + transform: translateY(50%); + left: 0; + } + &::after + { + position: absolute; + width: 100%; + border-top: thin solid rgb(var(--v-theme-borderColor)); + top: 50%; + content: ""; + transform: translateY(50%); + right: 0; + } +} + +@media (min-width: 1536px){ + .auth{ + .v-col-lg-7{ + flex: 0 0 66.66%; + max-width: 66.66%; + } + .v-col-lg-5{ + flex: 0 0 33.33%; + max-width: 33.33%; + } + } + +} +@media screen and (max-width:1280px){ + .mh-100{ + height: 100% !important; + } +} + +@media screen and (max-width:600px){ + .mw-100{ + width: 100%; + padding: 0 15px; + } +} + +.auth{ + .v-switch .v-label, .v-checkbox .v-label { + opacity: 0.7; + font-weight: 400 !important; + } +} \ No newline at end of file diff --git a/web/src/scss/pages/_dashboards.scss b/web/src/scss/pages/_dashboards.scss new file mode 100644 index 0000000..e222a21 --- /dev/null +++ b/web/src/scss/pages/_dashboards.scss @@ -0,0 +1,227 @@ +.month-table { + &.custom-px-0 { + thead { + tr { + th:first-child { + padding-left: 0 !important; + } + + th:last-child { + padding-right: 0 !important; + } + } + } + + tr.month-item { + td:first-child { + padding-left: 0 !important; + } + + td:last-child { + padding-right: 0 !important; + } + } + } + + tr.month-item { + td { + padding-top: 16px !important; + padding-bottom: 16px !important; + } + + &:hover { + background: transparent !important; + } + } + + tr.month-item-0 { + td { + padding-top: 12px !important; + padding-bottom: 12px !important; + } + + &:hover { + background: transparent !important; + } + } + + tr.month-item-hover { + + td { + padding-top: 12px !important; + padding-bottom: 12px !important; + } + + border-left: 4px solid transparent; + + &:hover { + border-left: 4px solid rgba(var(--v-theme-primary)) !important; + } + } + + +} + + +.no-line { + + .v-table .v-table__wrapper>table>tbody>tr:not(:last-child)>td { + border-bottom: 0 !important; + } + + .v-table .v-table__wrapper>table>tbody>tr>td { + padding: 12px; + } +} + +.recent-transaction { + .line { + width: 2px; + height: 35px; + } +} + + +.chip-label { + width: 80px; + justify-content: center; +} + +// +// Apex Chart +// + +body { + .apexcharts-tooltip { + border-radius: 16px; + } + + .apexcharts-tooltip-marker { + border-radius: 4px; + width: 12px; + height: 4px; + } + + .apexcharts-tooltip.apexcharts-theme-dark { + background: rgba(17, 28, 45, 0.8); + + .apexcharts-tooltip-title { + border-bottom: 0; + background: rgba(17, 28, 45, 0.7); + } + } + + .apexcharts-tooltip-series-group { + padding: 0 14px; + } + + .apexcharts-tooltip-title { + padding: 10px 14px; + } +} + +.profile-activity { + + .v-tab { + + &.v-btn { + border: 1px dashed rgba(var(--v-theme-borderColor)); + border-radius: 8px; + min-width: 90px; + overflow: hidden; + padding: 15px 20px; + overflow: hidden; + + .v-btn__content { + display: block; + } + + &.v-tab--selected{ + border: 1px solid rgba(var(--v-theme-borderColor)); + border-bottom: 2px solid; + } + .v-tab__slider{ + opacity: 0; + } + } + + } + + .v-slide-group__content { + gap: 16px; + } +} + +.comment-box { + border-bottom: 1px solid rgba(var(--v-theme-borderColor)); + padding-bottom: 20px; + margin-bottom: 20px; + cursor: pointer; + + &:last-child { + border-bottom: 0; + padding-bottom: 0px; + margin-bottom: 0px; + } + + .comment-action { + opacity: 0; + transition: 0.5s; + } + + &:hover { + .comment-action { + opacity: 1; + } + } +} + +.todo-list { + border-bottom: 1px solid rgba(var(--v-theme-borderColor)); + padding-bottom: 25px; + margin-bottom: 25px; + cursor: pointer; + + &:last-child { + border-bottom: 0; + padding-bottom: 20px; + margin-bottom: 20px; + } + +} + +.progress-cards { + border-inline-end: 1px solid rgba(var(--v-theme-borderColor)); + + &:last-child { + border: 0; + } + + @media screen and (max-width:991px) { + border-inline-end: 0 !important + } +} + +.notification { + border-bottom: 1px solid rgba(var(--v-theme-borderColor)); + + &:last-child { + border: 0; + } +} + + +.earning-cards { + @media screen and (max-width:991px){ + .w-25{ + width: 100% !important; + &.border-e{ + border: 0 !important; + } + .mobile-border{ + border-bottom:1px solid rgba(var(--v-theme-borderColor)); + padding-bottom: 8px !important; + } + } + } +} \ No newline at end of file diff --git a/web/src/scss/pages/_datatable.scss b/web/src/scss/pages/_datatable.scss new file mode 100644 index 0000000..a540915 --- /dev/null +++ b/web/src/scss/pages/_datatable.scss @@ -0,0 +1,48 @@ +@use "../variables" as *; + +.customize-table { + border-radius: $border-radius-root; + .vue3-easy-data-table__main, + .vue3-easy-data-table__footer { + border-radius: $border-radius-root; + } + white-space: nowrap; + --easy-table-border: 1px solid rgb(var(--v-theme-inputBorder), 0.1); + --easy-table-row-border: 1px solid rgb(var(--v-theme-inputBorder), 0.1); + + --easy-table-header-font-size: 14px; + --easy-table-header-height: 50px; + --easy-table-header-font-color: rgb(var(--v-theme-textPrimary)); + --easy-table-header-background-color: rgb(var(--v-theme-surface)); + + --easy-table-header-item-padding: 10px 15px; + + --easy-table-body-even-row-font-color: rgb(var(--v-theme-surface)); + --easy-table-body-even-row-background-color: rgba(0, 0, 0, 0.02); + + --easy-table-body-row-font-color: rgb(var(--v-theme-textPrimary)); + --easy-table-body-row-background-color: rgb(var(--v-theme-surface)); + --easy-table-body-row-height: 50px; + --easy-table-body-row-font-size: 14px; + + --easy-table-body-row-hover-font-color: rgb(var(--v-theme-textPrimary)); + --easy-table-body-row-hover-background-color: rgba(0, 0, 0, 0.02); + + --easy-table-body-item-padding: 15px; + + --easy-table-footer-background-color: rgb(var(--v-theme-surface)); + --easy-table-footer-font-color: rgb(var(--v-theme-textPrimary)); + --easy-table-footer-font-size: 14px; + --easy-table-footer-padding: 0px 10px; + --easy-table-footer-height: 50px; + + --easy-table-rows-per-page-selector-width: 70px; + --easy-table-rows-per-page-selector-option-padding: 10px; + + --easy-table-scrollbar-track-color: #; + --easy-table-scrollbar-color: #; + --easy-table-scrollbar-thumb-color: #4c5d7a; + --easy-table-scrollbar-corner-color: #; + + --easy-table-loading-mask-background-color: #; +} diff --git a/web/src/scss/pages/_editor.scss b/web/src/scss/pages/_editor.scss new file mode 100644 index 0000000..0076bfc --- /dev/null +++ b/web/src/scss/pages/_editor.scss @@ -0,0 +1,61 @@ +.ProseMirror { + padding: 20px; + border: 1px solid rgb(var(--v-theme-inputBorder), 0.3); + border-radius: 0 0 12px 12px; + &.ProseMirror-focused { + outline-color: rgb(var(--v-theme-primary), 0.3) !important; + } + > * + * { + margin-top: 0.75em; + } + + ul, + ol { + padding: 0 1rem; + } + + h1, + h2, + h3, + h4, + h5, + h6 { + line-height: 1.1; + } + + code { + background-color: rgba(#616161, 0.1); + color: #616161; + } + + pre { + background: #0d0d0d; + color: #fff; + font-family: 'JetBrainsMono', monospace; + padding: 0.75rem 1rem; + border-radius: 0.5rem; + + code { + color: inherit; + padding: 0; + background: none; + font-size: 0.8rem; + } + } + + img { + max-width: 100%; + height: auto; + } + + blockquote { + padding-left: 1rem; + border-left: 2px solid rgba(#0d0d0d, 0.1); + } + + hr { + border: none; + border-top: 2px solid rgba(#0d0d0d, 0.1); + margin: 2rem 0; + } +} diff --git a/web/src/scss/style.scss b/web/src/scss/style.scss new file mode 100644 index 0000000..7edb098 --- /dev/null +++ b/web/src/scss/style.scss @@ -0,0 +1,91 @@ +@use "./variables"; +@use "vuetify/styles.scss"; +@use "./override"; +@use "./layout/text"; +@use "./layout/reboot"; +@use "./layout/container"; +@use "./layout/sidebar"; +@use "./layout/rtl"; +@use "./layout/topbar"; +@use "./layout/horizontal"; +@use "./layout/dark"; +@use "./layout/customizer"; + +@use "./theme/themeColors"; + +@use "./components/VDatatable"; +@use "./components/VAlert"; +@use "./components/VButtons"; +@use "./components/VBreadcrumb"; +@use "./components/VCard"; +@use "./components/VCarousel"; +@use "./components/VField"; +@use "./components/VList"; +@use "./components/VInput"; +@use "./components/VNavigationDrawer"; +@use "./components/VShadow"; +@use "./components/VSwitch"; +@use "./components/VSelectionControl"; +@use "./components/VTextField"; +@use "./components/VTextarea"; +@use "./components/VTabs"; +@use "./components/VTable"; +@use "./components/VExpansionpanel"; +@use "./components/VDatatables"; +@use "./components/VStepper"; +@use "./components/VLabs"; + +@use "./front/header"; +@use "./front/general"; + +@use "./pages/datatable"; +@use "./pages/dashboards"; +@use "./pages/editor"; +@use "./pages/authentication"; +@use "./pages/apps"; + +//@use 'vue3-perfect-scrollbar/dist/vue3-perfect-scrollbar.css'; + +.small-stat-card { + border: 1px solid #25334355; + background-color: #152332; + border-radius: 8px; +} + +.small-stat-card .v-card-subtitle { + padding: 8px 14px 4px; + font-size: 13px; + border-bottom: 1px solid #253343; +} +.small-stat-card .v-card-text { + font-size: 20px; + padding: 9px 14px 10px; +} + +.small-stat-card.bg-error { + background-color: #cf667925 !important; + border: 1px solid #cf667955 !important; +} +.small-stat-card.bg-error .v-card-subtitle { + border-bottom: 1px solid #cf667955; +} + +.small-stat-card.bg-warning { + background-color: #fb8c0025 !important; + border: 1px solid #fb8c0055 !important; +} +.small-stat-card.bg-warning .v-card-subtitle { + border-bottom: 1px solid #fb8c0055; +} +.small-stat-card .text-warning { + color: #fb8c00de !important; +} + +.row-clickable tbody tr { + cursor: pointer; +} + +.v-data-table-rows-loading, +.v-data-table-rows-no-data { + text-align: left; +} diff --git a/web/src/scss/theme/_themeColors.scss b/web/src/scss/theme/_themeColors.scss new file mode 100644 index 0000000..6e3c2ae --- /dev/null +++ b/web/src/scss/theme/_themeColors.scss @@ -0,0 +1,59 @@ +// Light Theme Colors +.v-theme--AQUA_THEME { + --v-theme-primary: 0, 116, 186; + --v-theme-secondary: 71, 215, 188; + --v-theme-lightprimary: 229, 241, 248; + --v-theme-lightsecondary: 237, 251, 247; +} + +.v-theme--PURPLE_THEME { + --v-theme-primary: 118, 62, 189; + --v-theme-secondary: 148, 208, 214; + --v-theme-lightprimary: 242, 236, 249; + --v-theme-lightsecondary: 237, 248, 250; +} + +.v-theme--GREEN_THEME { + --v-theme-primary: 10, 126, 164; + --v-theme-secondary: 204, 218, 78; + --v-theme-lightprimary: 230, 242, 246; + --v-theme-lightsecondary: 250, 251, 239; +} + +.v-theme--CYAN_THEME { + --v-theme-primary: 1, 192, 200; + --v-theme-secondary: 251, 150, 120; + --v-theme-lightprimary: 235, 249, 250; + --v-theme-lightsecondary: 255, 245, 242; +} + +.v-theme--ORANGE_THEME { + --v-theme-primary: 250, 137, 107; + --v-theme-secondary: 0, 116, 186; + --v-theme-lightprimary: 251, 242, 239; + --v-theme-lightsecondary: 239, 249, 255; +} + +.v-theme--DARK_AQUA_THEME{ + --v-theme-primary: 0, 116, 186; + --v-theme-secondary: 71, 215, 188; +} + +.v-theme--DARK_PURPLE_THEME { + --v-theme-primary: 118, 62, 189; + --v-theme-secondary: 148, 208, 214; +} + +.v-theme--DARK_GREEN_THEME { + --v-theme-primary: 10, 126, 164; + --v-theme-secondary: 204, 218, 78; +} + +.v-theme--DARK_CYAN_THEME { + --v-theme-primary: 1, 192, 200; + --v-theme-secondary: 251, 150, 120; +} +.v-theme--DARK_ORANGE_THEME { + --v-theme-primary: 250, 137, 107; + --v-theme-secondary: 0, 116, 186; +} \ No newline at end of file diff --git a/web/src/theme/DarkTheme.ts b/web/src/theme/DarkTheme.ts new file mode 100644 index 0000000..16fed7f --- /dev/null +++ b/web/src/theme/DarkTheme.ts @@ -0,0 +1,191 @@ +import type { ThemeTypes } from "./ThemeTypes" + +const DARK_BLUE_THEME: ThemeTypes = { + name: "DARK_BLUE_THEME", + dark: true, + variables: { + "border-color": "#333F55", + "border-opacity": 1, + }, + colors: { + primary: "#1B84FF", + secondary: "#0cb9c5", + lightprimary: "#253662", + lightsecondary: "#1C455D", + lightsuccess: "#1B3C48", + lighterror: "#4B313D", + lightwarning: "#4D3A2A", + lightinfo: "#223662", + textPrimary: "#EAEFF4", + textSecondary: "#7C8FAC", + borderColor: "#333F55", + inputBorder: "#465670", + containerBg: "#2a3447", + background: "#192838", + surface: "#152332", + hoverColor: "#333f55", + "on-surface-variant": "#2a3447", + grey100: "#333F55", + grey200: "#465670", + }, +} + +const DARK_AQUA_THEME: ThemeTypes = { + name: "DARK_AQUA_THEME", + dark: true, + variables: { + "border-color": "#333F55", + "border-opacity": 1, + }, + colors: { + primary: "#0074BA", + info: "#725af2", + secondary: "#47D7BC", + lightprimary: "#103247", + lightsecondary: "#0C4339", + lightsuccess: "#1B3C48", + lighterror: "#4B313D", + lightwarning: "#4D3A2A", + lightinfo: "#223662", + textPrimary: "#EAEFF4", + textSecondary: "#7C8FAC", + borderColor: "#333F55", + inputBorder: "#465670", + containerBg: "#171c23", + background: "#192838", + surface: "#152332", + hoverColor: "#333f55", + "on-surface-variant": "#171c23", + grey100: "#333F55", + grey200: "#465670", + }, +} + +const DARK_PURPLE_THEME: ThemeTypes = { + name: "DARK_PURPLE_THEME", + dark: true, + variables: { + "border-color": "#333F55", + "border-opacity": 1, + }, + colors: { + primary: "#763EBD", + secondary: "#95CFD5", + lightprimary: "#26153C", + lightsecondary: "#09454B", + lightsuccess: "#1B3C48", + lighterror: "#4B313D", + lightwarning: "#4D3A2A", + lightinfo: "#223662", + textPrimary: "#EAEFF4", + textSecondary: "#7C8FAC", + borderColor: "#333F55", + inputBorder: "#465670", + containerBg: "#171c23", + background: "#192838", + surface: "#152332", + hoverColor: "#333f55", + "on-surface-variant": "#171c23", + grey100: "#333F55", + grey200: "#465670", + }, +} + +const DARK_GREEN_THEME: ThemeTypes = { + name: "DARK_GREEN_THEME", + dark: true, + variables: { + "border-color": "#333F55", + "border-opacity": 1, + }, + colors: { + primary: "#0A7EA4", + secondary: "#CCDA4E", + lightprimary: "#05313F", + lightsecondary: "#282917", + lightsuccess: "#1B3C48", + lighterror: "#4B313D", + lightwarning: "#4D3A2A", + lightinfo: "#223662", + textPrimary: "#EAEFF4", + textSecondary: "#7C8FAC", + borderColor: "#333F55", + inputBorder: "#465670", + containerBg: "#171c23", + background: "#192838", + surface: "#152332", + hoverColor: "#333f55", + "on-surface-variant": "#171c23", + grey100: "#333F55", + grey200: "#465670", + }, +} + +const DARK_CYAN_THEME: ThemeTypes = { + name: "DARK_CYAN_THEME", + dark: true, + variables: { + "border-color": "#333F55", + "border-opacity": 1, + }, + colors: { + primary: "#01C0C8", + secondary: "#FB9678", + lightprimary: "#003638", + lightsecondary: "#40241C", + lightsuccess: "#1B3C48", + lighterror: "#4B313D", + lightwarning: "#4D3A2A", + lightinfo: "#223662", + textPrimary: "#EAEFF4", + textSecondary: "#7C8FAC", + borderColor: "#333F55", + inputBorder: "#465670", + containerBg: "#171c23", + background: "#192838", + surface: "#152332", + hoverColor: "#333f55", + "on-surface-variant": "#171c23", + grey100: "#333F55", + grey200: "#465670", + }, +} + +const DARK_ORANGE_THEME: ThemeTypes = { + name: "DARK_ORANGE_THEME", + dark: true, + variables: { + "border-color": "#333F55", + "border-opacity": 1, + }, + colors: { + primary: "#FA896B", + secondary: "#0074BA", + lightprimary: "#402E32", + lightsecondary: "#082E45", + lightsuccess: "#1B3C48", + lighterror: "#4B313D", + lightwarning: "#4D3A2A", + lightinfo: "#223662", + textPrimary: "#EAEFF4", + textSecondary: "#7C8FAC", + borderColor: "#333F55", + inputBorder: "#465670", + containerBg: "#171c23", + background: "#192838", + surface: "#152332", + hoverColor: "#333f55", + "on-surface-variant": "#171c23", + grey100: "#333F55", + grey200: "#465670", + }, +} + +export { + DARK_BLUE_THEME, + DARK_AQUA_THEME, + DARK_ORANGE_THEME, + DARK_PURPLE_THEME, + DARK_GREEN_THEME, + DARK_CYAN_THEME, +} diff --git a/web/src/theme/LightTheme.ts b/web/src/theme/LightTheme.ts new file mode 100644 index 0000000..28231e7 --- /dev/null +++ b/web/src/theme/LightTheme.ts @@ -0,0 +1,40 @@ +import type { ThemeTypes } from "./ThemeTypes" + +const BLUE_THEME: ThemeTypes = { + name: "BLUE_THEME", + dark: false, + variables: { + "border-color": "#ebf1f6", + "border-opacity": 1, + }, + colors: { + primary: "#1B84FF", + secondary: "#43CED7", + info: "#2CABE3", + success: "#2CD07E", + accent: "#FFAB91", + warning: "#F6C000", + error: "#F8285A", + purple: "#725AF2", + indigo: "#6610f2", + lightprimary: "#EDF5FD", + lightsecondary: "#F2FCFC", + lightsuccess: "#EDFDF2", + lighterror: "#FFF0F4", + lightwarning: "#FFFCF0", + lightinfo: "#E4F5FF", + textPrimary: "#3A4752", + textSecondary: "#768B9E", + borderColor: "#ebf1f6", + inputBorder: "#DFE5EF", + containerBg: "#ffffff", + background: "#eef5f9", + hoverColor: "#f6f9fc", + surface: "#fff", + "on-surface-variant": "#fff", + grey100: "#F2F6FA", + grey200: "#EAEFF4", + }, +} + +export { BLUE_THEME } diff --git a/web/src/theme/ThemeTypes.ts b/web/src/theme/ThemeTypes.ts new file mode 100644 index 0000000..b7a3c68 --- /dev/null +++ b/web/src/theme/ThemeTypes.ts @@ -0,0 +1,33 @@ +export type ThemeTypes = { + name: string + dark: boolean + variables?: object + colors: { + primary?: string + secondary?: string + info?: string + success?: string + accent?: string + warning?: string + error?: string + purple?: string + indigo?: string + lightprimary?: string + lightsecondary?: string + lightsuccess?: string + lighterror?: string + lightinfo?: string + lightwarning?: string + textPrimary?: string + textSecondary?: string + borderColor?: string + hoverColor?: string + inputBorder?: string + containerBg?: string + background?: string + surface?: string + "on-surface-variant"?: string + grey100?: string + grey200?: string + } +} diff --git a/web/src/use/use-breadcrumbs.ts b/web/src/use/use-breadcrumbs.ts new file mode 100644 index 0000000..36b12e0 --- /dev/null +++ b/web/src/use/use-breadcrumbs.ts @@ -0,0 +1,95 @@ +import { reactive, toRefs, watch, MaybeRefOrGetter, toValue } from "vue" +import { RouteLocationRaw } from "vue-router" +import { cloneDeep, isUndefined } from "lodash" + +export type Breadcrumb = { + title?: string + disabled?: boolean + exact?: boolean + to: RouteLocationRaw +} + +// Global state for breadcrumbs +const state = reactive<{ + title?: string + baseCrumb: Breadcrumb + breadcrumbs: Breadcrumb[] + showBackButton: boolean +}>({ + title: "Default", + baseCrumb: { + title: "Dashboard", + to: { + name: "DashboardPage", + }, + }, + breadcrumbs: [], + showBackButton: false, +}) + +// TODO: Consider supporting config option for setting base crumb? +export function useBreadcrumbs( + title?: MaybeRefOrGetter, + breadcrumbs?: MaybeRefOrGetter, + options?: MaybeRefOrGetter<{ + baseCrumb?: Breadcrumb + }>, + isGrounded?: MaybeRefOrGetter, + showBackButton?: MaybeRefOrGetter +) { + watch( + () => toValue(title), + (newTitle) => { + if (isUndefined(newTitle)) return + + state.title = newTitle + }, + { + immediate: true, + } + ) + + watch( + () => toValue(showBackButton), + (newShowBackButton) => { + state.showBackButton = newShowBackButton ?? false + }, + { + immediate: true, + } + ) + + watch( + () => cloneDeep(toValue(breadcrumbs)), + (newBreadcrumbs) => { + if (isUndefined(newBreadcrumbs)) return + + state.breadcrumbs = [state.baseCrumb, ...newBreadcrumbs] + }, + { + immediate: true, + deep: true, + } + ) + + watch( + () => cloneDeep(toValue(options)), + (newOptions) => { + if (isUndefined(newOptions)) return + + if (!isUndefined(newOptions.baseCrumb)) { + state.baseCrumb = newOptions.baseCrumb + } + }, + { + immediate: true, + deep: true, + } + ) + + return { + ...toRefs(state), + } +} + +export default useBreadcrumbs diff --git a/web/src/use/use-current-user.ts b/web/src/use/use-current-user.ts new file mode 100644 index 0000000..cf8597e --- /dev/null +++ b/web/src/use/use-current-user.ts @@ -0,0 +1,74 @@ +import { computed, reactive, toRefs } from "vue" +import { DateTime } from "luxon" + +import currentUserApi, { UserRoles, type UserAsShow } from "@/api/current-user-api" + +export { UserRoles, type UserAsShow } + +// TODO: consider sending this with every api request? +export const CURRENT_USERS_TIMEZONE = DateTime.local().zoneName + +// Global state +const state = reactive<{ + currentUser: UserAsShow | null + isLoading: boolean + isErrored: boolean + isCached: boolean +}>({ + currentUser: null, + isLoading: false, + isErrored: false, + isCached: false, +}) + +type State = typeof state +type LoadedState = Omit & { + currentUser: Exclude +} + +export function useCurrentUser() { + type StateOrLoadedState = IsLoaded extends true ? LoadedState : State + + const isReady = computed(() => state.isCached && !state.isLoading && !state.isErrored) + + const isSystemAdmin = computed(() => { + return state.currentUser?.roles.includes(UserRoles.SYSTEM_ADMIN) + }) + + async function fetch(): Promise { + state.isLoading = true + try { + const { user } = await currentUserApi.get() + state.isErrored = false + state.currentUser = user + state.isCached = true + return user + } catch (error) { + console.error("Failed to fetch current user:", error) + state.isErrored = true + throw error + } finally { + state.isLoading = false + } + } + + // Needs to be called during logout or current user will persist. + function reset() { + state.currentUser = null + state.isLoading = false + state.isErrored = false + state.isCached = false + } + + return { + ...toRefs(state as StateOrLoadedState), + isReady, + fetch, + refresh: fetch, + reset, + // helpers + isSystemAdmin, + } +} + +export default useCurrentUser diff --git a/web/src/use/use-interface.ts b/web/src/use/use-interface.ts new file mode 100644 index 0000000..17f169f --- /dev/null +++ b/web/src/use/use-interface.ts @@ -0,0 +1,46 @@ +import { reactive, toRefs, watch } from "vue" + +// Global state for breadcrumbs +const state = reactive<{ + sidebarDrawer: boolean + sidebarMini: boolean +}>({ + sidebarDrawer: false, + sidebarMini: false, +}) + +/* watch( + state, + (newValue) => { + console.log("Sidebar drawer state changed:", newValue) + }, + { deep: true } +) */ + +export function useInterface() { + function setSidebarDrawer(value: boolean) { + state.sidebarDrawer = value + } + + function setSidebarMini(value: boolean) { + state.sidebarMini = value + } + + function toggleSidebarDrawer() { + state.sidebarDrawer = !state.sidebarDrawer + } + + function toggleSidebarMini() { + state.sidebarMini = !state.sidebarMini + } + + return { + ...toRefs(state), + setSidebarDrawer, + setSidebarMini, + toggleSidebarDrawer, + toggleSidebarMini, + } +} + +export default useInterface diff --git a/web/src/use/use-notifications.ts b/web/src/use/use-notifications.ts new file mode 100644 index 0000000..78f9f5c --- /dev/null +++ b/web/src/use/use-notifications.ts @@ -0,0 +1,71 @@ +import { type Ref, reactive, toRefs, ref, unref, watch } from "vue" + +import notificationsApi, { + NotificationSourceTypes, + type Notification, + type NotificationWhereOptions, + type NotificationFiltersOptions, +} from "@/api/notifications-api" + +export { + NotificationSourceTypes, + type Notification, + type NotificationWhereOptions, + type NotificationFiltersOptions, +} + +export function useNotifications( + queryOptions: Ref<{ + where?: Record + page?: number + perPage?: number + }> = ref({}), + { skipWatchIf = () => false }: { skipWatchIf?: () => boolean } = {} +) { + const state = reactive<{ + notifications: Notification[] + totalCount: number + isLoading: boolean + isErrored: boolean + }>({ + notifications: [], + totalCount: 0, + isLoading: false, + isErrored: false, + }) + + async function fetch(): Promise { + state.isLoading = true + try { + const { notifications, totalCount } = await notificationsApi.list(unref(queryOptions)) + state.isErrored = false + state.notifications = notifications + state.totalCount = totalCount + return notifications + } catch (error) { + console.error("Failed to fetch notifications:", error) + state.isErrored = true + throw error + } finally { + state.isLoading = false + } + } + + watch( + () => unref(queryOptions), + async () => { + if (skipWatchIf()) return + + await fetch() + }, + { deep: true, immediate: true } + ) + + return { + ...toRefs(state), + fetch, + refresh: fetch, + } +} + +export default useNotifications diff --git a/web/src/use/use-snack.ts b/web/src/use/use-snack.ts new file mode 100644 index 0000000..fa319b7 --- /dev/null +++ b/web/src/use/use-snack.ts @@ -0,0 +1,69 @@ +import { reactive, toRef, ToRef } from "vue" +import { VSnackbar } from "vuetify/components" + +type VSnackbarProps = VSnackbar["$props"] + +const state = reactive<{ + message: string + options: VSnackbarProps +}>({ + message: "", + options: {}, +}) + +/** + * @example + * const snack = useSnack() + * snack("Hello world", { color: "success" }) + * + * @example + * const snack = useSnack() + * snack.success("Hello world") + */ +export function useSnack(defaultOptions: VSnackbarProps = {}): { + (message: string, options?: VSnackbarProps): void + message: ToRef + options: ToRef + notify: (message: string, options?: VSnackbarProps) => void + reset: () => void + success: (message: string, options?: VSnackbarProps) => void + error: (message: string, options?: VSnackbarProps) => void + info: (message: string, options?: VSnackbarProps) => void + warning: (message: string, options?: VSnackbarProps) => void +} { + const notify = (message: string, options: VSnackbarProps = {}) => { + state.message = message + state.options = { ...defaultOptions, ...options } + } + + notify.message = toRef(state, "message") + notify.options = toRef(state, "options") + + notify.notify = notify + + notify.reset = () => { + state.message = "" + state.options = {} + } + + notify.success = (message: string, options: VSnackbarProps = {}) => { + notify(message, { color: "success", ...options }) + } + + notify.error = (message: string, options: VSnackbarProps = {}) => { + notify(message, { color: "error", ...options }) + } + + notify.info = (message: string, options: VSnackbarProps = {}) => { + notify(message, { color: "info", ...options }) + } + + notify.warning = (message: string, options: VSnackbarProps = {}) => { + notify(message, { color: "warning", ...options }) + } + + // @ts-expect-error - VSnackbarProps definition is probably not infinte + return notify +} + +export default useSnack diff --git a/web/src/use/use-status.ts b/web/src/use/use-status.ts new file mode 100644 index 0000000..ee5ff89 --- /dev/null +++ b/web/src/use/use-status.ts @@ -0,0 +1,47 @@ +import { reactive, toRefs } from "vue" + +import statusApi, { type Status } from "@/api/status-api" + +export { type Status } + +export function useStatus() { + const state = reactive<{ + releaseTag: null | string + gitCommitHash: null | string + isLoading: boolean + isErrored: boolean + }>({ + releaseTag: null, + gitCommitHash: null, + isLoading: false, + isErrored: false, + }) + + async function fetch(): Promise { + state.isLoading = true + try { + const status = await statusApi.get() + state.isErrored = false + state.releaseTag = status.RELEASE_TAG + state.gitCommitHash = status.GIT_COMMIT_HASH + return status + } catch (error) { + console.error("Failed to fetch status:", error) + state.isErrored = true + throw error + } finally { + state.isLoading = false + } + } + + // Fetch status immediately + fetch() + + return { + ...toRefs(state), + fetch, + refresh: fetch, + } +} + +export default useStatus diff --git a/web/src/use/use-user.ts b/web/src/use/use-user.ts new file mode 100644 index 0000000..76effb3 --- /dev/null +++ b/web/src/use/use-user.ts @@ -0,0 +1,113 @@ +import { type Ref, reactive, toRefs, unref, watch } from "vue" +import { isNil } from "lodash" + +import { type Policy } from "@/api/base-api" +import usersApi, { type User } from "@/api/users-api" + +export { type User } + +export function useUser(id: Ref) { + const state = reactive<{ + user: User | null + policy: Policy | null + isLoading: boolean + isErrored: boolean + }>({ + user: null, + policy: null, + isLoading: false, + isErrored: false, + }) + + async function fetch(): Promise { + const staticId = unref(id) + if (isNil(staticId)) { + throw new Error("id is required") + } + + state.isLoading = true + try { + const { user, policy } = await usersApi.get(staticId) + state.isErrored = false + state.user = user + state.policy = policy + return user + } catch (error) { + console.error("Failed to fetch user:", error) + state.isErrored = true + throw error + } finally { + state.isLoading = false + } + } + + async function save(): Promise { + const staticId = unref(id) + if (isNil(staticId)) { + throw new Error("id is required") + } + + if (isNil(state.user)) { + throw new Error("No user to save") + } + + state.isLoading = true + try { + const { user } = await usersApi.update(staticId, state.user) + state.isErrored = false + state.user = user + return user + } catch (error) { + console.error("Failed to save user:", error) + state.isErrored = true + throw error + } finally { + state.isLoading = false + } + } + + async function directorySync() { + const staticId = unref(id) + if (isNil(staticId)) { + throw new Error("id is required") + } + + if (isNil(state.user)) { + throw new Error("No user to save") + } + + state.isLoading = true + try { + const { user } = await usersApi.directorySync(staticId) + state.isErrored = false + state.user = user + return user + } catch (error) { + console.error("Failed to sync user:", error) + state.isErrored = true + throw error + } finally { + state.isLoading = false + } + } + + watch( + () => unref(id), + async (newId) => { + if (isNil(newId)) return + + await fetch() + }, + { immediate: true } + ) + + return { + ...toRefs(state), + fetch, + refresh: fetch, + save, + directorySync, + } +} + +export default useUser diff --git a/web/src/use/use-users.ts b/web/src/use/use-users.ts new file mode 100644 index 0000000..8660299 --- /dev/null +++ b/web/src/use/use-users.ts @@ -0,0 +1,62 @@ +import { type Ref, reactive, toRefs, ref, unref, watch } from "vue" + +import usersApi, { + type User, + type UserWhereOptions, + type UserFiltersOptions, + type UserQueryOptions, +} from "@/api/users-api" + +export { type User, type UserWhereOptions, type UserFiltersOptions, type UserQueryOptions } + +export function useUsers( + queryOptions: Ref = ref({}), + { skipWatchIf = () => false }: { skipWatchIf?: () => boolean } = {} +) { + const state = reactive<{ + users: User[] + totalCount: number + isLoading: boolean + isErrored: boolean + }>({ + users: [], + totalCount: 0, + isLoading: false, + isErrored: false, + }) + + async function fetch(): Promise { + state.isLoading = true + try { + const { users, totalCount } = await usersApi.list(unref(queryOptions)) + state.isErrored = false + state.users = users + state.totalCount = totalCount + return users + } catch (error) { + console.error("Failed to fetch users:", error) + state.isErrored = true + throw error + } finally { + state.isLoading = false + } + } + + watch( + () => [skipWatchIf(), unref(queryOptions)], + async ([skip]) => { + if (skip) return + + await fetch() + }, + { deep: true, immediate: true } + ) + + return { + ...toRefs(state), + fetch, + refresh: fetch, + } +} + +export default useUsers diff --git a/web/src/use/utils/use-page-title.ts b/web/src/use/utils/use-page-title.ts new file mode 100644 index 0000000..ab469b8 --- /dev/null +++ b/web/src/use/utils/use-page-title.ts @@ -0,0 +1,22 @@ +import { MaybeRefOrGetter, ref, toValue, watch } from "vue" +import { isNil, isEmpty } from "lodash" + +import { APPLICATION_NAME } from "@/config" + +export function usePageTitle(title: MaybeRefOrGetter = ref(null)) { + watch( + () => toValue(title), + (newTitle) => { + if (!isNil(newTitle) && !isEmpty(newTitle)) { + document.title = `${APPLICATION_NAME} - ${newTitle}` + } else { + document.title = APPLICATION_NAME + } + }, + { + immediate: true, + } + ) +} + +export default usePageTitle diff --git a/web/src/use/utils/use-route-query-enhanced.ts b/web/src/use/utils/use-route-query-enhanced.ts new file mode 100644 index 0000000..13981aa --- /dev/null +++ b/web/src/use/utils/use-route-query-enhanced.ts @@ -0,0 +1,32 @@ +import { computed, MaybeRefOrGetter, Ref } from "vue" +import { useRouteQuery } from "@vueuse/router" +import { RouteParamValueRaw } from "vue-router" + +type RouteQueryValueRaw = RouteParamValueRaw | string[] + +/** + * Enhanced useRouteQuery with parse and stringify transformations + * + * See https://github.com/vueuse/vueuse/blob/0f11df11962f5f2e912d66c8544bc6767630780a/packages/router/useRouteQuery/index.ts + */ +export function useRouteQueryEnhanced( + name: string, + defaultValue: MaybeRefOrGetter, + options: { + parse: (value: T) => K + stringify: (value: K) => T + } +): Ref { + const query = useRouteQuery(name, defaultValue) + + return computed({ + get() { + return options.parse(query.value) + }, + set(value: K) { + query.value = options.stringify(value) + }, + }) +} + +export default useRouteQueryEnhanced diff --git a/web/src/use/utils/use-route-query-pagination.ts b/web/src/use/utils/use-route-query-pagination.ts new file mode 100644 index 0000000..5371095 --- /dev/null +++ b/web/src/use/utils/use-route-query-pagination.ts @@ -0,0 +1,41 @@ +import { useRouteQuery } from "@vueuse/router" + +import { integerTransformer } from "@/utils/use-route-query-transformers" + +const DEFAULT_PAGE = 1 +const DEFAULT_PER_PAGE = 10 + +/** + * Usage: use in conjunction with EnhancedPagination component. + * @param {Object} [options] - Options object. + * @param {number} [options.page=1] - Initial page number. Default is 1. + * @param {number} [options.perPage=10] - Initial items per page. Default is 10. + */ +export function useRouteQueryPagination({ + page = DEFAULT_PAGE, + perPage = DEFAULT_PER_PAGE, + routeQuerySuffix = "", +}: { + page?: number + perPage?: number + routeQuerySuffix?: string +} = {}) { + const queryPage = useRouteQuery(`page${routeQuerySuffix}`, page.toString(), { + transform: integerTransformer, + }) + + const queryPerPage = useRouteQuery( + `perPage${routeQuerySuffix}`, + perPage.toString(), + { + transform: integerTransformer, + } + ) + + return { + page: queryPage, + perPage: queryPerPage, + } +} + +export default useRouteQueryPagination diff --git a/web/src/use/utils/use-vuetify-color-classes-as-specific-color-classes.ts b/web/src/use/utils/use-vuetify-color-classes-as-specific-color-classes.ts new file mode 100644 index 0000000..152f2bc --- /dev/null +++ b/web/src/use/utils/use-vuetify-color-classes-as-specific-color-classes.ts @@ -0,0 +1,25 @@ +import { computed, Ref, toValue } from "vue" +import { isNil, isEmpty } from "lodash" + +/** + * Returns a computed ref that returns a specific color class based on the provided color classes. + * Given + * "red" could be used produce "text-red" or "bg-red" or "border-red" + */ +export function useVuetifyColorClassesAsSpecificColorClasses( + colorClasses: Ref, + prefix: string = "text" +) { + const textColorClass = computed(() => { + const colorClassesValues = toValue(colorClasses) + if (isNil(colorClassesValues)) return "" + if (isEmpty(colorClassesValues)) return "" + + const normalizedClass = colorClassesValues.split(" ").join("-") + return `${prefix}-${normalizedClass}` + }) + + return textColorClass +} + +export default useVuetifyColorClassesAsSpecificColorClasses diff --git a/web/src/use/utils/use-vuetify-color-name-to-hex-value.ts b/web/src/use/utils/use-vuetify-color-name-to-hex-value.ts new file mode 100644 index 0000000..b951904 --- /dev/null +++ b/web/src/use/utils/use-vuetify-color-name-to-hex-value.ts @@ -0,0 +1,12 @@ +import { useTheme } from "vuetify" + +/** + * Useful for setting the color of a tabler icon. + */ +export function useVuetifyColorNameToHexValue(colorName: string) { + const theme = useTheme() + + return theme.current.value.colors[colorName] +} + +export default useVuetifyColorNameToHexValue diff --git a/web/src/use/utils/use-vuetify-slot-names-pass-through.ts b/web/src/use/utils/use-vuetify-slot-names-pass-through.ts new file mode 100644 index 0000000..7c220ae --- /dev/null +++ b/web/src/use/utils/use-vuetify-slot-names-pass-through.ts @@ -0,0 +1,26 @@ +import { ComputedRef, computed, useSlots } from "vue" + +type ComponentWithSlots = { + $slots: { + [key: string]: unknown + } +} + +type SlotNamesExtractor = T extends ComponentWithSlots ? keyof T["$slots"] & string : never + +export function useVuetifySlotNamesPassThrough< + Component extends ComponentWithSlots = never, + SlotNames extends SlotNamesExtractor = SlotNamesExtractor, +>(slotsToPassThrough: SlotNames[]): ComputedRef { + const wrappedSlotNames = new Set(slotsToPassThrough) + + const slots = useSlots() + + return computed(() => { + return Object.keys(slots).filter((slotName): slotName is SlotNames => + wrappedSlotNames.has(slotName as SlotNames) + ) + }) +} + +export default useVuetifySlotNamesPassThrough diff --git a/web/src/use/utils/use-vuetify-sort-by-to-safe-route-query.ts b/web/src/use/utils/use-vuetify-sort-by-to-safe-route-query.ts new file mode 100644 index 0000000..03d6508 --- /dev/null +++ b/web/src/use/utils/use-vuetify-sort-by-to-safe-route-query.ts @@ -0,0 +1,53 @@ +import { isEmpty, isNil, isString } from "lodash" +import { Ref } from "vue" + +import { VDataTable } from "vuetify/components" + +import useRouteQueryEnhanced from "@/use/utils/use-route-query-enhanced" + +export type SortItem = VDataTable["sortBy"][0] + +/** + * Must not conflict with web/src/use/utils/use-vuetify-sort-by-to-sequelize-safe-order.ts SEPARATOR. + */ +const SEPARATOR = "_" + +export function useVuetifySortByToSafeRouteQuery( + name: string, + defaultValue?: SortItem[] | undefined +): Ref { + function parse(newSortBy: string[] | string | undefined): SortItem[] | undefined { + if (isNil(newSortBy) || isEmpty(newSortBy)) { + return + } + + if (isString(newSortBy)) { + newSortBy = [newSortBy] + } + + return newSortBy.map((entry) => { + const [key, order] = entry.split(SEPARATOR) + return { key, order } as SortItem + }) + } + + function stringify(sortByValue: SortItem[] | undefined): string[] | undefined { + if (isNil(sortByValue) || isEmpty(sortByValue)) { + return + } + + return sortByValue.map(({ key, order }) => `${key}${SEPARATOR}${order}`) + } + + const defaultValueString = stringify(defaultValue) + return useRouteQueryEnhanced( + name, + defaultValueString, + { + parse, + stringify, + } + ) +} + +export default useVuetifySortByToSafeRouteQuery diff --git a/web/src/use/utils/use-vuetify-sort-by-to-sequelize-safe-order.ts b/web/src/use/utils/use-vuetify-sort-by-to-sequelize-safe-order.ts new file mode 100644 index 0000000..558925b --- /dev/null +++ b/web/src/use/utils/use-vuetify-sort-by-to-sequelize-safe-order.ts @@ -0,0 +1,61 @@ +import { isEmpty, isNil } from "lodash" +import { computed, ComputedRef, Ref, toValue } from "vue" + +import { type ModelOrder } from "@/api/base-api" +import { type SortItem } from "@/use/utils/use-vuetify-sort-by-to-safe-route-query" + +/** + * Must not conflict with web/src/use/utils/use-vuetify-sort-by-to-safe-route-query.ts SEPARATOR + */ +const SEPARATOR = "." + +/** + * Converts content of the form [ + * { key: "attribute", order: "asc" }, + * { key: "attribute", order: "desc" }, + * { key: "nested.associated.attribute", order: "asc" }, + * { key: "nested.associated.attribute", order: "desc" }, + * ] + * + * to the form [ + * [ "attribute", "ASC" ], + * [ "attribute", "DESC" ], + * [ "nested", "associated", "attribute", "ASC" ], + * [ "nested", "associated", "attribute", "DESC" ], + * ] + */ +export function useVuetifySortByToSequelizeSafeOrder( + sortBy: Ref +): ComputedRef { + const order = computed(() => { + const sortByValue = toValue(sortBy) + if (isNil(sortByValue) || isEmpty(sortByValue)) { + return undefined + } + + return sortByValue.map(({ key: column, order }) => { + let direction: "ASC" | "DESC" = "ASC" + if (order === true) { + direction = "ASC" + } else if (order === false) { + direction = "DESC" + } else if (order === "desc") { + direction = "DESC" + } else if (order === "asc") { + direction = "ASC" + } + + const nestedAssociatedModelAttributes = column.split(SEPARATOR) as + | [string, string] + | [string, string, string] + | [string, string, string, string] + | [string, string, string, string, string] + + return [...nestedAssociatedModelAttributes, direction] + }) + }) + + return order +} + +export default useVuetifySortByToSequelizeSafeOrder diff --git a/web/src/utils/authorization-guards/authorization-guard.ts b/web/src/utils/authorization-guards/authorization-guard.ts new file mode 100644 index 0000000..ad34b8f --- /dev/null +++ b/web/src/utils/authorization-guards/authorization-guard.ts @@ -0,0 +1,37 @@ +import { type RouteLocationNormalized } from "vue-router" +import { isEmpty, isNil } from "lodash" + +import useCurrentUser, { type UserAsShow } from "@/use/use-current-user" + +export async function authorizationGuard(to: RouteLocationNormalized) { + const guardGroups = to.matched + .map((record) => record.meta.guards as ((user: UserAsShow) => boolean)[] | undefined) + .filter((g): g is ((user: UserAsShow) => boolean)[] => !isNil(g) && !isEmpty(g)) + + if (guardGroups.length === 0) return true + + const { currentUser, fetch } = useCurrentUser() + if (isNil(currentUser.value)) { + await fetch() + } + + if (isNil(currentUser.value)) { + throw new Error("No current user") + } + + // AND across matched records (every level must pass), OR within each + // record's guards array (any guard at that level satisfies it). + for (const guards of guardGroups) { + const passes = guards.some((guard) => { + if (typeof guard !== "function") { + throw new Error(`Guard ${guard} is not a function`) + } + return guard(currentUser.value as UserAsShow) + }) + if (!passes) return false + } + + return true +} + +export default authorizationGuard diff --git a/web/src/utils/authorization-guards/index.ts b/web/src/utils/authorization-guards/index.ts new file mode 100644 index 0000000..121f9c4 --- /dev/null +++ b/web/src/utils/authorization-guards/index.ts @@ -0,0 +1,2 @@ +export { authorizationGuard } from "./authorization-guard" +export { isSystemAdmin } from "./user-guards" diff --git a/web/src/utils/authorization-guards/user-guards.ts b/web/src/utils/authorization-guards/user-guards.ts new file mode 100644 index 0000000..b445fb3 --- /dev/null +++ b/web/src/utils/authorization-guards/user-guards.ts @@ -0,0 +1,6 @@ +import { UserRoles } from "@/api/users-api" +import { type UserAsShow } from "@/api/current-user-api" + +export function isSystemAdmin(user: UserAsShow): boolean { + return user.roles.includes(UserRoles.SYSTEM_ADMIN) ?? false +} diff --git a/web/src/utils/debounce-with-args-cache.ts b/web/src/utils/debounce-with-args-cache.ts new file mode 100644 index 0000000..ac25d6a --- /dev/null +++ b/web/src/utils/debounce-with-args-cache.ts @@ -0,0 +1,57 @@ +import { debounce } from "lodash" + +type DebounceableFunction = Parameters["0"] + +/** + * @example + * ``` + * const usersApi = { + * async get(userId, params = {}) { + * console.trace(`usersApi.get: Fetching user: ${userId} with params:`, params) + * const { data } = await http.get(`/api/users/${userId}`, { params }) + * return data + * }, + * } + * + * usersApi.get = debounceWithArgsCache(usersApi.get, 300, 10) + * + * usersApi.get(1, { role: "admin" }) + * usersApi.get(2, { role: "user" }) + * usersApi.get(1, { role: "admin" }) + * setTimeout(() => usersApi.get(1, { role: "admin" }), 400) + * ``` + */ +export function debounceWithArgsCache( + fn: DebounceableFunction, + { + wait = 300, + leading = true, + trailing = true, + cacheSize = 10, + }: { wait?: number; leading?: boolean; trailing?: boolean; cacheSize?: number } +) { + const invocationCache = new Map() + + return (...args: unknown[]) => { + const argsKey = JSON.stringify(args) + + if (invocationCache.has(argsKey)) { + const debouncedFn = invocationCache.get(argsKey) + const result = debouncedFn(...args) + return result + } + + if (invocationCache.size >= cacheSize) { + const oldestInvocation = invocationCache.keys().next().value + invocationCache.delete(oldestInvocation) + } + + const debouncedFn = debounce(fn, wait, { leading, trailing }) + invocationCache.set(argsKey, debouncedFn) + + const result = debouncedFn(...args) + return result + } +} + +export default debounceWithArgsCache diff --git a/web/src/utils/formatters/format-bytes.ts b/web/src/utils/formatters/format-bytes.ts new file mode 100644 index 0000000..3186eb0 --- /dev/null +++ b/web/src/utils/formatters/format-bytes.ts @@ -0,0 +1,13 @@ +export function formatBytes(bytes: number, decimals = 2) { + if (bytes === 0) return "0 Bytes" + + const k = 1024 + const dm = decimals < 0 ? 0 : decimals + const sizes = ["Bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"] + + const i = Math.floor(Math.log(bytes) / Math.log(k)) + + return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + " " + sizes[i] +} + +export default formatBytes diff --git a/web/src/utils/formatters/format-date-long.ts b/web/src/utils/formatters/format-date-long.ts new file mode 100644 index 0000000..eb9f03d --- /dev/null +++ b/web/src/utils/formatters/format-date-long.ts @@ -0,0 +1,21 @@ +import { isNil, isEmpty } from "lodash" +import { DateTime } from "luxon" + +/** + * Note: \u00A0d is a non-breaking space, and permits date to wrap like this: + * November 07, 72024 + * @ 710:21 AM + */ +export function formatDateLong(input: string | Date | undefined): string { + if (isNil(input) || isEmpty(input)) { + return "" + } else if (typeof input == "string") { + return DateTime.fromISO(input).toLocal().toFormat("MMMM\u00A0dd,\u00A0yyyy @\u00A0t") + } else if (input instanceof Date) { + return DateTime.fromJSDate(input).toLocal().toFormat("MMMM\u00A0dd,\u00A0yyyy @\u00A0t") + } else { + return "" + } +} + +export default formatDateLong diff --git a/web/src/utils/formatters/format-date-words.ts b/web/src/utils/formatters/format-date-words.ts new file mode 100644 index 0000000..4e3f111 --- /dev/null +++ b/web/src/utils/formatters/format-date-words.ts @@ -0,0 +1,16 @@ +import { isNil, isEmpty } from "lodash" +import { DateTime } from "luxon" + +export function formatDateWords(input: string | Date | undefined): string { + if (isNil(input) || isEmpty(input)) { + return "" + } else if (typeof input == "string") { + return DateTime.fromISO(input).toLocal().toFormat("MMMM dd, yyyy") + } else if (input instanceof Date) { + return DateTime.fromJSDate(input).toLocal().toFormat("MMMM dd, yyyy") + } else { + return "" + } +} + +export default formatDateWords diff --git a/web/src/utils/formatters/format-date.ts b/web/src/utils/formatters/format-date.ts new file mode 100644 index 0000000..cf6bf2b --- /dev/null +++ b/web/src/utils/formatters/format-date.ts @@ -0,0 +1,18 @@ +import { isNil, isEmpty } from "lodash" +import { DateTime } from "luxon" + +export function formatDate(input: string | Date | undefined): string { + if (isNil(input) || isEmpty(input)) { + return "" + } else if (typeof input == "string") { + const parsed = DateTime.fromISO(input, { zone: "utc" }) + const isMidnight = parsed.hour === 0 && parsed.minute === 0 && parsed.second === 0 + return isMidnight ? parsed.toFormat("yyyy-MM-dd") : parsed.toLocal().toFormat("yyyy-MM-dd") + } else if (input instanceof Date) { + return DateTime.fromJSDate(input).toLocal().toFormat("yyyy-MM-dd") + } else { + return "" + } +} + +export default formatDate diff --git a/web/src/utils/formatters/format-number-in-string-to-fixed-decimal.ts b/web/src/utils/formatters/format-number-in-string-to-fixed-decimal.ts new file mode 100644 index 0000000..755ae23 --- /dev/null +++ b/web/src/utils/formatters/format-number-in-string-to-fixed-decimal.ts @@ -0,0 +1,24 @@ +import { isNil } from "lodash" + +/** + * Extracts the numeric part of a string and formats it to desired decimal places + * + * Ex. -15.030000000000001 Cycles => -15.03 Cycles + * + * NOTE: number of decimals defaults to 2 + */ +export function formatNumberInStringToFixedDecimal( + input: string | null | undefined, + decimals: number = 2 +): string { + if (isNil(input) || decimals < 0) { + console.warn( + `formatNumberInStringToFixedDecimal received invalid input: input=${input}, decimals=${decimals}` + ) + return "" + } + + return input.replace(/([-+]?\d[\d,]*\.?\d*)/, (match) => { + return parseFloat(match.replace(/,/g, "")).toFixed(decimals) + }) +} diff --git a/web/src/utils/formatters/format-relative.ts b/web/src/utils/formatters/format-relative.ts new file mode 100644 index 0000000..7fe65bf --- /dev/null +++ b/web/src/utils/formatters/format-relative.ts @@ -0,0 +1,16 @@ +import { isNil, isEmpty } from "lodash" +import { DateTime } from "luxon" + +export function formatRelative(input: string | Date | undefined): string { + if (isNil(input) || isEmpty(input)) { + return "" + } else if (typeof input == "string") { + return DateTime.fromISO(input).toLocal().toRelative() ?? "" + } else if (input instanceof Date) { + return DateTime.fromJSDate(input).toLocal().toRelative() ?? "" + } else { + return "" + } +} + +export default formatRelative diff --git a/web/src/utils/formatters/index.ts b/web/src/utils/formatters/index.ts new file mode 100644 index 0000000..60a99f3 --- /dev/null +++ b/web/src/utils/formatters/index.ts @@ -0,0 +1,6 @@ +export { formatBytes } from "./format-bytes" +export { formatDate } from "./format-date" +export { formatDateLong } from "./format-date-long" +export { formatRelative } from "./format-relative" +export { formatDateWords } from "./format-date-words" + diff --git a/web/src/utils/safe-json-parse.ts b/web/src/utils/safe-json-parse.ts new file mode 100644 index 0000000..136f19a --- /dev/null +++ b/web/src/utils/safe-json-parse.ts @@ -0,0 +1,14 @@ +export function safeJsonParse(values: string): unknown | null { + try { + return JSON.parse(values) + } catch (error) { + if (error instanceof SyntaxError) { + return null + } else { + console.warn(`Unexpected json parsing error: ${error}`, { error }) + return null + } + } +} + +export default safeJsonParse diff --git a/web/src/utils/sleep.ts b/web/src/utils/sleep.ts new file mode 100644 index 0000000..0c1353d --- /dev/null +++ b/web/src/utils/sleep.ts @@ -0,0 +1,3 @@ +export function sleep(milliseconds: number) { + return new Promise((resolve) => setTimeout(resolve, milliseconds)) +} diff --git a/web/src/utils/strip-trailing-slash.ts b/web/src/utils/strip-trailing-slash.ts new file mode 100644 index 0000000..94279ee --- /dev/null +++ b/web/src/utils/strip-trailing-slash.ts @@ -0,0 +1,3 @@ +export function stripTrailingSlash(url: string) { + return url.endsWith("/") ? url.slice(0, -1) : url +} diff --git a/web/src/utils/use-route-query-transformers/boolean-transformer.ts b/web/src/utils/use-route-query-transformers/boolean-transformer.ts new file mode 100644 index 0000000..7d927f3 --- /dev/null +++ b/web/src/utils/use-route-query-transformers/boolean-transformer.ts @@ -0,0 +1,22 @@ +import { isNil } from "lodash" + +export const booleanTransformer = { + get(value: boolean | string | null | undefined): boolean { + if (isNil(value)) return false + if (typeof value === "string") { + return value === "true" + } + + return value + }, + set(value: boolean | string | null | undefined): string { + if (isNil(value)) return "false" + if (typeof value === "boolean") { + return value.toString() + } + + return value + }, +} + +export default booleanTransformer diff --git a/web/src/utils/use-route-query-transformers/index.ts b/web/src/utils/use-route-query-transformers/index.ts new file mode 100644 index 0000000..23590a6 --- /dev/null +++ b/web/src/utils/use-route-query-transformers/index.ts @@ -0,0 +1,4 @@ +export { booleanTransformer } from "./boolean-transformer" +export { integerTransformer } from "./integer-transformer" +export { integerTransformerLegacy } from "./integer-transformer-legacy" +export { stringTransformer } from "./string-transformer" diff --git a/web/src/utils/use-route-query-transformers/integer-transformer-legacy.ts b/web/src/utils/use-route-query-transformers/integer-transformer-legacy.ts new file mode 100644 index 0000000..2faa83a --- /dev/null +++ b/web/src/utils/use-route-query-transformers/integer-transformer-legacy.ts @@ -0,0 +1,9 @@ +import { isNil } from "lodash" + +export function integerTransformerLegacy(value: string | null | undefined): number | null { + if (isNil(value)) return null + + return parseInt(value) +} + +export default integerTransformerLegacy diff --git a/web/src/utils/use-route-query-transformers/integer-transformer.ts b/web/src/utils/use-route-query-transformers/integer-transformer.ts new file mode 100644 index 0000000..d41c9a2 --- /dev/null +++ b/web/src/utils/use-route-query-transformers/integer-transformer.ts @@ -0,0 +1,27 @@ +import { isNil } from "lodash" + +function integerGet( + value: T +): number | (T & undefined) | (T & null) { + if (isNil(value)) return value + if (typeof value === "number") return value + + return parseInt(value, 10) +} + +function integerSet( + value: T +): string | (T & undefined) | (T & null) { + if (isNil(value)) return value + if (typeof value === "number") return value.toString() + if (typeof value === "string") return value + + return "" +} + +export const integerTransformer = { + get: integerGet, + set: integerSet, +} as const + +export default integerTransformer diff --git a/web/src/utils/use-route-query-transformers/string-transformer.ts b/web/src/utils/use-route-query-transformers/string-transformer.ts new file mode 100644 index 0000000..761923e --- /dev/null +++ b/web/src/utils/use-route-query-transformers/string-transformer.ts @@ -0,0 +1,16 @@ +import { isNil } from "lodash" + +export const stringTransformer = { + get(value: string | null | undefined) { + if (isNil(value)) return "" + + return value + }, + set(value: string | null | undefined) { + if (isNil(value)) return "" + + return value + }, +} + +export default stringTransformer diff --git a/web/src/utils/utility-types.ts b/web/src/utils/utility-types.ts new file mode 100644 index 0000000..5219ce9 --- /dev/null +++ b/web/src/utils/utility-types.ts @@ -0,0 +1,5 @@ +export type VueHtmlClass = string | Record | (string | Record)[] + +export type SetIntersection = { + [K in keyof T[number]]: K extends keyof T[0] ? Extract : never +} diff --git a/web/src/utils/validators/email.ts b/web/src/utils/validators/email.ts new file mode 100644 index 0000000..2eca2d3 --- /dev/null +++ b/web/src/utils/validators/email.ts @@ -0,0 +1,7 @@ +import isEmail from "validator/lib/isEmail" + +export function email(value: string) { + if (isEmail(value)) return true + + return "Invalid email" +} diff --git a/web/src/utils/validators/index.ts b/web/src/utils/validators/index.ts new file mode 100644 index 0000000..d628dcc --- /dev/null +++ b/web/src/utils/validators/index.ts @@ -0,0 +1,4 @@ +export { email } from "./email" +export { minimum } from "./minimum" +export { required } from "./required" +export { requiredFile } from "./required-file" diff --git a/web/src/utils/validators/minimum.ts b/web/src/utils/validators/minimum.ts new file mode 100644 index 0000000..0330c7a --- /dev/null +++ b/web/src/utils/validators/minimum.ts @@ -0,0 +1,13 @@ +import { isString } from "lodash" + +export function minimum(length: number) { + return (v: unknown): boolean | string => { + if (isString(v) && v.length < length) { + return `Must be at least ${length} characters` + } + + return true + } +} + +export default minimum diff --git a/web/src/utils/validators/required-file.ts b/web/src/utils/validators/required-file.ts new file mode 100644 index 0000000..1d7d583 --- /dev/null +++ b/web/src/utils/validators/required-file.ts @@ -0,0 +1,20 @@ +export function requiredFile(v: unknown): boolean | string { + // Handle File object + if (v instanceof File) { + return true + } + + // Handle null or undefined + if (v === null || v === undefined) { + return "File is required" + } + + // Handle empty array (when file input is cleared) + if (Array.isArray(v) && v.length === 0) { + return "File is required" + } + + return "File is required" +} + +export default requiredFile diff --git a/web/src/utils/validators/required.ts b/web/src/utils/validators/required.ts new file mode 100644 index 0000000..8391522 --- /dev/null +++ b/web/src/utils/validators/required.ts @@ -0,0 +1,15 @@ +import { isArray, isEmpty, isString, isNull, isObject, isUndefined } from "lodash" + +export function required(v: unknown): boolean | string { + if (isNull(v) || isUndefined(v)) { + return "This field is required" + } + + if ((isArray(v) || isString(v) || isObject(v)) && isEmpty(v)) { + return "This field is required" + } + + return true +} + +export default required diff --git a/web/src/vite-env.d.ts b/web/src/vite-env.d.ts new file mode 100644 index 0000000..11f02fe --- /dev/null +++ b/web/src/vite-env.d.ts @@ -0,0 +1 @@ +/// diff --git a/web/tests/setup.ts b/web/tests/setup.ts new file mode 100644 index 0000000..55b92b1 --- /dev/null +++ b/web/tests/setup.ts @@ -0,0 +1,7 @@ +import { mockHttpClient } from "@/tests/support/mock-http-client" +import { mockCurrentUserApi } from "@/tests/support/mock-current-user-api" + +beforeEach(() => { + mockHttpClient() + mockCurrentUserApi() +}) diff --git a/web/tests/support/index.ts b/web/tests/support/index.ts new file mode 100644 index 0000000..16dc4b1 --- /dev/null +++ b/web/tests/support/index.ts @@ -0,0 +1,2 @@ +export { mockCurrentUserApi } from "./mock-current-user-api" +export { mockHttpClient } from "./mock-http-client" diff --git a/web/tests/support/mock-current-user-api.ts b/web/tests/support/mock-current-user-api.ts new file mode 100644 index 0000000..a9da4f6 --- /dev/null +++ b/web/tests/support/mock-current-user-api.ts @@ -0,0 +1,54 @@ +import { merge } from "lodash" + +import { type Policy } from "@/api/base-api" +import currentUserApi, { type UserAsShow } from "@/api/current-user-api" + +export const DEFAULT_USER: UserAsShow = { + id: 1, + email: "default-mock-user@example.com", + firstName: null, + lastName: null, + displayName: null, + title: null, + isActive: true, + emailNotificationsEnabled: true, + createdAt: "1970-01-01T00:00:00.000Z", + updatedAt: "1970-01-01T00:00:00.000Z", +} +export const DEFAULT_POLICY: Policy = { + show: true, + create: false, + update: true, + destroy: false, +} + +/** + * Usage: + * At the top section of a test file import: + * import { mockCurrentUserApi } from "@/tests/support" + * + * Then where you want to set the current user: + * mockCurrentUserApi({ user, policy }) + * + * Note that all values for user and policy are optional as minium safe defaults are provided. + * Note that order of operations matters. This file must be imported before any file that imports currentUserApi. + * As such this file has been imported and mocked in the pre-test run "web/tests/setup.ts" file. + * + * @param currentUserApiGetResponseWithDefaults - The response to set for the current user + */ +export function mockCurrentUserApi( + currentUserApiGetResponseWithDefaults: { user?: UserAsShow; policy?: Policy } = {} +) { + vi.mock("@/api/current-user-api") + + const userWithDefaults = merge({}, DEFAULT_USER, currentUserApiGetResponseWithDefaults.user) + const policyWithDefaults = merge({}, DEFAULT_POLICY, currentUserApiGetResponseWithDefaults.policy) + + const mockedCurrentUserApi = vi.mocked(currentUserApi, true) + mockedCurrentUserApi.get.mockResolvedValue({ + user: userWithDefaults, + policy: policyWithDefaults, + }) +} + +export default mockCurrentUserApi diff --git a/web/tests/support/mock-http-client.ts b/web/tests/support/mock-http-client.ts new file mode 100644 index 0000000..330a79f --- /dev/null +++ b/web/tests/support/mock-http-client.ts @@ -0,0 +1,40 @@ +import httpClient from "@/api/http-client" + +vi.mock("@/api/http-client") + +/** + * Usage: + * At the top section of a test file import: + * import { mockHttpClient } from "@/tests/support" + * + * Then where you want to set the http client: + * mockHttpClient() + * + * Note that order of operations matters. This file must be imported before any file that imports httpClient. + * As such this file has been imported and mocked in the pre-test run "web/tests/setup.ts" file. + * + * @returns The mocked http client + */ +export function mockHttpClient() { + const httpClientMock = vi.mocked(httpClient, true) + + httpClientMock.get.mockResolvedValue({ + data: {}, + }) + httpClientMock.post.mockResolvedValue({ + data: {}, + }) + httpClientMock.put.mockResolvedValue({ + data: {}, + }) + httpClientMock.patch.mockResolvedValue({ + data: {}, + }) + httpClientMock.delete.mockResolvedValue({ + data: {}, + }) + + return httpClientMock +} + +export default mockHttpClient diff --git a/web/tests/tsconfig.json b/web/tests/tsconfig.json new file mode 100644 index 0000000..4e08243 --- /dev/null +++ b/web/tests/tsconfig.json @@ -0,0 +1,12 @@ +{ + "extends": "./../tsconfig.json", + "compilerOptions": { + "baseUrl": "./../", + "types": ["vitest/globals"], + "paths": { + "@/tests/*": ["./tests/*"], + "@/*": ["./src/*"] + } + }, + "include": ["../src/**/*", "../tests/**/*", ""] +} diff --git a/web/tests/utils/authorization-guards/authorization-guard.test.ts b/web/tests/utils/authorization-guards/authorization-guard.test.ts new file mode 100644 index 0000000..09ad5c9 --- /dev/null +++ b/web/tests/utils/authorization-guards/authorization-guard.test.ts @@ -0,0 +1,41 @@ +import { type RouteLocationNormalized } from "vue-router" + +import authorizationGuard from "@/utils/authorization-guards/authorization-guard" + +describe("web/src/utils/authorization-guards/authorization-guard.ts", () => { + describe("authorizationGuard", () => { + test("when there are no guards, returns true", async () => { + const to = { + meta: {}, + } as unknown as RouteLocationNormalized + + const result = await authorizationGuard(to) + + expect(result).toBe(true) + }) + + test("when all guards return true, returns true", async () => { + const to = { + meta: { + guards: [() => true, () => true, () => true], + }, + } as unknown as RouteLocationNormalized + + const result = await authorizationGuard(to) + + expect(result).toBe(true) + }) + + test("when any guard returns false, returns false", async () => { + const to = { + meta: { + guards: [() => true, () => false, () => true], + }, + } as unknown as RouteLocationNormalized + + const result = await authorizationGuard(to) + + expect(result).toBe(false) + }) + }) +}) diff --git a/web/tsconfig.json b/web/tsconfig.json new file mode 100644 index 0000000..416ec29 --- /dev/null +++ b/web/tsconfig.json @@ -0,0 +1,29 @@ +{ + "compilerOptions": { + "allowJs": true, + "target": "ESNext", + "useDefineForClassFields": true, + "module": "ESNext", + "moduleResolution": "Node", + "strict": true, + "jsx": "preserve", + "resolveJsonModule": true, + "isolatedModules": true, + "esModuleInterop": true, + "lib": ["ESNext", "DOM"], + "skipLibCheck": true, + "noEmit": true, + "paths": { + "@/*": ["./src/*", "./dist/*"] + } + }, + "include": [ + "src/**/*.ts", + "src/**/*.d.ts", + "src/**/*.tsx", + "src/**/*.vue", + "src/**/*.js", + ".eslintrc.cjs" + ], + "references": [{ "path": "./tsconfig.node.json" }] +} diff --git a/web/tsconfig.node.json b/web/tsconfig.node.json new file mode 100644 index 0000000..77ae975 --- /dev/null +++ b/web/tsconfig.node.json @@ -0,0 +1,11 @@ +{ + "compilerOptions": { + "allowJs": true, + "composite": true, + "module": "ESNext", + "moduleResolution": "Node", + "allowSyntheticDefaultImports": true, + "outDir": "./dist" + }, + "include": ["vite.config.js"] +} diff --git a/web/vite.config.js b/web/vite.config.js new file mode 100644 index 0000000..1c13544 --- /dev/null +++ b/web/vite.config.js @@ -0,0 +1,45 @@ +/// +import { fileURLToPath, URL } from "node:url" + +// Plugins +import vue from "@vitejs/plugin-vue" +import vuetify from "vite-plugin-vuetify" + +// Utilities +import { defineConfig } from "vite" + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [ + vue(), + // https://github.com/vuetifyjs/vuetify-loader/tree/next/packages/vite-plugin + vuetify({ + autoImport: true, + }), + ], + build: { + outDir: "./dist", + }, + define: { "process.env": {} }, + resolve: { + alias: { + "@/tests": fileURLToPath(new URL("./tests", import.meta.url)), + "@": fileURLToPath(new URL("./src", import.meta.url)), + }, + extensions: [".js", ".json", ".jsx", ".mjs", ".ts", ".tsx", ".vue"], + }, + server: { + port: 8080, + }, + test: { + environment: "jsdom", + globals: true, // https://vitest.dev/config/#globals + setupFiles: ["./tests/setup.ts"], + // Mocking + clearMocks: true, + mockReset: true, + restoreMocks: true, + unstubEnvs: true, + unstubGlobals: true, + }, +})