Compare commits
18 Commits
66aca32b65
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| 57a669df71 | |||
| f8df3d2681 | |||
| 8f1964c374 | |||
| 90ccd8d6d0 | |||
| 45a5c581f9 | |||
| 01d89e0303 | |||
| 8bf80c2f31 | |||
| b7a939ee85 | |||
| 20b9ad37ed | |||
| 18aee54570 | |||
| 28c13d98e0 | |||
| e8b6e165bd | |||
| c0bae2c1bb | |||
| 5d791ce996 | |||
| 9ccba5ea1c | |||
| f5af8ed640 | |||
| f0ec23bcce | |||
| 5f08e317fa |
@@ -1,5 +1,3 @@
|
|||||||
# Vue 3 + Vite
|
# uTools虚拟列表实现
|
||||||
|
|
||||||
This template should help get you started developing with Vue 3 in Vite. The template uses Vue 3 `<script setup>` SFCs, check out the [script setup docs](https://v3.vuejs.org/api/sfc-script-setup.html#sfc-script-setup) to learn more.
|
模版插件的自定义实现,用于扩展模版插件的可能性
|
||||||
|
|
||||||
Learn more about IDE Support for Vue in the [Vue Docs Scaling up Guide](https://vuejs.org/guide/scaling-up/tooling.html#ide-support).
|
|
||||||
|
|||||||
@@ -4,15 +4,6 @@
|
|||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<title>utools-list</title>
|
<title>utools-list</title>
|
||||||
<style>
|
|
||||||
* {
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
body {
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="app"></div>
|
<div id="app"></div>
|
||||||
|
|||||||
@@ -9,11 +9,13 @@
|
|||||||
"preview": "vite preview"
|
"preview": "vite preview"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"vue": "^3.5.13"
|
"vue": "^3.5.13",
|
||||||
|
"vue-router": "^4.5.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@vitejs/plugin-vue": "^5.2.1",
|
|
||||||
"@types/node": "^22.10.1",
|
"@types/node": "^22.10.1",
|
||||||
|
"@vitejs/plugin-vue": "^5.2.1",
|
||||||
|
"sass-embedded": "^1.82.0",
|
||||||
"typescript": "^5.0.2",
|
"typescript": "^5.0.2",
|
||||||
"vite": "^6.0.1"
|
"vite": "^6.0.1"
|
||||||
}
|
}
|
||||||
|
|||||||
464
pnpm-lock.yaml
generated
464
pnpm-lock.yaml
generated
@@ -11,377 +11,548 @@ importers:
|
|||||||
vue:
|
vue:
|
||||||
specifier: ^3.5.13
|
specifier: ^3.5.13
|
||||||
version: 3.5.13(typescript@5.7.2)
|
version: 3.5.13(typescript@5.7.2)
|
||||||
|
vue-router:
|
||||||
|
specifier: ^4.5.0
|
||||||
|
version: 4.5.0(vue@3.5.13(typescript@5.7.2))
|
||||||
devDependencies:
|
devDependencies:
|
||||||
'@types/node':
|
'@types/node':
|
||||||
specifier: ^22.10.1
|
specifier: ^22.10.1
|
||||||
version: 22.10.1
|
version: 22.10.1
|
||||||
'@vitejs/plugin-vue':
|
'@vitejs/plugin-vue':
|
||||||
specifier: ^5.2.1
|
specifier: ^5.2.1
|
||||||
version: 5.2.1(vite@6.0.3(@types/node@22.10.1))(vue@3.5.13(typescript@5.7.2))
|
version: 5.2.1(vite@6.0.3(@types/node@22.10.1)(sass-embedded@1.82.0))(vue@3.5.13(typescript@5.7.2))
|
||||||
|
sass-embedded:
|
||||||
|
specifier: ^1.82.0
|
||||||
|
version: 1.82.0
|
||||||
typescript:
|
typescript:
|
||||||
specifier: ^5.0.2
|
specifier: ^5.0.2
|
||||||
version: 5.7.2
|
version: 5.7.2
|
||||||
vite:
|
vite:
|
||||||
specifier: ^6.0.1
|
specifier: ^6.0.1
|
||||||
version: 6.0.3(@types/node@22.10.1)
|
version: 6.0.3(@types/node@22.10.1)(sass-embedded@1.82.0)
|
||||||
|
|
||||||
packages:
|
packages:
|
||||||
|
|
||||||
'@babel/helper-string-parser@7.25.9':
|
'@babel/helper-string-parser@7.25.9':
|
||||||
resolution: {integrity: sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==, tarball: https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz}
|
resolution: {integrity: sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==}
|
||||||
engines: {node: '>=6.9.0'}
|
engines: {node: '>=6.9.0'}
|
||||||
|
|
||||||
'@babel/helper-validator-identifier@7.25.9':
|
'@babel/helper-validator-identifier@7.25.9':
|
||||||
resolution: {integrity: sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==, tarball: https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz}
|
resolution: {integrity: sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==}
|
||||||
engines: {node: '>=6.9.0'}
|
engines: {node: '>=6.9.0'}
|
||||||
|
|
||||||
'@babel/parser@7.26.3':
|
'@babel/parser@7.26.3':
|
||||||
resolution: {integrity: sha512-WJ/CvmY8Mea8iDXo6a7RK2wbmJITT5fN3BEkRuFlxVyNx8jOKIIhmC4fSkTcPcf8JyavbBwIe6OpiCOBXt/IcA==, tarball: https://registry.npmjs.org/@babel/parser/-/parser-7.26.3.tgz}
|
resolution: {integrity: sha512-WJ/CvmY8Mea8iDXo6a7RK2wbmJITT5fN3BEkRuFlxVyNx8jOKIIhmC4fSkTcPcf8JyavbBwIe6OpiCOBXt/IcA==}
|
||||||
engines: {node: '>=6.0.0'}
|
engines: {node: '>=6.0.0'}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
'@babel/types@7.26.3':
|
'@babel/types@7.26.3':
|
||||||
resolution: {integrity: sha512-vN5p+1kl59GVKMvTHt55NzzmYVxprfJD+ql7U9NFIfKCBkYE55LYtS+WtPlaYOyzydrKI8Nezd+aZextrd+FMA==, tarball: https://registry.npmjs.org/@babel/types/-/types-7.26.3.tgz}
|
resolution: {integrity: sha512-vN5p+1kl59GVKMvTHt55NzzmYVxprfJD+ql7U9NFIfKCBkYE55LYtS+WtPlaYOyzydrKI8Nezd+aZextrd+FMA==}
|
||||||
engines: {node: '>=6.9.0'}
|
engines: {node: '>=6.9.0'}
|
||||||
|
|
||||||
|
'@bufbuild/protobuf@2.2.3':
|
||||||
|
resolution: {integrity: sha512-tFQoXHJdkEOSwj5tRIZSPNUuXK3RaR7T1nUrPgbYX1pUbvqqaaZAsfo+NXBPsz5rZMSKVFrgK1WL8Q/MSLvprg==}
|
||||||
|
|
||||||
'@esbuild/aix-ppc64@0.24.0':
|
'@esbuild/aix-ppc64@0.24.0':
|
||||||
resolution: {integrity: sha512-WtKdFM7ls47zkKHFVzMz8opM7LkcsIp9amDUBIAWirg70RM71WRSjdILPsY5Uv1D42ZpUfaPILDlfactHgsRkw==, tarball: https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.24.0.tgz}
|
resolution: {integrity: sha512-WtKdFM7ls47zkKHFVzMz8opM7LkcsIp9amDUBIAWirg70RM71WRSjdILPsY5Uv1D42ZpUfaPILDlfactHgsRkw==}
|
||||||
engines: {node: '>=18'}
|
engines: {node: '>=18'}
|
||||||
cpu: [ppc64]
|
cpu: [ppc64]
|
||||||
os: [aix]
|
os: [aix]
|
||||||
|
|
||||||
'@esbuild/android-arm64@0.24.0':
|
'@esbuild/android-arm64@0.24.0':
|
||||||
resolution: {integrity: sha512-Vsm497xFM7tTIPYK9bNTYJyF/lsP590Qc1WxJdlB6ljCbdZKU9SY8i7+Iin4kyhV/KV5J2rOKsBQbB77Ab7L/w==, tarball: https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.24.0.tgz}
|
resolution: {integrity: sha512-Vsm497xFM7tTIPYK9bNTYJyF/lsP590Qc1WxJdlB6ljCbdZKU9SY8i7+Iin4kyhV/KV5J2rOKsBQbB77Ab7L/w==}
|
||||||
engines: {node: '>=18'}
|
engines: {node: '>=18'}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [android]
|
os: [android]
|
||||||
|
|
||||||
'@esbuild/android-arm@0.24.0':
|
'@esbuild/android-arm@0.24.0':
|
||||||
resolution: {integrity: sha512-arAtTPo76fJ/ICkXWetLCc9EwEHKaeya4vMrReVlEIUCAUncH7M4bhMQ+M9Vf+FFOZJdTNMXNBrWwW+OXWpSew==, tarball: https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.24.0.tgz}
|
resolution: {integrity: sha512-arAtTPo76fJ/ICkXWetLCc9EwEHKaeya4vMrReVlEIUCAUncH7M4bhMQ+M9Vf+FFOZJdTNMXNBrWwW+OXWpSew==}
|
||||||
engines: {node: '>=18'}
|
engines: {node: '>=18'}
|
||||||
cpu: [arm]
|
cpu: [arm]
|
||||||
os: [android]
|
os: [android]
|
||||||
|
|
||||||
'@esbuild/android-x64@0.24.0':
|
'@esbuild/android-x64@0.24.0':
|
||||||
resolution: {integrity: sha512-t8GrvnFkiIY7pa7mMgJd7p8p8qqYIz1NYiAoKc75Zyv73L3DZW++oYMSHPRarcotTKuSs6m3hTOa5CKHaS02TQ==, tarball: https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.24.0.tgz}
|
resolution: {integrity: sha512-t8GrvnFkiIY7pa7mMgJd7p8p8qqYIz1NYiAoKc75Zyv73L3DZW++oYMSHPRarcotTKuSs6m3hTOa5CKHaS02TQ==}
|
||||||
engines: {node: '>=18'}
|
engines: {node: '>=18'}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [android]
|
os: [android]
|
||||||
|
|
||||||
'@esbuild/darwin-arm64@0.24.0':
|
'@esbuild/darwin-arm64@0.24.0':
|
||||||
resolution: {integrity: sha512-CKyDpRbK1hXwv79soeTJNHb5EiG6ct3efd/FTPdzOWdbZZfGhpbcqIpiD0+vwmpu0wTIL97ZRPZu8vUt46nBSw==, tarball: https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.24.0.tgz}
|
resolution: {integrity: sha512-CKyDpRbK1hXwv79soeTJNHb5EiG6ct3efd/FTPdzOWdbZZfGhpbcqIpiD0+vwmpu0wTIL97ZRPZu8vUt46nBSw==}
|
||||||
engines: {node: '>=18'}
|
engines: {node: '>=18'}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [darwin]
|
os: [darwin]
|
||||||
|
|
||||||
'@esbuild/darwin-x64@0.24.0':
|
'@esbuild/darwin-x64@0.24.0':
|
||||||
resolution: {integrity: sha512-rgtz6flkVkh58od4PwTRqxbKH9cOjaXCMZgWD905JOzjFKW+7EiUObfd/Kav+A6Gyud6WZk9w+xu6QLytdi2OA==, tarball: https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.24.0.tgz}
|
resolution: {integrity: sha512-rgtz6flkVkh58od4PwTRqxbKH9cOjaXCMZgWD905JOzjFKW+7EiUObfd/Kav+A6Gyud6WZk9w+xu6QLytdi2OA==}
|
||||||
engines: {node: '>=18'}
|
engines: {node: '>=18'}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [darwin]
|
os: [darwin]
|
||||||
|
|
||||||
'@esbuild/freebsd-arm64@0.24.0':
|
'@esbuild/freebsd-arm64@0.24.0':
|
||||||
resolution: {integrity: sha512-6Mtdq5nHggwfDNLAHkPlyLBpE5L6hwsuXZX8XNmHno9JuL2+bg2BX5tRkwjyfn6sKbxZTq68suOjgWqCicvPXA==, tarball: https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.24.0.tgz}
|
resolution: {integrity: sha512-6Mtdq5nHggwfDNLAHkPlyLBpE5L6hwsuXZX8XNmHno9JuL2+bg2BX5tRkwjyfn6sKbxZTq68suOjgWqCicvPXA==}
|
||||||
engines: {node: '>=18'}
|
engines: {node: '>=18'}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [freebsd]
|
os: [freebsd]
|
||||||
|
|
||||||
'@esbuild/freebsd-x64@0.24.0':
|
'@esbuild/freebsd-x64@0.24.0':
|
||||||
resolution: {integrity: sha512-D3H+xh3/zphoX8ck4S2RxKR6gHlHDXXzOf6f/9dbFt/NRBDIE33+cVa49Kil4WUjxMGW0ZIYBYtaGCa2+OsQwQ==, tarball: https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.24.0.tgz}
|
resolution: {integrity: sha512-D3H+xh3/zphoX8ck4S2RxKR6gHlHDXXzOf6f/9dbFt/NRBDIE33+cVa49Kil4WUjxMGW0ZIYBYtaGCa2+OsQwQ==}
|
||||||
engines: {node: '>=18'}
|
engines: {node: '>=18'}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [freebsd]
|
os: [freebsd]
|
||||||
|
|
||||||
'@esbuild/linux-arm64@0.24.0':
|
'@esbuild/linux-arm64@0.24.0':
|
||||||
resolution: {integrity: sha512-TDijPXTOeE3eaMkRYpcy3LarIg13dS9wWHRdwYRnzlwlA370rNdZqbcp0WTyyV/k2zSxfko52+C7jU5F9Tfj1g==, tarball: https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.24.0.tgz}
|
resolution: {integrity: sha512-TDijPXTOeE3eaMkRYpcy3LarIg13dS9wWHRdwYRnzlwlA370rNdZqbcp0WTyyV/k2zSxfko52+C7jU5F9Tfj1g==}
|
||||||
engines: {node: '>=18'}
|
engines: {node: '>=18'}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
|
||||||
'@esbuild/linux-arm@0.24.0':
|
'@esbuild/linux-arm@0.24.0':
|
||||||
resolution: {integrity: sha512-gJKIi2IjRo5G6Glxb8d3DzYXlxdEj2NlkixPsqePSZMhLudqPhtZ4BUrpIuTjJYXxvF9njql+vRjB2oaC9XpBw==, tarball: https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.24.0.tgz}
|
resolution: {integrity: sha512-gJKIi2IjRo5G6Glxb8d3DzYXlxdEj2NlkixPsqePSZMhLudqPhtZ4BUrpIuTjJYXxvF9njql+vRjB2oaC9XpBw==}
|
||||||
engines: {node: '>=18'}
|
engines: {node: '>=18'}
|
||||||
cpu: [arm]
|
cpu: [arm]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
|
||||||
'@esbuild/linux-ia32@0.24.0':
|
'@esbuild/linux-ia32@0.24.0':
|
||||||
resolution: {integrity: sha512-K40ip1LAcA0byL05TbCQ4yJ4swvnbzHscRmUilrmP9Am7//0UjPreh4lpYzvThT2Quw66MhjG//20mrufm40mA==, tarball: https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.24.0.tgz}
|
resolution: {integrity: sha512-K40ip1LAcA0byL05TbCQ4yJ4swvnbzHscRmUilrmP9Am7//0UjPreh4lpYzvThT2Quw66MhjG//20mrufm40mA==}
|
||||||
engines: {node: '>=18'}
|
engines: {node: '>=18'}
|
||||||
cpu: [ia32]
|
cpu: [ia32]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
|
||||||
'@esbuild/linux-loong64@0.24.0':
|
'@esbuild/linux-loong64@0.24.0':
|
||||||
resolution: {integrity: sha512-0mswrYP/9ai+CU0BzBfPMZ8RVm3RGAN/lmOMgW4aFUSOQBjA31UP8Mr6DDhWSuMwj7jaWOT0p0WoZ6jeHhrD7g==, tarball: https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.24.0.tgz}
|
resolution: {integrity: sha512-0mswrYP/9ai+CU0BzBfPMZ8RVm3RGAN/lmOMgW4aFUSOQBjA31UP8Mr6DDhWSuMwj7jaWOT0p0WoZ6jeHhrD7g==}
|
||||||
engines: {node: '>=18'}
|
engines: {node: '>=18'}
|
||||||
cpu: [loong64]
|
cpu: [loong64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
|
||||||
'@esbuild/linux-mips64el@0.24.0':
|
'@esbuild/linux-mips64el@0.24.0':
|
||||||
resolution: {integrity: sha512-hIKvXm0/3w/5+RDtCJeXqMZGkI2s4oMUGj3/jM0QzhgIASWrGO5/RlzAzm5nNh/awHE0A19h/CvHQe6FaBNrRA==, tarball: https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.24.0.tgz}
|
resolution: {integrity: sha512-hIKvXm0/3w/5+RDtCJeXqMZGkI2s4oMUGj3/jM0QzhgIASWrGO5/RlzAzm5nNh/awHE0A19h/CvHQe6FaBNrRA==}
|
||||||
engines: {node: '>=18'}
|
engines: {node: '>=18'}
|
||||||
cpu: [mips64el]
|
cpu: [mips64el]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
|
||||||
'@esbuild/linux-ppc64@0.24.0':
|
'@esbuild/linux-ppc64@0.24.0':
|
||||||
resolution: {integrity: sha512-HcZh5BNq0aC52UoocJxaKORfFODWXZxtBaaZNuN3PUX3MoDsChsZqopzi5UupRhPHSEHotoiptqikjN/B77mYQ==, tarball: https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.24.0.tgz}
|
resolution: {integrity: sha512-HcZh5BNq0aC52UoocJxaKORfFODWXZxtBaaZNuN3PUX3MoDsChsZqopzi5UupRhPHSEHotoiptqikjN/B77mYQ==}
|
||||||
engines: {node: '>=18'}
|
engines: {node: '>=18'}
|
||||||
cpu: [ppc64]
|
cpu: [ppc64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
|
||||||
'@esbuild/linux-riscv64@0.24.0':
|
'@esbuild/linux-riscv64@0.24.0':
|
||||||
resolution: {integrity: sha512-bEh7dMn/h3QxeR2KTy1DUszQjUrIHPZKyO6aN1X4BCnhfYhuQqedHaa5MxSQA/06j3GpiIlFGSsy1c7Gf9padw==, tarball: https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.24.0.tgz}
|
resolution: {integrity: sha512-bEh7dMn/h3QxeR2KTy1DUszQjUrIHPZKyO6aN1X4BCnhfYhuQqedHaa5MxSQA/06j3GpiIlFGSsy1c7Gf9padw==}
|
||||||
engines: {node: '>=18'}
|
engines: {node: '>=18'}
|
||||||
cpu: [riscv64]
|
cpu: [riscv64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
|
||||||
'@esbuild/linux-s390x@0.24.0':
|
'@esbuild/linux-s390x@0.24.0':
|
||||||
resolution: {integrity: sha512-ZcQ6+qRkw1UcZGPyrCiHHkmBaj9SiCD8Oqd556HldP+QlpUIe2Wgn3ehQGVoPOvZvtHm8HPx+bH20c9pvbkX3g==, tarball: https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.24.0.tgz}
|
resolution: {integrity: sha512-ZcQ6+qRkw1UcZGPyrCiHHkmBaj9SiCD8Oqd556HldP+QlpUIe2Wgn3ehQGVoPOvZvtHm8HPx+bH20c9pvbkX3g==}
|
||||||
engines: {node: '>=18'}
|
engines: {node: '>=18'}
|
||||||
cpu: [s390x]
|
cpu: [s390x]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
|
||||||
'@esbuild/linux-x64@0.24.0':
|
'@esbuild/linux-x64@0.24.0':
|
||||||
resolution: {integrity: sha512-vbutsFqQ+foy3wSSbmjBXXIJ6PL3scghJoM8zCL142cGaZKAdCZHyf+Bpu/MmX9zT9Q0zFBVKb36Ma5Fzfa8xA==, tarball: https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.24.0.tgz}
|
resolution: {integrity: sha512-vbutsFqQ+foy3wSSbmjBXXIJ6PL3scghJoM8zCL142cGaZKAdCZHyf+Bpu/MmX9zT9Q0zFBVKb36Ma5Fzfa8xA==}
|
||||||
engines: {node: '>=18'}
|
engines: {node: '>=18'}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
|
||||||
'@esbuild/netbsd-x64@0.24.0':
|
'@esbuild/netbsd-x64@0.24.0':
|
||||||
resolution: {integrity: sha512-hjQ0R/ulkO8fCYFsG0FZoH+pWgTTDreqpqY7UnQntnaKv95uP5iW3+dChxnx7C3trQQU40S+OgWhUVwCjVFLvg==, tarball: https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.24.0.tgz}
|
resolution: {integrity: sha512-hjQ0R/ulkO8fCYFsG0FZoH+pWgTTDreqpqY7UnQntnaKv95uP5iW3+dChxnx7C3trQQU40S+OgWhUVwCjVFLvg==}
|
||||||
engines: {node: '>=18'}
|
engines: {node: '>=18'}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [netbsd]
|
os: [netbsd]
|
||||||
|
|
||||||
'@esbuild/openbsd-arm64@0.24.0':
|
'@esbuild/openbsd-arm64@0.24.0':
|
||||||
resolution: {integrity: sha512-MD9uzzkPQbYehwcN583yx3Tu5M8EIoTD+tUgKF982WYL9Pf5rKy9ltgD0eUgs8pvKnmizxjXZyLt0z6DC3rRXg==, tarball: https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.24.0.tgz}
|
resolution: {integrity: sha512-MD9uzzkPQbYehwcN583yx3Tu5M8EIoTD+tUgKF982WYL9Pf5rKy9ltgD0eUgs8pvKnmizxjXZyLt0z6DC3rRXg==}
|
||||||
engines: {node: '>=18'}
|
engines: {node: '>=18'}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [openbsd]
|
os: [openbsd]
|
||||||
|
|
||||||
'@esbuild/openbsd-x64@0.24.0':
|
'@esbuild/openbsd-x64@0.24.0':
|
||||||
resolution: {integrity: sha512-4ir0aY1NGUhIC1hdoCzr1+5b43mw99uNwVzhIq1OY3QcEwPDO3B7WNXBzaKY5Nsf1+N11i1eOfFcq+D/gOS15Q==, tarball: https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.24.0.tgz}
|
resolution: {integrity: sha512-4ir0aY1NGUhIC1hdoCzr1+5b43mw99uNwVzhIq1OY3QcEwPDO3B7WNXBzaKY5Nsf1+N11i1eOfFcq+D/gOS15Q==}
|
||||||
engines: {node: '>=18'}
|
engines: {node: '>=18'}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [openbsd]
|
os: [openbsd]
|
||||||
|
|
||||||
'@esbuild/sunos-x64@0.24.0':
|
'@esbuild/sunos-x64@0.24.0':
|
||||||
resolution: {integrity: sha512-jVzdzsbM5xrotH+W5f1s+JtUy1UWgjU0Cf4wMvffTB8m6wP5/kx0KiaLHlbJO+dMgtxKV8RQ/JvtlFcdZ1zCPA==, tarball: https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.24.0.tgz}
|
resolution: {integrity: sha512-jVzdzsbM5xrotH+W5f1s+JtUy1UWgjU0Cf4wMvffTB8m6wP5/kx0KiaLHlbJO+dMgtxKV8RQ/JvtlFcdZ1zCPA==}
|
||||||
engines: {node: '>=18'}
|
engines: {node: '>=18'}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [sunos]
|
os: [sunos]
|
||||||
|
|
||||||
'@esbuild/win32-arm64@0.24.0':
|
'@esbuild/win32-arm64@0.24.0':
|
||||||
resolution: {integrity: sha512-iKc8GAslzRpBytO2/aN3d2yb2z8XTVfNV0PjGlCxKo5SgWmNXx82I/Q3aG1tFfS+A2igVCY97TJ8tnYwpUWLCA==, tarball: https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.24.0.tgz}
|
resolution: {integrity: sha512-iKc8GAslzRpBytO2/aN3d2yb2z8XTVfNV0PjGlCxKo5SgWmNXx82I/Q3aG1tFfS+A2igVCY97TJ8tnYwpUWLCA==}
|
||||||
engines: {node: '>=18'}
|
engines: {node: '>=18'}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [win32]
|
os: [win32]
|
||||||
|
|
||||||
'@esbuild/win32-ia32@0.24.0':
|
'@esbuild/win32-ia32@0.24.0':
|
||||||
resolution: {integrity: sha512-vQW36KZolfIudCcTnaTpmLQ24Ha1RjygBo39/aLkM2kmjkWmZGEJ5Gn9l5/7tzXA42QGIoWbICfg6KLLkIw6yw==, tarball: https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.24.0.tgz}
|
resolution: {integrity: sha512-vQW36KZolfIudCcTnaTpmLQ24Ha1RjygBo39/aLkM2kmjkWmZGEJ5Gn9l5/7tzXA42QGIoWbICfg6KLLkIw6yw==}
|
||||||
engines: {node: '>=18'}
|
engines: {node: '>=18'}
|
||||||
cpu: [ia32]
|
cpu: [ia32]
|
||||||
os: [win32]
|
os: [win32]
|
||||||
|
|
||||||
'@esbuild/win32-x64@0.24.0':
|
'@esbuild/win32-x64@0.24.0':
|
||||||
resolution: {integrity: sha512-7IAFPrjSQIJrGsK6flwg7NFmwBoSTyF3rl7If0hNUFQU4ilTsEPL6GuMuU9BfIWVVGuRnuIidkSMC+c0Otu8IA==, tarball: https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.24.0.tgz}
|
resolution: {integrity: sha512-7IAFPrjSQIJrGsK6flwg7NFmwBoSTyF3rl7If0hNUFQU4ilTsEPL6GuMuU9BfIWVVGuRnuIidkSMC+c0Otu8IA==}
|
||||||
engines: {node: '>=18'}
|
engines: {node: '>=18'}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [win32]
|
os: [win32]
|
||||||
|
|
||||||
'@jridgewell/sourcemap-codec@1.5.0':
|
'@jridgewell/sourcemap-codec@1.5.0':
|
||||||
resolution: {integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==, tarball: https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz}
|
resolution: {integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==}
|
||||||
|
|
||||||
'@rollup/rollup-android-arm-eabi@4.28.1':
|
'@rollup/rollup-android-arm-eabi@4.28.1':
|
||||||
resolution: {integrity: sha512-2aZp8AES04KI2dy3Ss6/MDjXbwBzj+i0GqKtWXgw2/Ma6E4jJvujryO6gJAghIRVz7Vwr9Gtl/8na3nDUKpraQ==, tarball: https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.28.1.tgz}
|
resolution: {integrity: sha512-2aZp8AES04KI2dy3Ss6/MDjXbwBzj+i0GqKtWXgw2/Ma6E4jJvujryO6gJAghIRVz7Vwr9Gtl/8na3nDUKpraQ==}
|
||||||
cpu: [arm]
|
cpu: [arm]
|
||||||
os: [android]
|
os: [android]
|
||||||
|
|
||||||
'@rollup/rollup-android-arm64@4.28.1':
|
'@rollup/rollup-android-arm64@4.28.1':
|
||||||
resolution: {integrity: sha512-EbkK285O+1YMrg57xVA+Dp0tDBRB93/BZKph9XhMjezf6F4TpYjaUSuPt5J0fZXlSag0LmZAsTmdGGqPp4pQFA==, tarball: https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.28.1.tgz}
|
resolution: {integrity: sha512-EbkK285O+1YMrg57xVA+Dp0tDBRB93/BZKph9XhMjezf6F4TpYjaUSuPt5J0fZXlSag0LmZAsTmdGGqPp4pQFA==}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [android]
|
os: [android]
|
||||||
|
|
||||||
'@rollup/rollup-darwin-arm64@4.28.1':
|
'@rollup/rollup-darwin-arm64@4.28.1':
|
||||||
resolution: {integrity: sha512-prduvrMKU6NzMq6nxzQw445zXgaDBbMQvmKSJaxpaZ5R1QDM8w+eGxo6Y/jhT/cLoCvnZI42oEqf9KQNYz1fqQ==, tarball: https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.28.1.tgz}
|
resolution: {integrity: sha512-prduvrMKU6NzMq6nxzQw445zXgaDBbMQvmKSJaxpaZ5R1QDM8w+eGxo6Y/jhT/cLoCvnZI42oEqf9KQNYz1fqQ==}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [darwin]
|
os: [darwin]
|
||||||
|
|
||||||
'@rollup/rollup-darwin-x64@4.28.1':
|
'@rollup/rollup-darwin-x64@4.28.1':
|
||||||
resolution: {integrity: sha512-WsvbOunsUk0wccO/TV4o7IKgloJ942hVFK1CLatwv6TJspcCZb9umQkPdvB7FihmdxgaKR5JyxDjWpCOp4uZlQ==, tarball: https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.28.1.tgz}
|
resolution: {integrity: sha512-WsvbOunsUk0wccO/TV4o7IKgloJ942hVFK1CLatwv6TJspcCZb9umQkPdvB7FihmdxgaKR5JyxDjWpCOp4uZlQ==}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [darwin]
|
os: [darwin]
|
||||||
|
|
||||||
'@rollup/rollup-freebsd-arm64@4.28.1':
|
'@rollup/rollup-freebsd-arm64@4.28.1':
|
||||||
resolution: {integrity: sha512-HTDPdY1caUcU4qK23FeeGxCdJF64cKkqajU0iBnTVxS8F7H/7BewvYoG+va1KPSL63kQ1PGNyiwKOfReavzvNA==, tarball: https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.28.1.tgz}
|
resolution: {integrity: sha512-HTDPdY1caUcU4qK23FeeGxCdJF64cKkqajU0iBnTVxS8F7H/7BewvYoG+va1KPSL63kQ1PGNyiwKOfReavzvNA==}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [freebsd]
|
os: [freebsd]
|
||||||
|
|
||||||
'@rollup/rollup-freebsd-x64@4.28.1':
|
'@rollup/rollup-freebsd-x64@4.28.1':
|
||||||
resolution: {integrity: sha512-m/uYasxkUevcFTeRSM9TeLyPe2QDuqtjkeoTpP9SW0XxUWfcYrGDMkO/m2tTw+4NMAF9P2fU3Mw4ahNvo7QmsQ==, tarball: https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.28.1.tgz}
|
resolution: {integrity: sha512-m/uYasxkUevcFTeRSM9TeLyPe2QDuqtjkeoTpP9SW0XxUWfcYrGDMkO/m2tTw+4NMAF9P2fU3Mw4ahNvo7QmsQ==}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [freebsd]
|
os: [freebsd]
|
||||||
|
|
||||||
'@rollup/rollup-linux-arm-gnueabihf@4.28.1':
|
'@rollup/rollup-linux-arm-gnueabihf@4.28.1':
|
||||||
resolution: {integrity: sha512-QAg11ZIt6mcmzpNE6JZBpKfJaKkqTm1A9+y9O+frdZJEuhQxiugM05gnCWiANHj4RmbgeVJpTdmKRmH/a+0QbA==, tarball: https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.28.1.tgz}
|
resolution: {integrity: sha512-QAg11ZIt6mcmzpNE6JZBpKfJaKkqTm1A9+y9O+frdZJEuhQxiugM05gnCWiANHj4RmbgeVJpTdmKRmH/a+0QbA==}
|
||||||
cpu: [arm]
|
cpu: [arm]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
|
||||||
'@rollup/rollup-linux-arm-musleabihf@4.28.1':
|
'@rollup/rollup-linux-arm-musleabihf@4.28.1':
|
||||||
resolution: {integrity: sha512-dRP9PEBfolq1dmMcFqbEPSd9VlRuVWEGSmbxVEfiq2cs2jlZAl0YNxFzAQS2OrQmsLBLAATDMb3Z6MFv5vOcXg==, tarball: https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.28.1.tgz}
|
resolution: {integrity: sha512-dRP9PEBfolq1dmMcFqbEPSd9VlRuVWEGSmbxVEfiq2cs2jlZAl0YNxFzAQS2OrQmsLBLAATDMb3Z6MFv5vOcXg==}
|
||||||
cpu: [arm]
|
cpu: [arm]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
|
||||||
'@rollup/rollup-linux-arm64-gnu@4.28.1':
|
'@rollup/rollup-linux-arm64-gnu@4.28.1':
|
||||||
resolution: {integrity: sha512-uGr8khxO+CKT4XU8ZUH1TTEUtlktK6Kgtv0+6bIFSeiSlnGJHG1tSFSjm41uQ9sAO/5ULx9mWOz70jYLyv1QkA==, tarball: https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.28.1.tgz}
|
resolution: {integrity: sha512-uGr8khxO+CKT4XU8ZUH1TTEUtlktK6Kgtv0+6bIFSeiSlnGJHG1tSFSjm41uQ9sAO/5ULx9mWOz70jYLyv1QkA==}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
|
||||||
'@rollup/rollup-linux-arm64-musl@4.28.1':
|
'@rollup/rollup-linux-arm64-musl@4.28.1':
|
||||||
resolution: {integrity: sha512-QF54q8MYGAqMLrX2t7tNpi01nvq5RI59UBNx+3+37zoKX5KViPo/gk2QLhsuqok05sSCRluj0D00LzCwBikb0A==, tarball: https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.28.1.tgz}
|
resolution: {integrity: sha512-QF54q8MYGAqMLrX2t7tNpi01nvq5RI59UBNx+3+37zoKX5KViPo/gk2QLhsuqok05sSCRluj0D00LzCwBikb0A==}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
|
||||||
'@rollup/rollup-linux-loongarch64-gnu@4.28.1':
|
'@rollup/rollup-linux-loongarch64-gnu@4.28.1':
|
||||||
resolution: {integrity: sha512-vPul4uodvWvLhRco2w0GcyZcdyBfpfDRgNKU+p35AWEbJ/HPs1tOUrkSueVbBS0RQHAf/A+nNtDpvw95PeVKOA==, tarball: https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.28.1.tgz}
|
resolution: {integrity: sha512-vPul4uodvWvLhRco2w0GcyZcdyBfpfDRgNKU+p35AWEbJ/HPs1tOUrkSueVbBS0RQHAf/A+nNtDpvw95PeVKOA==}
|
||||||
cpu: [loong64]
|
cpu: [loong64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
|
||||||
'@rollup/rollup-linux-powerpc64le-gnu@4.28.1':
|
'@rollup/rollup-linux-powerpc64le-gnu@4.28.1':
|
||||||
resolution: {integrity: sha512-pTnTdBuC2+pt1Rmm2SV7JWRqzhYpEILML4PKODqLz+C7Ou2apEV52h19CR7es+u04KlqplggmN9sqZlekg3R1A==, tarball: https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.28.1.tgz}
|
resolution: {integrity: sha512-pTnTdBuC2+pt1Rmm2SV7JWRqzhYpEILML4PKODqLz+C7Ou2apEV52h19CR7es+u04KlqplggmN9sqZlekg3R1A==}
|
||||||
cpu: [ppc64]
|
cpu: [ppc64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
|
||||||
'@rollup/rollup-linux-riscv64-gnu@4.28.1':
|
'@rollup/rollup-linux-riscv64-gnu@4.28.1':
|
||||||
resolution: {integrity: sha512-vWXy1Nfg7TPBSuAncfInmAI/WZDd5vOklyLJDdIRKABcZWojNDY0NJwruY2AcnCLnRJKSaBgf/GiJfauu8cQZA==, tarball: https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.28.1.tgz}
|
resolution: {integrity: sha512-vWXy1Nfg7TPBSuAncfInmAI/WZDd5vOklyLJDdIRKABcZWojNDY0NJwruY2AcnCLnRJKSaBgf/GiJfauu8cQZA==}
|
||||||
cpu: [riscv64]
|
cpu: [riscv64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
|
||||||
'@rollup/rollup-linux-s390x-gnu@4.28.1':
|
'@rollup/rollup-linux-s390x-gnu@4.28.1':
|
||||||
resolution: {integrity: sha512-/yqC2Y53oZjb0yz8PVuGOQQNOTwxcizudunl/tFs1aLvObTclTwZ0JhXF2XcPT/zuaymemCDSuuUPXJJyqeDOg==, tarball: https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.28.1.tgz}
|
resolution: {integrity: sha512-/yqC2Y53oZjb0yz8PVuGOQQNOTwxcizudunl/tFs1aLvObTclTwZ0JhXF2XcPT/zuaymemCDSuuUPXJJyqeDOg==}
|
||||||
cpu: [s390x]
|
cpu: [s390x]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
|
||||||
'@rollup/rollup-linux-x64-gnu@4.28.1':
|
'@rollup/rollup-linux-x64-gnu@4.28.1':
|
||||||
resolution: {integrity: sha512-fzgeABz7rrAlKYB0y2kSEiURrI0691CSL0+KXwKwhxvj92VULEDQLpBYLHpF49MSiPG4sq5CK3qHMnb9tlCjBw==, tarball: https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.28.1.tgz}
|
resolution: {integrity: sha512-fzgeABz7rrAlKYB0y2kSEiURrI0691CSL0+KXwKwhxvj92VULEDQLpBYLHpF49MSiPG4sq5CK3qHMnb9tlCjBw==}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
|
||||||
'@rollup/rollup-linux-x64-musl@4.28.1':
|
'@rollup/rollup-linux-x64-musl@4.28.1':
|
||||||
resolution: {integrity: sha512-xQTDVzSGiMlSshpJCtudbWyRfLaNiVPXt1WgdWTwWz9n0U12cI2ZVtWe/Jgwyv/6wjL7b66uu61Vg0POWVfz4g==, tarball: https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.28.1.tgz}
|
resolution: {integrity: sha512-xQTDVzSGiMlSshpJCtudbWyRfLaNiVPXt1WgdWTwWz9n0U12cI2ZVtWe/Jgwyv/6wjL7b66uu61Vg0POWVfz4g==}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
|
||||||
'@rollup/rollup-win32-arm64-msvc@4.28.1':
|
'@rollup/rollup-win32-arm64-msvc@4.28.1':
|
||||||
resolution: {integrity: sha512-wSXmDRVupJstFP7elGMgv+2HqXelQhuNf+IS4V+nUpNVi/GUiBgDmfwD0UGN3pcAnWsgKG3I52wMOBnk1VHr/A==, tarball: https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.28.1.tgz}
|
resolution: {integrity: sha512-wSXmDRVupJstFP7elGMgv+2HqXelQhuNf+IS4V+nUpNVi/GUiBgDmfwD0UGN3pcAnWsgKG3I52wMOBnk1VHr/A==}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [win32]
|
os: [win32]
|
||||||
|
|
||||||
'@rollup/rollup-win32-ia32-msvc@4.28.1':
|
'@rollup/rollup-win32-ia32-msvc@4.28.1':
|
||||||
resolution: {integrity: sha512-ZkyTJ/9vkgrE/Rk9vhMXhf8l9D+eAhbAVbsGsXKy2ohmJaWg0LPQLnIxRdRp/bKyr8tXuPlXhIoGlEB5XpJnGA==, tarball: https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.28.1.tgz}
|
resolution: {integrity: sha512-ZkyTJ/9vkgrE/Rk9vhMXhf8l9D+eAhbAVbsGsXKy2ohmJaWg0LPQLnIxRdRp/bKyr8tXuPlXhIoGlEB5XpJnGA==}
|
||||||
cpu: [ia32]
|
cpu: [ia32]
|
||||||
os: [win32]
|
os: [win32]
|
||||||
|
|
||||||
'@rollup/rollup-win32-x64-msvc@4.28.1':
|
'@rollup/rollup-win32-x64-msvc@4.28.1':
|
||||||
resolution: {integrity: sha512-ZvK2jBafvttJjoIdKm/Q/Bh7IJ1Ose9IBOwpOXcOvW3ikGTQGmKDgxTC6oCAzW6PynbkKP8+um1du81XJHZ0JA==, tarball: https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.28.1.tgz}
|
resolution: {integrity: sha512-ZvK2jBafvttJjoIdKm/Q/Bh7IJ1Ose9IBOwpOXcOvW3ikGTQGmKDgxTC6oCAzW6PynbkKP8+um1du81XJHZ0JA==}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [win32]
|
os: [win32]
|
||||||
|
|
||||||
'@types/estree@1.0.6':
|
'@types/estree@1.0.6':
|
||||||
resolution: {integrity: sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==, tarball: https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz}
|
resolution: {integrity: sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==}
|
||||||
|
|
||||||
'@types/node@22.10.1':
|
'@types/node@22.10.1':
|
||||||
resolution: {integrity: sha512-qKgsUwfHZV2WCWLAnVP1JqnpE6Im6h3Y0+fYgMTasNQ7V++CBX5OT1as0g0f+OyubbFqhf6XVNIsmN4IIhEgGQ==, tarball: https://registry.npmjs.org/@types/node/-/node-22.10.1.tgz}
|
resolution: {integrity: sha512-qKgsUwfHZV2WCWLAnVP1JqnpE6Im6h3Y0+fYgMTasNQ7V++CBX5OT1as0g0f+OyubbFqhf6XVNIsmN4IIhEgGQ==}
|
||||||
|
|
||||||
'@vitejs/plugin-vue@5.2.1':
|
'@vitejs/plugin-vue@5.2.1':
|
||||||
resolution: {integrity: sha512-cxh314tzaWwOLqVes2gnnCtvBDcM1UMdn+iFR+UjAn411dPT3tOmqrJjbMd7koZpMAmBM/GqeV4n9ge7JSiJJQ==, tarball: https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-5.2.1.tgz}
|
resolution: {integrity: sha512-cxh314tzaWwOLqVes2gnnCtvBDcM1UMdn+iFR+UjAn411dPT3tOmqrJjbMd7koZpMAmBM/GqeV4n9ge7JSiJJQ==}
|
||||||
engines: {node: ^18.0.0 || >=20.0.0}
|
engines: {node: ^18.0.0 || >=20.0.0}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
vite: ^5.0.0 || ^6.0.0
|
vite: ^5.0.0 || ^6.0.0
|
||||||
vue: ^3.2.25
|
vue: ^3.2.25
|
||||||
|
|
||||||
'@vue/compiler-core@3.5.13':
|
'@vue/compiler-core@3.5.13':
|
||||||
resolution: {integrity: sha512-oOdAkwqUfW1WqpwSYJce06wvt6HljgY3fGeM9NcVA1HaYOij3mZG9Rkysn0OHuyUAGMbEbARIpsG+LPVlBJ5/Q==, tarball: https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.13.tgz}
|
resolution: {integrity: sha512-oOdAkwqUfW1WqpwSYJce06wvt6HljgY3fGeM9NcVA1HaYOij3mZG9Rkysn0OHuyUAGMbEbARIpsG+LPVlBJ5/Q==}
|
||||||
|
|
||||||
'@vue/compiler-dom@3.5.13':
|
'@vue/compiler-dom@3.5.13':
|
||||||
resolution: {integrity: sha512-ZOJ46sMOKUjO3e94wPdCzQ6P1Lx/vhp2RSvfaab88Ajexs0AHeV0uasYhi99WPaogmBlRHNRuly8xV75cNTMDA==, tarball: https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.13.tgz}
|
resolution: {integrity: sha512-ZOJ46sMOKUjO3e94wPdCzQ6P1Lx/vhp2RSvfaab88Ajexs0AHeV0uasYhi99WPaogmBlRHNRuly8xV75cNTMDA==}
|
||||||
|
|
||||||
'@vue/compiler-sfc@3.5.13':
|
'@vue/compiler-sfc@3.5.13':
|
||||||
resolution: {integrity: sha512-6VdaljMpD82w6c2749Zhf5T9u5uLBWKnVue6XWxprDobftnletJ8+oel7sexFfM3qIxNmVE7LSFGTpv6obNyaQ==, tarball: https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.13.tgz}
|
resolution: {integrity: sha512-6VdaljMpD82w6c2749Zhf5T9u5uLBWKnVue6XWxprDobftnletJ8+oel7sexFfM3qIxNmVE7LSFGTpv6obNyaQ==}
|
||||||
|
|
||||||
'@vue/compiler-ssr@3.5.13':
|
'@vue/compiler-ssr@3.5.13':
|
||||||
resolution: {integrity: sha512-wMH6vrYHxQl/IybKJagqbquvxpWCuVYpoUJfCqFZwa/JY1GdATAQ+TgVtgrwwMZ0D07QhA99rs/EAAWfvG6KpA==, tarball: https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.13.tgz}
|
resolution: {integrity: sha512-wMH6vrYHxQl/IybKJagqbquvxpWCuVYpoUJfCqFZwa/JY1GdATAQ+TgVtgrwwMZ0D07QhA99rs/EAAWfvG6KpA==}
|
||||||
|
|
||||||
|
'@vue/devtools-api@6.6.4':
|
||||||
|
resolution: {integrity: sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g==}
|
||||||
|
|
||||||
'@vue/reactivity@3.5.13':
|
'@vue/reactivity@3.5.13':
|
||||||
resolution: {integrity: sha512-NaCwtw8o48B9I6L1zl2p41OHo/2Z4wqYGGIK1Khu5T7yxrn+ATOixn/Udn2m+6kZKB/J7cuT9DbWWhRxqixACg==, tarball: https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.13.tgz}
|
resolution: {integrity: sha512-NaCwtw8o48B9I6L1zl2p41OHo/2Z4wqYGGIK1Khu5T7yxrn+ATOixn/Udn2m+6kZKB/J7cuT9DbWWhRxqixACg==}
|
||||||
|
|
||||||
'@vue/runtime-core@3.5.13':
|
'@vue/runtime-core@3.5.13':
|
||||||
resolution: {integrity: sha512-Fj4YRQ3Az0WTZw1sFe+QDb0aXCerigEpw418pw1HBUKFtnQHWzwojaukAs2X/c9DQz4MQ4bsXTGlcpGxU/RCIw==, tarball: https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.5.13.tgz}
|
resolution: {integrity: sha512-Fj4YRQ3Az0WTZw1sFe+QDb0aXCerigEpw418pw1HBUKFtnQHWzwojaukAs2X/c9DQz4MQ4bsXTGlcpGxU/RCIw==}
|
||||||
|
|
||||||
'@vue/runtime-dom@3.5.13':
|
'@vue/runtime-dom@3.5.13':
|
||||||
resolution: {integrity: sha512-dLaj94s93NYLqjLiyFzVs9X6dWhTdAlEAciC3Moq7gzAc13VJUdCnjjRurNM6uTLFATRHexHCTu/Xp3eW6yoog==, tarball: https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.5.13.tgz}
|
resolution: {integrity: sha512-dLaj94s93NYLqjLiyFzVs9X6dWhTdAlEAciC3Moq7gzAc13VJUdCnjjRurNM6uTLFATRHexHCTu/Xp3eW6yoog==}
|
||||||
|
|
||||||
'@vue/server-renderer@3.5.13':
|
'@vue/server-renderer@3.5.13':
|
||||||
resolution: {integrity: sha512-wAi4IRJV/2SAW3htkTlB+dHeRmpTiVIK1OGLWV1yeStVSebSQQOwGwIq0D3ZIoBj2C2qpgz5+vX9iEBkTdk5YA==, tarball: https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.5.13.tgz}
|
resolution: {integrity: sha512-wAi4IRJV/2SAW3htkTlB+dHeRmpTiVIK1OGLWV1yeStVSebSQQOwGwIq0D3ZIoBj2C2qpgz5+vX9iEBkTdk5YA==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
vue: 3.5.13
|
vue: 3.5.13
|
||||||
|
|
||||||
'@vue/shared@3.5.13':
|
'@vue/shared@3.5.13':
|
||||||
resolution: {integrity: sha512-/hnE/qP5ZoGpol0a5mDi45bOd7t3tjYJBjsgCsivow7D48cJeV5l05RD82lPqi7gRiphZM37rnhW1l6ZoCNNnQ==, tarball: https://registry.npmjs.org/@vue/shared/-/shared-3.5.13.tgz}
|
resolution: {integrity: sha512-/hnE/qP5ZoGpol0a5mDi45bOd7t3tjYJBjsgCsivow7D48cJeV5l05RD82lPqi7gRiphZM37rnhW1l6ZoCNNnQ==}
|
||||||
|
|
||||||
|
buffer-builder@0.2.0:
|
||||||
|
resolution: {integrity: sha512-7VPMEPuYznPSoR21NE1zvd2Xna6c/CloiZCfcMXR1Jny6PjX0N4Nsa38zcBFo/FMK+BlA+FLKbJCQ0i2yxp+Xg==}
|
||||||
|
|
||||||
|
colorjs.io@0.5.2:
|
||||||
|
resolution: {integrity: sha512-twmVoizEW7ylZSN32OgKdXRmo1qg+wT5/6C3xu5b9QsWzSFAhHLn2xd8ro0diCsKfCj1RdaTP/nrcW+vAoQPIw==}
|
||||||
|
|
||||||
csstype@3.1.3:
|
csstype@3.1.3:
|
||||||
resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==, tarball: https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz}
|
resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==}
|
||||||
|
|
||||||
entities@4.5.0:
|
entities@4.5.0:
|
||||||
resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==, tarball: https://registry.npmjs.org/entities/-/entities-4.5.0.tgz}
|
resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==}
|
||||||
engines: {node: '>=0.12'}
|
engines: {node: '>=0.12'}
|
||||||
|
|
||||||
esbuild@0.24.0:
|
esbuild@0.24.0:
|
||||||
resolution: {integrity: sha512-FuLPevChGDshgSicjisSooU0cemp/sGXR841D5LHMB7mTVOmsEHcAxaH3irL53+8YDIeVNQEySh4DaYU/iuPqQ==, tarball: https://registry.npmjs.org/esbuild/-/esbuild-0.24.0.tgz}
|
resolution: {integrity: sha512-FuLPevChGDshgSicjisSooU0cemp/sGXR841D5LHMB7mTVOmsEHcAxaH3irL53+8YDIeVNQEySh4DaYU/iuPqQ==}
|
||||||
engines: {node: '>=18'}
|
engines: {node: '>=18'}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
estree-walker@2.0.2:
|
estree-walker@2.0.2:
|
||||||
resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==, tarball: https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz}
|
resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==}
|
||||||
|
|
||||||
fsevents@2.3.3:
|
fsevents@2.3.3:
|
||||||
resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==, tarball: https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz}
|
resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==}
|
||||||
engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
|
engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
|
||||||
os: [darwin]
|
os: [darwin]
|
||||||
|
|
||||||
|
has-flag@4.0.0:
|
||||||
|
resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==}
|
||||||
|
engines: {node: '>=8'}
|
||||||
|
|
||||||
|
immutable@5.0.3:
|
||||||
|
resolution: {integrity: sha512-P8IdPQHq3lA1xVeBRi5VPqUm5HDgKnx0Ru51wZz5mjxHr5n3RWhjIpOFU7ybkUxfB+5IToy+OLaHYDBIWsv+uw==}
|
||||||
|
|
||||||
magic-string@0.30.15:
|
magic-string@0.30.15:
|
||||||
resolution: {integrity: sha512-zXeaYRgZ6ldS1RJJUrMrYgNJ4fdwnyI6tVqoiIhyCyv5IVTK9BU8Ic2l253GGETQHxI4HNUwhJ3fjDhKqEoaAw==, tarball: https://registry.npmjs.org/magic-string/-/magic-string-0.30.15.tgz}
|
resolution: {integrity: sha512-zXeaYRgZ6ldS1RJJUrMrYgNJ4fdwnyI6tVqoiIhyCyv5IVTK9BU8Ic2l253GGETQHxI4HNUwhJ3fjDhKqEoaAw==}
|
||||||
|
|
||||||
nanoid@3.3.8:
|
nanoid@3.3.8:
|
||||||
resolution: {integrity: sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==, tarball: https://registry.npmjs.org/nanoid/-/nanoid-3.3.8.tgz}
|
resolution: {integrity: sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==}
|
||||||
engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
|
engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
picocolors@1.1.1:
|
picocolors@1.1.1:
|
||||||
resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==, tarball: https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz}
|
resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==}
|
||||||
|
|
||||||
postcss@8.4.49:
|
postcss@8.4.49:
|
||||||
resolution: {integrity: sha512-OCVPnIObs4N29kxTjzLfUryOkvZEq+pf8jTF0lg8E7uETuWHA+v7j3c/xJmiqpX450191LlmZfUKkXxkTry7nA==, tarball: https://registry.npmjs.org/postcss/-/postcss-8.4.49.tgz}
|
resolution: {integrity: sha512-OCVPnIObs4N29kxTjzLfUryOkvZEq+pf8jTF0lg8E7uETuWHA+v7j3c/xJmiqpX450191LlmZfUKkXxkTry7nA==}
|
||||||
engines: {node: ^10 || ^12 || >=14}
|
engines: {node: ^10 || ^12 || >=14}
|
||||||
|
|
||||||
rollup@4.28.1:
|
rollup@4.28.1:
|
||||||
resolution: {integrity: sha512-61fXYl/qNVinKmGSTHAZ6Yy8I3YIJC/r2m9feHo6SwVAVcLT5MPwOUFe7EuURA/4m0NR8lXG4BBXuo/IZEsjMg==, tarball: https://registry.npmjs.org/rollup/-/rollup-4.28.1.tgz}
|
resolution: {integrity: sha512-61fXYl/qNVinKmGSTHAZ6Yy8I3YIJC/r2m9feHo6SwVAVcLT5MPwOUFe7EuURA/4m0NR8lXG4BBXuo/IZEsjMg==}
|
||||||
engines: {node: '>=18.0.0', npm: '>=8.0.0'}
|
engines: {node: '>=18.0.0', npm: '>=8.0.0'}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
|
rxjs@7.8.1:
|
||||||
|
resolution: {integrity: sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==}
|
||||||
|
|
||||||
|
sass-embedded-android-arm64@1.82.0:
|
||||||
|
resolution: {integrity: sha512-bldHMs02QQWXsgHUZRgolNnZdMjN6XHvmUYoRkzmFq7lsvtLU6SJg2S1Wa9IZJs9jRWdTmOgA6YibSf3pROyFQ==}
|
||||||
|
engines: {node: '>=14.0.0'}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [android]
|
||||||
|
|
||||||
|
sass-embedded-android-arm@1.82.0:
|
||||||
|
resolution: {integrity: sha512-ttGMvWnA/5TYdZTjr5fWHDbb9nZgKipHKCc9zZQRF5HjUydOYWKNqmAJHQtbFWaq35kd5qn6yiE73IJN6eJ6wA==}
|
||||||
|
engines: {node: '>=14.0.0'}
|
||||||
|
cpu: [arm]
|
||||||
|
os: [android]
|
||||||
|
|
||||||
|
sass-embedded-android-ia32@1.82.0:
|
||||||
|
resolution: {integrity: sha512-FUJOnxw8IYKuYuxxiOkk6QXle8/yQFtKjnuSAJuZ5ZpLVMcSZzLc3SWOtuEXYx5iSAfJCO075o2ZoG/pPrJ9aw==}
|
||||||
|
engines: {node: '>=14.0.0'}
|
||||||
|
cpu: [ia32]
|
||||||
|
os: [android]
|
||||||
|
|
||||||
|
sass-embedded-android-riscv64@1.82.0:
|
||||||
|
resolution: {integrity: sha512-rd+vc+sxJxNnbhaubiIJmnb1b3FvC9wxCIq8spstopbO7o1uufvBBDeRoFSJaN+7oNhamzjlYGdu6aQoQNs3+A==}
|
||||||
|
engines: {node: '>=14.0.0'}
|
||||||
|
cpu: [riscv64]
|
||||||
|
os: [android]
|
||||||
|
|
||||||
|
sass-embedded-android-x64@1.82.0:
|
||||||
|
resolution: {integrity: sha512-EVlybGTgJ8wNLyWj8RUatPXSnmIcvCsx3EfsRfBfhGihLbn4NNpavYO9QsvZzI2XWbJqHLBCd+CvkTcDw/TaSQ==}
|
||||||
|
engines: {node: '>=14.0.0'}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [android]
|
||||||
|
|
||||||
|
sass-embedded-darwin-arm64@1.82.0:
|
||||||
|
resolution: {integrity: sha512-LvdJPojjKlNGYOB0nSUR/ZtMDuAF4puspHlwK42aA/qK292bfSkMUKZPPapB2aSRwccc/ieBq5fI7n/WHrOCVw==}
|
||||||
|
engines: {node: '>=14.0.0'}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [darwin]
|
||||||
|
|
||||||
|
sass-embedded-darwin-x64@1.82.0:
|
||||||
|
resolution: {integrity: sha512-6LfnD6YmG1aBfd3ReqMOJDb6Pg2Z/hmlJB7nU+Lb3E+hCNjAZAgeUHQxU/Pm1eIqJJTU/h4ib5QP0Pt9O8yVnw==}
|
||||||
|
engines: {node: '>=14.0.0'}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [darwin]
|
||||||
|
|
||||||
|
sass-embedded-linux-arm64@1.82.0:
|
||||||
|
resolution: {integrity: sha512-590/y0HJr/JiyxaqgR7Xf9P20BIhJ+zhB/afAnVuZe/4lEfCpTyM5xMe2+sKLsqtrVyzs9Zm/M4S4ASUOPCggA==}
|
||||||
|
engines: {node: '>=14.0.0'}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [linux]
|
||||||
|
|
||||||
|
sass-embedded-linux-arm@1.82.0:
|
||||||
|
resolution: {integrity: sha512-ozjdC5rWzyi5Vo300I4tVZzneXOTQUiaxOr7DjtN26HuFaGAGCGmvThh2BRV4RvySg++5H9rdFu+VgyUQ5iukw==}
|
||||||
|
engines: {node: '>=14.0.0'}
|
||||||
|
cpu: [arm]
|
||||||
|
os: [linux]
|
||||||
|
|
||||||
|
sass-embedded-linux-ia32@1.82.0:
|
||||||
|
resolution: {integrity: sha512-hpc4acZ3UTjjJ3Q/GUXqQOCSml6AFKaku0HMawra9bKyRmOpxn8V5hqgXeOWVjK2oQzCmCnJvwKoQUP+S/SIYQ==}
|
||||||
|
engines: {node: '>=14.0.0'}
|
||||||
|
cpu: [ia32]
|
||||||
|
os: [linux]
|
||||||
|
|
||||||
|
sass-embedded-linux-musl-arm64@1.82.0:
|
||||||
|
resolution: {integrity: sha512-bc2MUSMv/jabnNGEyKP2jQAYZoEzTT/c633W6QoeSEWETGCuTNjaHvWWE6qSI6/UfRg1EpuV1LQA2jPMzZfv/w==}
|
||||||
|
engines: {node: '>=14.0.0'}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [linux]
|
||||||
|
|
||||||
|
sass-embedded-linux-musl-arm@1.82.0:
|
||||||
|
resolution: {integrity: sha512-R5PQmY/I+GSoMtfLo8GgHkvF/q6x6y8VNM7yu/Ac1mJj86n48VFi29W1HfY2496+Q6cpAq7toobDj7YfldIdVA==}
|
||||||
|
engines: {node: '>=14.0.0'}
|
||||||
|
cpu: [arm]
|
||||||
|
os: [linux]
|
||||||
|
|
||||||
|
sass-embedded-linux-musl-ia32@1.82.0:
|
||||||
|
resolution: {integrity: sha512-ZQKCFKm5TBcJ19UG6uUQmIKfVCJIWMb7e1a93lGeujSb9gyKF5Fb6MN3tuExoT7iFK8zU0Z9iyHqh93F58lcCw==}
|
||||||
|
engines: {node: '>=14.0.0'}
|
||||||
|
cpu: [ia32]
|
||||||
|
os: [linux]
|
||||||
|
|
||||||
|
sass-embedded-linux-musl-riscv64@1.82.0:
|
||||||
|
resolution: {integrity: sha512-5meSU8BHFeaT09RWfkuUrikRlC+WZcYb9To7MpfV1d9nlD7CZ2xydPExK+mj3DqRuQvTbvhMPcr7f+pHlgHINQ==}
|
||||||
|
engines: {node: '>=14.0.0'}
|
||||||
|
cpu: [riscv64]
|
||||||
|
os: [linux]
|
||||||
|
|
||||||
|
sass-embedded-linux-musl-x64@1.82.0:
|
||||||
|
resolution: {integrity: sha512-ASLAMfjWv7YEPBvEOVlb3zzHq8l4Y9Eh4x3m7B1dNauGVbO11Yng5cPCX/XbwGVf30BtE75pwqvV7oXxBtN15w==}
|
||||||
|
engines: {node: '>=14.0.0'}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [linux]
|
||||||
|
|
||||||
|
sass-embedded-linux-riscv64@1.82.0:
|
||||||
|
resolution: {integrity: sha512-qWvRDXCXH3GzD8OcP0ntd8gBTK3kZyUeyXmxQDZyEtMAM4STC2Tn7+5+2JYYHlppzqWnZPFBNESvpKeOtHaBBw==}
|
||||||
|
engines: {node: '>=14.0.0'}
|
||||||
|
cpu: [riscv64]
|
||||||
|
os: [linux]
|
||||||
|
|
||||||
|
sass-embedded-linux-x64@1.82.0:
|
||||||
|
resolution: {integrity: sha512-AmRaHqShztwfep+M4NagdGaY7fTyWGSOM3k4Z/dd7q4nZclXbALLqNJtKx8xOM7A41LHYJ9zDpIBVRkrh0PzTA==}
|
||||||
|
engines: {node: '>=14.0.0'}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [linux]
|
||||||
|
|
||||||
|
sass-embedded-win32-arm64@1.82.0:
|
||||||
|
resolution: {integrity: sha512-zL9JDQZHXHSGAZe5DqSrR86wMHbm9QPziU4/3hoIG+99StuS74CuV42+hw/+FXXBkXMWbjKWsyF/HZt+I/wJuw==}
|
||||||
|
engines: {node: '>=14.0.0'}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [win32]
|
||||||
|
|
||||||
|
sass-embedded-win32-ia32@1.82.0:
|
||||||
|
resolution: {integrity: sha512-xE+AzLquCkFPnnpo0NHjQdLRIhG1bVs42xIKx42aUbVLYKkBDvbBGpw6EtTscRMyvcjoOqGH5saRvSFComUQcw==}
|
||||||
|
engines: {node: '>=14.0.0'}
|
||||||
|
cpu: [ia32]
|
||||||
|
os: [win32]
|
||||||
|
|
||||||
|
sass-embedded-win32-x64@1.82.0:
|
||||||
|
resolution: {integrity: sha512-cEgfOQG5womOzzk16ReTv2dxPq5BG16LgLUold/LH9IZH86u4E/MN7Fspf4RWeEJ2EcLdew9QYSC2YWs1l98dQ==}
|
||||||
|
engines: {node: '>=14.0.0'}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [win32]
|
||||||
|
|
||||||
|
sass-embedded@1.82.0:
|
||||||
|
resolution: {integrity: sha512-v13sRVVZtWAQLpAGTz5D8hy+oyNKRHao5tKVc/P6AMqSP+jDM8X6GkEpL0jfbu3MaN2/hAQsd4Qx14GG1u0prQ==}
|
||||||
|
engines: {node: '>=16.0.0'}
|
||||||
|
hasBin: true
|
||||||
|
|
||||||
source-map-js@1.2.1:
|
source-map-js@1.2.1:
|
||||||
resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==, tarball: https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz}
|
resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==}
|
||||||
engines: {node: '>=0.10.0'}
|
engines: {node: '>=0.10.0'}
|
||||||
|
|
||||||
|
supports-color@8.1.1:
|
||||||
|
resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==}
|
||||||
|
engines: {node: '>=10'}
|
||||||
|
|
||||||
|
sync-child-process@1.0.2:
|
||||||
|
resolution: {integrity: sha512-8lD+t2KrrScJ/7KXCSyfhT3/hRq78rC0wBFqNJXv3mZyn6hW2ypM05JmlSvtqRbeq6jqA94oHbxAr2vYsJ8vDA==}
|
||||||
|
engines: {node: '>=16.0.0'}
|
||||||
|
|
||||||
|
sync-message-port@1.1.3:
|
||||||
|
resolution: {integrity: sha512-GTt8rSKje5FilG+wEdfCkOcLL7LWqpMlr2c3LRuKt/YXxcJ52aGSbGBAdI4L3aaqfrBt6y711El53ItyH1NWzg==}
|
||||||
|
engines: {node: '>=16.0.0'}
|
||||||
|
|
||||||
|
tslib@2.8.1:
|
||||||
|
resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==}
|
||||||
|
|
||||||
typescript@5.7.2:
|
typescript@5.7.2:
|
||||||
resolution: {integrity: sha512-i5t66RHxDvVN40HfDd1PsEThGNnlMCMT3jMUuoh9/0TaqWevNontacunWyN02LA9/fIbEWlcHZcgTKb9QoaLfg==, tarball: https://registry.npmjs.org/typescript/-/typescript-5.7.2.tgz}
|
resolution: {integrity: sha512-i5t66RHxDvVN40HfDd1PsEThGNnlMCMT3jMUuoh9/0TaqWevNontacunWyN02LA9/fIbEWlcHZcgTKb9QoaLfg==}
|
||||||
engines: {node: '>=14.17'}
|
engines: {node: '>=14.17'}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
undici-types@6.20.0:
|
undici-types@6.20.0:
|
||||||
resolution: {integrity: sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==, tarball: https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz}
|
resolution: {integrity: sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==}
|
||||||
|
|
||||||
|
varint@6.0.0:
|
||||||
|
resolution: {integrity: sha512-cXEIW6cfr15lFv563k4GuVuW/fiwjknytD37jIOLSdSWuOI6WnO/oKwmP2FQTU2l01LP8/M5TSAJpzUaGe3uWg==}
|
||||||
|
|
||||||
vite@6.0.3:
|
vite@6.0.3:
|
||||||
resolution: {integrity: sha512-Cmuo5P0ENTN6HxLSo6IHsjCLn/81Vgrp81oaiFFMRa8gGDj5xEjIcEpf2ZymZtZR8oU0P2JX5WuUp/rlXcHkAw==, tarball: https://registry.npmjs.org/vite/-/vite-6.0.3.tgz}
|
resolution: {integrity: sha512-Cmuo5P0ENTN6HxLSo6IHsjCLn/81Vgrp81oaiFFMRa8gGDj5xEjIcEpf2ZymZtZR8oU0P2JX5WuUp/rlXcHkAw==}
|
||||||
engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0}
|
engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
@@ -420,8 +591,13 @@ packages:
|
|||||||
yaml:
|
yaml:
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
|
vue-router@4.5.0:
|
||||||
|
resolution: {integrity: sha512-HDuk+PuH5monfNuY+ct49mNmkCRK4xJAV9Ts4z9UFc4rzdDnxQLyCMGGc8pKhZhHTVzfanpNwB/lwqevcBwI4w==}
|
||||||
|
peerDependencies:
|
||||||
|
vue: ^3.2.0
|
||||||
|
|
||||||
vue@3.5.13:
|
vue@3.5.13:
|
||||||
resolution: {integrity: sha512-wmeiSMxkZCSc+PM2w2VRsOYAZC8GdipNFRTsLSfodVqI9mbejKeXEGr8SckuLnrQPGe3oJN5c3K0vpoU9q/wCQ==, tarball: https://registry.npmjs.org/vue/-/vue-3.5.13.tgz}
|
resolution: {integrity: sha512-wmeiSMxkZCSc+PM2w2VRsOYAZC8GdipNFRTsLSfodVqI9mbejKeXEGr8SckuLnrQPGe3oJN5c3K0vpoU9q/wCQ==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
typescript: '*'
|
typescript: '*'
|
||||||
peerDependenciesMeta:
|
peerDependenciesMeta:
|
||||||
@@ -443,6 +619,8 @@ snapshots:
|
|||||||
'@babel/helper-string-parser': 7.25.9
|
'@babel/helper-string-parser': 7.25.9
|
||||||
'@babel/helper-validator-identifier': 7.25.9
|
'@babel/helper-validator-identifier': 7.25.9
|
||||||
|
|
||||||
|
'@bufbuild/protobuf@2.2.3': {}
|
||||||
|
|
||||||
'@esbuild/aix-ppc64@0.24.0':
|
'@esbuild/aix-ppc64@0.24.0':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
@@ -580,9 +758,9 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
undici-types: 6.20.0
|
undici-types: 6.20.0
|
||||||
|
|
||||||
'@vitejs/plugin-vue@5.2.1(vite@6.0.3(@types/node@22.10.1))(vue@3.5.13(typescript@5.7.2))':
|
'@vitejs/plugin-vue@5.2.1(vite@6.0.3(@types/node@22.10.1)(sass-embedded@1.82.0))(vue@3.5.13(typescript@5.7.2))':
|
||||||
dependencies:
|
dependencies:
|
||||||
vite: 6.0.3(@types/node@22.10.1)
|
vite: 6.0.3(@types/node@22.10.1)(sass-embedded@1.82.0)
|
||||||
vue: 3.5.13(typescript@5.7.2)
|
vue: 3.5.13(typescript@5.7.2)
|
||||||
|
|
||||||
'@vue/compiler-core@3.5.13':
|
'@vue/compiler-core@3.5.13':
|
||||||
@@ -615,6 +793,8 @@ snapshots:
|
|||||||
'@vue/compiler-dom': 3.5.13
|
'@vue/compiler-dom': 3.5.13
|
||||||
'@vue/shared': 3.5.13
|
'@vue/shared': 3.5.13
|
||||||
|
|
||||||
|
'@vue/devtools-api@6.6.4': {}
|
||||||
|
|
||||||
'@vue/reactivity@3.5.13':
|
'@vue/reactivity@3.5.13':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@vue/shared': 3.5.13
|
'@vue/shared': 3.5.13
|
||||||
@@ -639,6 +819,10 @@ snapshots:
|
|||||||
|
|
||||||
'@vue/shared@3.5.13': {}
|
'@vue/shared@3.5.13': {}
|
||||||
|
|
||||||
|
buffer-builder@0.2.0: {}
|
||||||
|
|
||||||
|
colorjs.io@0.5.2: {}
|
||||||
|
|
||||||
csstype@3.1.3: {}
|
csstype@3.1.3: {}
|
||||||
|
|
||||||
entities@4.5.0: {}
|
entities@4.5.0: {}
|
||||||
@@ -675,6 +859,10 @@ snapshots:
|
|||||||
fsevents@2.3.3:
|
fsevents@2.3.3:
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
|
has-flag@4.0.0: {}
|
||||||
|
|
||||||
|
immutable@5.0.3: {}
|
||||||
|
|
||||||
magic-string@0.30.15:
|
magic-string@0.30.15:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@jridgewell/sourcemap-codec': 1.5.0
|
'@jridgewell/sourcemap-codec': 1.5.0
|
||||||
@@ -714,13 +902,123 @@ snapshots:
|
|||||||
'@rollup/rollup-win32-x64-msvc': 4.28.1
|
'@rollup/rollup-win32-x64-msvc': 4.28.1
|
||||||
fsevents: 2.3.3
|
fsevents: 2.3.3
|
||||||
|
|
||||||
|
rxjs@7.8.1:
|
||||||
|
dependencies:
|
||||||
|
tslib: 2.8.1
|
||||||
|
|
||||||
|
sass-embedded-android-arm64@1.82.0:
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
sass-embedded-android-arm@1.82.0:
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
sass-embedded-android-ia32@1.82.0:
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
sass-embedded-android-riscv64@1.82.0:
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
sass-embedded-android-x64@1.82.0:
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
sass-embedded-darwin-arm64@1.82.0:
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
sass-embedded-darwin-x64@1.82.0:
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
sass-embedded-linux-arm64@1.82.0:
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
sass-embedded-linux-arm@1.82.0:
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
sass-embedded-linux-ia32@1.82.0:
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
sass-embedded-linux-musl-arm64@1.82.0:
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
sass-embedded-linux-musl-arm@1.82.0:
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
sass-embedded-linux-musl-ia32@1.82.0:
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
sass-embedded-linux-musl-riscv64@1.82.0:
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
sass-embedded-linux-musl-x64@1.82.0:
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
sass-embedded-linux-riscv64@1.82.0:
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
sass-embedded-linux-x64@1.82.0:
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
sass-embedded-win32-arm64@1.82.0:
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
sass-embedded-win32-ia32@1.82.0:
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
sass-embedded-win32-x64@1.82.0:
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
sass-embedded@1.82.0:
|
||||||
|
dependencies:
|
||||||
|
'@bufbuild/protobuf': 2.2.3
|
||||||
|
buffer-builder: 0.2.0
|
||||||
|
colorjs.io: 0.5.2
|
||||||
|
immutable: 5.0.3
|
||||||
|
rxjs: 7.8.1
|
||||||
|
supports-color: 8.1.1
|
||||||
|
sync-child-process: 1.0.2
|
||||||
|
varint: 6.0.0
|
||||||
|
optionalDependencies:
|
||||||
|
sass-embedded-android-arm: 1.82.0
|
||||||
|
sass-embedded-android-arm64: 1.82.0
|
||||||
|
sass-embedded-android-ia32: 1.82.0
|
||||||
|
sass-embedded-android-riscv64: 1.82.0
|
||||||
|
sass-embedded-android-x64: 1.82.0
|
||||||
|
sass-embedded-darwin-arm64: 1.82.0
|
||||||
|
sass-embedded-darwin-x64: 1.82.0
|
||||||
|
sass-embedded-linux-arm: 1.82.0
|
||||||
|
sass-embedded-linux-arm64: 1.82.0
|
||||||
|
sass-embedded-linux-ia32: 1.82.0
|
||||||
|
sass-embedded-linux-musl-arm: 1.82.0
|
||||||
|
sass-embedded-linux-musl-arm64: 1.82.0
|
||||||
|
sass-embedded-linux-musl-ia32: 1.82.0
|
||||||
|
sass-embedded-linux-musl-riscv64: 1.82.0
|
||||||
|
sass-embedded-linux-musl-x64: 1.82.0
|
||||||
|
sass-embedded-linux-riscv64: 1.82.0
|
||||||
|
sass-embedded-linux-x64: 1.82.0
|
||||||
|
sass-embedded-win32-arm64: 1.82.0
|
||||||
|
sass-embedded-win32-ia32: 1.82.0
|
||||||
|
sass-embedded-win32-x64: 1.82.0
|
||||||
|
|
||||||
source-map-js@1.2.1: {}
|
source-map-js@1.2.1: {}
|
||||||
|
|
||||||
|
supports-color@8.1.1:
|
||||||
|
dependencies:
|
||||||
|
has-flag: 4.0.0
|
||||||
|
|
||||||
|
sync-child-process@1.0.2:
|
||||||
|
dependencies:
|
||||||
|
sync-message-port: 1.1.3
|
||||||
|
|
||||||
|
sync-message-port@1.1.3: {}
|
||||||
|
|
||||||
|
tslib@2.8.1: {}
|
||||||
|
|
||||||
typescript@5.7.2: {}
|
typescript@5.7.2: {}
|
||||||
|
|
||||||
undici-types@6.20.0: {}
|
undici-types@6.20.0: {}
|
||||||
|
|
||||||
vite@6.0.3(@types/node@22.10.1):
|
varint@6.0.0: {}
|
||||||
|
|
||||||
|
vite@6.0.3(@types/node@22.10.1)(sass-embedded@1.82.0):
|
||||||
dependencies:
|
dependencies:
|
||||||
esbuild: 0.24.0
|
esbuild: 0.24.0
|
||||||
postcss: 8.4.49
|
postcss: 8.4.49
|
||||||
@@ -728,6 +1026,12 @@ snapshots:
|
|||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
'@types/node': 22.10.1
|
'@types/node': 22.10.1
|
||||||
fsevents: 2.3.3
|
fsevents: 2.3.3
|
||||||
|
sass-embedded: 1.82.0
|
||||||
|
|
||||||
|
vue-router@4.5.0(vue@3.5.13(typescript@5.7.2)):
|
||||||
|
dependencies:
|
||||||
|
'@vue/devtools-api': 6.6.4
|
||||||
|
vue: 3.5.13(typescript@5.7.2)
|
||||||
|
|
||||||
vue@3.5.13(typescript@5.7.2):
|
vue@3.5.13(typescript@5.7.2):
|
||||||
dependencies:
|
dependencies:
|
||||||
|
|||||||
70
src/App.vue
70
src/App.vue
@@ -1,72 +1,10 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import ProjectList from './components/ProjectList.vue'
|
import { useRouter } from 'vue-router'
|
||||||
import type { ListItem, MenuItem } from '@/types'
|
|
||||||
|
|
||||||
const samplePic =
|
const router = useRouter()
|
||||||
'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAHgAAAB4CAMAAAAOusbgAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JQAAgIMAAPn/AACA6QAAdTAAAOpgAAA6mAAAF2+SX8VGAAACf1BMVEVGQksvbmYyaWM0ZGA3X107WFk9U1VATlNDSU8ucWgyamQ2Yl88VlhDSE8wbWY1ZGAvb2c1ZGA+U1U6WloucWgzZ2I/UFQ0ZmFATVIyaWM/T1MyaWMwbWY7V1gucWg1Yl8wbWUucWg0ZWAvb2cwbWYxa2QzaGI0ZWFBTFE5XFszZmI0ZmE9VFY7WFkxa2RERk5BTVIxamQ2YV4xbGUvcGdATlI8Vlgvb2c6Wlo5XFswbWYucWgzZ2IucWgxa2Q9U1U7WFg5W1pCSlAucWgzZ2IyaWMucWg1Y19DSE43X103X104XlwvcGc8VlcxbGUvb2c3X10wbWU6WVk4XlxATlMyaWMucWg2YV4vbmYxa2RDR041Y18ucWgyaGM2YV4vb2c1Y185W1ovb2cwbGU8VVdCSU82Yl8+UVQxa2Q4XVs0ZWE1Yl8xbGU4XVwyaWM6WlowbWY2Yl8wbGUwbWY4XVs/T1M0ZmEvb2c3X109U1YwbWYwbmYxbGU4Xlw2YV4+UVU5XFs0ZmEvbmY5W1o+UlUwbmY6Wlo/UFQ1Y181Y180ZWEyamQzZ2JBS1Evb2c8Vlc5XFsvb2cyaWM2Yl8vcGcvb2dDSU80ZWE7V1g1Yl9BTFExamRER049VFY6WVk6WlpBS1AwbWU0ZWEyaWM7WFkvb2c0ZmE5W1ozaGIxbGU4XVs1ZGAyamQzaGIxa2RCSVAzaGI7V1g6WVk2YV4zZ2I9VFYxbGU0ZmEucWgwbmYzZmIzaGIxa2QwbWY4Xlw3YF03YF5CSlAxamQvb2cyaWM0ZWA2YV43X11AT1M3X107V1gwbGVFRU1GQktFRExERU1GQ0tFQ0xERk5ERk3///+ARxMXAAAAzHRSTlMAMXyqzeXy+f4UdL7s/jivKrDz4wiX9pz6ffh/RusKuU0CqBdFao+n+9qbofHnaP77cMNfIfrrH+DbQwSSBmTz6Nz9FpN6ErP+y8rQI+1aMM9P5dL6gQ7CNWf+sgyHxBu03SxU7v279mXYprZc1YPhQbxZStf5mR3M8kg8V9HA9dygM9/0PuL3uLWidpb8KOzZJoa9JS79pOm6/HP+8OPf/EujgOY3nd6MYdmucY5t/Yjo5MWQ71WeEDqYi10/08fG/G4ZeanByfnO6lCAYmwuAAAAAWJLR0TUCbsLhQAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB+QLEgYgM+IYZDcAAAfcSURBVGjexZv5fxNFFMCnSdqmbdKDpCkNPZK2lAJtw1FaIFSkCIIcraAcpXhgoQoiIpdCQUBKQaSKIiCHKB6g4oVUQQ7vO5tS+IfM5pzrzc4myyfvJ9h5877NzsybN2/eIqRXMkxmS2ZWtjWghCRgzc7KtJhNGbrN6JKc3DybXeGK3ZaXm3N/qPkFtoAilICtIN9oamHRCEVKRhQVGojNdQTlsKoEHbnGUJ3FLnlqRFzFztSxJSP1YlUZWZIiutSdDFYV96gUsGXlyWJVKS9LEltRGUiFG1pelRXJcD265xQrLo9urLdqKHWuogxVefVxqx1GYFVxVOvh1iQ9mVlx18hzR1uN4yqKdbQstzbF2UxLoFaOW3LHWK6i3CmR4Y4xGqvKGInfez+4iqL5m2sNf8/Rt60xzqMNnlcJCQjndo2h64gUq2A9VxvoN1hxgz7My/rJurFFxePGW+oNITsgv11FazY0xpoyKnUOgo/3sIrP9VD70YSJxDBMkt2u6gsmh15qU+OkKXTLkIfHraD23+YWSiF/qgQ1OG16vIN/Bh2vuXiRQSU1IK2sygMztbgPkuFO9SyqvZI1Wkau4LbZ3On3UJ0I657D9CggNQJsHFZODRQwAec+PA/C2s28kHY+qVROt4+izYBuvekR7iwbXrCQqz6d0qOiXifrOhYthtDtHSza9iigTL1rxU2+Fu6etMQDopcOE5qPPQ4oLlvOWCX2KSf/nHJn2goIvbIzoeZb1QVorebYHYn/5GJowgw98SRg86m4ztNrAJVnurk2izEVQey+top//FoXbe95FsCueQ6w6Ero5CoicfMGsCyyquzr/cDgbvCBBhPnZ63ofdHztN3JbeGGjfwlhNALosOtI6ZVqH3e3/QiMRc3hyf1zJcA7JZmobFgYVSvSJMbUt66JWa2dcY29UnbdmB73fHysIaxoqimZF7llc2mnbt6Z+wOv2X7HmC6+8ev1bQ0IqKaL8fFxW6GclorX5XpH8lKkU5t775Z2kMOLaH9r8n94QVhbRv+6EBo4PoOavQLAkuo8i7Uo//QUvy/NlU9h9iID4dNNB4Qk7n7x+oJkLr1dT+5ZgPqSJHe40jEiPeNoyJw/wCD9bwJar91TFV4G3+k+pA8Qim+aOa+A763kBydSGJbOsAl5IoeIVbgD/PoIVaOJ4y9u1W0Hi07EppdVeASOnEy5lP9uDV1kO2EIpF+9ZwSkH0dD0Q8SN97pyGd4Y6mhDV88OyhUJ1UpbzyGeGyPHvu/fO2D+D25g9xW0ScmIFMpO4F2hEVC+NKkUz5iDRFRIkmZCa1pzLTde6GTj24mNxbt4y0c4xoNiMLqR/gbHTHFuhIV0fl40+YZU60W1Am1WM5zzfULNGHvfspa+MioZGJsqg+Af75uTFLHquc4Hi2dvKkkoWy6V4H+BuP95J0xjz4Gaf/56RONmLPvaeWccmo6wu7HNjM6XyZ0rEiTralfoBPRi27Zbj9nPhvRRs9oog7Rl8CZPTV19rgS2y3newwIX7nU1sAcr6mP+lkR+obzgkTACvDS4H3PX2eIpZv6R67rvDUEGig8zB/ktVCHRrmtF/uZxxB9Xf83AkSpPLqrnID2EGussOjtn1PHaz9P7TxbQeQMI00kxfVmTiKvmiq8pqijMNUJ/ZAlq2sAyHlYB8DbmV/xNreaFsGvr9dvwLbzUZarjA4n047ISbtdC9+llkcCxdDPz5PlBjLYjYJVuyrrpFgOrugbE+8W0UZG/nXmSlCo5n0tsiVuh8JZ3SDau5GOHiCOiMXjtUwaaEDAUD6TRh4DtWI3RffDP33JLq2XvP8ZObOUZ50J6Kxq9T7wP6m3vADn7Y5Ex3sCWTTrah1Kst7mwbLSAYd3ookuCASdf9EPt6HgW9JmgqFt1RAL5YT6s5TQS39M7hfljSkBvR5kroRudg3cJ56NDkJsHqEyZXU7TkHzJleDNwkaUxdCDlyNz4/h3zRVa7rxcEtctzwMVVykMPBp/fSL2zLrxh4hxzYxveAXPktarmBaSFOrHLgSCpCLvkS2ypaNxoAjp5JpdJN+2OmvfRmpx8cTTdJJdgSqQJ0nIodSnGwhLdMJNgkUoqKgp0OqBvm1ThY5mQZTylqJlGpFzqbtK4bHE+iSvmQ3zHre1MDY9uoRJELbp68wbihE4wlyuGrAT74JtFSohOMXw04tY+gOLg9FTBxGSJRkoCDZ8PgNk1DZJmCU/OunJhCsCXNMx114YVKkwdf0AUuRZSU63lDREuBHjBzqUlf44rBxBlBD5hzjUtfXAvBxNzVA+ZcXDNX9cmBxbOae1XPFCeQ8occWDhg/OIETjkGLn/imkch8IDwBwPlGLwClIQ0gCN5CGsQrkqwAEVYcmOvgMB7sIa/BFy3oGxQVGRUKgH2C7LmVmHRoKCsahBT+xsA34C5AY2SQUEhGZZwd/HBXfAmp1VIJtqnTidy6PV88Hywr3bpnKhYcDCeUO7mggVlhhLFgqLyyMHYZU4D/vSf6MTaDL9nqfJIUUFoXfQG8F/84ZXwo//gvJVsQaiwBLb5csgLOAmP7LuOWo80gD10lMCKi37rbhdRJQC+nrOwuq6i3/SVOaevsBulrZQdpa94H6XtcwVVRiVdm7otlQ80UPo+SUFp+wgnLOn57CgsafrQKizp+bQsIun5mC4mBn0++D/zTxjuNchMFwAAACV0RVh0ZGF0ZTpjcmVhdGUAMjAyMC0xMS0xOFQwNjozMjo1MCswMDowMD++7mUAAAAldEVYdGRhdGU6bW9kaWZ5ADIwMjAtMTEtMThUMDY6MzI6NTArMDA6MDBO41bZAAAAAElFTkSuQmCC'
|
router.push('/config')
|
||||||
// 生成模拟数据
|
|
||||||
const listData: ListItem[] = Array.from({ length: 1000 }, (_, i) => ({
|
|
||||||
id: i,
|
|
||||||
name: `project-${i + 1}`,
|
|
||||||
path: `/Users/lanyuanxiaoyao/Project/IdeaProjects/project-${i + 1}`,
|
|
||||||
// 随机选择一个图标
|
|
||||||
icon: samplePic,
|
|
||||||
tags: [
|
|
||||||
...(i % 2 === 0 ? [{ id: 1, name: 'Vue', color: '#42b883' }] : []),
|
|
||||||
...(i % 3 === 0 ? [{ id: 2, name: 'TypeScript', color: '#3178c6' }] : []),
|
|
||||||
...(i % 4 === 0 ? [{ id: 3, name: 'React', color: '#149eca' }] : []),
|
|
||||||
...(i % 5 === 0 ? [{ id: 4, name: 'Node.js', color: '#539e43' }] : []),
|
|
||||||
],
|
|
||||||
}))
|
|
||||||
|
|
||||||
// 自定义菜单项
|
|
||||||
const menuItems: MenuItem[] = [
|
|
||||||
{
|
|
||||||
id: 'refresh',
|
|
||||||
label: '刷新列表',
|
|
||||||
action: (item) => {
|
|
||||||
console.log('当前选中项:', item)
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'clear',
|
|
||||||
label: '清空选择',
|
|
||||||
action: (item) => {
|
|
||||||
console.log('清空前选中项:', item)
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'export',
|
|
||||||
label: '导出数据',
|
|
||||||
action: (item) => {
|
|
||||||
console.log('当前选中项:', item)
|
|
||||||
},
|
|
||||||
},
|
|
||||||
]
|
|
||||||
|
|
||||||
// 列表项点击事件处理
|
|
||||||
const handleItemClick = (item: ListItem): void => {
|
|
||||||
console.log('点击列表项:', item)
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<ProjectList
|
<router-view />
|
||||||
:data="listData"
|
|
||||||
:menu-items="menuItems"
|
|
||||||
@click="handleItemClick"
|
|
||||||
/>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style>
|
|
||||||
html,
|
|
||||||
body {
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
#app {
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import VirtualList from './VirtualList.vue'
|
import VirtualList from './VirtualList.vue'
|
||||||
import { ref, onMounted, onBeforeUnmount } from 'vue'
|
import { ref, onMounted, onBeforeUnmount, computed } from 'vue'
|
||||||
import type { ListItem, MenuItem } from '@/types'
|
import type { ListItem, MenuItem } from '@/types'
|
||||||
|
import { keyboardManager } from '@/utils/KeyboardManager'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 组件属性接口
|
* 组件属性接口
|
||||||
@@ -9,12 +10,13 @@ import type { ListItem, MenuItem } from '@/types'
|
|||||||
interface Props {
|
interface Props {
|
||||||
/** 列表数据 */
|
/** 列表数据 */
|
||||||
data: ListItem[]
|
data: ListItem[]
|
||||||
/** 菜单项配置 */
|
|
||||||
menuItems: MenuItem[]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const props = withDefaults(defineProps<Props>(), {})
|
const props = withDefaults(defineProps<Props>(), {})
|
||||||
|
|
||||||
|
// 在显示菜单时使用选中项的菜单列表
|
||||||
|
const currentMenuItems = computed(() => selectedItem.value?.menuItems || [])
|
||||||
|
|
||||||
// ===== 工具栏配置常量 =====
|
// ===== 工具栏配置常量 =====
|
||||||
/** 是否显示工具栏 */
|
/** 是否显示工具栏 */
|
||||||
const SHOW_TOOLBAR = true
|
const SHOW_TOOLBAR = true
|
||||||
@@ -48,6 +50,10 @@ const selectedMenuIndex = ref<number>(-1)
|
|||||||
const toastVisible = ref<boolean>(false)
|
const toastVisible = ref<boolean>(false)
|
||||||
/** Toast 消息内容 */
|
/** Toast 消息内容 */
|
||||||
const toastMessage = ref<string>('')
|
const toastMessage = ref<string>('')
|
||||||
|
/** 是否正在使用键盘导航菜单 */
|
||||||
|
const isKeyboardNavigation = ref<boolean>(false)
|
||||||
|
/** 快捷键处理函数映射 */
|
||||||
|
const shortcutHandlers = new Map<string, (e: KeyboardEvent) => void>()
|
||||||
|
|
||||||
// ===== 定时器 =====
|
// ===== 定时器 =====
|
||||||
/** 鼠标悬停禁用定时器 */
|
/** 鼠标悬停禁用定时器 */
|
||||||
@@ -82,18 +88,26 @@ const showContextMenu = (data: { item: ListItem }): void => {
|
|||||||
handleSelect(item)
|
handleSelect(item)
|
||||||
showMenu.value = true
|
showMenu.value = true
|
||||||
listFrozen.value = true
|
listFrozen.value = true
|
||||||
|
selectedMenuIndex.value = 0
|
||||||
|
isKeyboardNavigation.value = true
|
||||||
|
bindShortcuts() // 打开菜单时绑定快捷键
|
||||||
emit('context-menu', data)
|
emit('context-menu', data)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 关闭菜单并处理相关状态
|
* 关闭菜单处理相关状态
|
||||||
*/
|
*/
|
||||||
const closeMenu = (): void => {
|
const closeMenu = (): void => {
|
||||||
showMenu.value = false
|
showMenu.value = false
|
||||||
listFrozen.value = false
|
listFrozen.value = false
|
||||||
selectedMenuIndex.value = -1
|
selectedMenuIndex.value = -1
|
||||||
|
isKeyboardNavigation.value = false
|
||||||
|
|
||||||
// 临时禁用鼠标悬停,防止菜单关闭时立即触发悬停效果
|
// 清除快捷键绑定
|
||||||
|
keyboardManager.disable()
|
||||||
|
shortcutHandlers.clear()
|
||||||
|
|
||||||
|
// 临时禁用鼠标悬停,防止菜单关闭时<E997AD><E697B6><EFBFBD>即触发悬停效果
|
||||||
temporaryDisableHover.value = true
|
temporaryDisableHover.value = true
|
||||||
if (hoverDisableTimer) clearTimeout(hoverDisableTimer)
|
if (hoverDisableTimer) clearTimeout(hoverDisableTimer)
|
||||||
hoverDisableTimer = window.setTimeout(() => {
|
hoverDisableTimer = window.setTimeout(() => {
|
||||||
@@ -128,6 +142,9 @@ const handleMenuTriggerClick = (e: MouseEvent): void => {
|
|||||||
// 如果没有数据,仅显示菜单
|
// 如果没有数据,仅显示菜单
|
||||||
showMenu.value = true
|
showMenu.value = true
|
||||||
listFrozen.value = true
|
listFrozen.value = true
|
||||||
|
selectedMenuIndex.value = 0
|
||||||
|
isKeyboardNavigation.value = true
|
||||||
|
bindShortcuts() // 打开菜单时绑定快捷键
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -138,7 +155,7 @@ const handleMenuTriggerClick = (e: MouseEvent): void => {
|
|||||||
* - 左方向键/ESC:关闭菜单
|
* - 左方向键/ESC:关闭菜单
|
||||||
* - 上下方向键:在菜单打开时导航菜单项
|
* - 上下方向键:在菜单打开时导航菜单项
|
||||||
* - 回车键:在菜单打开时选择当前菜单项
|
* - 回车键:在菜单打开时选择当前菜单项
|
||||||
* @param e 键盘事件对象
|
* @param e 键盘事件<EFBFBD><EFBFBD>象
|
||||||
*/
|
*/
|
||||||
const handleKeyDown = (e: KeyboardEvent): void => {
|
const handleKeyDown = (e: KeyboardEvent): void => {
|
||||||
if (e.key === 'ArrowRight' && !showMenu.value && selectedItem.value) {
|
if (e.key === 'ArrowRight' && !showMenu.value && selectedItem.value) {
|
||||||
@@ -151,24 +168,26 @@ const handleKeyDown = (e: KeyboardEvent): void => {
|
|||||||
switch (e.key) {
|
switch (e.key) {
|
||||||
case 'ArrowUp':
|
case 'ArrowUp':
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
|
isKeyboardNavigation.value = true
|
||||||
// 向上选择菜单项,到顶部时循环到底部
|
// 向上选择菜单项,到顶部时循环到底部
|
||||||
selectedMenuIndex.value =
|
selectedMenuIndex.value =
|
||||||
selectedMenuIndex.value <= 0
|
selectedMenuIndex.value <= 0
|
||||||
? props.menuItems.length - 1
|
? currentMenuItems.value.length - 1
|
||||||
: selectedMenuIndex.value - 1
|
: selectedMenuIndex.value - 1
|
||||||
break
|
break
|
||||||
case 'ArrowDown':
|
case 'ArrowDown':
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
|
isKeyboardNavigation.value = true
|
||||||
// 向下选择菜单项,到底部时循环到顶部
|
// 向下选择菜单项,到底部时循环到顶部
|
||||||
selectedMenuIndex.value =
|
selectedMenuIndex.value =
|
||||||
selectedMenuIndex.value >= props.menuItems.length - 1
|
selectedMenuIndex.value >= currentMenuItems.value.length - 1
|
||||||
? 0
|
? 0
|
||||||
: selectedMenuIndex.value + 1
|
: selectedMenuIndex.value + 1
|
||||||
break
|
break
|
||||||
case 'Enter':
|
case 'Enter':
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
if (selectedMenuIndex.value >= 0) {
|
if (selectedMenuIndex.value >= 0) {
|
||||||
handleMenuClick(props.menuItems[selectedMenuIndex.value])
|
handleMenuClick(currentMenuItems.value[selectedMenuIndex.value])
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@@ -188,6 +207,11 @@ const showToast = (message: string): void => {
|
|||||||
}, 3000)
|
}, 3000)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 添加鼠标悬浮处理函数
|
||||||
|
const handleMenuItemHover = (index: number): void => {
|
||||||
|
selectedMenuIndex.value = index
|
||||||
|
}
|
||||||
|
|
||||||
// ===== 生命周期钩子 =====
|
// ===== 生命周期钩子 =====
|
||||||
/**
|
/**
|
||||||
* 组件挂载时添加全局事件监听
|
* 组件挂载时添加全局事件监听
|
||||||
@@ -205,6 +229,7 @@ onBeforeUnmount(() => {
|
|||||||
document.removeEventListener('keydown', handleKeyDown)
|
document.removeEventListener('keydown', handleKeyDown)
|
||||||
if (toastTimer) clearTimeout(toastTimer)
|
if (toastTimer) clearTimeout(toastTimer)
|
||||||
if (hoverDisableTimer) clearTimeout(hoverDisableTimer)
|
if (hoverDisableTimer) clearTimeout(hoverDisableTimer)
|
||||||
|
keyboardManager.disable()
|
||||||
})
|
})
|
||||||
|
|
||||||
// ===== 过渡钩子 =====
|
// ===== 过渡钩子 =====
|
||||||
@@ -225,6 +250,34 @@ const onBeforeLeave = (el: Element): void => {
|
|||||||
const onAfterLeave = (el: Element): void => {
|
const onAfterLeave = (el: Element): void => {
|
||||||
(el as HTMLElement).style.display = ''
|
(el as HTMLElement).style.display = ''
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 修改 bindShortcuts 函数
|
||||||
|
const bindShortcuts = (): void => {
|
||||||
|
// 清除之前的绑定
|
||||||
|
shortcutHandlers.forEach((_, shortcut) => {
|
||||||
|
keyboardManager.unbind(shortcut)
|
||||||
|
})
|
||||||
|
shortcutHandlers.clear()
|
||||||
|
|
||||||
|
// 只在菜单打开时绑定快捷键
|
||||||
|
if (showMenu.value) {
|
||||||
|
keyboardManager.enable()
|
||||||
|
currentMenuItems.value.forEach((item) => {
|
||||||
|
if (item.shortcut) {
|
||||||
|
const handler = (e: KeyboardEvent) => {
|
||||||
|
if (selectedItem.value || !item.action.toString().includes('selectedItem')) {
|
||||||
|
item.action(selectedItem.value)
|
||||||
|
closeMenu()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
shortcutHandlers.set(item.shortcut, handler)
|
||||||
|
keyboardManager.bind(item.shortcut, handler)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
keyboardManager.disable()
|
||||||
|
}
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@@ -232,15 +285,36 @@ const onAfterLeave = (el: Element): void => {
|
|||||||
<div class="project-list-container" @contextmenu.prevent>
|
<div class="project-list-container" @contextmenu.prevent>
|
||||||
<!-- 主要内容区域 -->
|
<!-- 主要内容区域 -->
|
||||||
<div class="main-content">
|
<div class="main-content">
|
||||||
<VirtualList
|
<template v-if="data.length > 0">
|
||||||
:data="data"
|
<VirtualList
|
||||||
:frozen="listFrozen"
|
:data="data"
|
||||||
:disable-hover="showMenu || temporaryDisableHover"
|
:frozen="listFrozen"
|
||||||
@select="handleSelect"
|
:disable-hover="showMenu || temporaryDisableHover"
|
||||||
@click="handleClick"
|
@select="handleSelect"
|
||||||
@contextmenu="showContextMenu"
|
@click="handleClick"
|
||||||
@showToast="showToast"
|
@contextmenu="showContextMenu"
|
||||||
/>
|
@showToast="showToast"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
<div v-else class="empty-state">
|
||||||
|
<div class="empty-state-content">
|
||||||
|
<svg class="empty-state-icon" viewBox="0 0 24 24" width="48" height="48">
|
||||||
|
<path
|
||||||
|
fill="currentColor"
|
||||||
|
d="M19 3H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm0 16H5V5h14v14z"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
fill="currentColor"
|
||||||
|
d="M12 6c-3.31 0-6 2.69-6 6s2.69 6 6 6 6-2.69 6-6-2.69-6-6-6zm2 7h-4v-2h4v2z"
|
||||||
|
opacity=".3"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
<h3 class="empty-state-title">暂无项目</h3>
|
||||||
|
<p class="empty-state-description">
|
||||||
|
当前列表为空,您可以添加新的项目或导入现有项目
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 工具栏 -->
|
<!-- 工具栏 -->
|
||||||
@@ -281,7 +355,7 @@ const onAfterLeave = (el: Element): void => {
|
|||||||
<div class="selected-item-name">{{ selectedItem.name }}</div>
|
<div class="selected-item-name">{{ selectedItem.name }}</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="selected-item-content">
|
<div class="selected-item-content">
|
||||||
<div class="selected-item-path">{{ selectedItem.path }}</div>
|
<div class="selected-item-description">{{ selectedItem.description }}</div>
|
||||||
<div class="selected-item-tags" v-if="selectedItem.tags?.length">
|
<div class="selected-item-tags" v-if="selectedItem.tags?.length">
|
||||||
<span
|
<span
|
||||||
v-for="tag in selectedItem.tags"
|
v-for="tag in selectedItem.tags"
|
||||||
@@ -294,16 +368,26 @@ const onAfterLeave = (el: Element): void => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="menu-divider"></div>
|
<!-- 只在有菜单项时显示分割线和菜单项列表 -->
|
||||||
<div
|
<template v-if="currentMenuItems.length > 0">
|
||||||
v-for="(item, index) in menuItems"
|
<div class="menu-divider"></div>
|
||||||
:key="item.id"
|
<div
|
||||||
class="menu-item"
|
v-for="(item, index) in currentMenuItems"
|
||||||
:class="{ 'menu-item-selected': index === selectedMenuIndex }"
|
:key="item.id"
|
||||||
@click="handleMenuClick(item)"
|
class="menu-item"
|
||||||
>
|
:class="{ 'menu-item-selected': index === selectedMenuIndex }"
|
||||||
{{ item.label }}
|
@click="handleMenuClick(item)"
|
||||||
</div>
|
@mouseover="handleMenuItemHover(index)"
|
||||||
|
>
|
||||||
|
<span class="menu-item-label">{{ item.label }}</span>
|
||||||
|
<div v-if="item.shortcut" class="menu-item-shortcut">
|
||||||
|
<template v-for="(key, keyIndex) in item.shortcut.split('+')" :key="keyIndex">
|
||||||
|
<span>{{ key }}</span>
|
||||||
|
<template v-if="keyIndex < item.shortcut.split('+').length - 1">+</template>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
</div>
|
</div>
|
||||||
</transition>
|
</transition>
|
||||||
</div>
|
</div>
|
||||||
@@ -333,7 +417,7 @@ const onAfterLeave = (el: Element): void => {
|
|||||||
min-height: 0;
|
min-height: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 工具栏:固定高度,顶部边框和阴影效果 */
|
/* 工具栏固定高度,顶部边框和阴影效果 */
|
||||||
.toolbar {
|
.toolbar {
|
||||||
height: 40px;
|
height: 40px;
|
||||||
background-color: #fff;
|
background-color: #fff;
|
||||||
@@ -435,14 +519,46 @@ const onAfterLeave = (el: Element): void => {
|
|||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 菜单项悬停和选中状态 */
|
/* 菜单项标签 */
|
||||||
.menu-item:hover,
|
.menu-item-label {
|
||||||
.menu-item-selected {
|
flex: 1;
|
||||||
background-color: rgba(0, 0, 0, 0.04);
|
min-width: 0;
|
||||||
color: rgba(0, 0, 0, 0.87);
|
}
|
||||||
|
|
||||||
|
/* 菜单项快捷键 */
|
||||||
|
.menu-item-shortcut {
|
||||||
|
margin-left: 24px;
|
||||||
|
font-size: 12px;
|
||||||
|
color: rgba(0, 0, 0, 0.6);
|
||||||
|
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
|
||||||
|
display: flex;
|
||||||
|
gap: 4px;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 快捷键按键样式 */
|
||||||
|
.menu-item-shortcut span {
|
||||||
|
padding: 2px 6px;
|
||||||
|
border-radius: 4px;
|
||||||
|
background-color: rgba(0, 0, 0, 0.05);
|
||||||
|
border: 1px solid rgba(0, 0, 0, 0.1);
|
||||||
|
box-shadow: 0 1px 0 rgba(0, 0, 0, 0.05);
|
||||||
|
font-size: 11px;
|
||||||
|
line-height: 1;
|
||||||
|
text-transform: capitalize;
|
||||||
|
min-width: 20px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 快捷键按键按下效果 */
|
||||||
|
.menu-item-selected .menu-item-shortcut span {
|
||||||
|
background-color: rgba(0, 0, 0, 0.08);
|
||||||
|
border-color: rgba(0, 0, 0, 0.15);
|
||||||
|
box-shadow: 0 1px 0 rgba(0, 0, 0, 0.1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 选中项信息区域 */
|
/* 选中项信息区域 */
|
||||||
@@ -498,11 +614,12 @@ const onAfterLeave = (el: Element): void => {
|
|||||||
gap: 8px;
|
gap: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 选中项路径 */
|
/* 选中项描述 */
|
||||||
.selected-item-path {
|
.selected-item-description {
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
color: rgba(0, 0, 0, 0.6);
|
color: rgba(0, 0, 0, 0.6);
|
||||||
word-break: break-all;
|
word-break: break-word;
|
||||||
|
overflow-wrap: break-word;
|
||||||
line-height: 1.5;
|
line-height: 1.5;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -554,4 +671,50 @@ const onAfterLeave = (el: Element): void => {
|
|||||||
opacity: 0;
|
opacity: 0;
|
||||||
transform: translate(-50%, calc(-50% - 20px));
|
transform: translate(-50%, calc(-50% - 20px));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 统一的选中效果 */
|
||||||
|
.menu-item-selected {
|
||||||
|
background-color: rgba(0, 0, 0, 0.08);
|
||||||
|
color: rgba(0, 0, 0, 0.87);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 空状态容器 */
|
||||||
|
.empty-state {
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
background-color: #fafafa;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 空状态内容区域 */
|
||||||
|
.empty-state-content {
|
||||||
|
text-align: center;
|
||||||
|
padding: 32px;
|
||||||
|
max-width: 400px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 空状态图标 */
|
||||||
|
.empty-state-icon {
|
||||||
|
color: rgba(0, 0, 0, 0.38);
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 空状态标题 */
|
||||||
|
.empty-state-title {
|
||||||
|
font-size: 20px;
|
||||||
|
font-weight: 500;
|
||||||
|
color: rgba(0, 0, 0, 0.87);
|
||||||
|
margin: 0 0 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 空状态描述文本 */
|
||||||
|
.empty-state-description {
|
||||||
|
font-size: 14px;
|
||||||
|
color: rgba(0, 0, 0, 0.6);
|
||||||
|
margin: 0;
|
||||||
|
line-height: 1.5;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
@@ -179,7 +179,6 @@ function handleMouseEnter(index: number): void {
|
|||||||
if (!isKeyboardNavigating.value) {
|
if (!isKeyboardNavigating.value) {
|
||||||
selectedIndex.value = index
|
selectedIndex.value = index
|
||||||
emit('select', { ...props.data[index], index })
|
emit('select', { ...props.data[index], index })
|
||||||
ensureSelectedItemVisible()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -192,8 +191,12 @@ const lastReachBoundaryTime = ref<{ top: number; bottom: number }>({
|
|||||||
bottom: 0
|
bottom: 0
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// 添加新的状态变量用于追踪按键状<E994AE><E78AB6><EFBFBD>
|
||||||
|
const isKeyPressed = ref<boolean>(false)
|
||||||
|
let keyPressTimer: number | null = null
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 处理<EFBFBD><EFBFBD>盘事件
|
* 处理键盘事件
|
||||||
* 实现键盘导航、边界循环和项目选择功能
|
* 实现键盘导航、边界循环和项目选择功能
|
||||||
* @param e 键盘事件对象
|
* @param e 键盘事件对象
|
||||||
*/
|
*/
|
||||||
@@ -205,13 +208,25 @@ function handleKeyDown(e: KeyboardEvent): void {
|
|||||||
const item = props.data[selectedIndex.value]
|
const item = props.data[selectedIndex.value]
|
||||||
emit('click', { ...item, index: selectedIndex.value })
|
emit('click', { ...item, index: selectedIndex.value })
|
||||||
}
|
}
|
||||||
} else if (e.key === 'ArrowUp' || e.key === 'ArrowDown') {
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (e.key === 'ArrowUp' || e.key === 'ArrowDown') {
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
|
|
||||||
const isFirstItem = selectedIndex.value === 0
|
const isFirstItem = selectedIndex.value === 0
|
||||||
const isLastItem = selectedIndex.value === props.data.length - 1
|
const isLastItem = selectedIndex.value === props.data.length - 1
|
||||||
const now = Date.now()
|
const now = Date.now()
|
||||||
|
|
||||||
|
// 只在首尾项时检查按键状态
|
||||||
|
if ((e.key === 'ArrowUp' && isFirstItem) || (e.key === 'ArrowDown' && isLastItem)) {
|
||||||
|
if (isKeyPressed.value) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
isKeyPressed.value = true
|
||||||
|
if (keyPressTimer) clearTimeout(keyPressTimer)
|
||||||
|
}
|
||||||
|
|
||||||
if (e.key === 'ArrowUp' && isFirstItem) {
|
if (e.key === 'ArrowUp' && isFirstItem) {
|
||||||
const timeSinceLastTop = now - lastReachBoundaryTime.value.top
|
const timeSinceLastTop = now - lastReachBoundaryTime.value.top
|
||||||
if (timeSinceLastTop < 5000) {
|
if (timeSinceLastTop < 5000) {
|
||||||
@@ -248,6 +263,7 @@ function handleKeyDown(e: KeyboardEvent): void {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 非首尾项的正常导航逻辑
|
||||||
isKeyboardNavigating.value = true
|
isKeyboardNavigating.value = true
|
||||||
if (keyboardTimer) clearTimeout(keyboardTimer)
|
if (keyboardTimer) clearTimeout(keyboardTimer)
|
||||||
|
|
||||||
@@ -278,6 +294,17 @@ function handleKeyDown(e: KeyboardEvent): void {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 添加键盘抬起事件处理函数
|
||||||
|
function handleKeyUp(e: KeyboardEvent): void {
|
||||||
|
if (e.key === 'ArrowUp' || e.key === 'ArrowDown') {
|
||||||
|
// 设置一个短暂的延时,确保不会立即响应下一次按键
|
||||||
|
if (keyPressTimer) clearTimeout(keyPressTimer)
|
||||||
|
keyPressTimer = window.setTimeout(() => {
|
||||||
|
isKeyPressed.value = false
|
||||||
|
}, 50)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 保持选中项在可视区域内
|
* 保持选中项在可视区域内
|
||||||
* 如果选中项不可见,则滚动到合适位置
|
* 如果选中项不可见,则滚动到合适位置
|
||||||
@@ -331,6 +358,7 @@ onMounted(() => {
|
|||||||
// 添加全局事件监听
|
// 添加全局事件监听
|
||||||
window.addEventListener('resize', updateContainerHeight)
|
window.addEventListener('resize', updateContainerHeight)
|
||||||
window.addEventListener('keydown', handleKeyDown)
|
window.addEventListener('keydown', handleKeyDown)
|
||||||
|
window.addEventListener('keyup', handleKeyUp)
|
||||||
})
|
})
|
||||||
|
|
||||||
onBeforeUnmount(() => {
|
onBeforeUnmount(() => {
|
||||||
@@ -345,8 +373,10 @@ onBeforeUnmount(() => {
|
|||||||
|
|
||||||
window.removeEventListener('resize', updateContainerHeight)
|
window.removeEventListener('resize', updateContainerHeight)
|
||||||
window.removeEventListener('keydown', handleKeyDown)
|
window.removeEventListener('keydown', handleKeyDown)
|
||||||
|
window.removeEventListener('keyup', handleKeyUp)
|
||||||
if (keyboardTimer) clearTimeout(keyboardTimer)
|
if (keyboardTimer) clearTimeout(keyboardTimer)
|
||||||
if (hoverTimer) clearTimeout(hoverTimer)
|
if (hoverTimer) clearTimeout(hoverTimer)
|
||||||
|
if (keyPressTimer) clearTimeout(keyPressTimer)
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -415,8 +445,8 @@ onBeforeUnmount(() => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- 路径信息 -->
|
<!-- 路径信息 -->
|
||||||
<div class="item-info">
|
<div class="item-description">
|
||||||
<div class="item-path">{{ item.path }}</div>
|
<div class="item-description-text">{{ item.description }}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -436,6 +466,7 @@ onBeforeUnmount(() => {
|
|||||||
background-color: #fafafa;
|
background-color: #fafafa;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
outline: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 拟高度容器:用于保持滚动条比例 */
|
/* 拟高度容器:用于保持滚动条比例 */
|
||||||
@@ -526,13 +557,13 @@ onBeforeUnmount(() => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* 信息行布局 */
|
/* 信息行布局 */
|
||||||
.item-info {
|
.item-description {
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 4px;
|
gap: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 路径文本样式 */
|
/* 描述文本样式 */
|
||||||
.item-path {
|
.item-description-text {
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
color: rgba(0, 0, 0, 0.6);
|
color: rgba(0, 0, 0, 0.6);
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
import { createApp } from 'vue'
|
import { createApp } from 'vue'
|
||||||
import type { App as AppType } from 'vue'
|
|
||||||
import App from './App.vue'
|
import App from './App.vue'
|
||||||
|
import router from './router'
|
||||||
|
import './style.css'
|
||||||
|
|
||||||
const app: AppType = createApp(App)
|
const app = createApp(App)
|
||||||
|
app.use(router)
|
||||||
app.mount('#app')
|
app.mount('#app')
|
||||||
|
|||||||
317
src/pages/Config.vue
Normal file
317
src/pages/Config.vue
Normal file
@@ -0,0 +1,317 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { ref } from 'vue'
|
||||||
|
import { ConfigGroup, TextConfigItem, SelectConfigItem, SwitchConfigItem, ConfigItemType } from '@/types/config'
|
||||||
|
import { ConfigManager, LocalStorageConfigStore } from '@/utils/ConfigStore'
|
||||||
|
|
||||||
|
const configManager = ConfigManager.getInstance(new LocalStorageConfigStore())
|
||||||
|
|
||||||
|
// 防抖函数
|
||||||
|
const debounce = (fn: Function, delay: number) => {
|
||||||
|
let timer: number | null = null
|
||||||
|
return (...args: any[]) => {
|
||||||
|
if (timer) clearTimeout(timer)
|
||||||
|
timer = setTimeout(() => {
|
||||||
|
fn(...args)
|
||||||
|
timer = null
|
||||||
|
}, delay)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理文本配置项实时更新
|
||||||
|
const handleTextConfigChange = debounce((item: TextConfigItem, group: ConfigGroup) => {
|
||||||
|
configManager.updateConfig({
|
||||||
|
[`${group.key}.${item.key}`]: item.value
|
||||||
|
})
|
||||||
|
console.log('配置已更新:', configManager.getAllConfig())
|
||||||
|
}, 300)
|
||||||
|
|
||||||
|
// 处理单个配置项更改
|
||||||
|
const handleConfigItemChange = (item: any, group: ConfigGroup) => {
|
||||||
|
configManager.updateConfig({
|
||||||
|
[`${group.key}.${item.key}`]: item.value
|
||||||
|
})
|
||||||
|
console.log('配置已更新:', configManager.getAllConfig())
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理配置组启用状态变更
|
||||||
|
const handleGroupEnableChange = (group: ConfigGroup) => {
|
||||||
|
configManager.updateConfig({
|
||||||
|
[`${group.key}.enabled`]: group.enabled
|
||||||
|
})
|
||||||
|
console.log('配置已更新:', configManager.getAllConfig())
|
||||||
|
}
|
||||||
|
|
||||||
|
// 使用构造函数定义配置组
|
||||||
|
const configGroups = ref([
|
||||||
|
new ConfigGroup('appearance', '外观设置', false, [
|
||||||
|
new TextConfigItem(
|
||||||
|
'projectName',
|
||||||
|
'项目名称',
|
||||||
|
'设置新建项目时的默认项目名称',
|
||||||
|
'',
|
||||||
|
'请输入默认项目名称'
|
||||||
|
),
|
||||||
|
new SelectConfigItem(
|
||||||
|
'theme',
|
||||||
|
'主题',
|
||||||
|
'切换应用的显示主题',
|
||||||
|
[
|
||||||
|
{ label: '浅色', value: 'light' },
|
||||||
|
{ label: '深色', value: 'dark' }
|
||||||
|
],
|
||||||
|
'light'
|
||||||
|
)
|
||||||
|
]),
|
||||||
|
|
||||||
|
new ConfigGroup('system', '系统设置', true, [
|
||||||
|
new SelectConfigItem(
|
||||||
|
'language',
|
||||||
|
'语言',
|
||||||
|
'设置应用界面显示的语言',
|
||||||
|
[
|
||||||
|
{ label: '中文', value: 'zh-CN' },
|
||||||
|
{ label: 'English', value: 'en-US' }
|
||||||
|
],
|
||||||
|
'zh-CN'
|
||||||
|
),
|
||||||
|
new SwitchConfigItem(
|
||||||
|
'autoSave',
|
||||||
|
'自动保存',
|
||||||
|
'开启后将自动保存您的修改',
|
||||||
|
true
|
||||||
|
),
|
||||||
|
new SwitchConfigItem(
|
||||||
|
'notifications',
|
||||||
|
'通知提醒',
|
||||||
|
'是否显示系统通知提醒',
|
||||||
|
true
|
||||||
|
)
|
||||||
|
])
|
||||||
|
])
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="config-container">
|
||||||
|
<h2 class="config-title">系统设置</h2>
|
||||||
|
|
||||||
|
<div
|
||||||
|
v-for="(group, groupIndex) in configGroups"
|
||||||
|
:key="groupIndex"
|
||||||
|
class="config-section"
|
||||||
|
>
|
||||||
|
<div class="group-header">
|
||||||
|
<h3 class="group-title">{{ group.title }}</h3>
|
||||||
|
<label class="switch">
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
v-model="group.enabled"
|
||||||
|
@change="handleGroupEnableChange(group)"
|
||||||
|
>
|
||||||
|
<span class="slider"></span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div
|
||||||
|
v-if="group.enabled"
|
||||||
|
v-for="(item, itemIndex) in group.items"
|
||||||
|
:key="itemIndex"
|
||||||
|
class="config-item"
|
||||||
|
>
|
||||||
|
<div class="item-info">
|
||||||
|
<div class="item-label">{{ item.label }}</div>
|
||||||
|
<div v-if="item.description" class="item-description">
|
||||||
|
{{ item.description }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 文本输入 -->
|
||||||
|
<div v-if="item.type === ConfigItemType.TEXT" class="input-wrapper">
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
v-model="item.value"
|
||||||
|
:placeholder="(item as any).placeholder"
|
||||||
|
@input="handleTextConfigChange(item, group)"
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 开关 -->
|
||||||
|
<label v-else-if="item.type === ConfigItemType.SWITCH" class="switch">
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
v-model="item.value"
|
||||||
|
@change="handleConfigItemChange(item, group)"
|
||||||
|
>
|
||||||
|
<span class="slider"></span>
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<!-- 下拉选择 -->
|
||||||
|
<div v-else-if="item.type === ConfigItemType.SELECT" class="select-wrapper">
|
||||||
|
<select
|
||||||
|
v-model="item.value"
|
||||||
|
@change="handleConfigItemChange(item, group)"
|
||||||
|
>
|
||||||
|
<option
|
||||||
|
v-for="option in (item as any).options"
|
||||||
|
:key="option.value"
|
||||||
|
:value="option.value"
|
||||||
|
>
|
||||||
|
{{ option.label }}
|
||||||
|
</option>
|
||||||
|
</select>
|
||||||
|
<div class="select-arrow"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.config-container {
|
||||||
|
padding: 24px;
|
||||||
|
max-width: 600px;
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.config-title {
|
||||||
|
font-size: 24px;
|
||||||
|
font-weight: 500;
|
||||||
|
color: #333;
|
||||||
|
margin-bottom: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.config-section {
|
||||||
|
background: #fff;
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 24px;
|
||||||
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||||||
|
margin-bottom: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.group-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.group-title {
|
||||||
|
font-size: 18px;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
.config-item {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: 12px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.item-info {
|
||||||
|
flex: 1;
|
||||||
|
margin-right: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.item-label {
|
||||||
|
font-size: 14px;
|
||||||
|
color: rgba(0, 0, 0, 0.87);
|
||||||
|
}
|
||||||
|
|
||||||
|
.item-description {
|
||||||
|
font-size: 12px;
|
||||||
|
color: rgba(0, 0, 0, 0.45);
|
||||||
|
margin-top: 4px;
|
||||||
|
line-height: 1.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 输入框通用包装器 */
|
||||||
|
.input-wrapper {
|
||||||
|
position: relative;
|
||||||
|
width: 200px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-wrapper input {
|
||||||
|
width: 100%;
|
||||||
|
padding: 8px 12px;
|
||||||
|
outline: none;
|
||||||
|
font-size: 14px;
|
||||||
|
border: 1px solid #ddd;
|
||||||
|
border-radius: 4px;
|
||||||
|
transition: all 0.2s;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-wrapper input:focus {
|
||||||
|
border-color: #1976d2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 开关样式 */
|
||||||
|
.switch {
|
||||||
|
position: relative;
|
||||||
|
display: inline-block;
|
||||||
|
width: 40px;
|
||||||
|
height: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.switch input {
|
||||||
|
opacity: 0;
|
||||||
|
width: 0;
|
||||||
|
height: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.slider {
|
||||||
|
position: absolute;
|
||||||
|
cursor: pointer;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
background-color: #ccc;
|
||||||
|
transition: 0.3s;
|
||||||
|
border-radius: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.slider:before {
|
||||||
|
position: absolute;
|
||||||
|
content: "";
|
||||||
|
height: 16px;
|
||||||
|
width: 16px;
|
||||||
|
left: 2px;
|
||||||
|
bottom: 2px;
|
||||||
|
background-color: white;
|
||||||
|
transition: 0.3s;
|
||||||
|
border-radius: 50%;
|
||||||
|
box-shadow: 0 1px 2px rgba(0,0,0,0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.switch input:checked + .slider {
|
||||||
|
background-color: #1976d2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.switch input:checked + .slider:before {
|
||||||
|
transform: translateX(20px);
|
||||||
|
background-color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 下拉选择框样式 */
|
||||||
|
.select-wrapper {
|
||||||
|
position: relative;
|
||||||
|
width: 200px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.select-wrapper select {
|
||||||
|
width: 100%;
|
||||||
|
padding: 8px 12px;
|
||||||
|
border: 1px solid #ddd;
|
||||||
|
border-radius: 4px;
|
||||||
|
appearance: none;
|
||||||
|
background: white;
|
||||||
|
font-size: 14px;
|
||||||
|
cursor: pointer;
|
||||||
|
outline: none;
|
||||||
|
transition: all 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.select-wrapper select:focus {
|
||||||
|
border-color: #1976d2;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
59
src/pages/Project.vue
Normal file
59
src/pages/Project.vue
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { ref, type Ref } from 'vue'
|
||||||
|
import ProjectList from '@/components/ProjectList.vue'
|
||||||
|
import type { ListItem, MenuItem } from '@/types'
|
||||||
|
|
||||||
|
// 生成模拟数据
|
||||||
|
const listData: Ref<ListItem[]> = ref([])
|
||||||
|
const initListData = () => {
|
||||||
|
let samplePic = 'https://aisuda.bce.baidu.com/amis/static/favicon_b3b0647.png'
|
||||||
|
listData.value = Array.from({ length: 1000 }, (_, i) => ({
|
||||||
|
id: i,
|
||||||
|
name: `project-${i + 1}`,
|
||||||
|
description: `这是项目 ${i + 1} 的详细描述信息`,
|
||||||
|
icon: samplePic,
|
||||||
|
tags: [
|
||||||
|
...(i % 2 === 0 ? [{ id: 1, name: 'Vue', color: '#42b883' }] : []),
|
||||||
|
...(i % 3 === 0 ? [{ id: 2, name: 'TypeScript', color: '#3178c6' }] : []),
|
||||||
|
...(i % 4 === 0 ? [{ id: 3, name: 'React', color: '#149eca' }] : []),
|
||||||
|
...(i % 5 === 0 ? [{ id: 4, name: 'Node.js', color: '#539e43' }] : []),
|
||||||
|
],
|
||||||
|
// 为每个列表项定义其特有的菜单项
|
||||||
|
menuItems: (i % 2 === 0 ? [
|
||||||
|
{
|
||||||
|
id: 'open',
|
||||||
|
label: '打开项目',
|
||||||
|
action: (item) => {
|
||||||
|
console.log('打开项目:', item?.name)
|
||||||
|
},
|
||||||
|
shortcut: 'alt+o'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'edit',
|
||||||
|
label: '编辑项目',
|
||||||
|
action: (item) => {
|
||||||
|
console.log('编辑项目:', item?.name)
|
||||||
|
},
|
||||||
|
shortcut: 'ctrl+e'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'delete',
|
||||||
|
label: '删除项目',
|
||||||
|
action: (item) => {
|
||||||
|
console.log('删除项目:', item?.name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
] : undefined)
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
initListData()
|
||||||
|
|
||||||
|
// 列表项点击事件处理
|
||||||
|
const handleItemClick = (item: ListItem): void => {
|
||||||
|
console.log('点击列表项:', item)
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<ProjectList :data="listData" @click="handleItemClick" />
|
||||||
|
</template>
|
||||||
27
src/router/index.ts
Normal file
27
src/router/index.ts
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
import { createWebHashHistory } from 'vue-router'
|
||||||
|
import { createRouter } from 'vue-router'
|
||||||
|
import type { RouteRecordRaw } from 'vue-router'
|
||||||
|
|
||||||
|
const routes: RouteRecordRaw[] = [
|
||||||
|
{
|
||||||
|
path: '/',
|
||||||
|
redirect: '/project'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/project',
|
||||||
|
name: 'project',
|
||||||
|
component: () => import('@/pages/Project.vue')
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/config',
|
||||||
|
name: 'config',
|
||||||
|
component: () => import('@/pages/Config.vue')
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
const router = createRouter({
|
||||||
|
history: createWebHashHistory(),
|
||||||
|
routes
|
||||||
|
})
|
||||||
|
|
||||||
|
export default router
|
||||||
10
src/style.css
Normal file
10
src/style.css
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
html,
|
||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
#app {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
74
src/types/config.ts
Normal file
74
src/types/config.ts
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
// 配置项类型枚举
|
||||||
|
export enum ConfigItemType {
|
||||||
|
TEXT = 'text',
|
||||||
|
SWITCH = 'switch',
|
||||||
|
SELECT = 'select'
|
||||||
|
}
|
||||||
|
|
||||||
|
// 基础配置项接口
|
||||||
|
export interface BaseConfigItem {
|
||||||
|
type: ConfigItemType
|
||||||
|
key: string
|
||||||
|
label: string
|
||||||
|
value: any
|
||||||
|
description: string
|
||||||
|
}
|
||||||
|
|
||||||
|
// 文本配置项
|
||||||
|
export class TextConfigItem implements BaseConfigItem {
|
||||||
|
readonly type = ConfigItemType.TEXT
|
||||||
|
value: string
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
public key: string,
|
||||||
|
public label: string,
|
||||||
|
public description: string,
|
||||||
|
defaultValue: string = '',
|
||||||
|
public placeholder?: string
|
||||||
|
) {
|
||||||
|
this.value = defaultValue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 开关配置项
|
||||||
|
export class SwitchConfigItem implements BaseConfigItem {
|
||||||
|
readonly type = ConfigItemType.SWITCH
|
||||||
|
value: boolean
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
public key: string,
|
||||||
|
public label: string,
|
||||||
|
public description: string,
|
||||||
|
defaultValue: boolean = false
|
||||||
|
) {
|
||||||
|
this.value = defaultValue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 选择配置项
|
||||||
|
export class SelectConfigItem implements BaseConfigItem {
|
||||||
|
readonly type = ConfigItemType.SELECT
|
||||||
|
value: string
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
public key: string,
|
||||||
|
public label: string,
|
||||||
|
public description: string,
|
||||||
|
public options: Array<{ label: string; value: string }>,
|
||||||
|
defaultValue: string
|
||||||
|
) {
|
||||||
|
this.value = defaultValue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export type ConfigItem = TextConfigItem | SelectConfigItem | SwitchConfigItem
|
||||||
|
|
||||||
|
// 配置组
|
||||||
|
export class ConfigGroup {
|
||||||
|
constructor(
|
||||||
|
public key: string,
|
||||||
|
public title: string,
|
||||||
|
public enabled: boolean,
|
||||||
|
public items: ConfigItem[]
|
||||||
|
) {}
|
||||||
|
}
|
||||||
@@ -18,14 +18,16 @@ export interface ListItem {
|
|||||||
id: number
|
id: number
|
||||||
/** 项目名称 */
|
/** 项目名称 */
|
||||||
name: string
|
name: string
|
||||||
/** 项目路径 */
|
/** 项目描述 */
|
||||||
path: string
|
description: string
|
||||||
/** 项目图标 URL */
|
/** 项目图标 URL */
|
||||||
icon?: string
|
icon?: string
|
||||||
/** 项目标签列表 */
|
/** 项目标签列表 */
|
||||||
tags?: Tag[]
|
tags?: Tag[]
|
||||||
/** 在虚拟列表中的索引位置 */
|
/** 在虚拟列表中的索引位置 */
|
||||||
index?: number
|
index?: number
|
||||||
|
/** 菜单项列表 */
|
||||||
|
menuItems?: MenuItem[]
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -38,4 +40,6 @@ export interface MenuItem {
|
|||||||
label: string
|
label: string
|
||||||
/** 菜单项点击处理函数,接收当前选中的列表项作为参数 */
|
/** 菜单项点击处理函数,接收当前选中的列表项作为参数 */
|
||||||
action: (item: ListItem | null) => void
|
action: (item: ListItem | null) => void
|
||||||
|
/** 快捷键,例如 'ctrl+c', 'command+v' 等 */
|
||||||
|
shortcut?: string
|
||||||
}
|
}
|
||||||
98
src/utils/ConfigStore.ts
Normal file
98
src/utils/ConfigStore.ts
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
// 配置存储接口
|
||||||
|
export interface ConfigStore {
|
||||||
|
get<T>(key: string): T | undefined
|
||||||
|
set<T>(key: string, value: T): void
|
||||||
|
getAll(): Record<string, any>
|
||||||
|
clear(): void
|
||||||
|
}
|
||||||
|
|
||||||
|
// 内存存储实现
|
||||||
|
export class MemoryConfigStore implements ConfigStore {
|
||||||
|
private store: Record<string, any> = {}
|
||||||
|
|
||||||
|
get<T>(key: string): T | undefined {
|
||||||
|
return this.store[key] as T
|
||||||
|
}
|
||||||
|
|
||||||
|
set<T>(key: string, value: T): void {
|
||||||
|
this.store[key] = value
|
||||||
|
}
|
||||||
|
|
||||||
|
getAll(): Record<string, any> {
|
||||||
|
return { ...this.store }
|
||||||
|
}
|
||||||
|
|
||||||
|
clear(): void {
|
||||||
|
this.store = {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// LocalStorage存储实现
|
||||||
|
export class LocalStorageConfigStore implements ConfigStore {
|
||||||
|
private readonly prefix = 'app_config.'
|
||||||
|
|
||||||
|
private getKey(key: string): string {
|
||||||
|
return this.prefix + key
|
||||||
|
}
|
||||||
|
|
||||||
|
get<T>(key: string): T | undefined {
|
||||||
|
const value = localStorage.getItem(this.getKey(key))
|
||||||
|
return value ? JSON.parse(value) : undefined
|
||||||
|
}
|
||||||
|
|
||||||
|
set<T>(key: string, value: T): void {
|
||||||
|
localStorage.setItem(this.getKey(key), JSON.stringify(value))
|
||||||
|
}
|
||||||
|
|
||||||
|
getAll(): Record<string, any> {
|
||||||
|
const result: Record<string, any> = {}
|
||||||
|
for (let i = 0; i < localStorage.length; i++) {
|
||||||
|
const key = localStorage.key(i)
|
||||||
|
if (key?.startsWith(this.prefix)) {
|
||||||
|
const realKey = key.slice(this.prefix.length)
|
||||||
|
result[realKey] = JSON.parse(localStorage.getItem(key) || '{}')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
clear(): void {
|
||||||
|
for (let i = localStorage.length - 1; i >= 0; i--) {
|
||||||
|
const key = localStorage.key(i)
|
||||||
|
if (key?.startsWith(this.prefix)) {
|
||||||
|
localStorage.removeItem(key)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 配置管理器
|
||||||
|
export class ConfigManager {
|
||||||
|
private static instance: ConfigManager
|
||||||
|
private store: ConfigStore
|
||||||
|
|
||||||
|
private constructor(store: ConfigStore) {
|
||||||
|
this.store = store
|
||||||
|
}
|
||||||
|
|
||||||
|
static getInstance(store: ConfigStore = new MemoryConfigStore()): ConfigManager {
|
||||||
|
if (!ConfigManager.instance) {
|
||||||
|
ConfigManager.instance = new ConfigManager(store)
|
||||||
|
}
|
||||||
|
return ConfigManager.instance
|
||||||
|
}
|
||||||
|
|
||||||
|
updateConfig(config: Record<string, any>): void {
|
||||||
|
Object.entries(config).forEach(([key, value]) => {
|
||||||
|
this.store.set(key, value)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
getConfig<T>(key: string): T | undefined {
|
||||||
|
return this.store.get<T>(key)
|
||||||
|
}
|
||||||
|
|
||||||
|
getAllConfig(): Record<string, any> {
|
||||||
|
return this.store.getAll()
|
||||||
|
}
|
||||||
|
}
|
||||||
116
src/utils/KeyboardManager.ts
Normal file
116
src/utils/KeyboardManager.ts
Normal file
@@ -0,0 +1,116 @@
|
|||||||
|
type KeyboardCallback = (e: KeyboardEvent) => void
|
||||||
|
|
||||||
|
export class KeyboardManager {
|
||||||
|
private shortcuts: Map<string, KeyboardCallback> = new Map()
|
||||||
|
private pressedKeys: Set<string> = new Set()
|
||||||
|
private enabled: boolean = false
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this.handleKeyDown = this.handleKeyDown.bind(this)
|
||||||
|
this.handleKeyUp = this.handleKeyUp.bind(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 启用快捷键监听
|
||||||
|
*/
|
||||||
|
enable(): void {
|
||||||
|
if (!this.enabled) {
|
||||||
|
window.addEventListener('keydown', this.handleKeyDown)
|
||||||
|
window.addEventListener('keyup', this.handleKeyUp)
|
||||||
|
this.enabled = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 禁用快捷键监听
|
||||||
|
*/
|
||||||
|
disable(): void {
|
||||||
|
if (this.enabled) {
|
||||||
|
window.removeEventListener('keydown', this.handleKeyDown)
|
||||||
|
window.removeEventListener('keyup', this.handleKeyUp)
|
||||||
|
this.enabled = false
|
||||||
|
this.pressedKeys.clear()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 绑定快捷键
|
||||||
|
*/
|
||||||
|
bind(shortcut: string, callback: KeyboardCallback): void {
|
||||||
|
this.shortcuts.set(this.normalizeShortcut(shortcut), callback)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 解绑快捷键
|
||||||
|
*/
|
||||||
|
unbind(shortcut: string): void {
|
||||||
|
this.shortcuts.delete(this.normalizeShortcut(shortcut))
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 清除所有快捷键绑定
|
||||||
|
*/
|
||||||
|
clear(): void {
|
||||||
|
this.shortcuts.clear()
|
||||||
|
this.pressedKeys.clear()
|
||||||
|
}
|
||||||
|
|
||||||
|
private handleKeyDown(e: KeyboardEvent): void {
|
||||||
|
// 忽略在输入框中的按键
|
||||||
|
if (this.shouldIgnoreInput(e)) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const key = this.normalizeKey(e.key.toLowerCase())
|
||||||
|
this.pressedKeys.add(key)
|
||||||
|
|
||||||
|
const currentShortcut = Array.from(this.pressedKeys).sort().join('+')
|
||||||
|
const callback = this.shortcuts.get(currentShortcut)
|
||||||
|
|
||||||
|
if (callback) {
|
||||||
|
e.preventDefault()
|
||||||
|
e.stopPropagation()
|
||||||
|
callback(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private handleKeyUp(e: KeyboardEvent): void {
|
||||||
|
const key = this.normalizeKey(e.key.toLowerCase())
|
||||||
|
this.pressedKeys.delete(key)
|
||||||
|
}
|
||||||
|
|
||||||
|
private normalizeKey(key: string): string {
|
||||||
|
const keyMap: Record<string, string> = {
|
||||||
|
'control': 'ctrl',
|
||||||
|
'command': 'cmd',
|
||||||
|
'meta': 'cmd',
|
||||||
|
'escape': 'esc',
|
||||||
|
' ': 'space',
|
||||||
|
'arrowup': 'up',
|
||||||
|
'arrowdown': 'down',
|
||||||
|
'arrowleft': 'left',
|
||||||
|
'arrowright': 'right',
|
||||||
|
}
|
||||||
|
return keyMap[key] || key
|
||||||
|
}
|
||||||
|
|
||||||
|
private normalizeShortcut(shortcut: string): string {
|
||||||
|
return shortcut
|
||||||
|
.toLowerCase()
|
||||||
|
.split('+')
|
||||||
|
.map(key => this.normalizeKey(key.trim()))
|
||||||
|
.sort()
|
||||||
|
.join('+')
|
||||||
|
}
|
||||||
|
|
||||||
|
private shouldIgnoreInput(e: KeyboardEvent): boolean {
|
||||||
|
const element = e.target as HTMLElement
|
||||||
|
return element.tagName === 'INPUT' ||
|
||||||
|
element.tagName === 'TEXTAREA' ||
|
||||||
|
element.tagName === 'SELECT' ||
|
||||||
|
element.isContentEditable
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 导出单例实例
|
||||||
|
export const keyboardManager = new KeyboardManager()
|
||||||
@@ -21,7 +21,10 @@
|
|||||||
"@/*": [
|
"@/*": [
|
||||||
"src/*"
|
"src/*"
|
||||||
]
|
]
|
||||||
}
|
},
|
||||||
|
"types": [
|
||||||
|
"vue-router"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"include": [
|
"include": [
|
||||||
"src/**/*.ts",
|
"src/**/*.ts",
|
||||||
|
|||||||
Reference in New Issue
Block a user