hexo-theme-gnix 3.3.1 → 4.0.0
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/README.md +2 -0
- package/include/hexo/generator/insight.js +0 -1
- package/include/hexo/{helper/cdn.js → helper.js} +3 -0
- package/include/register.js +1 -4
- package/layout/archive.jsx +6 -22
- package/layout/common/article.jsx +22 -75
- package/layout/common/article_cover.jsx +1 -5
- package/layout/common/article_media.jsx +6 -16
- package/layout/common/head.jsx +4 -18
- package/layout/search/insight.jsx +0 -1
- package/package.json +1 -1
- package/source/css/callout_blocks.css +1 -1
- package/source/css/default.css +66 -79
- package/source/css/shiki/shiki.css +1 -1
- package/source/js/insight.js +1 -2
- package/include/hexo/generator/categories.js +0 -12
- package/include/hexo/generator/category.js +0 -52
- package/include/hexo/helper/page.js +0 -27
- package/layout/categories.jsx +0 -147
- package/layout/category.jsx +0 -38
package/README.md
CHANGED
|
@@ -33,7 +33,6 @@ module.exports = (hexo) => {
|
|
|
33
33
|
const site = {
|
|
34
34
|
posts: locals.posts.map(mapPost),
|
|
35
35
|
tags: locals.tags.map(mapTag),
|
|
36
|
-
categories: locals.categories.map(mapTag),
|
|
37
36
|
};
|
|
38
37
|
const index_pages = this.theme.config?.search?.index_pages;
|
|
39
38
|
if (index_pages === false) {
|
|
@@ -18,4 +18,7 @@ module.exports = (hexo) => {
|
|
|
18
18
|
cdn = this.config.providers?.cdn ? this.config.providers.cdn : "jsdelivr";
|
|
19
19
|
return getCDN(cdn, _package, version, filename);
|
|
20
20
|
});
|
|
21
|
+
hexo.extend.helper.register("is_tags", function (page = null) {
|
|
22
|
+
return (page === null ? this.page : page).__tags === true;
|
|
23
|
+
});
|
|
21
24
|
};
|
package/include/register.js
CHANGED
|
@@ -1,11 +1,8 @@
|
|
|
1
1
|
module.exports = (hexo) => {
|
|
2
2
|
require("./hexo/filter/locals")(hexo);
|
|
3
3
|
require("./hexo/generator/insight")(hexo);
|
|
4
|
-
require("./hexo/generator/categories")(hexo);
|
|
5
|
-
require("./hexo/generator/category")(hexo);
|
|
6
4
|
require("./hexo/generator/tags")(hexo);
|
|
7
|
-
require("./hexo/helper/cdn")(hexo);
|
|
8
|
-
require("./hexo/helper/page")(hexo);
|
|
9
5
|
require("./hexo/view").init(hexo);
|
|
6
|
+
require("./hexo/helper")(hexo);
|
|
10
7
|
require("./hexo/renderer")(hexo);
|
|
11
8
|
};
|
package/layout/archive.jsx
CHANGED
|
@@ -10,13 +10,12 @@ module.exports = class extends Component {
|
|
|
10
10
|
|
|
11
11
|
const inlineCSS = `
|
|
12
12
|
.article-meta {
|
|
13
|
-
font-family: var(--font-monospace);
|
|
14
13
|
font-size: 0.8rem;
|
|
15
|
-
|
|
14
|
+
color: var(--subtext1);
|
|
16
15
|
margin-bottom: 0.1rem;
|
|
17
16
|
}
|
|
18
17
|
|
|
19
|
-
.
|
|
18
|
+
a.archive-title {
|
|
20
19
|
color: var(--text);
|
|
21
20
|
|
|
22
21
|
&:hover {
|
|
@@ -24,10 +23,6 @@ module.exports = class extends Component {
|
|
|
24
23
|
}
|
|
25
24
|
}
|
|
26
25
|
|
|
27
|
-
.article-meta span {
|
|
28
|
-
padding-right: 0.5rem;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
26
|
span.year {
|
|
32
27
|
position: absolute;
|
|
33
28
|
top: 1.5rem;
|
|
@@ -36,7 +31,7 @@ module.exports = class extends Component {
|
|
|
36
31
|
font-size: 7.5rem;
|
|
37
32
|
font-weight: bolder;
|
|
38
33
|
font-family: Paris2024;
|
|
39
|
-
color: hsl(from var(--
|
|
34
|
+
color: hsl(from var(--lavender) h s l / 0.15);
|
|
40
35
|
line-height: 1;
|
|
41
36
|
user-select: none;
|
|
42
37
|
}
|
|
@@ -55,7 +50,7 @@ module.exports = class extends Component {
|
|
|
55
50
|
.archive-item + .archive-item {
|
|
56
51
|
border: none;
|
|
57
52
|
margin-top: 0;
|
|
58
|
-
padding-top:
|
|
53
|
+
padding-top: .5rem;
|
|
59
54
|
}
|
|
60
55
|
`;
|
|
61
56
|
function renderArticleList(posts, year, month = null) {
|
|
@@ -68,25 +63,16 @@ module.exports = class extends Component {
|
|
|
68
63
|
<div class="card">
|
|
69
64
|
<div class="card-content">
|
|
70
65
|
<span class="year">
|
|
71
|
-
{month === null
|
|
72
|
-
? year
|
|
73
|
-
: isValid(time)
|
|
74
|
-
? format(time, "LLLL yyyy")
|
|
75
|
-
: year}
|
|
66
|
+
{month === null ? year : isValid(time) ? format(time, "LLLL yyyy") : year}
|
|
76
67
|
</span>
|
|
77
68
|
<div class="timeline">
|
|
78
69
|
{posts.map((post) => {
|
|
79
|
-
const categories = post.categories.map((category) => ({
|
|
80
|
-
url: url_for(category.path),
|
|
81
|
-
name: category.name,
|
|
82
|
-
}));
|
|
83
70
|
return (
|
|
84
71
|
<ArticleMedia
|
|
85
72
|
url={url_for(post.link || post.path)}
|
|
86
73
|
title={post.title}
|
|
87
74
|
date={date(post.date)}
|
|
88
75
|
dateXml={date_xml(post.date)}
|
|
89
|
-
categories={categories}
|
|
90
76
|
/>
|
|
91
77
|
);
|
|
92
78
|
})}
|
|
@@ -105,9 +91,7 @@ module.exports = class extends Component {
|
|
|
105
91
|
articleList = Object.keys(years)
|
|
106
92
|
.sort((a, b) => b - a)
|
|
107
93
|
.map((year) => {
|
|
108
|
-
const posts = page.posts.filter(
|
|
109
|
-
(p) => p.date.year() === parseInt(year, 10),
|
|
110
|
-
);
|
|
94
|
+
const posts = page.posts.filter((p) => p.date.year() === parseInt(year, 10));
|
|
111
95
|
return renderArticleList(posts, year, null);
|
|
112
96
|
});
|
|
113
97
|
} else {
|
|
@@ -14,9 +14,7 @@ function getWordCount(content) {
|
|
|
14
14
|
}
|
|
15
15
|
content = content.replace(/<\/?[a-z][^>]*>/gi, "");
|
|
16
16
|
content = content.trim();
|
|
17
|
-
return content
|
|
18
|
-
? (content.match(/[\u00ff-\uffff]|[a-zA-Z]+/g) || []).length
|
|
19
|
-
: 0;
|
|
17
|
+
return content ? (content.match(/[\u00ff-\uffff]|[a-zA-Z]+/g) || []).length : 0;
|
|
20
18
|
}
|
|
21
19
|
|
|
22
20
|
module.exports = class extends Component {
|
|
@@ -36,45 +34,27 @@ module.exports = class extends Component {
|
|
|
36
34
|
{/* Main content */}
|
|
37
35
|
<div class="card article-wrapper">
|
|
38
36
|
{/* Cover image */}
|
|
39
|
-
{cover ?
|
|
40
|
-
|
|
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
|
-
>
|
|
37
|
+
{cover ? <ArticleCover page={page} cover={cover} index={index} helper={helper} /> : null}
|
|
38
|
+
<article class={`card-content article${"direction" in page ? ` ${page.direction}` : ""}`}>
|
|
50
39
|
{/* Title */}
|
|
51
40
|
{page.title !== "" && index ? (
|
|
52
41
|
<h2 class="article-title">
|
|
53
42
|
<a href={url_for(page.link || page.path)}>{page.title}</a>
|
|
54
43
|
</h2>
|
|
55
44
|
) : null}
|
|
56
|
-
{page.title !== "" && !index ?
|
|
57
|
-
<h1 class="article-title">{page.title}</h1>
|
|
58
|
-
) : null}
|
|
45
|
+
{page.title !== "" && !index ? <h1 class="article-title">{page.title}</h1> : null}
|
|
59
46
|
|
|
60
47
|
{/* Metadata - Medium style */}
|
|
61
48
|
{page.layout !== "page" ? (
|
|
62
49
|
<div class="article-header-meta">
|
|
63
50
|
<div class="article-meta-info">
|
|
64
51
|
{page.date && (
|
|
65
|
-
<time
|
|
66
|
-
class="article-date"
|
|
67
|
-
datetime={page.date.toISOString()}
|
|
68
|
-
>
|
|
52
|
+
<time class="article-date" datetime={page.date.toISOString()}>
|
|
69
53
|
{format(page.date, "LLL dd")}
|
|
70
54
|
</time>
|
|
71
55
|
)}
|
|
72
|
-
{page.date && (wordCount > 0 || !index) &&
|
|
73
|
-
|
|
74
|
-
)}
|
|
75
|
-
{wordCount > 0 && (
|
|
76
|
-
<span class="article-reading-time">{readTime} min</span>
|
|
77
|
-
)}
|
|
56
|
+
{page.date && (wordCount > 0 || !index) && <span class="meta-separator">·</span>}
|
|
57
|
+
{wordCount > 0 && <span class="article-reading-time">{readTime} min</span>}
|
|
78
58
|
{!index && (
|
|
79
59
|
<Fragment>
|
|
80
60
|
<span class="meta-separator">·</span>
|
|
@@ -88,42 +68,18 @@ module.exports = class extends Component {
|
|
|
88
68
|
</Fragment>
|
|
89
69
|
)}
|
|
90
70
|
</div>
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
<
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
</Fragment>
|
|
104
|
-
))}
|
|
105
|
-
</div>
|
|
106
|
-
) : null}
|
|
107
|
-
{page.categories?.length && page.tags?.length ? (
|
|
108
|
-
<span class="meta-separator">·</span>
|
|
109
|
-
) : null}
|
|
110
|
-
{page.tags?.length ? (
|
|
111
|
-
<div class="article-tags-inline">
|
|
112
|
-
{page.tags.map((tag, idx) => (
|
|
113
|
-
<Fragment>
|
|
114
|
-
{idx > 0 && <span class="meta-separator">,</span>}
|
|
115
|
-
<a
|
|
116
|
-
class="article-tag"
|
|
117
|
-
rel="tag"
|
|
118
|
-
href={url_for(tag.path)}
|
|
119
|
-
>
|
|
120
|
-
{tag.name}
|
|
121
|
-
</a>
|
|
122
|
-
</Fragment>
|
|
123
|
-
))}
|
|
124
|
-
</div>
|
|
125
|
-
) : null}
|
|
126
|
-
</div>
|
|
71
|
+
{page.tags?.length ? (
|
|
72
|
+
<div class="article-tags-inline">
|
|
73
|
+
{page.tags.map((tag, idx) => (
|
|
74
|
+
<Fragment>
|
|
75
|
+
{idx > 0 && <span class="meta-separator">,</span>}
|
|
76
|
+
<a class="article-tag" rel="tag" href={url_for(tag.path)}>
|
|
77
|
+
{tag.name}
|
|
78
|
+
</a>
|
|
79
|
+
</Fragment>
|
|
80
|
+
))}
|
|
81
|
+
</div>
|
|
82
|
+
) : null}
|
|
127
83
|
</div>
|
|
128
84
|
) : null}
|
|
129
85
|
|
|
@@ -135,22 +91,13 @@ module.exports = class extends Component {
|
|
|
135
91
|
}}
|
|
136
92
|
></div>
|
|
137
93
|
{/* Licensing block */}
|
|
138
|
-
{!index &&
|
|
139
|
-
|
|
140
|
-
article.licenses &&
|
|
141
|
-
Object.keys(article.licenses) ? (
|
|
142
|
-
<ArticleLicensing.Cacheable
|
|
143
|
-
page={page}
|
|
144
|
-
config={config}
|
|
145
|
-
helper={helper}
|
|
146
|
-
/>
|
|
94
|
+
{!index && article && article.licenses && Object.keys(article.licenses) ? (
|
|
95
|
+
<ArticleLicensing.Cacheable page={page} config={config} helper={helper} />
|
|
147
96
|
) : null}
|
|
148
97
|
</article>
|
|
149
98
|
</div>
|
|
150
99
|
{/* Comment */}
|
|
151
|
-
{!index ?
|
|
152
|
-
<Comment config={config} page={page} helper={helper} />
|
|
153
|
-
) : null}
|
|
100
|
+
{!index ? <Comment config={config} page={page} helper={helper} /> : null}
|
|
154
101
|
</Fragment>
|
|
155
102
|
);
|
|
156
103
|
}
|
|
@@ -5,10 +5,7 @@ module.exports = class extends Component {
|
|
|
5
5
|
const { page, cover, helper } = this.props;
|
|
6
6
|
const { url_for } = helper;
|
|
7
7
|
|
|
8
|
-
const imageSrcset = `${cover}?w=
|
|
9
|
-
const coverLQIP = (
|
|
10
|
-
<img class="cover-lqip" alt="lqip" src={`${cover}?q=10&blur=25`} />
|
|
11
|
-
);
|
|
8
|
+
const imageSrcset = `${cover}?w=800 800w, ${cover}?w=1500 1500w, ${cover}?w=2000 2000w, ${cover} 6144w`;
|
|
12
9
|
const CoverImage = (
|
|
13
10
|
<img
|
|
14
11
|
class="fill"
|
|
@@ -25,7 +22,6 @@ module.exports = class extends Component {
|
|
|
25
22
|
<div class="card-image">
|
|
26
23
|
<a href={url_for(page.link || page.path)} class="image is-7by3">
|
|
27
24
|
{CoverImage}
|
|
28
|
-
{coverLQIP}
|
|
29
25
|
</a>
|
|
30
26
|
</div>
|
|
31
27
|
);
|
|
@@ -2,33 +2,23 @@
|
|
|
2
2
|
* Article media component, used in article lists such as archive page and recent posts widget
|
|
3
3
|
*/
|
|
4
4
|
const { Component } = require("inferno");
|
|
5
|
-
const { format, parseISO
|
|
5
|
+
const { format, parseISO } = require("date-fns");
|
|
6
6
|
|
|
7
7
|
module.exports = class extends Component {
|
|
8
8
|
render() {
|
|
9
|
-
const { url, title, date
|
|
9
|
+
const { url, title, date } = this.props;
|
|
10
10
|
// Formatted like May.15
|
|
11
|
-
|
|
12
|
-
const d = typeof date === "string" ? parseISO(date) : date;
|
|
13
|
-
formattedDate = isValid(d) ? format(d, "MMM.dd") : "";
|
|
14
|
-
const categoryTags = [];
|
|
15
|
-
categories.forEach((category, i) => {
|
|
16
|
-
categoryTags.push(<a href={category.url}>{category.name}</a>);
|
|
17
|
-
if (i < categories.length - 1) {
|
|
18
|
-
categoryTags.push("/");
|
|
19
|
-
}
|
|
20
|
-
});
|
|
11
|
+
const formattedDate = format(parseISO(date), "MMM dd");
|
|
21
12
|
|
|
22
13
|
return (
|
|
23
14
|
<article class="archive-item">
|
|
24
15
|
<div>
|
|
25
16
|
<p class="article-meta">
|
|
26
17
|
<span>{formattedDate}</span>
|
|
27
|
-
{categoryTags.length ? <span>{categoryTags}</span> : null}
|
|
28
|
-
</p>
|
|
29
|
-
<p class="title" style="font-size: 1em;">
|
|
30
|
-
<a href={url}>{title}</a>
|
|
31
18
|
</p>
|
|
19
|
+
<a class="archive-title" href={url}>
|
|
20
|
+
{title}
|
|
21
|
+
</a>
|
|
32
22
|
</div>
|
|
33
23
|
</article>
|
|
34
24
|
);
|
package/layout/common/head.jsx
CHANGED
|
@@ -14,12 +14,8 @@ function getPageTitle(page, siteTitle, helper) {
|
|
|
14
14
|
} else if (helper.is_year()) {
|
|
15
15
|
title += `: ${page.year}`;
|
|
16
16
|
}
|
|
17
|
-
} else if (helper.is_category()) {
|
|
18
|
-
title = `${helper._p("common.category", 1)}: ${page.category}`;
|
|
19
17
|
} else if (helper.is_tag()) {
|
|
20
18
|
title = `${helper._p("common.tag", 1)}: ${page.tag}`;
|
|
21
|
-
} else if (helper.is_categories()) {
|
|
22
|
-
title = helper._p("common.category", Infinity);
|
|
23
19
|
} else if (helper.is_tags()) {
|
|
24
20
|
title = helper._p("common.tag", Infinity);
|
|
25
21
|
}
|
|
@@ -43,8 +39,7 @@ module.exports = class extends Component {
|
|
|
43
39
|
favicon,
|
|
44
40
|
} = head;
|
|
45
41
|
|
|
46
|
-
const noIndex =
|
|
47
|
-
helper.is_archive() || helper.is_category() || helper.is_tag();
|
|
42
|
+
const noIndex = helper.is_archive() || helper.is_tag();
|
|
48
43
|
|
|
49
44
|
const language = page.lang || page.language || config.language;
|
|
50
45
|
|
|
@@ -95,8 +90,7 @@ module.exports = class extends Component {
|
|
|
95
90
|
if (
|
|
96
91
|
typeof structured_data === "object" &&
|
|
97
92
|
structured_data !== null &&
|
|
98
|
-
((Array.isArray(structured_data.image) &&
|
|
99
|
-
structured_data.image.length > 0) ||
|
|
93
|
+
((Array.isArray(structured_data.image) && structured_data.image.length > 0) ||
|
|
100
94
|
typeof structured_data.image === "string")
|
|
101
95
|
) {
|
|
102
96
|
structuredImages = structured_data.image;
|
|
@@ -150,9 +144,7 @@ module.exports = class extends Component {
|
|
|
150
144
|
page.content ||
|
|
151
145
|
config.description
|
|
152
146
|
}
|
|
153
|
-
keywords={
|
|
154
|
-
(page.tags?.length ? page.tags : undefined) || config.keywords
|
|
155
|
-
}
|
|
147
|
+
keywords={(page.tags?.length ? page.tags : undefined) || config.keywords}
|
|
156
148
|
url={open_graph.url || page.permalink || url}
|
|
157
149
|
images={openGraphImages}
|
|
158
150
|
siteName={open_graph.site_name || config.title}
|
|
@@ -229,13 +221,7 @@ module.exports = class extends Component {
|
|
|
229
221
|
onload="this.onload=null;this.rel='stylesheet'"
|
|
230
222
|
/>
|
|
231
223
|
<link rel="stylesheet" href="/css/shiki/shiki.css" />
|
|
232
|
-
<Plugins
|
|
233
|
-
site={site}
|
|
234
|
-
config={config}
|
|
235
|
-
helper={helper}
|
|
236
|
-
page={page}
|
|
237
|
-
head={true}
|
|
238
|
-
/>
|
|
224
|
+
<Plugins site={site} config={config} helper={helper} page={page} head={true} />
|
|
239
225
|
{adsenseClientId ? (
|
|
240
226
|
<script
|
|
241
227
|
data-ad-client={adsenseClientId}
|
|
@@ -42,7 +42,6 @@ Insight.Cacheable = cacheComponent(Insight, "search.insight", (props) => {
|
|
|
42
42
|
untitled: helper.__("search.untitled"),
|
|
43
43
|
posts: helper._p("common.post", Infinity),
|
|
44
44
|
pages: helper._p("common.page", Infinity),
|
|
45
|
-
categories: helper._p("common.category", Infinity),
|
|
46
45
|
tags: helper._p("common.tag", Infinity),
|
|
47
46
|
},
|
|
48
47
|
contentUrl: helper.url_for("/content.json"),
|
package/package.json
CHANGED
package/source/css/default.css
CHANGED
|
@@ -411,7 +411,6 @@ html {
|
|
|
411
411
|
box-sizing: border-box;
|
|
412
412
|
height: 100%;
|
|
413
413
|
font-size: 16px;
|
|
414
|
-
scroll-behavior: smooth;
|
|
415
414
|
min-width: 300px;
|
|
416
415
|
overflow-x: hidden;
|
|
417
416
|
overflow-y: scroll;
|
|
@@ -511,7 +510,6 @@ video {
|
|
|
511
510
|
overflow: hidden;
|
|
512
511
|
}
|
|
513
512
|
|
|
514
|
-
.card-image .cover-lqip,
|
|
515
513
|
.card-image .fill {
|
|
516
514
|
position: absolute;
|
|
517
515
|
top: 0;
|
|
@@ -521,15 +519,6 @@ video {
|
|
|
521
519
|
object-fit: cover;
|
|
522
520
|
}
|
|
523
521
|
|
|
524
|
-
.card-image .cover-lqip {
|
|
525
|
-
z-index: 1;
|
|
526
|
-
transition: opacity 0.3s cubic-bezier(0.25, 0.46, 0.45, 0.94);
|
|
527
|
-
}
|
|
528
|
-
|
|
529
|
-
.card-image .fill.loaded + .cover-lqip {
|
|
530
|
-
display: none;
|
|
531
|
-
}
|
|
532
|
-
|
|
533
522
|
.card-content {
|
|
534
523
|
padding: 1.25rem;
|
|
535
524
|
border-radius: 0;
|
|
@@ -606,7 +595,7 @@ video {
|
|
|
606
595
|
.theme-selector-modal {
|
|
607
596
|
position: fixed;
|
|
608
597
|
inset: 0;
|
|
609
|
-
z-index:
|
|
598
|
+
z-index: 100;
|
|
610
599
|
display: flex;
|
|
611
600
|
align-items: center;
|
|
612
601
|
justify-content: center;
|
|
@@ -740,8 +729,10 @@ video {
|
|
|
740
729
|
.pagination-next,
|
|
741
730
|
.pagination-previous {
|
|
742
731
|
height: 2.5em;
|
|
743
|
-
border-radius:
|
|
732
|
+
border-radius: 10px;
|
|
744
733
|
font-size: 1.1em;
|
|
734
|
+
font-weight: bolder;
|
|
735
|
+
color: var(--text);
|
|
745
736
|
margin: 0.25rem;
|
|
746
737
|
padding: 0 0.5em;
|
|
747
738
|
justify-content: center;
|
|
@@ -759,13 +750,6 @@ video {
|
|
|
759
750
|
min-width: 1.5em;
|
|
760
751
|
}
|
|
761
752
|
|
|
762
|
-
.pagination-next,
|
|
763
|
-
.pagination-previous {
|
|
764
|
-
padding-left: 0.75em;
|
|
765
|
-
padding-right: 0.75em;
|
|
766
|
-
white-space: nowrap;
|
|
767
|
-
}
|
|
768
|
-
|
|
769
753
|
.pagination-ellipsis {
|
|
770
754
|
pointer-events: none;
|
|
771
755
|
}
|
|
@@ -925,55 +909,69 @@ video {
|
|
|
925
909
|
overflow: auto;
|
|
926
910
|
word-wrap: break-word;
|
|
927
911
|
font-family: var(--font-article);
|
|
928
|
-
font-size:
|
|
929
|
-
line-height: 1.
|
|
912
|
+
font-size: 1rem;
|
|
913
|
+
line-height: 1.5;
|
|
930
914
|
letter-spacing: -0.003em;
|
|
931
915
|
|
|
916
|
+
::selection {
|
|
917
|
+
color: inherit;
|
|
918
|
+
text-decoration: underline wavy;
|
|
919
|
+
text-decoration-color: var(--mauve);
|
|
920
|
+
}
|
|
921
|
+
|
|
932
922
|
h2 {
|
|
933
923
|
font-size: 2em;
|
|
934
924
|
font-weight: 700;
|
|
935
925
|
line-height: 1.25;
|
|
936
926
|
letter-spacing: -0.02em;
|
|
937
|
-
margin
|
|
938
|
-
}
|
|
939
|
-
|
|
940
|
-
h2:not(:first-child) {
|
|
941
|
-
margin-top: 1.5em;
|
|
927
|
+
margin: 1.2rem 0 1rem;
|
|
942
928
|
}
|
|
943
929
|
|
|
944
930
|
h3 {
|
|
945
|
-
font-size: 1.
|
|
931
|
+
font-size: 1.875em;
|
|
946
932
|
font-weight: 700;
|
|
947
|
-
line-height: 1.
|
|
933
|
+
line-height: 1.25;
|
|
948
934
|
letter-spacing: -0.015em;
|
|
949
|
-
margin
|
|
935
|
+
margin: 1.2rem 0 1rem;
|
|
950
936
|
}
|
|
951
937
|
|
|
952
938
|
h4 {
|
|
953
|
-
font-size: 1.
|
|
939
|
+
font-size: 1.5em;
|
|
954
940
|
font-weight: 600;
|
|
955
|
-
line-height: 1.
|
|
941
|
+
line-height: 1.25;
|
|
956
942
|
letter-spacing: -0.01em;
|
|
957
|
-
margin
|
|
943
|
+
margin: 1.2rem 0 1rem;
|
|
958
944
|
}
|
|
959
945
|
|
|
960
946
|
h5 {
|
|
961
947
|
font-size: 1.25em;
|
|
962
948
|
font-weight: 600;
|
|
963
|
-
line-height: 1.
|
|
949
|
+
line-height: 1.25;
|
|
964
950
|
letter-spacing: -0.005em;
|
|
965
|
-
margin
|
|
951
|
+
margin: 1.2rem 0 1rem;
|
|
966
952
|
}
|
|
967
953
|
|
|
968
954
|
h6 {
|
|
969
|
-
font-size: 1.
|
|
955
|
+
font-size: 1.2em;
|
|
970
956
|
font-weight: 600;
|
|
971
|
-
line-height: 1.
|
|
972
|
-
margin
|
|
957
|
+
line-height: 1.25;
|
|
958
|
+
margin: 1.2rem 0 1rem;
|
|
973
959
|
}
|
|
974
960
|
|
|
975
961
|
.p:not(:last-child) {
|
|
976
|
-
margin-bottom:
|
|
962
|
+
margin-bottom: 1rem;
|
|
963
|
+
}
|
|
964
|
+
|
|
965
|
+
p,
|
|
966
|
+
blockquote,
|
|
967
|
+
ul,
|
|
968
|
+
ol,
|
|
969
|
+
dl,
|
|
970
|
+
table,
|
|
971
|
+
pre,
|
|
972
|
+
details {
|
|
973
|
+
margin-top: 0;
|
|
974
|
+
margin-bottom: 1rem;
|
|
977
975
|
}
|
|
978
976
|
|
|
979
977
|
p:last-child,
|
|
@@ -984,14 +982,13 @@ video {
|
|
|
984
982
|
}
|
|
985
983
|
|
|
986
984
|
li + li {
|
|
987
|
-
margin-top: 0.
|
|
985
|
+
margin-top: 0.25em;
|
|
988
986
|
}
|
|
989
987
|
|
|
990
988
|
img,
|
|
991
989
|
video {
|
|
992
990
|
display: block;
|
|
993
|
-
margin: 0
|
|
994
|
-
margin-bottom: 2rem;
|
|
991
|
+
margin: 0 0 1rem 0;
|
|
995
992
|
border-radius: 2px;
|
|
996
993
|
}
|
|
997
994
|
|
|
@@ -1002,16 +999,16 @@ video {
|
|
|
1002
999
|
|
|
1003
1000
|
ol {
|
|
1004
1001
|
list-style-position: outside;
|
|
1005
|
-
|
|
1006
|
-
margin-top:
|
|
1007
|
-
margin-bottom:
|
|
1002
|
+
padding-left: 2em;
|
|
1003
|
+
margin-top: 0;
|
|
1004
|
+
margin-bottom: 0;
|
|
1008
1005
|
}
|
|
1009
1006
|
|
|
1010
1007
|
ul {
|
|
1011
1008
|
list-style: disc outside;
|
|
1012
|
-
|
|
1013
|
-
margin-top:
|
|
1014
|
-
margin-bottom:
|
|
1009
|
+
padding-left: 2em;
|
|
1010
|
+
margin-top: 0;
|
|
1011
|
+
margin-bottom: 0;
|
|
1015
1012
|
}
|
|
1016
1013
|
|
|
1017
1014
|
ul ul {
|
|
@@ -1029,21 +1026,24 @@ video {
|
|
|
1029
1026
|
|
|
1030
1027
|
math {
|
|
1031
1028
|
overflow: auto;
|
|
1032
|
-
margin-bottom:
|
|
1029
|
+
margin-bottom: 1rem;
|
|
1030
|
+
}
|
|
1031
|
+
|
|
1032
|
+
iframe {
|
|
1033
|
+
overflow: auto;
|
|
1033
1034
|
}
|
|
1034
1035
|
|
|
1035
1036
|
figure {
|
|
1036
|
-
margin
|
|
1037
|
-
margin-right: 2em;
|
|
1037
|
+
margin: 1em 2.5rem;
|
|
1038
1038
|
text-align: center;
|
|
1039
1039
|
}
|
|
1040
1040
|
|
|
1041
1041
|
figure:not(:first-child) {
|
|
1042
|
-
margin-top:
|
|
1042
|
+
margin-top: 1.5rem;
|
|
1043
1043
|
}
|
|
1044
1044
|
|
|
1045
1045
|
figure:not(:last-child) {
|
|
1046
|
-
margin-bottom:
|
|
1046
|
+
margin-bottom: 1rem;
|
|
1047
1047
|
}
|
|
1048
1048
|
|
|
1049
1049
|
figure img {
|
|
@@ -1058,9 +1058,11 @@ video {
|
|
|
1058
1058
|
-webkit-overflow-scrolling: touch;
|
|
1059
1059
|
overflow-x: auto;
|
|
1060
1060
|
font-size: 0.85em;
|
|
1061
|
-
padding:
|
|
1061
|
+
padding: 1rem;
|
|
1062
|
+
margin: 0 0 1rem 0;
|
|
1062
1063
|
white-space: pre;
|
|
1063
1064
|
word-wrap: normal;
|
|
1065
|
+
line-height: 1.45;
|
|
1064
1066
|
}
|
|
1065
1067
|
|
|
1066
1068
|
sub,
|
|
@@ -1112,8 +1114,8 @@ table {
|
|
|
1112
1114
|
border-spacing: 0;
|
|
1113
1115
|
border-radius: 8px;
|
|
1114
1116
|
overflow: hidden;
|
|
1115
|
-
margin:
|
|
1116
|
-
font-size:
|
|
1117
|
+
margin: 1rem 0;
|
|
1118
|
+
font-size: 1rem;
|
|
1117
1119
|
border: 1px solid var(--surface0);
|
|
1118
1120
|
}
|
|
1119
1121
|
|
|
@@ -1146,16 +1148,16 @@ blockquote {
|
|
|
1146
1148
|
position: relative;
|
|
1147
1149
|
padding: 1.5rem 2rem 1.5rem 3rem;
|
|
1148
1150
|
margin: 1.5rem 0;
|
|
1149
|
-
border-left:
|
|
1151
|
+
border-left: 2px solid var(--red);
|
|
1150
1152
|
border-radius: 0 8px 8px 0;
|
|
1151
1153
|
font-family: var(--font-serif);
|
|
1152
1154
|
font-style: italic;
|
|
1153
|
-
font-size:
|
|
1154
|
-
line-height: 1.
|
|
1155
|
+
font-size: 1rem;
|
|
1156
|
+
line-height: 1.5;
|
|
1155
1157
|
}
|
|
1156
1158
|
|
|
1157
1159
|
blockquote:before {
|
|
1158
|
-
content: '
|
|
1160
|
+
content: '”';
|
|
1159
1161
|
position: absolute;
|
|
1160
1162
|
left: 0.5rem;
|
|
1161
1163
|
top: 0.2rem;
|
|
@@ -1218,23 +1220,8 @@ input.task-list-item-checkbox:checked::before {
|
|
|
1218
1220
|
color: var(--base);
|
|
1219
1221
|
}
|
|
1220
1222
|
|
|
1221
|
-
.title {
|
|
1222
|
-
word-break: break-word;
|
|
1223
|
-
margin-bottom: 0.4em;
|
|
1224
|
-
position: relative;
|
|
1225
|
-
display: inline-block;
|
|
1226
|
-
transition: color 0.3s ease-out;
|
|
1227
|
-
font-size: 3em;
|
|
1228
|
-
font-weight: 800;
|
|
1229
|
-
line-height: 1.2;
|
|
1230
|
-
}
|
|
1231
|
-
|
|
1232
|
-
.title .tag {
|
|
1233
|
-
vertical-align: middle;
|
|
1234
|
-
}
|
|
1235
|
-
|
|
1236
1223
|
code {
|
|
1237
|
-
font-size: 0.
|
|
1224
|
+
font-size: 0.85em;
|
|
1238
1225
|
font-weight: 400;
|
|
1239
1226
|
font-family: var(--font-monospace);
|
|
1240
1227
|
padding: 0 0.15em;
|
|
@@ -1253,7 +1240,7 @@ strong {
|
|
|
1253
1240
|
hr {
|
|
1254
1241
|
border: none;
|
|
1255
1242
|
display: block;
|
|
1256
|
-
height:
|
|
1243
|
+
height: 0.25em;
|
|
1257
1244
|
margin: 1.5rem 0;
|
|
1258
1245
|
}
|
|
1259
1246
|
|
|
@@ -1370,14 +1357,14 @@ section {
|
|
|
1370
1357
|
}
|
|
1371
1358
|
|
|
1372
1359
|
.article-meta-info,
|
|
1373
|
-
.article-
|
|
1360
|
+
.article-tags-inline {
|
|
1374
1361
|
display: flex;
|
|
1375
1362
|
align-items: center;
|
|
1376
1363
|
flex-wrap: wrap;
|
|
1377
1364
|
gap: 0.3rem;
|
|
1378
1365
|
}
|
|
1379
1366
|
|
|
1380
|
-
.article-
|
|
1367
|
+
.article-tags-inline {
|
|
1381
1368
|
/* Push to the right */
|
|
1382
1369
|
margin-left: auto;
|
|
1383
1370
|
}
|
package/source/js/insight.js
CHANGED
|
@@ -118,7 +118,7 @@ function loadInsight(config, translation) {
|
|
|
118
118
|
const text = findAndHighlight(item.text, keywords, 100);
|
|
119
119
|
return searchItem(title, text, item.link);
|
|
120
120
|
} else {
|
|
121
|
-
//
|
|
121
|
+
// Tags
|
|
122
122
|
const name = findAndHighlight(item.name, keywords);
|
|
123
123
|
return searchItem(name, null, item.link);
|
|
124
124
|
}
|
|
@@ -197,7 +197,6 @@ function loadInsight(config, translation) {
|
|
|
197
197
|
return {
|
|
198
198
|
posts: executeSearch(json.posts, ["title", "text"], [3, 1]),
|
|
199
199
|
pages: executeSearch(json.pages, ["title", "text"], [3, 1]),
|
|
200
|
-
categories: executeSearch(json.categories, ["name", "slug"], [1, 1]),
|
|
201
200
|
tags: executeSearch(json.tags, ["name", "slug"], [1, 1]),
|
|
202
201
|
};
|
|
203
202
|
}
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
// Generates the <root>/categories page
|
|
2
|
-
module.exports = (hexo) => {
|
|
3
|
-
hexo.extend.generator.register("categories", (locals) => {
|
|
4
|
-
return {
|
|
5
|
-
path: "categories/",
|
|
6
|
-
layout: ["categories"],
|
|
7
|
-
data: Object.assign({}, locals, {
|
|
8
|
-
__categories: true,
|
|
9
|
-
}),
|
|
10
|
-
};
|
|
11
|
-
});
|
|
12
|
-
};
|
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Register the Hexo generator for generating <code>/category/</code> pages.
|
|
3
|
-
* @module hexo/generator/category
|
|
4
|
-
*/
|
|
5
|
-
const pagination = require("hexo-pagination");
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* Register the Hexo generator for generating <code>/category/</code> pages.
|
|
9
|
-
* <p>
|
|
10
|
-
* An array of parent categories will be attached to the page local
|
|
11
|
-
* variables.
|
|
12
|
-
*
|
|
13
|
-
* @param {Hexo} hexo The Hexo instance.
|
|
14
|
-
*/
|
|
15
|
-
module.exports = (hexo) => {
|
|
16
|
-
hexo.extend.generator.register("category", function (locals) {
|
|
17
|
-
const config = this.config;
|
|
18
|
-
const paginationDir = config.pagination_dir || "page";
|
|
19
|
-
const perPage =
|
|
20
|
-
(config.category_generator ? config.category_generator.per_page : null) ||
|
|
21
|
-
0;
|
|
22
|
-
const orderBy =
|
|
23
|
-
(config.category_generator ? config.category_generator.order_by : null) ||
|
|
24
|
-
"-date";
|
|
25
|
-
|
|
26
|
-
function findParent(category) {
|
|
27
|
-
let parents = [];
|
|
28
|
-
if (typeof category === "object" && "parent" in category) {
|
|
29
|
-
const parent = locals.categories
|
|
30
|
-
.filter((cat) => cat._id === category.parent)
|
|
31
|
-
.first();
|
|
32
|
-
parents = findParent(parent).concat([parent]);
|
|
33
|
-
}
|
|
34
|
-
return parents;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
return locals.categories.reduce((result, category) => {
|
|
38
|
-
const posts = category.posts.sort(orderBy);
|
|
39
|
-
const data = pagination(category.path, posts, {
|
|
40
|
-
perPage: perPage,
|
|
41
|
-
layout: ["category", "archive", "index"],
|
|
42
|
-
format: `${paginationDir}/%d/`,
|
|
43
|
-
data: {
|
|
44
|
-
category: category.name,
|
|
45
|
-
parents: findParent(category),
|
|
46
|
-
},
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
return result.concat(data);
|
|
50
|
-
}, []);
|
|
51
|
-
});
|
|
52
|
-
};
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Register the Hexo helper functions for a Hexo page/post.
|
|
3
|
-
* @module hexo/helper/page
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* Register the Hexo helper functions for a Hexo page/post.
|
|
8
|
-
*
|
|
9
|
-
* @param {Hexo} hexo The Hexo instance.
|
|
10
|
-
* @example
|
|
11
|
-
* // Use the function below to test if the given page is the /categories page
|
|
12
|
-
* // Need to be combined with lib/hexo/generator/categories
|
|
13
|
-
* is_categories(page);
|
|
14
|
-
*
|
|
15
|
-
* // Use the function below to test if the given page is the /tags page
|
|
16
|
-
* // Need to be combined with lib/hexo/generator/tags
|
|
17
|
-
* is_tags(page);
|
|
18
|
-
*/
|
|
19
|
-
module.exports = (hexo) => {
|
|
20
|
-
hexo.extend.helper.register("is_categories", function (page = null) {
|
|
21
|
-
return (page === null ? this.page : page).__categories === true;
|
|
22
|
-
});
|
|
23
|
-
|
|
24
|
-
hexo.extend.helper.register("is_tags", function (page = null) {
|
|
25
|
-
return (page === null ? this.page : page).__tags === true;
|
|
26
|
-
});
|
|
27
|
-
};
|
package/layout/categories.jsx
DELETED
|
@@ -1,147 +0,0 @@
|
|
|
1
|
-
const { Component, cacheComponent } = require("../include/util/common");
|
|
2
|
-
|
|
3
|
-
class Categories extends Component {
|
|
4
|
-
renderList(categories, showCount) {
|
|
5
|
-
return categories.map((category) => (
|
|
6
|
-
<li class="category-list-item">
|
|
7
|
-
<a class={`category-link`} href={category.url}>
|
|
8
|
-
<span>{category.name}</span>
|
|
9
|
-
{showCount ? <span class="category-count">{category.count}</span> : null}
|
|
10
|
-
</a>
|
|
11
|
-
{category.children.length ? (
|
|
12
|
-
<ul class="category-sublist">{this.renderList(category.children, false)}</ul>
|
|
13
|
-
) : null}
|
|
14
|
-
</li>
|
|
15
|
-
));
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
render() {
|
|
19
|
-
const { showCount, categories } = this.props;
|
|
20
|
-
const categoriesCSS = `
|
|
21
|
-
.category-list-item {
|
|
22
|
-
list-style: none;
|
|
23
|
-
margin-bottom: 0.4em;
|
|
24
|
-
}
|
|
25
|
-
.category-link {
|
|
26
|
-
display: flex;
|
|
27
|
-
align-items: center;
|
|
28
|
-
justify-content: space-between;
|
|
29
|
-
padding: 0.6em 0.8em;
|
|
30
|
-
border-radius: 8px;
|
|
31
|
-
color: var(--text);
|
|
32
|
-
background-color: transparent;
|
|
33
|
-
text-decoration: none;
|
|
34
|
-
transition: all 0.2s ease;
|
|
35
|
-
font-weight: 400;
|
|
36
|
-
}
|
|
37
|
-
.category-link:hover {
|
|
38
|
-
background-color: var(--base) !important;
|
|
39
|
-
transform: translateX(4px);
|
|
40
|
-
}
|
|
41
|
-
.category-link span:first-child {
|
|
42
|
-
flex: 1;
|
|
43
|
-
}
|
|
44
|
-
.category-count {
|
|
45
|
-
padding: 0.15em 0.6em;
|
|
46
|
-
border-radius: 10px;
|
|
47
|
-
min-width: 1.5em;
|
|
48
|
-
text-align: center;
|
|
49
|
-
}
|
|
50
|
-
.category-sublist {
|
|
51
|
-
margin-left: 0.8em;
|
|
52
|
-
padding-left: 0.8em;
|
|
53
|
-
border-left: 2px solid var(--surface0);
|
|
54
|
-
margin-top: 0.4em;
|
|
55
|
-
list-style: none;
|
|
56
|
-
}
|
|
57
|
-
`;
|
|
58
|
-
|
|
59
|
-
return (
|
|
60
|
-
<div class="card widget" data-type="categories">
|
|
61
|
-
<style>{categoriesCSS}</style>
|
|
62
|
-
<div class="card-content" style="padding: 1.2em;">
|
|
63
|
-
<ul style="list-style: none; padding: 0; margin: 0;">
|
|
64
|
-
{this.renderList(categories, showCount)}
|
|
65
|
-
</ul>
|
|
66
|
-
</div>
|
|
67
|
-
</div>
|
|
68
|
-
);
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
Categories.Cacheable = cacheComponent(Categories, "widget.categories", (props) => {
|
|
73
|
-
const { page, helper, widget = {} } = props;
|
|
74
|
-
const {
|
|
75
|
-
categories = props.site.categories,
|
|
76
|
-
orderBy = "name",
|
|
77
|
-
order = 1,
|
|
78
|
-
showCurrent = false,
|
|
79
|
-
showCount = true,
|
|
80
|
-
} = widget;
|
|
81
|
-
const { url_for, _p } = helper;
|
|
82
|
-
|
|
83
|
-
if (!categories || !categories.length) {
|
|
84
|
-
return null;
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
const depth = parseInt(props.depth, 10);
|
|
88
|
-
|
|
89
|
-
function prepareQuery(parent) {
|
|
90
|
-
const query = {};
|
|
91
|
-
|
|
92
|
-
if (parent) {
|
|
93
|
-
query.parent = parent;
|
|
94
|
-
} else {
|
|
95
|
-
query.parent = { $exists: false };
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
return categories
|
|
99
|
-
.find(query)
|
|
100
|
-
.sort(orderBy, order)
|
|
101
|
-
.filter((cat) => cat.length);
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
function hierarchicalList(level, parent) {
|
|
105
|
-
return prepareQuery(parent).map((cat, _) => {
|
|
106
|
-
let children = [];
|
|
107
|
-
if (!depth || level + 1 < depth) {
|
|
108
|
-
children = hierarchicalList(level + 1, cat._id);
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
let isCurrent = false;
|
|
112
|
-
if (showCurrent && page) {
|
|
113
|
-
for (let j = 0; j < cat.length; j++) {
|
|
114
|
-
const post = cat.posts.data[j];
|
|
115
|
-
if (post && post._id === page._id) {
|
|
116
|
-
isCurrent = true;
|
|
117
|
-
break;
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
// special case: category page
|
|
121
|
-
isCurrent = isCurrent || page.base?.startsWith(cat.path);
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
return {
|
|
125
|
-
children,
|
|
126
|
-
isCurrent,
|
|
127
|
-
name: cat.name,
|
|
128
|
-
count: cat.length,
|
|
129
|
-
url: url_for(cat.path),
|
|
130
|
-
};
|
|
131
|
-
});
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
return {
|
|
135
|
-
showCount,
|
|
136
|
-
categories: hierarchicalList(0),
|
|
137
|
-
title: _p("common.category", Infinity),
|
|
138
|
-
};
|
|
139
|
-
});
|
|
140
|
-
|
|
141
|
-
module.exports = class extends Component {
|
|
142
|
-
render() {
|
|
143
|
-
const { site, page, helper } = this.props;
|
|
144
|
-
|
|
145
|
-
return <Categories.Cacheable site={site} page={page} helper={helper} />;
|
|
146
|
-
}
|
|
147
|
-
};
|
package/layout/category.jsx
DELETED
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
const { Component, Fragment } = require("../include/util/common");
|
|
2
|
-
const Index = require("./index");
|
|
3
|
-
|
|
4
|
-
module.exports = class extends Component {
|
|
5
|
-
render() {
|
|
6
|
-
const { config, page, helper } = this.props;
|
|
7
|
-
const { url_for, _p } = helper;
|
|
8
|
-
|
|
9
|
-
return (
|
|
10
|
-
<Fragment>
|
|
11
|
-
<nav class="breadcrumb" aria-label="breadcrumbs">
|
|
12
|
-
<ul>
|
|
13
|
-
<li>
|
|
14
|
-
{" "}
|
|
15
|
-
<font style="color: var(--green)">$</font> ls
|
|
16
|
-
<a href={url_for("/categories/")}>
|
|
17
|
-
{_p("common.category", Infinity)}
|
|
18
|
-
</a>
|
|
19
|
-
</li>
|
|
20
|
-
{page.parents.map((category) => {
|
|
21
|
-
return (
|
|
22
|
-
<li>
|
|
23
|
-
<a href={url_for(category.path)}>{category.name}</a>
|
|
24
|
-
</li>
|
|
25
|
-
);
|
|
26
|
-
})}
|
|
27
|
-
<li class="is-active">
|
|
28
|
-
<a href="#" aria-current="page">
|
|
29
|
-
{page.category}
|
|
30
|
-
</a>
|
|
31
|
-
</li>
|
|
32
|
-
</ul>
|
|
33
|
-
</nav>
|
|
34
|
-
<Index config={config} page={page} helper={helper} />
|
|
35
|
-
</Fragment>
|
|
36
|
-
);
|
|
37
|
-
}
|
|
38
|
-
};
|