hexo-theme-linen 1.0.19 → 1.0.20

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.19",
3
+ "version": "1.0.20",
4
4
  "description": "A clean Hexo theme",
5
5
  "main": "index.js",
6
6
  "homepage": "https://github.com/lynanbreeze/hexo-theme-linen",
@@ -0,0 +1,99 @@
1
+ "use strict";
2
+
3
+ hexo.extend.filter.register("before_post_render", function (data) {
4
+ let lines = data.content.split("\n");
5
+
6
+ const footnotes = {};
7
+ const refRegex = /\[\^(.+?)\]/g;
8
+ const defStartRegex = /^\[\^(.+?)\]:\s*(.*)$/;
9
+
10
+ let i = 0;
11
+
12
+ while (i < lines.length) {
13
+ const line = lines[i];
14
+ const defMatch = line.match(defStartRegex);
15
+
16
+ if (defMatch) {
17
+ const id = defMatch[1];
18
+ const firstLine = defMatch[2] || "";
19
+ let blocks = [];
20
+
21
+ if (firstLine.trim()) {
22
+ blocks.push(firstLine);
23
+ }
24
+
25
+ i++;
26
+
27
+ while (i < lines.length) {
28
+ const next = lines[i];
29
+
30
+ if (defStartRegex.test(next)) break;
31
+
32
+ if (/^\s{4,}|\t/.test(next)) {
33
+ blocks.push(next.replace(/^\s{4}/, ""));
34
+ i++;
35
+ continue;
36
+ }
37
+
38
+ if (next.trim() === "") {
39
+ blocks.push("");
40
+ i++;
41
+ continue;
42
+ }
43
+
44
+ break;
45
+ }
46
+
47
+ footnotes[id] = blocks.join("\n");
48
+ continue;
49
+ }
50
+
51
+ i++;
52
+ }
53
+
54
+ data.content = data.content.replace(
55
+ /^\[\^(.+?)\]:[\s\S]+?(?=\n\[|\n*$)/gm,
56
+ "",
57
+ );
58
+
59
+ const refCount = {};
60
+
61
+ data.content = data.content.replace(refRegex, (m, id) => {
62
+ if (!footnotes[id]) return m;
63
+
64
+ refCount[id] = (refCount[id] || 0) + 1;
65
+ const n = refCount[id];
66
+
67
+ return `<sup class="footnote-anchor-wrap" id="fnref-${id}-${n}"><a class="footnote-href" href="#fn-${id}">${id}</a></sup>`;
68
+ });
69
+
70
+ const keys = Object.keys(footnotes);
71
+ if (keys.length > 0) {
72
+ const list = keys
73
+ .map((id) => {
74
+ const html = footnotes[id]
75
+ .split("\n")
76
+ .map((p) => (p.trim() ? p : ""))
77
+ .join("\n");
78
+
79
+ const backrefs = Array.from({ length: refCount[id] || 0 }, (_, i) => {
80
+ const n = i + 1;
81
+ return `<a href="#fnref-${id}-${n}" class="footnote-backref"></a>`;
82
+ }).join(" ");
83
+
84
+ return `<li id="fn-${id}">${html}${backrefs}</li>`;
85
+ })
86
+ .join("\n");
87
+
88
+ data.content += `
89
+ <hr class="footnotes-sep">
90
+ <section class="footnotes">
91
+ <ol>
92
+ ${list}
93
+ </ol>
94
+ </section>
95
+ `;
96
+ }
97
+
98
+ return data;
99
+ });
package/scripts/index.js CHANGED
@@ -5,6 +5,7 @@ require("./custom")(hexo);
5
5
  require("./hoverTexts")(hexo);
6
6
  require("./helpers/tools")(hexo);
7
7
  require("./font-version")(hexo);
8
+ require("./footnote")(hexo);
8
9
  require("./appendRawMarkdownContent")(hexo);
9
10
  require("./addCopyButtonToCodeBlocks")(hexo);
10
11
  require('./folded-code-block')(hexo);
@@ -2531,3 +2531,19 @@ ul {
2531
2531
  }
2532
2532
  }
2533
2533
  }
2534
+
2535
+ .footnote-anchor-wrap {
2536
+ .footnote-href{
2537
+ color: $green;
2538
+ }
2539
+ }
2540
+ .footnote-backref{
2541
+ width: 0.8em;
2542
+ height: 0.8em;
2543
+ background-image: url("../img/icons/backref.svg");
2544
+ background-size: contain;
2545
+ display: inline-block;
2546
+ &:not(:first-child) {
2547
+ display: none;
2548
+ }
2549
+ }
@@ -0,0 +1 @@
1
+ <svg t="1776504285799" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4049" width="200" height="200"><path d="M853.312 170.688v384a170.688 170.688 0 0 1-170.624 170.624H294.976L401.664 832l-60.352 60.352-209.664-209.664L341.312 472.96l60.352 60.288L295.04 640h387.712C729.792 640 768 601.792 768 554.688v-384h85.312z" p-id="4050" fill="#0f730c"></path></svg>
@@ -161,14 +161,30 @@ function copyToClipboard(text) {
161
161
  copyToClipboard(text);
162
162
  }
163
163
 
164
- function highlightAnchor(hash, highlightClass = "anchor-highlight") {
165
- if (!hash) return;
166
- const id = hash.replace(/^#/, "");
167
- const el = document.getElementById(id);
168
- if (el) {
169
- el.classList.remove(highlightClass);
170
- void el.offsetWidth;
171
- el.classList.add(highlightClass);
164
+ function highlightAnchor(
165
+ hash,
166
+ highlightClass = "anchor-highlight",
167
+ element = null,
168
+ ) {
169
+ if (element) {
170
+ element.classList.remove(highlightClass);
171
+ void element.offsetWidth;
172
+ element.classList.add(highlightClass);
173
+ setTimeout(() => {
174
+ element.classList.remove(highlightClass);
175
+ }, 4000);
176
+ } else {
177
+ if (!hash) return;
178
+ const id = hash.replace(/^#/, "");
179
+ const el = document.getElementById(id);
180
+ if (el) {
181
+ el.classList.remove(highlightClass);
182
+ void el.offsetWidth;
183
+ el.classList.add(highlightClass);
184
+ setTimeout(() => {
185
+ el.classList.remove(highlightClass);
186
+ }, 4000);
187
+ }
172
188
  }
173
189
  }
174
190
 
@@ -272,6 +288,34 @@ function handleClick(e) {
272
288
  var maskElement = document.getElementById("mask");
273
289
  var bodyElement = document.body;
274
290
  var donateModal = document.getElementById("donate-modal");
291
+ if(target?.className === 'footnote-href') {
292
+ const footNoteDefinitionId = target.getAttribute("href").substring(1);
293
+ const footNoteDefinitionElement = document.getElementById(footNoteDefinitionId);
294
+ if (footNoteDefinitionElement) {
295
+ footNoteDefinitionElement.scrollIntoView({
296
+ behavior: "smooth",
297
+ block: "start",
298
+ });
299
+ e.preventDefault();
300
+ highlightAnchor(undefined, undefined, footNoteDefinitionElement);
301
+ return;
302
+ }
303
+ }
304
+ if (target?.className === "footnote-backref") {
305
+ const footNoteId = target.getAttribute("href").substring(1);
306
+ const footNoteTextElements = document.querySelectorAll('.footnote-anchor-wrap');
307
+ if (footNoteTextElements.length) {
308
+ footNoteTextElements[0].scrollIntoView({
309
+ behavior: "smooth",
310
+ block: "start",
311
+ });
312
+ e.preventDefault();
313
+ Array.prototype.forEach.call(footNoteTextElements, (el) => {
314
+ highlightAnchor(undefined, undefined, el);
315
+ })
316
+ return;
317
+ }
318
+ }
275
319
  if (/content-switch/.test(target.id)) {
276
320
  if (document.body.classList.contains("render-raw")) {
277
321
  target.innerText = target.dataset.rawcontentlabel;
@@ -148,19 +148,6 @@ function removeTransitionStyle(el) {
148
148
  * @returns {Promise<HTMLImageElement | void>}
149
149
  */
150
150
  function decodeImage(img) {
151
- // Skip decode for HDR images to prevent Chrome crashes
152
- if (img.src && img.src.includes("/hdr/")) {
153
- if (img.complete) {
154
- return Promise.resolve(img);
155
- }
156
- return new Promise((resolve, reject) => {
157
- img.onload = () => resolve(img);
158
- img.onerror = reject;
159
- });
160
- }
161
- if ("decode" in img) {
162
- return img.decode().catch(() => {});
163
- }
164
151
  if (img.complete) {
165
152
  return Promise.resolve(img);
166
153
  }