@@ -440,7 +485,13 @@ function HighlightItem({ highlight, onClick, onAddNote, onDelete }: HighlightIte
style={{ backgroundColor: HIGHLIGHT_COLOR_HEX[highlight.color] }}
/>
-
"{highlight.text}"
+ {highlight.text ? (
+
"{highlight.text}"
+ ) : (
+
+ {pageNoteLabel(highlight.cfi, t)}
+
+ )}
{highlight.chapterTitle && (
{highlight.chapterTitle}
)}
diff --git a/packages/app/src/components/reader/ReaderView.tsx b/packages/app/src/components/reader/ReaderView.tsx
index ade0140b9..6dd27b2be 100644
--- a/packages/app/src/components/reader/ReaderView.tsx
+++ b/packages/app/src/components/reader/ReaderView.tsx
@@ -1673,6 +1673,19 @@ export function ReaderView({ bookId, tabId }: ReaderViewProps) {
setSelection(null);
}, [selection, bookId, highlights, readerTab?.chapterTitle]);
+ // Handle page-level note button — anchor a note to the current position so
+ // formats without usable text selection (e.g. PDF) can still take notes.
+ const handleAddPageNote = useCallback(() => {
+ const cfi = readerTab?.currentCfi;
+ if (!cfi) return;
+ useNotebookStore.getState().startNewNote({
+ text: "",
+ cfi,
+ chapterTitle: readerTab?.chapterTitle,
+ page: currentPage || undefined,
+ });
+ }, [readerTab?.currentCfi, readerTab?.chapterTitle, currentPage]);
+
const handleCopy = useCallback(() => {
if (selection?.text) navigator.clipboard.writeText(selection.text);
setSelection(null);
@@ -2870,6 +2883,7 @@ export function ReaderView({ bookId, tabId }: ReaderViewProps) {
{/* Notebook sidebar — LEFT side */}
{
foliateRef.current?.addAnnotation({
@@ -3214,6 +3228,7 @@ export function ReaderView({ bookId, tabId }: ReaderViewProps) {
// Separate component to use notebook store hook
function NotebookSidebarWrapper({
bookId,
+ onAddPageNote,
onGoToCfi,
onAddAnnotation,
onDeleteAnnotation,
@@ -3223,6 +3238,7 @@ function NotebookSidebarWrapper({
onResizeEnd,
}: {
bookId: string;
+ onAddPageNote?: () => void;
onGoToCfi: (cfi: string) => void;
onAddAnnotation: (cfi: string, color: string, note?: string) => void;
onDeleteAnnotation: (cfi: string) => void;
@@ -3250,6 +3266,7 @@ function NotebookSidebarWrapper({
0 ? page : null;
+}
+
+type LabelT = (key: string, options?: Record) => string;
+
+/** List label for a page-level note: "第N页笔记" when the page is known. */
+export function pageNoteLabel(cfi: string, t: LabelT): string {
+ const page = parseFakeCfiPage(cfi);
+ return page
+ ? t("notebook.pageNoteWithPage", { page })
+ : t("notebook.pageNoteBadge");
+}
diff --git a/packages/core/src/i18n/locales/en/reader.json b/packages/core/src/i18n/locales/en/reader.json
index d5b86f34f..fcb296cf2 100644
--- a/packages/core/src/i18n/locales/en/reader.json
+++ b/packages/core/src/i18n/locales/en/reader.json
@@ -113,6 +113,11 @@
"emptyHint": "Select text in the book to highlight or add notes",
"editNote": "Edit note",
"addNoteBtn": "Add note",
+ "addPageNote": "Add page note",
+ "pageNoteBadge": "Page note",
+ "pageNotePage": "Page {{page}}",
+ "pageNoteNoPage": "Current position",
+ "pageNoteWithPage": "Note on page {{page}}",
"deleteHighlightBtn": "Delete highlight"
},
"editor": {
diff --git a/packages/core/src/i18n/locales/es/reader.json b/packages/core/src/i18n/locales/es/reader.json
index b1f3fa60e..27cde9d84 100644
--- a/packages/core/src/i18n/locales/es/reader.json
+++ b/packages/core/src/i18n/locales/es/reader.json
@@ -109,6 +109,11 @@
"emptyHint": "Selecciona texto en el libro para subrayar o agregar notas",
"editNote": "Editar nota",
"addNoteBtn": "Agregar nota",
+ "addPageNote": "Añadir nota de página",
+ "pageNoteBadge": "Nota de página",
+ "pageNotePage": "Página {{page}}",
+ "pageNoteNoPage": "Posición actual",
+ "pageNoteWithPage": "Nota en la página {{page}}",
"deleteHighlightBtn": "Eliminar subrayado"
},
"editor": {
diff --git a/packages/core/src/i18n/locales/fr/reader.json b/packages/core/src/i18n/locales/fr/reader.json
index b754cc55a..68b21a8d4 100644
--- a/packages/core/src/i18n/locales/fr/reader.json
+++ b/packages/core/src/i18n/locales/fr/reader.json
@@ -109,6 +109,11 @@
"emptyHint": "Sélectionnez du texte dans le livre pour surligner ou ajouter des notes",
"editNote": "Modifier la note",
"addNoteBtn": "Ajouter une note",
+ "addPageNote": "Ajouter une note de page",
+ "pageNoteBadge": "Note de page",
+ "pageNotePage": "Page {{page}}",
+ "pageNoteNoPage": "Position actuelle",
+ "pageNoteWithPage": "Note page {{page}}",
"deleteHighlightBtn": "Supprimer le surlignage"
},
"editor": {
diff --git a/packages/core/src/i18n/locales/ja/reader.json b/packages/core/src/i18n/locales/ja/reader.json
index 2edd42242..48fc7d36a 100644
--- a/packages/core/src/i18n/locales/ja/reader.json
+++ b/packages/core/src/i18n/locales/ja/reader.json
@@ -109,6 +109,11 @@
"emptyHint": "本のテキストを選択してハイライトやノートを追加",
"editNote": "ノートを編集",
"addNoteBtn": "ノートを追加",
+ "addPageNote": "ページメモを追加",
+ "pageNoteBadge": "ページメモ",
+ "pageNotePage": "{{page}} ページ",
+ "pageNoteNoPage": "現在位置",
+ "pageNoteWithPage": "{{page}} ページのメモ",
"deleteHighlightBtn": "ハイライトを削除"
},
"editor": {
diff --git a/packages/core/src/i18n/locales/ko/reader.json b/packages/core/src/i18n/locales/ko/reader.json
index 7fefaa391..9b0c5511f 100644
--- a/packages/core/src/i18n/locales/ko/reader.json
+++ b/packages/core/src/i18n/locales/ko/reader.json
@@ -109,6 +109,11 @@
"emptyHint": "책에서 텍스트를 선택하여 하이라이트하거나 노트를 추가하세요",
"editNote": "노트 편집",
"addNoteBtn": "노트 추가",
+ "addPageNote": "페이지 메모 추가",
+ "pageNoteBadge": "페이지 메모",
+ "pageNotePage": "{{page}}쪽",
+ "pageNoteNoPage": "현재 위치",
+ "pageNoteWithPage": "{{page}}쪽 메모",
"deleteHighlightBtn": "하이라이트 삭제"
},
"editor": {
diff --git a/packages/core/src/i18n/locales/zh-TW/reader.json b/packages/core/src/i18n/locales/zh-TW/reader.json
index 5e4117f8f..68a7ea35e 100644
--- a/packages/core/src/i18n/locales/zh-TW/reader.json
+++ b/packages/core/src/i18n/locales/zh-TW/reader.json
@@ -109,6 +109,11 @@
"emptyHint": "選取書中文字進行醒目標示或新增筆記",
"editNote": "編輯筆記",
"addNoteBtn": "新增筆記",
+ "addPageNote": "新增頁級筆記",
+ "pageNoteBadge": "頁級筆記",
+ "pageNotePage": "第 {{page}} 頁",
+ "pageNoteNoPage": "當前位置",
+ "pageNoteWithPage": "第 {{page}} 頁筆記",
"deleteHighlightBtn": "刪除醒目標示"
},
"editor": {
diff --git a/packages/core/src/i18n/locales/zh/reader.json b/packages/core/src/i18n/locales/zh/reader.json
index 706280ce1..79dcbb5c0 100644
--- a/packages/core/src/i18n/locales/zh/reader.json
+++ b/packages/core/src/i18n/locales/zh/reader.json
@@ -113,6 +113,11 @@
"emptyHint": "选择书中文本进行高亮或添加笔记",
"editNote": "编辑笔记",
"addNoteBtn": "添加笔记",
+ "addPageNote": "添加页级笔记",
+ "pageNoteBadge": "页级笔记",
+ "pageNotePage": "第 {{page}} 页",
+ "pageNoteNoPage": "当前位置",
+ "pageNoteWithPage": "第 {{page}} 页笔记",
"deleteHighlightBtn": "删除高亮"
},
"editor": {
diff --git a/packages/core/src/stores/notebook-store.ts b/packages/core/src/stores/notebook-store.ts
index 9c7c6cd91..0d15deb9c 100644
--- a/packages/core/src/stores/notebook-store.ts
+++ b/packages/core/src/stores/notebook-store.ts
@@ -5,8 +5,10 @@ import { create } from "zustand";
import type { Highlight } from "../types";
export interface PendingNote {
- /** Selected text to annotate */
+ /** Selected text to annotate (empty string = page-level note) */
text: string;
+ /** Page number for page-level notes (fixed-layout books) */
+ page?: number;
/** CFI location */
cfi: string;
/** Chapter title for context */