diff --git a/README.md b/README.md index eceaf86..8c569da 100644 --- a/README.md +++ b/README.md @@ -38,6 +38,16 @@ - 窗口支持透明背景、置顶显示、圆角毛玻璃外观 - 设置通过 Pinia + 持久化插件跨会话保存 +## 界面预览 + +| 书架管理 | 书籍详情 | +| --- | --- | +| ![书架管理](images/1.png) | ![书籍章节详情](images/3.png) | + +| 幽灵阅读模式 | 阅读设置 | +| --- | --- | +| ![幽灵阅读模式](images/4.png) | ![阅读设置](images/2.png) | + ## 技术栈 | 层 | 技术 | diff --git a/images/1.png b/images/1.png new file mode 100644 index 0000000..0043dee Binary files /dev/null and b/images/1.png differ diff --git a/images/2.png b/images/2.png new file mode 100644 index 0000000..ba85d04 Binary files /dev/null and b/images/2.png differ diff --git a/images/3.png b/images/3.png new file mode 100644 index 0000000..06444bd Binary files /dev/null and b/images/3.png differ diff --git a/images/4.png b/images/4.png new file mode 100644 index 0000000..1a62cfc Binary files /dev/null and b/images/4.png differ diff --git a/package.json b/package.json index 3f5275e..b9f1011 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "stealthreader", "private": true, - "version": "0.1.0", + "version": "0.3.0", "type": "module", "scripts": { "dev": "vite", diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json index 9df2a9e..c826f69 100644 --- a/src-tauri/tauri.conf.json +++ b/src-tauri/tauri.conf.json @@ -1,7 +1,7 @@ { "$schema": "https://schema.tauri.app/config/2", - "productName": "stealthreader", - "version": "0.2.0", + "productName": "StealthReader", + "version": "../package.json", "identifier": "StealthReader", "build": { "beforeDevCommand": "pnpm dev", diff --git a/src/views/BookDetail.vue b/src/views/BookDetail.vue index a3bffdd..58c8f59 100644 --- a/src/views/BookDetail.vue +++ b/src/views/BookDetail.vue @@ -20,31 +20,44 @@ {{ book?.total_chapters ?? 0 }} {{ formatChars(book?.total_chars) }} {{ formatTime(book?.create_time) }} - {{ formatTime(book?.last_read_time) }} - {{ readProgress }} - - - - -
{{ book?.introduction || "暂无简介" }}
-
-
-
+ +
+ + + + + + +
{{ book?.introduction || "暂无简介" }}
+
+
+
@@ -137,6 +150,7 @@ const page = ref(1) const limit = ref(50) const loadingChapters = ref(false) const keyword = ref("") +const lastReadChapter = ref(null) const goBack = () => router.back() @@ -144,11 +158,30 @@ const readChapter = (ch: Chapters) => { 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 - if (!b || b.total_chapters <= 0) return "—" - const percent = Math.round((b.last_read_chapter_id / b.total_chapters) * 100) - return `第 ${b.last_read_chapter_id} 章 · ${percent}%` + if (!b || b.last_read_chapter_id <= 0) return null + return lastReadChapter.value +}) + +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) => { @@ -168,11 +201,25 @@ const loadBook = async () => { const res = await withLoading(() => BookApi.detail(bookId.value), "加载中...") if (res.code === 0) { book.value = res.data + if (res.data.last_read_chapter_id > 0) { + await loadLastReadChapter(res.data.last_read_chapter_id) + } } else { 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 () => { if (!bookId.value) return loadingChapters.value = true @@ -277,17 +324,99 @@ onMounted(() => { text-overflow: ellipsis; } +.intro-popover-wrap { + flex: 1; + min-width: 0; +} + .intro-preview { + box-sizing: border-box; + height: var(--progress-height); + min-width: 0; line-height: 1.6; font-size: 13px; color: var(--color-text-secondary); word-break: break-all; white-space: pre-wrap; - display: -webkit-box; - -webkit-box-orient: vertical; - -webkit-line-clamp: 2; overflow: hidden; 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) { diff --git a/src/views/Reader.vue b/src/views/Reader.vue index 665f973..2dadf19 100644 --- a/src/views/Reader.vue +++ b/src/views/Reader.vue @@ -1,7 +1,9 @@