From e791419db0bc2457360e9c196cf4244170a128fc Mon Sep 17 00:00:00 2001 From: Retsomm <112182ssss@gmail.com> Date: Tue, 7 Jul 2026 14:26:46 +0800 Subject: [PATCH 1/5] =?UTF-8?q?refactor(renderer):=20=E4=BE=9D=20Grokking?= =?UTF-8?q?=20Simplicity=20=E5=8E=9F=E5=89=87=E9=87=8D=E6=A7=8B=20Reader.t?= =?UTF-8?q?sx=EF=BC=8C=E5=88=86=E9=9B=A2=20action/calculation/data?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 抽出 4 個純計算檔案與 4 個 hooks(useBookmarks/useChapterPageScan/useAnnotationPopups/useReaderEngine),Reader.tsx 從 1850 行降至 314 行 - 修正章節掃描背景渲染共用主 book 導致偶爾清空 annotation 的問題 - 修正朗讀跟隨高亮閃爍(移除搶跑的估算進度計時器,比照 pwa 已驗證修法) - 修正註記跳轉後不顯示(relocated 後補救重新注入遺漏的 SVG 底線) - 修正書庫排序按鈕缺少 no-drag class 導致點擊被視窗拖曳吃掉 Co-Authored-By: Claude Sonnet 5 --- FP_REFACTOR_PROGRESS.md | 44 +- .../src/components/Library/SortControl.tsx | 2 +- .../src/components/Reader/BookmarkPanel.tsx | 5 +- .../src/components/Reader/bookmarkUtils.ts | 17 + .../components/Reader/progressCalculations.ts | 34 + renderer/src/components/Reader/tocLookup.ts | 62 + .../Reader/ttsFollowCalculations.ts | 100 + .../src/hooks/reader/useAnnotationPopups.ts | 167 ++ renderer/src/hooks/reader/useBookmarks.ts | 33 + .../src/hooks/reader/useChapterPageScan.ts | 155 ++ renderer/src/hooks/reader/useReaderEngine.ts | 1359 +++++++++++++ renderer/src/hooks/useTTS.ts | 17 +- renderer/src/page/Reader.tsx | 1682 +---------------- renderer/src/store/useAnnotationStore.ts | 11 +- 14 files changed, 2049 insertions(+), 1639 deletions(-) create mode 100644 renderer/src/components/Reader/bookmarkUtils.ts create mode 100644 renderer/src/components/Reader/progressCalculations.ts create mode 100644 renderer/src/components/Reader/tocLookup.ts create mode 100644 renderer/src/components/Reader/ttsFollowCalculations.ts create mode 100644 renderer/src/hooks/reader/useAnnotationPopups.ts create mode 100644 renderer/src/hooks/reader/useBookmarks.ts create mode 100644 renderer/src/hooks/reader/useChapterPageScan.ts create mode 100644 renderer/src/hooks/reader/useReaderEngine.ts diff --git a/FP_REFACTOR_PROGRESS.md b/FP_REFACTOR_PROGRESS.md index 729babc..90708ae 100644 --- a/FP_REFACTOR_PROGRESS.md +++ b/FP_REFACTOR_PROGRESS.md @@ -12,7 +12,7 @@ tags: ## 整體順序 1. ✅ **PWA**(`pwa/`)— 已完成 -2. ⬜ **RENDERER**(`renderer/`)— 待開始 +2. ✅ **RENDERER**(`renderer/`)— 已完成 3. ⬜ **RN / mobile**(`mobile/`)— 待開始 每完成一個版本先暫停,等使用者確認沒問題再進行下一個。 @@ -54,17 +54,43 @@ tags: --- -## 2. RENDERER(待開始) +## 2. RENDERER(已完成) -目標檔案:`renderer/src/page/Reader.tsx` +目標檔案:`renderer/src/page/Reader.tsx`(原始 1850 行,重構後 314 行) -**注意**:`renderer` 目前程式碼已與 `pwa` 分岔,功能不完全相同(例如少了書籤功能、annotation popup 拆成獨立的 `BookmarkPanel.tsx` / `HighlightPopup.tsx` 元件)。不能直接複製 PWA 版的重構結果,需要重新評估: +**更正**:舊版本文件寫「renderer 少了書籤功能」已過期——renderer 其實已有完整書籤功能與更早就元件化的 `BookmarkPanel.tsx` / `HighlightPopup.tsx`,只是書籤/annotation/TTS 邏輯尚未抽成純函數 + hooks。 -- [ ] 比對 `renderer` 與 `pwa` 的 `Reader.tsx` 差異,確認哪些抽出的邏輯可以共用、哪些需要為 renderer 版本量身設計 -- [ ] 決定是否要與 PWA 共用同一份純計算檔案(若邏輯完全一致) -- [ ] 依同樣的 ACD 原則拆分 renderer 版 `Reader.tsx` -- [ ] `cd renderer && yarn build` 驗證 -- [ ] 列出需使用者實測的項目(Electron 環境特有行為) +### 已完成項目 + +- [x] 新增 4 個純計算檔案(`renderer/src/components/Reader/`,與 pwa 共用同一份邏輯,逐字搬移): + - `progressCalculations.ts`、`tocLookup.ts`、`bookmarkUtils.ts`、`ttsFollowCalculations.ts` +- [x] 抽出 `useBookmarks.ts`、`useChapterPageScan.ts`、`useAnnotationPopups.ts`、`useReaderEngine.ts`(`renderer/src/hooks/reader/`) + - `useAnnotationPopups.ts` 依 renderer 現有 `HighlightPopup.tsx` 介面調整為 `{x, y}` 座標(不採用 pwa 版的 `{left, top}` clamp 寫法) + - `useReaderEngine.ts` 以 renderer 原有邏輯為底重新組織(而非直接搬 pwa 版),刻意保留 renderer 特有行為: + - TTS 高亮改用 renderer 原有的 CSS Custom Highlight API 直接繪製(不採用 pwa 版新增的 DOM overlay fallback,那是獨立的行為改動,超出本次重構範圍) + - 不引入 pwa 版新增的行動裝置專屬邏輯(觸控 selectionchange 選字路徑、iOS selectionchange 轉發、`getVisibleContentDocument` 多 iframe 命中測試)——Electron 桌面版不需要 + - 同步修正 `renderer/src/store/useAnnotationStore.ts` 的 `addAnnotation`,改為回傳新建立的 id(比照 pwa 版介面,讓 `useAnnotationPopups.ts` 可直接使用回傳值) + - 修掉章節掃描 bug:背景掃描改用獨立的 `ePub(buffer.slice(0))` 實例(`useChapterPageScan.ts`),不再複用主 `book` 建立第二個 rendition,避免掃描完成時偶爾清空主渲染器 annotation 的問題 +- [x] `Reader.tsx` 從 1850 行降至 314 行 +- [x] `cd renderer && yarn build` 驗證型別/編譯無誤 + +### 使用者實測結果(已通過) + +- [x] 翻頁、鍵盤左右鍵翻頁 +- [x] 朗讀播放/暫停/繼續/跨章節自動翻頁 +- [x] 選字高亮 popup 位置(新增/編輯/刪除標記) +- [x] 書籤新增/刪除/跳轉 +- [x] 簡繁轉換、深色模式、字體大小/字型/行距/字距設定 +- [x] 睡眠計時器 +- [x] 章節掃描:切換字體大小後多次翻頁,頁碼校正正確且高亮標記不會被意外清除 + +### 實測中發現並修正的問題 + +- [x] **朗讀跟隨螢光色閃爍、同時出現在目標與非目標句子**:`renderer/src/hooks/useTTS.ts` 仍保留舊版「估算進度計時器」(每 250ms 用預估字速推進高亮位置),與真實 `onboundary` 事件互相搶跑造成閃爍。比照 pwa 版已驗證過的修法,移除估算計時器,高亮改成只跟隨真實 boundary 事件。 +- [x] **註記跳轉後不顯示**:在 `useReaderEngine.ts` 的 `relocated` 事件中新增補救邏輯——每次換頁/跳轉後延遲檢查當前章節的既有註記是否有對應 SVG 底線,缺漏則重新呼叫 `addEpubAnnotation` 補畫(epub.js 的 `annotations.inject(view)` 在 contents 尚未完全就緒時偶爾會失敗)。 +- [x] **書庫排序按鈕(最近閱讀/書名/進度)點擊無效**:與本次 Reader 重構無關的既有 bug——`Library.tsx` 外層有 `drag-region`(Electron 視窗可拖曳區域),`SortControl.tsx` 的按鈕缺少 `no-drag` class,導致點擊被系統拖曳行為吃掉。已補上 `no-drag`。 + +**RENDERER 重構已通過完整實測,可視為此階段完成。** --- diff --git a/renderer/src/components/Library/SortControl.tsx b/renderer/src/components/Library/SortControl.tsx index 8feae72..45b4159 100644 --- a/renderer/src/components/Library/SortControl.tsx +++ b/renderer/src/components/Library/SortControl.tsx @@ -22,7 +22,7 @@ const SortControl = ({ count, sort, paperBg, paperBg2, borderCol, inkCol, ink3Co -
+
{(['recent', 'title', 'progress'] as SortKey[]).map((key) => (
) : (
- {[...bookmarks].sort((a, b) => a.addedAt - b.addedAt).map((bm) => ( + {sortBookmarksByAddedAt(bookmarks).map((bm) => (
onNavigate(bm)} onMouseEnter={(e) => (e.currentTarget.style.background = darkMode ? '#231f1c' : '#f1ede4')} onMouseLeave={(e) => (e.currentTarget.style.background = 'transparent')}>
{bm.label}
- {new Date(bm.addedAt).toLocaleDateString('zh-TW', { month: 'numeric', day: 'numeric' })} + {formatBookmarkDate(bm.addedAt)}