├── .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 |
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 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
101 |
--------------------------------------------------------------------------------
/src/assets/bars.svg:
--------------------------------------------------------------------------------
1 |
53 |
--------------------------------------------------------------------------------
/src/assets/fingerPanel.svg:
--------------------------------------------------------------------------------
1 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/src/components/ChordDraw.vue:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
115 |
116 |
137 |
--------------------------------------------------------------------------------
/src/components/ChordSelect.vue:
--------------------------------------------------------------------------------
1 |
28 |
29 |
30 |
34 |
35 | {{ greetMsg }}
36 |
37 |
--------------------------------------------------------------------------------
/src/components/Fingering.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
模拟15品吉他纸板
4 |
通过点击琴弦品格获取想要知道的和弦名
5 |
6 |
重置
7 |
8 |
9 |
现有六根弦各自音名: {{ chordNotes }}
10 |
11 |
{{ chordTone }}
12 |
不同根音可能的和弦名:{{ chordNameList }}
13 |
14 |
15 |
16 |
17 |
262 |
263 |
359 |
--------------------------------------------------------------------------------
/src/components/chordSelect.vue:
--------------------------------------------------------------------------------
1 |
108 |
109 |
110 |
111 |
112 |
125 |
{{ key }}
126 |
127 |
128 |
129 |
左右拖动可改变和弦组成音
130 |
131 |
三音和弦
132 |
四音和弦
133 |
134 |
137 |
138 |
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 |
--------------------------------------------------------------------------------