feat: implement settings page

main
imspace 2023-03-07 03:36:06 +08:00
parent a98e02f15e
commit 4a081e1237
10 changed files with 666 additions and 379 deletions

View File

@ -8,5 +8,8 @@ indent_style = space
indent_size = 2 indent_size = 2
end_of_line = lf end_of_line = lf
charset = utf-8 charset = utf-8
trim_trailing_whitespace = false trim_trailing_whitespace = true
insert_final_newline = false insert_final_newline = true
[*.rs]
indent_size = 4

View File

@ -12,6 +12,7 @@
}, },
"dependencies": { "dependencies": {
"@tauri-apps/api": "^1.2.0", "@tauri-apps/api": "^1.2.0",
"classnames": "^2.3.2",
"daisyui": "^2.51.3", "daisyui": "^2.51.3",
"i18next": "^22.4.10", "i18next": "^22.4.10",
"i18next-browser-languagedetector": "^7.0.1", "i18next-browser-languagedetector": "^7.0.1",

View File

@ -10,6 +10,7 @@ specifiers:
'@types/react-dom': ^18.0.6 '@types/react-dom': ^18.0.6
'@vitejs/plugin-react': ^3.1.0 '@vitejs/plugin-react': ^3.1.0
autoprefixer: ^10.4.13 autoprefixer: ^10.4.13
classnames: ^2.3.2
daisyui: ^2.51.3 daisyui: ^2.51.3
eslint: ^8.35.0 eslint: ^8.35.0
eslint-config-react-app: ^7.0.1 eslint-config-react-app: ^7.0.1
@ -29,6 +30,7 @@ specifiers:
dependencies: dependencies:
'@tauri-apps/api': 1.2.0 '@tauri-apps/api': 1.2.0
classnames: registry.npmmirror.com/classnames/2.3.2
daisyui: 2.51.3_gbtt6ss3tbiz4yjtvdr6fbrj44 daisyui: 2.51.3_gbtt6ss3tbiz4yjtvdr6fbrj44
i18next: 22.4.10 i18next: 22.4.10
i18next-browser-languagedetector: 7.0.1 i18next-browser-languagedetector: 7.0.1
@ -48,7 +50,7 @@ devDependencies:
eslint: 8.35.0 eslint: 8.35.0
eslint-config-react-app: 7.0.1_ycpbpc6yetojsgtrx3mwntkhsu eslint-config-react-app: 7.0.1_ycpbpc6yetojsgtrx3mwntkhsu
postcss: 8.4.21 postcss: 8.4.21
tailwindcss: 3.2.7_postcss@8.4.21 tailwindcss: 3.2.7
typescript: 4.9.5 typescript: 4.9.5
vite: 4.1.4_@types+node@18.14.5 vite: 4.1.4_@types+node@18.14.5
vite-plugin-eslint: 1.8.1_eslint@8.35.0+vite@4.1.4 vite-plugin-eslint: 1.8.1_eslint@8.35.0+vite@4.1.4
@ -1415,204 +1417,6 @@ packages:
to-fast-properties: 2.0.0 to-fast-properties: 2.0.0
dev: true dev: true
/@esbuild/android-arm/0.16.17:
resolution: {integrity: sha512-N9x1CMXVhtWEAMS7pNNONyA14f71VPQN9Cnavj1XQh6T7bskqiLLrSca4O0Vr8Wdcga943eThxnVp3JLnBMYtw==}
engines: {node: '>=12'}
cpu: [arm]
os: [android]
requiresBuild: true
dev: true
optional: true
/@esbuild/android-arm64/0.16.17:
resolution: {integrity: sha512-MIGl6p5sc3RDTLLkYL1MyL8BMRN4tLMRCn+yRJJmEDvYZ2M7tmAf80hx1kbNEUX2KJ50RRtxZ4JHLvCfuB6kBg==}
engines: {node: '>=12'}
cpu: [arm64]
os: [android]
requiresBuild: true
dev: true
optional: true
/@esbuild/android-x64/0.16.17:
resolution: {integrity: sha512-a3kTv3m0Ghh4z1DaFEuEDfz3OLONKuFvI4Xqczqx4BqLyuFaFkuaG4j2MtA6fuWEFeC5x9IvqnX7drmRq/fyAQ==}
engines: {node: '>=12'}
cpu: [x64]
os: [android]
requiresBuild: true
dev: true
optional: true
/@esbuild/darwin-arm64/0.16.17:
resolution: {integrity: sha512-/2agbUEfmxWHi9ARTX6OQ/KgXnOWfsNlTeLcoV7HSuSTv63E4DqtAc+2XqGw1KHxKMHGZgbVCZge7HXWX9Vn+w==}
engines: {node: '>=12'}
cpu: [arm64]
os: [darwin]
requiresBuild: true
dev: true
optional: true
/@esbuild/darwin-x64/0.16.17:
resolution: {integrity: sha512-2By45OBHulkd9Svy5IOCZt376Aa2oOkiE9QWUK9fe6Tb+WDr8hXL3dpqi+DeLiMed8tVXspzsTAvd0jUl96wmg==}
engines: {node: '>=12'}
cpu: [x64]
os: [darwin]
requiresBuild: true
dev: true
optional: true
/@esbuild/freebsd-arm64/0.16.17:
resolution: {integrity: sha512-mt+cxZe1tVx489VTb4mBAOo2aKSnJ33L9fr25JXpqQqzbUIw/yzIzi+NHwAXK2qYV1lEFp4OoVeThGjUbmWmdw==}
engines: {node: '>=12'}
cpu: [arm64]
os: [freebsd]
requiresBuild: true
dev: true
optional: true
/@esbuild/freebsd-x64/0.16.17:
resolution: {integrity: sha512-8ScTdNJl5idAKjH8zGAsN7RuWcyHG3BAvMNpKOBaqqR7EbUhhVHOqXRdL7oZvz8WNHL2pr5+eIT5c65kA6NHug==}
engines: {node: '>=12'}
cpu: [x64]
os: [freebsd]
requiresBuild: true
dev: true
optional: true
/@esbuild/linux-arm/0.16.17:
resolution: {integrity: sha512-iihzrWbD4gIT7j3caMzKb/RsFFHCwqqbrbH9SqUSRrdXkXaygSZCZg1FybsZz57Ju7N/SHEgPyaR0LZ8Zbe9gQ==}
engines: {node: '>=12'}
cpu: [arm]
os: [linux]
requiresBuild: true
dev: true
optional: true
/@esbuild/linux-arm64/0.16.17:
resolution: {integrity: sha512-7S8gJnSlqKGVJunnMCrXHU9Q8Q/tQIxk/xL8BqAP64wchPCTzuM6W3Ra8cIa1HIflAvDnNOt2jaL17vaW+1V0g==}
engines: {node: '>=12'}
cpu: [arm64]
os: [linux]
requiresBuild: true
dev: true
optional: true
/@esbuild/linux-ia32/0.16.17:
resolution: {integrity: sha512-kiX69+wcPAdgl3Lonh1VI7MBr16nktEvOfViszBSxygRQqSpzv7BffMKRPMFwzeJGPxcio0pdD3kYQGpqQ2SSg==}
engines: {node: '>=12'}
cpu: [ia32]
os: [linux]
requiresBuild: true
dev: true
optional: true
/@esbuild/linux-loong64/0.16.17:
resolution: {integrity: sha512-dTzNnQwembNDhd654cA4QhbS9uDdXC3TKqMJjgOWsC0yNCbpzfWoXdZvp0mY7HU6nzk5E0zpRGGx3qoQg8T2DQ==}
engines: {node: '>=12'}
cpu: [loong64]
os: [linux]
requiresBuild: true
dev: true
optional: true
/@esbuild/linux-mips64el/0.16.17:
resolution: {integrity: sha512-ezbDkp2nDl0PfIUn0CsQ30kxfcLTlcx4Foz2kYv8qdC6ia2oX5Q3E/8m6lq84Dj/6b0FrkgD582fJMIfHhJfSw==}
engines: {node: '>=12'}
cpu: [mips64el]
os: [linux]
requiresBuild: true
dev: true
optional: true
/@esbuild/linux-ppc64/0.16.17:
resolution: {integrity: sha512-dzS678gYD1lJsW73zrFhDApLVdM3cUF2MvAa1D8K8KtcSKdLBPP4zZSLy6LFZ0jYqQdQ29bjAHJDgz0rVbLB3g==}
engines: {node: '>=12'}
cpu: [ppc64]
os: [linux]
requiresBuild: true
dev: true
optional: true
/@esbuild/linux-riscv64/0.16.17:
resolution: {integrity: sha512-ylNlVsxuFjZK8DQtNUwiMskh6nT0vI7kYl/4fZgV1llP5d6+HIeL/vmmm3jpuoo8+NuXjQVZxmKuhDApK0/cKw==}
engines: {node: '>=12'}
cpu: [riscv64]
os: [linux]
requiresBuild: true
dev: true
optional: true
/@esbuild/linux-s390x/0.16.17:
resolution: {integrity: sha512-gzy7nUTO4UA4oZ2wAMXPNBGTzZFP7mss3aKR2hH+/4UUkCOyqmjXiKpzGrY2TlEUhbbejzXVKKGazYcQTZWA/w==}
engines: {node: '>=12'}
cpu: [s390x]
os: [linux]
requiresBuild: true
dev: true
optional: true
/@esbuild/linux-x64/0.16.17:
resolution: {integrity: sha512-mdPjPxfnmoqhgpiEArqi4egmBAMYvaObgn4poorpUaqmvzzbvqbowRllQ+ZgzGVMGKaPkqUmPDOOFQRUFDmeUw==}
engines: {node: '>=12'}
cpu: [x64]
os: [linux]
requiresBuild: true
dev: true
optional: true
/@esbuild/netbsd-x64/0.16.17:
resolution: {integrity: sha512-/PzmzD/zyAeTUsduZa32bn0ORug+Jd1EGGAUJvqfeixoEISYpGnAezN6lnJoskauoai0Jrs+XSyvDhppCPoKOA==}
engines: {node: '>=12'}
cpu: [x64]
os: [netbsd]
requiresBuild: true
dev: true
optional: true
/@esbuild/openbsd-x64/0.16.17:
resolution: {integrity: sha512-2yaWJhvxGEz2RiftSk0UObqJa/b+rIAjnODJgv2GbGGpRwAfpgzyrg1WLK8rqA24mfZa9GvpjLcBBg8JHkoodg==}
engines: {node: '>=12'}
cpu: [x64]
os: [openbsd]
requiresBuild: true
dev: true
optional: true
/@esbuild/sunos-x64/0.16.17:
resolution: {integrity: sha512-xtVUiev38tN0R3g8VhRfN7Zl42YCJvyBhRKw1RJjwE1d2emWTVToPLNEQj/5Qxc6lVFATDiy6LjVHYhIPrLxzw==}
engines: {node: '>=12'}
cpu: [x64]
os: [sunos]
requiresBuild: true
dev: true
optional: true
/@esbuild/win32-arm64/0.16.17:
resolution: {integrity: sha512-ga8+JqBDHY4b6fQAmOgtJJue36scANy4l/rL97W+0wYmijhxKetzZdKOJI7olaBaMhWt8Pac2McJdZLxXWUEQw==}
engines: {node: '>=12'}
cpu: [arm64]
os: [win32]
requiresBuild: true
dev: true
optional: true
/@esbuild/win32-ia32/0.16.17:
resolution: {integrity: sha512-WnsKaf46uSSF/sZhwnqE4L/F89AYNMiD4YtEcYekBt9Q7nj0DiId2XH2Ng2PHM54qi5oPrQ8luuzGszqi/veig==}
engines: {node: '>=12'}
cpu: [ia32]
os: [win32]
requiresBuild: true
dev: true
optional: true
/@esbuild/win32-x64/0.16.17:
resolution: {integrity: sha512-y+EHuSchhL7FjHgvQL/0fnnFmO4T1bhvWANX6gcnqTjtnKWbTvUMCpGnv2+t+31d7RzyEAYAd4u2fnIhHL6N/Q==}
engines: {node: '>=12'}
cpu: [x64]
os: [win32]
requiresBuild: true
dev: true
optional: true
/@eslint/eslintrc/2.0.0: /@eslint/eslintrc/2.0.0:
resolution: {integrity: sha512-fluIaaV+GyV24CCu/ggiHdV+j4RNh85yQnAYS/G2mZODZgGmmlrgCydjUcV3YvxCm9x8nMAfThsqTni4KiXT4A==} resolution: {integrity: sha512-fluIaaV+GyV24CCu/ggiHdV+j4RNh85yQnAYS/G2mZODZgGmmlrgCydjUcV3YvxCm9x8nMAfThsqTni4KiXT4A==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
@ -1739,101 +1543,20 @@ packages:
engines: {node: '>= 14.6.0', npm: '>= 6.6.0', yarn: '>= 1.19.1'} engines: {node: '>= 14.6.0', npm: '>= 6.6.0', yarn: '>= 1.19.1'}
dev: false dev: false
/@tauri-apps/cli-darwin-arm64/1.2.3:
resolution: {integrity: sha512-phJN3fN8FtZZwqXg08bcxfq1+X1JSDglLvRxOxB7VWPq+O5SuB8uLyssjJsu+PIhyZZnIhTGdjhzLSFhSXfLsw==}
engines: {node: '>= 10'}
cpu: [arm64]
os: [darwin]
requiresBuild: true
dev: true
optional: true
/@tauri-apps/cli-darwin-x64/1.2.3:
resolution: {integrity: sha512-jFZ/y6z8z6v4yliIbXKBXA7BJgtZVMsITmEXSuD6s5+eCOpDhQxbRkr6CA+FFfr+/r96rWSDSgDenDQuSvPAKw==}
engines: {node: '>= 10'}
cpu: [x64]
os: [darwin]
requiresBuild: true
dev: true
optional: true
/@tauri-apps/cli-linux-arm-gnueabihf/1.2.3:
resolution: {integrity: sha512-C7h5vqAwXzY0kRGSU00Fj8PudiDWFCiQqqUNI1N+fhCILrzWZB9TPBwdx33ZfXKt/U4+emdIoo/N34v3TiAOmQ==}
engines: {node: '>= 10'}
cpu: [arm]
os: [linux]
requiresBuild: true
dev: true
optional: true
/@tauri-apps/cli-linux-arm64-gnu/1.2.3:
resolution: {integrity: sha512-buf1c8sdkuUzVDkGPQpyUdAIIdn5r0UgXU6+H5fGPq/Xzt5K69JzXaeo6fHsZEZghbV0hOK+taKV4J0m30UUMQ==}
engines: {node: '>= 10'}
cpu: [arm64]
os: [linux]
requiresBuild: true
dev: true
optional: true
/@tauri-apps/cli-linux-arm64-musl/1.2.3:
resolution: {integrity: sha512-x88wPS9W5xAyk392vc4uNHcKBBvCp0wf4H9JFMF9OBwB7vfd59LbQCFcPSu8f0BI7bPrOsyHqspWHuFL8ojQEA==}
engines: {node: '>= 10'}
cpu: [arm64]
os: [linux]
requiresBuild: true
dev: true
optional: true
/@tauri-apps/cli-linux-x64-gnu/1.2.3:
resolution: {integrity: sha512-ZMz1jxEVe0B4/7NJnlPHmwmSIuwiD6ViXKs8F+OWWz2Y4jn5TGxWKFg7DLx5OwQTRvEIZxxT7lXHi5CuTNAxKg==}
engines: {node: '>= 10'}
cpu: [x64]
os: [linux]
requiresBuild: true
dev: true
optional: true
/@tauri-apps/cli-linux-x64-musl/1.2.3:
resolution: {integrity: sha512-B/az59EjJhdbZDzawEVox0LQu2ZHCZlk8rJf85AMIktIUoAZPFbwyiUv7/zjzA/sY6Nb58OSJgaPL2/IBy7E0A==}
engines: {node: '>= 10'}
cpu: [x64]
os: [linux]
requiresBuild: true
dev: true
optional: true
/@tauri-apps/cli-win32-ia32-msvc/1.2.3:
resolution: {integrity: sha512-ypdO1OdC5ugNJAKO2m3sb1nsd+0TSvMS9Tr5qN/ZSMvtSduaNwrcZ3D7G/iOIanrqu/Nl8t3LYlgPZGBKlw7Ng==}
engines: {node: '>= 10'}
cpu: [ia32]
os: [win32]
requiresBuild: true
dev: true
optional: true
/@tauri-apps/cli-win32-x64-msvc/1.2.3:
resolution: {integrity: sha512-CsbHQ+XhnV/2csOBBDVfH16cdK00gNyNYUW68isedmqcn8j+s0e9cQ1xXIqi+Hue3awp8g3ImYN5KPepf3UExw==}
engines: {node: '>= 10'}
cpu: [x64]
os: [win32]
requiresBuild: true
dev: true
optional: true
/@tauri-apps/cli/1.2.3: /@tauri-apps/cli/1.2.3:
resolution: {integrity: sha512-erxtXuPhMEGJPBtnhPILD4AjuT81GZsraqpFvXAmEJZ2p8P6t7MVBifCL8LznRknznM3jn90D3M8RNBP3wcXTw==} resolution: {integrity: sha512-erxtXuPhMEGJPBtnhPILD4AjuT81GZsraqpFvXAmEJZ2p8P6t7MVBifCL8LznRknznM3jn90D3M8RNBP3wcXTw==}
engines: {node: '>= 10'} engines: {node: '>= 10'}
hasBin: true hasBin: true
optionalDependencies: optionalDependencies:
'@tauri-apps/cli-darwin-arm64': 1.2.3 '@tauri-apps/cli-darwin-arm64': registry.npmmirror.com/@tauri-apps/cli-darwin-arm64/1.2.3
'@tauri-apps/cli-darwin-x64': 1.2.3 '@tauri-apps/cli-darwin-x64': registry.npmmirror.com/@tauri-apps/cli-darwin-x64/1.2.3
'@tauri-apps/cli-linux-arm-gnueabihf': 1.2.3 '@tauri-apps/cli-linux-arm-gnueabihf': registry.npmmirror.com/@tauri-apps/cli-linux-arm-gnueabihf/1.2.3
'@tauri-apps/cli-linux-arm64-gnu': 1.2.3 '@tauri-apps/cli-linux-arm64-gnu': registry.npmmirror.com/@tauri-apps/cli-linux-arm64-gnu/1.2.3
'@tauri-apps/cli-linux-arm64-musl': 1.2.3 '@tauri-apps/cli-linux-arm64-musl': registry.npmmirror.com/@tauri-apps/cli-linux-arm64-musl/1.2.3
'@tauri-apps/cli-linux-x64-gnu': 1.2.3 '@tauri-apps/cli-linux-x64-gnu': registry.npmmirror.com/@tauri-apps/cli-linux-x64-gnu/1.2.3
'@tauri-apps/cli-linux-x64-musl': 1.2.3 '@tauri-apps/cli-linux-x64-musl': registry.npmmirror.com/@tauri-apps/cli-linux-x64-musl/1.2.3
'@tauri-apps/cli-win32-ia32-msvc': 1.2.3 '@tauri-apps/cli-win32-ia32-msvc': registry.npmmirror.com/@tauri-apps/cli-win32-ia32-msvc/1.2.3
'@tauri-apps/cli-win32-x64-msvc': 1.2.3 '@tauri-apps/cli-win32-x64-msvc': registry.npmmirror.com/@tauri-apps/cli-win32-x64-msvc/1.2.3
dev: true dev: true
/@types/eslint/8.21.1: /@types/eslint/8.21.1:
@ -2359,7 +2082,7 @@ packages:
normalize-path: 3.0.0 normalize-path: 3.0.0
readdirp: 3.6.0 readdirp: 3.6.0
optionalDependencies: optionalDependencies:
fsevents: 2.3.2 fsevents: registry.npmmirror.com/fsevents/2.3.2
/color-convert/1.9.3: /color-convert/1.9.3:
resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==} resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==}
@ -2460,7 +2183,7 @@ packages:
css-selector-tokenizer: 0.8.0 css-selector-tokenizer: 0.8.0
postcss: 8.4.21 postcss: 8.4.21
postcss-js: 4.0.1_postcss@8.4.21 postcss-js: 4.0.1_postcss@8.4.21
tailwindcss: 3.2.7_postcss@8.4.21 tailwindcss: 3.2.7
transitivePeerDependencies: transitivePeerDependencies:
- ts-node - ts-node
dev: false dev: false
@ -2661,28 +2384,28 @@ packages:
hasBin: true hasBin: true
requiresBuild: true requiresBuild: true
optionalDependencies: optionalDependencies:
'@esbuild/android-arm': 0.16.17 '@esbuild/android-arm': registry.npmmirror.com/@esbuild/android-arm/0.16.17
'@esbuild/android-arm64': 0.16.17 '@esbuild/android-arm64': registry.npmmirror.com/@esbuild/android-arm64/0.16.17
'@esbuild/android-x64': 0.16.17 '@esbuild/android-x64': registry.npmmirror.com/@esbuild/android-x64/0.16.17
'@esbuild/darwin-arm64': 0.16.17 '@esbuild/darwin-arm64': registry.npmmirror.com/@esbuild/darwin-arm64/0.16.17
'@esbuild/darwin-x64': 0.16.17 '@esbuild/darwin-x64': registry.npmmirror.com/@esbuild/darwin-x64/0.16.17
'@esbuild/freebsd-arm64': 0.16.17 '@esbuild/freebsd-arm64': registry.npmmirror.com/@esbuild/freebsd-arm64/0.16.17
'@esbuild/freebsd-x64': 0.16.17 '@esbuild/freebsd-x64': registry.npmmirror.com/@esbuild/freebsd-x64/0.16.17
'@esbuild/linux-arm': 0.16.17 '@esbuild/linux-arm': registry.npmmirror.com/@esbuild/linux-arm/0.16.17
'@esbuild/linux-arm64': 0.16.17 '@esbuild/linux-arm64': registry.npmmirror.com/@esbuild/linux-arm64/0.16.17
'@esbuild/linux-ia32': 0.16.17 '@esbuild/linux-ia32': registry.npmmirror.com/@esbuild/linux-ia32/0.16.17
'@esbuild/linux-loong64': 0.16.17 '@esbuild/linux-loong64': registry.npmmirror.com/@esbuild/linux-loong64/0.16.17
'@esbuild/linux-mips64el': 0.16.17 '@esbuild/linux-mips64el': registry.npmmirror.com/@esbuild/linux-mips64el/0.16.17
'@esbuild/linux-ppc64': 0.16.17 '@esbuild/linux-ppc64': registry.npmmirror.com/@esbuild/linux-ppc64/0.16.17
'@esbuild/linux-riscv64': 0.16.17 '@esbuild/linux-riscv64': registry.npmmirror.com/@esbuild/linux-riscv64/0.16.17
'@esbuild/linux-s390x': 0.16.17 '@esbuild/linux-s390x': registry.npmmirror.com/@esbuild/linux-s390x/0.16.17
'@esbuild/linux-x64': 0.16.17 '@esbuild/linux-x64': registry.npmmirror.com/@esbuild/linux-x64/0.16.17
'@esbuild/netbsd-x64': 0.16.17 '@esbuild/netbsd-x64': registry.npmmirror.com/@esbuild/netbsd-x64/0.16.17
'@esbuild/openbsd-x64': 0.16.17 '@esbuild/openbsd-x64': registry.npmmirror.com/@esbuild/openbsd-x64/0.16.17
'@esbuild/sunos-x64': 0.16.17 '@esbuild/sunos-x64': registry.npmmirror.com/@esbuild/sunos-x64/0.16.17
'@esbuild/win32-arm64': 0.16.17 '@esbuild/win32-arm64': registry.npmmirror.com/@esbuild/win32-arm64/0.16.17
'@esbuild/win32-ia32': 0.16.17 '@esbuild/win32-ia32': registry.npmmirror.com/@esbuild/win32-ia32/0.16.17
'@esbuild/win32-x64': 0.16.17 '@esbuild/win32-x64': registry.npmmirror.com/@esbuild/win32-x64/0.16.17
dev: true dev: true
/escalade/3.1.1: /escalade/3.1.1:
@ -3120,13 +2843,6 @@ packages:
resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==}
dev: true dev: true
/fsevents/2.3.2:
resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==}
engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
os: [darwin]
requiresBuild: true
optional: true
/function-bind/1.1.1: /function-bind/1.1.1:
resolution: {integrity: sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==} resolution: {integrity: sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==}
@ -3832,7 +3548,7 @@ packages:
peerDependencies: peerDependencies:
postcss: ^8.0.0 postcss: ^8.0.0
dependencies: dependencies:
postcss: 8.4.21 postcss: registry.npmmirror.com/postcss/8.4.21
postcss-value-parser: 4.2.0 postcss-value-parser: 4.2.0
read-cache: 1.0.0 read-cache: 1.0.0
resolve: 1.22.1 resolve: 1.22.1
@ -3844,7 +3560,7 @@ packages:
postcss: ^8.4.21 postcss: ^8.4.21
dependencies: dependencies:
camelcase-css: 2.0.1 camelcase-css: 2.0.1
postcss: 8.4.21 postcss: registry.npmmirror.com/postcss/8.4.21
/postcss-load-config/3.1.4_postcss@8.4.21: /postcss-load-config/3.1.4_postcss@8.4.21:
resolution: {integrity: sha512-6DiM4E7v4coTE4uzA8U//WhtPwyhiim3eyjEMFCnUpzbrkK9wJHgKDT2mR+HbtSrd/NubVaYTOpSpjUl8NQeRg==} resolution: {integrity: sha512-6DiM4E7v4coTE4uzA8U//WhtPwyhiim3eyjEMFCnUpzbrkK9wJHgKDT2mR+HbtSrd/NubVaYTOpSpjUl8NQeRg==}
@ -3859,7 +3575,7 @@ packages:
optional: true optional: true
dependencies: dependencies:
lilconfig: 2.1.0 lilconfig: 2.1.0
postcss: 8.4.21 postcss: registry.npmmirror.com/postcss/8.4.21
yaml: 1.10.2 yaml: 1.10.2
/postcss-nested/6.0.0_postcss@8.4.21: /postcss-nested/6.0.0_postcss@8.4.21:
@ -3868,7 +3584,7 @@ packages:
peerDependencies: peerDependencies:
postcss: ^8.2.14 postcss: ^8.2.14
dependencies: dependencies:
postcss: 8.4.21 postcss: registry.npmmirror.com/postcss/8.4.21
postcss-selector-parser: 6.0.11 postcss-selector-parser: 6.0.11
/postcss-selector-parser/6.0.11: /postcss-selector-parser/6.0.11:
@ -4093,7 +3809,7 @@ packages:
engines: {node: '>=10.0.0'} engines: {node: '>=10.0.0'}
hasBin: true hasBin: true
optionalDependencies: optionalDependencies:
fsevents: 2.3.2 fsevents: registry.npmmirror.com/fsevents/2.3.2
dev: true dev: true
/rollup/3.18.0: /rollup/3.18.0:
@ -4101,7 +3817,7 @@ packages:
engines: {node: '>=14.18.0', npm: '>=8.0.0'} engines: {node: '>=14.18.0', npm: '>=8.0.0'}
hasBin: true hasBin: true
optionalDependencies: optionalDependencies:
fsevents: 2.3.2 fsevents: registry.npmmirror.com/fsevents/2.3.2
dev: true dev: true
/run-parallel/1.2.0: /run-parallel/1.2.0:
@ -4246,12 +3962,10 @@ packages:
resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==}
engines: {node: '>= 0.4'} engines: {node: '>= 0.4'}
/tailwindcss/3.2.7_postcss@8.4.21: /tailwindcss/3.2.7:
resolution: {integrity: sha512-B6DLqJzc21x7wntlH/GsZwEXTBttVSl1FtCzC8WP4oBc/NKef7kaax5jeihkkCEWc831/5NDJ9gRNDK6NEioQQ==} resolution: {integrity: sha512-B6DLqJzc21x7wntlH/GsZwEXTBttVSl1FtCzC8WP4oBc/NKef7kaax5jeihkkCEWc831/5NDJ9gRNDK6NEioQQ==}
engines: {node: '>=12.13.0'} engines: {node: '>=12.13.0'}
hasBin: true hasBin: true
peerDependencies:
postcss: ^8.0.9
dependencies: dependencies:
arg: 5.0.2 arg: 5.0.2
chokidar: 3.5.3 chokidar: 3.5.3
@ -4267,7 +3981,7 @@ packages:
normalize-path: 3.0.0 normalize-path: 3.0.0
object-hash: 3.0.0 object-hash: 3.0.0
picocolors: 1.0.0 picocolors: 1.0.0
postcss: 8.4.21 postcss: registry.npmmirror.com/postcss/8.4.21
postcss-import: 14.1.0_postcss@8.4.21 postcss-import: 14.1.0_postcss@8.4.21
postcss-js: 4.0.1_postcss@8.4.21 postcss-js: 4.0.1_postcss@8.4.21
postcss-load-config: 3.1.4_postcss@8.4.21 postcss-load-config: 3.1.4_postcss@8.4.21
@ -4396,7 +4110,7 @@ packages:
dependencies: dependencies:
browserslist: 4.21.5 browserslist: 4.21.5
escalade: 3.1.1 escalade: 3.1.1
picocolors: 1.0.0 picocolors: registry.npmmirror.com/picocolors/1.0.0
/uri-js/4.4.1: /uri-js/4.4.1:
resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==}
@ -4462,7 +4176,7 @@ packages:
resolve: 1.22.1 resolve: 1.22.1
rollup: 3.18.0 rollup: 3.18.0
optionalDependencies: optionalDependencies:
fsevents: 2.3.2 fsevents: registry.npmmirror.com/fsevents/2.3.2
dev: true dev: true
/void-elements/3.1.0: /void-elements/3.1.0:
@ -4538,3 +4252,391 @@ packages:
resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==}
engines: {node: '>=10'} engines: {node: '>=10'}
dev: true dev: true
registry.npmmirror.com/@esbuild/android-arm/0.16.17:
resolution: {integrity: sha512-N9x1CMXVhtWEAMS7pNNONyA14f71VPQN9Cnavj1XQh6T7bskqiLLrSca4O0Vr8Wdcga943eThxnVp3JLnBMYtw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@esbuild/android-arm/-/android-arm-0.16.17.tgz}
name: '@esbuild/android-arm'
version: 0.16.17
engines: {node: '>=12'}
cpu: [arm]
os: [android]
requiresBuild: true
dev: true
optional: true
registry.npmmirror.com/@esbuild/android-arm64/0.16.17:
resolution: {integrity: sha512-MIGl6p5sc3RDTLLkYL1MyL8BMRN4tLMRCn+yRJJmEDvYZ2M7tmAf80hx1kbNEUX2KJ50RRtxZ4JHLvCfuB6kBg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@esbuild/android-arm64/-/android-arm64-0.16.17.tgz}
name: '@esbuild/android-arm64'
version: 0.16.17
engines: {node: '>=12'}
cpu: [arm64]
os: [android]
requiresBuild: true
dev: true
optional: true
registry.npmmirror.com/@esbuild/android-x64/0.16.17:
resolution: {integrity: sha512-a3kTv3m0Ghh4z1DaFEuEDfz3OLONKuFvI4Xqczqx4BqLyuFaFkuaG4j2MtA6fuWEFeC5x9IvqnX7drmRq/fyAQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@esbuild/android-x64/-/android-x64-0.16.17.tgz}
name: '@esbuild/android-x64'
version: 0.16.17
engines: {node: '>=12'}
cpu: [x64]
os: [android]
requiresBuild: true
dev: true
optional: true
registry.npmmirror.com/@esbuild/darwin-arm64/0.16.17:
resolution: {integrity: sha512-/2agbUEfmxWHi9ARTX6OQ/KgXnOWfsNlTeLcoV7HSuSTv63E4DqtAc+2XqGw1KHxKMHGZgbVCZge7HXWX9Vn+w==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@esbuild/darwin-arm64/-/darwin-arm64-0.16.17.tgz}
name: '@esbuild/darwin-arm64'
version: 0.16.17
engines: {node: '>=12'}
cpu: [arm64]
os: [darwin]
requiresBuild: true
dev: true
optional: true
registry.npmmirror.com/@esbuild/darwin-x64/0.16.17:
resolution: {integrity: sha512-2By45OBHulkd9Svy5IOCZt376Aa2oOkiE9QWUK9fe6Tb+WDr8hXL3dpqi+DeLiMed8tVXspzsTAvd0jUl96wmg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@esbuild/darwin-x64/-/darwin-x64-0.16.17.tgz}
name: '@esbuild/darwin-x64'
version: 0.16.17
engines: {node: '>=12'}
cpu: [x64]
os: [darwin]
requiresBuild: true
dev: true
optional: true
registry.npmmirror.com/@esbuild/freebsd-arm64/0.16.17:
resolution: {integrity: sha512-mt+cxZe1tVx489VTb4mBAOo2aKSnJ33L9fr25JXpqQqzbUIw/yzIzi+NHwAXK2qYV1lEFp4OoVeThGjUbmWmdw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.16.17.tgz}
name: '@esbuild/freebsd-arm64'
version: 0.16.17
engines: {node: '>=12'}
cpu: [arm64]
os: [freebsd]
requiresBuild: true
dev: true
optional: true
registry.npmmirror.com/@esbuild/freebsd-x64/0.16.17:
resolution: {integrity: sha512-8ScTdNJl5idAKjH8zGAsN7RuWcyHG3BAvMNpKOBaqqR7EbUhhVHOqXRdL7oZvz8WNHL2pr5+eIT5c65kA6NHug==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@esbuild/freebsd-x64/-/freebsd-x64-0.16.17.tgz}
name: '@esbuild/freebsd-x64'
version: 0.16.17
engines: {node: '>=12'}
cpu: [x64]
os: [freebsd]
requiresBuild: true
dev: true
optional: true
registry.npmmirror.com/@esbuild/linux-arm/0.16.17:
resolution: {integrity: sha512-iihzrWbD4gIT7j3caMzKb/RsFFHCwqqbrbH9SqUSRrdXkXaygSZCZg1FybsZz57Ju7N/SHEgPyaR0LZ8Zbe9gQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@esbuild/linux-arm/-/linux-arm-0.16.17.tgz}
name: '@esbuild/linux-arm'
version: 0.16.17
engines: {node: '>=12'}
cpu: [arm]
os: [linux]
requiresBuild: true
dev: true
optional: true
registry.npmmirror.com/@esbuild/linux-arm64/0.16.17:
resolution: {integrity: sha512-7S8gJnSlqKGVJunnMCrXHU9Q8Q/tQIxk/xL8BqAP64wchPCTzuM6W3Ra8cIa1HIflAvDnNOt2jaL17vaW+1V0g==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@esbuild/linux-arm64/-/linux-arm64-0.16.17.tgz}
name: '@esbuild/linux-arm64'
version: 0.16.17
engines: {node: '>=12'}
cpu: [arm64]
os: [linux]
requiresBuild: true
dev: true
optional: true
registry.npmmirror.com/@esbuild/linux-ia32/0.16.17:
resolution: {integrity: sha512-kiX69+wcPAdgl3Lonh1VI7MBr16nktEvOfViszBSxygRQqSpzv7BffMKRPMFwzeJGPxcio0pdD3kYQGpqQ2SSg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@esbuild/linux-ia32/-/linux-ia32-0.16.17.tgz}
name: '@esbuild/linux-ia32'
version: 0.16.17
engines: {node: '>=12'}
cpu: [ia32]
os: [linux]
requiresBuild: true
dev: true
optional: true
registry.npmmirror.com/@esbuild/linux-loong64/0.16.17:
resolution: {integrity: sha512-dTzNnQwembNDhd654cA4QhbS9uDdXC3TKqMJjgOWsC0yNCbpzfWoXdZvp0mY7HU6nzk5E0zpRGGx3qoQg8T2DQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@esbuild/linux-loong64/-/linux-loong64-0.16.17.tgz}
name: '@esbuild/linux-loong64'
version: 0.16.17
engines: {node: '>=12'}
cpu: [loong64]
os: [linux]
requiresBuild: true
dev: true
optional: true
registry.npmmirror.com/@esbuild/linux-mips64el/0.16.17:
resolution: {integrity: sha512-ezbDkp2nDl0PfIUn0CsQ30kxfcLTlcx4Foz2kYv8qdC6ia2oX5Q3E/8m6lq84Dj/6b0FrkgD582fJMIfHhJfSw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@esbuild/linux-mips64el/-/linux-mips64el-0.16.17.tgz}
name: '@esbuild/linux-mips64el'
version: 0.16.17
engines: {node: '>=12'}
cpu: [mips64el]
os: [linux]
requiresBuild: true
dev: true
optional: true
registry.npmmirror.com/@esbuild/linux-ppc64/0.16.17:
resolution: {integrity: sha512-dzS678gYD1lJsW73zrFhDApLVdM3cUF2MvAa1D8K8KtcSKdLBPP4zZSLy6LFZ0jYqQdQ29bjAHJDgz0rVbLB3g==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@esbuild/linux-ppc64/-/linux-ppc64-0.16.17.tgz}
name: '@esbuild/linux-ppc64'
version: 0.16.17
engines: {node: '>=12'}
cpu: [ppc64]
os: [linux]
requiresBuild: true
dev: true
optional: true
registry.npmmirror.com/@esbuild/linux-riscv64/0.16.17:
resolution: {integrity: sha512-ylNlVsxuFjZK8DQtNUwiMskh6nT0vI7kYl/4fZgV1llP5d6+HIeL/vmmm3jpuoo8+NuXjQVZxmKuhDApK0/cKw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@esbuild/linux-riscv64/-/linux-riscv64-0.16.17.tgz}
name: '@esbuild/linux-riscv64'
version: 0.16.17
engines: {node: '>=12'}
cpu: [riscv64]
os: [linux]
requiresBuild: true
dev: true
optional: true
registry.npmmirror.com/@esbuild/linux-s390x/0.16.17:
resolution: {integrity: sha512-gzy7nUTO4UA4oZ2wAMXPNBGTzZFP7mss3aKR2hH+/4UUkCOyqmjXiKpzGrY2TlEUhbbejzXVKKGazYcQTZWA/w==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@esbuild/linux-s390x/-/linux-s390x-0.16.17.tgz}
name: '@esbuild/linux-s390x'
version: 0.16.17
engines: {node: '>=12'}
cpu: [s390x]
os: [linux]
requiresBuild: true
dev: true
optional: true
registry.npmmirror.com/@esbuild/linux-x64/0.16.17:
resolution: {integrity: sha512-mdPjPxfnmoqhgpiEArqi4egmBAMYvaObgn4poorpUaqmvzzbvqbowRllQ+ZgzGVMGKaPkqUmPDOOFQRUFDmeUw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@esbuild/linux-x64/-/linux-x64-0.16.17.tgz}
name: '@esbuild/linux-x64'
version: 0.16.17
engines: {node: '>=12'}
cpu: [x64]
os: [linux]
requiresBuild: true
dev: true
optional: true
registry.npmmirror.com/@esbuild/netbsd-x64/0.16.17:
resolution: {integrity: sha512-/PzmzD/zyAeTUsduZa32bn0ORug+Jd1EGGAUJvqfeixoEISYpGnAezN6lnJoskauoai0Jrs+XSyvDhppCPoKOA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@esbuild/netbsd-x64/-/netbsd-x64-0.16.17.tgz}
name: '@esbuild/netbsd-x64'
version: 0.16.17
engines: {node: '>=12'}
cpu: [x64]
os: [netbsd]
requiresBuild: true
dev: true
optional: true
registry.npmmirror.com/@esbuild/openbsd-x64/0.16.17:
resolution: {integrity: sha512-2yaWJhvxGEz2RiftSk0UObqJa/b+rIAjnODJgv2GbGGpRwAfpgzyrg1WLK8rqA24mfZa9GvpjLcBBg8JHkoodg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@esbuild/openbsd-x64/-/openbsd-x64-0.16.17.tgz}
name: '@esbuild/openbsd-x64'
version: 0.16.17
engines: {node: '>=12'}
cpu: [x64]
os: [openbsd]
requiresBuild: true
dev: true
optional: true
registry.npmmirror.com/@esbuild/sunos-x64/0.16.17:
resolution: {integrity: sha512-xtVUiev38tN0R3g8VhRfN7Zl42YCJvyBhRKw1RJjwE1d2emWTVToPLNEQj/5Qxc6lVFATDiy6LjVHYhIPrLxzw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@esbuild/sunos-x64/-/sunos-x64-0.16.17.tgz}
name: '@esbuild/sunos-x64'
version: 0.16.17
engines: {node: '>=12'}
cpu: [x64]
os: [sunos]
requiresBuild: true
dev: true
optional: true
registry.npmmirror.com/@esbuild/win32-arm64/0.16.17:
resolution: {integrity: sha512-ga8+JqBDHY4b6fQAmOgtJJue36scANy4l/rL97W+0wYmijhxKetzZdKOJI7olaBaMhWt8Pac2McJdZLxXWUEQw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@esbuild/win32-arm64/-/win32-arm64-0.16.17.tgz}
name: '@esbuild/win32-arm64'
version: 0.16.17
engines: {node: '>=12'}
cpu: [arm64]
os: [win32]
requiresBuild: true
dev: true
optional: true
registry.npmmirror.com/@esbuild/win32-ia32/0.16.17:
resolution: {integrity: sha512-WnsKaf46uSSF/sZhwnqE4L/F89AYNMiD4YtEcYekBt9Q7nj0DiId2XH2Ng2PHM54qi5oPrQ8luuzGszqi/veig==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@esbuild/win32-ia32/-/win32-ia32-0.16.17.tgz}
name: '@esbuild/win32-ia32'
version: 0.16.17
engines: {node: '>=12'}
cpu: [ia32]
os: [win32]
requiresBuild: true
dev: true
optional: true
registry.npmmirror.com/@esbuild/win32-x64/0.16.17:
resolution: {integrity: sha512-y+EHuSchhL7FjHgvQL/0fnnFmO4T1bhvWANX6gcnqTjtnKWbTvUMCpGnv2+t+31d7RzyEAYAd4u2fnIhHL6N/Q==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@esbuild/win32-x64/-/win32-x64-0.16.17.tgz}
name: '@esbuild/win32-x64'
version: 0.16.17
engines: {node: '>=12'}
cpu: [x64]
os: [win32]
requiresBuild: true
dev: true
optional: true
registry.npmmirror.com/@tauri-apps/cli-darwin-arm64/1.2.3:
resolution: {integrity: sha512-phJN3fN8FtZZwqXg08bcxfq1+X1JSDglLvRxOxB7VWPq+O5SuB8uLyssjJsu+PIhyZZnIhTGdjhzLSFhSXfLsw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@tauri-apps/cli-darwin-arm64/-/cli-darwin-arm64-1.2.3.tgz}
name: '@tauri-apps/cli-darwin-arm64'
version: 1.2.3
engines: {node: '>= 10'}
cpu: [arm64]
os: [darwin]
requiresBuild: true
dev: true
optional: true
registry.npmmirror.com/@tauri-apps/cli-darwin-x64/1.2.3:
resolution: {integrity: sha512-jFZ/y6z8z6v4yliIbXKBXA7BJgtZVMsITmEXSuD6s5+eCOpDhQxbRkr6CA+FFfr+/r96rWSDSgDenDQuSvPAKw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@tauri-apps/cli-darwin-x64/-/cli-darwin-x64-1.2.3.tgz}
name: '@tauri-apps/cli-darwin-x64'
version: 1.2.3
engines: {node: '>= 10'}
cpu: [x64]
os: [darwin]
requiresBuild: true
dev: true
optional: true
registry.npmmirror.com/@tauri-apps/cli-linux-arm-gnueabihf/1.2.3:
resolution: {integrity: sha512-C7h5vqAwXzY0kRGSU00Fj8PudiDWFCiQqqUNI1N+fhCILrzWZB9TPBwdx33ZfXKt/U4+emdIoo/N34v3TiAOmQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@tauri-apps/cli-linux-arm-gnueabihf/-/cli-linux-arm-gnueabihf-1.2.3.tgz}
name: '@tauri-apps/cli-linux-arm-gnueabihf'
version: 1.2.3
engines: {node: '>= 10'}
cpu: [arm]
os: [linux]
requiresBuild: true
dev: true
optional: true
registry.npmmirror.com/@tauri-apps/cli-linux-arm64-gnu/1.2.3:
resolution: {integrity: sha512-buf1c8sdkuUzVDkGPQpyUdAIIdn5r0UgXU6+H5fGPq/Xzt5K69JzXaeo6fHsZEZghbV0hOK+taKV4J0m30UUMQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@tauri-apps/cli-linux-arm64-gnu/-/cli-linux-arm64-gnu-1.2.3.tgz}
name: '@tauri-apps/cli-linux-arm64-gnu'
version: 1.2.3
engines: {node: '>= 10'}
cpu: [arm64]
os: [linux]
libc: [glibc]
requiresBuild: true
dev: true
optional: true
registry.npmmirror.com/@tauri-apps/cli-linux-arm64-musl/1.2.3:
resolution: {integrity: sha512-x88wPS9W5xAyk392vc4uNHcKBBvCp0wf4H9JFMF9OBwB7vfd59LbQCFcPSu8f0BI7bPrOsyHqspWHuFL8ojQEA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@tauri-apps/cli-linux-arm64-musl/-/cli-linux-arm64-musl-1.2.3.tgz}
name: '@tauri-apps/cli-linux-arm64-musl'
version: 1.2.3
engines: {node: '>= 10'}
cpu: [arm64]
os: [linux]
libc: [musl]
requiresBuild: true
dev: true
optional: true
registry.npmmirror.com/@tauri-apps/cli-linux-x64-gnu/1.2.3:
resolution: {integrity: sha512-ZMz1jxEVe0B4/7NJnlPHmwmSIuwiD6ViXKs8F+OWWz2Y4jn5TGxWKFg7DLx5OwQTRvEIZxxT7lXHi5CuTNAxKg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@tauri-apps/cli-linux-x64-gnu/-/cli-linux-x64-gnu-1.2.3.tgz}
name: '@tauri-apps/cli-linux-x64-gnu'
version: 1.2.3
engines: {node: '>= 10'}
cpu: [x64]
os: [linux]
libc: [glibc]
requiresBuild: true
dev: true
optional: true
registry.npmmirror.com/@tauri-apps/cli-linux-x64-musl/1.2.3:
resolution: {integrity: sha512-B/az59EjJhdbZDzawEVox0LQu2ZHCZlk8rJf85AMIktIUoAZPFbwyiUv7/zjzA/sY6Nb58OSJgaPL2/IBy7E0A==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@tauri-apps/cli-linux-x64-musl/-/cli-linux-x64-musl-1.2.3.tgz}
name: '@tauri-apps/cli-linux-x64-musl'
version: 1.2.3
engines: {node: '>= 10'}
cpu: [x64]
os: [linux]
libc: [musl]
requiresBuild: true
dev: true
optional: true
registry.npmmirror.com/@tauri-apps/cli-win32-ia32-msvc/1.2.3:
resolution: {integrity: sha512-ypdO1OdC5ugNJAKO2m3sb1nsd+0TSvMS9Tr5qN/ZSMvtSduaNwrcZ3D7G/iOIanrqu/Nl8t3LYlgPZGBKlw7Ng==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@tauri-apps/cli-win32-ia32-msvc/-/cli-win32-ia32-msvc-1.2.3.tgz}
name: '@tauri-apps/cli-win32-ia32-msvc'
version: 1.2.3
engines: {node: '>= 10'}
cpu: [ia32]
os: [win32]
requiresBuild: true
dev: true
optional: true
registry.npmmirror.com/@tauri-apps/cli-win32-x64-msvc/1.2.3:
resolution: {integrity: sha512-CsbHQ+XhnV/2csOBBDVfH16cdK00gNyNYUW68isedmqcn8j+s0e9cQ1xXIqi+Hue3awp8g3ImYN5KPepf3UExw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@tauri-apps/cli-win32-x64-msvc/-/cli-win32-x64-msvc-1.2.3.tgz}
name: '@tauri-apps/cli-win32-x64-msvc'
version: 1.2.3
engines: {node: '>= 10'}
cpu: [x64]
os: [win32]
requiresBuild: true
dev: true
optional: true
registry.npmmirror.com/classnames/2.3.2:
resolution: {integrity: sha512-CSbhY4cFEJRe6/GQzIk5qXZ4Jeg5pcsP7b5peFSDpffpe1cqjASH/n9UTjBwOp6XpMSTwQ8Za2K5V02ueA7Tmw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/classnames/-/classnames-2.3.2.tgz}
name: classnames
version: 2.3.2
dev: false
registry.npmmirror.com/fsevents/2.3.2:
resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/fsevents/-/fsevents-2.3.2.tgz}
name: fsevents
version: 2.3.2
engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
os: [darwin]
requiresBuild: true
optional: true
registry.npmmirror.com/nanoid/3.3.4:
resolution: {integrity: sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/nanoid/-/nanoid-3.3.4.tgz}
name: nanoid
version: 3.3.4
engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
hasBin: true
registry.npmmirror.com/picocolors/1.0.0:
resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/picocolors/-/picocolors-1.0.0.tgz}
name: picocolors
version: 1.0.0
registry.npmmirror.com/postcss/8.4.21:
resolution: {integrity: sha512-tP7u/Sn/dVxK2NnruI4H9BG+x+Wxz6oeZ1cJ8P6G/PZY0IKk4k/63TDsQf2kQq3+qoJeLm2kIBUNlZe3zgb4Zg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/postcss/-/postcss-8.4.21.tgz}
name: postcss
version: 8.4.21
engines: {node: ^10 || ^12 || >=14}
dependencies:
nanoid: registry.npmmirror.com/nanoid/3.3.4
picocolors: registry.npmmirror.com/picocolors/1.0.0
source-map-js: registry.npmmirror.com/source-map-js/1.0.2
registry.npmmirror.com/source-map-js/1.0.2:
resolution: {integrity: sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/source-map-js/-/source-map-js-1.0.2.tgz}
name: source-map-js
version: 1.0.2
engines: {node: '>=0.10.0'}

View File

@ -39,9 +39,9 @@
}, },
"fs": { "fs": {
"scope": [ "scope": [
"$APPCONFIG/*", "$APPCONFIG/**/*",
"$APPDATA/*", "$APPDATA/**/*",
"$APPCACHE/*" "$APPCACHE/**/*"
], ],
"all": true "all": true
}, },

View File

@ -0,0 +1,26 @@
import React from 'react'
import { useTranslation } from 'react-i18next'
import { AiOutlineWarning } from 'react-icons/ai'
type ErrorContentProps = {
error: any
retry?: () => void
}
export const ErrorContent: React.FC<ErrorContentProps> = ({ error, retry }) => {
const { t } = useTranslation();
if (!error) {
return <></>;
}
return <div className='w-full h-full flex justify-center items-center flex-col'>
<span className='inline-flex items-center'>
<AiOutlineWarning className='inline-block scale-[2] mr-4 justify-end flex-none' />
<div className='max-w-full break-all'>
<div>{t('发生了错误')}{retry && <button className='link link-info ml-1'>{t('重试')}</button>}</div>
{String(error)}
</div>
</span>
</div>
}

View File

@ -2,9 +2,7 @@ import { useState } from "react";
/** /**
* A hook that returns a promise and its state. * A hook that returns a promise and its state.
* *
* The promise is only created once, and the state is updated when the promise resolves or rejects.
*
* @param factory A function that returns a promise. * @param factory A function that returns a promise.
* @returns An object containing the promise's state and result. * @returns An object containing the promise's state and result.
* @example * @example
@ -20,21 +18,67 @@ import { useState } from "react";
* return <p>Result: {result}</p>; * return <p>Result: {result}</p>;
*/ */
export function usePromise<T>(factory: () => Promise<T>) { export function usePromise<T>(factory: () => Promise<T>) {
const [loading, setLoading] = useState(true); const init = () => {
const [result, setResult] = useState<T | undefined>(undefined);
const [error, setError] = useState<any | undefined>(undefined);
const [promise] = useState(() => {
const promise = factory(); const promise = factory();
if (!promise || typeof promise.then !== "function") { if (!promise || typeof promise.then !== "function") {
throw new Error("The factory function must return a promise."); throw new Error("The factory function must return a promise.");
} }
return promise return promise
.then(setResult) .then(r => {
.catch(setError) setResult(r);
.finally(() => {
setLoading(false); setLoading(false);
return r;
})
.catch(e => {
setError(e);
setLoading(false);
throw e;
}); });
}); }
const [loading, setLoading] = useState(true);
const [result, setResult] = useState<T | undefined>(undefined);
const [error, setError] = useState<any | undefined>(undefined);
const [promise, setPromise] = useState(init);
const retry = () => {
setLoading(true);
setResult(undefined);
setError(undefined);
setPromise(init);
}
return { loading, result, error, promise }; return { loading, result, error, promise, retry };
}
/**
* A hook that returns a promise and its state.
*/
export function usePromiseLazy<T, Args extends any[]>(factory: (...args: Args) => Promise<T>) {
const init = (promise: Promise<T>) => {
if (!promise || typeof promise.then !== "function") {
throw new Error("The factory function must return a promise.");
}
return promise
.then(r => {
setResult(r);
setLoading(false);
return r;
})
.catch(e => {
setError(e);
setLoading(false);
throw e;
});
}
const [loading, setLoading] = useState(false);
const [result, setResult] = useState<T | undefined>(undefined);
const [error, setError] = useState<any | undefined>(undefined);
const [promise, setPromise] = useState<Promise<T> | undefined>(undefined);
const execute = (...args: Args) => {
setLoading(true);
setResult(undefined);
setError(undefined);
setPromise(init(factory(...args)));
}
return [execute, { loading, result, error, promise }] as const;
} }

View File

@ -1,41 +1,105 @@
import { ErrorContent } from 'components/ErrorContent';
import { Loading } from 'components/Loading'; import { Loading } from 'components/Loading';
import { usePromise } from 'hooks/usePromise'; import { usePromise, usePromiseLazy } from 'hooks/usePromise';
import React from 'react' import React, { useState } from 'react'
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { AiOutlineLeft } from 'react-icons/ai'; import { AiOutlineLeft } from 'react-icons/ai';
import { useNavigate } from 'react-router-dom'; import { useNavigate } from 'react-router-dom';
import { getConfig } from 'services/config'; import { Config, getConfig, getProfile, Profile, setConfig, setProfile } from 'services/config';
import { composeLoadable } from 'utils/composeLoadable';
import classNames from 'classnames';
export const Settings: React.FC = () => { const Page: React.FC<{ children?: React.ReactNode }> = ({ children }) => {
const { loading, result, error } = usePromise(getConfig);
const navigate = useNavigate();
const { t } = useTranslation(); const { t } = useTranslation();
const onSave = async () => { const navigate = useNavigate();
} return <div className='card m-2 h-full'>
<h2 className="card-title" data-tauri-drag-region><button onClick={() => navigate('/')}><AiOutlineLeft /></button>{t('配置')}</h2>
{children}
</div>
}
if (loading) { type FormData = {
return <div className='h-full flex items-center justify-center'><Loading /></div> config: Config,
} profile: Profile,
}
const Form: React.FC<{
oldValue: FormData,
onSaved?: () => void,
}> = ({ oldValue, onSaved }) => {
const { t } = useTranslation();
const [value, setValue] = useState(oldValue);
const changed = JSON.stringify(value) !== JSON.stringify(oldValue);
const [onSave, { loading, error }] = usePromiseLazy(async () => {
await setProfile(0, value.profile);
await setConfig(value.config);
onSaved?.();
})
return <> return <>
<div className='card m-2 h-full'> <div className='card'>
<h2 className="card-title" data-tauri-drag-region><button onClick={() => navigate('/')}><AiOutlineLeft /></button>{t('配置')}</h2> <div className="form-control w-full max-w-xs mb-4">
<div className='card'> <label className="label">
<div className="form-control w-full max-w-xs mb-4"> <span className="label-text">{t('stat.ink API密钥')}</span>
<label className="label"> <span className="label-text-alt"><a
<span className="label-text">{t('stat.ink API密钥')}</span> className='underline'
<span className="label-text-alt"><a target='_blank'
className='underline' rel='noopener noreferrer'
target='_blank' href='https://stat.ink/profile'
rel='noopener noreferrer' title={t('打开 stat.ink') ?? undefined}
href='https://stat.ink/profile' >{t('stat.ink')}</a></span>
title={t('打开 stat.ink') ?? undefined} </label>
>{t('stat.ink')}</a></span> <input
</label> className="input input-bordered w-full max-w-xs"
<input type="text" placeholder={t('长度为43') ?? undefined} className="input input-bordered w-full max-w-xs" /> type="text"
</div> placeholder={t('长度为43') ?? undefined}
value={value.profile.state.statInkApiKey ?? ''}
onChange={e => setValue({
...value,
profile: {
...value.profile,
state: {
...value.profile.state,
statInkApiKey: e.target.value,
}
}
})}
/>
</div> </div>
<button className='btn btn-primary w-20' onClick={onSave}>{t('保存')}</button> </div>
<ErrorContent error={error} />
<div className='flex gap-5'>
<button className={classNames('btn btn-primary w-[150px]', {
loading,
})} onClick={onSave} disabled={!changed}>{t('保存')}</button>
<button className={classNames('btn w-[150px]', {
loading,
})} onClick={() => setValue(oldValue)}>{t('重置')}</button>
</div> </div>
</> </>
} }
export const Settings: React.FC = () => {
let { loading, error, retry, result } = composeLoadable({
config: usePromise(getConfig),
profile: usePromise(() => getProfile(0)),
});
if (loading) {
return <Page>
<div className='h-full flex items-center justify-center'><Loading /></div>
</Page>
}
if (error) {
return <Page>
<ErrorContent error={error} retry={retry} />
</Page>
}
return <Page>
{result && <Form oldValue={result} onSaved={retry} />}
</Page>
}

View File

@ -12,6 +12,18 @@ export type Profile = {
export type Config = { export type Config = {
} }
// TODO: import from state.ts.
const DEFAULT_STATE: State = {
cacheDir: "./cache",
fGen: "https://api.imink.app/f",
fileExportPath: "./export",
monitorInterval: 500,
};
const defaultProfile: Profile = {
state: DEFAULT_STATE,
}
const defaultConfig: Config = { const defaultConfig: Config = {
} }
@ -22,8 +34,8 @@ export async function initFiles() {
initFiles().catch(console.error); initFiles().catch(console.error);
export async function getConfig(): Promise<Config> { export async function getConfig(): Promise<Config> {
const config = await fs.readTextFile(await configFile);
try { try {
const config = await fs.readTextFile(await configFile);
return JSON.parse(config); return JSON.parse(config);
} catch (e) { } catch (e) {
return defaultConfig; return defaultConfig;
@ -33,3 +45,16 @@ export async function getConfig(): Promise<Config> {
export async function setConfig(config: Config) { export async function setConfig(config: Config) {
await fs.writeTextFile(await configFile, JSON.stringify(config)); await fs.writeTextFile(await configFile, JSON.stringify(config));
} }
export async function getProfile(index: number): Promise<Profile> {
try {
const profile = await fs.readTextFile(await profileDir.then(c => join(c, `${index}.json`)));
return JSON.parse(profile);
} catch (e) {
return defaultProfile;
}
}
export async function setProfile(index: number, profile: Profile) {
await fs.writeTextFile(await profileDir.then(c => join(c, `${index}.json`)), JSON.stringify(profile));
}

View File

@ -0,0 +1,19 @@
export type Loadable<T> = {
loading: boolean;
result?: T;
error?: any;
retry?: () => void;
}
export function composeLoadable<T extends Record<string, Loadable<any>>>(map: T): Loadable<{
[P in keyof T]: T[P] extends Loadable<infer R> ? R : never
}> {
const values = Object.values(map)
const loading = values.some(v => v.loading);
const error = values.find(v => v.error)?.error;
const result = loading || error ? undefined : Object.fromEntries(Object.entries(map).map(([k, v]) => [k, v.result])) as any;
const retry = values.some(i => !!i.retry) ? () => Object.values(map).forEach(v => v.retry?.()) : undefined;
return { loading, result, error, retry };
}

3
gui/src/utils/sleep.ts Normal file
View File

@ -0,0 +1,3 @@
export function sleep(ms: number) {
return new Promise<void>(resolve => setTimeout(resolve, ms));
}