hexo-theme-linen 1.0.34 → 1.0.35

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hexo-theme-linen",
3
- "version": "1.0.34",
3
+ "version": "1.0.35",
4
4
  "description": "A clean Hexo theme",
5
5
  "main": "index.js",
6
6
  "homepage": "https://github.com/lynanbreeze/hexo-theme-linen",
@@ -12,7 +12,7 @@ document.addEventListener("DOMContentLoaded", () => {
12
12
  );
13
13
  if (headerElements.length === 0) return;
14
14
 
15
- // 1. 保证所有标题均具备有效 ID(补全缺失的 ID 并写回 DOM)
15
+ // 1. Ensure every heading has a valid ID, filling in missing IDs in the DOM.
16
16
  headerElements.forEach((header, index) => {
17
17
  if (!header.id) {
18
18
  const text = (header.textContent || "").trim();
@@ -21,7 +21,7 @@ document.addEventListener("DOMContentLoaded", () => {
21
21
  }
22
22
  });
23
23
 
24
- // 2. 解析 TOC 目录的 DOM 结构建立映射字典
24
+ // 2. Parse the TOC DOM and build lookup maps.
25
25
  const tocItemWraps = Array.from(
26
26
  tocContainer.querySelectorAll(".toc-item-wrap"),
27
27
  );
@@ -51,7 +51,7 @@ document.addEventListener("DOMContentLoaded", () => {
51
51
  });
52
52
  });
53
53
 
54
- // 3. 构建正文标题列表
54
+ // 3. Build the ordered list of content headings.
55
55
  let currentH2Id = null;
56
56
  const headers = headerElements.map((header) => {
57
57
  const isH2 = header.tagName === "H2";
@@ -66,13 +66,13 @@ document.addEventListener("DOMContentLoaded", () => {
66
66
  };
67
67
  });
68
68
 
69
- // 顶部导航栏避让阈值
69
+ // Offset used to account for the fixed top navigation bar.
70
70
  const TOP_OFFSET = 80;
71
71
 
72
72
  let lastActiveH2Id = null;
73
73
  let lastActiveH3Id = null;
74
74
 
75
- // 4. 目录容器内部滚动居中/可见,避免触发外部 window 的异常抖动
75
+ // Keep the active TOC item visible without affecting the page scroll position.
76
76
  function scrollIntoTocView(element) {
77
77
  if (!element || !tocContainer) return;
78
78
  const containerRect = tocContainer.getBoundingClientRect();
@@ -85,30 +85,23 @@ document.addEventListener("DOMContentLoaded", () => {
85
85
  }
86
86
  }
87
87
 
88
- // 5. 计算当前应当激活的 H2 / H3
88
+ // 5. Determine the currently active H2 / H3.
89
89
  function determineActive() {
90
- // 优先兼容外部锚定参数 window.anchoringId
91
- const currentAnchoringId =
92
- typeof window !== "undefined" && "anchoringId" in window
93
- ? window.anchoringId
94
- : null;
95
-
96
- if (currentAnchoringId) {
97
- if (tocItemsMap.has(currentAnchoringId)) {
98
- return {
99
- h2Id: currentAnchoringId,
100
- h3Id: null,
101
- };
102
- }
103
- if (h3ToH2Map.has(currentAnchoringId)) {
104
- return {
105
- h2Id: h3ToH2Map.get(currentAnchoringId),
106
- h3Id: currentAnchoringId,
107
- };
90
+ // At the bottom of the page, the last heading may not reach the top trigger
91
+ // line. In that case, the last heading represents the current section.
92
+ const scrollElement = document.scrollingElement || document.documentElement;
93
+ const isAtBottom =
94
+ window.scrollY + window.innerHeight >= scrollElement.scrollHeight - 1;
95
+ if (isAtBottom) {
96
+ const lastHeader = headers[headers.length - 1];
97
+ if (lastHeader) {
98
+ return lastHeader.isH2
99
+ ? { h2Id: lastHeader.id, h3Id: null }
100
+ : { h2Id: lastHeader.h2Id, h3Id: lastHeader.id };
108
101
  }
109
102
  }
110
103
 
111
- // 根据滚动位置,查找位于视口顶部触发线(top <= TOP_OFFSET)之上的最后一个标题
104
+ // Find the last heading above the viewport trigger line (top <= TOP_OFFSET).
112
105
  let activeHeading = null;
113
106
  for (let i = 0; i < headers.length; i++) {
114
107
  const header = headers[i];
@@ -120,7 +113,7 @@ document.addEventListener("DOMContentLoaded", () => {
120
113
  }
121
114
  }
122
115
 
123
- // 若未滚动到任何标题(如文章开头前言),激活第一个 H2
116
+ // If no heading has reached the trigger line, activate the first H2.
124
117
  if (!activeHeading) {
125
118
  const firstH2 = headers.find((h) => h.isH2);
126
119
  return {
@@ -142,7 +135,7 @@ document.addEventListener("DOMContentLoaded", () => {
142
135
  };
143
136
  }
144
137
 
145
- // 6. 执行高亮更新与 DOM 渲染
138
+ // 6. Apply the active state to the TOC DOM.
146
139
  function updateActive() {
147
140
  const { h2Id, h3Id } = determineActive();
148
141
 
@@ -164,7 +157,7 @@ document.addEventListener("DOMContentLoaded", () => {
164
157
  item.wrap.classList.remove("active");
165
158
  }
166
159
 
167
- // 仅在当前 H2 为 active 时匹配子项 H3,彻底杜绝跨章节残留
160
+ // Match H3 items only within the active H2 to prevent cross-section residue.
168
161
  item.subMap.forEach((subLink, currentH3Id) => {
169
162
  if (isH2Active && currentH3Id === h3Id) {
170
163
  subLink.classList.add("active");
@@ -180,7 +173,7 @@ document.addEventListener("DOMContentLoaded", () => {
180
173
  }
181
174
  }
182
175
 
183
- // 7. 使用 requestAnimationFrame 优化滚动触发频率
176
+ // 7. Throttle scroll updates with requestAnimationFrame.
184
177
  let isTicking = false;
185
178
  function requestUpdate() {
186
179
  if (isTicking) return;
@@ -191,7 +184,7 @@ document.addEventListener("DOMContentLoaded", () => {
191
184
  });
192
185
  }
193
186
 
194
- // 8. 监听视口变化与滚动
187
+ // 8. Listen for viewport changes and scrolling.
195
188
  window.addEventListener("scroll", requestUpdate, { passive: true });
196
189
  window.addEventListener("resize", requestUpdate, { passive: true });
197
190
 
@@ -208,6 +201,6 @@ document.addEventListener("DOMContentLoaded", () => {
208
201
  headerElements.forEach((header) => observer.observe(header));
209
202
  }
210
203
 
211
- // 初始执行一次
204
+ // Run once on initialization.
212
205
  updateActive();
213
206
  });