Compare commits
2 Commits
3b966c5655
...
7b06516cbe
| Author | SHA1 | Date |
|---|---|---|
|
|
7b06516cbe | |
|
|
8f8f4691c4 |
10
README.md
10
README.md
|
|
@ -38,6 +38,16 @@
|
||||||
- 窗口支持透明背景、置顶显示、圆角毛玻璃外观
|
- 窗口支持透明背景、置顶显示、圆角毛玻璃外观
|
||||||
- 设置通过 Pinia + 持久化插件跨会话保存
|
- 设置通过 Pinia + 持久化插件跨会话保存
|
||||||
|
|
||||||
|
## 界面预览
|
||||||
|
|
||||||
|
| 书架管理 | 书籍详情 |
|
||||||
|
| --- | --- |
|
||||||
|
|  |  |
|
||||||
|
|
||||||
|
| 幽灵阅读模式 | 阅读设置 |
|
||||||
|
| --- | --- |
|
||||||
|
|  |  |
|
||||||
|
|
||||||
## 技术栈
|
## 技术栈
|
||||||
|
|
||||||
| 层 | 技术 |
|
| 层 | 技术 |
|
||||||
|
|
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 65 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 32 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 75 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 141 KiB |
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"name": "stealthreader",
|
"name": "stealthreader",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "0.1.0",
|
"version": "0.3.0",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite",
|
"dev": "vite",
|
||||||
|
|
@ -13,7 +13,9 @@
|
||||||
"@tauri-apps/api": "^2",
|
"@tauri-apps/api": "^2",
|
||||||
"@tauri-apps/plugin-dialog": "^2.7.2",
|
"@tauri-apps/plugin-dialog": "^2.7.2",
|
||||||
"@tauri-apps/plugin-opener": "^2",
|
"@tauri-apps/plugin-opener": "^2",
|
||||||
|
"@tauri-apps/plugin-process": "^2.3.1",
|
||||||
"@tauri-apps/plugin-store": "~2.4.4",
|
"@tauri-apps/plugin-store": "~2.4.4",
|
||||||
|
"@tauri-apps/plugin-updater": "^2.10.1",
|
||||||
"axios": "^1.19.0",
|
"axios": "^1.19.0",
|
||||||
"dayjs": "^1.11.21",
|
"dayjs": "^1.11.21",
|
||||||
"naive-ui": "^2.45.0",
|
"naive-ui": "^2.45.0",
|
||||||
|
|
|
||||||
|
|
@ -17,12 +17,18 @@ importers:
|
||||||
'@tauri-apps/plugin-opener':
|
'@tauri-apps/plugin-opener':
|
||||||
specifier: ^2
|
specifier: ^2
|
||||||
version: 2.5.4
|
version: 2.5.4
|
||||||
|
'@tauri-apps/plugin-process':
|
||||||
|
specifier: ^2.3.1
|
||||||
|
version: 2.3.1
|
||||||
'@tauri-apps/plugin-store':
|
'@tauri-apps/plugin-store':
|
||||||
specifier: ~2.4.4
|
specifier: ~2.4.4
|
||||||
version: 2.4.4
|
version: 2.4.4
|
||||||
|
'@tauri-apps/plugin-updater':
|
||||||
|
specifier: ^2.10.1
|
||||||
|
version: 2.10.1
|
||||||
axios:
|
axios:
|
||||||
specifier: ^1.19.0
|
specifier: ^1.19.0
|
||||||
version: 1.19.0
|
version: 1.19.0(debug@4.4.3)
|
||||||
dayjs:
|
dayjs:
|
||||||
specifier: ^1.11.21
|
specifier: ^1.11.21
|
||||||
version: 1.11.23
|
version: 1.11.23
|
||||||
|
|
@ -440,9 +446,15 @@ packages:
|
||||||
'@tauri-apps/plugin-opener@2.5.4':
|
'@tauri-apps/plugin-opener@2.5.4':
|
||||||
resolution: {integrity: sha512-1HnPkb+AmgO29HBazm4uPLKB+r7zzcTBW1d0fyYp1uP+jwtpoiNDGKMMzz58SFp49nOIrxdE3aUJtT57lfO9CQ==}
|
resolution: {integrity: sha512-1HnPkb+AmgO29HBazm4uPLKB+r7zzcTBW1d0fyYp1uP+jwtpoiNDGKMMzz58SFp49nOIrxdE3aUJtT57lfO9CQ==}
|
||||||
|
|
||||||
|
'@tauri-apps/plugin-process@2.3.1':
|
||||||
|
resolution: {integrity: sha512-nCa4fGVaDL/B9ai03VyPOjfAHRHSBz5v6F/ObsB73r/dA3MHHhZtldaDMIc0V/pnUw9ehzr2iEG+XkSEyC0JJA==}
|
||||||
|
|
||||||
'@tauri-apps/plugin-store@2.4.4':
|
'@tauri-apps/plugin-store@2.4.4':
|
||||||
resolution: {integrity: sha512-oxSMaj/QpVfJcBMYX5aOQV94fWvga0MwQMfD6TLlbK2dh+ShPWAzefd8HWXhvOKjPRJdGVAkW7ZGO76JzzjaDA==}
|
resolution: {integrity: sha512-oxSMaj/QpVfJcBMYX5aOQV94fWvga0MwQMfD6TLlbK2dh+ShPWAzefd8HWXhvOKjPRJdGVAkW7ZGO76JzzjaDA==}
|
||||||
|
|
||||||
|
'@tauri-apps/plugin-updater@2.10.1':
|
||||||
|
resolution: {integrity: sha512-NFYMg+tWOZPJdzE/PpFj2qfqwAWwNS3kXrb1tm1gnBJ9mYzZ4WDRrwy8udzWoAnfGCHLuePNLY1WVCNHnh3eRA==}
|
||||||
|
|
||||||
'@types/estree@1.0.9':
|
'@types/estree@1.0.9':
|
||||||
resolution: {integrity: sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==}
|
resolution: {integrity: sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==}
|
||||||
|
|
||||||
|
|
@ -505,6 +517,11 @@ packages:
|
||||||
|
|
||||||
'@volar/typescript@2.4.28':
|
'@volar/typescript@2.4.28':
|
||||||
resolution: {integrity: sha512-Ja6yvWrbis2QtN4ClAKreeUZPVYMARDYZl9LMEv1iQ1QdepB6wn0jTRxA9MftYmYa4DQ4k/DaSZpFPUfxl8giw==}
|
resolution: {integrity: sha512-Ja6yvWrbis2QtN4ClAKreeUZPVYMARDYZl9LMEv1iQ1QdepB6wn0jTRxA9MftYmYa4DQ4k/DaSZpFPUfxl8giw==}
|
||||||
|
peerDependencies:
|
||||||
|
typescript: '*'
|
||||||
|
peerDependenciesMeta:
|
||||||
|
typescript:
|
||||||
|
optional: true
|
||||||
|
|
||||||
'@vue-macros/common@3.1.4':
|
'@vue-macros/common@3.1.4':
|
||||||
resolution: {integrity: sha512-/5Fv+6DgIcM9ajY05ZmKBv+LMX1M9A0X+IUwDRVdt67ciw8OV9bvG2r34p3RiEadlsQybjhKPRKNXDC8Bp23cw==}
|
resolution: {integrity: sha512-/5Fv+6DgIcM9ajY05ZmKBv+LMX1M9A0X+IUwDRVdt67ciw8OV9bvG2r34p3RiEadlsQybjhKPRKNXDC8Bp23cw==}
|
||||||
|
|
@ -1429,10 +1446,18 @@ snapshots:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@tauri-apps/api': 2.11.1
|
'@tauri-apps/api': 2.11.1
|
||||||
|
|
||||||
|
'@tauri-apps/plugin-process@2.3.1':
|
||||||
|
dependencies:
|
||||||
|
'@tauri-apps/api': 2.11.1
|
||||||
|
|
||||||
'@tauri-apps/plugin-store@2.4.4':
|
'@tauri-apps/plugin-store@2.4.4':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@tauri-apps/api': 2.11.1
|
'@tauri-apps/api': 2.11.1
|
||||||
|
|
||||||
|
'@tauri-apps/plugin-updater@2.10.1':
|
||||||
|
dependencies:
|
||||||
|
'@tauri-apps/api': 2.11.1
|
||||||
|
|
||||||
'@types/estree@1.0.9': {}
|
'@types/estree@1.0.9': {}
|
||||||
|
|
||||||
'@types/jsesc@2.5.1': {}
|
'@types/jsesc@2.5.1': {}
|
||||||
|
|
@ -1482,11 +1507,13 @@ snapshots:
|
||||||
|
|
||||||
'@volar/source-map@2.4.28': {}
|
'@volar/source-map@2.4.28': {}
|
||||||
|
|
||||||
'@volar/typescript@2.4.28':
|
'@volar/typescript@2.4.28(typescript@5.6.3)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@volar/language-core': 2.4.28
|
'@volar/language-core': 2.4.28
|
||||||
path-browserify: 1.0.1
|
path-browserify: 1.0.1
|
||||||
vscode-uri: 3.1.0
|
vscode-uri: 3.1.0
|
||||||
|
optionalDependencies:
|
||||||
|
typescript: 5.6.3
|
||||||
|
|
||||||
'@vue-macros/common@3.1.4(vue@3.5.41(typescript@5.6.3))':
|
'@vue-macros/common@3.1.4(vue@3.5.41(typescript@5.6.3))':
|
||||||
dependencies:
|
dependencies:
|
||||||
|
|
@ -1609,9 +1636,9 @@ snapshots:
|
||||||
|
|
||||||
asynckit@0.4.0: {}
|
asynckit@0.4.0: {}
|
||||||
|
|
||||||
axios@1.19.0:
|
axios@1.19.0(debug@4.4.3):
|
||||||
dependencies:
|
dependencies:
|
||||||
follow-redirects: 1.16.0
|
follow-redirects: 1.16.0(debug@4.4.3)
|
||||||
form-data: 4.0.6
|
form-data: 4.0.6
|
||||||
https-proxy-agent: 5.0.1
|
https-proxy-agent: 5.0.1
|
||||||
proxy-from-env: 2.1.0
|
proxy-from-env: 2.1.0
|
||||||
|
|
@ -1710,7 +1737,9 @@ snapshots:
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
picomatch: 4.0.5
|
picomatch: 4.0.5
|
||||||
|
|
||||||
follow-redirects@1.16.0: {}
|
follow-redirects@1.16.0(debug@4.4.3):
|
||||||
|
optionalDependencies:
|
||||||
|
debug: 4.4.3
|
||||||
|
|
||||||
form-data@4.0.6:
|
form-data@4.0.6:
|
||||||
dependencies:
|
dependencies:
|
||||||
|
|
@ -2149,7 +2178,7 @@ snapshots:
|
||||||
|
|
||||||
vue-tsc@3.3.10(typescript@5.6.3):
|
vue-tsc@3.3.10(typescript@5.6.3):
|
||||||
dependencies:
|
dependencies:
|
||||||
'@volar/typescript': 2.4.28
|
'@volar/typescript': 2.4.28(typescript@5.6.3)
|
||||||
'@vue/language-core': 3.3.10
|
'@vue/language-core': 3.3.10
|
||||||
typescript: 5.6.3
|
typescript: 5.6.3
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -53,6 +53,15 @@ version = "1.0.104"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "330a5ed07fa54e4702c9d6c4174f74427fc0ef6e214bbd677ae50a5099946470"
|
checksum = "330a5ed07fa54e4702c9d6c4174f74427fc0ef6e214bbd677ae50a5099946470"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "arbitrary"
|
||||||
|
version = "1.4.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c3d036a3c4ab069c7b410a2ce876bd74808d2d0888a82667669f8e783a898bf1"
|
||||||
|
dependencies = [
|
||||||
|
"derive_arbitrary",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "async-broadcast"
|
name = "async-broadcast"
|
||||||
version = "0.7.2"
|
version = "0.7.2"
|
||||||
|
|
@ -825,6 +834,17 @@ dependencies = [
|
||||||
"serde_core",
|
"serde_core",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "derive_arbitrary"
|
||||||
|
version = "1.4.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1e567bd82dcff979e4b03460c307b3cdc9e96fde3d73bed1496d2bc75d9dd62a"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 2.0.119",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "derive_more"
|
name = "derive_more"
|
||||||
version = "2.1.1"
|
version = "2.1.1"
|
||||||
|
|
@ -1153,6 +1173,16 @@ dependencies = [
|
||||||
"rustc_version",
|
"rustc_version",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "filetime"
|
||||||
|
version = "0.2.29"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5c287a33c7f0a620c38e641e7f60827713987b3c0f26e8ddc9462cc69cf75759"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "find-msvc-tools"
|
name = "find-msvc-tools"
|
||||||
version = "0.1.11"
|
version = "0.1.11"
|
||||||
|
|
@ -1783,6 +1813,21 @@ dependencies = [
|
||||||
"want",
|
"want",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hyper-rustls"
|
||||||
|
version = "0.27.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "33ca68d021ef39cf6463ab54c1d0f5daf03377b70561305bb89a8f83aab66e0f"
|
||||||
|
dependencies = [
|
||||||
|
"http",
|
||||||
|
"hyper",
|
||||||
|
"hyper-util",
|
||||||
|
"rustls",
|
||||||
|
"tokio",
|
||||||
|
"tokio-rustls",
|
||||||
|
"tower-service",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hyper-util"
|
name = "hyper-util"
|
||||||
version = "0.1.20"
|
version = "0.1.20"
|
||||||
|
|
@ -2105,6 +2150,36 @@ dependencies = [
|
||||||
"windows-sys 0.45.0",
|
"windows-sys 0.45.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "jni"
|
||||||
|
version = "0.22.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5efd9a482cf3a427f00d6b35f14332adc7902ce91efb778580e180ff90fa3498"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"combine",
|
||||||
|
"jni-macros",
|
||||||
|
"jni-sys 0.4.1",
|
||||||
|
"log",
|
||||||
|
"simd_cesu8",
|
||||||
|
"thiserror 2.0.20",
|
||||||
|
"walkdir",
|
||||||
|
"windows-link 0.2.1",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "jni-macros"
|
||||||
|
version = "0.22.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a00109accc170f0bdb141fed3e393c565b6f5e072365c3bd58f5b062591560a3"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"rustc_version",
|
||||||
|
"simd_cesu8",
|
||||||
|
"syn 2.0.119",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "jni-sys"
|
name = "jni-sys"
|
||||||
version = "0.3.1"
|
version = "0.3.1"
|
||||||
|
|
@ -2315,6 +2390,12 @@ version = "0.3.17"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a"
|
checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "minisign-verify"
|
||||||
|
version = "0.2.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "22f9645cb765ea72b8111f36c522475d2daa0d22c957a9826437e97534bc4e9e"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "miniz_oxide"
|
name = "miniz_oxide"
|
||||||
version = "0.8.9"
|
version = "0.8.9"
|
||||||
|
|
@ -2580,6 +2661,18 @@ dependencies = [
|
||||||
"objc2-core-foundation",
|
"objc2-core-foundation",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "objc2-osa-kit"
|
||||||
|
version = "0.3.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f112d1746737b0da274ef79a23aac283376f335f4095a083a267a082f21db0c0"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags 2.13.1",
|
||||||
|
"objc2",
|
||||||
|
"objc2-app-kit",
|
||||||
|
"objc2-foundation",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "objc2-quartz-core"
|
name = "objc2-quartz-core"
|
||||||
version = "0.3.2"
|
version = "0.3.2"
|
||||||
|
|
@ -2713,6 +2806,20 @@ dependencies = [
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "osakit"
|
||||||
|
version = "0.3.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "732c71caeaa72c065bb69d7ea08717bd3f4863a4f451402fc9513e29dbd5261b"
|
||||||
|
dependencies = [
|
||||||
|
"objc2",
|
||||||
|
"objc2-foundation",
|
||||||
|
"objc2-osa-kit",
|
||||||
|
"serde",
|
||||||
|
"serde_json",
|
||||||
|
"thiserror 2.0.20",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pango"
|
name = "pango"
|
||||||
version = "0.18.3"
|
version = "0.18.3"
|
||||||
|
|
@ -3156,15 +3263,20 @@ dependencies = [
|
||||||
"http-body",
|
"http-body",
|
||||||
"http-body-util",
|
"http-body-util",
|
||||||
"hyper",
|
"hyper",
|
||||||
|
"hyper-rustls",
|
||||||
"hyper-util",
|
"hyper-util",
|
||||||
"js-sys",
|
"js-sys",
|
||||||
"log",
|
"log",
|
||||||
"percent-encoding",
|
"percent-encoding",
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
|
"rustls",
|
||||||
|
"rustls-pki-types",
|
||||||
|
"rustls-platform-verifier",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"sync_wrapper",
|
"sync_wrapper",
|
||||||
"tokio",
|
"tokio",
|
||||||
|
"tokio-rustls",
|
||||||
"tokio-util",
|
"tokio-util",
|
||||||
"tower",
|
"tower",
|
||||||
"tower-http",
|
"tower-http",
|
||||||
|
|
@ -3200,6 +3312,20 @@ dependencies = [
|
||||||
"windows-sys 0.60.2",
|
"windows-sys 0.60.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ring"
|
||||||
|
version = "0.17.14"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
"cfg-if",
|
||||||
|
"getrandom 0.2.17",
|
||||||
|
"libc",
|
||||||
|
"untrusted",
|
||||||
|
"windows-sys 0.52.0",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustc-hash"
|
name = "rustc-hash"
|
||||||
version = "2.1.3"
|
version = "2.1.3"
|
||||||
|
|
@ -3228,6 +3354,79 @@ dependencies = [
|
||||||
"windows-sys 0.61.2",
|
"windows-sys 0.61.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rustls"
|
||||||
|
version = "0.23.43"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0283386ce02abc0151e1761d08802dfe86c173b0b494af5cbc086574e453da06"
|
||||||
|
dependencies = [
|
||||||
|
"once_cell",
|
||||||
|
"ring",
|
||||||
|
"rustls-pki-types",
|
||||||
|
"rustls-webpki",
|
||||||
|
"subtle",
|
||||||
|
"zeroize",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rustls-native-certs"
|
||||||
|
version = "0.8.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "dab5152771c58876a2146916e53e35057e1a4dfa2b9df0f0305b07f611fdea4d"
|
||||||
|
dependencies = [
|
||||||
|
"openssl-probe",
|
||||||
|
"rustls-pki-types",
|
||||||
|
"schannel",
|
||||||
|
"security-framework",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rustls-pki-types"
|
||||||
|
version = "1.15.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2f4925028c7eb5d1fcdaf196971378ed9d2c1c4efc7dc5d011256f76c99c0a96"
|
||||||
|
dependencies = [
|
||||||
|
"zeroize",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rustls-platform-verifier"
|
||||||
|
version = "0.7.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "26d1e2536ce4f35f4846aa13bff16bd0ff40157cdb14cc056c7b14ba41233ba0"
|
||||||
|
dependencies = [
|
||||||
|
"core-foundation",
|
||||||
|
"core-foundation-sys",
|
||||||
|
"jni 0.22.4",
|
||||||
|
"log",
|
||||||
|
"once_cell",
|
||||||
|
"rustls",
|
||||||
|
"rustls-native-certs",
|
||||||
|
"rustls-platform-verifier-android",
|
||||||
|
"rustls-webpki",
|
||||||
|
"security-framework",
|
||||||
|
"security-framework-sys",
|
||||||
|
"webpki-root-certs",
|
||||||
|
"windows-sys 0.61.2",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rustls-platform-verifier-android"
|
||||||
|
version = "0.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f87165f0995f63a9fbeea62b64d10b4d9d8e78ec6d7d51fb2125fda7bb36788f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rustls-webpki"
|
||||||
|
version = "0.103.15"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f3c3cf1d8b1e7d4927e2d154c3fcb02979afb9939629c62cd9048d4f07b60ac2"
|
||||||
|
dependencies = [
|
||||||
|
"ring",
|
||||||
|
"rustls-pki-types",
|
||||||
|
"untrusted",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustversion"
|
name = "rustversion"
|
||||||
version = "1.0.23"
|
version = "1.0.23"
|
||||||
|
|
@ -3575,6 +3774,22 @@ version = "0.3.10"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3a219298ac11a56ea9a6d2120044824d6f01aeb034955e7af7bc16858527deea"
|
checksum = "3a219298ac11a56ea9a6d2120044824d6f01aeb034955e7af7bc16858527deea"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "simd_cesu8"
|
||||||
|
version = "1.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "11031e251abf8611c80f460e19dbdeb54a66db918e49c65a7065b46ac7aec520"
|
||||||
|
dependencies = [
|
||||||
|
"rustc_version",
|
||||||
|
"simdutf8",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "simdutf8"
|
||||||
|
version = "0.1.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "siphasher"
|
name = "siphasher"
|
||||||
version = "1.0.3"
|
version = "1.0.3"
|
||||||
|
|
@ -3861,7 +4076,9 @@ dependencies = [
|
||||||
"tauri-helper",
|
"tauri-helper",
|
||||||
"tauri-plugin-dialog",
|
"tauri-plugin-dialog",
|
||||||
"tauri-plugin-opener",
|
"tauri-plugin-opener",
|
||||||
|
"tauri-plugin-process",
|
||||||
"tauri-plugin-store",
|
"tauri-plugin-store",
|
||||||
|
"tauri-plugin-updater",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -3905,6 +4122,12 @@ version = "0.11.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
|
checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "subtle"
|
||||||
|
version = "2.6.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "swift-rs"
|
name = "swift-rs"
|
||||||
version = "1.0.7"
|
version = "1.0.7"
|
||||||
|
|
@ -3999,7 +4222,7 @@ dependencies = [
|
||||||
"gdkwayland-sys",
|
"gdkwayland-sys",
|
||||||
"gdkx11-sys",
|
"gdkx11-sys",
|
||||||
"gtk",
|
"gtk",
|
||||||
"jni",
|
"jni 0.21.1",
|
||||||
"libc",
|
"libc",
|
||||||
"log",
|
"log",
|
||||||
"ndk",
|
"ndk",
|
||||||
|
|
@ -4032,6 +4255,17 @@ dependencies = [
|
||||||
"syn 2.0.119",
|
"syn 2.0.119",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tar"
|
||||||
|
version = "0.4.46"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3f6221d9a6003c78398e3b239969f352578258df48c8eb051caadae0015bc840"
|
||||||
|
dependencies = [
|
||||||
|
"filetime",
|
||||||
|
"libc",
|
||||||
|
"xattr",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "target-lexicon"
|
name = "target-lexicon"
|
||||||
version = "0.12.16"
|
version = "0.12.16"
|
||||||
|
|
@ -4055,7 +4289,7 @@ dependencies = [
|
||||||
"gtk",
|
"gtk",
|
||||||
"heck 0.5.0",
|
"heck 0.5.0",
|
||||||
"http",
|
"http",
|
||||||
"jni",
|
"jni 0.21.1",
|
||||||
"libc",
|
"libc",
|
||||||
"log",
|
"log",
|
||||||
"mime",
|
"mime",
|
||||||
|
|
@ -4246,6 +4480,16 @@ dependencies = [
|
||||||
"zbus",
|
"zbus",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tauri-plugin-process"
|
||||||
|
version = "2.3.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d55511a7bf6cd70c8767b02c97bf8134fa434daf3926cfc1be0a0f94132d165a"
|
||||||
|
dependencies = [
|
||||||
|
"tauri",
|
||||||
|
"tauri-plugin",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tauri-plugin-store"
|
name = "tauri-plugin-store"
|
||||||
version = "2.4.4"
|
version = "2.4.4"
|
||||||
|
|
@ -4262,6 +4506,39 @@ dependencies = [
|
||||||
"tracing",
|
"tracing",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tauri-plugin-updater"
|
||||||
|
version = "2.10.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "806d9dac662c2e4594ff03c647a552f2c9bd544e7d0f683ec58f872f952ce4af"
|
||||||
|
dependencies = [
|
||||||
|
"base64 0.22.1",
|
||||||
|
"dirs",
|
||||||
|
"flate2",
|
||||||
|
"futures-util",
|
||||||
|
"http",
|
||||||
|
"infer",
|
||||||
|
"log",
|
||||||
|
"minisign-verify",
|
||||||
|
"osakit",
|
||||||
|
"percent-encoding",
|
||||||
|
"reqwest",
|
||||||
|
"rustls",
|
||||||
|
"semver",
|
||||||
|
"serde",
|
||||||
|
"serde_json",
|
||||||
|
"tar",
|
||||||
|
"tauri",
|
||||||
|
"tauri-plugin",
|
||||||
|
"tempfile",
|
||||||
|
"thiserror 2.0.20",
|
||||||
|
"time",
|
||||||
|
"tokio",
|
||||||
|
"url",
|
||||||
|
"windows-sys 0.60.2",
|
||||||
|
"zip",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tauri-runtime"
|
name = "tauri-runtime"
|
||||||
version = "2.11.3"
|
version = "2.11.3"
|
||||||
|
|
@ -4272,7 +4549,7 @@ dependencies = [
|
||||||
"dpi",
|
"dpi",
|
||||||
"gtk",
|
"gtk",
|
||||||
"http",
|
"http",
|
||||||
"jni",
|
"jni 0.21.1",
|
||||||
"objc2",
|
"objc2",
|
||||||
"objc2-ui-kit",
|
"objc2-ui-kit",
|
||||||
"objc2-web-kit",
|
"objc2-web-kit",
|
||||||
|
|
@ -4295,7 +4572,7 @@ checksum = "4e6fac707727b7a2f48e4ded90976324267371073edbb415ffb73bb0458d203f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"gtk",
|
"gtk",
|
||||||
"http",
|
"http",
|
||||||
"jni",
|
"jni 0.21.1",
|
||||||
"log",
|
"log",
|
||||||
"objc2",
|
"objc2",
|
||||||
"objc2-app-kit",
|
"objc2-app-kit",
|
||||||
|
|
@ -4532,6 +4809,16 @@ dependencies = [
|
||||||
"syn 3.0.3",
|
"syn 3.0.3",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tokio-rustls"
|
||||||
|
version = "0.26.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1729aa945f29d91ba541258c8df89027d5792d85a8841fb65e8bf0f4ede4ef61"
|
||||||
|
dependencies = [
|
||||||
|
"rustls",
|
||||||
|
"tokio",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tokio-stream"
|
name = "tokio-stream"
|
||||||
version = "0.1.19"
|
version = "0.1.19"
|
||||||
|
|
@ -4878,6 +5165,12 @@ version = "1.13.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c6f5d3c3b1bf09027a88a6bc961fc00497d651009560b5463668dc81b0fa87a8"
|
checksum = "c6f5d3c3b1bf09027a88a6bc961fc00497d651009560b5463668dc81b0fa87a8"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "untrusted"
|
||||||
|
version = "0.9.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "url"
|
name = "url"
|
||||||
version = "2.5.8"
|
version = "2.5.8"
|
||||||
|
|
@ -5127,6 +5420,15 @@ dependencies = [
|
||||||
"system-deps",
|
"system-deps",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "webpki-root-certs"
|
||||||
|
version = "1.0.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b96554aa2acc8ccdb7e1c9a58a7a68dd5d13bccc69cd124cb09406db612a1c9b"
|
||||||
|
dependencies = [
|
||||||
|
"rustls-pki-types",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "webview2-com"
|
name = "webview2-com"
|
||||||
version = "0.38.2"
|
version = "0.38.2"
|
||||||
|
|
@ -5363,6 +5665,15 @@ dependencies = [
|
||||||
"windows-targets 0.42.2",
|
"windows-targets 0.42.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-sys"
|
||||||
|
version = "0.52.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
|
||||||
|
dependencies = [
|
||||||
|
"windows-targets 0.52.6",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows-sys"
|
name = "windows-sys"
|
||||||
version = "0.59.0"
|
version = "0.59.0"
|
||||||
|
|
@ -5658,7 +5969,7 @@ dependencies = [
|
||||||
"gtk",
|
"gtk",
|
||||||
"http",
|
"http",
|
||||||
"javascriptcore-rs",
|
"javascriptcore-rs",
|
||||||
"jni",
|
"jni 0.21.1",
|
||||||
"libc",
|
"libc",
|
||||||
"ndk",
|
"ndk",
|
||||||
"objc2",
|
"objc2",
|
||||||
|
|
@ -5705,6 +6016,16 @@ dependencies = [
|
||||||
"pkg-config",
|
"pkg-config",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "xattr"
|
||||||
|
version = "1.6.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "32e45ad4206f6d2479085147f02bc2ef834ac85886624a23575ae137c8aa8156"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"rustix",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "yoke"
|
name = "yoke"
|
||||||
version = "0.8.3"
|
version = "0.8.3"
|
||||||
|
|
@ -5819,6 +6140,12 @@ dependencies = [
|
||||||
"synstructure",
|
"synstructure",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "zeroize"
|
||||||
|
version = "1.9.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e13c156562582aa81c60cb29407084cdb54c4164760106ab78e6c5b0858cf64e"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zerotrie"
|
name = "zerotrie"
|
||||||
version = "0.2.5"
|
version = "0.2.5"
|
||||||
|
|
@ -5852,6 +6179,18 @@ dependencies = [
|
||||||
"syn 3.0.3",
|
"syn 3.0.3",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "zip"
|
||||||
|
version = "4.6.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "caa8cd6af31c3b31c6631b8f483848b91589021b28fffe50adada48d4f4d2ed1"
|
||||||
|
dependencies = [
|
||||||
|
"arbitrary",
|
||||||
|
"crc32fast",
|
||||||
|
"indexmap 2.14.0",
|
||||||
|
"memchr",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zmij"
|
name = "zmij"
|
||||||
version = "1.0.23"
|
version = "1.0.23"
|
||||||
|
|
|
||||||
|
|
@ -39,3 +39,5 @@ tauri-plugin-dialog = "2.7.2"
|
||||||
encoding_rs = "0.8.35"
|
encoding_rs = "0.8.35"
|
||||||
regex = "1.13.1"
|
regex = "1.13.1"
|
||||||
chardetng = "1.0.0"
|
chardetng = "1.0.0"
|
||||||
|
tauri-plugin-updater = "2.10.1"
|
||||||
|
tauri-plugin-process = "2.3.1"
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,10 @@
|
||||||
"core:window:allow-set-size",
|
"core:window:allow-set-size",
|
||||||
"opener:default",
|
"opener:default",
|
||||||
"dialog:default",
|
"dialog:default",
|
||||||
"dialog:allow-open"
|
"dialog:allow-open",
|
||||||
|
"updater:default",
|
||||||
|
"updater:allow-check",
|
||||||
|
"process:default",
|
||||||
|
"process:allow-restart"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,19 +1,23 @@
|
||||||
mod commands;
|
mod commands;
|
||||||
mod services;
|
|
||||||
mod models;
|
mod models;
|
||||||
|
mod services;
|
||||||
|
|
||||||
use tauri::Manager;
|
|
||||||
use commands::book::*;
|
use commands::book::*;
|
||||||
use services::db::init_pool;
|
use services::db::init_pool;
|
||||||
|
use tauri::Manager;
|
||||||
|
|
||||||
#[cfg_attr(mobile, tauri::mobile_entry_point)]
|
#[cfg_attr(mobile, tauri::mobile_entry_point)]
|
||||||
pub fn run() {
|
pub fn run() {
|
||||||
tauri::Builder::default()
|
tauri::Builder::default()
|
||||||
.plugin(tauri_plugin_opener::init())
|
.plugin(tauri_plugin_opener::init())
|
||||||
.plugin(tauri_plugin_dialog::init())
|
.plugin(tauri_plugin_dialog::init()) // 对话框插件
|
||||||
|
.plugin(tauri_plugin_updater::Builder::new().build()) // 更新插件
|
||||||
|
.plugin(tauri_plugin_process::init()) // 进程插件(更新后重启)
|
||||||
.setup(|app| {
|
.setup(|app| {
|
||||||
let pool = tauri::async_runtime::block_on(async {
|
let pool = tauri::async_runtime::block_on(async {
|
||||||
init_pool(app.handle()).await.expect("sqlite数据库连接池初始化失败!")
|
init_pool(app.handle())
|
||||||
|
.await
|
||||||
|
.expect("sqlite数据库连接池初始化失败!")
|
||||||
});
|
});
|
||||||
app.manage(pool);
|
app.manage(pool);
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"$schema": "https://schema.tauri.app/config/2",
|
"$schema": "https://schema.tauri.app/config/2",
|
||||||
"productName": "stealthreader",
|
"productName": "StealthReader",
|
||||||
"version": "0.2.0",
|
"version": "../package.json",
|
||||||
"identifier": "StealthReader",
|
"identifier": "StealthReader",
|
||||||
"build": {
|
"build": {
|
||||||
"beforeDevCommand": "pnpm dev",
|
"beforeDevCommand": "pnpm dev",
|
||||||
|
|
@ -32,13 +32,16 @@
|
||||||
},
|
},
|
||||||
"bundle": {
|
"bundle": {
|
||||||
"active": true,
|
"active": true,
|
||||||
|
"createUpdaterArtifacts": true,
|
||||||
"targets": "all",
|
"targets": "all",
|
||||||
"icon": [
|
"icon": ["icons/32x32.png", "icons/128x128.png", "icons/128x128@2x.png", "icons/icon.icns", "icons/icon.ico"]
|
||||||
"icons/32x32.png",
|
},
|
||||||
"icons/128x128.png",
|
"plugins": {
|
||||||
"icons/128x128@2x.png",
|
"updater": {
|
||||||
"icons/icon.icns",
|
"active": true,
|
||||||
"icons/icon.ico"
|
"dialog": true,
|
||||||
]
|
"endpoints": ["https://github.com/SparksFly91/StealthReader/releases/latest/download/latest.json"],
|
||||||
|
"pubkey": "dW50cnVzdGVkIGNvbW1lbnQ6IG1pbmlzaWduIHB1YmxpYyBrZXk6IDYyQjM0MUIxMDNGRkMxOUQKUldTZHdmOERzVUd6WWx5TzJlczBjU2dWSXdzSjhwVjRtOFJZUDJ2ajB1MHdTS1p3NmhuZlIwNloK"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,11 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { zhCN, dateZhCN } from "naive-ui"
|
import { zhCN, dateZhCN } from "naive-ui"
|
||||||
import GlobalLoading from "@/components/GlobalLoading.vue"
|
import GlobalLoading from "@/components/GlobalLoading.vue"
|
||||||
|
import { checkAndUpdate } from "@/utils/updater"
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
checkAndUpdate()
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,54 @@
|
||||||
|
import { check, type Update } from "@tauri-apps/plugin-updater"
|
||||||
|
import { ask } from "@tauri-apps/plugin-dialog"
|
||||||
|
import { relaunch } from "@tauri-apps/plugin-process"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新检查结果
|
||||||
|
* - updated:已确认更新并开始安装(随后应用重启)
|
||||||
|
* - none:当前已是最新版本
|
||||||
|
* - cancelled:存在更新但用户取消
|
||||||
|
* - error:检查或安装过程出错
|
||||||
|
*/
|
||||||
|
export type CheckUpdateResult = "updated" | "none" | "cancelled" | "error"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 仅检查是否有可用更新,返回 Update 对象或 null
|
||||||
|
*/
|
||||||
|
export async function checkUpdate(): Promise<Update | null> {
|
||||||
|
return await check()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 询问用户是否立即更新,确认后下载安装并重启应用
|
||||||
|
* @param update 更新对象
|
||||||
|
* @returns true=已确认并开始安装;false=用户取消
|
||||||
|
*/
|
||||||
|
export async function promptAndInstall(update: Update): Promise<boolean> {
|
||||||
|
const yes = await ask(
|
||||||
|
`发现新版本 ${update.version},是否现在更新?\n\n${update.body || ""}`,
|
||||||
|
{ title: "发现更新", kind: "info" }
|
||||||
|
)
|
||||||
|
if (!yes) return false
|
||||||
|
|
||||||
|
await update.downloadAndInstall()
|
||||||
|
await relaunch()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 一键检查并更新(完整流程)。
|
||||||
|
* 适合应用启动时静默调用:无更新、用户取消或出错均不打扰用户。
|
||||||
|
* @returns 更新结果状态
|
||||||
|
*/
|
||||||
|
export async function checkAndUpdate(): Promise<CheckUpdateResult> {
|
||||||
|
try {
|
||||||
|
const update = await check()
|
||||||
|
if (!update) return "none"
|
||||||
|
|
||||||
|
const installed = await promptAndInstall(update)
|
||||||
|
return installed ? "updated" : "cancelled"
|
||||||
|
} catch (error) {
|
||||||
|
console.error("检查更新失败:", error)
|
||||||
|
return "error"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -20,31 +20,44 @@
|
||||||
<n-descriptions-item label="总章节">{{ book?.total_chapters ?? 0 }}</n-descriptions-item>
|
<n-descriptions-item label="总章节">{{ book?.total_chapters ?? 0 }}</n-descriptions-item>
|
||||||
<n-descriptions-item label="总字数">{{ formatChars(book?.total_chars) }}</n-descriptions-item>
|
<n-descriptions-item label="总字数">{{ formatChars(book?.total_chars) }}</n-descriptions-item>
|
||||||
<n-descriptions-item label="导入时间">{{ formatTime(book?.create_time) }}</n-descriptions-item>
|
<n-descriptions-item label="导入时间">{{ formatTime(book?.create_time) }}</n-descriptions-item>
|
||||||
<n-descriptions-item label="上次阅读">{{ formatTime(book?.last_read_time) }}</n-descriptions-item>
|
|
||||||
<n-descriptions-item label="阅读进度">{{ readProgress }}</n-descriptions-item>
|
|
||||||
<n-descriptions-item label="简介" :span="2">
|
|
||||||
<n-popover
|
|
||||||
trigger="hover"
|
|
||||||
placement="bottom-start"
|
|
||||||
:show-arrow="true"
|
|
||||||
content-class="intro-popover-panel"
|
|
||||||
:content-style="{
|
|
||||||
width: '520px',
|
|
||||||
maxWidth: 'calc(100vw - 64px)',
|
|
||||||
maxHeight: '180px',
|
|
||||||
padding: '0',
|
|
||||||
overflow: 'hidden',
|
|
||||||
}"
|
|
||||||
>
|
|
||||||
<template #trigger>
|
|
||||||
<div class="intro-preview">{{ book?.introduction || "暂无简介" }}</div>
|
|
||||||
</template>
|
|
||||||
<n-scrollbar class="intro-popover-scrollbar" style="height: 180px">
|
|
||||||
<div class="intro-popover">{{ book?.introduction || "暂无简介" }}</div>
|
|
||||||
</n-scrollbar>
|
|
||||||
</n-popover>
|
|
||||||
</n-descriptions-item>
|
|
||||||
</n-descriptions>
|
</n-descriptions>
|
||||||
|
|
||||||
|
<div class="progress-row">
|
||||||
|
<n-button v-if="continueInfo" class="continue-btn" @click="continueRead">
|
||||||
|
<template #default>
|
||||||
|
<div class="continue-content">
|
||||||
|
<div class="continue-action">点击继续阅读</div>
|
||||||
|
<div class="continue-main">
|
||||||
|
<span class="continue-prefix">阅读到</span>
|
||||||
|
<span class="continue-title" :title="continueInfo.title">{{ continueTitle }}</span>
|
||||||
|
<span class="continue-percent">{{ continuePercent }}%</span>
|
||||||
|
</div>
|
||||||
|
<div class="continue-time">上次阅读 {{ formatTime(book?.last_read_time) }}</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</n-button>
|
||||||
|
<n-popover
|
||||||
|
class="intro-popover-wrap"
|
||||||
|
trigger="hover"
|
||||||
|
placement="bottom-start"
|
||||||
|
:show-arrow="true"
|
||||||
|
content-class="intro-popover-panel"
|
||||||
|
:content-style="{
|
||||||
|
width: '520px',
|
||||||
|
maxWidth: 'calc(100vw - 64px)',
|
||||||
|
maxHeight: '180px',
|
||||||
|
padding: '0',
|
||||||
|
overflow: 'hidden',
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<template #trigger>
|
||||||
|
<div class="intro-preview">{{ book?.introduction || "暂无简介" }}</div>
|
||||||
|
</template>
|
||||||
|
<n-scrollbar class="intro-popover-scrollbar" style="height: 180px">
|
||||||
|
<div class="intro-popover">{{ book?.introduction || "暂无简介" }}</div>
|
||||||
|
</n-scrollbar>
|
||||||
|
</n-popover>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
@ -137,6 +150,7 @@ const page = ref(1)
|
||||||
const limit = ref(50)
|
const limit = ref(50)
|
||||||
const loadingChapters = ref(false)
|
const loadingChapters = ref(false)
|
||||||
const keyword = ref("")
|
const keyword = ref("")
|
||||||
|
const lastReadChapter = ref<Chapters | null>(null)
|
||||||
|
|
||||||
const goBack = () => router.back()
|
const goBack = () => router.back()
|
||||||
|
|
||||||
|
|
@ -144,11 +158,30 @@ const readChapter = (ch: Chapters) => {
|
||||||
router.push({ name: "Reader", query: { id: ch.id } })
|
router.push({ name: "Reader", query: { id: ch.id } })
|
||||||
}
|
}
|
||||||
|
|
||||||
const readProgress = computed(() => {
|
const continueRead = () => {
|
||||||
|
const ch = lastReadChapter.value
|
||||||
|
if (ch) {
|
||||||
|
router.push({ name: "Reader", query: { id: ch.id } })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const continueInfo = computed(() => {
|
||||||
const b = book.value
|
const b = book.value
|
||||||
if (!b || b.total_chapters <= 0) return "—"
|
if (!b || b.last_read_chapter_id <= 0) return null
|
||||||
const percent = Math.round((b.last_read_chapter_id / b.total_chapters) * 100)
|
return lastReadChapter.value
|
||||||
return `第 ${b.last_read_chapter_id} 章 · ${percent}%`
|
})
|
||||||
|
|
||||||
|
const continueTitle = computed(() => {
|
||||||
|
const t = lastReadChapter.value?.title
|
||||||
|
if (!t) return ""
|
||||||
|
return t.length > 5 ? `${t.slice(0, 5)}…` : t
|
||||||
|
})
|
||||||
|
|
||||||
|
const continuePercent = computed(() => {
|
||||||
|
const b = book.value
|
||||||
|
const ch = lastReadChapter.value
|
||||||
|
if (!b || b.total_chapters <= 0 || !ch) return 0
|
||||||
|
return Math.round((ch.number / b.total_chapters) * 100)
|
||||||
})
|
})
|
||||||
|
|
||||||
const formatChars = (chars?: number) => {
|
const formatChars = (chars?: number) => {
|
||||||
|
|
@ -168,11 +201,25 @@ const loadBook = async () => {
|
||||||
const res = await withLoading(() => BookApi.detail(bookId.value), "加载中...")
|
const res = await withLoading(() => BookApi.detail(bookId.value), "加载中...")
|
||||||
if (res.code === 0) {
|
if (res.code === 0) {
|
||||||
book.value = res.data
|
book.value = res.data
|
||||||
|
if (res.data.last_read_chapter_id > 0) {
|
||||||
|
await loadLastReadChapter(res.data.last_read_chapter_id)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
message.error(res.msg)
|
message.error(res.msg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const loadLastReadChapter = async (chapterId: number) => {
|
||||||
|
try {
|
||||||
|
const res = await BookApi.chapterDetail(chapterId)
|
||||||
|
if (res.code === 0) {
|
||||||
|
lastReadChapter.value = res.data
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
lastReadChapter.value = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const loadChapters = async () => {
|
const loadChapters = async () => {
|
||||||
if (!bookId.value) return
|
if (!bookId.value) return
|
||||||
loadingChapters.value = true
|
loadingChapters.value = true
|
||||||
|
|
@ -277,17 +324,99 @@ onMounted(() => {
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.intro-popover-wrap {
|
||||||
|
flex: 1;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
.intro-preview {
|
.intro-preview {
|
||||||
|
box-sizing: border-box;
|
||||||
|
height: var(--progress-height);
|
||||||
|
min-width: 0;
|
||||||
line-height: 1.6;
|
line-height: 1.6;
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
color: var(--color-text-secondary);
|
color: var(--color-text-secondary);
|
||||||
word-break: break-all;
|
word-break: break-all;
|
||||||
white-space: pre-wrap;
|
white-space: pre-wrap;
|
||||||
display: -webkit-box;
|
|
||||||
-webkit-box-orient: vertical;
|
|
||||||
-webkit-line-clamp: 2;
|
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
cursor: help;
|
cursor: help;
|
||||||
|
padding: 10px 0;
|
||||||
|
border-radius: var(--radius-sm);
|
||||||
|
}
|
||||||
|
|
||||||
|
.progress-row {
|
||||||
|
--progress-height: 84px;
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-start;
|
||||||
|
gap: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.continue-btn {
|
||||||
|
box-sizing: border-box;
|
||||||
|
flex-shrink: 0;
|
||||||
|
width: 220px;
|
||||||
|
height: var(--progress-height);
|
||||||
|
border-radius: var(--radius-card);
|
||||||
|
padding: 10px 16px;
|
||||||
|
text-align: left;
|
||||||
|
transition: box-shadow 0.2s ease, background-color 0.2s ease;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
box-shadow: var(--shadow-card-hover);
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.n-button__content) {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.continue-content {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: flex-start;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 4px;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.continue-action {
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 600;
|
||||||
|
line-height: 1.4;
|
||||||
|
color: var(--color-text-primary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.continue-main {
|
||||||
|
display: flex;
|
||||||
|
align-items: baseline;
|
||||||
|
gap: 6px;
|
||||||
|
font-size: 13px;
|
||||||
|
line-height: 1.4;
|
||||||
|
}
|
||||||
|
|
||||||
|
.continue-prefix {
|
||||||
|
color: var(--color-text-secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.continue-title {
|
||||||
|
max-width: 5em;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
color: var(--color-text-primary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.continue-percent {
|
||||||
|
font-weight: 700;
|
||||||
|
color: var(--color-accent);
|
||||||
|
}
|
||||||
|
|
||||||
|
.continue-time {
|
||||||
|
font-size: 12px;
|
||||||
|
line-height: 1.4;
|
||||||
|
color: var(--color-text-secondary);
|
||||||
}
|
}
|
||||||
|
|
||||||
:global(.intro-popover-scrollbar .n-scrollbar-container) {
|
:global(.intro-popover-scrollbar .n-scrollbar-container) {
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,9 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="glass-panel" :style="readerStyle" data-tauri-drag-region @mousedown="onWindowMouseDown">
|
<div class="glass-panel" :style="readerStyle" data-tauri-drag-region @mousedown="onWindowMouseDown">
|
||||||
<div class="reading-wrap">
|
<div class="reading-wrap">
|
||||||
<div v-if="currentPage == 0" class="chapter-name">{{ chapter?.title || "加载中..." }}</div>
|
<div class="chapter-name" :class="{ 'chapter-name--hidden': currentPage !== 0 }">
|
||||||
|
{{ chapter?.title || "加载中..." }}
|
||||||
|
</div>
|
||||||
|
|
||||||
<div ref="pageEl" class="page-body" @click="onPageClick">
|
<div ref="pageEl" class="page-body" @click="onPageClick">
|
||||||
<div class="page-text">{{ currentText }}</div>
|
<div class="page-text">{{ currentText }}</div>
|
||||||
|
|
@ -252,6 +254,10 @@ onUnmounted(() => {
|
||||||
margin-bottom: 20px;
|
margin-bottom: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.chapter-name--hidden {
|
||||||
|
visibility: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
.page-body {
|
.page-body {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
min-height: 0;
|
min-height: 0;
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,156 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="setting-page">
|
<div class="setting-page">
|
||||||
<h2 class="page-title">关于</h2>
|
<h2 class="page-title">关于</h2>
|
||||||
<p class="page-desc">关于本应用的信息</p>
|
<p class="page-desc">关于幽灵阅读器</p>
|
||||||
|
|
||||||
<div class="about-card">
|
<div class="about-hero">
|
||||||
<div class="app-logo">幽</div>
|
<div class="about-logo">
|
||||||
<div class="app-name">幽灵阅读器</div>
|
<img :src="appIcon" alt="幽灵阅读器" />
|
||||||
<div class="app-version">版本 0.1.0</div>
|
</div>
|
||||||
<div class="app-desc">一款安静、沉浸的本地阅读器</div>
|
<div class="about-info">
|
||||||
|
<div class="about-name">幽灵阅读器</div>
|
||||||
|
<div class="about-subname">Stealth Reader</div>
|
||||||
|
<div class="about-meta">
|
||||||
|
<div class="about-version">版本 {{ version || "0.0.0" }}</div>
|
||||||
|
<n-button
|
||||||
|
class="check-update-btn"
|
||||||
|
size="tiny"
|
||||||
|
secondary
|
||||||
|
round
|
||||||
|
:loading="checkingUpdate"
|
||||||
|
@click="onCheckUpdate"
|
||||||
|
>
|
||||||
|
<template #icon>
|
||||||
|
<n-icon :component="SyncOutlined" />
|
||||||
|
</template>
|
||||||
|
{{ checkingUpdate ? "检查中..." : "检查更新" }}
|
||||||
|
</n-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="about-intro">
|
||||||
|
一款安静、本地优先的桌面小说阅读器。轻量、纯本地、无账号、无广告,专注「好好读一本书」。
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="about-section">
|
||||||
|
<div class="section-title">核心特性</div>
|
||||||
|
<div class="feature-list">
|
||||||
|
<div v-for="f in features" :key="f.title" class="feature-item">
|
||||||
|
<span class="feature-icon" :style="{ backgroundColor: f.bg }">
|
||||||
|
<n-icon :component="f.icon" :size="16" />
|
||||||
|
</span>
|
||||||
|
<div class="feature-body">
|
||||||
|
<div class="feature-title">{{ f.title }}</div>
|
||||||
|
<div class="feature-desc">{{ f.desc }}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="about-section">
|
||||||
|
<div class="section-title">技术栈</div>
|
||||||
|
<div class="tech-list">
|
||||||
|
<div v-for="t in tech" :key="t.name" class="tech-item">
|
||||||
|
<span class="tech-name">{{ t.name }}</span>
|
||||||
|
<span class="tech-desc">{{ t.desc }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="about-footer">
|
||||||
|
<span>© {{ year }} Stealth Reader</span>
|
||||||
|
<span>Apache-2.0 License</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts"></script>
|
<script setup lang="ts">
|
||||||
|
import { getVersion } from "@tauri-apps/api/app"
|
||||||
|
import {
|
||||||
|
BookOutlined,
|
||||||
|
FileTextOutlined,
|
||||||
|
FontColorsOutlined,
|
||||||
|
LockOutlined,
|
||||||
|
ScanOutlined,
|
||||||
|
SyncOutlined,
|
||||||
|
ThunderboltOutlined,
|
||||||
|
} from "@vicons/antd"
|
||||||
|
import appIcon from "../../../app-icon.svg"
|
||||||
|
import { checkAndUpdate } from "@/utils/updater"
|
||||||
|
|
||||||
|
const message = useMessage()
|
||||||
|
const year = new Date().getFullYear()
|
||||||
|
const version = ref("")
|
||||||
|
const checkingUpdate = ref(false)
|
||||||
|
|
||||||
|
getVersion().then((v) => {
|
||||||
|
version.value = v
|
||||||
|
})
|
||||||
|
|
||||||
|
const onCheckUpdate = async () => {
|
||||||
|
if (checkingUpdate.value) return
|
||||||
|
checkingUpdate.value = true
|
||||||
|
try {
|
||||||
|
const result = await checkAndUpdate()
|
||||||
|
if (result === "none") {
|
||||||
|
message.success("当前已是最新版本")
|
||||||
|
} else if (result === "error") {
|
||||||
|
message.error("检查更新失败,请稍后重试")
|
||||||
|
}
|
||||||
|
// updated:即将重启应用;cancelled:用户取消,无需提示
|
||||||
|
} finally {
|
||||||
|
checkingUpdate.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const features = [
|
||||||
|
{
|
||||||
|
title: "本地优先",
|
||||||
|
desc: "纯本地存储,数据不离开你的设备",
|
||||||
|
icon: LockOutlined,
|
||||||
|
bg: "color-mix(in srgb, #667eea 14%, transparent)",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "智能分章",
|
||||||
|
desc: "自动识别「第X章」「Chapter N」等章节格式",
|
||||||
|
icon: ScanOutlined,
|
||||||
|
bg: "color-mix(in srgb, #10b981 14%, transparent)",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "自动编码检测",
|
||||||
|
desc: "GBK / UTF-8 等中文编码自动识别",
|
||||||
|
icon: FileTextOutlined,
|
||||||
|
bg: "color-mix(in srgb, #f59e0b 14%, transparent)",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "沉浸阅读",
|
||||||
|
desc: "可拖拽窗口、透明背景、翻页阅读",
|
||||||
|
icon: BookOutlined,
|
||||||
|
bg: "color-mix(in srgb, #ec4899 14%, transparent)",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "外观自定义",
|
||||||
|
desc: "字体大小 / 颜色 / 背景随心调整",
|
||||||
|
icon: FontColorsOutlined,
|
||||||
|
bg: "color-mix(in srgb, #8b5cf6 14%, transparent)",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "轻量快速",
|
||||||
|
desc: "Tauri 2 构建,内存占用远低于 Electron",
|
||||||
|
icon: ThunderboltOutlined,
|
||||||
|
bg: "color-mix(in srgb, #06b6d4 14%, transparent)",
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
const tech = [
|
||||||
|
{ name: "桌面框架", desc: "Tauri 2 + Rust" },
|
||||||
|
{ name: "前端框架", desc: "Vue 3 + TypeScript" },
|
||||||
|
{ name: "UI 组件", desc: "Naive UI" },
|
||||||
|
{ name: "数据存储", desc: "SQLite (sqlx)" },
|
||||||
|
{ name: "编码检测", desc: "chardetng" },
|
||||||
|
]
|
||||||
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.setting-page {
|
.setting-page {
|
||||||
|
|
@ -33,48 +171,185 @@
|
||||||
color: var(--color-text-secondary);
|
color: var(--color-text-secondary);
|
||||||
}
|
}
|
||||||
|
|
||||||
.about-card {
|
.about-hero {
|
||||||
display: grid;
|
display: flex;
|
||||||
grid-template-columns: 52px minmax(0, 1fr);
|
|
||||||
column-gap: 14px;
|
|
||||||
align-items: center;
|
align-items: center;
|
||||||
min-height: 108px;
|
gap: 16px;
|
||||||
padding: 18px 16px;
|
padding: 20px 16px;
|
||||||
border-top: 1px solid var(--color-border);
|
border-top: 1px solid var(--color-border);
|
||||||
border-bottom: 1px solid var(--color-border);
|
border-bottom: 1px solid var(--color-border);
|
||||||
}
|
}
|
||||||
|
|
||||||
.app-logo {
|
.about-logo {
|
||||||
width: 52px;
|
width: 64px;
|
||||||
height: 52px;
|
height: 64px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
border-radius: 16px;
|
||||||
|
overflow: hidden;
|
||||||
|
box-shadow: var(--shadow-card);
|
||||||
|
|
||||||
|
img {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.about-info {
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.about-name {
|
||||||
|
font-size: 18px;
|
||||||
|
font-weight: 700;
|
||||||
|
color: var(--color-text-primary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.about-subname {
|
||||||
|
font-size: 13px;
|
||||||
|
color: var(--color-text-secondary);
|
||||||
|
margin-top: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.about-version {
|
||||||
|
display: inline-block;
|
||||||
|
margin-top: 6px;
|
||||||
|
padding: 1px 8px;
|
||||||
|
border-radius: 999px;
|
||||||
|
background-color: color-mix(in srgb, var(--color-accent) 12%, transparent);
|
||||||
|
color: var(--color-accent);
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.about-meta {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.check-update-btn {
|
||||||
|
margin-top: 6px;
|
||||||
|
font-weight: 500;
|
||||||
|
|
||||||
|
:deep(.n-button__icon) {
|
||||||
|
margin-right: 4px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.about-intro {
|
||||||
|
margin: 18px 0;
|
||||||
|
padding: 14px 16px;
|
||||||
|
border-radius: var(--radius-sm);
|
||||||
|
background-color: var(--color-window-bg);
|
||||||
|
font-size: 13px;
|
||||||
|
line-height: 1.7;
|
||||||
|
color: var(--color-text-secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.about-section {
|
||||||
|
& + & {
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-title {
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: var(--color-text-primary);
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.feature-list {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.feature-item {
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-start;
|
||||||
|
gap: 10px;
|
||||||
|
padding: 12px;
|
||||||
|
border: 1px solid var(--color-border);
|
||||||
|
border-radius: var(--radius-sm);
|
||||||
|
transition: border-color 0.2s ease, box-shadow 0.2s ease;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
border-color: var(--color-border-hover);
|
||||||
|
box-shadow: var(--shadow-card);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.feature-icon {
|
||||||
|
width: 32px;
|
||||||
|
height: 32px;
|
||||||
|
flex-shrink: 0;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
background: var(--color-accent-gradient);
|
color: var(--color-text-primary);
|
||||||
color: var(--color-text-invert);
|
|
||||||
font-size: 22px;
|
|
||||||
font-weight: 700;
|
|
||||||
grid-row: span 2;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.app-name {
|
.feature-body {
|
||||||
font-size: 16px;
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.feature-title {
|
||||||
|
font-size: 13px;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
color: var(--color-text-primary);
|
color: var(--color-text-primary);
|
||||||
}
|
}
|
||||||
|
|
||||||
.app-version {
|
.feature-desc {
|
||||||
font-size: 13px;
|
margin-top: 2px;
|
||||||
|
font-size: 12px;
|
||||||
|
line-height: 1.5;
|
||||||
color: var(--color-text-secondary);
|
color: var(--color-text-secondary);
|
||||||
margin: 2px 0 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.app-desc {
|
.tech-list {
|
||||||
grid-column: 1 / -1;
|
overflow: hidden;
|
||||||
|
border: 1px solid var(--color-border);
|
||||||
|
border-radius: var(--radius-sm);
|
||||||
|
}
|
||||||
|
|
||||||
|
.tech-item {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: 12px;
|
||||||
|
padding: 10px 14px;
|
||||||
|
min-height: 40px;
|
||||||
|
|
||||||
|
& + & {
|
||||||
|
border-top: 1px solid var(--color-border);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.tech-name {
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: var(--color-text-primary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.tech-desc {
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
color: var(--color-text-secondary);
|
color: var(--color-text-secondary);
|
||||||
margin: 12px 0 0;
|
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
|
||||||
|
}
|
||||||
|
|
||||||
|
.about-footer {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: 12px;
|
||||||
|
margin-top: 24px;
|
||||||
|
padding-top: 14px;
|
||||||
|
border-top: 1px solid var(--color-border);
|
||||||
|
font-size: 12px;
|
||||||
|
color: var(--color-text-secondary);
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 640px) {
|
@media (max-width: 640px) {
|
||||||
|
|
@ -82,8 +357,14 @@
|
||||||
padding: 18px 16px 24px;
|
padding: 18px 16px 24px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.app-desc {
|
.feature-list {
|
||||||
margin-left: 0;
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
|
|
||||||
|
.about-footer {
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: flex-start;
|
||||||
|
gap: 4px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue