hexo-theme-linen 1.0.19 → 1.0.21

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.21",
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);
@@ -1675,7 +1675,7 @@ body {
1675
1675
  .series-nav {
1676
1676
  background-color: #f5f5f5;
1677
1677
  width: calc(100% - min(6vw, 30px));
1678
- margin: $postWidgetGap auto 1em auto;
1678
+ margin: 0 auto 1em auto;
1679
1679
  padding: 1em;
1680
1680
  padding-top: 0.65em;
1681
1681
  border-radius: 2px;
@@ -2141,7 +2141,7 @@ html[lang="zh-CN"] {
2141
2141
  }
2142
2142
 
2143
2143
  #related-posts {
2144
- @include pageXPadding;
2144
+ padding: 0 $commonPadding;
2145
2145
  border-top: solid 1px #f5f5f5;
2146
2146
  .related-posts-title {
2147
2147
  margin: 1em 0;
@@ -2531,3 +2531,24 @@ 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
+ }
2550
+ .footnotes {
2551
+ ol {
2552
+ padding-left: calc(40px - $commonPadding);
2553
+ }
2554
+ }
@@ -240,9 +240,7 @@
240
240
  }
241
241
  .site-info {
242
242
  padding: 0;
243
- &.home {
244
- padding: 0;
245
- }
243
+ padding-bottom: 1rem;
246
244
  .author {
247
245
  flex-direction: column;
248
246
  align-items: center;
@@ -86,6 +86,9 @@ $postWidth: max(min(1192px, 68vw), 960px);
86
86
  @mixin tags {
87
87
  @include defaultFont;
88
88
  margin-bottom: -10px;
89
+ &:last-child {
90
+ margin-bottom: calc(1rem - 10px);
91
+ }
89
92
  .tag-item {
90
93
  background-color: #f5f5f5;
91
94
  padding: 4px 7px 4px 6px;
@@ -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
  }