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.
- package/include/hexo/{generator/insight.js → generator.js} +11 -7
- package/include/register.js +2 -3
- package/layout/archive.jsx +8 -2
- package/layout/common/article.jsx +44 -11
- package/layout/common/head.jsx +12 -3
- package/layout/common/scripts.jsx +27 -6
- package/layout/misc/article_licensing.jsx +38 -27
- package/package.json +1 -1
- package/source/css/callout_blocks.css +1 -1
- package/source/css/default.css +66 -41
- package/source/css/responsive/desktop.css +1 -1
- package/source/css/responsive/mobile.css +1 -1
- package/source/css/responsive/tablet.css +1 -1
- package/source/css/responsive/touch.css +2 -2
- package/source/css/shiki/shiki.css +7 -7
- package/source/css/twikoo.css +2 -7
- package/source/js/insight.js +31 -9
- package/source/js/theme-selector.js +0 -3
- package/include/hexo/generator/tags.js +0 -12
- package/source/css/font/woff2/Futura-Book.woff2 +0 -0
- /package/include/hexo/{filter/locals.js → filter.js} +0 -0
|
@@ -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
|
};
|
package/include/register.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
module.exports = (hexo) => {
|
|
2
|
-
require("./hexo/filter
|
|
3
|
-
require("./hexo/generator
|
|
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);
|
package/layout/archive.jsx
CHANGED
|
@@ -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
|
|
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(
|
|
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
|
|
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 ?
|
|
38
|
-
|
|
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 ?
|
|
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
|
|
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) &&
|
|
57
|
-
|
|
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
|
|
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 &&
|
|
95
|
-
|
|
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 ?
|
|
131
|
+
{!index ? (
|
|
132
|
+
<Comment config={config} page={page} helper={helper} />
|
|
133
|
+
) : null}
|
|
101
134
|
</Fragment>
|
|
102
135
|
);
|
|
103
136
|
}
|
package/layout/common/head.jsx
CHANGED
|
@@ -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) &&
|
|
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={
|
|
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
|
|
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 &&
|
|
11
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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(
|
|
86
|
-
|
|
87
|
-
|
|
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
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
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
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
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
package/source/css/default.css
CHANGED
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
@charset "UTF-8";
|
|
2
2
|
|
|
3
3
|
:root {
|
|
4
|
-
--font-serif:
|
|
4
|
+
--font-serif:
|
|
5
|
+
"PT Serif", Georgia, "Times New Roman", Times, "Songti SC", "STSong", serif;
|
|
5
6
|
--font-sans-serif:
|
|
6
|
-
Avenir,
|
|
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",
|
|
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
|
-
|
|
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:
|
|
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:
|
|
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.
|
|
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.
|
|
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.
|
|
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
|
-
|
|
995
|
-
|
|
996
|
-
|
|
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
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
}
|
|
1039
|
+
ul {
|
|
1040
|
+
margin-top: 0.5em;
|
|
1041
|
+
list-style: circle;
|
|
1017
1042
|
|
|
1018
|
-
|
|
1019
|
-
|
|
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:
|
|
1323
|
-
font-weight:
|
|
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.
|
|
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;
|
|
@@ -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(
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
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
|
+
}
|
package/source/css/twikoo.css
CHANGED
|
@@ -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
|
+
}
|
package/source/js/insight.js
CHANGED
|
@@ -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
|
+
"&": "&",
|
|
35
|
+
"<": "<",
|
|
36
|
+
">": ">",
|
|
37
|
+
'"': """,
|
|
38
|
+
"'": "'",
|
|
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)
|
|
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 +=
|
|
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 +=
|
|
85
|
-
|
|
86
|
-
|
|
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
|
|
|
Binary file
|
|
File without changes
|