hexo-theme-gnix 4.0.3 → 4.0.5

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.
@@ -19,7 +19,7 @@ module.exports = (hexo) => {
19
19
  function mapPost(post) {
20
20
  return {
21
21
  title: util.escapeHTML(post.title).trim(),
22
- text: minify(post.content),
22
+ text: post.password ? "该文章需要密码" : minify(post.content),
23
23
  link: url_for(post.path),
24
24
  };
25
25
  }
@@ -34,16 +34,20 @@ module.exports = (hexo) => {
34
34
  posts: locals.posts.map(mapPost),
35
35
  tags: locals.tags.map(mapTag),
36
36
  };
37
- const index_pages = this.theme.config?.search?.index_pages;
38
- if (index_pages === false) {
39
- site.pages = [];
40
- } else {
41
- site.pages = locals.pages.map(mapPost);
42
- }
43
37
 
44
38
  return {
45
39
  path: "/content.json",
46
40
  data: JSON.stringify(site),
47
41
  };
48
42
  });
43
+ // Generate "<root>/tags/" page
44
+ hexo.extend.generator.register("tags", (locals) => {
45
+ return {
46
+ path: "tags/",
47
+ layout: ["tags"],
48
+ data: Object.assign({}, locals, {
49
+ __tags: true,
50
+ }),
51
+ };
52
+ });
49
53
  };
@@ -1,7 +1,6 @@
1
1
  module.exports = (hexo) => {
2
- require("./hexo/filter/locals")(hexo);
3
- require("./hexo/generator/insight")(hexo);
4
- require("./hexo/generator/tags")(hexo);
2
+ require("./hexo/filter")(hexo);
3
+ require("./hexo/generator")(hexo);
5
4
  require("./hexo/view").init(hexo);
6
5
  require("./hexo/helper")(hexo);
7
6
  require("./hexo/renderer")(hexo);
@@ -63,7 +63,11 @@ module.exports = class extends Component {
63
63
  <div class="card">
64
64
  <div class="card-content">
65
65
  <span class="year">
66
- {month === null ? year : isValid(time) ? format(time, "LLLL yyyy") : year}
66
+ {month === null
67
+ ? year
68
+ : isValid(time)
69
+ ? format(time, "LLLL yyyy")
70
+ : year}
67
71
  </span>
68
72
  <div class="timeline">
69
73
  {posts.map((post) => {
@@ -91,7 +95,9 @@ module.exports = class extends Component {
91
95
  articleList = Object.keys(years)
92
96
  .sort((a, b) => b - a)
93
97
  .map((year) => {
94
- const posts = page.posts.filter((p) => p.date.year() === parseInt(year, 10));
98
+ const posts = page.posts.filter(
99
+ (p) => p.date.year() === parseInt(year, 10),
100
+ );
95
101
  return renderArticleList(posts, year, null);
96
102
  });
97
103
  } else {
@@ -14,7 +14,9 @@ function getWordCount(content) {
14
14
  }
15
15
  content = content.replace(/<\/?[a-z][^>]*>/gi, "");
16
16
  content = content.trim();
17
- return content ? (content.match(/[\u00ff-\uffff]|[a-zA-Z]+/g) || []).length : 0;
17
+ return content
18
+ ? (content.match(/[\u00ff-\uffff]|[a-zA-Z]+/g) || []).length
19
+ : 0;
18
20
  }
19
21
 
20
22
  module.exports = class extends Component {
@@ -34,27 +36,45 @@ module.exports = class extends Component {
34
36
  {/* Main content */}
35
37
  <div class="card article-wrapper">
36
38
  {/* Cover image */}
37
- {cover ? <ArticleCover page={page} cover={cover} index={index} helper={helper} /> : null}
38
- <article class={`card-content article${"direction" in page ? ` ${page.direction}` : ""}`}>
39
+ {cover ? (
40
+ <ArticleCover
41
+ page={page}
42
+ cover={cover}
43
+ index={index}
44
+ helper={helper}
45
+ />
46
+ ) : null}
47
+ <article
48
+ class={`card-content article${"direction" in page ? ` ${page.direction}` : ""}`}
49
+ >
39
50
  {/* Title */}
40
51
  {page.title !== "" && index ? (
41
52
  <h2 class="article-title">
42
53
  <a href={url_for(page.link || page.path)}>{page.title}</a>
43
54
  </h2>
44
55
  ) : null}
45
- {page.title !== "" && !index ? <h1 class="article-title">{page.title}</h1> : null}
56
+ {page.title !== "" && !index ? (
57
+ <h1 class="article-title">{page.title}</h1>
58
+ ) : null}
46
59
 
47
60
  {/* Metadata - Medium style */}
48
61
  {page.layout !== "page" ? (
49
62
  <div class="article-header-meta">
50
63
  <div class="article-meta-info">
51
64
  {page.date && (
52
- <time class="article-date" datetime={page.date.toISOString()}>
65
+ <time
66
+ class="article-date"
67
+ datetime={page.date.toISOString()}
68
+ >
53
69
  {format(page.date, "LLL dd")}
54
70
  </time>
55
71
  )}
56
- {page.date && (wordCount > 0 || !index) && <span class="meta-separator">·</span>}
57
- {wordCount > 0 && <span class="article-reading-time">{readTime} min</span>}
72
+ {page.date && (wordCount > 0 || !index) && (
73
+ <span class="meta-separator">·</span>
74
+ )}
75
+ {wordCount > 0 && (
76
+ <span class="article-reading-time">{readTime} min</span>
77
+ )}
58
78
  {!index && (
59
79
  <Fragment>
60
80
  <span class="meta-separator">·</span>
@@ -73,7 +93,11 @@ module.exports = class extends Component {
73
93
  {page.tags.map((tag, idx) => (
74
94
  <Fragment>
75
95
  {idx > 0 && <span class="meta-separator">,</span>}
76
- <a class="article-tag" rel="tag" href={url_for(tag.path)}>
96
+ <a
97
+ class="article-tag"
98
+ rel="tag"
99
+ href={url_for(tag.path)}
100
+ >
77
101
  {tag.name}
78
102
  </a>
79
103
  </Fragment>
@@ -91,13 +115,22 @@ module.exports = class extends Component {
91
115
  }}
92
116
  ></div>
93
117
  {/* Licensing block */}
94
- {!index && article && article.licenses && Object.keys(article.licenses) ? (
95
- <ArticleLicensing.Cacheable page={page} config={config} helper={helper} />
118
+ {!index &&
119
+ article &&
120
+ article.licenses &&
121
+ Object.keys(article.licenses) ? (
122
+ <ArticleLicensing.Cacheable
123
+ page={page}
124
+ config={config}
125
+ helper={helper}
126
+ />
96
127
  ) : null}
97
128
  </article>
98
129
  </div>
99
130
  {/* Comment */}
100
- {!index ? <Comment config={config} page={page} helper={helper} /> : null}
131
+ {!index ? (
132
+ <Comment config={config} page={page} helper={helper} />
133
+ ) : null}
101
134
  </Fragment>
102
135
  );
103
136
  }
@@ -90,7 +90,8 @@ module.exports = class extends Component {
90
90
  if (
91
91
  typeof structured_data === "object" &&
92
92
  structured_data !== null &&
93
- ((Array.isArray(structured_data.image) && structured_data.image.length > 0) ||
93
+ ((Array.isArray(structured_data.image) &&
94
+ structured_data.image.length > 0) ||
94
95
  typeof structured_data.image === "string")
95
96
  ) {
96
97
  structuredImages = structured_data.image;
@@ -144,7 +145,9 @@ module.exports = class extends Component {
144
145
  page.content ||
145
146
  config.description
146
147
  }
147
- keywords={(page.tags?.length ? page.tags : undefined) || config.keywords}
148
+ keywords={
149
+ (page.tags?.length ? page.tags : undefined) || config.keywords
150
+ }
148
151
  url={open_graph.url || page.permalink || url}
149
152
  images={openGraphImages}
150
153
  siteName={open_graph.site_name || config.title}
@@ -221,7 +224,13 @@ module.exports = class extends Component {
221
224
  onload="this.onload=null;this.rel='stylesheet'"
222
225
  />
223
226
  <link rel="stylesheet" href="/css/shiki/shiki.css" />
224
- <Plugins site={site} config={config} helper={helper} page={page} head={true} />
227
+ <Plugins
228
+ site={site}
229
+ config={config}
230
+ helper={helper}
231
+ page={page}
232
+ head={true}
233
+ />
225
234
  {adsenseClientId ? (
226
235
  <script
227
236
  data-ad-client={adsenseClientId}
@@ -7,24 +7,45 @@ module.exports = class extends Component {
7
7
 
8
8
  return (
9
9
  <Fragment>
10
- {config.comment?.js_url && <script defer src={config.comment.js_url}></script>}
11
- <Plugins site={site} config={config} page={page} helper={helper} head={false} />
10
+ {config.comment?.js_url && (
11
+ <script defer src={config.comment.js_url}></script>
12
+ )}
13
+ <Plugins
14
+ site={site}
15
+ config={config}
16
+ page={page}
17
+ helper={helper}
18
+ head={false}
19
+ />
12
20
  <script defer data-pjax src="/js/main.js"></script>
13
- <script async src="/js/host/iconify-icon/3.0.2/iconify-icon.min.js"></script>
21
+ <script
22
+ async
23
+ src="/js/host/iconify-icon/3.0.2/iconify-icon.min.js"
24
+ ></script>
14
25
  <script async src="/js/theme-selector.js"></script>
15
- <script defer src="/js/host/medium-zoom/dist/medium-zoom.min.js"></script>
26
+ <script
27
+ defer
28
+ src="/js/host/medium-zoom/dist/medium-zoom.min.js"
29
+ ></script>
16
30
  <script async src="/js/shiki/shiki.js"></script>
17
31
  <script async src="/js/instant-page.min.js" type="module"></script>
18
32
  {config?.plugins?.live2d_Asoul && (
19
33
  <>
20
34
  <script defer src="/js/live2d_Asoul/TweenLite.min.js"></script>
21
- <script defer src="/js/live2d_Asoul/live2dcubismcore.min.js"></script>
35
+ <script
36
+ defer
37
+ src="/js/live2d_Asoul/live2dcubismcore.min.js"
38
+ ></script>
22
39
  <script defer src="/js/live2d_Asoul/pixi.min.js"></script>
23
40
  <script defer src="/js/live2d_Asoul/cubism4.min.js"></script>
24
41
  <script defer src="/js/live2d_Asoul/pio.js"></script>
25
42
  <script defer src="/js/live2d_Asoul/pio_sdk4.js"></script>
26
43
  <script defer src="/js/live2d_Asoul/load.js"></script>
27
- <link href="/js/live2d_Asoul/pio.css" rel="stylesheet" type="text/css" />
44
+ <link
45
+ href="/js/live2d_Asoul/pio.css"
46
+ rel="stylesheet"
47
+ type="text/css"
48
+ />
28
49
  </>
29
50
  )}
30
51
  </Fragment>
@@ -67,7 +67,12 @@ class ArticleLicensing extends Component {
67
67
  <p>{licensedTitle}</p>
68
68
  <p>
69
69
  {Object.keys(licenses).map((name) => (
70
- <a rel="noopener" target="_blank" title={name} href={licenses[name].url}>
70
+ <a
71
+ rel="noopener"
72
+ target="_blank"
73
+ title={name}
74
+ href={licenses[name].url}
75
+ >
71
76
  <iconify-icon icon={licenses[name].icon} />
72
77
  </a>
73
78
  ))}
@@ -82,33 +87,39 @@ class ArticleLicensing extends Component {
82
87
  }
83
88
  }
84
89
 
85
- ArticleLicensing.Cacheable = cacheComponent(ArticleLicensing, "misc.articlelicensing", (props) => {
86
- const { config, page, helper } = props;
87
- const { licenses } = config.article || {};
90
+ ArticleLicensing.Cacheable = cacheComponent(
91
+ ArticleLicensing,
92
+ "misc.articlelicensing",
93
+ (props) => {
94
+ const { config, page, helper } = props;
95
+ const { licenses } = config.article || {};
88
96
 
89
- const links = {};
90
- if (licenses) {
91
- Object.keys(licenses).forEach((name) => {
92
- const license = licenses[name];
93
- links[name] = {
94
- url: helper.url_for(typeof license === "string" ? license : license.url),
95
- icon: license.icon,
96
- };
97
- });
98
- }
97
+ const links = {};
98
+ if (licenses) {
99
+ Object.keys(licenses).forEach((name) => {
100
+ const license = licenses[name];
101
+ links[name] = {
102
+ url: helper.url_for(
103
+ typeof license === "string" ? license : license.url,
104
+ ),
105
+ icon: license.icon,
106
+ };
107
+ });
108
+ }
99
109
 
100
- return {
101
- title: page.title,
102
- link: decodeURI(page.permalink),
103
- author: page.author || config.author,
104
- authorTitle: helper.__("article.licensing.author"),
105
- createdAt: page.date ? helper.date(page.date) : null,
106
- createdTitle: helper.__("article.licensing.created_at"),
107
- updatedAt: page.updated ? helper.date(page.updated) : null,
108
- updatedTitle: helper.__("article.licensing.updated_at"),
109
- licenses: links,
110
- licensedTitle: helper.__("article.licensing.licensed_under"),
111
- };
112
- });
110
+ return {
111
+ title: page.title,
112
+ link: decodeURI(page.permalink),
113
+ author: page.author || config.author,
114
+ authorTitle: helper.__("article.licensing.author"),
115
+ createdAt: page.date ? helper.date(page.date) : null,
116
+ createdTitle: helper.__("article.licensing.created_at"),
117
+ updatedAt: page.updated ? helper.date(page.updated) : null,
118
+ updatedTitle: helper.__("article.licensing.updated_at"),
119
+ licenses: links,
120
+ licensedTitle: helper.__("article.licensing.licensed_under"),
121
+ };
122
+ },
123
+ );
113
124
 
114
125
  module.exports = ArticleLicensing;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hexo-theme-gnix",
3
- "version": "4.0.3",
3
+ "version": "4.0.5",
4
4
  "author": "Efterklang <gaojiaxing0220@gmail.com>",
5
5
  "license": "MIT",
6
6
  "description": "Second generation of Hexo theme Icarus, now with Catppuccin flavor and night mode support.",
@@ -116,4 +116,4 @@ details[open].callout > .callout-title > .callout-fold {
116
116
  .callout[data-callout="cite"] {
117
117
  --callout-icon: quote-glyph;
118
118
  --callout-color: var(--lavender);
119
- }
119
+ }
@@ -1,15 +1,16 @@
1
1
  @charset "UTF-8";
2
2
 
3
3
  :root {
4
- --font-serif: Georgia, "Times New Roman", Times, "Songti SC", "STSong", serif;
4
+ --font-serif:
5
+ "PT Serif", Georgia, "Times New Roman", Times, "Songti SC", "STSong", serif;
5
6
  --font-sans-serif:
6
- Avenir, Futura, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
7
+ Avenir, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
7
8
  Oxygen, Ubuntu, Cantarell, "Open Sans", "Helvetica Neue", sans-serif;
8
9
  --font-monospace:
9
- "Maple Mono NF CN", "Maple Mono NF", "SF Mono", "SF Pro", Menlo, Monaco,
10
+ "Maple Mono NF CN Local", "Maple Mono NF CN", "SF Mono", "SF Pro", Monaco,
10
11
  Consolas, "Liberation Mono", "Courier New", monospace;
11
12
  --font-article:
12
- system-ui, "Segoe UI", Roboto, Helvetica, Arial, "PingFang SC",
13
+ Avenir, system-ui, "Segoe UI", Roboto, Helvetica, Arial, "PingFang SC",
13
14
  "Hiragino Sans GB", "Microsoft YaHei", "Noto Sans CJK SC",
14
15
  "Source Han Sans CN", sans-serif;
15
16
  }
@@ -203,24 +204,53 @@ a:hover {
203
204
  color: var(--blue);
204
205
  }
205
206
 
206
- h2 {
207
+ a.header-anchor {
208
+ font-family: var(--font-sans-serif);
209
+ }
210
+
211
+ a.header-anchor:hover::after {
212
+ margin-left: 0.2em;
213
+ color: var(--surface0);
214
+ }
215
+
216
+ h2 a.header-anchor {
207
217
  color: var(--peach);
218
+
219
+ &:hover::after {
220
+ content: "##";
221
+ }
208
222
  }
209
223
 
210
- h3 {
224
+ h3 a.header-anchor {
211
225
  color: var(--yellow);
226
+
227
+ &:hover::after {
228
+ content: "###";
229
+ }
212
230
  }
213
231
 
214
- h4 {
232
+ h4 a.header-anchor {
215
233
  color: var(--green);
234
+
235
+ &:hover::after {
236
+ content: "####";
237
+ }
216
238
  }
217
239
 
218
- h5 {
240
+ h5 a.header-anchor {
219
241
  color: var(--blue);
242
+
243
+ &:hover::after {
244
+ content: "#####";
245
+ }
220
246
  }
221
247
 
222
- h6 {
248
+ h6 a.header-anchor {
223
249
  color: var(--mauve);
250
+
251
+ &:hover::after {
252
+ content: "######";
253
+ }
224
254
  }
225
255
 
226
256
  mark {
@@ -342,6 +372,13 @@ input:-webkit-autofill {
342
372
  /* #endregion Color */
343
373
 
344
374
  /* #region Font */
375
+
376
+ @font-face {
377
+ font-family: "Maple Mono NF CN Local";
378
+ font-weight: 100 900;
379
+ src: local("MapleMono-NF-CN-Regular");
380
+ }
381
+
345
382
  @font-face {
346
383
  font-family: doto;
347
384
  font-style: normal;
@@ -360,14 +397,6 @@ input:-webkit-autofill {
360
397
  url(/css/font/woff2/Paris2024-Variable.woff2) format("woff2");
361
398
  }
362
399
 
363
- @font-face {
364
- font-family: Futura;
365
- font-weight: 400;
366
- src:
367
- local("Futura"),
368
- url(/css/font/woff2/Futura-Book.woff2) format("woff2");
369
- }
370
-
371
400
  /* #endregion */
372
401
 
373
402
  blockquote,
@@ -920,7 +949,7 @@ video {
920
949
  }
921
950
 
922
951
  h2 {
923
- font-size: 2em;
952
+ font-size: 2.25em;
924
953
  font-weight: 700;
925
954
  line-height: 1.25;
926
955
  letter-spacing: -0.02em;
@@ -928,7 +957,7 @@ video {
928
957
  }
929
958
 
930
959
  h3 {
931
- font-size: 1.875em;
960
+ font-size: 2em;
932
961
  font-weight: 700;
933
962
  line-height: 1.25;
934
963
  letter-spacing: -0.015em;
@@ -936,7 +965,7 @@ video {
936
965
  }
937
966
 
938
967
  h4 {
939
- font-size: 1.5em;
968
+ font-size: 1.75em;
940
969
  font-weight: 600;
941
970
  line-height: 1.25;
942
971
  letter-spacing: -0.01em;
@@ -944,7 +973,7 @@ video {
944
973
  }
945
974
 
946
975
  h5 {
947
- font-size: 1.25em;
976
+ font-size: 1.5em;
948
977
  font-weight: 600;
949
978
  line-height: 1.25;
950
979
  letter-spacing: -0.005em;
@@ -952,7 +981,7 @@ video {
952
981
  }
953
982
 
954
983
  h6 {
955
- font-size: 1.2em;
984
+ font-size: 1.25em;
956
985
  font-weight: 600;
957
986
  line-height: 1.25;
958
987
  margin: 1.2rem 0 1rem;
@@ -967,7 +996,6 @@ video {
967
996
  ul,
968
997
  ol,
969
998
  dl,
970
- table,
971
999
  pre,
972
1000
  details {
973
1001
  margin-top: 0;
@@ -989,11 +1017,10 @@ video {
989
1017
  video {
990
1018
  display: block;
991
1019
  margin: 0 auto;
992
- }
993
1020
 
994
- img:hover,
995
- video:hover {
996
- cursor: pointer;
1021
+ &:hover {
1022
+ cursor: pointer;
1023
+ }
997
1024
  }
998
1025
 
999
1026
  ol {
@@ -1008,15 +1035,15 @@ video {
1008
1035
  padding-left: 2em;
1009
1036
  margin-top: 0;
1010
1037
  margin-bottom: 0;
1011
- }
1012
1038
 
1013
- ul ul {
1014
- list-style-type: circle;
1015
- margin-top: 0.5em;
1016
- }
1039
+ ul {
1040
+ margin-top: 0.5em;
1041
+ list-style: circle;
1017
1042
 
1018
- ul ul ul {
1019
- list-style-type: square;
1043
+ ul {
1044
+ list-style: square;
1045
+ }
1046
+ }
1020
1047
  }
1021
1048
 
1022
1049
  dd {
@@ -1168,7 +1195,7 @@ blockquote {
1168
1195
  }
1169
1196
 
1170
1197
  blockquote:before {
1171
- content: '';
1198
+ content: "";
1172
1199
  position: absolute;
1173
1200
  left: 0.5rem;
1174
1201
  top: 0.2rem;
@@ -1319,11 +1346,11 @@ section {
1319
1346
 
1320
1347
  .article-title {
1321
1348
  font-family: var(--font-article);
1322
- font-size: 3em;
1323
- font-weight: 800;
1349
+ font-size: 2.75em;
1350
+ font-weight: bold;
1324
1351
  line-height: 1.2;
1325
1352
  letter-spacing: -0.02em;
1326
- margin-bottom: 0.4em;
1353
+ margin-bottom: 0.3em;
1327
1354
  color: var(--text);
1328
1355
  word-break: break-word;
1329
1356
  }
@@ -1334,10 +1361,8 @@ section {
1334
1361
 
1335
1362
  .article-header-meta {
1336
1363
  font-family: var(--font-monospace);
1337
- font-style: italic;
1338
1364
  overflow: auto;
1339
1365
  margin-bottom: 1rem;
1340
- padding-bottom: 0.5rem;
1341
1366
  border-bottom: 1px dashed var(--surface0);
1342
1367
  color: var(--subtext0);
1343
1368
  display: flex;
@@ -1433,7 +1458,7 @@ section {
1433
1458
  width: 100%;
1434
1459
  height: 100%;
1435
1460
  z-index: 100;
1436
- font-family: var(--font-monospace);
1461
+ font-family: monospace, var(--font-monospace);
1437
1462
  line-height: 0;
1438
1463
  opacity: 0;
1439
1464
  visibility: hidden;
@@ -161,4 +161,4 @@
161
161
  padding: 0;
162
162
  margin: 0;
163
163
  display: contents;
164
- }
164
+ }
@@ -46,4 +46,4 @@ table td {
46
46
  .pagination-list li {
47
47
  flex-grow: 1;
48
48
  flex-shrink: 1;
49
- }
49
+ }
@@ -40,4 +40,4 @@
40
40
 
41
41
  .pagination-next {
42
42
  order: 3;
43
- }
43
+ }
@@ -184,7 +184,7 @@
184
184
  }
185
185
 
186
186
  #icarus-toc-container .toc-item {
187
- margin-bottom: .5rem;
187
+ margin-bottom: 0.5rem;
188
188
  }
189
189
 
190
190
  #icarus-toc-container .toc-text {
@@ -249,4 +249,4 @@
249
249
  width: 90%;
250
250
  }
251
251
 
252
- /* #endregion TOC */
252
+ /* #endregion TOC */
@@ -135,7 +135,6 @@ figure.shiki {
135
135
  }
136
136
 
137
137
  @keyframes code-expand-pulse {
138
-
139
138
  0%,
140
139
  to {
141
140
  opacity: 0.6;
@@ -168,7 +167,6 @@ figure.shiki {
168
167
  }
169
168
  }
170
169
 
171
-
172
170
  pre.shiki {
173
171
  background: var(--mantle);
174
172
  padding: 0.6em;
@@ -221,10 +219,12 @@ figure.shiki[data-collapsible="true"]:not(.expanded) > pre.shiki:after {
221
219
  height: 80px;
222
220
  pointer-events: none;
223
221
  z-index: 1;
224
- background: linear-gradient(transparent 0%,
225
- hsl(from var(--mantle) h s l / 0.8),
226
- 30%,
227
- var(--mantle) 100%);
222
+ background: linear-gradient(
223
+ transparent 0%,
224
+ hsl(from var(--mantle) h s l / 0.8),
225
+ 30%,
226
+ var(--mantle) 100%
227
+ );
228
228
  opacity: 1;
229
229
  }
230
230
 
@@ -1651,4 +1651,4 @@ pre.shiki.has-focused > code {
1651
1651
  --shiki-nord-font-weight: inherit;
1652
1652
  --shiki-tokyo: #89ddff;
1653
1653
  --shiki-tokyo-font-weight: bold;
1654
- }
1654
+ }
@@ -547,7 +547,7 @@
547
547
  height: 32px;
548
548
  width: 50px;
549
549
  margin: 0 0.5em;
550
- padding-left: .5em;
550
+ padding-left: 0.5em;
551
551
  font-size: 1em;
552
552
  color: var(--text);
553
553
  background: var(--surface0);
@@ -676,9 +676,7 @@
676
676
  height: 100%;
677
677
  overflow-y: auto;
678
678
  pointer-events: all;
679
- color: var(--text);
680
679
  background-color: var(--mantle);
681
- transition: all 0.5s ease;
682
680
  visibility: hidden;
683
681
  }
684
682
 
@@ -723,7 +721,6 @@
723
721
  }
724
722
 
725
723
  .tk-login-title {
726
- color: var(--base);
727
724
  font-size: 1.25rem;
728
725
  text-align: center;
729
726
  margin-top: 10rem;
@@ -731,7 +728,6 @@
731
728
 
732
729
  .tk-password,
733
730
  .tk-login-msg {
734
- color: var(--base);
735
731
  width: 80%;
736
732
  text-align: center;
737
733
  margin-top: 1rem;
@@ -752,7 +748,6 @@
752
748
  }
753
749
 
754
750
  .tk-panel {
755
- /* color: var(--text); */
756
751
  padding: 2rem;
757
752
  }
758
753
 
@@ -2129,4 +2124,4 @@
2129
2124
  stroke-dasharray: 90, 150;
2130
2125
  stroke-dashoffset: -120px;
2131
2126
  }
2132
- }
2127
+ }
@@ -28,6 +28,18 @@ function loadInsight(config, translation) {
28
28
 
29
29
  // --- 核心逻辑优化区 ---
30
30
 
31
+ // HTML 转义函数,防止 XSS 攻击和标签渲染异常
32
+ function escapeHTML(str) {
33
+ const map = {
34
+ "&": "&amp;",
35
+ "<": "&lt;",
36
+ ">": "&gt;",
37
+ '"': "&quot;",
38
+ "'": "&#039;",
39
+ };
40
+ return str.replace(/[&<>"']/g, (m) => map[m]);
41
+ }
42
+
31
43
  // 优化点:合并 ranges 的逻辑保持不变,这是高亮的核心算法
32
44
  function merge(ranges) {
33
45
  let last;
@@ -44,7 +56,7 @@ function loadInsight(config, translation) {
44
56
 
45
57
  function findAndHighlight(text, matches, maxlen) {
46
58
  if (!Array.isArray(matches) || !matches.length || !text) {
47
- return maxlen ? text.slice(0, maxlen) : text;
59
+ return maxlen ? escapeHTML(text.slice(0, maxlen)) : escapeHTML(text);
48
60
  }
49
61
  const testText = text.toLowerCase();
50
62
 
@@ -60,7 +72,8 @@ function loadInsight(config, translation) {
60
72
  // 排序
61
73
  indices.sort((a, b) => a[0] - b[0] || a[1] - b[1]);
62
74
 
63
- if (!indices.length) return maxlen ? text.slice(0, maxlen) : text;
75
+ if (!indices.length)
76
+ return maxlen ? escapeHTML(text.slice(0, maxlen)) : escapeHTML(text);
64
77
 
65
78
  let result = "";
66
79
  let last = 0;
@@ -73,20 +86,24 @@ function loadInsight(config, translation) {
73
86
 
74
87
  for (let i = 0; i < ranges.length; i++) {
75
88
  const range = ranges[i];
76
- result += text.slice(last, Math.min(range[0], sumRange[0] + maxlen));
89
+ result += escapeHTML(
90
+ text.slice(last, Math.min(range[0], sumRange[0] + maxlen)),
91
+ );
77
92
  if (maxlen && range[0] >= sumRange[0] + maxlen) break;
78
93
 
79
- result += `<em>${text.slice(range[0], range[1])}</em>`;
94
+ result += `<em>${escapeHTML(text.slice(range[0], range[1]))}</em>`;
80
95
  last = range[1];
81
96
 
82
97
  if (i === ranges.length - 1) {
83
98
  if (maxlen) {
84
- result += text.slice(
85
- range[1],
86
- Math.min(text.length, sumRange[0] + maxlen + 1),
99
+ result += escapeHTML(
100
+ text.slice(
101
+ range[1],
102
+ Math.min(text.length, sumRange[0] + maxlen + 1),
103
+ ),
87
104
  );
88
105
  } else {
89
- result += text.slice(range[1]);
106
+ result += escapeHTML(text.slice(range[1]));
90
107
  }
91
108
  }
92
109
  }
@@ -137,6 +154,12 @@ function loadInsight(config, translation) {
137
154
  .map((k) => k.toLowerCase());
138
155
  }
139
156
 
157
+ /**
158
+ *
159
+ * @param {{posts: Array, tags: Array}} json: dataset generatored from content.json
160
+ * @param {string} keywordsStr: user input keywords string
161
+ * @returns
162
+ */
140
163
  function search(json, keywordsStr) {
141
164
  const keywords = parseKeywords(keywordsStr);
142
165
  if (keywords.length === 0) return {};
@@ -196,7 +219,6 @@ function loadInsight(config, translation) {
196
219
 
197
220
  return {
198
221
  posts: executeSearch(json.posts, ["title", "text"], [3, 1]),
199
- pages: executeSearch(json.pages, ["title", "text"], [3, 1]),
200
222
  tags: executeSearch(json.tags, ["name", "slug"], [1, 1]),
201
223
  };
202
224
  }
@@ -65,9 +65,7 @@
65
65
 
66
66
  // Set initial focus
67
67
  updateFocus(themeOptions);
68
-
69
68
  modal.classList.add("is-active");
70
- document.body.style.overflow = "hidden";
71
69
  }
72
70
 
73
71
  function closeModal(apply = false) {
@@ -85,7 +83,6 @@
85
83
  }
86
84
 
87
85
  modal.classList.remove("is-active");
88
- document.body.style.overflow = "";
89
86
  previewTheme = null;
90
87
  originalTheme = null;
91
88
 
@@ -1,12 +0,0 @@
1
- // Generate "<root>/tags/" page
2
- module.exports = (hexo) => {
3
- hexo.extend.generator.register("tags", (locals) => {
4
- return {
5
- path: "tags/",
6
- layout: ["tags"],
7
- data: Object.assign({}, locals, {
8
- __tags: true,
9
- }),
10
- };
11
- });
12
- };
File without changes