Skip to content

Commit c16864c

Browse files
committed
feat: 书签和大纲的字体大小可进行手动调节
1 parent 153a850 commit c16864c

File tree

8 files changed

+253
-35
lines changed

8 files changed

+253
-35
lines changed

src/modules/outline/bookmark.ts

Lines changed: 47 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
import { version } from "../../../package.json";
22
import { getString } from "../../utils/locale";
33
import { ICONS } from "./style";
4+
import { OUTLINE_SCHEMA } from "./outline";
45

5-
export const BOOKMARK_SCHEMA = 1;
6+
export const BOOKMARK_SCHEMA = OUTLINE_SCHEMA;
7+
export const DEFAULT_BOOKMARK_FONT_SIZE = 13; // Default font size for bookmarks
68

79
// 学生友好的清新现代颜色
810
export const DEFAULT_BOOKMARK_COLORS = [
@@ -49,6 +51,7 @@ function getReaderPagePosition(): PdfPosition {
4951
export async function saveBookmarksToJSON(
5052
item?: Zotero.Item,
5153
bookmarks?: BookmarkNode[],
54+
baseFontSize?: number,
5255
) {
5356
if (!bookmarks) {
5457
bookmarks = getBookmarksFromPage();
@@ -59,11 +62,17 @@ export async function saveBookmarksToJSON(
5962
);
6063
item = reader._item;
6164
}
65+
// Get current baseFontSize if not provided
66+
if (baseFontSize === undefined) {
67+
const currentInfo = await loadBookmarkInfoFromJSON(item);
68+
baseFontSize = currentInfo?.baseFontSize ?? DEFAULT_BOOKMARK_FONT_SIZE;
69+
}
6270
const bookmarkInfo: BookmarkInfo = {
6371
info: {
6472
itemID: item.id,
6573
schema: BOOKMARK_SCHEMA,
6674
jasminumVersion: version,
75+
baseFontSize: baseFontSize,
6776
},
6877
bookmarks: bookmarks,
6978
};
@@ -78,9 +87,9 @@ export async function saveBookmarksToJSON(
7887
ztoolkit.log("Save bookmarks to JSON");
7988
}
8089

81-
export async function loadBookmarksFromJSON(
90+
export async function loadBookmarkInfoFromJSON(
8291
item: Zotero.Item,
83-
): Promise<BookmarkNode[] | null> {
92+
): Promise<{ bookmarks: BookmarkNode[]; baseFontSize: number } | null> {
8493
const bookmarkPath = PathUtils.join(
8594
Zotero.DataDirectory.dir,
8695
"storage",
@@ -99,16 +108,23 @@ export async function loadBookmarksFromJSON(
99108
if (tmp.info.schema < BOOKMARK_SCHEMA) {
100109
return null;
101110
} else {
102-
const bookmarks: BookmarkNode[] = JSON.parse(content)["bookmarks"];
103-
// 为向后兼容性添加默认颜色
104-
return bookmarks.map((bookmark) => ({
105-
...bookmark,
106-
color: bookmark.color || getRandomBookmarkColor(),
107-
}));
111+
const bookmarkInfo = JSON.parse(content) as BookmarkInfo;
112+
return {
113+
bookmarks: bookmarkInfo.bookmarks,
114+
baseFontSize:
115+
bookmarkInfo.info.baseFontSize ?? DEFAULT_BOOKMARK_FONT_SIZE,
116+
};
108117
}
109118
}
110119
}
111120

121+
export async function loadBookmarksFromJSON(
122+
item: Zotero.Item,
123+
): Promise<BookmarkNode[] | null> {
124+
const info = await loadBookmarkInfoFromJSON(item);
125+
return info?.bookmarks ?? null;
126+
}
127+
112128
export function getBookmarksFromPage(): BookmarkNode[] {
113129
const reader = Zotero.Reader.getByTabID(
114130
ztoolkit.getGlobal("Zotero_Tabs").selectedID,
@@ -262,3 +278,25 @@ export function addBookmarkButton(doc: Document) {
262278
doc.querySelector("#sidebarContainer div.start")!,
263279
);
264280
}
281+
282+
// Update bookmark font size dynamically
283+
export function updateBookmarkFontSize(doc: Document, baseFontSize: number) {
284+
const styleId = "jasminum-bookmark-dynamic-font-size";
285+
let styleElement = doc.getElementById(styleId) as HTMLStyleElement;
286+
287+
if (!styleElement) {
288+
styleElement = doc.createElement("style");
289+
styleElement.id = styleId;
290+
styleElement.type = "text/css";
291+
doc.querySelector("head")!.appendChild(styleElement);
292+
}
293+
294+
const dynamicCSS = `
295+
.bookmark-node {
296+
font-size: ${baseFontSize}px !important;
297+
}
298+
`;
299+
300+
styleElement.textContent = dynamicCSS;
301+
ztoolkit.log(`Updated bookmark font size: ${baseFontSize}px`);
302+
}

src/modules/outline/events.ts

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,18 @@ import {
22
saveOutlineToJSON,
33
createTreeNodes,
44
getOutlineFromPDF,
5+
updateOutlineFontSize,
6+
loadOutlineInfoFromJSON,
7+
DEFAULT_BASE_FONT_SIZE,
58
} from "./outline";
69
import {
710
saveBookmarksToJSON,
811
createBookmarkNodes,
912
addNewBookmark,
1013
DEFAULT_BOOKMARK_COLORS,
14+
updateBookmarkFontSize,
15+
loadBookmarkInfoFromJSON,
16+
DEFAULT_BOOKMARK_FONT_SIZE,
1117
} from "./bookmark";
1218
import { ICONS } from "./style";
1319
import { getString } from "../../utils/locale";
@@ -214,6 +220,14 @@ export function initEventListener(
214220
doc
215221
.getElementById("j-bookmark-delete")
216222
?.addEventListener("click", deleteSelectedBookmarkNode);
223+
224+
// 字体大小调整按钮事件
225+
doc
226+
.getElementById("j-outline-zoom-in")
227+
?.addEventListener("click", handleFontSizeIncrease);
228+
doc
229+
.getElementById("j-outline-zoom-out")
230+
?.addEventListener("click", handleFontSizeDecrease);
217231
}
218232

219233
// 为节点添加事件监听,以下为事件处理函数
@@ -1365,3 +1379,88 @@ export function handleBookmarkDragEnd(e: DragEvent) {
13651379
el.classList.remove("bookmark-dragover");
13661380
});
13671381
}
1382+
1383+
// ========== 字体大小调整函数 ==========
1384+
1385+
const MIN_FONT_SIZE = 8;
1386+
const MAX_FONT_SIZE = 20;
1387+
1388+
// Increase font size for both outline and bookmark
1389+
async function handleFontSizeIncrease(ev: Event) {
1390+
const doc = (ev.target as Element).ownerDocument;
1391+
const reader = Zotero.Reader.getByTabID(
1392+
ztoolkit.getGlobal("Zotero_Tabs").selectedID,
1393+
);
1394+
if (!reader) return;
1395+
1396+
// Get current baseFontSize for outline
1397+
const outlineInfo = await loadOutlineInfoFromJSON(reader._item);
1398+
const currentOutlineSize =
1399+
outlineInfo?.baseFontSize ?? DEFAULT_BASE_FONT_SIZE;
1400+
1401+
// Get current baseFontSize for bookmark
1402+
const bookmarkInfo = await loadBookmarkInfoFromJSON(reader._item);
1403+
const currentBookmarkSize =
1404+
bookmarkInfo?.baseFontSize ?? DEFAULT_BOOKMARK_FONT_SIZE;
1405+
1406+
// Increase by 1, max 20
1407+
const newOutlineSize = Math.min(currentOutlineSize + 1, MAX_FONT_SIZE);
1408+
const newBookmarkSize = Math.min(currentBookmarkSize + 1, MAX_FONT_SIZE);
1409+
1410+
if (
1411+
newOutlineSize !== currentOutlineSize ||
1412+
newBookmarkSize !== currentBookmarkSize
1413+
) {
1414+
// Update CSS
1415+
updateOutlineFontSize(doc, newOutlineSize);
1416+
updateBookmarkFontSize(doc, newBookmarkSize);
1417+
1418+
// Save to JSON
1419+
await saveOutlineToJSON(reader._item, undefined, newOutlineSize);
1420+
await saveBookmarksToJSON(reader._item, undefined, newBookmarkSize);
1421+
1422+
ztoolkit.log(
1423+
`Font size increased: outline=${newOutlineSize}px, bookmark=${newBookmarkSize}px`,
1424+
);
1425+
}
1426+
}
1427+
1428+
// Decrease font size for both outline and bookmark
1429+
async function handleFontSizeDecrease(ev: Event) {
1430+
const doc = (ev.target as Element).ownerDocument;
1431+
const reader = Zotero.Reader.getByTabID(
1432+
ztoolkit.getGlobal("Zotero_Tabs").selectedID,
1433+
);
1434+
if (!reader) return;
1435+
1436+
// Get current baseFontSize for outline
1437+
const outlineInfo = await loadOutlineInfoFromJSON(reader._item);
1438+
const currentOutlineSize =
1439+
outlineInfo?.baseFontSize ?? DEFAULT_BASE_FONT_SIZE;
1440+
1441+
// Get current baseFontSize for bookmark
1442+
const bookmarkInfo = await loadBookmarkInfoFromJSON(reader._item);
1443+
const currentBookmarkSize =
1444+
bookmarkInfo?.baseFontSize ?? DEFAULT_BOOKMARK_FONT_SIZE;
1445+
1446+
// Decrease by 1, min 8
1447+
const newOutlineSize = Math.max(currentOutlineSize - 1, MIN_FONT_SIZE);
1448+
const newBookmarkSize = Math.max(currentBookmarkSize - 1, MIN_FONT_SIZE);
1449+
1450+
if (
1451+
newOutlineSize !== currentOutlineSize ||
1452+
newBookmarkSize !== currentBookmarkSize
1453+
) {
1454+
// Update CSS
1455+
updateOutlineFontSize(doc, newOutlineSize);
1456+
updateBookmarkFontSize(doc, newBookmarkSize);
1457+
1458+
// Save to JSON
1459+
await saveOutlineToJSON(reader._item, undefined, newOutlineSize);
1460+
await saveBookmarksToJSON(reader._item, undefined, newBookmarkSize);
1461+
1462+
ztoolkit.log(
1463+
`Font size decreased: outline=${newOutlineSize}px, bookmark=${newBookmarkSize}px`,
1464+
);
1465+
}
1466+
}

src/modules/outline/index.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,17 @@ import {
77
getOutlineFromPDF,
88
registerOutlineCSS,
99
registerThemeChange,
10+
updateOutlineFontSize,
11+
loadOutlineInfoFromJSON,
12+
DEFAULT_BASE_FONT_SIZE,
1013
} from "./outline";
1114
import {
1215
addBookmarkButton,
1316
createBookmarkNodes,
1417
loadBookmarksFromJSON,
18+
updateBookmarkFontSize,
19+
loadBookmarkInfoFromJSON,
20+
DEFAULT_BOOKMARK_FONT_SIZE,
1521
} from "./bookmark";
1622
import { ICONS } from "./style";
1723
import { getPref } from "../../utils/prefs";
@@ -232,9 +238,23 @@ export async function addOutlineToReader(reader: _ZoteroTypes.ReaderInstance) {
232238
const bookmarks = await loadBookmarksFromJSON(reader._item);
233239
ztoolkit.log("++bookmarks", bookmarks);
234240

241+
// Load baseFontSize from JSON for outline
242+
const outlineInfo = await loadOutlineInfoFromJSON(reader._item);
243+
const outlineBaseFontSize =
244+
outlineInfo?.baseFontSize ?? DEFAULT_BASE_FONT_SIZE;
245+
246+
// Load baseFontSize from JSON for bookmark
247+
const bookmarkInfo = await loadBookmarkInfoFromJSON(reader._item);
248+
const bookmarkBaseFontSize =
249+
bookmarkInfo?.baseFontSize ?? DEFAULT_BOOKMARK_FONT_SIZE;
250+
235251
registerOutlineCSS(doc);
236252
registerThemeChange(reader._iframeWindow!);
237253

254+
// Apply dynamic font size for both outline and bookmark
255+
updateOutlineFontSize(doc, outlineBaseFontSize);
256+
updateBookmarkFontSize(doc, bookmarkBaseFontSize);
257+
238258
renderTree(reader, doc, joutline);
239259
renderBookmarkTree(reader, doc, bookmarks);
240260
initEventListener(reader, doc);

src/modules/outline/outline.ts

Lines changed: 53 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@ import { version } from "../../../package.json";
33
import { getString } from "../../utils/locale";
44
import { outline_css, ICONS } from "./style";
55

6-
export const OUTLINE_SCHEMA = 1;
6+
// 2 : Add base font size = 12
7+
export const OUTLINE_SCHEMA = 2;
8+
export const DEFAULT_BASE_FONT_SIZE = 12; // Default base font size for level-1
79

810
// Register custom CSS for Jasminum outline
911
export function registerOutlineCSS(doc: Document) {
@@ -21,6 +23,35 @@ export function registerOutlineCSS(doc: Document) {
2123
);
2224
}
2325

26+
// Update font size dynamically based on baseFontSize
27+
export function updateOutlineFontSize(doc: Document, baseFontSize: number) {
28+
const styleId = "jasminum-dynamic-font-size";
29+
let styleElement = doc.getElementById(styleId) as HTMLStyleElement;
30+
31+
if (!styleElement) {
32+
styleElement = doc.createElement("style");
33+
styleElement.id = styleId;
34+
styleElement.type = "text/css";
35+
doc.querySelector("head")!.appendChild(styleElement);
36+
}
37+
38+
// Calculate font sizes: level-1 = base, level-2 = base-1, level-3+ = base-2
39+
const level1Size = baseFontSize;
40+
const level2Size = baseFontSize - 1;
41+
const level3PlusSize = baseFontSize - 2;
42+
43+
const dynamicCSS = `
44+
.level-1 { font-size: ${level1Size}px !important; }
45+
.level-2 { font-size: ${level2Size}px !important; }
46+
.level-3, .level-4, .level-5, .level-6, .level-7 {
47+
font-size: ${level3PlusSize}px !important;
48+
}
49+
`;
50+
51+
styleElement.textContent = dynamicCSS;
52+
ztoolkit.log(`Updated font size: base=${baseFontSize}px`);
53+
}
54+
2455
// Register for theme update
2556
export function registerThemeChange(win: Window) {
2657
win
@@ -220,6 +251,7 @@ export function getOutlineFromPage(): OutlineNode[] {
220251
export async function saveOutlineToJSON(
221252
item?: Zotero.Item,
222253
outline?: OutlineNode[],
254+
baseFontSize?: number,
223255
) {
224256
if (!outline) {
225257
outline = getOutlineFromPage();
@@ -230,11 +262,17 @@ export async function saveOutlineToJSON(
230262
);
231263
item = reader._item;
232264
}
265+
// Get current baseFontSize if not provided
266+
if (baseFontSize === undefined) {
267+
const currentInfo = await loadOutlineInfoFromJSON(item);
268+
baseFontSize = currentInfo?.baseFontSize ?? DEFAULT_BASE_FONT_SIZE;
269+
}
233270
const outlineInfo: OutlineInfo = {
234271
info: {
235272
itemID: item.id,
236273
schema: OUTLINE_SCHEMA,
237274
jasminumVersion: version,
275+
baseFontSize: baseFontSize,
238276
},
239277
outline: outline,
240278
};
@@ -250,9 +288,9 @@ export async function saveOutlineToJSON(
250288
}
251289

252290
// 加载时要考虑JSON文件的版本信息,如果版本低,要重新从原文件加载信息
253-
export async function loadOutlineFromJSON(
291+
export async function loadOutlineInfoFromJSON(
254292
item: Zotero.Item,
255-
): Promise<OutlineNode[] | null> {
293+
): Promise<{ outline: OutlineNode[]; baseFontSize: number } | null> {
256294
const outlinePath = PathUtils.join(
257295
Zotero.DataDirectory.dir,
258296
"storage",
@@ -269,11 +307,22 @@ export async function loadOutlineFromJSON(
269307
if (tmp.info.schema < OUTLINE_SCHEMA) {
270308
return null;
271309
} else {
272-
return JSON.parse(content)["outline"];
310+
const outlineInfo = JSON.parse(content) as OutlineInfo;
311+
return {
312+
outline: outlineInfo.outline,
313+
baseFontSize: outlineInfo.info.baseFontSize ?? DEFAULT_BASE_FONT_SIZE,
314+
};
273315
}
274316
}
275317
}
276318

319+
export async function loadOutlineFromJSON(
320+
item: Zotero.Item,
321+
): Promise<OutlineNode[] | null> {
322+
const info = await loadOutlineInfoFromJSON(item);
323+
return info?.outline ?? null;
324+
}
325+
277326
export function createTreeNodes(
278327
nodes: OutlineNode[] | null,
279328
parentElement: HTMLElement,

src/modules/outline/style.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ export const ICONS = {
66
add: `<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="currentColor" d="m12 18l-4.2 1.8q-1 .425-1.9-.162T5 17.975V5q0-.825.588-1.412T7 3h5q.425 0 .713.288T13 4t-.288.713T12 5H7v12.95l5-2.15l5 2.15V12q0-.425.288-.712T18 11t.713.288T19 12v5.975q0 1.075-.9 1.663t-1.9.162zm0-13H7h6zm5 2h-1q-.425 0-.712-.288T15 6t.288-.712T16 5h1V4q0-.425.288-.712T18 3t.713.288T19 4v1h1q.425 0 .713.288T21 6t-.288.713T20 7h-1v1q0 .425-.288.713T18 9t-.712-.288T17 8z"/></svg>`,
77
del: `<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="currentColor" d="M16 7q-.425 0-.712-.288T15 6t.288-.712T16 5h4q.425 0 .713.288T21 6t-.288.713T20 7zm-4 11l-4.2 1.8q-1 .425-1.9-.162T5 17.975V5q0-.825.588-1.412T7 3h5q.425 0 .713.288T13 4t-.288.713T12 5H7v12.95l5-2.15l5 2.15V12q0-.425.288-.712T18 11t.713.288T19 12v5.975q0 1.075-.9 1.663t-1.9.162zm0-13H7h6z"/></svg>`,
88
save: `<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="currentColor" d="M5 21q-.825 0-1.412-.587T3 19V5q0-.825.588-1.412T5 3h11.175q.4 0 .763.15t.637.425l2.85 2.85q.275.275.425.638t.15.762V19q0 .825-.587 1.413T19 21zM19 7.85L16.15 5H5v14h14zM12 18q1.25 0 2.125-.875T15 15t-.875-2.125T12 12t-2.125.875T9 15t.875 2.125T12 18m-5-8h7q.425 0 .713-.288T15 9V7q0-.425-.288-.712T14 6H7q-.425 0-.712.288T6 7v2q0 .425.288.713T7 10M5 7.85V19V5z"/></svg>`,
9+
down: `<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 2 20 20"><g fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" color="currentColor"><path d="M16 10.5s-2.946 3-4 3s-4-3-4-3"/></g></svg>`,
10+
right: `<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 2 20 20"><g fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" color="currentColor"><path d="M10.5 8s3 2.946 3 4s-3 4-3 4"/></g></svg>`,
911
plus: `<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="currentColor" d="M4.194 14.867L2.881 18.16q-.067.157-.189.249q-.12.091-.296.091q-.288 0-.443-.228t-.051-.49l4.9-11.994q.048-.119.16-.204t.242-.084h.357q.149 0 .254.084q.104.085.152.204l4.887 11.943q.104.28-.063.525q-.167.244-.452.244q-.173 0-.322-.097q-.15-.098-.211-.268l-1.308-3.268zm.36-.967h5.584l-2.71-6.8h-.132zm13.83-1.4h-2.5q-.212 0-.356-.144t-.143-.357t.143-.356t.357-.143h2.5V9q0-.213.143-.356t.357-.144t.356.144t.144.356v2.5h2.5q.212 0 .356.144t.143.357t-.143.356t-.357.143h-2.5V15q0 .213-.143.356q-.144.144-.357.144t-.356-.144t-.144-.356z" /></svg>`,
1012
minus: `<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="currentColor" d="m1.616 18.5l5.288-13h.962l5.288 13h-1.208l-1.448-3.633H4.194L2.746 18.5zm2.938-4.6h5.584L7.436 7.1h-.139zm10.83-1.4v-1h7v1z" /></svg>`,
1113
};

0 commit comments

Comments
 (0)