├── .gitignore ├── .vscode └── extensions.json ├── README.md ├── auto-imports.d.ts ├── components.d.ts ├── index.html ├── package-lock.json ├── package.json ├── pnpm-lock.yaml ├── public ├── tauri.svg └── vite.svg ├── src-tauri ├── .gitignore ├── Cargo.lock ├── Cargo.toml ├── build.rs ├── icons │ ├── 128x128.png │ ├── 128x128@2x.png │ ├── 32x32.png │ ├── Square107x107Logo.png │ ├── Square142x142Logo.png │ ├── Square150x150Logo.png │ ├── Square284x284Logo.png │ ├── Square30x30Logo.png │ ├── Square310x310Logo.png │ ├── Square44x44Logo.png │ ├── Square71x71Logo.png │ ├── Square89x89Logo.png │ ├── StoreLogo.png │ ├── af-icon.ico │ ├── af.ico │ ├── af.png │ ├── icon.icns │ ├── icon.ico │ └── icon.png ├── src │ └── main.rs └── tauri.conf.json ├── src ├── App.vue ├── assets │ ├── bars.svg │ └── fingerPanel.svg ├── components │ ├── ChordDraw.vue │ ├── ChordSelect.vue │ ├── Fingering.vue │ └── chordSelect.vue ├── main.ts ├── styles.css ├── types │ └── index.ts ├── utils │ ├── chordComputed │ │ ├── chordName │ │ │ └── index.ts │ │ ├── chordSvg │ │ │ └── index.ts │ │ ├── guitarChord │ │ │ └── index.ts │ │ ├── index.ts │ │ └── tone │ │ │ └── index.ts │ └── tools │ │ └── index.ts └── vite-env.d.ts ├── tsconfig.json ├── vite.config.ts └── vite.config.ts.timestamp-1707646459839-1ec6ee3517027.mjs /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "Vue.volar", 4 | "tauri-apps.tauri-vscode", 5 | "rust-lang.rust-analyzer" 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # guitar-assits 2 | 3 | (Under design, not yet perfected) 4 | 5 | ## latest release version 1.1.1 6 | 网页版: https://zourunfa.github.io/guitar-elf/ 7 | 8 | 运行: pnpm run tarui build 9 | 既可以打包得到桌面端软件: 10 | windows版本(tauri打包): 11 | guitar-assits_0.0.0_x64_en-US.msi 12 | 13 | 14 | 15 | to learing guitar base theory with coding 16 | 17 | 18 | There are two main functions as follows: 19 | 1. The cardboard can click on the character and generate the chord name you want to know 20 | 21 | 2. Generate chord fingering based on sound names 22 | 23 | 24 | 25 | #Todos: 26 | 27 | 28 | - [ ] Finger: reseting and clear all clicks 29 | 30 | - [ ] Finger: List the root and constituent notes of the generated chords 31 | 32 | - [ ] Finger: make the click point with a finger img 33 | -------------------------------------------------------------------------------- /auto-imports.d.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | /* prettier-ignore */ 3 | // @ts-nocheck 4 | // noinspection JSUnusedGlobalSymbols 5 | // Generated by unplugin-auto-import 6 | export {} 7 | declare global { 8 | 9 | } 10 | -------------------------------------------------------------------------------- /components.d.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | /* prettier-ignore */ 3 | // @ts-nocheck 4 | // Generated by unplugin-vue-components 5 | // Read more: https://github.com/vuejs/core/pull/3399 6 | export {} 7 | 8 | declare module 'vue' { 9 | export interface GlobalComponents { 10 | ChordDraw: typeof import('./src/components/ChordDraw.vue')['default'] 11 | ChordSelect: typeof import('./src/components/ChordSelect.vue')['default'] 12 | ElButton: typeof import('element-plus/es')['ElButton'] 13 | ElTabPane: typeof import('element-plus/es')['ElTabPane'] 14 | ElTabs: typeof import('element-plus/es')['ElTabs'] 15 | Fingering: typeof import('./src/components/Fingering.vue')['default'] 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | test 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "guitar-assits", 3 | "version": "0.0.0", 4 | "lockfileVersion": 2, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "version": "0.0.0", 9 | "dependencies": { 10 | "@tauri-apps/api": "^1.5.0", 11 | "vue": "^3.3.4" 12 | }, 13 | "devDependencies": { 14 | "@tauri-apps/cli": "^1.5.0", 15 | "@vitejs/plugin-vue": "^4.2.3", 16 | "typescript": "^5.0.2", 17 | "vite": "^4.4.4", 18 | "vue-tsc": "^1.8.5" 19 | } 20 | }, 21 | "node_modules/@babel/parser": { 22 | "version": "7.23.0", 23 | "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.0.tgz", 24 | "integrity": "sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw==", 25 | "bin": { 26 | "parser": "bin/babel-parser.js" 27 | }, 28 | "engines": { 29 | "node": ">=6.0.0" 30 | } 31 | }, 32 | "node_modules/@esbuild/android-arm": { 33 | "version": "0.18.20", 34 | "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.18.20.tgz", 35 | "integrity": "sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw==", 36 | "cpu": [ 37 | "arm" 38 | ], 39 | "dev": true, 40 | "optional": true, 41 | "os": [ 42 | "android" 43 | ], 44 | "engines": { 45 | "node": ">=12" 46 | } 47 | }, 48 | "node_modules/@esbuild/android-arm64": { 49 | "version": "0.18.20", 50 | "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.18.20.tgz", 51 | "integrity": "sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==", 52 | "cpu": [ 53 | "arm64" 54 | ], 55 | "dev": true, 56 | "optional": true, 57 | "os": [ 58 | "android" 59 | ], 60 | "engines": { 61 | "node": ">=12" 62 | } 63 | }, 64 | "node_modules/@esbuild/android-x64": { 65 | "version": "0.18.20", 66 | "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.18.20.tgz", 67 | "integrity": "sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg==", 68 | "cpu": [ 69 | "x64" 70 | ], 71 | "dev": true, 72 | "optional": true, 73 | "os": [ 74 | "android" 75 | ], 76 | "engines": { 77 | "node": ">=12" 78 | } 79 | }, 80 | "node_modules/@esbuild/darwin-arm64": { 81 | "version": "0.18.20", 82 | "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.18.20.tgz", 83 | "integrity": "sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA==", 84 | "cpu": [ 85 | "arm64" 86 | ], 87 | "dev": true, 88 | "optional": true, 89 | "os": [ 90 | "darwin" 91 | ], 92 | "engines": { 93 | "node": ">=12" 94 | } 95 | }, 96 | "node_modules/@esbuild/darwin-x64": { 97 | "version": "0.18.20", 98 | "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.18.20.tgz", 99 | "integrity": "sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ==", 100 | "cpu": [ 101 | "x64" 102 | ], 103 | "dev": true, 104 | "optional": true, 105 | "os": [ 106 | "darwin" 107 | ], 108 | "engines": { 109 | "node": ">=12" 110 | } 111 | }, 112 | "node_modules/@esbuild/freebsd-arm64": { 113 | "version": "0.18.20", 114 | "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.18.20.tgz", 115 | "integrity": "sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw==", 116 | "cpu": [ 117 | "arm64" 118 | ], 119 | "dev": true, 120 | "optional": true, 121 | "os": [ 122 | "freebsd" 123 | ], 124 | "engines": { 125 | "node": ">=12" 126 | } 127 | }, 128 | "node_modules/@esbuild/freebsd-x64": { 129 | "version": "0.18.20", 130 | "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.18.20.tgz", 131 | "integrity": "sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ==", 132 | "cpu": [ 133 | "x64" 134 | ], 135 | "dev": true, 136 | "optional": true, 137 | "os": [ 138 | "freebsd" 139 | ], 140 | "engines": { 141 | "node": ">=12" 142 | } 143 | }, 144 | "node_modules/@esbuild/linux-arm": { 145 | "version": "0.18.20", 146 | "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.18.20.tgz", 147 | "integrity": "sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg==", 148 | "cpu": [ 149 | "arm" 150 | ], 151 | "dev": true, 152 | "optional": true, 153 | "os": [ 154 | "linux" 155 | ], 156 | "engines": { 157 | "node": ">=12" 158 | } 159 | }, 160 | "node_modules/@esbuild/linux-arm64": { 161 | "version": "0.18.20", 162 | "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.18.20.tgz", 163 | "integrity": "sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA==", 164 | "cpu": [ 165 | "arm64" 166 | ], 167 | "dev": true, 168 | "optional": true, 169 | "os": [ 170 | "linux" 171 | ], 172 | "engines": { 173 | "node": ">=12" 174 | } 175 | }, 176 | "node_modules/@esbuild/linux-ia32": { 177 | "version": "0.18.20", 178 | "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.18.20.tgz", 179 | "integrity": "sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA==", 180 | "cpu": [ 181 | "ia32" 182 | ], 183 | "dev": true, 184 | "optional": true, 185 | "os": [ 186 | "linux" 187 | ], 188 | "engines": { 189 | "node": ">=12" 190 | } 191 | }, 192 | "node_modules/@esbuild/linux-loong64": { 193 | "version": "0.18.20", 194 | "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.18.20.tgz", 195 | "integrity": "sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg==", 196 | "cpu": [ 197 | "loong64" 198 | ], 199 | "dev": true, 200 | "optional": true, 201 | "os": [ 202 | "linux" 203 | ], 204 | "engines": { 205 | "node": ">=12" 206 | } 207 | }, 208 | "node_modules/@esbuild/linux-mips64el": { 209 | "version": "0.18.20", 210 | "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.18.20.tgz", 211 | "integrity": "sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ==", 212 | "cpu": [ 213 | "mips64el" 214 | ], 215 | "dev": true, 216 | "optional": true, 217 | "os": [ 218 | "linux" 219 | ], 220 | "engines": { 221 | "node": ">=12" 222 | } 223 | }, 224 | "node_modules/@esbuild/linux-ppc64": { 225 | "version": "0.18.20", 226 | "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.18.20.tgz", 227 | "integrity": "sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA==", 228 | "cpu": [ 229 | "ppc64" 230 | ], 231 | "dev": true, 232 | "optional": true, 233 | "os": [ 234 | "linux" 235 | ], 236 | "engines": { 237 | "node": ">=12" 238 | } 239 | }, 240 | "node_modules/@esbuild/linux-riscv64": { 241 | "version": "0.18.20", 242 | "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.18.20.tgz", 243 | "integrity": "sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A==", 244 | "cpu": [ 245 | "riscv64" 246 | ], 247 | "dev": true, 248 | "optional": true, 249 | "os": [ 250 | "linux" 251 | ], 252 | "engines": { 253 | "node": ">=12" 254 | } 255 | }, 256 | "node_modules/@esbuild/linux-s390x": { 257 | "version": "0.18.20", 258 | "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.18.20.tgz", 259 | "integrity": "sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ==", 260 | "cpu": [ 261 | "s390x" 262 | ], 263 | "dev": true, 264 | "optional": true, 265 | "os": [ 266 | "linux" 267 | ], 268 | "engines": { 269 | "node": ">=12" 270 | } 271 | }, 272 | "node_modules/@esbuild/linux-x64": { 273 | "version": "0.18.20", 274 | "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.18.20.tgz", 275 | "integrity": "sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w==", 276 | "cpu": [ 277 | "x64" 278 | ], 279 | "dev": true, 280 | "optional": true, 281 | "os": [ 282 | "linux" 283 | ], 284 | "engines": { 285 | "node": ">=12" 286 | } 287 | }, 288 | "node_modules/@esbuild/netbsd-x64": { 289 | "version": "0.18.20", 290 | "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.18.20.tgz", 291 | "integrity": "sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A==", 292 | "cpu": [ 293 | "x64" 294 | ], 295 | "dev": true, 296 | "optional": true, 297 | "os": [ 298 | "netbsd" 299 | ], 300 | "engines": { 301 | "node": ">=12" 302 | } 303 | }, 304 | "node_modules/@esbuild/openbsd-x64": { 305 | "version": "0.18.20", 306 | "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.18.20.tgz", 307 | "integrity": "sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg==", 308 | "cpu": [ 309 | "x64" 310 | ], 311 | "dev": true, 312 | "optional": true, 313 | "os": [ 314 | "openbsd" 315 | ], 316 | "engines": { 317 | "node": ">=12" 318 | } 319 | }, 320 | "node_modules/@esbuild/sunos-x64": { 321 | "version": "0.18.20", 322 | "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.18.20.tgz", 323 | "integrity": "sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ==", 324 | "cpu": [ 325 | "x64" 326 | ], 327 | "dev": true, 328 | "optional": true, 329 | "os": [ 330 | "sunos" 331 | ], 332 | "engines": { 333 | "node": ">=12" 334 | } 335 | }, 336 | "node_modules/@esbuild/win32-arm64": { 337 | "version": "0.18.20", 338 | "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.18.20.tgz", 339 | "integrity": "sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg==", 340 | "cpu": [ 341 | "arm64" 342 | ], 343 | "dev": true, 344 | "optional": true, 345 | "os": [ 346 | "win32" 347 | ], 348 | "engines": { 349 | "node": ">=12" 350 | } 351 | }, 352 | "node_modules/@esbuild/win32-ia32": { 353 | "version": "0.18.20", 354 | "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.18.20.tgz", 355 | "integrity": "sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g==", 356 | "cpu": [ 357 | "ia32" 358 | ], 359 | "dev": true, 360 | "optional": true, 361 | "os": [ 362 | "win32" 363 | ], 364 | "engines": { 365 | "node": ">=12" 366 | } 367 | }, 368 | "node_modules/@esbuild/win32-x64": { 369 | "version": "0.18.20", 370 | "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.18.20.tgz", 371 | "integrity": "sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ==", 372 | "cpu": [ 373 | "x64" 374 | ], 375 | "dev": true, 376 | "optional": true, 377 | "os": [ 378 | "win32" 379 | ], 380 | "engines": { 381 | "node": ">=12" 382 | } 383 | }, 384 | "node_modules/@jridgewell/sourcemap-codec": { 385 | "version": "1.4.15", 386 | "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", 387 | "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==" 388 | }, 389 | "node_modules/@tauri-apps/api": { 390 | "version": "1.5.1", 391 | "resolved": "https://registry.npmjs.org/@tauri-apps/api/-/api-1.5.1.tgz", 392 | "integrity": "sha512-6unsZDOdlXTmauU3NhWhn+Cx0rODV+rvNvTdvolE5Kls5ybA6cqndQENDt1+FS0tF7ozCP66jwWoH6a5h90BrA==", 393 | "engines": { 394 | "node": ">= 14.6.0", 395 | "npm": ">= 6.6.0", 396 | "yarn": ">= 1.19.1" 397 | }, 398 | "funding": { 399 | "type": "opencollective", 400 | "url": "https://opencollective.com/tauri" 401 | } 402 | }, 403 | "node_modules/@tauri-apps/cli": { 404 | "version": "1.5.6", 405 | "resolved": "https://registry.npmjs.org/@tauri-apps/cli/-/cli-1.5.6.tgz", 406 | "integrity": "sha512-k4Y19oVCnt7WZb2TnDzLqfs7o98Jq0tUoVMv+JQSzuRDJqaVu2xMBZ8dYplEn+EccdR5SOMyzaLBJWu38TVK1A==", 407 | "dev": true, 408 | "bin": { 409 | "tauri": "tauri.js" 410 | }, 411 | "engines": { 412 | "node": ">= 10" 413 | }, 414 | "funding": { 415 | "type": "opencollective", 416 | "url": "https://opencollective.com/tauri" 417 | }, 418 | "optionalDependencies": { 419 | "@tauri-apps/cli-darwin-arm64": "1.5.6", 420 | "@tauri-apps/cli-darwin-x64": "1.5.6", 421 | "@tauri-apps/cli-linux-arm-gnueabihf": "1.5.6", 422 | "@tauri-apps/cli-linux-arm64-gnu": "1.5.6", 423 | "@tauri-apps/cli-linux-arm64-musl": "1.5.6", 424 | "@tauri-apps/cli-linux-x64-gnu": "1.5.6", 425 | "@tauri-apps/cli-linux-x64-musl": "1.5.6", 426 | "@tauri-apps/cli-win32-arm64-msvc": "1.5.6", 427 | "@tauri-apps/cli-win32-ia32-msvc": "1.5.6", 428 | "@tauri-apps/cli-win32-x64-msvc": "1.5.6" 429 | } 430 | }, 431 | "node_modules/@tauri-apps/cli-darwin-arm64": { 432 | "version": "1.5.6", 433 | "resolved": "https://registry.npmjs.org/@tauri-apps/cli-darwin-arm64/-/cli-darwin-arm64-1.5.6.tgz", 434 | "integrity": "sha512-NNvG3XLtciCMsBahbDNUEvq184VZmOveTGOuy0So2R33b/6FDkuWaSgWZsR1mISpOuP034htQYW0VITCLelfqg==", 435 | "cpu": [ 436 | "arm64" 437 | ], 438 | "dev": true, 439 | "optional": true, 440 | "os": [ 441 | "darwin" 442 | ], 443 | "engines": { 444 | "node": ">= 10" 445 | } 446 | }, 447 | "node_modules/@tauri-apps/cli-darwin-x64": { 448 | "version": "1.5.6", 449 | "resolved": "https://registry.npmjs.org/@tauri-apps/cli-darwin-x64/-/cli-darwin-x64-1.5.6.tgz", 450 | "integrity": "sha512-nkiqmtUQw3N1j4WoVjv81q6zWuZFhBLya/RNGUL94oafORloOZoSY0uTZJAoeieb3Y1YK0rCHSDl02MyV2Fi4A==", 451 | "cpu": [ 452 | "x64" 453 | ], 454 | "dev": true, 455 | "optional": true, 456 | "os": [ 457 | "darwin" 458 | ], 459 | "engines": { 460 | "node": ">= 10" 461 | } 462 | }, 463 | "node_modules/@tauri-apps/cli-linux-arm-gnueabihf": { 464 | "version": "1.5.6", 465 | "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm-gnueabihf/-/cli-linux-arm-gnueabihf-1.5.6.tgz", 466 | "integrity": "sha512-z6SPx+axZexmWXTIVPNs4Tg7FtvdJl9EKxYN6JPjOmDZcqA13iyqWBQal2DA/GMZ1Xqo3vyJf6EoEaKaliymPQ==", 467 | "cpu": [ 468 | "arm" 469 | ], 470 | "dev": true, 471 | "optional": true, 472 | "os": [ 473 | "linux" 474 | ], 475 | "engines": { 476 | "node": ">= 10" 477 | } 478 | }, 479 | "node_modules/@tauri-apps/cli-linux-arm64-gnu": { 480 | "version": "1.5.6", 481 | "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm64-gnu/-/cli-linux-arm64-gnu-1.5.6.tgz", 482 | "integrity": "sha512-QuQjMQmpsCbzBrmtQiG4uhnfAbdFx3nzm+9LtqjuZlurc12+Mj5MTgqQ3AOwQedH3f7C+KlvbqD2AdXpwTg7VA==", 483 | "cpu": [ 484 | "arm64" 485 | ], 486 | "dev": true, 487 | "optional": true, 488 | "os": [ 489 | "linux" 490 | ], 491 | "engines": { 492 | "node": ">= 10" 493 | } 494 | }, 495 | "node_modules/@tauri-apps/cli-linux-arm64-musl": { 496 | "version": "1.5.6", 497 | "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm64-musl/-/cli-linux-arm64-musl-1.5.6.tgz", 498 | "integrity": "sha512-8j5dH3odweFeom7bRGlfzDApWVOT4jIq8/214Wl+JeiNVehouIBo9lZGeghZBH3XKFRwEvU23i7sRVjuh2s8mg==", 499 | "cpu": [ 500 | "arm64" 501 | ], 502 | "dev": true, 503 | "optional": true, 504 | "os": [ 505 | "linux" 506 | ], 507 | "engines": { 508 | "node": ">= 10" 509 | } 510 | }, 511 | "node_modules/@tauri-apps/cli-linux-x64-gnu": { 512 | "version": "1.5.6", 513 | "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-x64-gnu/-/cli-linux-x64-gnu-1.5.6.tgz", 514 | "integrity": "sha512-gbFHYHfdEGW0ffk8SigDsoXks6USpilF6wR0nqB/JbWzbzFR/sBuLVNQlJl1RKNakyJHu+lsFxGy0fcTdoX8xA==", 515 | "cpu": [ 516 | "x64" 517 | ], 518 | "dev": true, 519 | "optional": true, 520 | "os": [ 521 | "linux" 522 | ], 523 | "engines": { 524 | "node": ">= 10" 525 | } 526 | }, 527 | "node_modules/@tauri-apps/cli-linux-x64-musl": { 528 | "version": "1.5.6", 529 | "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-x64-musl/-/cli-linux-x64-musl-1.5.6.tgz", 530 | "integrity": "sha512-9v688ogoLkeFYQNgqiSErfhTreLUd8B3prIBSYUt+x4+5Kcw91zWvIh+VSxL1n3KCGGsM7cuXhkGPaxwlEh1ug==", 531 | "cpu": [ 532 | "x64" 533 | ], 534 | "dev": true, 535 | "optional": true, 536 | "os": [ 537 | "linux" 538 | ], 539 | "engines": { 540 | "node": ">= 10" 541 | } 542 | }, 543 | "node_modules/@tauri-apps/cli-win32-arm64-msvc": { 544 | "version": "1.5.6", 545 | "resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-arm64-msvc/-/cli-win32-arm64-msvc-1.5.6.tgz", 546 | "integrity": "sha512-DRNDXFNZb6y5IZrw+lhTTA9l4wbzO4TNRBAlHAiXUrH+pRFZ/ZJtv5WEuAj9ocVSahVw2NaK5Yaold4NPAxHog==", 547 | "cpu": [ 548 | "arm64" 549 | ], 550 | "dev": true, 551 | "optional": true, 552 | "os": [ 553 | "win32" 554 | ], 555 | "engines": { 556 | "node": ">= 10" 557 | } 558 | }, 559 | "node_modules/@tauri-apps/cli-win32-ia32-msvc": { 560 | "version": "1.5.6", 561 | "resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-ia32-msvc/-/cli-win32-ia32-msvc-1.5.6.tgz", 562 | "integrity": "sha512-oUYKNR/IZjF4fsOzRpw0xesl2lOjhsQEyWlgbpT25T83EU113Xgck9UjtI7xemNI/OPCv1tPiaM1e7/ABdg5iA==", 563 | "cpu": [ 564 | "ia32" 565 | ], 566 | "dev": true, 567 | "optional": true, 568 | "os": [ 569 | "win32" 570 | ], 571 | "engines": { 572 | "node": ">= 10" 573 | } 574 | }, 575 | "node_modules/@tauri-apps/cli-win32-x64-msvc": { 576 | "version": "1.5.6", 577 | "resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-x64-msvc/-/cli-win32-x64-msvc-1.5.6.tgz", 578 | "integrity": "sha512-RmEf1os9C8//uq2hbjXi7Vgz9ne7798ZxqemAZdUwo1pv3oLVZSz1/IvZmUHPdy2e6zSeySqWu1D0Y3QRNN+dg==", 579 | "cpu": [ 580 | "x64" 581 | ], 582 | "dev": true, 583 | "optional": true, 584 | "os": [ 585 | "win32" 586 | ], 587 | "engines": { 588 | "node": ">= 10" 589 | } 590 | }, 591 | "node_modules/@vitejs/plugin-vue": { 592 | "version": "4.4.0", 593 | "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-4.4.0.tgz", 594 | "integrity": "sha512-xdguqb+VUwiRpSg+nsc2HtbAUSGak25DXYvpQQi4RVU1Xq1uworyoH/md9Rfd8zMmPR/pSghr309QNcftUVseg==", 595 | "dev": true, 596 | "engines": { 597 | "node": "^14.18.0 || >=16.0.0" 598 | }, 599 | "peerDependencies": { 600 | "vite": "^4.0.0", 601 | "vue": "^3.2.25" 602 | } 603 | }, 604 | "node_modules/@volar/language-core": { 605 | "version": "1.10.7", 606 | "resolved": "https://registry.npmjs.org/@volar/language-core/-/language-core-1.10.7.tgz", 607 | "integrity": "sha512-6+WI7HGqWCsKJ/bms4V45WP7eDeoGxDtLjYPrHB7QkIWVkRLIeGPzzBoonZz9kERM+Kld3W89Y+IlICejVAKhA==", 608 | "dev": true, 609 | "dependencies": { 610 | "@volar/source-map": "1.10.7" 611 | } 612 | }, 613 | "node_modules/@volar/source-map": { 614 | "version": "1.10.7", 615 | "resolved": "https://registry.npmjs.org/@volar/source-map/-/source-map-1.10.7.tgz", 616 | "integrity": "sha512-anA254XO0lmmeu0p/kvgPOCkrVpqNIHWMvEkPX70PSk4ntg0iBzN/f0Kip6deXvibl6v14Q3Z8RihWrZwdZEEQ==", 617 | "dev": true, 618 | "dependencies": { 619 | "muggle-string": "^0.3.1" 620 | } 621 | }, 622 | "node_modules/@volar/typescript": { 623 | "version": "1.10.7", 624 | "resolved": "https://registry.npmjs.org/@volar/typescript/-/typescript-1.10.7.tgz", 625 | "integrity": "sha512-2hvA3vjXVUn1vOpsP/nWLnE5DUmY6YKQhvDRoZVfBrnWwIo0ySxdTUP4XieXGGgSk43xJaeU1zqQS/3Wfm7QgA==", 626 | "dev": true, 627 | "dependencies": { 628 | "@volar/language-core": "1.10.7", 629 | "path-browserify": "^1.0.1" 630 | } 631 | }, 632 | "node_modules/@vue/compiler-core": { 633 | "version": "3.3.7", 634 | "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.3.7.tgz", 635 | "integrity": "sha512-pACdY6YnTNVLXsB86YD8OF9ihwpolzhhtdLVHhBL6do/ykr6kKXNYABRtNMGrsQXpEXXyAdwvWWkuTbs4MFtPQ==", 636 | "dependencies": { 637 | "@babel/parser": "^7.23.0", 638 | "@vue/shared": "3.3.7", 639 | "estree-walker": "^2.0.2", 640 | "source-map-js": "^1.0.2" 641 | } 642 | }, 643 | "node_modules/@vue/compiler-dom": { 644 | "version": "3.3.7", 645 | "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.3.7.tgz", 646 | "integrity": "sha512-0LwkyJjnUPssXv/d1vNJ0PKfBlDoQs7n81CbO6Q0zdL7H1EzqYRrTVXDqdBVqro0aJjo/FOa1qBAPVI4PGSHBw==", 647 | "dependencies": { 648 | "@vue/compiler-core": "3.3.7", 649 | "@vue/shared": "3.3.7" 650 | } 651 | }, 652 | "node_modules/@vue/compiler-sfc": { 653 | "version": "3.3.7", 654 | "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.3.7.tgz", 655 | "integrity": "sha512-7pfldWy/J75U/ZyYIXRVqvLRw3vmfxDo2YLMwVtWVNew8Sm8d6wodM+OYFq4ll/UxfqVr0XKiVwti32PCrruAw==", 656 | "dependencies": { 657 | "@babel/parser": "^7.23.0", 658 | "@vue/compiler-core": "3.3.7", 659 | "@vue/compiler-dom": "3.3.7", 660 | "@vue/compiler-ssr": "3.3.7", 661 | "@vue/reactivity-transform": "3.3.7", 662 | "@vue/shared": "3.3.7", 663 | "estree-walker": "^2.0.2", 664 | "magic-string": "^0.30.5", 665 | "postcss": "^8.4.31", 666 | "source-map-js": "^1.0.2" 667 | } 668 | }, 669 | "node_modules/@vue/compiler-ssr": { 670 | "version": "3.3.7", 671 | "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.3.7.tgz", 672 | "integrity": "sha512-TxOfNVVeH3zgBc82kcUv+emNHo+vKnlRrkv8YvQU5+Y5LJGJwSNzcmLUoxD/dNzv0bhQ/F0s+InlgV0NrApJZg==", 673 | "dependencies": { 674 | "@vue/compiler-dom": "3.3.7", 675 | "@vue/shared": "3.3.7" 676 | } 677 | }, 678 | "node_modules/@vue/language-core": { 679 | "version": "1.8.22", 680 | "resolved": "https://registry.npmjs.org/@vue/language-core/-/language-core-1.8.22.tgz", 681 | "integrity": "sha512-bsMoJzCrXZqGsxawtUea1cLjUT9dZnDsy5TuZ+l1fxRMzUGQUG9+Ypq4w//CqpWmrx7nIAJpw2JVF/t258miRw==", 682 | "dev": true, 683 | "dependencies": { 684 | "@volar/language-core": "~1.10.5", 685 | "@volar/source-map": "~1.10.5", 686 | "@vue/compiler-dom": "^3.3.0", 687 | "@vue/shared": "^3.3.0", 688 | "computeds": "^0.0.1", 689 | "minimatch": "^9.0.3", 690 | "muggle-string": "^0.3.1", 691 | "vue-template-compiler": "^2.7.14" 692 | }, 693 | "peerDependencies": { 694 | "typescript": "*" 695 | }, 696 | "peerDependenciesMeta": { 697 | "typescript": { 698 | "optional": true 699 | } 700 | } 701 | }, 702 | "node_modules/@vue/reactivity": { 703 | "version": "3.3.7", 704 | "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.3.7.tgz", 705 | "integrity": "sha512-cZNVjWiw00708WqT0zRpyAgduG79dScKEPYJXq2xj/aMtk3SKvL3FBt2QKUlh6EHBJ1m8RhBY+ikBUzwc7/khg==", 706 | "dependencies": { 707 | "@vue/shared": "3.3.7" 708 | } 709 | }, 710 | "node_modules/@vue/reactivity-transform": { 711 | "version": "3.3.7", 712 | "resolved": "https://registry.npmjs.org/@vue/reactivity-transform/-/reactivity-transform-3.3.7.tgz", 713 | "integrity": "sha512-APhRmLVbgE1VPGtoLQoWBJEaQk4V8JUsqrQihImVqKT+8U6Qi3t5ATcg4Y9wGAPb3kIhetpufyZ1RhwbZCIdDA==", 714 | "dependencies": { 715 | "@babel/parser": "^7.23.0", 716 | "@vue/compiler-core": "3.3.7", 717 | "@vue/shared": "3.3.7", 718 | "estree-walker": "^2.0.2", 719 | "magic-string": "^0.30.5" 720 | } 721 | }, 722 | "node_modules/@vue/runtime-core": { 723 | "version": "3.3.7", 724 | "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.3.7.tgz", 725 | "integrity": "sha512-LHq9du3ubLZFdK/BP0Ysy3zhHqRfBn80Uc+T5Hz3maFJBGhci1MafccnL3rpd5/3wVfRHAe6c+PnlO2PAavPTQ==", 726 | "dependencies": { 727 | "@vue/reactivity": "3.3.7", 728 | "@vue/shared": "3.3.7" 729 | } 730 | }, 731 | "node_modules/@vue/runtime-dom": { 732 | "version": "3.3.7", 733 | "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.3.7.tgz", 734 | "integrity": "sha512-PFQU1oeJxikdDmrfoNQay5nD4tcPNYixUBruZzVX/l0eyZvFKElZUjW4KctCcs52nnpMGO6UDK+jF5oV4GT5Lw==", 735 | "dependencies": { 736 | "@vue/runtime-core": "3.3.7", 737 | "@vue/shared": "3.3.7", 738 | "csstype": "^3.1.2" 739 | } 740 | }, 741 | "node_modules/@vue/server-renderer": { 742 | "version": "3.3.7", 743 | "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.3.7.tgz", 744 | "integrity": "sha512-UlpKDInd1hIZiNuVVVvLgxpfnSouxKQOSE2bOfQpBuGwxRV/JqqTCyyjXUWiwtVMyeRaZhOYYqntxElk8FhBhw==", 745 | "dependencies": { 746 | "@vue/compiler-ssr": "3.3.7", 747 | "@vue/shared": "3.3.7" 748 | }, 749 | "peerDependencies": { 750 | "vue": "3.3.7" 751 | } 752 | }, 753 | "node_modules/@vue/shared": { 754 | "version": "3.3.7", 755 | "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.3.7.tgz", 756 | "integrity": "sha512-N/tbkINRUDExgcPTBvxNkvHGu504k8lzlNQRITVnm6YjOjwa4r0nnbd4Jb01sNpur5hAllyRJzSK5PvB9PPwRg==" 757 | }, 758 | "node_modules/balanced-match": { 759 | "version": "1.0.2", 760 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", 761 | "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", 762 | "dev": true 763 | }, 764 | "node_modules/brace-expansion": { 765 | "version": "2.0.1", 766 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", 767 | "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", 768 | "dev": true, 769 | "dependencies": { 770 | "balanced-match": "^1.0.0" 771 | } 772 | }, 773 | "node_modules/computeds": { 774 | "version": "0.0.1", 775 | "resolved": "https://registry.npmjs.org/computeds/-/computeds-0.0.1.tgz", 776 | "integrity": "sha512-7CEBgcMjVmitjYo5q8JTJVra6X5mQ20uTThdK+0kR7UEaDrAWEQcRiBtWJzga4eRpP6afNwwLsX2SET2JhVB1Q==", 777 | "dev": true 778 | }, 779 | "node_modules/csstype": { 780 | "version": "3.1.2", 781 | "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.2.tgz", 782 | "integrity": "sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==" 783 | }, 784 | "node_modules/de-indent": { 785 | "version": "1.0.2", 786 | "resolved": "https://registry.npmjs.org/de-indent/-/de-indent-1.0.2.tgz", 787 | "integrity": "sha512-e/1zu3xH5MQryN2zdVaF0OrdNLUbvWxzMbi+iNA6Bky7l1RoP8a2fIbRocyHclXt/arDrrR6lL3TqFD9pMQTsg==", 788 | "dev": true 789 | }, 790 | "node_modules/esbuild": { 791 | "version": "0.18.20", 792 | "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.18.20.tgz", 793 | "integrity": "sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==", 794 | "dev": true, 795 | "hasInstallScript": true, 796 | "bin": { 797 | "esbuild": "bin/esbuild" 798 | }, 799 | "engines": { 800 | "node": ">=12" 801 | }, 802 | "optionalDependencies": { 803 | "@esbuild/android-arm": "0.18.20", 804 | "@esbuild/android-arm64": "0.18.20", 805 | "@esbuild/android-x64": "0.18.20", 806 | "@esbuild/darwin-arm64": "0.18.20", 807 | "@esbuild/darwin-x64": "0.18.20", 808 | "@esbuild/freebsd-arm64": "0.18.20", 809 | "@esbuild/freebsd-x64": "0.18.20", 810 | "@esbuild/linux-arm": "0.18.20", 811 | "@esbuild/linux-arm64": "0.18.20", 812 | "@esbuild/linux-ia32": "0.18.20", 813 | "@esbuild/linux-loong64": "0.18.20", 814 | "@esbuild/linux-mips64el": "0.18.20", 815 | "@esbuild/linux-ppc64": "0.18.20", 816 | "@esbuild/linux-riscv64": "0.18.20", 817 | "@esbuild/linux-s390x": "0.18.20", 818 | "@esbuild/linux-x64": "0.18.20", 819 | "@esbuild/netbsd-x64": "0.18.20", 820 | "@esbuild/openbsd-x64": "0.18.20", 821 | "@esbuild/sunos-x64": "0.18.20", 822 | "@esbuild/win32-arm64": "0.18.20", 823 | "@esbuild/win32-ia32": "0.18.20", 824 | "@esbuild/win32-x64": "0.18.20" 825 | } 826 | }, 827 | "node_modules/estree-walker": { 828 | "version": "2.0.2", 829 | "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", 830 | "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==" 831 | }, 832 | "node_modules/fsevents": { 833 | "version": "2.3.3", 834 | "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", 835 | "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", 836 | "dev": true, 837 | "hasInstallScript": true, 838 | "optional": true, 839 | "os": [ 840 | "darwin" 841 | ], 842 | "engines": { 843 | "node": "^8.16.0 || ^10.6.0 || >=11.0.0" 844 | } 845 | }, 846 | "node_modules/he": { 847 | "version": "1.2.0", 848 | "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", 849 | "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", 850 | "dev": true, 851 | "bin": { 852 | "he": "bin/he" 853 | } 854 | }, 855 | "node_modules/lru-cache": { 856 | "version": "6.0.0", 857 | "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", 858 | "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", 859 | "dev": true, 860 | "dependencies": { 861 | "yallist": "^4.0.0" 862 | }, 863 | "engines": { 864 | "node": ">=10" 865 | } 866 | }, 867 | "node_modules/magic-string": { 868 | "version": "0.30.5", 869 | "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.5.tgz", 870 | "integrity": "sha512-7xlpfBaQaP/T6Vh8MO/EqXSW5En6INHEvEXQiuff7Gku0PWjU3uf6w/j9o7O+SpB5fOAkrI5HeoNgwjEO0pFsA==", 871 | "dependencies": { 872 | "@jridgewell/sourcemap-codec": "^1.4.15" 873 | }, 874 | "engines": { 875 | "node": ">=12" 876 | } 877 | }, 878 | "node_modules/minimatch": { 879 | "version": "9.0.3", 880 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", 881 | "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", 882 | "dev": true, 883 | "dependencies": { 884 | "brace-expansion": "^2.0.1" 885 | }, 886 | "engines": { 887 | "node": ">=16 || 14 >=14.17" 888 | }, 889 | "funding": { 890 | "url": "https://github.com/sponsors/isaacs" 891 | } 892 | }, 893 | "node_modules/muggle-string": { 894 | "version": "0.3.1", 895 | "resolved": "https://registry.npmjs.org/muggle-string/-/muggle-string-0.3.1.tgz", 896 | "integrity": "sha512-ckmWDJjphvd/FvZawgygcUeQCxzvohjFO5RxTjj4eq8kw359gFF3E1brjfI+viLMxss5JrHTDRHZvu2/tuy0Qg==", 897 | "dev": true 898 | }, 899 | "node_modules/nanoid": { 900 | "version": "3.3.6", 901 | "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz", 902 | "integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==", 903 | "funding": [ 904 | { 905 | "type": "github", 906 | "url": "https://github.com/sponsors/ai" 907 | } 908 | ], 909 | "bin": { 910 | "nanoid": "bin/nanoid.cjs" 911 | }, 912 | "engines": { 913 | "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" 914 | } 915 | }, 916 | "node_modules/path-browserify": { 917 | "version": "1.0.1", 918 | "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz", 919 | "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==", 920 | "dev": true 921 | }, 922 | "node_modules/picocolors": { 923 | "version": "1.0.0", 924 | "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", 925 | "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" 926 | }, 927 | "node_modules/postcss": { 928 | "version": "8.4.31", 929 | "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", 930 | "integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==", 931 | "funding": [ 932 | { 933 | "type": "opencollective", 934 | "url": "https://opencollective.com/postcss/" 935 | }, 936 | { 937 | "type": "tidelift", 938 | "url": "https://tidelift.com/funding/github/npm/postcss" 939 | }, 940 | { 941 | "type": "github", 942 | "url": "https://github.com/sponsors/ai" 943 | } 944 | ], 945 | "dependencies": { 946 | "nanoid": "^3.3.6", 947 | "picocolors": "^1.0.0", 948 | "source-map-js": "^1.0.2" 949 | }, 950 | "engines": { 951 | "node": "^10 || ^12 || >=14" 952 | } 953 | }, 954 | "node_modules/rollup": { 955 | "version": "3.29.4", 956 | "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.29.4.tgz", 957 | "integrity": "sha512-oWzmBZwvYrU0iJHtDmhsm662rC15FRXmcjCk1xD771dFDx5jJ02ufAQQTn0etB2emNk4J9EZg/yWKpsn9BWGRw==", 958 | "dev": true, 959 | "bin": { 960 | "rollup": "dist/bin/rollup" 961 | }, 962 | "engines": { 963 | "node": ">=14.18.0", 964 | "npm": ">=8.0.0" 965 | }, 966 | "optionalDependencies": { 967 | "fsevents": "~2.3.2" 968 | } 969 | }, 970 | "node_modules/semver": { 971 | "version": "7.5.4", 972 | "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", 973 | "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", 974 | "dev": true, 975 | "dependencies": { 976 | "lru-cache": "^6.0.0" 977 | }, 978 | "bin": { 979 | "semver": "bin/semver.js" 980 | }, 981 | "engines": { 982 | "node": ">=10" 983 | } 984 | }, 985 | "node_modules/source-map-js": { 986 | "version": "1.0.2", 987 | "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", 988 | "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", 989 | "engines": { 990 | "node": ">=0.10.0" 991 | } 992 | }, 993 | "node_modules/typescript": { 994 | "version": "5.2.2", 995 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz", 996 | "integrity": "sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==", 997 | "devOptional": true, 998 | "bin": { 999 | "tsc": "bin/tsc", 1000 | "tsserver": "bin/tsserver" 1001 | }, 1002 | "engines": { 1003 | "node": ">=14.17" 1004 | } 1005 | }, 1006 | "node_modules/vite": { 1007 | "version": "4.5.0", 1008 | "resolved": "https://registry.npmjs.org/vite/-/vite-4.5.0.tgz", 1009 | "integrity": "sha512-ulr8rNLA6rkyFAlVWw2q5YJ91v098AFQ2R0PRFwPzREXOUJQPtFUG0t+/ZikhaOCDqFoDhN6/v8Sq0o4araFAw==", 1010 | "dev": true, 1011 | "dependencies": { 1012 | "esbuild": "^0.18.10", 1013 | "postcss": "^8.4.27", 1014 | "rollup": "^3.27.1" 1015 | }, 1016 | "bin": { 1017 | "vite": "bin/vite.js" 1018 | }, 1019 | "engines": { 1020 | "node": "^14.18.0 || >=16.0.0" 1021 | }, 1022 | "funding": { 1023 | "url": "https://github.com/vitejs/vite?sponsor=1" 1024 | }, 1025 | "optionalDependencies": { 1026 | "fsevents": "~2.3.2" 1027 | }, 1028 | "peerDependencies": { 1029 | "@types/node": ">= 14", 1030 | "less": "*", 1031 | "lightningcss": "^1.21.0", 1032 | "sass": "*", 1033 | "stylus": "*", 1034 | "sugarss": "*", 1035 | "terser": "^5.4.0" 1036 | }, 1037 | "peerDependenciesMeta": { 1038 | "@types/node": { 1039 | "optional": true 1040 | }, 1041 | "less": { 1042 | "optional": true 1043 | }, 1044 | "lightningcss": { 1045 | "optional": true 1046 | }, 1047 | "sass": { 1048 | "optional": true 1049 | }, 1050 | "stylus": { 1051 | "optional": true 1052 | }, 1053 | "sugarss": { 1054 | "optional": true 1055 | }, 1056 | "terser": { 1057 | "optional": true 1058 | } 1059 | } 1060 | }, 1061 | "node_modules/vue": { 1062 | "version": "3.3.7", 1063 | "resolved": "https://registry.npmjs.org/vue/-/vue-3.3.7.tgz", 1064 | "integrity": "sha512-YEMDia1ZTv1TeBbnu6VybatmSteGOS3A3YgfINOfraCbf85wdKHzscD6HSS/vB4GAtI7sa1XPX7HcQaJ1l24zA==", 1065 | "dependencies": { 1066 | "@vue/compiler-dom": "3.3.7", 1067 | "@vue/compiler-sfc": "3.3.7", 1068 | "@vue/runtime-dom": "3.3.7", 1069 | "@vue/server-renderer": "3.3.7", 1070 | "@vue/shared": "3.3.7" 1071 | }, 1072 | "peerDependencies": { 1073 | "typescript": "*" 1074 | }, 1075 | "peerDependenciesMeta": { 1076 | "typescript": { 1077 | "optional": true 1078 | } 1079 | } 1080 | }, 1081 | "node_modules/vue-template-compiler": { 1082 | "version": "2.7.15", 1083 | "resolved": "https://registry.npmjs.org/vue-template-compiler/-/vue-template-compiler-2.7.15.tgz", 1084 | "integrity": "sha512-yQxjxMptBL7UAog00O8sANud99C6wJF+7kgbcwqkvA38vCGF7HWE66w0ZFnS/kX5gSoJr/PQ4/oS3Ne2pW37Og==", 1085 | "dev": true, 1086 | "dependencies": { 1087 | "de-indent": "^1.0.2", 1088 | "he": "^1.2.0" 1089 | } 1090 | }, 1091 | "node_modules/vue-tsc": { 1092 | "version": "1.8.22", 1093 | "resolved": "https://registry.npmjs.org/vue-tsc/-/vue-tsc-1.8.22.tgz", 1094 | "integrity": "sha512-j9P4kHtW6eEE08aS5McFZE/ivmipXy0JzrnTgbomfABMaVKx37kNBw//irL3+LlE3kOo63XpnRigyPC3w7+z+A==", 1095 | "dev": true, 1096 | "dependencies": { 1097 | "@volar/typescript": "~1.10.5", 1098 | "@vue/language-core": "1.8.22", 1099 | "semver": "^7.5.4" 1100 | }, 1101 | "bin": { 1102 | "vue-tsc": "bin/vue-tsc.js" 1103 | }, 1104 | "peerDependencies": { 1105 | "typescript": "*" 1106 | } 1107 | }, 1108 | "node_modules/yallist": { 1109 | "version": "4.0.0", 1110 | "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", 1111 | "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", 1112 | "dev": true 1113 | } 1114 | }, 1115 | "dependencies": { 1116 | "@babel/parser": { 1117 | "version": "7.23.0", 1118 | "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.0.tgz", 1119 | "integrity": "sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw==" 1120 | }, 1121 | "@esbuild/android-arm": { 1122 | "version": "0.18.20", 1123 | "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.18.20.tgz", 1124 | "integrity": "sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw==", 1125 | "dev": true, 1126 | "optional": true 1127 | }, 1128 | "@esbuild/android-arm64": { 1129 | "version": "0.18.20", 1130 | "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.18.20.tgz", 1131 | "integrity": "sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==", 1132 | "dev": true, 1133 | "optional": true 1134 | }, 1135 | "@esbuild/android-x64": { 1136 | "version": "0.18.20", 1137 | "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.18.20.tgz", 1138 | "integrity": "sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg==", 1139 | "dev": true, 1140 | "optional": true 1141 | }, 1142 | "@esbuild/darwin-arm64": { 1143 | "version": "0.18.20", 1144 | "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.18.20.tgz", 1145 | "integrity": "sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA==", 1146 | "dev": true, 1147 | "optional": true 1148 | }, 1149 | "@esbuild/darwin-x64": { 1150 | "version": "0.18.20", 1151 | "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.18.20.tgz", 1152 | "integrity": "sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ==", 1153 | "dev": true, 1154 | "optional": true 1155 | }, 1156 | "@esbuild/freebsd-arm64": { 1157 | "version": "0.18.20", 1158 | "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.18.20.tgz", 1159 | "integrity": "sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw==", 1160 | "dev": true, 1161 | "optional": true 1162 | }, 1163 | "@esbuild/freebsd-x64": { 1164 | "version": "0.18.20", 1165 | "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.18.20.tgz", 1166 | "integrity": "sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ==", 1167 | "dev": true, 1168 | "optional": true 1169 | }, 1170 | "@esbuild/linux-arm": { 1171 | "version": "0.18.20", 1172 | "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.18.20.tgz", 1173 | "integrity": "sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg==", 1174 | "dev": true, 1175 | "optional": true 1176 | }, 1177 | "@esbuild/linux-arm64": { 1178 | "version": "0.18.20", 1179 | "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.18.20.tgz", 1180 | "integrity": "sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA==", 1181 | "dev": true, 1182 | "optional": true 1183 | }, 1184 | "@esbuild/linux-ia32": { 1185 | "version": "0.18.20", 1186 | "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.18.20.tgz", 1187 | "integrity": "sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA==", 1188 | "dev": true, 1189 | "optional": true 1190 | }, 1191 | "@esbuild/linux-loong64": { 1192 | "version": "0.18.20", 1193 | "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.18.20.tgz", 1194 | "integrity": "sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg==", 1195 | "dev": true, 1196 | "optional": true 1197 | }, 1198 | "@esbuild/linux-mips64el": { 1199 | "version": "0.18.20", 1200 | "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.18.20.tgz", 1201 | "integrity": "sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ==", 1202 | "dev": true, 1203 | "optional": true 1204 | }, 1205 | "@esbuild/linux-ppc64": { 1206 | "version": "0.18.20", 1207 | "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.18.20.tgz", 1208 | "integrity": "sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA==", 1209 | "dev": true, 1210 | "optional": true 1211 | }, 1212 | "@esbuild/linux-riscv64": { 1213 | "version": "0.18.20", 1214 | "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.18.20.tgz", 1215 | "integrity": "sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A==", 1216 | "dev": true, 1217 | "optional": true 1218 | }, 1219 | "@esbuild/linux-s390x": { 1220 | "version": "0.18.20", 1221 | "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.18.20.tgz", 1222 | "integrity": "sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ==", 1223 | "dev": true, 1224 | "optional": true 1225 | }, 1226 | "@esbuild/linux-x64": { 1227 | "version": "0.18.20", 1228 | "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.18.20.tgz", 1229 | "integrity": "sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w==", 1230 | "dev": true, 1231 | "optional": true 1232 | }, 1233 | "@esbuild/netbsd-x64": { 1234 | "version": "0.18.20", 1235 | "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.18.20.tgz", 1236 | "integrity": "sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A==", 1237 | "dev": true, 1238 | "optional": true 1239 | }, 1240 | "@esbuild/openbsd-x64": { 1241 | "version": "0.18.20", 1242 | "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.18.20.tgz", 1243 | "integrity": "sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg==", 1244 | "dev": true, 1245 | "optional": true 1246 | }, 1247 | "@esbuild/sunos-x64": { 1248 | "version": "0.18.20", 1249 | "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.18.20.tgz", 1250 | "integrity": "sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ==", 1251 | "dev": true, 1252 | "optional": true 1253 | }, 1254 | "@esbuild/win32-arm64": { 1255 | "version": "0.18.20", 1256 | "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.18.20.tgz", 1257 | "integrity": "sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg==", 1258 | "dev": true, 1259 | "optional": true 1260 | }, 1261 | "@esbuild/win32-ia32": { 1262 | "version": "0.18.20", 1263 | "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.18.20.tgz", 1264 | "integrity": "sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g==", 1265 | "dev": true, 1266 | "optional": true 1267 | }, 1268 | "@esbuild/win32-x64": { 1269 | "version": "0.18.20", 1270 | "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.18.20.tgz", 1271 | "integrity": "sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ==", 1272 | "dev": true, 1273 | "optional": true 1274 | }, 1275 | "@jridgewell/sourcemap-codec": { 1276 | "version": "1.4.15", 1277 | "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", 1278 | "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==" 1279 | }, 1280 | "@tauri-apps/api": { 1281 | "version": "1.5.1", 1282 | "resolved": "https://registry.npmjs.org/@tauri-apps/api/-/api-1.5.1.tgz", 1283 | "integrity": "sha512-6unsZDOdlXTmauU3NhWhn+Cx0rODV+rvNvTdvolE5Kls5ybA6cqndQENDt1+FS0tF7ozCP66jwWoH6a5h90BrA==" 1284 | }, 1285 | "@tauri-apps/cli": { 1286 | "version": "1.5.6", 1287 | "resolved": "https://registry.npmjs.org/@tauri-apps/cli/-/cli-1.5.6.tgz", 1288 | "integrity": "sha512-k4Y19oVCnt7WZb2TnDzLqfs7o98Jq0tUoVMv+JQSzuRDJqaVu2xMBZ8dYplEn+EccdR5SOMyzaLBJWu38TVK1A==", 1289 | "dev": true, 1290 | "requires": { 1291 | "@tauri-apps/cli-darwin-arm64": "1.5.6", 1292 | "@tauri-apps/cli-darwin-x64": "1.5.6", 1293 | "@tauri-apps/cli-linux-arm-gnueabihf": "1.5.6", 1294 | "@tauri-apps/cli-linux-arm64-gnu": "1.5.6", 1295 | "@tauri-apps/cli-linux-arm64-musl": "1.5.6", 1296 | "@tauri-apps/cli-linux-x64-gnu": "1.5.6", 1297 | "@tauri-apps/cli-linux-x64-musl": "1.5.6", 1298 | "@tauri-apps/cli-win32-arm64-msvc": "1.5.6", 1299 | "@tauri-apps/cli-win32-ia32-msvc": "1.5.6", 1300 | "@tauri-apps/cli-win32-x64-msvc": "1.5.6" 1301 | } 1302 | }, 1303 | "@tauri-apps/cli-darwin-arm64": { 1304 | "version": "1.5.6", 1305 | "resolved": "https://registry.npmjs.org/@tauri-apps/cli-darwin-arm64/-/cli-darwin-arm64-1.5.6.tgz", 1306 | "integrity": "sha512-NNvG3XLtciCMsBahbDNUEvq184VZmOveTGOuy0So2R33b/6FDkuWaSgWZsR1mISpOuP034htQYW0VITCLelfqg==", 1307 | "dev": true, 1308 | "optional": true 1309 | }, 1310 | "@tauri-apps/cli-darwin-x64": { 1311 | "version": "1.5.6", 1312 | "resolved": "https://registry.npmjs.org/@tauri-apps/cli-darwin-x64/-/cli-darwin-x64-1.5.6.tgz", 1313 | "integrity": "sha512-nkiqmtUQw3N1j4WoVjv81q6zWuZFhBLya/RNGUL94oafORloOZoSY0uTZJAoeieb3Y1YK0rCHSDl02MyV2Fi4A==", 1314 | "dev": true, 1315 | "optional": true 1316 | }, 1317 | "@tauri-apps/cli-linux-arm-gnueabihf": { 1318 | "version": "1.5.6", 1319 | "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm-gnueabihf/-/cli-linux-arm-gnueabihf-1.5.6.tgz", 1320 | "integrity": "sha512-z6SPx+axZexmWXTIVPNs4Tg7FtvdJl9EKxYN6JPjOmDZcqA13iyqWBQal2DA/GMZ1Xqo3vyJf6EoEaKaliymPQ==", 1321 | "dev": true, 1322 | "optional": true 1323 | }, 1324 | "@tauri-apps/cli-linux-arm64-gnu": { 1325 | "version": "1.5.6", 1326 | "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm64-gnu/-/cli-linux-arm64-gnu-1.5.6.tgz", 1327 | "integrity": "sha512-QuQjMQmpsCbzBrmtQiG4uhnfAbdFx3nzm+9LtqjuZlurc12+Mj5MTgqQ3AOwQedH3f7C+KlvbqD2AdXpwTg7VA==", 1328 | "dev": true, 1329 | "optional": true 1330 | }, 1331 | "@tauri-apps/cli-linux-arm64-musl": { 1332 | "version": "1.5.6", 1333 | "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm64-musl/-/cli-linux-arm64-musl-1.5.6.tgz", 1334 | "integrity": "sha512-8j5dH3odweFeom7bRGlfzDApWVOT4jIq8/214Wl+JeiNVehouIBo9lZGeghZBH3XKFRwEvU23i7sRVjuh2s8mg==", 1335 | "dev": true, 1336 | "optional": true 1337 | }, 1338 | "@tauri-apps/cli-linux-x64-gnu": { 1339 | "version": "1.5.6", 1340 | "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-x64-gnu/-/cli-linux-x64-gnu-1.5.6.tgz", 1341 | "integrity": "sha512-gbFHYHfdEGW0ffk8SigDsoXks6USpilF6wR0nqB/JbWzbzFR/sBuLVNQlJl1RKNakyJHu+lsFxGy0fcTdoX8xA==", 1342 | "dev": true, 1343 | "optional": true 1344 | }, 1345 | "@tauri-apps/cli-linux-x64-musl": { 1346 | "version": "1.5.6", 1347 | "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-x64-musl/-/cli-linux-x64-musl-1.5.6.tgz", 1348 | "integrity": "sha512-9v688ogoLkeFYQNgqiSErfhTreLUd8B3prIBSYUt+x4+5Kcw91zWvIh+VSxL1n3KCGGsM7cuXhkGPaxwlEh1ug==", 1349 | "dev": true, 1350 | "optional": true 1351 | }, 1352 | "@tauri-apps/cli-win32-arm64-msvc": { 1353 | "version": "1.5.6", 1354 | "resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-arm64-msvc/-/cli-win32-arm64-msvc-1.5.6.tgz", 1355 | "integrity": "sha512-DRNDXFNZb6y5IZrw+lhTTA9l4wbzO4TNRBAlHAiXUrH+pRFZ/ZJtv5WEuAj9ocVSahVw2NaK5Yaold4NPAxHog==", 1356 | "dev": true, 1357 | "optional": true 1358 | }, 1359 | "@tauri-apps/cli-win32-ia32-msvc": { 1360 | "version": "1.5.6", 1361 | "resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-ia32-msvc/-/cli-win32-ia32-msvc-1.5.6.tgz", 1362 | "integrity": "sha512-oUYKNR/IZjF4fsOzRpw0xesl2lOjhsQEyWlgbpT25T83EU113Xgck9UjtI7xemNI/OPCv1tPiaM1e7/ABdg5iA==", 1363 | "dev": true, 1364 | "optional": true 1365 | }, 1366 | "@tauri-apps/cli-win32-x64-msvc": { 1367 | "version": "1.5.6", 1368 | "resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-x64-msvc/-/cli-win32-x64-msvc-1.5.6.tgz", 1369 | "integrity": "sha512-RmEf1os9C8//uq2hbjXi7Vgz9ne7798ZxqemAZdUwo1pv3oLVZSz1/IvZmUHPdy2e6zSeySqWu1D0Y3QRNN+dg==", 1370 | "dev": true, 1371 | "optional": true 1372 | }, 1373 | "@vitejs/plugin-vue": { 1374 | "version": "4.4.0", 1375 | "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-4.4.0.tgz", 1376 | "integrity": "sha512-xdguqb+VUwiRpSg+nsc2HtbAUSGak25DXYvpQQi4RVU1Xq1uworyoH/md9Rfd8zMmPR/pSghr309QNcftUVseg==", 1377 | "dev": true, 1378 | "requires": {} 1379 | }, 1380 | "@volar/language-core": { 1381 | "version": "1.10.7", 1382 | "resolved": "https://registry.npmjs.org/@volar/language-core/-/language-core-1.10.7.tgz", 1383 | "integrity": "sha512-6+WI7HGqWCsKJ/bms4V45WP7eDeoGxDtLjYPrHB7QkIWVkRLIeGPzzBoonZz9kERM+Kld3W89Y+IlICejVAKhA==", 1384 | "dev": true, 1385 | "requires": { 1386 | "@volar/source-map": "1.10.7" 1387 | } 1388 | }, 1389 | "@volar/source-map": { 1390 | "version": "1.10.7", 1391 | "resolved": "https://registry.npmjs.org/@volar/source-map/-/source-map-1.10.7.tgz", 1392 | "integrity": "sha512-anA254XO0lmmeu0p/kvgPOCkrVpqNIHWMvEkPX70PSk4ntg0iBzN/f0Kip6deXvibl6v14Q3Z8RihWrZwdZEEQ==", 1393 | "dev": true, 1394 | "requires": { 1395 | "muggle-string": "^0.3.1" 1396 | } 1397 | }, 1398 | "@volar/typescript": { 1399 | "version": "1.10.7", 1400 | "resolved": "https://registry.npmjs.org/@volar/typescript/-/typescript-1.10.7.tgz", 1401 | "integrity": "sha512-2hvA3vjXVUn1vOpsP/nWLnE5DUmY6YKQhvDRoZVfBrnWwIo0ySxdTUP4XieXGGgSk43xJaeU1zqQS/3Wfm7QgA==", 1402 | "dev": true, 1403 | "requires": { 1404 | "@volar/language-core": "1.10.7", 1405 | "path-browserify": "^1.0.1" 1406 | } 1407 | }, 1408 | "@vue/compiler-core": { 1409 | "version": "3.3.7", 1410 | "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.3.7.tgz", 1411 | "integrity": "sha512-pACdY6YnTNVLXsB86YD8OF9ihwpolzhhtdLVHhBL6do/ykr6kKXNYABRtNMGrsQXpEXXyAdwvWWkuTbs4MFtPQ==", 1412 | "requires": { 1413 | "@babel/parser": "^7.23.0", 1414 | "@vue/shared": "3.3.7", 1415 | "estree-walker": "^2.0.2", 1416 | "source-map-js": "^1.0.2" 1417 | } 1418 | }, 1419 | "@vue/compiler-dom": { 1420 | "version": "3.3.7", 1421 | "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.3.7.tgz", 1422 | "integrity": "sha512-0LwkyJjnUPssXv/d1vNJ0PKfBlDoQs7n81CbO6Q0zdL7H1EzqYRrTVXDqdBVqro0aJjo/FOa1qBAPVI4PGSHBw==", 1423 | "requires": { 1424 | "@vue/compiler-core": "3.3.7", 1425 | "@vue/shared": "3.3.7" 1426 | } 1427 | }, 1428 | "@vue/compiler-sfc": { 1429 | "version": "3.3.7", 1430 | "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.3.7.tgz", 1431 | "integrity": "sha512-7pfldWy/J75U/ZyYIXRVqvLRw3vmfxDo2YLMwVtWVNew8Sm8d6wodM+OYFq4ll/UxfqVr0XKiVwti32PCrruAw==", 1432 | "requires": { 1433 | "@babel/parser": "^7.23.0", 1434 | "@vue/compiler-core": "3.3.7", 1435 | "@vue/compiler-dom": "3.3.7", 1436 | "@vue/compiler-ssr": "3.3.7", 1437 | "@vue/reactivity-transform": "3.3.7", 1438 | "@vue/shared": "3.3.7", 1439 | "estree-walker": "^2.0.2", 1440 | "magic-string": "^0.30.5", 1441 | "postcss": "^8.4.31", 1442 | "source-map-js": "^1.0.2" 1443 | } 1444 | }, 1445 | "@vue/compiler-ssr": { 1446 | "version": "3.3.7", 1447 | "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.3.7.tgz", 1448 | "integrity": "sha512-TxOfNVVeH3zgBc82kcUv+emNHo+vKnlRrkv8YvQU5+Y5LJGJwSNzcmLUoxD/dNzv0bhQ/F0s+InlgV0NrApJZg==", 1449 | "requires": { 1450 | "@vue/compiler-dom": "3.3.7", 1451 | "@vue/shared": "3.3.7" 1452 | } 1453 | }, 1454 | "@vue/language-core": { 1455 | "version": "1.8.22", 1456 | "resolved": "https://registry.npmjs.org/@vue/language-core/-/language-core-1.8.22.tgz", 1457 | "integrity": "sha512-bsMoJzCrXZqGsxawtUea1cLjUT9dZnDsy5TuZ+l1fxRMzUGQUG9+Ypq4w//CqpWmrx7nIAJpw2JVF/t258miRw==", 1458 | "dev": true, 1459 | "requires": { 1460 | "@volar/language-core": "~1.10.5", 1461 | "@volar/source-map": "~1.10.5", 1462 | "@vue/compiler-dom": "^3.3.0", 1463 | "@vue/shared": "^3.3.0", 1464 | "computeds": "^0.0.1", 1465 | "minimatch": "^9.0.3", 1466 | "muggle-string": "^0.3.1", 1467 | "vue-template-compiler": "^2.7.14" 1468 | } 1469 | }, 1470 | "@vue/reactivity": { 1471 | "version": "3.3.7", 1472 | "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.3.7.tgz", 1473 | "integrity": "sha512-cZNVjWiw00708WqT0zRpyAgduG79dScKEPYJXq2xj/aMtk3SKvL3FBt2QKUlh6EHBJ1m8RhBY+ikBUzwc7/khg==", 1474 | "requires": { 1475 | "@vue/shared": "3.3.7" 1476 | } 1477 | }, 1478 | "@vue/reactivity-transform": { 1479 | "version": "3.3.7", 1480 | "resolved": "https://registry.npmjs.org/@vue/reactivity-transform/-/reactivity-transform-3.3.7.tgz", 1481 | "integrity": "sha512-APhRmLVbgE1VPGtoLQoWBJEaQk4V8JUsqrQihImVqKT+8U6Qi3t5ATcg4Y9wGAPb3kIhetpufyZ1RhwbZCIdDA==", 1482 | "requires": { 1483 | "@babel/parser": "^7.23.0", 1484 | "@vue/compiler-core": "3.3.7", 1485 | "@vue/shared": "3.3.7", 1486 | "estree-walker": "^2.0.2", 1487 | "magic-string": "^0.30.5" 1488 | } 1489 | }, 1490 | "@vue/runtime-core": { 1491 | "version": "3.3.7", 1492 | "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.3.7.tgz", 1493 | "integrity": "sha512-LHq9du3ubLZFdK/BP0Ysy3zhHqRfBn80Uc+T5Hz3maFJBGhci1MafccnL3rpd5/3wVfRHAe6c+PnlO2PAavPTQ==", 1494 | "requires": { 1495 | "@vue/reactivity": "3.3.7", 1496 | "@vue/shared": "3.3.7" 1497 | } 1498 | }, 1499 | "@vue/runtime-dom": { 1500 | "version": "3.3.7", 1501 | "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.3.7.tgz", 1502 | "integrity": "sha512-PFQU1oeJxikdDmrfoNQay5nD4tcPNYixUBruZzVX/l0eyZvFKElZUjW4KctCcs52nnpMGO6UDK+jF5oV4GT5Lw==", 1503 | "requires": { 1504 | "@vue/runtime-core": "3.3.7", 1505 | "@vue/shared": "3.3.7", 1506 | "csstype": "^3.1.2" 1507 | } 1508 | }, 1509 | "@vue/server-renderer": { 1510 | "version": "3.3.7", 1511 | "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.3.7.tgz", 1512 | "integrity": "sha512-UlpKDInd1hIZiNuVVVvLgxpfnSouxKQOSE2bOfQpBuGwxRV/JqqTCyyjXUWiwtVMyeRaZhOYYqntxElk8FhBhw==", 1513 | "requires": { 1514 | "@vue/compiler-ssr": "3.3.7", 1515 | "@vue/shared": "3.3.7" 1516 | } 1517 | }, 1518 | "@vue/shared": { 1519 | "version": "3.3.7", 1520 | "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.3.7.tgz", 1521 | "integrity": "sha512-N/tbkINRUDExgcPTBvxNkvHGu504k8lzlNQRITVnm6YjOjwa4r0nnbd4Jb01sNpur5hAllyRJzSK5PvB9PPwRg==" 1522 | }, 1523 | "balanced-match": { 1524 | "version": "1.0.2", 1525 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", 1526 | "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", 1527 | "dev": true 1528 | }, 1529 | "brace-expansion": { 1530 | "version": "2.0.1", 1531 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", 1532 | "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", 1533 | "dev": true, 1534 | "requires": { 1535 | "balanced-match": "^1.0.0" 1536 | } 1537 | }, 1538 | "computeds": { 1539 | "version": "0.0.1", 1540 | "resolved": "https://registry.npmjs.org/computeds/-/computeds-0.0.1.tgz", 1541 | "integrity": "sha512-7CEBgcMjVmitjYo5q8JTJVra6X5mQ20uTThdK+0kR7UEaDrAWEQcRiBtWJzga4eRpP6afNwwLsX2SET2JhVB1Q==", 1542 | "dev": true 1543 | }, 1544 | "csstype": { 1545 | "version": "3.1.2", 1546 | "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.2.tgz", 1547 | "integrity": "sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==" 1548 | }, 1549 | "de-indent": { 1550 | "version": "1.0.2", 1551 | "resolved": "https://registry.npmjs.org/de-indent/-/de-indent-1.0.2.tgz", 1552 | "integrity": "sha512-e/1zu3xH5MQryN2zdVaF0OrdNLUbvWxzMbi+iNA6Bky7l1RoP8a2fIbRocyHclXt/arDrrR6lL3TqFD9pMQTsg==", 1553 | "dev": true 1554 | }, 1555 | "esbuild": { 1556 | "version": "0.18.20", 1557 | "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.18.20.tgz", 1558 | "integrity": "sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==", 1559 | "dev": true, 1560 | "requires": { 1561 | "@esbuild/android-arm": "0.18.20", 1562 | "@esbuild/android-arm64": "0.18.20", 1563 | "@esbuild/android-x64": "0.18.20", 1564 | "@esbuild/darwin-arm64": "0.18.20", 1565 | "@esbuild/darwin-x64": "0.18.20", 1566 | "@esbuild/freebsd-arm64": "0.18.20", 1567 | "@esbuild/freebsd-x64": "0.18.20", 1568 | "@esbuild/linux-arm": "0.18.20", 1569 | "@esbuild/linux-arm64": "0.18.20", 1570 | "@esbuild/linux-ia32": "0.18.20", 1571 | "@esbuild/linux-loong64": "0.18.20", 1572 | "@esbuild/linux-mips64el": "0.18.20", 1573 | "@esbuild/linux-ppc64": "0.18.20", 1574 | "@esbuild/linux-riscv64": "0.18.20", 1575 | "@esbuild/linux-s390x": "0.18.20", 1576 | "@esbuild/linux-x64": "0.18.20", 1577 | "@esbuild/netbsd-x64": "0.18.20", 1578 | "@esbuild/openbsd-x64": "0.18.20", 1579 | "@esbuild/sunos-x64": "0.18.20", 1580 | "@esbuild/win32-arm64": "0.18.20", 1581 | "@esbuild/win32-ia32": "0.18.20", 1582 | "@esbuild/win32-x64": "0.18.20" 1583 | } 1584 | }, 1585 | "estree-walker": { 1586 | "version": "2.0.2", 1587 | "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", 1588 | "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==" 1589 | }, 1590 | "fsevents": { 1591 | "version": "2.3.3", 1592 | "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", 1593 | "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", 1594 | "dev": true, 1595 | "optional": true 1596 | }, 1597 | "he": { 1598 | "version": "1.2.0", 1599 | "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", 1600 | "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", 1601 | "dev": true 1602 | }, 1603 | "lru-cache": { 1604 | "version": "6.0.0", 1605 | "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", 1606 | "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", 1607 | "dev": true, 1608 | "requires": { 1609 | "yallist": "^4.0.0" 1610 | } 1611 | }, 1612 | "magic-string": { 1613 | "version": "0.30.5", 1614 | "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.5.tgz", 1615 | "integrity": "sha512-7xlpfBaQaP/T6Vh8MO/EqXSW5En6INHEvEXQiuff7Gku0PWjU3uf6w/j9o7O+SpB5fOAkrI5HeoNgwjEO0pFsA==", 1616 | "requires": { 1617 | "@jridgewell/sourcemap-codec": "^1.4.15" 1618 | } 1619 | }, 1620 | "minimatch": { 1621 | "version": "9.0.3", 1622 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", 1623 | "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", 1624 | "dev": true, 1625 | "requires": { 1626 | "brace-expansion": "^2.0.1" 1627 | } 1628 | }, 1629 | "muggle-string": { 1630 | "version": "0.3.1", 1631 | "resolved": "https://registry.npmjs.org/muggle-string/-/muggle-string-0.3.1.tgz", 1632 | "integrity": "sha512-ckmWDJjphvd/FvZawgygcUeQCxzvohjFO5RxTjj4eq8kw359gFF3E1brjfI+viLMxss5JrHTDRHZvu2/tuy0Qg==", 1633 | "dev": true 1634 | }, 1635 | "nanoid": { 1636 | "version": "3.3.6", 1637 | "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz", 1638 | "integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==" 1639 | }, 1640 | "path-browserify": { 1641 | "version": "1.0.1", 1642 | "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz", 1643 | "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==", 1644 | "dev": true 1645 | }, 1646 | "picocolors": { 1647 | "version": "1.0.0", 1648 | "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", 1649 | "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" 1650 | }, 1651 | "postcss": { 1652 | "version": "8.4.31", 1653 | "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", 1654 | "integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==", 1655 | "requires": { 1656 | "nanoid": "^3.3.6", 1657 | "picocolors": "^1.0.0", 1658 | "source-map-js": "^1.0.2" 1659 | } 1660 | }, 1661 | "rollup": { 1662 | "version": "3.29.4", 1663 | "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.29.4.tgz", 1664 | "integrity": "sha512-oWzmBZwvYrU0iJHtDmhsm662rC15FRXmcjCk1xD771dFDx5jJ02ufAQQTn0etB2emNk4J9EZg/yWKpsn9BWGRw==", 1665 | "dev": true, 1666 | "requires": { 1667 | "fsevents": "~2.3.2" 1668 | } 1669 | }, 1670 | "semver": { 1671 | "version": "7.5.4", 1672 | "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", 1673 | "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", 1674 | "dev": true, 1675 | "requires": { 1676 | "lru-cache": "^6.0.0" 1677 | } 1678 | }, 1679 | "source-map-js": { 1680 | "version": "1.0.2", 1681 | "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", 1682 | "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==" 1683 | }, 1684 | "typescript": { 1685 | "version": "5.2.2", 1686 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz", 1687 | "integrity": "sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==", 1688 | "devOptional": true 1689 | }, 1690 | "vite": { 1691 | "version": "4.5.0", 1692 | "resolved": "https://registry.npmjs.org/vite/-/vite-4.5.0.tgz", 1693 | "integrity": "sha512-ulr8rNLA6rkyFAlVWw2q5YJ91v098AFQ2R0PRFwPzREXOUJQPtFUG0t+/ZikhaOCDqFoDhN6/v8Sq0o4araFAw==", 1694 | "dev": true, 1695 | "requires": { 1696 | "esbuild": "^0.18.10", 1697 | "fsevents": "~2.3.2", 1698 | "postcss": "^8.4.27", 1699 | "rollup": "^3.27.1" 1700 | } 1701 | }, 1702 | "vue": { 1703 | "version": "3.3.7", 1704 | "resolved": "https://registry.npmjs.org/vue/-/vue-3.3.7.tgz", 1705 | "integrity": "sha512-YEMDia1ZTv1TeBbnu6VybatmSteGOS3A3YgfINOfraCbf85wdKHzscD6HSS/vB4GAtI7sa1XPX7HcQaJ1l24zA==", 1706 | "requires": { 1707 | "@vue/compiler-dom": "3.3.7", 1708 | "@vue/compiler-sfc": "3.3.7", 1709 | "@vue/runtime-dom": "3.3.7", 1710 | "@vue/server-renderer": "3.3.7", 1711 | "@vue/shared": "3.3.7" 1712 | } 1713 | }, 1714 | "vue-template-compiler": { 1715 | "version": "2.7.15", 1716 | "resolved": "https://registry.npmjs.org/vue-template-compiler/-/vue-template-compiler-2.7.15.tgz", 1717 | "integrity": "sha512-yQxjxMptBL7UAog00O8sANud99C6wJF+7kgbcwqkvA38vCGF7HWE66w0ZFnS/kX5gSoJr/PQ4/oS3Ne2pW37Og==", 1718 | "dev": true, 1719 | "requires": { 1720 | "de-indent": "^1.0.2", 1721 | "he": "^1.2.0" 1722 | } 1723 | }, 1724 | "vue-tsc": { 1725 | "version": "1.8.22", 1726 | "resolved": "https://registry.npmjs.org/vue-tsc/-/vue-tsc-1.8.22.tgz", 1727 | "integrity": "sha512-j9P4kHtW6eEE08aS5McFZE/ivmipXy0JzrnTgbomfABMaVKx37kNBw//irL3+LlE3kOo63XpnRigyPC3w7+z+A==", 1728 | "dev": true, 1729 | "requires": { 1730 | "@volar/typescript": "~1.10.5", 1731 | "@vue/language-core": "1.8.22", 1732 | "semver": "^7.5.4" 1733 | } 1734 | }, 1735 | "yallist": { 1736 | "version": "4.0.0", 1737 | "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", 1738 | "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", 1739 | "dev": true 1740 | } 1741 | } 1742 | } 1743 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "guitar-assits", 3 | "private": true, 4 | "version": "0.0.0", 5 | "type": "module", 6 | "scripts": { 7 | "dev": "vite", 8 | "build": "vue-tsc --noEmit && vite build", 9 | "preview": "vite preview", 10 | "tauri": "tauri" 11 | }, 12 | "dependencies": { 13 | "@tauri-apps/api": "^1.5.0", 14 | "element-plus": "^2.4.2", 15 | "lodash": "^4.17.21", 16 | "vue": "^3.3.4" 17 | }, 18 | "devDependencies": { 19 | "@tauri-apps/cli": "^1.5.0", 20 | "@types/lodash": "^4.14.202", 21 | "@vitejs/plugin-vue": "^4.2.3", 22 | "typescript": "^5.0.2", 23 | "unplugin-auto-import": "^0.16.7", 24 | "unplugin-vue-components": "^0.25.2", 25 | "vite": "^4.4.4", 26 | "vite-plugin-svg": "^0.7.0", 27 | "vue-tsc": "^1.8.5" 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /public/tauri.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /public/vite.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src-tauri/.gitignore: -------------------------------------------------------------------------------- 1 | # Generated by Cargo 2 | # will have compiled files and executables 3 | /target/ 4 | 5 | -------------------------------------------------------------------------------- /src-tauri/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "guitar-assits" 3 | version = "0.0.0" 4 | description = "A Tauri App" 5 | authors = ["you"] 6 | license = "" 7 | repository = "" 8 | edition = "2021" 9 | 10 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 11 | 12 | [build-dependencies] 13 | tauri-build = { version = "1.5", features = [] } 14 | 15 | [dependencies] 16 | tauri = { version = "1.5", features = ["shell-open"] } 17 | serde = { version = "1.0", features = ["derive"] } 18 | serde_json = "1.0" 19 | 20 | [features] 21 | # this feature is used for production builds or when `devPath` points to the filesystem 22 | # DO NOT REMOVE!! 23 | custom-protocol = ["tauri/custom-protocol"] 24 | -------------------------------------------------------------------------------- /src-tauri/build.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | tauri_build::build() 3 | } 4 | -------------------------------------------------------------------------------- /src-tauri/icons/128x128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zourunfa/guitar-assits/867573a8673f3a81a55b857388361f2b4bc68bdb/src-tauri/icons/128x128.png -------------------------------------------------------------------------------- /src-tauri/icons/128x128@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zourunfa/guitar-assits/867573a8673f3a81a55b857388361f2b4bc68bdb/src-tauri/icons/128x128@2x.png -------------------------------------------------------------------------------- /src-tauri/icons/32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zourunfa/guitar-assits/867573a8673f3a81a55b857388361f2b4bc68bdb/src-tauri/icons/32x32.png -------------------------------------------------------------------------------- /src-tauri/icons/Square107x107Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zourunfa/guitar-assits/867573a8673f3a81a55b857388361f2b4bc68bdb/src-tauri/icons/Square107x107Logo.png -------------------------------------------------------------------------------- /src-tauri/icons/Square142x142Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zourunfa/guitar-assits/867573a8673f3a81a55b857388361f2b4bc68bdb/src-tauri/icons/Square142x142Logo.png -------------------------------------------------------------------------------- /src-tauri/icons/Square150x150Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zourunfa/guitar-assits/867573a8673f3a81a55b857388361f2b4bc68bdb/src-tauri/icons/Square150x150Logo.png -------------------------------------------------------------------------------- /src-tauri/icons/Square284x284Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zourunfa/guitar-assits/867573a8673f3a81a55b857388361f2b4bc68bdb/src-tauri/icons/Square284x284Logo.png -------------------------------------------------------------------------------- /src-tauri/icons/Square30x30Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zourunfa/guitar-assits/867573a8673f3a81a55b857388361f2b4bc68bdb/src-tauri/icons/Square30x30Logo.png -------------------------------------------------------------------------------- /src-tauri/icons/Square310x310Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zourunfa/guitar-assits/867573a8673f3a81a55b857388361f2b4bc68bdb/src-tauri/icons/Square310x310Logo.png -------------------------------------------------------------------------------- /src-tauri/icons/Square44x44Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zourunfa/guitar-assits/867573a8673f3a81a55b857388361f2b4bc68bdb/src-tauri/icons/Square44x44Logo.png -------------------------------------------------------------------------------- /src-tauri/icons/Square71x71Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zourunfa/guitar-assits/867573a8673f3a81a55b857388361f2b4bc68bdb/src-tauri/icons/Square71x71Logo.png -------------------------------------------------------------------------------- /src-tauri/icons/Square89x89Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zourunfa/guitar-assits/867573a8673f3a81a55b857388361f2b4bc68bdb/src-tauri/icons/Square89x89Logo.png -------------------------------------------------------------------------------- /src-tauri/icons/StoreLogo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zourunfa/guitar-assits/867573a8673f3a81a55b857388361f2b4bc68bdb/src-tauri/icons/StoreLogo.png -------------------------------------------------------------------------------- /src-tauri/icons/af-icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zourunfa/guitar-assits/867573a8673f3a81a55b857388361f2b4bc68bdb/src-tauri/icons/af-icon.ico -------------------------------------------------------------------------------- /src-tauri/icons/af.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zourunfa/guitar-assits/867573a8673f3a81a55b857388361f2b4bc68bdb/src-tauri/icons/af.ico -------------------------------------------------------------------------------- /src-tauri/icons/af.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zourunfa/guitar-assits/867573a8673f3a81a55b857388361f2b4bc68bdb/src-tauri/icons/af.png -------------------------------------------------------------------------------- /src-tauri/icons/icon.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zourunfa/guitar-assits/867573a8673f3a81a55b857388361f2b4bc68bdb/src-tauri/icons/icon.icns -------------------------------------------------------------------------------- /src-tauri/icons/icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zourunfa/guitar-assits/867573a8673f3a81a55b857388361f2b4bc68bdb/src-tauri/icons/icon.ico -------------------------------------------------------------------------------- /src-tauri/icons/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zourunfa/guitar-assits/867573a8673f3a81a55b857388361f2b4bc68bdb/src-tauri/icons/icon.png -------------------------------------------------------------------------------- /src-tauri/src/main.rs: -------------------------------------------------------------------------------- 1 | // Prevents additional console window on Windows in release, DO NOT REMOVE!! 2 | #![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] 3 | 4 | // Learn more about Tauri commands at https://tauri.app/v1/guides/features/command 5 | #[tauri::command] 6 | fn greet(name: &str) -> String { 7 | format!("Hello, {}! You've been greeted from Rust!", name) 8 | } 9 | 10 | fn main() { 11 | tauri::Builder::default() 12 | .invoke_handler(tauri::generate_handler![greet]) 13 | .run(tauri::generate_context!()) 14 | .expect("error while running tauri application"); 15 | } 16 | -------------------------------------------------------------------------------- /src-tauri/tauri.conf.json: -------------------------------------------------------------------------------- 1 | { 2 | "build": { 3 | "beforeDevCommand": "pnpm dev", 4 | "beforeBuildCommand": "pnpm build", 5 | "devPath": "http://localhost:1420", 6 | "distDir": "../dist", 7 | "withGlobalTauri": false 8 | }, 9 | "package": { 10 | "productName": "guitar-assits", 11 | "version": "0.0.0" 12 | }, 13 | "tauri": { 14 | "allowlist": { 15 | "all": false, 16 | "shell": { 17 | "all": false, 18 | "open": true 19 | } 20 | }, 21 | "bundle": { 22 | "active": true, 23 | "targets": "all", 24 | "identifier": "com.mycoolapp.guitar-assits", 25 | "icon": ["icons/af.png", "icons/icon.icns", "icons/af.ico"] 26 | }, 27 | "security": { 28 | "csp": null 29 | }, 30 | "windows": [ 31 | { 32 | "fullscreen": false, 33 | "resizable": true, 34 | "title": "guitar-assits", 35 | "width": 1200, 36 | "height": 900 37 | } 38 | ] 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/App.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 29 | 30 | 101 | -------------------------------------------------------------------------------- /src/assets/bars.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 11 | 12 | 13 | 17 | 21 | 22 | 23 | 27 | 31 | 32 | 33 | 37 | 41 | 42 | 43 | 47 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /src/assets/fingerPanel.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /src/components/ChordDraw.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 115 | 116 | 137 | -------------------------------------------------------------------------------- /src/components/ChordSelect.vue: -------------------------------------------------------------------------------- 1 | 28 | 29 | 37 | -------------------------------------------------------------------------------- /src/components/Fingering.vue: -------------------------------------------------------------------------------- 1 | 16 | 17 | 262 | 263 | 359 | -------------------------------------------------------------------------------- /src/components/chordSelect.vue: -------------------------------------------------------------------------------- 1 | 108 | 109 | 139 | 140 | 286 | -------------------------------------------------------------------------------- /src/main.ts: -------------------------------------------------------------------------------- 1 | import { createApp } from 'vue' 2 | import './styles.css' 3 | import App from './App.vue' 4 | import ElementPlus from 'element-plus' 5 | import 'element-plus/dist/index.css' 6 | 7 | import './utils/chordComputed/index' 8 | 9 | const app = createApp(App) 10 | 11 | app.use(ElementPlus) 12 | app.mount('#app') 13 | -------------------------------------------------------------------------------- /src/styles.css: -------------------------------------------------------------------------------- 1 | :root { 2 | font-family: Inter, Avenir, Helvetica, Arial, sans-serif; 3 | font-size: 16px; 4 | line-height: 24px; 5 | font-weight: 400; 6 | 7 | color: #0f0f0f; 8 | background-color: #f6f6f6; 9 | 10 | font-synthesis: none; 11 | text-rendering: optimizeLegibility; 12 | -webkit-font-smoothing: antialiased; 13 | -moz-osx-font-smoothing: grayscale; 14 | -webkit-text-size-adjust: 100%; 15 | } 16 | 17 | .container { 18 | margin: 0; 19 | padding-top: 10vh; 20 | display: flex; 21 | flex-direction: column; 22 | justify-content: center; 23 | text-align: center; 24 | } 25 | 26 | .logo { 27 | height: 6em; 28 | padding: 1.5em; 29 | will-change: filter; 30 | transition: 0.75s; 31 | } 32 | 33 | .logo.tauri:hover { 34 | filter: drop-shadow(0 0 2em #24c8db); 35 | } 36 | 37 | .row { 38 | display: flex; 39 | justify-content: center; 40 | } 41 | 42 | a { 43 | font-weight: 500; 44 | color: #646cff; 45 | text-decoration: inherit; 46 | } 47 | 48 | a:hover { 49 | color: #535bf2; 50 | } 51 | 52 | h1 { 53 | text-align: center; 54 | } 55 | 56 | input, 57 | button { 58 | border-radius: 8px; 59 | border: 1px solid transparent; 60 | padding: 0.6em 1.2em; 61 | font-size: 1em; 62 | font-weight: 500; 63 | font-family: inherit; 64 | color: #0f0f0f; 65 | background-color: #ffffff; 66 | transition: border-color 0.25s; 67 | box-shadow: 0 2px 2px rgba(0, 0, 0, 0.2); 68 | } 69 | 70 | button { 71 | cursor: pointer; 72 | } 73 | 74 | button:hover { 75 | border-color: #396cd8; 76 | } 77 | button:active { 78 | border-color: #396cd8; 79 | background-color: #e8e8e8; 80 | } 81 | 82 | input, 83 | button { 84 | outline: none; 85 | } 86 | 87 | #greet-input { 88 | margin-right: 5px; 89 | } 90 | 91 | @media (prefers-color-scheme: dark) { 92 | :root { 93 | color: #f6f6f6; 94 | background-color: #2f2f2f; 95 | } 96 | 97 | a:hover { 98 | color: #24c8db; 99 | } 100 | 101 | input, 102 | button { 103 | color: #ffffff; 104 | background-color: #0f0f0f98; 105 | } 106 | button:active { 107 | background-color: #0f0f0f69; 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /src/types/index.ts: -------------------------------------------------------------------------------- 1 | // 提示消息类型 2 | export interface InfoMessageType { 3 | hasAnswer: string[] 4 | hasSvg: string[] 5 | noAnswer: string[] 6 | } 7 | 8 | // 位置类型 9 | export interface PositionType { 10 | string: number 11 | fret: number 12 | } 13 | export interface NormalObject { 14 | [key: string]: any 15 | } 16 | export interface StateInterface { 17 | [key: string]: any 18 | chordTone: string[] 19 | type: number 20 | } 21 | -------------------------------------------------------------------------------- /src/utils/chordComputed/chordName/index.ts: -------------------------------------------------------------------------------- 1 | import { Tone } from '../tone/index' 2 | export class ChordName { 3 | private toneUtil: Tone 4 | 5 | constructor() { 6 | // Assuming Tone class requires some parameters in the constructor 7 | this.toneUtil = new Tone(/* Pass required parameters */) 8 | } 9 | 10 | private getToneSpace(tonePre: string, toneNext: string): number { 11 | let toneSpace = this.toneUtil.findKeyIndex(toneNext) - this.toneUtil.findKeyIndex(tonePre) 12 | return (toneSpace = toneSpace < 0 ? toneSpace + 12 : toneSpace) 13 | } 14 | 15 | private isMajorThird(tonePre: string, toneNext: string): boolean { 16 | return this.getToneSpace(tonePre, toneNext) === 4 17 | } 18 | 19 | private isMinorThird(tonePre: string, toneNext: string): boolean { 20 | return this.getToneSpace(tonePre, toneNext) === 3 21 | } 22 | 23 | private isMajorMajorThird(tonePre: string, toneNext: string): boolean { 24 | return this.getToneSpace(tonePre, toneNext) === 5 25 | } 26 | 27 | private isMinorMinorThird(tonePre: string, toneNext: string): boolean { 28 | return this.getToneSpace(tonePre, toneNext) === 2 29 | } 30 | 31 | private isMajorChord(chordTone: string[]): boolean { 32 | return this.isMajorThird(chordTone[0], chordTone[1]) && this.isMinorThird(chordTone[1], chordTone[2]) 33 | } 34 | 35 | private isMinorChord(chordTone: string[]): boolean { 36 | return this.isMinorThird(chordTone[0], chordTone[1]) && this.isMajorThird(chordTone[1], chordTone[2]) 37 | } 38 | 39 | private isAugmentedChord(chordTone: string[]): boolean { 40 | return this.isMajorThird(chordTone[0], chordTone[1]) && this.isMajorThird(chordTone[1], chordTone[2]) 41 | } 42 | 43 | private isDiminishedChord(chordTone: string[]): boolean { 44 | return this.isMinorThird(chordTone[0], chordTone[1]) && this.isMinorThird(chordTone[1], chordTone[2]) 45 | } 46 | 47 | private isSus4(chordTone: string[]): boolean { 48 | return this.isMajorMajorThird(chordTone[0], chordTone[1]) && this.isMinorMinorThird(chordTone[1], chordTone[2]) 49 | } 50 | 51 | private isMajorMinorSeventhChord(chordTone: string[]): boolean { 52 | if (chordTone.length < 4) return false 53 | return this.isMajorChord(chordTone) && this.isMinorThird(chordTone[2], chordTone[3]) 54 | } 55 | 56 | private isMinorMajorSeventhChord(chordTone: string[]): boolean { 57 | if (chordTone.length < 4) return false 58 | return this.isMinorChord(chordTone) && this.isMajorThird(chordTone[2], chordTone[3]) 59 | } 60 | 61 | private isMajorMajorSeventhChord(chordTone: string[]): boolean { 62 | if (chordTone.length < 4) return false 63 | return this.isMajorChord(chordTone) && this.isMajorThird(chordTone[2], chordTone[3]) 64 | } 65 | 66 | private isMinorMinorSeventhChord(chordTone: string[]): boolean { 67 | if (chordTone.length < 4) return false 68 | return this.isMinorChord(chordTone) && this.isMinorThird(chordTone[2], chordTone[3]) 69 | } 70 | 71 | private isDiminishedSeventhChord(chordTone: string[]): boolean { 72 | if (chordTone.length < 4) return false 73 | return this.isDiminishedChord(chordTone) && this.isMinorThird(chordTone[2], chordTone[3]) 74 | } 75 | 76 | private isHalfDiminishedSeventhChord(chordTone: string[]): boolean { 77 | if (chordTone.length < 4) return false 78 | return this.isDiminishedChord(chordTone) && this.isMajorThird(chordTone[2], chordTone[3]) 79 | } 80 | 81 | private isHalfAugmentedSeventhChord(chordTone: string[]): boolean { 82 | if (chordTone.length < 4) return false 83 | return this.isAugmentedChord(chordTone) && this.isMinorMinorThird(chordTone[2], chordTone[3]) 84 | } 85 | 86 | private isAugmentedSeventhChord(chordTone: string[]): boolean { 87 | if (chordTone.length < 4) return false 88 | return this.isAugmentedChord(chordTone) && this.isMinorThird(chordTone[2], chordTone[3]) 89 | } 90 | 91 | public getKeyName(key: string): string { 92 | let keyName = this.toneUtil.intervalMap[this.toneUtil.findKeyIndex(key)] 93 | if (Array.isArray(keyName)) { 94 | keyName = /b/.test(key) ? keyName[1] : keyName[0] 95 | } 96 | return keyName 97 | } 98 | 99 | getChordName(chordTone: string[]): string { 100 | let rootKey = chordTone[0] 101 | let chordRootName = this.getKeyName(rootKey) 102 | let suffix = '...' 103 | let suffixArr: any[] = [] 104 | 105 | let chord3SuffixMap = [ 106 | { 107 | fn: this.isMajorChord, 108 | suffix: '', 109 | }, 110 | { 111 | fn: this.isMinorChord, 112 | suffix: 'm', 113 | }, 114 | { 115 | fn: this.isAugmentedChord, 116 | suffix: 'aug', 117 | }, 118 | { 119 | fn: this.isDiminishedChord, 120 | suffix: 'dim', 121 | }, 122 | { 123 | fn: this.isSus4, 124 | suffix: 'sus4', 125 | }, 126 | ] 127 | 128 | let chord4SuffixMap = [ 129 | { 130 | fn: this.isMajorMinorSeventhChord, 131 | suffix: '7', 132 | }, 133 | { 134 | fn: this.isMinorMajorSeventhChord, 135 | suffix: 'mM7', 136 | }, 137 | { 138 | fn: this.isMajorMajorSeventhChord, 139 | suffix: 'maj7', 140 | }, 141 | { 142 | fn: this.isMinorMinorSeventhChord, 143 | suffix: 'm7', 144 | }, 145 | { 146 | fn: this.isDiminishedSeventhChord, 147 | suffix: 'dim7', 148 | }, 149 | { 150 | fn: this.isHalfDiminishedSeventhChord, 151 | suffix: 'm7-5', 152 | }, 153 | { 154 | fn: this.isHalfAugmentedSeventhChord, 155 | suffix: '7#5', 156 | }, 157 | 158 | { 159 | fn: this.isAugmentedSeventhChord, 160 | suffix: 'aug7', 161 | }, 162 | ] 163 | 164 | if (chordTone.length === 3) { 165 | suffixArr = chord3SuffixMap.filter(item => { 166 | return item.fn.bind(this, chordTone)() 167 | }) 168 | suffix = suffixArr.length > 0 ? suffixArr[0].suffix : suffix 169 | } else { 170 | suffixArr = chord4SuffixMap.filter(item => { 171 | return item.fn.bind(this, chordTone)() 172 | }) 173 | suffix = suffixArr.length > 0 ? suffixArr[0].suffix : suffix 174 | } 175 | 176 | return chordRootName + suffix 177 | } 178 | } 179 | -------------------------------------------------------------------------------- /src/utils/chordComputed/chordSvg/index.ts: -------------------------------------------------------------------------------- 1 | import { ChordName } from '../chordName/index' 2 | 3 | export class ChordSvg { 4 | private SVG_NS: string 5 | private XLINK_NS: string 6 | private ATTR_MAP: Record 7 | private NS_MAP: Record 8 | private svg: SVGElement 9 | private chordRect: SVGElement 10 | private chordGird: SVGElement 11 | private defs: SVGElement 12 | private g_forbidden: SVGElement 13 | private g_blank_circle: SVGElement 14 | private g_block_circle: SVGElement 15 | // private minFret: number 16 | 17 | constructor() { 18 | this.SVG_NS = 'http://www.w3.org/2000/svg' 19 | this.XLINK_NS = 'http://www.w3.org/1999/xlink' 20 | this.ATTR_MAP = { 21 | className: 'class', 22 | svgHref: 'href', 23 | } 24 | this.NS_MAP = { 25 | svgHref: this.XLINK_NS, 26 | } 27 | this.initChordSvg() 28 | // this.minFret = 0 29 | } 30 | 31 | // 创建svg相关元素 32 | private createSVG(tag: string, attributes?: Record): SVGElement { 33 | let elem = document.createElementNS(this.SVG_NS, tag) as SVGElement 34 | 35 | for (let attribute in attributes) { 36 | let name = attribute in this.ATTR_MAP ? this.ATTR_MAP[attribute] : attribute 37 | let value = attributes[attribute] 38 | 39 | if (attribute in this.NS_MAP) { 40 | elem.setAttributeNS(this.NS_MAP[attribute], name, value) 41 | } else { 42 | elem.setAttribute(name, value) 43 | } 44 | } 45 | 46 | return elem 47 | } 48 | 49 | // 创建use标签 50 | private createUse(href: string, x: number, y: number): SVGElement { 51 | return this.createSVG('use', { 52 | svgHref: href, 53 | x: x, 54 | y: y, 55 | }) 56 | } 57 | 58 | // 设置禁止弹奏的叉号位置,位于几弦 59 | private setForbidden(svg: SVGElement, string: number = 6): void { 60 | svg.appendChild(this.createUse('#forbidden', 25 + 20 * (6 - string), 30)) 61 | } 62 | 63 | // 设置空弦弹奏的空心圈位置,位于几弦 64 | private setOpen(svg: SVGElement, string: number = 6): void { 65 | svg.appendChild(this.createUse('#blank_circle', 25 + 20 * (6 - string), 30)) 66 | } 67 | 68 | // 设置指法按弦位置,几弦几品 69 | private setFinger(svg: SVGElement, string: number = 6, fret: number = 0): void { 70 | if (+fret > 0 && +fret <= 5) { 71 | svg.appendChild(this.createUse('#block_circle', 25 + 20 * (6 - string), 35 + 20 * fret)) 72 | } 73 | } 74 | 75 | // 设置大横按位置 76 | // barreFret: number 77 | private setBarre(svg: SVGElement, stringTo: number, fret: number): void { 78 | if (fret > 0 && fret <= 5) { 79 | svg.appendChild( 80 | this.createSVG('rect', { 81 | className: 'chord-barre', 82 | width: stringTo * 20, 83 | x: 15 + 20 * (6 - stringTo), 84 | y: 27 + 20 * fret, 85 | rx: 8, 86 | ry: 8, 87 | }) 88 | ) 89 | } 90 | } 91 | 92 | // 设置把位偏移的数字提示 93 | private setFretOffset(svg: SVGElement, fret: number, fretOffset: number, isBarreCover: boolean): void { 94 | if (fret > 0) { 95 | let text = this.createSVG('text', { 96 | className: 'chord-barre-fret', 97 | x: isBarreCover ? 1 : 8, 98 | y: 40 + fret * 20, 99 | }) 100 | 101 | text.innerHTML = fretOffset.toString() 102 | svg.appendChild(text) 103 | } 104 | } 105 | 106 | // 设置每根弦在按住和弦后的发音名 107 | private setStringKey(svg: SVGElement, string: number, keyName: string): void { 108 | let xFixed = keyName.length === 2 ? -4 : 0 109 | let text = this.createSVG('text', { 110 | className: 'chord-string-key', 111 | x: 21.5 + 20 * (6 - string) + xFixed, 112 | y: 160, 113 | }) 114 | 115 | text.innerHTML = keyName 116 | svg.appendChild(text) 117 | } 118 | 119 | // 设置和弦名称 120 | private setChordName(svg: SVGElement, name: string = ''): void { 121 | let xFixed = /\.\.\./.test(name) ? 10 : 0 122 | let text = this.createSVG('text', { 123 | className: 'chord-name', 124 | x: 75 - name.length * 7 + xFixed, 125 | y: 20, 126 | }) 127 | 128 | text.innerHTML = name 129 | svg.appendChild(text) 130 | } 131 | 132 | // 初始化svg 133 | private initChordSvg(): void { 134 | // svg元素 135 | 136 | /** 137 | * viewBox: '0 0 150 150':定义SVG内容的坐标系统和纵横比。在这种情况下, 138 | * viewBox设置为'0 0 150 150',表示SVG内容将在一个150x150单位的坐标系统内。 139 | */ 140 | this.svg = this.createSVG('svg', { 141 | className: 'chord-svg', 142 | viewBox: '0 0 150 150', 143 | preserveAspectRatio: 'xMidYMin meet', 144 | }) 145 | 146 | // 和弦图方块 147 | this.chordRect = this.createSVG('rect', { 148 | className: 'chord-rect', 149 | x: 25, 150 | y: 45, 151 | rx: 5, 152 | ry: 5, 153 | }) 154 | 155 | // 和弦网格,代表弦和品 156 | this.chordGird = this.createSVG('path', { 157 | className: 'chord-gird', 158 | d: 'M25 65 L125 65 M25 85 L125 85 M25 105 L125 105 M25 125 L125 125 M45 45 L45 145 M65 45 L65 145 M85 45 L85 145 M105 45 L105 145 M25 40 L125 40', 159 | }) 160 | 161 | // 用于放置可复用的svg元素 162 | this.defs = this.createSVG('defs') 163 | 164 | // 禁止按弦的叉号标志 165 | this.g_forbidden = this.createSVG('g', { 166 | id: 'forbidden', 167 | }) 168 | 169 | this.g_forbidden.appendChild( 170 | this.createSVG('path', { 171 | className: 'chord-forbidden', 172 | d: 'M-5 -5 L5 5 M-5 5 L5 -5', 173 | }) 174 | ) 175 | 176 | // 空弦弹奏的空心圈标志 177 | this.g_blank_circle = this.createSVG('g', { 178 | id: 'blank_circle', 179 | }) 180 | 181 | this.g_blank_circle.appendChild( 182 | this.createSVG('circle', { 183 | className: 'chord-blank-circle', 184 | cx: 0, 185 | cy: 0, 186 | r: 6, 187 | }) 188 | ) 189 | 190 | // 表示按弦位置的实心圈标志 191 | this.g_block_circle = this.createSVG('g', { 192 | id: 'block_circle', 193 | }) 194 | 195 | this.g_block_circle.appendChild( 196 | this.createSVG('circle', { 197 | className: 'chord-block-circle', 198 | cx: 0, 199 | cy: 0, 200 | r: 8, 201 | }) 202 | ) 203 | 204 | // 可复用元素加入 205 | this.defs.appendChild(this.g_forbidden) 206 | this.defs.appendChild(this.g_blank_circle) 207 | this.defs.appendChild(this.g_block_circle) 208 | 209 | // svg子元素加入 210 | this.svg.appendChild(this.chordRect) 211 | this.svg.appendChild(this.chordGird) 212 | this.svg.appendChild(this.defs) 213 | } 214 | 215 | // 绘制和弦svg图案 216 | /* 217 | * @param chordTone 和弦组成音数组 218 | * @param chord 和弦指法结果 219 | * @param target svg指法图dom容器 220 | */ 221 | public drawChord(chordTone: string[], chord: any[], target?: Element): void { 222 | let svg = this.svg.cloneNode(true) as SVGElement 223 | 224 | let fretArr = chord.map(item => item.fret).filter(fret => fret != null) 225 | // 和弦指法中出现的最高品格位置 226 | let maxFret = Math.max(...fretArr) 227 | // 和弦指法中出现的最低品位位置 228 | let minFret = Math.min(...fretArr) 229 | // svg指法图案的起始品格位置相对于吉他上0品位置的偏移量 230 | let fretOffset = maxFret <= 5 ? 0 : minFret 231 | // 记录指法最低品位可能需要大横按的按弦数 232 | let barreCount = 0 233 | // 大横按初始只横跨1弦到1弦(相当于没横按) 234 | let barreStringTo = 1 235 | // 实例化用于计算和弦名称的类 236 | let chordName = new ChordName() 237 | // 遍历和弦指法数组 238 | chord.forEach(item => { 239 | if (item.fret == null) { 240 | // 某根弦没标记品格位置时禁止该弦弹奏 241 | this.setForbidden(svg, item.string) 242 | } else if (item.fret === 0) { 243 | // 某根弦没标记的品格位置为0品时标记空弦弹奏 244 | this.setOpen(svg, item.string) 245 | } else { 246 | // 剩下的指法绘制其对应的按法位置 247 | this.setFinger(svg, item.string, fretOffset > 0 ? item.fret - fretOffset + 1 : item.fret) 248 | } 249 | // 当按在该和弦的最低品格位置的指法反复出现时 250 | if (item.fret === minFret) { 251 | // 计算大横按的跨度 252 | barreStringTo = item.string > barreStringTo ? item.string : barreStringTo 253 | // 计算大横按实际按弦的数量 254 | barreCount++ 255 | } 256 | // 在允许弹奏的弦的下方标记其对应的音名 257 | if (item.fret != null) { 258 | this.setStringKey(svg, item.string, chordName.getKeyName(item.key)) 259 | } 260 | }) 261 | 262 | // 将真实的按弦品格位置转换为相对于svg图案上的品格位置 263 | let relativeFret = fretOffset > 0 ? minFret - fretOffset + 1 : minFret 264 | if (barreCount > 1) { 265 | // 横按数大于1才需要使用大横按 266 | // this.setBarre(svg, barreStringTo, relativeFret, minFret) 267 | this.setBarre(svg, barreStringTo, relativeFret) 268 | } 269 | // 在图案左侧绘制品格位置偏移标记 270 | this.setFretOffset(svg, relativeFret, minFret, barreStringTo === 6) 271 | // 在图案上侧绘制和弦名称 272 | this.setChordName(svg, chordName.getChordName(chordTone)) 273 | // 将生成的svg图案塞到指定结构中 274 | target ? target.appendChild(svg) : document.body.appendChild(svg) 275 | } 276 | } 277 | -------------------------------------------------------------------------------- /src/utils/chordComputed/guitarChord/index.ts: -------------------------------------------------------------------------------- 1 | import { Tone } from '../tone/index' 2 | export class GuitarChord { 3 | fretLength: number 4 | initialTone: Tone[] 5 | toneMap: Tone[][] 6 | 7 | chordTone: string[] 8 | rootTone: string 9 | chordResult: any[] 10 | 11 | constructor() { 12 | // 吉他的最大品格数 13 | this.fretLength = 15 14 | // 构建1到6弦的初始音 15 | this.initialTone = [new Tone('3.', 1, 0), new Tone('7', 2, 0), new Tone('5', 3, 0), new Tone('2', 4, 0), new Tone('.6', 5, 0), new Tone('.3', 6, 0)] 16 | // 用于吉他上所有位置对应的音 17 | this.toneMap = [] 18 | // 从1到6弦,从品数的低到高,依次计算每个位置的音 19 | for (let string = 1; string <= this.initialTone.length; string++) { 20 | this.toneMap[string] = [] 21 | for (let fret = 0; fret <= this.fretLength; fret++) { 22 | this.toneMap[string].push(this.initialTone[string - 1].step(fret)) 23 | } 24 | } 25 | } 26 | 27 | /* 28 | * @param key 搜寻的音(字符串形式) 29 | * @param toneArray 音域数组,即某根弦上所有单音类按顺序组成的数组 30 | * @param fretStart 搜寻的最低品格数 31 | * @param fretEnd 搜寻的最高品格数 32 | */ 33 | 34 | /* 35 | * @param key 搜寻的音(字符串形式) 36 | * @param toneArray 音域数组,即某根弦上所有单音类按顺序组成的数组 37 | * @param fretStart 搜寻的最低品格数 38 | * @param fretEnd 搜寻的最高品格数 39 | */ 40 | 41 | findFret(key: string, toneArray: Tone[], fretStart = 0, fretEnd?: number): number[] { 42 | key = key.replace(/\./g, '') 43 | let fretArray: number[] = [] 44 | fretStart = fretStart ? fretStart : 0 45 | fretEnd = fretEnd ? fretEnd + 1 : toneArray.length 46 | for (let i = fretStart; i < fretEnd; i++) { 47 | if (Array.isArray(toneArray[i])) { 48 | let toneStringArray = (toneArray[i] as any).map(item => { 49 | return item.toneNormal 50 | }) 51 | if (toneStringArray.includes(key)) { 52 | fretArray.push(i) 53 | } 54 | } else { 55 | if (toneArray[i].toneString.replace(/\./g, '') === key) { 56 | fretArray.push(i) 57 | } 58 | } 59 | } 60 | return fretArray 61 | } 62 | 63 | // 递归遍历范围内的指定和弦的所有位置组合 64 | /* 65 | * @param stringIndex 当前遍历到的弦的序号 66 | * @param toneIndex 上一根弦使用的音的序号(用于相邻的两根弦的音不重复) 67 | * @param fretStart 遍历的最低品格数 68 | * @param fretEnd 遍历的最高品格数 69 | * @param preResult 上一根弦确定的音的结果 70 | * @param positionSave 保存该轮递归的结果 71 | */ 72 | 73 | calc(stringIndex: number, toneIndex: number | null, fretStart: number, fretEnd: number, preResult: any | null, positionSave: any[]): boolean { 74 | let toneArray = this.toneMap[stringIndex] 75 | let result = false 76 | 77 | // 从和弦音的数组里面逐个选出音试探(this.chordTone)在后面提到的函数中复制 78 | for (let i = 0; i < this.chordTone.length; i++) { 79 | if (i !== toneIndex) { 80 | let resultNext = false 81 | let toneKey = this.chordTone[i] 82 | 83 | // 在品格内查找当前音的位置 84 | let fret = this.findFret(toneKey, toneArray, fretStart, fretEnd) 85 | 86 | // 品格范围类存在该音 87 | if (fret.length > 0) { 88 | // 记录该音的位置,几弦几品与音的数字秒速 89 | let resultNow = { 90 | string: stringIndex, 91 | fret: fret[0], 92 | key: toneKey, 93 | pre: null, 94 | } 95 | 96 | // 在本次记录上保存上一根弦的结果,方便回顾 97 | resultNow.pre = preResult ? preResult : null 98 | // 保存本次的结果 99 | positionSave.push(resultNow) 100 | // 设置该弦的结果标记 101 | resultNext = true 102 | 103 | // 没有遍历完所有的6根弦,则继续往下一根弦计算,附带上本次结果记录 104 | if (stringIndex < this.initialTone.length) { 105 | let nextStringIndex = stringIndex + 1 106 | // 该弦上的结果有效标记 取决于它后面的弦的结果也有效 107 | resultNext = resultNext && this.calc(nextStringIndex, i, fretStart, fretEnd, resultNow, positionSave) 108 | } else { 109 | // 所有弦均遍历成功,代表递归结果有效 110 | resultNext = true 111 | } 112 | 113 | if (!resultNext) { 114 | positionSave.pop() 115 | } 116 | } else { 117 | resultNext = false 118 | } 119 | 120 | result = result || resultNext 121 | } 122 | } 123 | 124 | return result 125 | } 126 | 127 | // 和弦指法过滤器 128 | filter(positionSave: any[]): any[] { 129 | // 从六弦开始回溯记录和和弦指法的结果,拆解所有指法的组合 130 | let allResult = positionSave 131 | .filter(item => { 132 | return item.string === this.initialTone.length 133 | }) 134 | .map(item => { 135 | let resultItem = [ 136 | { 137 | string: item.string, 138 | fret: item.fret, 139 | key: item.key, 140 | }, 141 | ] 142 | 143 | while (item.pre) { 144 | item = item.pre 145 | resultItem.unshift({ 146 | string: item.string, 147 | fret: item.fret, 148 | key: item.key, 149 | }) 150 | } 151 | 152 | return resultItem 153 | }) 154 | 155 | if (allResult.length > 0) { 156 | // 依次调用各个过滤器 157 | return this.integrityFilter(this.fingerFilter(this.rootToneFilter(allResult))) 158 | } else { 159 | return [] 160 | } 161 | } 162 | // 和弦组成音完整性过滤 163 | integrityFilter(preResult: any[]): any[] { 164 | return preResult.filter((chordItem: any) => { 165 | let keyCount = [...new Set(chordItem.map(item => item.key).filter(key => key != null))].length 166 | return keyCount == this.chordTone.length 167 | }) 168 | } 169 | // 按弦手指数量过滤 170 | fingerFilter(preResult) { 171 | return preResult.filter(chordItem => { 172 | // 按弦的最小品位 173 | let minFret = Math.min.apply( 174 | null, 175 | chordItem.map(item => item.fret).filter(fret => fret != null) 176 | ) 177 | // 记录需要的手指数量 178 | let fingerNum = minFret > 0 ? 1 : 0 179 | chordItem.forEach(item => { 180 | if (item.fret != null && item.fret > minFret) { 181 | fingerNum++ 182 | } 183 | }) 184 | return fingerNum <= 4 185 | }) 186 | } 187 | 188 | // 根音条件过滤 189 | rootToneFilter(preResult) { 190 | let nextResult = new Set() 191 | preResult.forEach(item => { 192 | // 允许发声的弦的总数,初始为6 193 | let realStringLength = 6 194 | // 从低音弦到高音弦遍历,不符合根音条件则禁止发声 195 | for (var i = item.length - 1; i >= 0; i--) { 196 | if (item[i].key !== this.rootTone) { 197 | item[i].fret = null 198 | item[i].key = null 199 | realStringLength-- 200 | } else { 201 | break 202 | } 203 | } 204 | if (realStringLength >= 4) { 205 | // 去重复 206 | nextResult.add(JSON.stringify(item)) 207 | } 208 | }) 209 | return [...nextResult].map(item => JSON.parse(item as string)) 210 | } 211 | 212 | // 和弦指法计算入口 213 | chord(ActualChordTone): any[] { 214 | // debugger 215 | let chordTone 216 | 217 | if (Array.isArray(ActualChordTone)) { 218 | chordTone = ActualChordTone 219 | } else { 220 | chordTone = Array.prototype.slice.apply(arguments).map(item => { 221 | let tone = new Tone(item.toString()) 222 | return tone.flat + tone.sharp + tone.key 223 | }) 224 | } 225 | 226 | this.chordTone = chordTone 227 | this.rootTone = chordTone[0] 228 | this.chordResult = [] 229 | let fretArray: number[] = [] 230 | console.log(this.chordTone, '--- this.chordTone') 231 | chordTone.forEach(item => { 232 | console.log(this.toneMap, '--this.toneMap') 233 | for (let i = 1; i < this.toneMap.length; i++) { 234 | fretArray = fretArray.concat(this.findFret(item, this.toneMap[i])) 235 | } 236 | }) 237 | 238 | fretArray = [...new Set(fretArray)] 239 | console.log(fretArray, '---fretArray') 240 | fretArray.sort((a, b) => a - b) 241 | 242 | for (let i = 0; i < fretArray.length; i++) { 243 | let fretStart = fretArray[i] 244 | let fretEnd = fretStart > 0 ? fretStart + 4 : fretStart + 5 245 | 246 | if (fretEnd <= this.fretLength) { 247 | let positionSave: any[] = [] 248 | 249 | if (this.calc(1, null, fretStart, fretEnd, null, positionSave)) { 250 | this.chordResult.push(...this.filter(positionSave)) 251 | } 252 | } 253 | } 254 | 255 | let result = [...new Set(this.chordResult.map(item => JSON.stringify(item)))].map(item => JSON.parse(item)) 256 | // debugger 257 | return result 258 | } 259 | } 260 | -------------------------------------------------------------------------------- /src/utils/chordComputed/index.ts: -------------------------------------------------------------------------------- 1 | export * from './tone' 2 | export * from './chordName' 3 | export * from './guitarChord' 4 | export * from './chordSvg' 5 | -------------------------------------------------------------------------------- /src/utils/chordComputed/tone/index.ts: -------------------------------------------------------------------------------- 1 | import { is } from '../../tools/index' 2 | import { PositionType } from '../../../types/index' 3 | 4 | // 生成一个单音,此音的映射查询与音高的改变,同时可标记记录其在吉他上的位置 5 | export class Tone { 6 | //所有唱名数组 7 | syllableMap: string[] = ['do', 're', 'mi', 'fa', 'sol', 'la', 'si'] 8 | // 音程 9 | keyMap: (string | string[])[] = ['1', ['#1', 'b2'], '2', ['#2', 'b3'], '3', '4', ['#4', 'b5'], '5', ['#5', 'b6'], '6', ['#6', 'b7'], '7'] 10 | //所有调名 11 | intervalMap: (string | string[])[] = ['C', ['#C', 'bD'], 'D', ['#D', 'bE'], 'E', 'F', ['#F', 'bG'], 'G', ['#G', 'bA'], 'A', ['#A', 'bB'], 'B'] 12 | // 单音的字符串表示(去除八度标记) 13 | toneString: string 14 | // 单音的字符串表示(去除八度标记) 15 | toneNormal: string 16 | // 数字音 17 | key: string 18 | // 唱名 19 | syllableName: string 20 | // 降半调标记 21 | flat: string 22 | // 升半调标记 23 | sharp: string 24 | octave: number 25 | position: PositionType 26 | 27 | constructor(toneString: string = '1', string?: number, fret?: number) { 28 | this.toneString = toneString 29 | this.toneNormal = toneString.replace(/\./g, '') 30 | this.key = toneString.replace(/\.|b|#/g, '') 31 | this.syllableName = this.syllableMap[+this.key - 1] 32 | this.flat = toneString.match('b') ? 'b' : '' 33 | this.sharp = toneString.match('#') ? '#' : '' 34 | 35 | let octave_arr = toneString.split(this.key) 36 | let octave_flat = octave_arr[0].toString().match(/\./g) 37 | let octave_sharp = octave_arr[1].toString().match(/\./g) 38 | // 八度度数 39 | this.octave = (octave_sharp ? octave_sharp.length : 0) - (octave_flat ? octave_flat.length : 0) 40 | // 吉他按弦位置 41 | this.position = { string, fret } 42 | } 43 | 44 | // 查找此音在音名数组中的位置-- 返回数组的索引号 45 | findKeyIndex(keyString: string): number { 46 | return this.keyMap.findIndex((item: string | string[]) => { 47 | if (Array.isArray(item)) { 48 | return item.includes(keyString) 49 | } else if (item === keyString) { 50 | return true 51 | } else { 52 | return false 53 | } 54 | }) 55 | } 56 | 57 | //音高增减,num为增或减的半音数量 58 | step(num: number): Tone | null { 59 | // 60 | let keyString = this.flat + this.sharp + this.key 61 | let len = this.keyMap.length 62 | let index = this.findKeyIndex(keyString) 63 | if (index > -1) { 64 | num = +num 65 | let nextIndex = parseInt((index + num).toString(), 0) 66 | let octave = this.octave 67 | if (nextIndex >= len) { 68 | let index_gap = nextIndex - len 69 | octave += Math.floor(index_gap / len) + 1 70 | nextIndex = index_gap % len 71 | } else if (nextIndex < 0) { 72 | let index_gap = nextIndex 73 | octave += Math.floor(index_gap / len) 74 | nextIndex = (index_gap % len) + len 75 | } 76 | let nextKey = this.keyMap[nextIndex] 77 | let octaveString = new Array(Math.abs(octave)).fill('.').join('') 78 | let toneString = '' 79 | if (!is(nextKey)('Array')) { 80 | toneString = (octave < 0 ? octaveString : '') + nextKey + (octave > 0 ? octaveString : '') 81 | return new Tone(toneString, this.position.string, this.position.fret + num) 82 | } else { 83 | return (nextKey as any).map(key => { 84 | return new Tone((octave < 0 ? octaveString : '') + key + (octave > 0 ? octaveString : ''), this.position.string, this.position.fret + num) 85 | }) 86 | } 87 | } else { 88 | return null 89 | } 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /src/utils/tools/index.ts: -------------------------------------------------------------------------------- 1 | // 比较两个数组相等 2 | export function arraysAreEqual(arr1: T[], arr2: T[]): boolean { 3 | if (arr1.length !== arr2.length) { 4 | return false 5 | } 6 | 7 | for (let i = 0; i < arr1.length; i++) { 8 | if (arr1[i] !== arr2[i]) { 9 | return false 10 | } 11 | } 12 | 13 | return true 14 | } 15 | 16 | // 数组去重 17 | export function uniqueArray(arr: T[]): T[] { 18 | return Array.from(new Set(arr)) 19 | } 20 | 21 | // 判断类型 22 | export function is(data: any) { 23 | return function (type: string) { 24 | return Object.prototype.toString.call(data) === `[object ${type}]` 25 | } 26 | } 27 | 28 | export function sortChordArray(arr: string[]): string[] { 29 | return arr.sort((a, b) => { 30 | // 如果 a 含有 ...,而 b 不含有 ...,则 a 排在 b 后面 31 | if (a.includes('...') && !b.includes('...')) { 32 | return 1 33 | } 34 | // 如果 b 含有 ...,而 a 不含有 ...,则 a 排在 b 前面 35 | if (!a.includes('...') && b.includes('...')) { 36 | return -1 37 | } 38 | // 其他情况保持原顺序不变 39 | return 0 40 | }) 41 | } 42 | -------------------------------------------------------------------------------- /src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | declare module "*.vue" { 4 | import type { DefineComponent } from "vue"; 5 | const component: DefineComponent<{}, {}, any>; 6 | export default component; 7 | } 8 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | // "target": "ES2020", 4 | "allowJs": true, 5 | "target": "ES2020", 6 | "useDefineForClassFields": true, 7 | // "module": "CommonJS", 8 | "module":"ESNext", 9 | "lib": ["ES2020", "DOM", "DOM.Iterable"], 10 | "skipLibCheck": true, 11 | "noEmitOnError": false, 12 | /* Bundler mode */ 13 | "moduleResolution": "bundler", 14 | "allowImportingTsExtensions": true, 15 | "resolveJsonModule": true, 16 | "isolatedModules": true, 17 | "noEmit": true, 18 | "jsx": "preserve", 19 | 20 | 21 | /* Linting */ 22 | "strict": false, 23 | "noUnusedLocals": true, 24 | "noUnusedParameters": true, 25 | "noFallthroughCasesInSwitch": true 26 | }, 27 | "include": [ "src/**/*.tsx", "src/**/*.vue", "src/**/*.js","src/components/*.vue"], 28 | // "include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue", "src/utils/tone.js","src/components/*.vue"], 29 | 30 | } 31 | -------------------------------------------------------------------------------- /vite.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite' 2 | import vue from '@vitejs/plugin-vue' 3 | import SvgPlugin from 'vite-plugin-svg' 4 | import AutoImport from 'unplugin-auto-import/vite' 5 | import Components from 'unplugin-vue-components/vite' 6 | import { ElementPlusResolver } from 'unplugin-vue-components/resolvers' 7 | // https://vitejs.dev/config/ 8 | export default defineConfig(async () => ({ 9 | plugins: [ 10 | vue(), 11 | SvgPlugin(), 12 | AutoImport({ 13 | resolvers: [ElementPlusResolver()], 14 | }), 15 | Components({ 16 | resolvers: [ElementPlusResolver()], 17 | }), 18 | ], 19 | 20 | // Vite options tailored for Tauri development and only applied in `tauri dev` or `tauri build` 21 | // 22 | // 1. prevent vite from obscuring rust errors 23 | clearScreen: false, 24 | // 2. tauri expects a fixed port, fail if that port is not available 25 | server: { 26 | port: 1420, 27 | strictPort: true, 28 | }, 29 | // 3. to make use of `TAURI_DEBUG` and other env variables 30 | // https://tauri.app/v1/api/config#buildconfig.beforedevcommand 31 | envPrefix: ['VITE_', 'TAURI_'], 32 | build: { 33 | rollupOptions: { 34 | onwarn(warning, rollupWarn) { 35 | if (warning.code !== 'THIS_IS_UNDEFINED') { 36 | rollupWarn(warning) 37 | } 38 | }, 39 | }, 40 | 41 | terserOptions: { 42 | compress: { 43 | // warningsFilter:{} 44 | }, 45 | }, 46 | }, 47 | })) 48 | -------------------------------------------------------------------------------- /vite.config.ts.timestamp-1707646459839-1ec6ee3517027.mjs: -------------------------------------------------------------------------------- 1 | // vite.config.ts 2 | import { defineConfig } from "file:///D:/guitar-assits/guitar-assits/node_modules/.pnpm/vite@4.4.11/node_modules/vite/dist/node/index.js"; 3 | import vue from "file:///D:/guitar-assits/guitar-assits/node_modules/.pnpm/@vitejs+plugin-vue@4.4.0_vite@4.4.11_vue@3.3.4/node_modules/@vitejs/plugin-vue/dist/index.mjs"; 4 | import SvgPlugin from "file:///D:/guitar-assits/guitar-assits/node_modules/.pnpm/registry.npmmirror.com+vite-plugin-svg@0.7.0_@vue+compiler-sfc@3.3.4_vite@4.4.11/node_modules/vite-plugin-svg/index.js"; 5 | import AutoImport from "file:///D:/guitar-assits/guitar-assits/node_modules/.pnpm/unplugin-auto-import@0.16.7/node_modules/unplugin-auto-import/dist/vite.js"; 6 | import Components from "file:///D:/guitar-assits/guitar-assits/node_modules/.pnpm/unplugin-vue-components@0.25.2_vue@3.3.4/node_modules/unplugin-vue-components/dist/vite.mjs"; 7 | import { ElementPlusResolver } from "file:///D:/guitar-assits/guitar-assits/node_modules/.pnpm/unplugin-vue-components@0.25.2_vue@3.3.4/node_modules/unplugin-vue-components/dist/resolvers.mjs"; 8 | var vite_config_default = defineConfig(async () => ({ 9 | plugins: [ 10 | vue(), 11 | SvgPlugin(), 12 | AutoImport({ 13 | resolvers: [ElementPlusResolver()] 14 | }), 15 | Components({ 16 | resolvers: [ElementPlusResolver()] 17 | }) 18 | ], 19 | // Vite options tailored for Tauri development and only applied in `tauri dev` or `tauri build` 20 | // 21 | // 1. prevent vite from obscuring rust errors 22 | clearScreen: false, 23 | // 2. tauri expects a fixed port, fail if that port is not available 24 | server: { 25 | port: 1420, 26 | strictPort: true 27 | }, 28 | // 3. to make use of `TAURI_DEBUG` and other env variables 29 | // https://tauri.app/v1/api/config#buildconfig.beforedevcommand 30 | envPrefix: ["VITE_", "TAURI_"], 31 | build: { 32 | rollupOptions: { 33 | onwarn(warning, rollupWarn) { 34 | if (warning.code !== "THIS_IS_UNDEFINED") { 35 | rollupWarn(warning); 36 | } 37 | } 38 | }, 39 | terserOptions: { 40 | compress: { 41 | // warningsFilter:{} 42 | } 43 | } 44 | } 45 | })); 46 | export { 47 | vite_config_default as default 48 | }; 49 | //# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsidml0ZS5jb25maWcudHMiXSwKICAic291cmNlc0NvbnRlbnQiOiBbImNvbnN0IF9fdml0ZV9pbmplY3RlZF9vcmlnaW5hbF9kaXJuYW1lID0gXCJEOlxcXFxndWl0YXItYXNzaXRzXFxcXGd1aXRhci1hc3NpdHNcIjtjb25zdCBfX3ZpdGVfaW5qZWN0ZWRfb3JpZ2luYWxfZmlsZW5hbWUgPSBcIkQ6XFxcXGd1aXRhci1hc3NpdHNcXFxcZ3VpdGFyLWFzc2l0c1xcXFx2aXRlLmNvbmZpZy50c1wiO2NvbnN0IF9fdml0ZV9pbmplY3RlZF9vcmlnaW5hbF9pbXBvcnRfbWV0YV91cmwgPSBcImZpbGU6Ly8vRDovZ3VpdGFyLWFzc2l0cy9ndWl0YXItYXNzaXRzL3ZpdGUuY29uZmlnLnRzXCI7aW1wb3J0IHsgZGVmaW5lQ29uZmlnIH0gZnJvbSAndml0ZSdcclxuaW1wb3J0IHZ1ZSBmcm9tICdAdml0ZWpzL3BsdWdpbi12dWUnXHJcbmltcG9ydCBTdmdQbHVnaW4gZnJvbSAndml0ZS1wbHVnaW4tc3ZnJ1xyXG5pbXBvcnQgQXV0b0ltcG9ydCBmcm9tICd1bnBsdWdpbi1hdXRvLWltcG9ydC92aXRlJ1xyXG5pbXBvcnQgQ29tcG9uZW50cyBmcm9tICd1bnBsdWdpbi12dWUtY29tcG9uZW50cy92aXRlJ1xyXG5pbXBvcnQgeyBFbGVtZW50UGx1c1Jlc29sdmVyIH0gZnJvbSAndW5wbHVnaW4tdnVlLWNvbXBvbmVudHMvcmVzb2x2ZXJzJ1xyXG4vLyBodHRwczovL3ZpdGVqcy5kZXYvY29uZmlnL1xyXG5leHBvcnQgZGVmYXVsdCBkZWZpbmVDb25maWcoYXN5bmMgKCkgPT4gKHtcclxuICBwbHVnaW5zOiBbXHJcbiAgICB2dWUoKSxcclxuICAgIFN2Z1BsdWdpbigpLFxyXG4gICAgQXV0b0ltcG9ydCh7XHJcbiAgICAgIHJlc29sdmVyczogW0VsZW1lbnRQbHVzUmVzb2x2ZXIoKV0sXHJcbiAgICB9KSxcclxuICAgIENvbXBvbmVudHMoe1xyXG4gICAgICByZXNvbHZlcnM6IFtFbGVtZW50UGx1c1Jlc29sdmVyKCldLFxyXG4gICAgfSksXHJcbiAgXSxcclxuXHJcbiAgLy8gVml0ZSBvcHRpb25zIHRhaWxvcmVkIGZvciBUYXVyaSBkZXZlbG9wbWVudCBhbmQgb25seSBhcHBsaWVkIGluIGB0YXVyaSBkZXZgIG9yIGB0YXVyaSBidWlsZGBcclxuICAvL1xyXG4gIC8vIDEuIHByZXZlbnQgdml0ZSBmcm9tIG9ic2N1cmluZyBydXN0IGVycm9yc1xyXG4gIGNsZWFyU2NyZWVuOiBmYWxzZSxcclxuICAvLyAyLiB0YXVyaSBleHBlY3RzIGEgZml4ZWQgcG9ydCwgZmFpbCBpZiB0aGF0IHBvcnQgaXMgbm90IGF2YWlsYWJsZVxyXG4gIHNlcnZlcjoge1xyXG4gICAgcG9ydDogMTQyMCxcclxuICAgIHN0cmljdFBvcnQ6IHRydWUsXHJcbiAgfSxcclxuICAvLyAzLiB0byBtYWtlIHVzZSBvZiBgVEFVUklfREVCVUdgIGFuZCBvdGhlciBlbnYgdmFyaWFibGVzXHJcbiAgLy8gaHR0cHM6Ly90YXVyaS5hcHAvdjEvYXBpL2NvbmZpZyNidWlsZGNvbmZpZy5iZWZvcmVkZXZjb21tYW5kXHJcbiAgZW52UHJlZml4OiBbJ1ZJVEVfJywgJ1RBVVJJXyddLFxyXG4gIGJ1aWxkOiB7XHJcbiAgICByb2xsdXBPcHRpb25zOiB7XHJcbiAgICAgIG9ud2Fybih3YXJuaW5nLCByb2xsdXBXYXJuKSB7XHJcbiAgICAgICAgaWYgKHdhcm5pbmcuY29kZSAhPT0gJ1RISVNfSVNfVU5ERUZJTkVEJykge1xyXG4gICAgICAgICAgcm9sbHVwV2Fybih3YXJuaW5nKVxyXG4gICAgICAgIH1cclxuICAgICAgfSxcclxuICAgIH0sXHJcblxyXG4gICAgdGVyc2VyT3B0aW9uczoge1xyXG4gICAgICBjb21wcmVzczoge1xyXG4gICAgICAgIC8vIHdhcm5pbmdzRmlsdGVyOnt9XHJcbiAgICAgIH0sXHJcbiAgICB9LFxyXG4gIH0sXHJcbn0pKVxyXG4iXSwKICAibWFwcGluZ3MiOiAiO0FBQWtSLFNBQVMsb0JBQW9CO0FBQy9TLE9BQU8sU0FBUztBQUNoQixPQUFPLGVBQWU7QUFDdEIsT0FBTyxnQkFBZ0I7QUFDdkIsT0FBTyxnQkFBZ0I7QUFDdkIsU0FBUywyQkFBMkI7QUFFcEMsSUFBTyxzQkFBUSxhQUFhLGFBQWE7QUFBQSxFQUN2QyxTQUFTO0FBQUEsSUFDUCxJQUFJO0FBQUEsSUFDSixVQUFVO0FBQUEsSUFDVixXQUFXO0FBQUEsTUFDVCxXQUFXLENBQUMsb0JBQW9CLENBQUM7QUFBQSxJQUNuQyxDQUFDO0FBQUEsSUFDRCxXQUFXO0FBQUEsTUFDVCxXQUFXLENBQUMsb0JBQW9CLENBQUM7QUFBQSxJQUNuQyxDQUFDO0FBQUEsRUFDSDtBQUFBO0FBQUE7QUFBQTtBQUFBLEVBS0EsYUFBYTtBQUFBO0FBQUEsRUFFYixRQUFRO0FBQUEsSUFDTixNQUFNO0FBQUEsSUFDTixZQUFZO0FBQUEsRUFDZDtBQUFBO0FBQUE7QUFBQSxFQUdBLFdBQVcsQ0FBQyxTQUFTLFFBQVE7QUFBQSxFQUM3QixPQUFPO0FBQUEsSUFDTCxlQUFlO0FBQUEsTUFDYixPQUFPLFNBQVMsWUFBWTtBQUMxQixZQUFJLFFBQVEsU0FBUyxxQkFBcUI7QUFDeEMscUJBQVcsT0FBTztBQUFBLFFBQ3BCO0FBQUEsTUFDRjtBQUFBLElBQ0Y7QUFBQSxJQUVBLGVBQWU7QUFBQSxNQUNiLFVBQVU7QUFBQTtBQUFBLE1BRVY7QUFBQSxJQUNGO0FBQUEsRUFDRjtBQUNGLEVBQUU7IiwKICAibmFtZXMiOiBbXQp9Cg== 50 | --------------------------------------------------------------------------------