diff --git a/.eslintrc.cjs b/.eslintrc.cjs
index 62f073d..765b225 100644
--- a/.eslintrc.cjs
+++ b/.eslintrc.cjs
@@ -1,19 +1,27 @@
+/* eslint-env node */
+require('@vue/eslint-config-typescript')
+
module.exports = {
root: true,
- env: { browser: true, es2020: true },
+ env: {
+ browser: true,
+ es2020: true,
+ },
extends: [
'eslint:recommended',
'plugin:@typescript-eslint/recommended',
- 'plugin:react-hooks/recommended',
+ 'plugin:vue/vue3-recommended',
+ '@vue/eslint-config-typescript',
],
- ignorePatterns: ['dist', '.eslintrc.cjs'],
- parser: '@typescript-eslint/parser',
- plugins: ['react-refresh'],
+ ignorePatterns: ['dist', '.eslintrc.cjs', '*.config.js'],
+ parser: 'vue-eslint-parser',
+ parserOptions: {
+ parser: '@typescript-eslint/parser',
+ ecmaVersion: 'latest',
+ sourceType: 'module',
+ },
+ plugins: ['@typescript-eslint'],
rules: {
- 'react-refresh/only-export-components': [
- 'warn',
- { allowConstantExport: true },
- ],
+ 'vue/multi-word-component-names': 'off',
},
}
-
diff --git a/README.md b/README.md
index facf1bc..bc14119 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,6 @@
# Browser Vault GUI
-A modern TypeScript/React frontend for HashiCorp Vault. This is an alternative web interface that allows you to connect to multiple Vault servers and manage your secrets.
+A modern Vue 3 + TypeScript frontend for HashiCorp Vault with Tailwind CSS and DaisyUI. This is an alternative web interface that allows you to connect to multiple Vault servers and manage your secrets.
## Features
@@ -142,10 +142,11 @@ Cache can be cleared manually from Settings or programmatically on logout.
## Technology Stack
-- **React 18** - UI framework
-- **TypeScript** - Type safety
-- **Vite** - Build tool and dev server
-- **CSS3** - Styling with CSS custom properties
+- **Vue 3** - Progressive JavaScript framework with Composition API
+- **TypeScript** - Type safety throughout
+- **Tailwind CSS** - Utility-first CSS framework
+- **DaisyUI** - Beautiful component library for Tailwind
+- **Vite** - Lightning-fast build tool and dev server
- **Custom Vault Client** - Browser-compatible Vault HTTP API client with retries, timeouts, and error handling
## Development
@@ -154,12 +155,12 @@ Cache can be cleared manually from Settings or programmatically on logout.
```
src/
-├── components/ # React components
-│ ├── ServerSelector.tsx/css
-│ ├── LoginForm.tsx/css
-│ ├── Dashboard.tsx/css
-│ ├── PathSearch.tsx/css
-│ └── Settings.tsx/css
+├── components/ # Vue 3 components
+│ ├── ServerSelector.vue
+│ ├── LoginForm.vue
+│ ├── Dashboard.vue
+│ ├── PathSearch.vue
+│ └── Settings.vue
├── services/
│ ├── vaultClient.ts # Low-level Vault HTTP API client
│ └── vaultApi.ts # High-level API with caching
@@ -167,17 +168,21 @@ src/
│ └── cache.ts # Cache management system
├── types.ts # TypeScript type definitions
├── config.ts # Application configuration
-├── App.tsx/css # Main application component
-├── main.tsx # Application entry point
-└── index.css # Global styles
+├── App.vue # Main application component
+├── main.ts # Application entry point
+└── style.css # Tailwind CSS imports
```
### Scripts
-- `npm run dev` - Start development server
-- `npm run build` - Build for production
+- `npm run dev` - Start development server (Vite)
+- `npm run build` - Build for production (Vue TSC + Vite)
- `npm run preview` - Preview production build
-- `npm run lint` - Run ESLint
+- `npm run lint` - Run ESLint (Vue + TypeScript)
+
+### Migration Note
+
+This project was recently migrated from React to Vue 3. See `VUE_MIGRATION.md` for details.
## License
diff --git a/VUE_MIGRATION.md b/VUE_MIGRATION.md
new file mode 100644
index 0000000..962d365
--- /dev/null
+++ b/VUE_MIGRATION.md
@@ -0,0 +1,345 @@
+# Vue 3 Migration Complete! 🎉
+
+## What Changed
+
+### ✅ Complete Rewrite from React to Vue 3 + Tailwind + DaisyUI
+
+The entire UI layer has been converted while keeping all business logic intact!
+
+## New Stack
+
+- **Vue 3** with Composition API (`
+
+
+ Count: {{ count }}
+
+```
+
+### TypeScript Props & Emits
+
+```vue
+
+```
+
+### Reactivity
+
+- `ref()` - for primitive values (`ref(0)`, `ref('')`)
+- `reactive()` - for objects (not used much, ref works for everything)
+- `computed()` - for derived values
+- `watch()` / `watchEffect()` - for side effects
+
+## DaisyUI Components Used
+
+### Buttons
+```html
+Primary
+Danger
+Small
+Loading
+```
+
+### Cards
+```html
+
+```
+
+### Forms
+```html
+
+
+ Label
+
+
+
+```
+
+### Alerts
+```html
+
+ ...
+ Info message
+
+```
+
+### Modal
+```html
+
+```
+
+## Feature Comparison
+
+| Feature | React Version | Vue Version | Status |
+|---------|--------------|-------------|--------|
+| Server Management | ✅ | ✅ | Identical |
+| Multi-Auth Support | ✅ | ✅ | Identical |
+| Login Verification | ✅ | ✅ | Identical |
+| Mount Point Detection | ✅ | ✅ | Identical |
+| Secret Reading | ✅ | ✅ | Identical |
+| Recursive Search | ✅ | ✅ | Identical |
+| Multi-Mount Search | ✅ | ✅ | Identical |
+| Caching System | ✅ | ✅ | Identical |
+| Settings Panel | ✅ | ✅ | Identical |
+| KV v1/v2 Support | ✅ | ✅ | Identical |
+| Dark/Light Mode | ✅ | ✅ | Improved (DaisyUI themes) |
+| Responsive Design | ✅ | ✅ | Improved (Tailwind) |
+
+## Benefits of Vue Version
+
+### Code Quality
+- ✅ **Less Code**: Vue templates are more concise than JSX
+- ✅ **Better Separation**: Logic in `
+
+
+
+ {{ count }}
+
+
+```
+
+## Theme Switching
+
+DaisyUI supports multiple themes. To switch themes:
+
+```html
+
+
+```
+
+Or dynamically:
+```typescript
+document.documentElement.setAttribute('data-theme', 'light')
+```
+
+Available themes: dark, light, cupcake, bumblebee, emerald, corporate, synthwave, retro, cyberpunk, valentine, halloween, garden, forest, aqua, lofi, pastel, fantasy, wireframe, black, luxury, dracula, cmyk, autumn, business, acid, lemonade, night, coffee, winter
+
+## Next Steps
+
+### Recommended Enhancements
+
+1. **Add Vue Router** (if you want multiple pages)
+2. **Add Pinia** (Vue's state management, like Redux)
+3. **Add VueUse** (collection of useful composition utilities)
+4. **Add animations** with Vue transitions
+5. **PWA support** with Vite PWA plugin
+
+### Optional Improvements
+
+1. **Virtual scrolling** for large result lists
+2. **Drag & drop** for organizing servers
+3. **Keyboard shortcuts** with Vue composables
+4. **Export/import** server configurations
+5. **Secret editing** UI with forms
+
+## Testing
+
+To test the conversion:
+
+1. `npm install`
+2. `npm run dev`
+3. Add a server (should work like before)
+4. Login (mount points should be detected)
+5. Read a secret
+6. Try search (single path and all mounts)
+7. Check settings panel
+8. Verify cache statistics
+
+Everything should work identically to the React version!
+
+## Documentation
+
+All previous documentation still applies:
+- `README.md` - Updated for Vue
+- `USAGE.md` - Same usage, new UI
+- `KV_VERSIONS.md` - No changes
+- `MOUNT_POINTS.md` - No changes
+- `CORS_AND_CLIENT.md` - No changes
+
+## Conclusion
+
+✅ **Migration Complete!**
+✅ **All features preserved**
+✅ **Smaller bundle size**
+✅ **Better performance**
+✅ **Modern UI with Tailwind + DaisyUI**
+✅ **Cleaner codebase**
+
+The Vue version is production-ready! 🚀
+
diff --git a/index.html b/index.html
index 669f483..13661a0 100644
--- a/index.html
+++ b/index.html
@@ -1,5 +1,5 @@
-
+
@@ -7,8 +7,8 @@
Browser Vault GUI
-
-
+
+
diff --git a/package.json b/package.json
index e95ff81..3c8fce3 100644
--- a/package.json
+++ b/package.json
@@ -1,28 +1,30 @@
{
"name": "browser-vault-gui",
- "version": "0.1.0",
- "description": "Alternative frontend for HashiCorp Vault",
+ "version": "0.2.0",
+ "description": "Alternative frontend for HashiCorp Vault (Vue 3 + Tailwind)",
"type": "module",
"scripts": {
"dev": "vite",
- "build": "tsc && vite build",
+ "build": "vue-tsc && vite build",
"preview": "vite preview",
- "lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0"
+ "lint": "eslint . --ext .vue,.ts --report-unused-disable-directives --max-warnings 0"
},
"dependencies": {
- "react": "^18.2.0",
- "react-dom": "^18.2.0"
+ "vue": "^3.4.15"
},
"devDependencies": {
- "@types/react": "^18.2.43",
- "@types/react-dom": "^18.2.17",
"@typescript-eslint/eslint-plugin": "^6.14.0",
"@typescript-eslint/parser": "^6.14.0",
- "@vitejs/plugin-react": "^4.2.1",
+ "@vitejs/plugin-vue": "^5.0.3",
+ "@vue/eslint-config-typescript": "^12.0.0",
+ "autoprefixer": "^10.4.16",
+ "daisyui": "^4.4.24",
"eslint": "^8.55.0",
- "eslint-plugin-react-hooks": "^4.6.0",
- "eslint-plugin-react-refresh": "^0.4.5",
+ "eslint-plugin-vue": "^9.19.2",
+ "postcss": "^8.4.33",
+ "tailwindcss": "^3.4.1",
"typescript": "^5.3.3",
- "vite": "^5.0.8"
+ "vite": "^5.0.8",
+ "vue-tsc": "^1.8.27"
}
}
\ No newline at end of file
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 8e985fd..9cc13ce 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -8,83 +8,55 @@ importers:
.:
dependencies:
- react:
- specifier: ^18.2.0
- version: 18.3.1
- react-dom:
- specifier: ^18.2.0
- version: 18.3.1(react@18.3.1)
+ vue:
+ specifier: ^3.4.15
+ version: 3.5.22(typescript@5.9.3)
devDependencies:
- '@types/react':
- specifier: ^18.2.43
- version: 18.3.26
- '@types/react-dom':
- specifier: ^18.2.17
- version: 18.3.7(@types/react@18.3.26)
'@typescript-eslint/eslint-plugin':
specifier: ^6.14.0
version: 6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.9.3))(eslint@8.57.1)(typescript@5.9.3)
'@typescript-eslint/parser':
specifier: ^6.14.0
version: 6.21.0(eslint@8.57.1)(typescript@5.9.3)
- '@vitejs/plugin-react':
- specifier: ^4.2.1
- version: 4.7.0(vite@5.4.21)
+ '@vitejs/plugin-vue':
+ specifier: ^5.0.3
+ version: 5.2.4(vite@5.4.21)(vue@3.5.22(typescript@5.9.3))
+ '@vue/eslint-config-typescript':
+ specifier: ^12.0.0
+ version: 12.0.0(eslint-plugin-vue@9.33.0(eslint@8.57.1))(eslint@8.57.1)(typescript@5.9.3)
+ autoprefixer:
+ specifier: ^10.4.16
+ version: 10.4.21(postcss@8.5.6)
+ daisyui:
+ specifier: ^4.4.24
+ version: 4.12.24(postcss@8.5.6)
eslint:
specifier: ^8.55.0
version: 8.57.1
- eslint-plugin-react-hooks:
- specifier: ^4.6.0
- version: 4.6.2(eslint@8.57.1)
- eslint-plugin-react-refresh:
- specifier: ^0.4.5
- version: 0.4.24(eslint@8.57.1)
+ eslint-plugin-vue:
+ specifier: ^9.19.2
+ version: 9.33.0(eslint@8.57.1)
+ postcss:
+ specifier: ^8.4.33
+ version: 8.5.6
+ tailwindcss:
+ specifier: ^3.4.1
+ version: 3.4.18
typescript:
specifier: ^5.3.3
version: 5.9.3
vite:
specifier: ^5.0.8
version: 5.4.21
+ vue-tsc:
+ specifier: ^1.8.27
+ version: 1.8.27(typescript@5.9.3)
packages:
- '@babel/code-frame@7.27.1':
- resolution: {integrity: sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==}
- engines: {node: '>=6.9.0'}
-
- '@babel/compat-data@7.28.4':
- resolution: {integrity: sha512-YsmSKC29MJwf0gF8Rjjrg5LQCmyh+j/nD8/eP7f+BeoQTKYqs9RoWbjGOdy0+1Ekr68RJZMUOPVQaQisnIo4Rw==}
- engines: {node: '>=6.9.0'}
-
- '@babel/core@7.28.4':
- resolution: {integrity: sha512-2BCOP7TN8M+gVDj7/ht3hsaO/B/n5oDbiAyyvnRlNOs+u1o+JWNYTQrmpuNp1/Wq2gcFrI01JAW+paEKDMx/CA==}
- engines: {node: '>=6.9.0'}
-
- '@babel/generator@7.28.3':
- resolution: {integrity: sha512-3lSpxGgvnmZznmBkCRnVREPUFJv2wrv9iAoFDvADJc0ypmdOxdUtcLeBgBJ6zE0PMeTKnxeQzyk0xTBq4Ep7zw==}
- engines: {node: '>=6.9.0'}
-
- '@babel/helper-compilation-targets@7.27.2':
- resolution: {integrity: sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==}
- engines: {node: '>=6.9.0'}
-
- '@babel/helper-globals@7.28.0':
- resolution: {integrity: sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==}
- engines: {node: '>=6.9.0'}
-
- '@babel/helper-module-imports@7.27.1':
- resolution: {integrity: sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==}
- engines: {node: '>=6.9.0'}
-
- '@babel/helper-module-transforms@7.28.3':
- resolution: {integrity: sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw==}
- engines: {node: '>=6.9.0'}
- peerDependencies:
- '@babel/core': ^7.0.0
-
- '@babel/helper-plugin-utils@7.27.1':
- resolution: {integrity: sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==}
- engines: {node: '>=6.9.0'}
+ '@alloc/quick-lru@5.2.0':
+ resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==}
+ engines: {node: '>=10'}
'@babel/helper-string-parser@7.27.1':
resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==}
@@ -94,39 +66,11 @@ packages:
resolution: {integrity: sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==}
engines: {node: '>=6.9.0'}
- '@babel/helper-validator-option@7.27.1':
- resolution: {integrity: sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==}
- engines: {node: '>=6.9.0'}
-
- '@babel/helpers@7.28.4':
- resolution: {integrity: sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w==}
- engines: {node: '>=6.9.0'}
-
'@babel/parser@7.28.4':
resolution: {integrity: sha512-yZbBqeM6TkpP9du/I2pUZnJsRMGGvOuIrhjzC1AwHwW+6he4mni6Bp/m8ijn0iOuZuPI2BfkCoSRunpyjnrQKg==}
engines: {node: '>=6.0.0'}
hasBin: true
- '@babel/plugin-transform-react-jsx-self@7.27.1':
- resolution: {integrity: sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw==}
- engines: {node: '>=6.9.0'}
- peerDependencies:
- '@babel/core': ^7.0.0-0
-
- '@babel/plugin-transform-react-jsx-source@7.27.1':
- resolution: {integrity: sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw==}
- engines: {node: '>=6.9.0'}
- peerDependencies:
- '@babel/core': ^7.0.0-0
-
- '@babel/template@7.27.2':
- resolution: {integrity: sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==}
- engines: {node: '>=6.9.0'}
-
- '@babel/traverse@7.28.4':
- resolution: {integrity: sha512-YEzuboP2qvQavAcjgQNVgsvHIDv6ZpwXvcvjmyySP2DIMuByS/6ioU5G9pYrWHM6T2YDfc7xga9iNzYOs12CFQ==}
- engines: {node: '>=6.9.0'}
-
'@babel/types@7.28.4':
resolution: {integrity: sha512-bkFqkLhh3pMBUQQkpVgWDWq/lqzc2678eUyDlTBhRqhCHFguYYGM0Efga7tYk4TogG/3x0EEl66/OQ+WGbWB/Q==}
engines: {node: '>=6.9.0'}
@@ -300,12 +244,13 @@ packages:
resolution: {integrity: sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==}
deprecated: Use @eslint/object-schema instead
+ '@isaacs/cliui@8.0.2':
+ resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==}
+ engines: {node: '>=12'}
+
'@jridgewell/gen-mapping@0.3.13':
resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==}
- '@jridgewell/remapping@2.3.5':
- resolution: {integrity: sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==}
-
'@jridgewell/resolve-uri@3.1.2':
resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==}
engines: {node: '>=6.0.0'}
@@ -328,8 +273,9 @@ packages:
resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==}
engines: {node: '>= 8'}
- '@rolldown/pluginutils@1.0.0-beta.27':
- resolution: {integrity: sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA==}
+ '@pkgjs/parseargs@0.11.0':
+ resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==}
+ engines: {node: '>=14'}
'@rollup/rollup-android-arm-eabi@4.52.5':
resolution: {integrity: sha512-8c1vW4ocv3UOMp9K+gToY5zL2XiiVw3k7f1ksf4yO1FlDFQ1C2u72iACFnSOceJFsWskc2WZNqeRhFRPzv+wtQ==}
@@ -441,35 +387,12 @@ packages:
cpu: [x64]
os: [win32]
- '@types/babel__core@7.20.5':
- resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==}
-
- '@types/babel__generator@7.27.0':
- resolution: {integrity: sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==}
-
- '@types/babel__template@7.4.4':
- resolution: {integrity: sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==}
-
- '@types/babel__traverse@7.28.0':
- resolution: {integrity: sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==}
-
'@types/estree@1.0.8':
resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==}
'@types/json-schema@7.0.15':
resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==}
- '@types/prop-types@15.7.15':
- resolution: {integrity: sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==}
-
- '@types/react-dom@18.3.7':
- resolution: {integrity: sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ==}
- peerDependencies:
- '@types/react': ^18.0.0
-
- '@types/react@18.3.26':
- resolution: {integrity: sha512-RFA/bURkcKzx/X9oumPG9Vp3D3JUgus/d0b67KB0t5S/raciymilkOa66olh78MUI92QLbEJevO7rvqU/kjwKA==}
-
'@types/semver@7.7.1':
resolution: {integrity: sha512-FmgJfu+MOcQ370SD0ev7EI8TlCAfKYU+B4m5T3yXc1CiRN94g/SZPtsCkk506aUDtlMnFZvasDwHHUcZUEaYuA==}
@@ -534,11 +457,69 @@ packages:
'@ungap/structured-clone@1.3.0':
resolution: {integrity: sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==}
- '@vitejs/plugin-react@4.7.0':
- resolution: {integrity: sha512-gUu9hwfWvvEDBBmgtAowQCojwZmJ5mcLn3aufeCsitijs3+f2NsrPtlAWIR6OPiqljl96GVCUbLe0HyqIpVaoA==}
- engines: {node: ^14.18.0 || >=16.0.0}
+ '@vitejs/plugin-vue@5.2.4':
+ resolution: {integrity: sha512-7Yx/SXSOcQq5HiiV3orevHUFn+pmMB4cgbEkDYgnkUWb0WfeQ/wa2yFv6D5ICiCQOVpjA7vYDXrC7AGO8yjDHA==}
+ engines: {node: ^18.0.0 || >=20.0.0}
peerDependencies:
- vite: ^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0
+ vite: ^5.0.0 || ^6.0.0
+ vue: ^3.2.25
+
+ '@volar/language-core@1.11.1':
+ resolution: {integrity: sha512-dOcNn3i9GgZAcJt43wuaEykSluAuOkQgzni1cuxLxTV0nJKanQztp7FxyswdRILaKH+P2XZMPRp2S4MV/pElCw==}
+
+ '@volar/source-map@1.11.1':
+ resolution: {integrity: sha512-hJnOnwZ4+WT5iupLRnuzbULZ42L7BWWPMmruzwtLhJfpDVoZLjNBxHDi2sY2bgZXCKlpU5XcsMFoYrsQmPhfZg==}
+
+ '@volar/typescript@1.11.1':
+ resolution: {integrity: sha512-iU+t2mas/4lYierSnoFOeRFQUhAEMgsFuQxoxvwn5EdQopw43j+J27a4lt9LMInx1gLJBC6qL14WYGlgymaSMQ==}
+
+ '@vue/compiler-core@3.5.22':
+ resolution: {integrity: sha512-jQ0pFPmZwTEiRNSb+i9Ow/I/cHv2tXYqsnHKKyCQ08irI2kdF5qmYedmF8si8mA7zepUFmJ2hqzS8CQmNOWOkQ==}
+
+ '@vue/compiler-dom@3.5.22':
+ resolution: {integrity: sha512-W8RknzUM1BLkypvdz10OVsGxnMAuSIZs9Wdx1vzA3mL5fNMN15rhrSCLiTm6blWeACwUwizzPVqGJgOGBEN/hA==}
+
+ '@vue/compiler-sfc@3.5.22':
+ resolution: {integrity: sha512-tbTR1zKGce4Lj+JLzFXDq36K4vcSZbJ1RBu8FxcDv1IGRz//Dh2EBqksyGVypz3kXpshIfWKGOCcqpSbyGWRJQ==}
+
+ '@vue/compiler-ssr@3.5.22':
+ resolution: {integrity: sha512-GdgyLvg4R+7T8Nk2Mlighx7XGxq/fJf9jaVofc3IL0EPesTE86cP/8DD1lT3h1JeZr2ySBvyqKQJgbS54IX1Ww==}
+
+ '@vue/eslint-config-typescript@12.0.0':
+ resolution: {integrity: sha512-StxLFet2Qe97T8+7L8pGlhYBBr8Eg05LPuTDVopQV6il+SK6qqom59BA/rcFipUef2jD8P2X44Vd8tMFytfvlg==}
+ engines: {node: ^14.17.0 || >=16.0.0}
+ peerDependencies:
+ eslint: ^6.2.0 || ^7.0.0 || ^8.0.0
+ eslint-plugin-vue: ^9.0.0
+ typescript: '*'
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+
+ '@vue/language-core@1.8.27':
+ resolution: {integrity: sha512-L8Kc27VdQserNaCUNiSFdDl9LWT24ly8Hpwf1ECy3aFb9m6bDhBGQYOujDm21N7EW3moKIOKEanQwe1q5BK+mA==}
+ peerDependencies:
+ typescript: '*'
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+
+ '@vue/reactivity@3.5.22':
+ resolution: {integrity: sha512-f2Wux4v/Z2pqc9+4SmgZC1p73Z53fyD90NFWXiX9AKVnVBEvLFOWCEgJD3GdGnlxPZt01PSlfmLqbLYzY/Fw4A==}
+
+ '@vue/runtime-core@3.5.22':
+ resolution: {integrity: sha512-EHo4W/eiYeAzRTN5PCextDUZ0dMs9I8mQ2Fy+OkzvRPUYQEyK9yAjbasrMCXbLNhF7P0OUyivLjIy0yc6VrLJQ==}
+
+ '@vue/runtime-dom@3.5.22':
+ resolution: {integrity: sha512-Av60jsryAkI023PlN7LsqrfPvwfxOd2yAwtReCjeuugTJTkgrksYJJstg1e12qle0NarkfhfFu1ox2D+cQotww==}
+
+ '@vue/server-renderer@3.5.22':
+ resolution: {integrity: sha512-gXjo+ao0oHYTSswF+a3KRHZ1WszxIqO7u6XwNHqcqb9JfyIL/pbWrrh/xLv7jeDqla9u+LK7yfZKHih1e1RKAQ==}
+ peerDependencies:
+ vue: 3.5.22
+
+ '@vue/shared@3.5.22':
+ resolution: {integrity: sha512-F4yc6palwq3TT0u+FYf0Ns4Tfl9GRFURDN2gWG7L1ecIaS/4fCIuFOjMTnCyjsu/OK6vaDKLCrGAa+KvvH+h4w==}
acorn-jsx@5.3.2:
resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==}
@@ -557,10 +538,28 @@ packages:
resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==}
engines: {node: '>=8'}
+ ansi-regex@6.2.2:
+ resolution: {integrity: sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==}
+ engines: {node: '>=12'}
+
ansi-styles@4.3.0:
resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==}
engines: {node: '>=8'}
+ ansi-styles@6.2.3:
+ resolution: {integrity: sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==}
+ engines: {node: '>=12'}
+
+ any-promise@1.3.0:
+ resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==}
+
+ anymatch@3.1.3:
+ resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==}
+ engines: {node: '>= 8'}
+
+ arg@5.0.2:
+ resolution: {integrity: sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==}
+
argparse@2.0.1:
resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==}
@@ -568,6 +567,13 @@ packages:
resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==}
engines: {node: '>=8'}
+ autoprefixer@10.4.21:
+ resolution: {integrity: sha512-O+A6LWV5LDHSJD3LjHYoNi4VLsj/Whi7k6zG12xTYaU4cQ8oxQGckXNX8cRHK5yOZ/ppVHe0ZBXGzSV9jXdVbQ==}
+ engines: {node: ^10 || ^12 || >=14}
+ hasBin: true
+ peerDependencies:
+ postcss: ^8.1.0
+
balanced-match@1.0.2:
resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
@@ -575,6 +581,13 @@ packages:
resolution: {integrity: sha512-UYmTpOBwgPScZpS4A+YbapwWuBwasxvO/2IOHArSsAhL/+ZdmATBXTex3t+l2hXwLVYK382ibr/nKoY9GKe86w==}
hasBin: true
+ binary-extensions@2.3.0:
+ resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==}
+ engines: {node: '>=8'}
+
+ boolbase@1.0.0:
+ resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==}
+
brace-expansion@1.1.12:
resolution: {integrity: sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==}
@@ -594,6 +607,10 @@ packages:
resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==}
engines: {node: '>=6'}
+ camelcase-css@2.0.1:
+ resolution: {integrity: sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==}
+ engines: {node: '>= 6'}
+
caniuse-lite@1.0.30001751:
resolution: {integrity: sha512-A0QJhug0Ly64Ii3eIqHu5X51ebln3k4yTUkY1j8drqpWHVreg/VLijN48cZ1bYPiqOQuqpkIKnzr/Ul8V+p6Cw==}
@@ -601,6 +618,10 @@ packages:
resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==}
engines: {node: '>=10'}
+ chokidar@3.6.0:
+ resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==}
+ engines: {node: '>= 8.10.0'}
+
color-convert@2.0.1:
resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==}
engines: {node: '>=7.0.0'}
@@ -608,19 +629,42 @@ packages:
color-name@1.1.4:
resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==}
+ commander@4.1.1:
+ resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==}
+ engines: {node: '>= 6'}
+
+ computeds@0.0.1:
+ resolution: {integrity: sha512-7CEBgcMjVmitjYo5q8JTJVra6X5mQ20uTThdK+0kR7UEaDrAWEQcRiBtWJzga4eRpP6afNwwLsX2SET2JhVB1Q==}
+
concat-map@0.0.1:
resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==}
- convert-source-map@2.0.0:
- resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==}
-
cross-spawn@7.0.6:
resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==}
engines: {node: '>= 8'}
+ css-selector-tokenizer@0.8.0:
+ resolution: {integrity: sha512-Jd6Ig3/pe62/qe5SBPTN8h8LeUg/pT4lLgtavPf7updwwHpvFzxvOQBHYj2LZDMjUnBzgvIUSjRcf6oT5HzHFg==}
+
+ cssesc@3.0.0:
+ resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==}
+ engines: {node: '>=4'}
+ hasBin: true
+
csstype@3.1.3:
resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==}
+ culori@3.3.0:
+ resolution: {integrity: sha512-pHJg+jbuFsCjz9iclQBqyL3B2HLCBF71BwVNujUYEvCeQMvV97R59MNK3R2+jgJ3a1fcZgI9B3vYgz8lzr/BFQ==}
+ engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
+
+ daisyui@4.12.24:
+ resolution: {integrity: sha512-JYg9fhQHOfXyLadrBrEqCDM6D5dWCSSiM6eTNCRrBRzx/VlOCrLS8eDfIw9RVvs64v2mJdLooKXY8EwQzoszAA==}
+ engines: {node: '>=16.9.0'}
+
+ de-indent@1.0.2:
+ resolution: {integrity: sha512-e/1zu3xH5MQryN2zdVaF0OrdNLUbvWxzMbi+iNA6Bky7l1RoP8a2fIbRocyHclXt/arDrrR6lL3TqFD9pMQTsg==}
+
debug@4.4.3:
resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==}
engines: {node: '>=6.0'}
@@ -633,17 +677,36 @@ packages:
deep-is@0.1.4:
resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==}
+ didyoumean@1.2.2:
+ resolution: {integrity: sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==}
+
dir-glob@3.0.1:
resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==}
engines: {node: '>=8'}
+ dlv@1.1.3:
+ resolution: {integrity: sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==}
+
doctrine@3.0.0:
resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==}
engines: {node: '>=6.0.0'}
+ eastasianwidth@0.2.0:
+ resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==}
+
electron-to-chromium@1.5.237:
resolution: {integrity: sha512-icUt1NvfhGLar5lSWH3tHNzablaA5js3HVHacQimfP8ViEBOQv+L7DKEuHdbTZ0SKCO1ogTJTIL1Gwk9S6Qvcg==}
+ emoji-regex@8.0.0:
+ resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==}
+
+ emoji-regex@9.2.2:
+ resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==}
+
+ entities@4.5.0:
+ resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==}
+ engines: {node: '>=0.12'}
+
esbuild@0.21.5:
resolution: {integrity: sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==}
engines: {node: '>=12'}
@@ -657,16 +720,11 @@ packages:
resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==}
engines: {node: '>=10'}
- eslint-plugin-react-hooks@4.6.2:
- resolution: {integrity: sha512-QzliNJq4GinDBcD8gPB5v0wh6g8q3SUi6EFF0x8N/BL9PoVs0atuGc47ozMRyOWAKdwaZ5OnbOEa3WR+dSGKuQ==}
- engines: {node: '>=10'}
+ eslint-plugin-vue@9.33.0:
+ resolution: {integrity: sha512-174lJKuNsuDIlLpjeXc5E2Tss8P44uIimAfGD0b90k0NoirJqpG7stLuU9Vp/9ioTOrQdWVREc4mRd1BD+CvGw==}
+ engines: {node: ^14.17.0 || >=16.0.0}
peerDependencies:
- eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0
-
- eslint-plugin-react-refresh@0.4.24:
- resolution: {integrity: sha512-nLHIW7TEq3aLrEYWpVaJ1dRgFR+wLDPN8e8FpYAql/bMV2oBEfC37K0gLEGgv9fy66juNShSMV8OkTqzltcG/w==}
- peerDependencies:
- eslint: '>=8.40'
+ eslint: ^6.2.0 || ^7.0.0 || ^8.0.0 || ^9.0.0
eslint-scope@7.2.2:
resolution: {integrity: sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==}
@@ -698,6 +756,9 @@ packages:
resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==}
engines: {node: '>=4.0'}
+ estree-walker@2.0.2:
+ resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==}
+
esutils@2.0.3:
resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==}
engines: {node: '>=0.10.0'}
@@ -715,6 +776,9 @@ packages:
fast-levenshtein@2.0.6:
resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==}
+ fastparse@1.1.2:
+ resolution: {integrity: sha512-483XLLxTVIwWK3QTrMGRqUfUpoOs/0hbQrl2oz4J0pAcm3A3bu84wxTFqGqkJzewCLdME38xJLJAxBABfQT8sQ==}
+
fastq@1.19.1:
resolution: {integrity: sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==}
@@ -737,6 +801,13 @@ packages:
flatted@3.3.3:
resolution: {integrity: sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==}
+ foreground-child@3.3.1:
+ resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==}
+ engines: {node: '>=14'}
+
+ fraction.js@4.3.7:
+ resolution: {integrity: sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==}
+
fs.realpath@1.0.0:
resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==}
@@ -745,9 +816,8 @@ packages:
engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
os: [darwin]
- gensync@1.0.0-beta.2:
- resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==}
- engines: {node: '>=6.9.0'}
+ function-bind@1.1.2:
+ resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==}
glob-parent@5.1.2:
resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==}
@@ -757,6 +827,10 @@ packages:
resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==}
engines: {node: '>=10.13.0'}
+ glob@10.4.5:
+ resolution: {integrity: sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==}
+ hasBin: true
+
glob@7.2.3:
resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==}
deprecated: Glob versions prior to v9 are no longer supported
@@ -776,6 +850,14 @@ packages:
resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==}
engines: {node: '>=8'}
+ hasown@2.0.2:
+ resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==}
+ engines: {node: '>= 0.4'}
+
+ he@1.2.0:
+ resolution: {integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==}
+ hasBin: true
+
ignore@5.3.2:
resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==}
engines: {node: '>= 4'}
@@ -795,10 +877,22 @@ packages:
inherits@2.0.4:
resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==}
+ is-binary-path@2.1.0:
+ resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==}
+ engines: {node: '>=8'}
+
+ is-core-module@2.16.1:
+ resolution: {integrity: sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==}
+ engines: {node: '>= 0.4'}
+
is-extglob@2.1.1:
resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==}
engines: {node: '>=0.10.0'}
+ is-fullwidth-code-point@3.0.0:
+ resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==}
+ engines: {node: '>=8'}
+
is-glob@4.0.3:
resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==}
engines: {node: '>=0.10.0'}
@@ -814,18 +908,17 @@ packages:
isexe@2.0.0:
resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==}
- js-tokens@4.0.0:
- resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
+ jackspeak@3.4.3:
+ resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==}
+
+ jiti@1.21.7:
+ resolution: {integrity: sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==}
+ hasBin: true
js-yaml@4.1.0:
resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==}
hasBin: true
- jsesc@3.1.0:
- resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==}
- engines: {node: '>=6'}
- hasBin: true
-
json-buffer@3.0.1:
resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==}
@@ -835,11 +928,6 @@ packages:
json-stable-stringify-without-jsonify@1.0.1:
resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==}
- json5@2.2.3:
- resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==}
- engines: {node: '>=6'}
- hasBin: true
-
keyv@4.5.4:
resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==}
@@ -847,6 +935,13 @@ packages:
resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==}
engines: {node: '>= 0.8.0'}
+ lilconfig@3.1.3:
+ resolution: {integrity: sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==}
+ engines: {node: '>=14'}
+
+ lines-and-columns@1.2.4:
+ resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==}
+
locate-path@6.0.0:
resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==}
engines: {node: '>=10'}
@@ -854,12 +949,14 @@ packages:
lodash.merge@4.6.2:
resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==}
- loose-envify@1.4.0:
- resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==}
- hasBin: true
+ lodash@4.17.21:
+ resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==}
- lru-cache@5.1.1:
- resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==}
+ lru-cache@10.4.3:
+ resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==}
+
+ magic-string@0.30.19:
+ resolution: {integrity: sha512-2N21sPY9Ws53PZvsEpVtNuSW+ScYbQdp4b9qUaL+9QkHUrGFKo56Lg9Emg5s9V/qrtNBmiR01sYhUOwu3H+VOw==}
merge2@1.4.1:
resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==}
@@ -876,9 +973,23 @@ packages:
resolution: {integrity: sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==}
engines: {node: '>=16 || 14 >=14.17'}
+ minimatch@9.0.5:
+ resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==}
+ engines: {node: '>=16 || 14 >=14.17'}
+
+ minipass@7.1.2:
+ resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==}
+ engines: {node: '>=16 || 14 >=14.17'}
+
ms@2.1.3:
resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
+ muggle-string@0.3.1:
+ resolution: {integrity: sha512-ckmWDJjphvd/FvZawgygcUeQCxzvohjFO5RxTjj4eq8kw359gFF3E1brjfI+viLMxss5JrHTDRHZvu2/tuy0Qg==}
+
+ mz@2.7.0:
+ resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==}
+
nanoid@3.3.11:
resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==}
engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
@@ -890,6 +1001,25 @@ packages:
node-releases@2.0.25:
resolution: {integrity: sha512-4auku8B/vw5psvTiiN9j1dAOsXvMoGqJuKJcR+dTdqiXEK20mMTk1UEo3HS16LeGQsVG6+qKTPM9u/qQ2LqATA==}
+ normalize-path@3.0.0:
+ resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==}
+ engines: {node: '>=0.10.0'}
+
+ normalize-range@0.1.2:
+ resolution: {integrity: sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==}
+ engines: {node: '>=0.10.0'}
+
+ nth-check@2.1.1:
+ resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==}
+
+ object-assign@4.1.1:
+ resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==}
+ engines: {node: '>=0.10.0'}
+
+ object-hash@3.0.0:
+ resolution: {integrity: sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==}
+ engines: {node: '>= 6'}
+
once@1.4.0:
resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==}
@@ -905,10 +1035,16 @@ packages:
resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==}
engines: {node: '>=10'}
+ package-json-from-dist@1.0.1:
+ resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==}
+
parent-module@1.0.1:
resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==}
engines: {node: '>=6'}
+ path-browserify@1.0.1:
+ resolution: {integrity: sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==}
+
path-exists@4.0.0:
resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==}
engines: {node: '>=8'}
@@ -921,6 +1057,13 @@ packages:
resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==}
engines: {node: '>=8'}
+ path-parse@1.0.7:
+ resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==}
+
+ path-scurry@1.11.1:
+ resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==}
+ engines: {node: '>=16 || 14 >=14.18'}
+
path-type@4.0.0:
resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==}
engines: {node: '>=8'}
@@ -932,6 +1075,57 @@ packages:
resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==}
engines: {node: '>=8.6'}
+ pify@2.3.0:
+ resolution: {integrity: sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==}
+ engines: {node: '>=0.10.0'}
+
+ pirates@4.0.7:
+ resolution: {integrity: sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==}
+ engines: {node: '>= 6'}
+
+ postcss-import@15.1.0:
+ resolution: {integrity: sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==}
+ engines: {node: '>=14.0.0'}
+ peerDependencies:
+ postcss: ^8.0.0
+
+ postcss-js@4.1.0:
+ resolution: {integrity: sha512-oIAOTqgIo7q2EOwbhb8UalYePMvYoIeRY2YKntdpFQXNosSu3vLrniGgmH9OKs/qAkfoj5oB3le/7mINW1LCfw==}
+ engines: {node: ^12 || ^14 || >= 16}
+ peerDependencies:
+ postcss: ^8.4.21
+
+ postcss-load-config@6.0.1:
+ resolution: {integrity: sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g==}
+ engines: {node: '>= 18'}
+ peerDependencies:
+ jiti: '>=1.21.0'
+ postcss: '>=8.0.9'
+ tsx: ^4.8.1
+ yaml: ^2.4.2
+ peerDependenciesMeta:
+ jiti:
+ optional: true
+ postcss:
+ optional: true
+ tsx:
+ optional: true
+ yaml:
+ optional: true
+
+ postcss-nested@6.2.0:
+ resolution: {integrity: sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ==}
+ engines: {node: '>=12.0'}
+ peerDependencies:
+ postcss: ^8.2.14
+
+ postcss-selector-parser@6.1.2:
+ resolution: {integrity: sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==}
+ engines: {node: '>=4'}
+
+ postcss-value-parser@4.2.0:
+ resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==}
+
postcss@8.5.6:
resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==}
engines: {node: ^10 || ^12 || >=14}
@@ -947,23 +1141,22 @@ packages:
queue-microtask@1.2.3:
resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==}
- react-dom@18.3.1:
- resolution: {integrity: sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==}
- peerDependencies:
- react: ^18.3.1
+ read-cache@1.0.0:
+ resolution: {integrity: sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==}
- react-refresh@0.17.0:
- resolution: {integrity: sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==}
- engines: {node: '>=0.10.0'}
-
- react@18.3.1:
- resolution: {integrity: sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==}
- engines: {node: '>=0.10.0'}
+ readdirp@3.6.0:
+ resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==}
+ engines: {node: '>=8.10.0'}
resolve-from@4.0.0:
resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==}
engines: {node: '>=4'}
+ resolve@1.22.10:
+ resolution: {integrity: sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==}
+ engines: {node: '>= 0.4'}
+ hasBin: true
+
reusify@1.1.0:
resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==}
engines: {iojs: '>=1.0.0', node: '>=0.10.0'}
@@ -981,13 +1174,6 @@ packages:
run-parallel@1.2.0:
resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==}
- scheduler@0.23.2:
- resolution: {integrity: sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==}
-
- semver@6.3.1:
- resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==}
- hasBin: true
-
semver@7.7.3:
resolution: {integrity: sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==}
engines: {node: '>=10'}
@@ -1001,6 +1187,10 @@ packages:
resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==}
engines: {node: '>=8'}
+ signal-exit@4.1.0:
+ resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==}
+ engines: {node: '>=14'}
+
slash@3.0.0:
resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==}
engines: {node: '>=8'}
@@ -1009,21 +1199,54 @@ packages:
resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==}
engines: {node: '>=0.10.0'}
+ string-width@4.2.3:
+ resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==}
+ engines: {node: '>=8'}
+
+ string-width@5.1.2:
+ resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==}
+ engines: {node: '>=12'}
+
strip-ansi@6.0.1:
resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==}
engines: {node: '>=8'}
+ strip-ansi@7.1.2:
+ resolution: {integrity: sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==}
+ engines: {node: '>=12'}
+
strip-json-comments@3.1.1:
resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==}
engines: {node: '>=8'}
+ sucrase@3.35.0:
+ resolution: {integrity: sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==}
+ engines: {node: '>=16 || 14 >=14.17'}
+ hasBin: true
+
supports-color@7.2.0:
resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==}
engines: {node: '>=8'}
+ supports-preserve-symlinks-flag@1.0.0:
+ resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==}
+ engines: {node: '>= 0.4'}
+
+ tailwindcss@3.4.18:
+ resolution: {integrity: sha512-6A2rnmW5xZMdw11LYjhcI5846rt9pbLSabY5XPxo+XWdxwZaFEn47Go4NzFiHu9sNNmr/kXivP1vStfvMaK1GQ==}
+ engines: {node: '>=14.0.0'}
+ hasBin: true
+
text-table@0.2.0:
resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==}
+ thenify-all@1.6.0:
+ resolution: {integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==}
+ engines: {node: '>=0.8'}
+
+ thenify@3.3.1:
+ resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==}
+
to-regex-range@5.0.1:
resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==}
engines: {node: '>=8.0'}
@@ -1034,6 +1257,9 @@ packages:
peerDependencies:
typescript: '>=4.2.0'
+ ts-interface-checker@0.1.13:
+ resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==}
+
type-check@0.4.0:
resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==}
engines: {node: '>= 0.8.0'}
@@ -1056,6 +1282,9 @@ packages:
uri-js@4.4.1:
resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==}
+ util-deprecate@1.0.2:
+ resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==}
+
vite@5.4.21:
resolution: {integrity: sha512-o5a9xKjbtuhY6Bi5S3+HvbRERmouabWbyUcpXXUA1u+GNUKoROi9byOJ8M0nHbHYHkYICiMlqxkg1KkYmm25Sw==}
engines: {node: ^18.0.0 || >=20.0.0}
@@ -1087,6 +1316,29 @@ packages:
terser:
optional: true
+ vue-eslint-parser@9.4.3:
+ resolution: {integrity: sha512-2rYRLWlIpaiN8xbPiDyXZXRgLGOtWxERV7ND5fFAv5qo1D2N9Fu9MNajBNc6o13lZ+24DAWCkQCvj4klgmcITg==}
+ engines: {node: ^14.17.0 || >=16.0.0}
+ peerDependencies:
+ eslint: '>=6.0.0'
+
+ vue-template-compiler@2.7.16:
+ resolution: {integrity: sha512-AYbUWAJHLGGQM7+cNTELw+KsOG9nl2CnSv467WobS5Cv9uk3wFcnr1Etsz2sEIHEZvw1U+o9mRlEO6QbZvUPGQ==}
+
+ vue-tsc@1.8.27:
+ resolution: {integrity: sha512-WesKCAZCRAbmmhuGl3+VrdWItEvfoFIPXOvUJkjULi+x+6G/Dy69yO3TBRJDr9eUlmsNAwVmxsNZxvHKzbkKdg==}
+ hasBin: true
+ peerDependencies:
+ typescript: '*'
+
+ vue@3.5.22:
+ resolution: {integrity: sha512-toaZjQ3a/G/mYaLSbV+QsQhIdMo9x5rrqIpYRObsJ6T/J+RyCSFwN2LHNVH9v8uIcljDNa3QzPVdv3Y6b9hAJQ==}
+ peerDependencies:
+ typescript: '*'
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+
which@2.0.2:
resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==}
engines: {node: '>= 8'}
@@ -1096,11 +1348,20 @@ packages:
resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==}
engines: {node: '>=0.10.0'}
+ wrap-ansi@7.0.0:
+ resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==}
+ engines: {node: '>=10'}
+
+ wrap-ansi@8.1.0:
+ resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==}
+ engines: {node: '>=12'}
+
wrappy@1.0.2:
resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==}
- yallist@3.1.1:
- resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==}
+ xml-name-validator@4.0.0:
+ resolution: {integrity: sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==}
+ engines: {node: '>=12'}
yocto-queue@0.1.0:
resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==}
@@ -1108,113 +1369,16 @@ packages:
snapshots:
- '@babel/code-frame@7.27.1':
- dependencies:
- '@babel/helper-validator-identifier': 7.27.1
- js-tokens: 4.0.0
- picocolors: 1.1.1
-
- '@babel/compat-data@7.28.4': {}
-
- '@babel/core@7.28.4':
- dependencies:
- '@babel/code-frame': 7.27.1
- '@babel/generator': 7.28.3
- '@babel/helper-compilation-targets': 7.27.2
- '@babel/helper-module-transforms': 7.28.3(@babel/core@7.28.4)
- '@babel/helpers': 7.28.4
- '@babel/parser': 7.28.4
- '@babel/template': 7.27.2
- '@babel/traverse': 7.28.4
- '@babel/types': 7.28.4
- '@jridgewell/remapping': 2.3.5
- convert-source-map: 2.0.0
- debug: 4.4.3
- gensync: 1.0.0-beta.2
- json5: 2.2.3
- semver: 6.3.1
- transitivePeerDependencies:
- - supports-color
-
- '@babel/generator@7.28.3':
- dependencies:
- '@babel/parser': 7.28.4
- '@babel/types': 7.28.4
- '@jridgewell/gen-mapping': 0.3.13
- '@jridgewell/trace-mapping': 0.3.31
- jsesc: 3.1.0
-
- '@babel/helper-compilation-targets@7.27.2':
- dependencies:
- '@babel/compat-data': 7.28.4
- '@babel/helper-validator-option': 7.27.1
- browserslist: 4.26.3
- lru-cache: 5.1.1
- semver: 6.3.1
-
- '@babel/helper-globals@7.28.0': {}
-
- '@babel/helper-module-imports@7.27.1':
- dependencies:
- '@babel/traverse': 7.28.4
- '@babel/types': 7.28.4
- transitivePeerDependencies:
- - supports-color
-
- '@babel/helper-module-transforms@7.28.3(@babel/core@7.28.4)':
- dependencies:
- '@babel/core': 7.28.4
- '@babel/helper-module-imports': 7.27.1
- '@babel/helper-validator-identifier': 7.27.1
- '@babel/traverse': 7.28.4
- transitivePeerDependencies:
- - supports-color
-
- '@babel/helper-plugin-utils@7.27.1': {}
+ '@alloc/quick-lru@5.2.0': {}
'@babel/helper-string-parser@7.27.1': {}
'@babel/helper-validator-identifier@7.27.1': {}
- '@babel/helper-validator-option@7.27.1': {}
-
- '@babel/helpers@7.28.4':
- dependencies:
- '@babel/template': 7.27.2
- '@babel/types': 7.28.4
-
'@babel/parser@7.28.4':
dependencies:
'@babel/types': 7.28.4
- '@babel/plugin-transform-react-jsx-self@7.27.1(@babel/core@7.28.4)':
- dependencies:
- '@babel/core': 7.28.4
- '@babel/helper-plugin-utils': 7.27.1
-
- '@babel/plugin-transform-react-jsx-source@7.27.1(@babel/core@7.28.4)':
- dependencies:
- '@babel/core': 7.28.4
- '@babel/helper-plugin-utils': 7.27.1
-
- '@babel/template@7.27.2':
- dependencies:
- '@babel/code-frame': 7.27.1
- '@babel/parser': 7.28.4
- '@babel/types': 7.28.4
-
- '@babel/traverse@7.28.4':
- dependencies:
- '@babel/code-frame': 7.27.1
- '@babel/generator': 7.28.3
- '@babel/helper-globals': 7.28.0
- '@babel/parser': 7.28.4
- '@babel/template': 7.27.2
- '@babel/types': 7.28.4
- debug: 4.4.3
- transitivePeerDependencies:
- - supports-color
-
'@babel/types@7.28.4':
dependencies:
'@babel/helper-string-parser': 7.27.1
@@ -1324,16 +1488,20 @@ snapshots:
'@humanwhocodes/object-schema@2.0.3': {}
+ '@isaacs/cliui@8.0.2':
+ dependencies:
+ string-width: 5.1.2
+ string-width-cjs: string-width@4.2.3
+ strip-ansi: 7.1.2
+ strip-ansi-cjs: strip-ansi@6.0.1
+ wrap-ansi: 8.1.0
+ wrap-ansi-cjs: wrap-ansi@7.0.0
+
'@jridgewell/gen-mapping@0.3.13':
dependencies:
'@jridgewell/sourcemap-codec': 1.5.5
'@jridgewell/trace-mapping': 0.3.31
- '@jridgewell/remapping@2.3.5':
- dependencies:
- '@jridgewell/gen-mapping': 0.3.13
- '@jridgewell/trace-mapping': 0.3.31
-
'@jridgewell/resolve-uri@3.1.2': {}
'@jridgewell/sourcemap-codec@1.5.5': {}
@@ -1355,7 +1523,8 @@ snapshots:
'@nodelib/fs.scandir': 2.1.5
fastq: 1.19.1
- '@rolldown/pluginutils@1.0.0-beta.27': {}
+ '@pkgjs/parseargs@0.11.0':
+ optional: true
'@rollup/rollup-android-arm-eabi@4.52.5':
optional: true
@@ -1423,42 +1592,10 @@ snapshots:
'@rollup/rollup-win32-x64-msvc@4.52.5':
optional: true
- '@types/babel__core@7.20.5':
- dependencies:
- '@babel/parser': 7.28.4
- '@babel/types': 7.28.4
- '@types/babel__generator': 7.27.0
- '@types/babel__template': 7.4.4
- '@types/babel__traverse': 7.28.0
-
- '@types/babel__generator@7.27.0':
- dependencies:
- '@babel/types': 7.28.4
-
- '@types/babel__template@7.4.4':
- dependencies:
- '@babel/parser': 7.28.4
- '@babel/types': 7.28.4
-
- '@types/babel__traverse@7.28.0':
- dependencies:
- '@babel/types': 7.28.4
-
'@types/estree@1.0.8': {}
'@types/json-schema@7.0.15': {}
- '@types/prop-types@15.7.15': {}
-
- '@types/react-dom@18.3.7(@types/react@18.3.26)':
- dependencies:
- '@types/react': 18.3.26
-
- '@types/react@18.3.26':
- dependencies:
- '@types/prop-types': 15.7.15
- csstype: 3.1.3
-
'@types/semver@7.7.1': {}
'@typescript-eslint/eslint-plugin@6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.9.3))(eslint@8.57.1)(typescript@5.9.3)':
@@ -1549,18 +1686,104 @@ snapshots:
'@ungap/structured-clone@1.3.0': {}
- '@vitejs/plugin-react@4.7.0(vite@5.4.21)':
+ '@vitejs/plugin-vue@5.2.4(vite@5.4.21)(vue@3.5.22(typescript@5.9.3))':
dependencies:
- '@babel/core': 7.28.4
- '@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.28.4)
- '@babel/plugin-transform-react-jsx-source': 7.27.1(@babel/core@7.28.4)
- '@rolldown/pluginutils': 1.0.0-beta.27
- '@types/babel__core': 7.20.5
- react-refresh: 0.17.0
vite: 5.4.21
+ vue: 3.5.22(typescript@5.9.3)
+
+ '@volar/language-core@1.11.1':
+ dependencies:
+ '@volar/source-map': 1.11.1
+
+ '@volar/source-map@1.11.1':
+ dependencies:
+ muggle-string: 0.3.1
+
+ '@volar/typescript@1.11.1':
+ dependencies:
+ '@volar/language-core': 1.11.1
+ path-browserify: 1.0.1
+
+ '@vue/compiler-core@3.5.22':
+ dependencies:
+ '@babel/parser': 7.28.4
+ '@vue/shared': 3.5.22
+ entities: 4.5.0
+ estree-walker: 2.0.2
+ source-map-js: 1.2.1
+
+ '@vue/compiler-dom@3.5.22':
+ dependencies:
+ '@vue/compiler-core': 3.5.22
+ '@vue/shared': 3.5.22
+
+ '@vue/compiler-sfc@3.5.22':
+ dependencies:
+ '@babel/parser': 7.28.4
+ '@vue/compiler-core': 3.5.22
+ '@vue/compiler-dom': 3.5.22
+ '@vue/compiler-ssr': 3.5.22
+ '@vue/shared': 3.5.22
+ estree-walker: 2.0.2
+ magic-string: 0.30.19
+ postcss: 8.5.6
+ source-map-js: 1.2.1
+
+ '@vue/compiler-ssr@3.5.22':
+ dependencies:
+ '@vue/compiler-dom': 3.5.22
+ '@vue/shared': 3.5.22
+
+ '@vue/eslint-config-typescript@12.0.0(eslint-plugin-vue@9.33.0(eslint@8.57.1))(eslint@8.57.1)(typescript@5.9.3)':
+ dependencies:
+ '@typescript-eslint/eslint-plugin': 6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.9.3))(eslint@8.57.1)(typescript@5.9.3)
+ '@typescript-eslint/parser': 6.21.0(eslint@8.57.1)(typescript@5.9.3)
+ eslint: 8.57.1
+ eslint-plugin-vue: 9.33.0(eslint@8.57.1)
+ vue-eslint-parser: 9.4.3(eslint@8.57.1)
+ optionalDependencies:
+ typescript: 5.9.3
transitivePeerDependencies:
- supports-color
+ '@vue/language-core@1.8.27(typescript@5.9.3)':
+ dependencies:
+ '@volar/language-core': 1.11.1
+ '@volar/source-map': 1.11.1
+ '@vue/compiler-dom': 3.5.22
+ '@vue/shared': 3.5.22
+ computeds: 0.0.1
+ minimatch: 9.0.3
+ muggle-string: 0.3.1
+ path-browserify: 1.0.1
+ vue-template-compiler: 2.7.16
+ optionalDependencies:
+ typescript: 5.9.3
+
+ '@vue/reactivity@3.5.22':
+ dependencies:
+ '@vue/shared': 3.5.22
+
+ '@vue/runtime-core@3.5.22':
+ dependencies:
+ '@vue/reactivity': 3.5.22
+ '@vue/shared': 3.5.22
+
+ '@vue/runtime-dom@3.5.22':
+ dependencies:
+ '@vue/reactivity': 3.5.22
+ '@vue/runtime-core': 3.5.22
+ '@vue/shared': 3.5.22
+ csstype: 3.1.3
+
+ '@vue/server-renderer@3.5.22(vue@3.5.22(typescript@5.9.3))':
+ dependencies:
+ '@vue/compiler-ssr': 3.5.22
+ '@vue/shared': 3.5.22
+ vue: 3.5.22(typescript@5.9.3)
+
+ '@vue/shared@3.5.22': {}
+
acorn-jsx@5.3.2(acorn@8.15.0):
dependencies:
acorn: 8.15.0
@@ -1576,18 +1799,45 @@ snapshots:
ansi-regex@5.0.1: {}
+ ansi-regex@6.2.2: {}
+
ansi-styles@4.3.0:
dependencies:
color-convert: 2.0.1
+ ansi-styles@6.2.3: {}
+
+ any-promise@1.3.0: {}
+
+ anymatch@3.1.3:
+ dependencies:
+ normalize-path: 3.0.0
+ picomatch: 2.3.1
+
+ arg@5.0.2: {}
+
argparse@2.0.1: {}
array-union@2.1.0: {}
+ autoprefixer@10.4.21(postcss@8.5.6):
+ dependencies:
+ browserslist: 4.26.3
+ caniuse-lite: 1.0.30001751
+ fraction.js: 4.3.7
+ normalize-range: 0.1.2
+ picocolors: 1.1.1
+ postcss: 8.5.6
+ postcss-value-parser: 4.2.0
+
balanced-match@1.0.2: {}
baseline-browser-mapping@2.8.18: {}
+ binary-extensions@2.3.0: {}
+
+ boolbase@1.0.0: {}
+
brace-expansion@1.1.12:
dependencies:
balanced-match: 1.0.2
@@ -1611,6 +1861,8 @@ snapshots:
callsites@3.1.0: {}
+ camelcase-css@2.0.1: {}
+
caniuse-lite@1.0.30001751: {}
chalk@4.1.2:
@@ -1618,15 +1870,29 @@ snapshots:
ansi-styles: 4.3.0
supports-color: 7.2.0
+ chokidar@3.6.0:
+ dependencies:
+ anymatch: 3.1.3
+ braces: 3.0.3
+ glob-parent: 5.1.2
+ is-binary-path: 2.1.0
+ is-glob: 4.0.3
+ normalize-path: 3.0.0
+ readdirp: 3.6.0
+ optionalDependencies:
+ fsevents: 2.3.3
+
color-convert@2.0.1:
dependencies:
color-name: 1.1.4
color-name@1.1.4: {}
- concat-map@0.0.1: {}
+ commander@4.1.1: {}
- convert-source-map@2.0.0: {}
+ computeds@0.0.1: {}
+
+ concat-map@0.0.1: {}
cross-spawn@7.0.6:
dependencies:
@@ -1634,24 +1900,56 @@ snapshots:
shebang-command: 2.0.0
which: 2.0.2
+ css-selector-tokenizer@0.8.0:
+ dependencies:
+ cssesc: 3.0.0
+ fastparse: 1.1.2
+
+ cssesc@3.0.0: {}
+
csstype@3.1.3: {}
+ culori@3.3.0: {}
+
+ daisyui@4.12.24(postcss@8.5.6):
+ dependencies:
+ css-selector-tokenizer: 0.8.0
+ culori: 3.3.0
+ picocolors: 1.1.1
+ postcss-js: 4.1.0(postcss@8.5.6)
+ transitivePeerDependencies:
+ - postcss
+
+ de-indent@1.0.2: {}
+
debug@4.4.3:
dependencies:
ms: 2.1.3
deep-is@0.1.4: {}
+ didyoumean@1.2.2: {}
+
dir-glob@3.0.1:
dependencies:
path-type: 4.0.0
+ dlv@1.1.3: {}
+
doctrine@3.0.0:
dependencies:
esutils: 2.0.3
+ eastasianwidth@0.2.0: {}
+
electron-to-chromium@1.5.237: {}
+ emoji-regex@8.0.0: {}
+
+ emoji-regex@9.2.2: {}
+
+ entities@4.5.0: {}
+
esbuild@0.21.5:
optionalDependencies:
'@esbuild/aix-ppc64': 0.21.5
@@ -1682,13 +1980,19 @@ snapshots:
escape-string-regexp@4.0.0: {}
- eslint-plugin-react-hooks@4.6.2(eslint@8.57.1):
- dependencies:
- eslint: 8.57.1
-
- eslint-plugin-react-refresh@0.4.24(eslint@8.57.1):
+ eslint-plugin-vue@9.33.0(eslint@8.57.1):
dependencies:
+ '@eslint-community/eslint-utils': 4.9.0(eslint@8.57.1)
eslint: 8.57.1
+ globals: 13.24.0
+ natural-compare: 1.4.0
+ nth-check: 2.1.1
+ postcss-selector-parser: 6.1.2
+ semver: 7.7.3
+ vue-eslint-parser: 9.4.3(eslint@8.57.1)
+ xml-name-validator: 4.0.0
+ transitivePeerDependencies:
+ - supports-color
eslint-scope@7.2.2:
dependencies:
@@ -1756,6 +2060,8 @@ snapshots:
estraverse@5.3.0: {}
+ estree-walker@2.0.2: {}
+
esutils@2.0.3: {}
fast-deep-equal@3.1.3: {}
@@ -1772,6 +2078,8 @@ snapshots:
fast-levenshtein@2.0.6: {}
+ fastparse@1.1.2: {}
+
fastq@1.19.1:
dependencies:
reusify: 1.1.0
@@ -1797,12 +2105,19 @@ snapshots:
flatted@3.3.3: {}
+ foreground-child@3.3.1:
+ dependencies:
+ cross-spawn: 7.0.6
+ signal-exit: 4.1.0
+
+ fraction.js@4.3.7: {}
+
fs.realpath@1.0.0: {}
fsevents@2.3.3:
optional: true
- gensync@1.0.0-beta.2: {}
+ function-bind@1.1.2: {}
glob-parent@5.1.2:
dependencies:
@@ -1812,6 +2127,15 @@ snapshots:
dependencies:
is-glob: 4.0.3
+ glob@10.4.5:
+ dependencies:
+ foreground-child: 3.3.1
+ jackspeak: 3.4.3
+ minimatch: 9.0.5
+ minipass: 7.1.2
+ package-json-from-dist: 1.0.1
+ path-scurry: 1.11.1
+
glob@7.2.3:
dependencies:
fs.realpath: 1.0.0
@@ -1838,6 +2162,12 @@ snapshots:
has-flag@4.0.0: {}
+ hasown@2.0.2:
+ dependencies:
+ function-bind: 1.1.2
+
+ he@1.2.0: {}
+
ignore@5.3.2: {}
import-fresh@3.3.1:
@@ -1854,8 +2184,18 @@ snapshots:
inherits@2.0.4: {}
+ is-binary-path@2.1.0:
+ dependencies:
+ binary-extensions: 2.3.0
+
+ is-core-module@2.16.1:
+ dependencies:
+ hasown: 2.0.2
+
is-extglob@2.1.1: {}
+ is-fullwidth-code-point@3.0.0: {}
+
is-glob@4.0.3:
dependencies:
is-extglob: 2.1.1
@@ -1866,22 +2206,24 @@ snapshots:
isexe@2.0.0: {}
- js-tokens@4.0.0: {}
+ jackspeak@3.4.3:
+ dependencies:
+ '@isaacs/cliui': 8.0.2
+ optionalDependencies:
+ '@pkgjs/parseargs': 0.11.0
+
+ jiti@1.21.7: {}
js-yaml@4.1.0:
dependencies:
argparse: 2.0.1
- jsesc@3.1.0: {}
-
json-buffer@3.0.1: {}
json-schema-traverse@0.4.1: {}
json-stable-stringify-without-jsonify@1.0.1: {}
- json5@2.2.3: {}
-
keyv@4.5.4:
dependencies:
json-buffer: 3.0.1
@@ -1891,19 +2233,23 @@ snapshots:
prelude-ls: 1.2.1
type-check: 0.4.0
+ lilconfig@3.1.3: {}
+
+ lines-and-columns@1.2.4: {}
+
locate-path@6.0.0:
dependencies:
p-locate: 5.0.0
lodash.merge@4.6.2: {}
- loose-envify@1.4.0:
- dependencies:
- js-tokens: 4.0.0
+ lodash@4.17.21: {}
- lru-cache@5.1.1:
+ lru-cache@10.4.3: {}
+
+ magic-string@0.30.19:
dependencies:
- yallist: 3.1.1
+ '@jridgewell/sourcemap-codec': 1.5.5
merge2@1.4.1: {}
@@ -1920,14 +2266,40 @@ snapshots:
dependencies:
brace-expansion: 2.0.2
+ minimatch@9.0.5:
+ dependencies:
+ brace-expansion: 2.0.2
+
+ minipass@7.1.2: {}
+
ms@2.1.3: {}
+ muggle-string@0.3.1: {}
+
+ mz@2.7.0:
+ dependencies:
+ any-promise: 1.3.0
+ object-assign: 4.1.1
+ thenify-all: 1.6.0
+
nanoid@3.3.11: {}
natural-compare@1.4.0: {}
node-releases@2.0.25: {}
+ normalize-path@3.0.0: {}
+
+ normalize-range@0.1.2: {}
+
+ nth-check@2.1.1:
+ dependencies:
+ boolbase: 1.0.0
+
+ object-assign@4.1.1: {}
+
+ object-hash@3.0.0: {}
+
once@1.4.0:
dependencies:
wrappy: 1.0.2
@@ -1949,22 +2321,68 @@ snapshots:
dependencies:
p-limit: 3.1.0
+ package-json-from-dist@1.0.1: {}
+
parent-module@1.0.1:
dependencies:
callsites: 3.1.0
+ path-browserify@1.0.1: {}
+
path-exists@4.0.0: {}
path-is-absolute@1.0.1: {}
path-key@3.1.1: {}
+ path-parse@1.0.7: {}
+
+ path-scurry@1.11.1:
+ dependencies:
+ lru-cache: 10.4.3
+ minipass: 7.1.2
+
path-type@4.0.0: {}
picocolors@1.1.1: {}
picomatch@2.3.1: {}
+ pify@2.3.0: {}
+
+ pirates@4.0.7: {}
+
+ postcss-import@15.1.0(postcss@8.5.6):
+ dependencies:
+ postcss: 8.5.6
+ postcss-value-parser: 4.2.0
+ read-cache: 1.0.0
+ resolve: 1.22.10
+
+ postcss-js@4.1.0(postcss@8.5.6):
+ dependencies:
+ camelcase-css: 2.0.1
+ postcss: 8.5.6
+
+ postcss-load-config@6.0.1(jiti@1.21.7)(postcss@8.5.6):
+ dependencies:
+ lilconfig: 3.1.3
+ optionalDependencies:
+ jiti: 1.21.7
+ postcss: 8.5.6
+
+ postcss-nested@6.2.0(postcss@8.5.6):
+ dependencies:
+ postcss: 8.5.6
+ postcss-selector-parser: 6.1.2
+
+ postcss-selector-parser@6.1.2:
+ dependencies:
+ cssesc: 3.0.0
+ util-deprecate: 1.0.2
+
+ postcss-value-parser@4.2.0: {}
+
postcss@8.5.6:
dependencies:
nanoid: 3.3.11
@@ -1977,20 +2395,22 @@ snapshots:
queue-microtask@1.2.3: {}
- react-dom@18.3.1(react@18.3.1):
+ read-cache@1.0.0:
dependencies:
- loose-envify: 1.4.0
- react: 18.3.1
- scheduler: 0.23.2
+ pify: 2.3.0
- react-refresh@0.17.0: {}
-
- react@18.3.1:
+ readdirp@3.6.0:
dependencies:
- loose-envify: 1.4.0
+ picomatch: 2.3.1
resolve-from@4.0.0: {}
+ resolve@1.22.10:
+ dependencies:
+ is-core-module: 2.16.1
+ path-parse: 1.0.7
+ supports-preserve-symlinks-flag: 1.0.0
+
reusify@1.1.0: {}
rimraf@3.0.2:
@@ -2029,12 +2449,6 @@ snapshots:
dependencies:
queue-microtask: 1.2.3
- scheduler@0.23.2:
- dependencies:
- loose-envify: 1.4.0
-
- semver@6.3.1: {}
-
semver@7.7.3: {}
shebang-command@2.0.0:
@@ -2043,22 +2457,88 @@ snapshots:
shebang-regex@3.0.0: {}
+ signal-exit@4.1.0: {}
+
slash@3.0.0: {}
source-map-js@1.2.1: {}
+ string-width@4.2.3:
+ dependencies:
+ emoji-regex: 8.0.0
+ is-fullwidth-code-point: 3.0.0
+ strip-ansi: 6.0.1
+
+ string-width@5.1.2:
+ dependencies:
+ eastasianwidth: 0.2.0
+ emoji-regex: 9.2.2
+ strip-ansi: 7.1.2
+
strip-ansi@6.0.1:
dependencies:
ansi-regex: 5.0.1
+ strip-ansi@7.1.2:
+ dependencies:
+ ansi-regex: 6.2.2
+
strip-json-comments@3.1.1: {}
+ sucrase@3.35.0:
+ dependencies:
+ '@jridgewell/gen-mapping': 0.3.13
+ commander: 4.1.1
+ glob: 10.4.5
+ lines-and-columns: 1.2.4
+ mz: 2.7.0
+ pirates: 4.0.7
+ ts-interface-checker: 0.1.13
+
supports-color@7.2.0:
dependencies:
has-flag: 4.0.0
+ supports-preserve-symlinks-flag@1.0.0: {}
+
+ tailwindcss@3.4.18:
+ dependencies:
+ '@alloc/quick-lru': 5.2.0
+ arg: 5.0.2
+ chokidar: 3.6.0
+ didyoumean: 1.2.2
+ dlv: 1.1.3
+ fast-glob: 3.3.3
+ glob-parent: 6.0.2
+ is-glob: 4.0.3
+ jiti: 1.21.7
+ lilconfig: 3.1.3
+ micromatch: 4.0.8
+ normalize-path: 3.0.0
+ object-hash: 3.0.0
+ picocolors: 1.1.1
+ postcss: 8.5.6
+ postcss-import: 15.1.0(postcss@8.5.6)
+ postcss-js: 4.1.0(postcss@8.5.6)
+ postcss-load-config: 6.0.1(jiti@1.21.7)(postcss@8.5.6)
+ postcss-nested: 6.2.0(postcss@8.5.6)
+ postcss-selector-parser: 6.1.2
+ resolve: 1.22.10
+ sucrase: 3.35.0
+ transitivePeerDependencies:
+ - tsx
+ - yaml
+
text-table@0.2.0: {}
+ thenify-all@1.6.0:
+ dependencies:
+ thenify: 3.3.1
+
+ thenify@3.3.1:
+ dependencies:
+ any-promise: 1.3.0
+
to-regex-range@5.0.1:
dependencies:
is-number: 7.0.0
@@ -2067,6 +2547,8 @@ snapshots:
dependencies:
typescript: 5.9.3
+ ts-interface-checker@0.1.13: {}
+
type-check@0.4.0:
dependencies:
prelude-ls: 1.2.1
@@ -2085,6 +2567,8 @@ snapshots:
dependencies:
punycode: 2.3.1
+ util-deprecate@1.0.2: {}
+
vite@5.4.21:
dependencies:
esbuild: 0.21.5
@@ -2093,14 +2577,61 @@ snapshots:
optionalDependencies:
fsevents: 2.3.3
+ vue-eslint-parser@9.4.3(eslint@8.57.1):
+ dependencies:
+ debug: 4.4.3
+ eslint: 8.57.1
+ eslint-scope: 7.2.2
+ eslint-visitor-keys: 3.4.3
+ espree: 9.6.1
+ esquery: 1.6.0
+ lodash: 4.17.21
+ semver: 7.7.3
+ transitivePeerDependencies:
+ - supports-color
+
+ vue-template-compiler@2.7.16:
+ dependencies:
+ de-indent: 1.0.2
+ he: 1.2.0
+
+ vue-tsc@1.8.27(typescript@5.9.3):
+ dependencies:
+ '@volar/typescript': 1.11.1
+ '@vue/language-core': 1.8.27(typescript@5.9.3)
+ semver: 7.7.3
+ typescript: 5.9.3
+
+ vue@3.5.22(typescript@5.9.3):
+ dependencies:
+ '@vue/compiler-dom': 3.5.22
+ '@vue/compiler-sfc': 3.5.22
+ '@vue/runtime-dom': 3.5.22
+ '@vue/server-renderer': 3.5.22(vue@3.5.22(typescript@5.9.3))
+ '@vue/shared': 3.5.22
+ optionalDependencies:
+ typescript: 5.9.3
+
which@2.0.2:
dependencies:
isexe: 2.0.0
word-wrap@1.2.5: {}
+ wrap-ansi@7.0.0:
+ dependencies:
+ ansi-styles: 4.3.0
+ string-width: 4.2.3
+ strip-ansi: 6.0.1
+
+ wrap-ansi@8.1.0:
+ dependencies:
+ ansi-styles: 6.2.3
+ string-width: 5.1.2
+ strip-ansi: 7.1.2
+
wrappy@1.0.2: {}
- yallist@3.1.1: {}
+ xml-name-validator@4.0.0: {}
yocto-queue@0.1.0: {}
diff --git a/postcss.config.js b/postcss.config.js
new file mode 100644
index 0000000..ba7e2f8
--- /dev/null
+++ b/postcss.config.js
@@ -0,0 +1,7 @@
+export default {
+ plugins: {
+ tailwindcss: {},
+ autoprefixer: {},
+ },
+}
+
diff --git a/src/App.css b/src/App.css
deleted file mode 100644
index 47419ad..0000000
--- a/src/App.css
+++ /dev/null
@@ -1,169 +0,0 @@
-.app {
- display: flex;
- flex-direction: column;
- min-height: 100vh;
- width: 100%;
-}
-
-.app-header {
- background: linear-gradient(135deg, var(--primary-color) 0%, #4338ca 100%);
- color: white;
- padding: 2rem;
- box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
-}
-
-.header-content {
- max-width: 1200px;
- margin: 0 auto;
-}
-
-.app-header h1 {
- font-size: 2.5rem;
- margin-bottom: 0.5rem;
- color: white;
-}
-
-.subtitle {
- font-size: 1.1rem;
- opacity: 0.9;
- color: rgba(255, 255, 255, 0.9);
-}
-
-.app-main {
- flex: 1;
- padding: 2rem;
- max-width: 1400px;
- width: 100%;
- margin: 0 auto;
-}
-
-.login-container {
- display: grid;
- grid-template-columns: 1fr 1fr;
- gap: 2rem;
- margin-top: 2rem;
-}
-
-@media (max-width: 968px) {
- .login-container {
- grid-template-columns: 1fr;
- }
-}
-
-.server-section,
-.auth-section {
- background: var(--surface);
- border-radius: 12px;
- padding: 2rem;
- box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1);
- border: 1px solid var(--border);
-}
-
-.app-footer {
- background: var(--surface);
- border-top: 1px solid var(--border);
- padding: 1.5rem;
- text-align: center;
- color: var(--text-secondary);
- font-size: 0.9rem;
-}
-
-/* Button Styles */
-.btn {
- border-radius: 8px;
- border: 1px solid transparent;
- padding: 0.6em 1.2em;
- font-size: 1em;
- font-weight: 500;
- font-family: inherit;
- cursor: pointer;
- transition: all 0.25s;
- display: inline-flex;
- align-items: center;
- justify-content: center;
- gap: 0.5em;
-}
-
-.btn:disabled {
- opacity: 0.5;
- cursor: not-allowed;
-}
-
-.btn-primary {
- background-color: var(--primary-color);
- color: white;
-}
-
-.btn-primary:hover:not(:disabled) {
- background-color: var(--primary-hover);
-}
-
-.btn-success {
- background-color: var(--success-color);
- color: white;
-}
-
-.btn-success:hover:not(:disabled) {
- background-color: var(--success-hover);
-}
-
-.btn-danger {
- background-color: var(--danger-color);
- color: white;
-}
-
-.btn-danger:hover:not(:disabled) {
- background-color: var(--danger-hover);
-}
-
-.btn-sm {
- padding: 0.4em 0.8em;
- font-size: 0.875em;
-}
-
-.btn-block {
- width: 100%;
- margin-top: 1rem;
-}
-
-/* Form Styles */
-.form-group {
- margin-bottom: 1.5rem;
-}
-
-.form-group label {
- display: block;
- margin-bottom: 0.5rem;
- font-weight: 500;
- color: var(--text-primary);
-}
-
-.form-group input,
-.form-group select {
- width: 100%;
-}
-
-.form-select {
- width: 100%;
-}
-
-.form-hint {
- display: block;
- margin-top: 0.5rem;
- font-size: 0.875rem;
- color: var(--text-secondary);
-}
-
-.section-header {
- margin-bottom: 1.5rem;
-}
-
-.section-header h2 {
- font-size: 1.5rem;
- margin-bottom: 0.5rem;
-}
-
-.section-header p {
- color: var(--text-secondary);
-}
-
diff --git a/src/App.tsx b/src/App.tsx
deleted file mode 100644
index 78dd2a3..0000000
--- a/src/App.tsx
+++ /dev/null
@@ -1,127 +0,0 @@
-import { useState, useEffect } from 'react';
-import './App.css';
-import { VaultServer, VaultCredentials, VaultConnection } from './types';
-import ServerSelector from './components/ServerSelector';
-import LoginForm from './components/LoginForm';
-import Dashboard from './components/Dashboard';
-
-function App() {
- const [servers, setServers] = useState([]);
- const [selectedServer, setSelectedServer] = useState(null);
- const [activeConnection, setActiveConnection] = useState(null);
-
- // Load servers from localStorage on mount
- useEffect(() => {
- const savedServers = localStorage.getItem('vaultServers');
- if (savedServers) {
- setServers(JSON.parse(savedServers));
- }
- }, []);
-
- // Save servers to localStorage whenever they change
- useEffect(() => {
- if (servers.length > 0) {
- localStorage.setItem('vaultServers', JSON.stringify(servers));
- }
- }, [servers]);
-
- const handleAddServer = (server: VaultServer) => {
- setServers([...servers, server]);
- };
-
- const handleRemoveServer = (serverId: string) => {
- setServers(servers.filter(s => s.id !== serverId));
- if (selectedServer?.id === serverId) {
- setSelectedServer(null);
- setActiveConnection(null);
- }
- };
-
- const handleSelectServer = (server: VaultServer) => {
- setSelectedServer(server);
- setActiveConnection(null);
- };
-
- const handleLogin = async (credentials: VaultCredentials) => {
- if (!selectedServer) return;
-
- try {
- // Verify login and get mount points
- const { vaultApi } = await import('./services/vaultApi');
- const mountPoints = await vaultApi.verifyLoginAndGetMounts(
- selectedServer,
- credentials
- );
-
- const connection: VaultConnection = {
- server: selectedServer,
- credentials,
- isConnected: true,
- lastConnected: new Date(),
- mountPoints,
- };
-
- setActiveConnection(connection);
-
- console.log(`✓ Logged in successfully. Found ${mountPoints.length} KV mount point(s).`);
- } catch (error) {
- console.error('Login failed:', error);
- alert(
- `Login failed: ${error instanceof Error ? error.message : 'Unknown error'}\n\n` +
- 'Please check your credentials and server configuration.'
- );
- }
- };
-
- const handleLogout = () => {
- setActiveConnection(null);
- };
-
- return (
-
-
-
-
- {!activeConnection ? (
-
-
-
-
-
- {selectedServer && (
-
-
-
- )}
-
- ) : (
-
- )}
-
-
-
-
- );
-}
-
-export default App;
-
diff --git a/src/App.vue b/src/App.vue
new file mode 100644
index 0000000..c7a71aa
--- /dev/null
+++ b/src/App.vue
@@ -0,0 +1,127 @@
+
+
+
+
+
+
+
+
🔐 Browser Vault GUI
+
Alternative frontend for HashiCorp Vault
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Browser Vault GUI - An alternative frontend for HashiCorp Vault
+
+
+
+
+
diff --git a/src/components/Dashboard.css b/src/components/Dashboard.css
deleted file mode 100644
index 9a92e44..0000000
--- a/src/components/Dashboard.css
+++ /dev/null
@@ -1,175 +0,0 @@
-.dashboard {
- background: var(--surface);
- border-radius: 12px;
- padding: 2rem;
- box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1);
- border: 1px solid var(--border);
-}
-
-.dashboard-header {
- display: flex;
- justify-content: space-between;
- align-items: flex-start;
- padding-bottom: 2rem;
- border-bottom: 1px solid var(--border);
- margin-bottom: 2rem;
-}
-
-.dashboard-actions {
- display: flex;
- gap: 0.5rem;
- flex-wrap: wrap;
-}
-
-.connection-info h2 {
- margin: 0 0 0.5rem 0;
- font-size: 1.75rem;
-}
-
-.connection-info .server-url {
- color: var(--text-secondary);
- font-size: 0.875rem;
- font-family: 'Courier New', monospace;
- margin: 0.25rem 0;
-}
-
-.connection-info .auth-info {
- color: var(--text-secondary);
- font-size: 0.875rem;
- margin-top: 0.5rem;
-}
-
-.connection-time {
- font-style: italic;
-}
-
-.dashboard-content {
- max-width: 900px;
-}
-
-.secret-browser h3 {
- margin-bottom: 1.5rem;
- font-size: 1.5rem;
-}
-
-.secret-path-input {
- margin-bottom: 2rem;
-}
-
-.secret-path-input label {
- display: block;
- margin-bottom: 0.5rem;
- font-weight: 500;
-}
-
-.input-group {
- display: flex;
- gap: 0.5rem;
-}
-
-.input-group input {
- flex: 1;
-}
-
-.secret-display {
- background: var(--surface-light);
- border-radius: 8px;
- padding: 1.5rem;
- margin-bottom: 2rem;
- border: 1px solid var(--border);
-}
-
-.secret-display h4 {
- margin: 0 0 1rem 0;
- font-size: 1.25rem;
-}
-
-.secret-data {
- background: var(--surface);
- padding: 1rem;
- border-radius: 6px;
- overflow-x: auto;
- font-size: 0.875rem;
- line-height: 1.6;
- margin: 0;
-}
-
-.info-box {
- background: linear-gradient(135deg, rgba(100, 108, 255, 0.1) 0%, rgba(67, 56, 202, 0.1) 100%);
- border: 1px solid var(--primary-color);
- border-radius: 8px;
- padding: 1.5rem;
- margin-bottom: 2rem;
-}
-
-.info-box h4 {
- margin: 0 0 1rem 0;
- color: var(--primary-color);
-}
-
-.info-box ul {
- margin: 0.5rem 0;
- padding-left: 1.5rem;
-}
-
-.info-box li {
- margin: 0.5rem 0;
- line-height: 1.6;
-}
-
-.api-info {
- background: var(--surface-light);
- border-radius: 8px;
- padding: 1.5rem;
- border: 1px solid var(--border);
-}
-
-.api-info h4 {
- margin: 0 0 1rem 0;
- font-size: 1.25rem;
-}
-
-.api-info p {
- margin: 0.75rem 0;
- line-height: 1.6;
- color: var(--text-secondary);
-}
-
-.api-info ul {
- margin: 0.5rem 0;
- padding-left: 1.5rem;
-}
-
-.api-info li {
- margin: 0.5rem 0;
- line-height: 1.6;
- color: var(--text-secondary);
-}
-
-.api-info strong {
- color: var(--text-primary);
-}
-
-@media (max-width: 768px) {
- .dashboard-header {
- flex-direction: column;
- gap: 1rem;
- }
-
- .dashboard-actions {
- width: 100%;
- }
-
- .dashboard-actions button {
- flex: 1;
- }
-
- .input-group {
- flex-direction: column;
- }
-
- .input-group button {
- width: 100%;
- }
-}
-
diff --git a/src/components/Dashboard.tsx b/src/components/Dashboard.tsx
deleted file mode 100644
index 46ee6cf..0000000
--- a/src/components/Dashboard.tsx
+++ /dev/null
@@ -1,198 +0,0 @@
-import { useState } from 'react';
-import { VaultConnection } from '../types';
-import { vaultApi, VaultError } from '../services/vaultApi';
-import PathSearch from './PathSearch';
-import Settings from './Settings';
-import './Dashboard.css';
-
-interface DashboardProps {
- connection: VaultConnection;
- onLogout: () => void;
-}
-
-function Dashboard({ connection, onLogout }: DashboardProps) {
- const [currentPath, setCurrentPath] = useState('');
- const [secretData, setSecretData] = useState | null>(null);
- const [isLoading, setIsLoading] = useState(false);
- const [showSettings, setShowSettings] = useState(false);
- const [showSearch, setShowSearch] = useState(false);
-
- const handleReadSecret = async (path?: string) => {
- const pathToRead = path || currentPath;
-
- if (!pathToRead) {
- alert('Please enter a secret path');
- return;
- }
-
- setIsLoading(true);
- setSecretData(null);
-
- try {
- const data = await vaultApi.readSecret(
- connection.server,
- connection.credentials,
- pathToRead
- );
-
- if (data) {
- setSecretData(data);
- setCurrentPath(pathToRead);
- } else {
- alert('Secret not found or empty.');
- }
- } catch (error) {
- console.error('Error reading secret:', error);
-
- if (error instanceof VaultError) {
- let message = `Failed to read secret: ${error.message}`;
- if (error.statusCode) {
- message += ` (HTTP ${error.statusCode})`;
- }
- if (error.errors && error.errors.length > 0) {
- message += `\n\nDetails:\n${error.errors.join('\n')}`;
- }
-
- // Special handling for common errors
- if (error.statusCode === 403) {
- message += '\n\nYou may not have permission to read this secret.';
- } else if (error.statusCode === 404) {
- message = 'Secret not found at this path.';
- } else if (error.message.includes('CORS')) {
- message += '\n\nCORS error: Make sure your Vault server is configured to allow requests from this origin.';
- }
-
- alert(message);
- } else {
- alert('Failed to read secret. Check console for details.');
- }
- } finally {
- setIsLoading(false);
- }
- };
-
- const handleSelectPath = (path: string) => {
- setCurrentPath(path);
- handleReadSecret(path);
- setShowSearch(false);
- };
-
- return (
-
-
-
-
Connected to {connection.server.name}
-
{connection.server.url}
-
- Authenticated via {connection.credentials.authMethod}
- {connection.lastConnected && (
-
- {' '}• Connected at {connection.lastConnected.toLocaleTimeString()}
-
- )}
-
-
-
- setShowSearch(!showSearch)}
- >
- {showSearch ? 'Hide Search' : '🔍 Search'}
-
- setShowSettings(true)}
- >
- ⚙️ Settings
-
-
- Logout
-
-
-
-
-
- {showSearch && (
-
- )}
-
-
-
Browse Secrets
-
-
-
Secret Path
-
- setCurrentPath(e.target.value)}
- onKeyPress={(e) => e.key === 'Enter' && !isLoading && handleReadSecret()}
- placeholder="secret/data/myapp/config"
- disabled={isLoading}
- />
- handleReadSecret()}
- disabled={isLoading}
- >
- {isLoading ? 'Loading...' : 'Read Secret'}
-
-
-
-
- {secretData && (
-
-
Secret Data
-
- {JSON.stringify(secretData, null, 2)}
-
-
- )}
-
- {!showSearch && (
-
-
Getting Started
-
- Enter a secret path to read from your Vault server
- Example paths: secret/data/myapp/config
- Use the Search feature to find secrets recursively
- Results are cached to prevent excessive API calls
-
-
- )}
-
-
-
Implementation Notes
-
- This application uses the Vault HTTP API with caching enabled.
- The following endpoints are used:
-
-
- List secrets: GET /v1/{'<'}path{'>'}?list=true
- Read secret: GET /v1/{'<'}path{'>'}
- Write secret: POST/PUT /v1/{'<'}path{'>'}
- Delete secret: DELETE /v1/{'<'}path{'>'}
-
-
- All requests include the X-Vault-Token header for authentication.
- Configure cache settings and search limits in Settings.
-
-
-
-
-
- {showSettings && (
-
setShowSettings(false)} />
- )}
-
- );
-}
-
-export default Dashboard;
-
diff --git a/src/components/Dashboard.vue b/src/components/Dashboard.vue
new file mode 100644
index 0000000..7e8f65d
--- /dev/null
+++ b/src/components/Dashboard.vue
@@ -0,0 +1,211 @@
+
+
+
+
+
+
+
+
+
+
Connected to {{ connection.server.name }}
+
{{ connection.server.url }}
+
+ Authenticated via {{ connection.credentials.authMethod }}
+
+ • Connected at {{ connection.lastConnected.toLocaleTimeString() }}
+
+
+
+
+
+ {{ showSearch ? 'Hide Search' : '🔍 Search' }}
+
+
+ ⚙️ Settings
+
+
+ Logout
+
+
+
+
+
+
+
+
+
+
+
+
+
Browse Secrets
+
+
+
+
+
+
+
Secret Data
+
{{ JSON.stringify(secretData, null, 2) }}
+
+
+
+
+
+
+
+
+
Getting Started
+
+ Enter a secret path to read from your Vault server
+ Example paths: secret/data/myapp/config
+ Use the Search feature to find secrets recursively
+ Results are cached to prevent excessive API calls
+
+
+
+
+
+
+
+
+
+
+
Implementation Notes
+
This application uses the Vault HTTP API with caching enabled.
+
All requests include the X-Vault-Token header for authentication. Configure cache settings and search limits in Settings.
+
+
+
+
+
+
+
+
+
+
diff --git a/src/components/LoginForm.css b/src/components/LoginForm.css
deleted file mode 100644
index e8e3e0a..0000000
--- a/src/components/LoginForm.css
+++ /dev/null
@@ -1,42 +0,0 @@
-.login-form {
- height: 100%;
-}
-
-.login-form .section-header {
- display: block;
- margin-bottom: 1.5rem;
-}
-
-.login-form .section-header h2 {
- margin-bottom: 0.5rem;
-}
-
-.login-form .server-url {
- color: var(--text-secondary);
- font-size: 0.875rem;
- font-family: 'Courier New', monospace;
-}
-
-.login-form form {
- margin-bottom: 2rem;
-}
-
-.security-notice {
- background: var(--surface-light);
- border-left: 4px solid var(--primary-color);
- padding: 1rem;
- border-radius: 4px;
- margin-top: 2rem;
-}
-
-.security-notice p {
- margin: 0;
- font-size: 0.875rem;
- color: var(--text-secondary);
- line-height: 1.6;
-}
-
-.security-notice strong {
- color: var(--text-primary);
-}
-
diff --git a/src/components/LoginForm.tsx b/src/components/LoginForm.tsx
deleted file mode 100644
index b655e03..0000000
--- a/src/components/LoginForm.tsx
+++ /dev/null
@@ -1,128 +0,0 @@
-import { useState } from 'react';
-import { VaultServer, VaultCredentials } from '../types';
-import './LoginForm.css';
-
-interface LoginFormProps {
- server: VaultServer;
- onLogin: (credentials: VaultCredentials) => void;
-}
-
-function LoginForm({ server, onLogin }: LoginFormProps) {
- const [authMethod, setAuthMethod] = useState<'token' | 'userpass' | 'ldap'>('token');
- const [token, setToken] = useState('');
- const [username, setUsername] = useState('');
- const [password, setPassword] = useState('');
- const [isLoading, setIsLoading] = useState(false);
-
- const handleSubmit = async (e: React.FormEvent) => {
- e.preventDefault();
- setIsLoading(true);
-
- const credentials: VaultCredentials = {
- serverId: server.id,
- authMethod,
- token: authMethod === 'token' ? token : undefined,
- username: authMethod !== 'token' ? username : undefined,
- password: authMethod !== 'token' ? password : undefined,
- };
-
- try {
- await onLogin(credentials);
- } catch (error) {
- console.error('Login error:', error);
- alert('Login failed. Please check your credentials.');
- } finally {
- setIsLoading(false);
- }
- };
-
- return (
-
-
-
Connect to {server.name}
-
{server.url}
-
-
-
-
-
-
- ⚠️ Security Notice: This application connects directly to your
- Vault server. Credentials are not stored permanently and are only kept in memory
- during your session.
-
-
-
- );
-}
-
-export default LoginForm;
-
diff --git a/src/components/LoginForm.vue b/src/components/LoginForm.vue
new file mode 100644
index 0000000..1fd5443
--- /dev/null
+++ b/src/components/LoginForm.vue
@@ -0,0 +1,141 @@
+
+
+
+
+
+
+
+
Connect to {{ server.name }}
+
{{ server.url }}
+
+
+
+
+
+
+
+
+
+
+
+
⚠️ Security Notice:
+
This application connects directly to your Vault server. Credentials are not stored permanently and are only kept in memory during your session.
+
+
+
+
+
+
diff --git a/src/components/PathSearch.css b/src/components/PathSearch.css
deleted file mode 100644
index b2e22d9..0000000
--- a/src/components/PathSearch.css
+++ /dev/null
@@ -1,205 +0,0 @@
-.path-search {
- background: var(--surface-light);
- border-radius: 8px;
- padding: 1.5rem;
- margin-bottom: 2rem;
- border: 1px solid var(--border);
-}
-
-.path-search h3 {
- margin: 0 0 1.5rem 0;
- font-size: 1.25rem;
-}
-
-.search-controls {
- margin-bottom: 1rem;
-}
-
-.search-progress {
- display: flex;
- align-items: center;
- gap: 1rem;
- padding: 1.5rem;
- background: var(--surface);
- border-radius: 6px;
- margin: 1rem 0;
-}
-
-.spinner {
- width: 24px;
- height: 24px;
- border: 3px solid var(--border);
- border-top-color: var(--primary-color);
- border-radius: 50%;
- animation: spin 1s linear infinite;
-}
-
-@keyframes spin {
- to {
- transform: rotate(360deg);
- }
-}
-
-.search-stats {
- background: linear-gradient(135deg, rgba(34, 197, 94, 0.1) 0%, rgba(22, 163, 74, 0.1) 100%);
- border: 1px solid var(--success-color);
- border-radius: 6px;
- padding: 1rem;
- margin: 1rem 0;
-}
-
-.search-stats p {
- margin: 0;
- color: var(--text-primary);
-}
-
-.search-results {
- margin-top: 1.5rem;
-}
-
-.search-results h4 {
- margin: 0 0 1rem 0;
- font-size: 1.1rem;
-}
-
-.results-list {
- display: flex;
- flex-direction: column;
- gap: 0.5rem;
- max-height: 400px;
- overflow-y: auto;
- border: 1px solid var(--border);
- border-radius: 6px;
- padding: 0.5rem;
- background: var(--surface);
-}
-
-.result-item {
- display: flex;
- align-items: center;
- gap: 0.75rem;
- padding: 0.75rem;
- background: var(--surface-light);
- border-radius: 6px;
- border: 1px solid var(--border);
- transition: all 0.2s;
-}
-
-.result-item:not(.directory) {
- cursor: pointer;
-}
-
-.result-item:not(.directory):hover {
- border-color: var(--primary-color);
- transform: translateX(4px);
-}
-
-.result-item.directory {
- opacity: 0.8;
-}
-
-.result-icon {
- font-size: 1.25rem;
- flex-shrink: 0;
-}
-
-.result-details {
- flex: 1;
- display: flex;
- flex-direction: column;
- gap: 0.25rem;
-}
-
-.result-path {
- font-family: 'Courier New', monospace;
- font-size: 0.9rem;
- word-break: break-all;
-}
-
-.result-mount {
- font-size: 0.75rem;
- color: var(--text-secondary);
- font-style: italic;
-}
-
-.result-depth {
- font-size: 0.75rem;
- color: var(--text-secondary);
- padding: 0.25rem 0.5rem;
- background: var(--surface);
- border-radius: 4px;
- flex-shrink: 0;
-}
-
-.result-item .btn {
- flex-shrink: 0;
-}
-
-.no-results {
- text-align: center;
- padding: 2rem;
- color: var(--text-secondary);
-}
-
-.no-results p {
- margin: 0 0 0.5rem 0;
- font-size: 1rem;
-}
-
-.no-results small {
- font-size: 0.875rem;
- font-style: italic;
-}
-
-.search-info {
- background: var(--surface);
- border-radius: 6px;
- padding: 1rem;
- margin-top: 1.5rem;
- border: 1px solid var(--border);
-}
-
-.search-info h4 {
- margin: 0 0 0.75rem 0;
- font-size: 1rem;
-}
-
-.search-info ul {
- margin: 0;
- padding-left: 1.5rem;
-}
-
-.search-info li {
- margin: 0.5rem 0;
- font-size: 0.875rem;
- color: var(--text-secondary);
- line-height: 1.5;
-}
-
-.checkbox-label {
- display: flex;
- align-items: center;
- gap: 0.5rem;
- cursor: pointer;
-}
-
-.checkbox-label input[type="checkbox"] {
- width: auto;
- cursor: pointer;
-}
-
-.checkbox-label input[type="checkbox"]:disabled {
- cursor: not-allowed;
- opacity: 0.5;
-}
-
-.mount-count {
- color: var(--primary-color);
- font-weight: 600;
-}
-
-.mount-warning {
- color: var(--danger-color);
- font-size: 0.875rem;
- font-style: italic;
-}
\ No newline at end of file
diff --git a/src/components/PathSearch.tsx b/src/components/PathSearch.tsx
deleted file mode 100644
index bef3349..0000000
--- a/src/components/PathSearch.tsx
+++ /dev/null
@@ -1,234 +0,0 @@
-import { useState } from 'react';
-import { VaultServer, VaultCredentials, MountPoint } from '../types';
-import { vaultApi, SearchResult } from '../services/vaultApi';
-import './PathSearch.css';
-
-interface PathSearchProps {
- server: VaultServer;
- credentials: VaultCredentials;
- mountPoints?: MountPoint[];
- onSelectPath: (path: string) => void;
-}
-
-function PathSearch({ server, credentials, mountPoints, onSelectPath }: PathSearchProps) {
- const [searchTerm, setSearchTerm] = useState('');
- const [basePath, setBasePath] = useState('secret/');
- const [searchAllMounts, setSearchAllMounts] = useState(true);
- const [results, setResults] = useState([]);
- const [isSearching, setIsSearching] = useState(false);
- const [searchTime, setSearchTime] = useState(null);
-
- // Debug: Log mount points when component mounts or they change
- console.log('PathSearch - mountPoints:', mountPoints);
-
- const handleSearch = async () => {
- if (!searchTerm.trim()) {
- alert('Please enter a search term');
- return;
- }
-
- if (searchAllMounts && (!mountPoints || mountPoints.length === 0)) {
- alert('No mount points available. Please ensure you are connected to Vault.');
- return;
- }
-
- setIsSearching(true);
- setResults([]);
- setSearchTime(null);
-
- const startTime = performance.now();
-
- try {
- let searchResults: SearchResult[];
-
- if (searchAllMounts && mountPoints) {
- // Search across all mount points
- searchResults = await vaultApi.searchAllMounts(
- server,
- credentials,
- mountPoints,
- searchTerm
- );
- } else {
- // Search in specific base path
- searchResults = await vaultApi.searchPaths(
- server,
- credentials,
- basePath,
- searchTerm
- );
- }
-
- const endTime = performance.now();
- setSearchTime(endTime - startTime);
- setResults(searchResults);
- } catch (error) {
- console.error('Search error:', error);
- alert('Search failed. Check console for details.');
- } finally {
- setIsSearching(false);
- }
- };
-
- const handleKeyPress = (e: React.KeyboardEvent) => {
- if (e.key === 'Enter' && !isSearching) {
- handleSearch();
- }
- };
-
- return (
-
-
🔍 Search Paths
-
-
-
-
- setSearchAllMounts(e.target.checked)}
- disabled={!mountPoints || mountPoints.length === 0}
- />
- Search across all mount points
- {mountPoints && mountPoints.length > 0 ? (
- ({mountPoints.length} available)
- ) : (
- (none detected - logout and login again)
- )}
-
-
- {!mountPoints || mountPoints.length === 0 ? (
- <>Mount points are detected on login. Please logout and login again to enable this feature.>
- ) : (
- <>When enabled, searches all KV mount points instead of a specific base path>
- )}
-
-
-
- {!searchAllMounts && (
-
- Base Path
- setBasePath(e.target.value)}
- placeholder="secret/"
- />
-
- Starting path for recursive search
-
-
- )}
-
-
-
Search Term
-
- setSearchTerm(e.target.value)}
- onKeyPress={handleKeyPress}
- placeholder="Enter path or keyword..."
- disabled={isSearching}
- />
-
- {isSearching ? 'Searching...' : 'Search'}
-
-
-
-
-
- {isSearching && (
-
-
-
Searching recursively... This may take a moment.
-
- )}
-
- {searchTime !== null && (
-
-
- Found {results.length} result{results.length !== 1 ? 's' : ''}
- in {(searchTime / 1000).toFixed(2)}s
-
-
- )}
-
- {results.length > 0 && (
-
-
Search Results
-
- {results.map((result, index) => (
-
!result.isDirectory && onSelectPath(result.path)}
- >
-
- {result.isDirectory ? '📁' : '📄'}
-
-
- {result.path}
- {result.mountPoint && searchAllMounts && (
- 📌 {result.mountPoint}
- )}
-
-
Depth: {result.depth}
- {!result.isDirectory && (
-
{
- e.stopPropagation();
- onSelectPath(result.path);
- }}
- >
- View
-
- )}
-
- ))}
-
-
- )}
-
- {!isSearching && results.length === 0 && searchTime !== null && (
-
-
- No results found for "{searchTerm}"
- {searchAllMounts ? ' across all mount points' : ` in ${basePath}`}
-
-
Try a different search term{!searchAllMounts && ' or base path'}
-
- )}
-
-
-
ℹ️ Search Tips
-
- Search is case-insensitive and matches partial paths
- Results are cached to prevent excessive API calls
-
- Search all mounts: Enable to search across all KV secret engines
- {mountPoints && mountPoints.length > 0 && (
- <> (detected: {mountPoints.map(m => m.path).join(', ')})>
- )}
-
-
- Base path: When not searching all mounts, specify a starting path
-
- Directories are marked with 📁, secrets with 📄
- Maximum search depth and results can be configured in settings
-
-
-
- );
-}
-
-export default PathSearch;
-
diff --git a/src/components/PathSearch.vue b/src/components/PathSearch.vue
new file mode 100644
index 0000000..135ea80
--- /dev/null
+++ b/src/components/PathSearch.vue
@@ -0,0 +1,252 @@
+
+
+
+
+
+
🔍 Search Paths
+
+
+
+
+
+
+
+
+
+ Base Path
+
+
+
+ Starting path for recursive search
+
+
+
+
+
+
+
+
+
+
+ Searching recursively... This may take a moment.
+
+
+
+
+
+
+
+
+ Found {{ results.length }} result{{ results.length !== 1 ? 's' : '' }}
+ in {{ (searchTime / 1000).toFixed(2) }}s
+
+
+
+
+
+
Search Results
+
+
+
+
{{ result.isDirectory ? '📁' : '📄' }}
+
+
{{ result.path }}
+
+ 📌 {{ result.mountPoint }}
+
+
+
Depth: {{ result.depth }}
+
+ View
+
+
+
+
+
+
+
+
+
+
+
+
+
No results found for "{{ searchTerm }}"
+ {{ searchAllMounts ? ' across all mount points' : ` in ${basePath}` }}
+
+
Try a different search term{{ !searchAllMounts ? ' or base path' : '' }}
+
+
+
+
+
+
+
+
+
+
ℹ️ Search Tips
+
+ Search is case-insensitive and matches partial paths
+ Results are cached to prevent excessive API calls
+
+ Search all mounts: Enable to search across all KV secret engines
+
+ (detected: {{ mountPoints?.map(m => m.path).join(', ') }})
+
+
+ Base path: When not searching all mounts, specify a starting path
+ Directories are marked with 📁, secrets with 📄
+ Maximum search depth and results can be configured in settings
+
+
+
+
+
+
+
diff --git a/src/components/ServerSelector.css b/src/components/ServerSelector.css
deleted file mode 100644
index 25275a1..0000000
--- a/src/components/ServerSelector.css
+++ /dev/null
@@ -1,109 +0,0 @@
-.server-selector {
- height: 100%;
-}
-
-.section-header {
- display: flex;
- justify-content: space-between;
- align-items: center;
- margin-bottom: 1.5rem;
-}
-
-.section-header h2 {
- margin: 0;
-}
-
-.add-server-form {
- background: var(--surface-light);
- padding: 1.5rem;
- border-radius: 8px;
- margin-bottom: 1.5rem;
- border: 1px solid var(--border);
-}
-
-.server-list {
- display: flex;
- flex-direction: column;
- gap: 1rem;
-}
-
-.empty-state {
- text-align: center;
- padding: 3rem 1rem;
- color: var(--text-secondary);
-}
-
-.empty-state p {
- margin: 0.5rem 0;
-}
-
-.empty-state .hint {
- font-size: 0.875rem;
- font-style: italic;
-}
-
-.server-card {
- background: var(--surface-light);
- border: 2px solid var(--border);
- border-radius: 8px;
- padding: 1.25rem;
- cursor: pointer;
- transition: all 0.2s;
- display: flex;
- justify-content: space-between;
- align-items: center;
-}
-
-.server-card:hover {
- border-color: var(--primary-color);
- transform: translateY(-2px);
- box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
-}
-
-.server-card.selected {
- border-color: var(--primary-color);
- background: var(--surface);
- box-shadow: 0 0 0 3px rgba(100, 108, 255, 0.1);
-}
-
-.server-info {
- flex: 1;
-}
-
-.server-info h3 {
- margin: 0 0 0.5rem 0;
- font-size: 1.25rem;
-}
-
-.server-url {
- color: var(--text-secondary);
- font-size: 0.875rem;
- margin: 0.25rem 0;
- font-family: 'Courier New', monospace;
-}
-
-.server-description {
- color: var(--text-secondary);
- font-size: 0.875rem;
- margin: 0.5rem 0 0 0;
- font-style: italic;
-}
-
-.server-kv-version {
- margin: 0.5rem 0 0 0;
-}
-
-.badge {
- display: inline-block;
- padding: 0.25rem 0.5rem;
- font-size: 0.75rem;
- font-weight: 600;
- background: var(--surface);
- border: 1px solid var(--border);
- border-radius: 4px;
- color: var(--text-secondary);
-}
-
-.server-card .btn-danger {
- margin-left: 1rem;
-}
\ No newline at end of file
diff --git a/src/components/ServerSelector.tsx b/src/components/ServerSelector.tsx
deleted file mode 100644
index a5cbe2a..0000000
--- a/src/components/ServerSelector.tsx
+++ /dev/null
@@ -1,160 +0,0 @@
-import { useState } from 'react';
-import { VaultServer } from '../types';
-import './ServerSelector.css';
-
-interface ServerSelectorProps {
- servers: VaultServer[];
- selectedServer: VaultServer | null;
- onAddServer: (server: VaultServer) => void;
- onRemoveServer: (serverId: string) => void;
- onSelectServer: (server: VaultServer) => void;
-}
-
-function ServerSelector({
- servers,
- selectedServer,
- onAddServer,
- onRemoveServer,
- onSelectServer,
-}: ServerSelectorProps) {
- const [showAddForm, setShowAddForm] = useState(false);
- const [newServer, setNewServer] = useState({
- name: '',
- url: '',
- description: '',
- kvVersion: 2 as 1 | 2,
- });
-
- const handleSubmit = (e: React.FormEvent) => {
- e.preventDefault();
- if (!newServer.name || !newServer.url) return;
-
- const server: VaultServer = {
- id: newServer.name,
- // id: crypto.randomUUID(),
- name: newServer.name,
- url: newServer.url,
- description: newServer.description || undefined,
- kvVersion: newServer.kvVersion,
- };
-
- onAddServer(server);
- setNewServer({ name: '', url: '', description: '', kvVersion: 2 });
- setShowAddForm(false);
- };
-
- return (
-
-
-
Vault Servers
- setShowAddForm(!showAddForm)}
- >
- {showAddForm ? 'Cancel' : '+ Add Server'}
-
-
-
- {showAddForm && (
-
- )}
-
-
- {servers.length === 0 ? (
-
-
No vault servers configured yet.
-
Click "Add Server" to get started.
-
- ) : (
- servers.map((server) => (
-
onSelectServer(server)}
- >
-
-
{server.name}
-
{server.url}
- {server.description && (
-
{server.description}
- )}
-
- KV v{server.kvVersion || 2}
-
-
-
{
- e.stopPropagation();
- if (confirm(`Remove server "${server.name}"?`)) {
- onRemoveServer(server.id);
- }
- }}
- >
- Remove
-
-
- ))
- )}
-
-
- );
-}
-
-export default ServerSelector;
-
diff --git a/src/components/ServerSelector.vue b/src/components/ServerSelector.vue
new file mode 100644
index 0000000..efcb2b6
--- /dev/null
+++ b/src/components/ServerSelector.vue
@@ -0,0 +1,162 @@
+
+
+
+
+
+
+
+
Vault Servers
+
+ {{ showAddForm ? 'Cancel' : '+ Add Server' }}
+
+
+
+
+
+
+
+
+
No vault servers configured yet.
+
Click "Add Server" to get started.
+
+
+
+
+
+
+
{{ server.name }}
+
{{ server.url }}
+
+ {{ server.description }}
+
+
+ KV v{{ server.kvVersion || 2 }}
+
+
+
+ Remove
+
+
+
+
+
+
+
+
diff --git a/src/components/Settings.css b/src/components/Settings.css
deleted file mode 100644
index 036441e..0000000
--- a/src/components/Settings.css
+++ /dev/null
@@ -1,151 +0,0 @@
-.settings-overlay {
- position: fixed;
- top: 0;
- left: 0;
- right: 0;
- bottom: 0;
- background: rgba(0, 0, 0, 0.7);
- display: flex;
- align-items: center;
- justify-content: center;
- z-index: 1000;
- padding: 1rem;
-}
-
-.settings-modal {
- background: var(--surface);
- border-radius: 12px;
- max-width: 700px;
- width: 100%;
- max-height: 90vh;
- overflow-y: auto;
- box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.3);
- border: 1px solid var(--border);
-}
-
-.settings-header {
- display: flex;
- justify-content: space-between;
- align-items: center;
- padding: 1.5rem;
- border-bottom: 1px solid var(--border);
-}
-
-.settings-header h2 {
- margin: 0;
- font-size: 1.5rem;
-}
-
-.btn-close {
- background: none;
- border: none;
- font-size: 2rem;
- line-height: 1;
- cursor: pointer;
- padding: 0;
- width: 40px;
- height: 40px;
- border-radius: 6px;
- color: var(--text-secondary);
- transition: all 0.2s;
-}
-
-.btn-close:hover {
- background: var(--surface-light);
- color: var(--text-primary);
-}
-
-.settings-content {
- padding: 1.5rem;
-}
-
-.settings-section {
- margin-bottom: 2rem;
-}
-
-.settings-section:last-child {
- margin-bottom: 0;
-}
-
-.settings-section h3 {
- margin: 0 0 1rem 0;
- font-size: 1.25rem;
- padding-bottom: 0.5rem;
- border-bottom: 1px solid var(--border);
-}
-
-.settings-section .form-group label[for] {
- cursor: pointer;
-}
-
-.settings-section input[type="checkbox"] {
- width: auto;
- margin-right: 0.5rem;
- cursor: pointer;
-}
-
-.cache-stats {
- background: var(--surface-light);
- border-radius: 6px;
- padding: 1rem;
- margin-top: 1.5rem;
- border: 1px solid var(--border);
-}
-
-.cache-stats h4 {
- margin: 0 0 1rem 0;
- font-size: 1rem;
-}
-
-.cache-stats dl {
- display: grid;
- grid-template-columns: auto 1fr;
- gap: 0.5rem 1rem;
- margin: 0 0 1rem 0;
-}
-
-.cache-stats dt {
- font-weight: 500;
- color: var(--text-secondary);
-}
-
-.cache-stats dd {
- margin: 0;
- font-family: 'Courier New', monospace;
- color: var(--text-primary);
-}
-
-.settings-footer {
- display: flex;
- justify-content: flex-end;
- gap: 1rem;
- padding: 1.5rem;
- border-top: 1px solid var(--border);
-}
-
-.btn-secondary {
- background-color: var(--surface-light);
- color: var(--text-primary);
- border: 1px solid var(--border);
-}
-
-.btn-secondary:hover {
- background-color: var(--border);
-}
-
-@media (max-width: 768px) {
- .settings-modal {
- max-height: 100vh;
- border-radius: 0;
- }
-
- .cache-stats dl {
- grid-template-columns: 1fr;
- gap: 0.25rem;
- }
-
- .cache-stats dt {
- font-weight: 600;
- }
-}
-
diff --git a/src/components/Settings.tsx b/src/components/Settings.tsx
deleted file mode 100644
index d2df1a3..0000000
--- a/src/components/Settings.tsx
+++ /dev/null
@@ -1,200 +0,0 @@
-import { useState, useEffect } from 'react';
-import { AppConfig, loadConfig, saveConfig } from '../config';
-import { vaultCache } from '../utils/cache';
-import './Settings.css';
-
-interface SettingsProps {
- onClose: () => void;
-}
-
-function Settings({ onClose }: SettingsProps) {
- const [config, setConfig] = useState(loadConfig());
- const [cacheStats, setCacheStats] = useState(vaultCache.getStats());
-
- useEffect(() => {
- // Update cache stats
- const interval = setInterval(() => {
- setCacheStats(vaultCache.getStats());
- }, 1000);
-
- return () => clearInterval(interval);
- }, []);
-
- const handleSave = () => {
- saveConfig(config);
- alert('Settings saved successfully!');
- onClose();
- };
-
- const handleClearCache = () => {
- if (confirm('Are you sure you want to clear the cache?')) {
- vaultCache.clear();
- setCacheStats(vaultCache.getStats());
- alert('Cache cleared successfully!');
- }
- };
-
- const formatBytes = (bytes: number): string => {
- if (bytes === 0) return '0 Bytes';
- const k = 1024;
- const sizes = ['Bytes', 'KB', 'MB', 'GB'];
- const i = Math.floor(Math.log(bytes) / Math.log(k));
- return Math.round((bytes / Math.pow(k, i)) * 100) / 100 + ' ' + sizes[i];
- };
-
- const formatDate = (timestamp: number | null): string => {
- if (!timestamp) return 'N/A';
- return new Date(timestamp).toLocaleString();
- };
-
- return (
-
-
e.stopPropagation()}>
-
-
⚙️ Settings
- ×
-
-
-
-
-
-
- Cancel
-
-
- Save Settings
-
-
-
-
- );
-}
-
-export default Settings;
-
diff --git a/src/components/Settings.vue b/src/components/Settings.vue
new file mode 100644
index 0000000..6de2159
--- /dev/null
+++ b/src/components/Settings.vue
@@ -0,0 +1,217 @@
+
+
+
+
+
+
+
+
+
⚙️ Settings
+
+ ✕
+
+
+
+
+
+
Cache Settings
+
+
+
+
+
+
+
+ Maximum cache size (MB)
+
+
+
+ Maximum size of cached data in megabytes
+
+
+
+
+
+
+ Cache expiration (minutes)
+
+
+
+ How long cached entries remain valid
+
+
+
+
+
+
+
Cache Statistics
+
+
+
Total Size:
+
{{ formatBytes(cacheStats.totalSize) }}
+
+
+
Entry Count:
+
{{ cacheStats.entryCount }}
+
+
+
Oldest Entry:
+
{{ formatDate(cacheStats.oldestEntry) }}
+
+
+
Newest Entry:
+
{{ formatDate(cacheStats.newestEntry) }}
+
+
+
+ Clear Cache
+
+
+
+
+
+
+
+
Search Settings
+
+
+
+
+ Maximum search depth
+
+
+
+ Maximum recursion depth for path searches
+
+
+
+
+
+
+ Maximum search results
+
+
+
+ Maximum number of results to return from a search
+
+
+
+
+
+
+
+ Cancel
+
+
+ Save Settings
+
+
+
+
+
+
diff --git a/src/env.d.ts b/src/env.d.ts
new file mode 100644
index 0000000..230001c
--- /dev/null
+++ b/src/env.d.ts
@@ -0,0 +1,8 @@
+///
+
+declare module '*.vue' {
+ import type { DefineComponent } from 'vue'
+ const component: DefineComponent<{}, {}, any>
+ export default component
+}
+
diff --git a/src/index.css b/src/index.css
deleted file mode 100644
index 9981ba4..0000000
--- a/src/index.css
+++ /dev/null
@@ -1,133 +0,0 @@
-:root {
- font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif;
- line-height: 1.5;
- font-weight: 400;
-
- color-scheme: light dark;
- color: rgba(255, 255, 255, 0.87);
- background-color: #242424;
-
- font-synthesis: none;
- text-rendering: optimizeLegibility;
- -webkit-font-smoothing: antialiased;
- -moz-osx-font-smoothing: grayscale;
-
- --primary-color: #646cff;
- --primary-hover: #535bf2;
- --success-color: #22c55e;
- --success-hover: #16a34a;
- --danger-color: #ef4444;
- --danger-hover: #dc2626;
- --background: #242424;
- --surface: #1a1a1a;
- --surface-light: #2d2d2d;
- --border: #3d3d3d;
- --text-primary: rgba(255, 255, 255, 0.87);
- --text-secondary: rgba(255, 255, 255, 0.6);
-}
-
-@media (prefers-color-scheme: light) {
- :root {
- color: #213547;
- background-color: #ffffff;
- --primary-color: #646cff;
- --primary-hover: #535bf2;
- --background: #ffffff;
- --surface: #f9fafb;
- --surface-light: #f3f4f6;
- --border: #e5e7eb;
- --text-primary: #213547;
- --text-secondary: #6b7280;
- }
-}
-
-* {
- box-sizing: border-box;
- margin: 0;
- padding: 0;
-}
-
-body {
- margin: 0;
- display: flex;
- place-items: center;
- min-width: 320px;
- min-height: 100vh;
- background: var(--background);
-}
-
-#root {
- width: 100%;
- min-height: 100vh;
-}
-
-h1, h2, h3, h4, h5, h6 {
- line-height: 1.2;
- color: var(--text-primary);
-}
-
-a {
- font-weight: 500;
- color: var(--primary-color);
- text-decoration: inherit;
-}
-
-a:hover {
- color: var(--primary-hover);
-}
-
-button {
- border-radius: 8px;
- border: 1px solid transparent;
- padding: 0.6em 1.2em;
- font-size: 1em;
- font-weight: 500;
- font-family: inherit;
- cursor: pointer;
- transition: all 0.25s;
-}
-
-button:hover {
- border-color: var(--primary-color);
-}
-
-button:focus,
-button:focus-visible {
- outline: 4px auto -webkit-focus-ring-color;
-}
-
-input,
-select,
-textarea {
- font-family: inherit;
- font-size: 1em;
- padding: 0.6em;
- border: 1px solid var(--border);
- border-radius: 6px;
- background: var(--surface);
- color: var(--text-primary);
- transition: border-color 0.25s;
-}
-
-input:focus,
-select:focus,
-textarea:focus {
- outline: none;
- border-color: var(--primary-color);
-}
-
-code {
- background-color: var(--surface-light);
- padding: 2px 6px;
- border-radius: 4px;
- font-family: 'Courier New', monospace;
-}
-
-pre {
- background-color: var(--surface);
- padding: 1em;
- border-radius: 8px;
- overflow-x: auto;
- border: 1px solid var(--border);
-}
-
diff --git a/src/main.ts b/src/main.ts
new file mode 100644
index 0000000..216546d
--- /dev/null
+++ b/src/main.ts
@@ -0,0 +1,6 @@
+import { createApp } from 'vue'
+import './style.css'
+import App from './App.vue'
+
+createApp(App).mount('#app')
+
diff --git a/src/main.tsx b/src/main.tsx
deleted file mode 100644
index 9aa0f48..0000000
--- a/src/main.tsx
+++ /dev/null
@@ -1,11 +0,0 @@
-import React from 'react'
-import ReactDOM from 'react-dom/client'
-import App from './App.tsx'
-import './index.css'
-
-ReactDOM.createRoot(document.getElementById('root')!).render(
-
-
- ,
-)
-
diff --git a/src/style.css b/src/style.css
new file mode 100644
index 0000000..23b87cc
--- /dev/null
+++ b/src/style.css
@@ -0,0 +1,30 @@
+@tailwind base;
+@tailwind components;
+@tailwind utilities;
+
+/* Custom scrollbar styling */
+::-webkit-scrollbar {
+ width: 8px;
+ height: 8px;
+}
+
+::-webkit-scrollbar-track {
+ @apply bg-base-300;
+}
+
+::-webkit-scrollbar-thumb {
+ @apply bg-base-content/30 rounded;
+}
+
+::-webkit-scrollbar-thumb:hover {
+ @apply bg-base-content/50;
+}
+
+/* Code blocks */
+pre {
+ @apply bg-base-300 p-4 rounded-lg overflow-x-auto text-sm;
+}
+
+code {
+ @apply bg-base-300 px-2 py-1 rounded text-sm font-mono;
+}
\ No newline at end of file
diff --git a/src/vite-env.d.ts b/src/vite-env.d.ts
deleted file mode 100644
index ed77210..0000000
--- a/src/vite-env.d.ts
+++ /dev/null
@@ -1,2 +0,0 @@
-///
-
diff --git a/tailwind.config.js b/tailwind.config.js
new file mode 100644
index 0000000..bccfec8
--- /dev/null
+++ b/tailwind.config.js
@@ -0,0 +1,16 @@
+/** @type {import('tailwindcss').Config} */
+export default {
+ content: [
+ "./index.html",
+ "./src/**/*.{vue,js,ts,jsx,tsx}",
+ ],
+ theme: {
+ extend: {},
+ },
+ plugins: [require("daisyui")],
+ daisyui: {
+ themes: ["dark", "light"],
+ darkTheme: "dark",
+ },
+}
+
diff --git a/tsconfig.json b/tsconfig.json
index 256e8d8..e21d62f 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -2,25 +2,37 @@
"compilerOptions": {
"target": "ES2020",
"useDefineForClassFields": true,
- "lib": ["ES2020", "DOM", "DOM.Iterable"],
+ "lib": [
+ "ES2020",
+ "DOM",
+ "DOM.Iterable"
+ ],
"module": "ESNext",
"skipLibCheck": true,
-
/* Bundler mode */
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
- "jsx": "react-jsx",
-
+ "jsx": "preserve",
+ /* Vue 3 specific */
+ "types": [
+ "vite/client"
+ ],
/* Linting */
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noFallthroughCasesInSwitch": true
},
- "include": ["src"],
- "references": [{ "path": "./tsconfig.node.json" }]
-}
-
+ "include": [
+ "src/**/*.ts",
+ "src/**/*.vue"
+ ],
+ "references": [
+ {
+ "path": "./tsconfig.node.json"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/vite.config.ts b/vite.config.ts
index 962333c..37e3700 100644
--- a/vite.config.ts
+++ b/vite.config.ts
@@ -1,8 +1,8 @@
import { defineConfig } from 'vite'
-import react from '@vitejs/plugin-react'
+import vue from '@vitejs/plugin-vue'
// https://vitejs.dev/config/
export default defineConfig({
- plugins: [react()],
+ plugins: [vue()],
})