hexo-theme-gnix 12.0.0 → 14.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/archive.js +14 -1
- package/include/hexo/generator/index.js +0 -5
- package/include/hexo/generator/page.js +18 -4
- package/include/hexo/generator/tag.js +1 -1
- package/include/hexo/helper.js +0 -4
- package/include/hexo/i18n.js +31 -136
- package/include/hexo/obsidian-callouts.js +210 -0
- package/include/hexo/renderer.js +4 -14
- package/include/hexo/shiki.js +191 -0
- package/include/hexo/sitemap.js +184 -0
- package/include/util/i18n.js +92 -106
- package/languages/en.yml +4 -10
- package/languages/zh-CN.yml +4 -10
- package/layout/archive.jsx +155 -78
- package/layout/common/article.jsx +94 -108
- package/layout/common/article_cover.jsx +3 -3
- package/layout/common/article_info.jsx +11 -48
- package/layout/common/article_media.jsx +9 -2
- package/layout/common/footer.jsx +17 -106
- package/layout/common/head.jsx +3 -15
- package/layout/common/navbar.jsx +24 -87
- package/layout/common/scripts.jsx +1 -1
- package/layout/layout.jsx +37 -19
- package/layout/plugin/goatcounter.jsx +25 -0
- package/layout/tag.jsx +3 -70
- package/layout/tags.jsx +26 -23
- package/package.json +7 -13
- package/scripts/index.js +1 -0
- package/source/css/archive.css +287 -168
- package/source/css/callout_blocks.css +41 -21
- package/source/css/default.css +154 -132
- package/source/css/optional/mermaid.css +12 -6
- package/source/css/responsive.css +1 -45
- package/source/css/shiki/shiki.css +5 -4
- package/source/css/tags.css +53 -59
- package/source/js/components/archive-popup.js +313 -0
- package/source/js/components/friends-list.js +270 -0
- package/source/js/components/x-info-card.js +297 -0
- package/source/js/main.js +38 -34
- package/source/js/mdit/mermaid.js +10 -0
- package/include/hexo/generator/home.js +0 -64
- package/layout/index.jsx +0 -19
- package/layout/misc/paginator.jsx +0 -69
- package/source/js/host/iconify-icon/3.0.2/iconify-icon.min.js +0 -12
package/languages/en.yml
CHANGED
|
@@ -40,16 +40,10 @@ article:
|
|
|
40
40
|
article_title: "Title"
|
|
41
41
|
url: "URL"
|
|
42
42
|
markdown_source: "Markdown source"
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
yes: "Yes"
|
|
48
|
-
no: "No"
|
|
49
|
-
translation_methods:
|
|
50
|
-
llm: "LLM translation"
|
|
51
|
-
machine: "Machine translation"
|
|
52
|
-
human: "Human translation"
|
|
43
|
+
translation_info: "Translation"
|
|
44
|
+
translation_original: "Original"
|
|
45
|
+
translation_llm_reviewed: "LLM · reviewed"
|
|
46
|
+
translation_llm_unreviewed: "LLM · unreviewed"
|
|
53
47
|
licensing:
|
|
54
48
|
author: "Author"
|
|
55
49
|
created_at: "Posted on"
|
package/languages/zh-CN.yml
CHANGED
|
@@ -40,16 +40,10 @@ article:
|
|
|
40
40
|
article_title: "标题"
|
|
41
41
|
url: "链接"
|
|
42
42
|
markdown_source: "Markdown 源码"
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
yes: "是"
|
|
48
|
-
no: "否"
|
|
49
|
-
translation_methods:
|
|
50
|
-
llm: "LLM 翻译"
|
|
51
|
-
machine: "机器翻译"
|
|
52
|
-
human: "人工翻译"
|
|
43
|
+
translation_info: "关于翻译"
|
|
44
|
+
translation_original: "原文"
|
|
45
|
+
translation_llm_reviewed: "LLM 翻译 · 已人工审阅"
|
|
46
|
+
translation_llm_unreviewed: "LLM 翻译 · 未人工审阅"
|
|
53
47
|
licensing:
|
|
54
48
|
author: "Author"
|
|
55
49
|
created_at: "Posted"
|
package/layout/archive.jsx
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
const { Component, Fragment, isValidDate, parseISO, dateFormatters } = require("../include/util/common");
|
|
2
|
-
const { filterByLanguage } = require("../include/util/i18n");
|
|
3
2
|
const ArticleMedia = require("./common/article_media");
|
|
4
3
|
|
|
5
4
|
function collectPosts(collection) {
|
|
@@ -12,6 +11,14 @@ function collectPosts(collection) {
|
|
|
12
11
|
return posts;
|
|
13
12
|
}
|
|
14
13
|
|
|
14
|
+
function estimateReadMinutes(content) {
|
|
15
|
+
if (typeof content !== "string" || !content) return 0;
|
|
16
|
+
const stripped = content.replace(/<\/?[a-z][^>]*>/gi, "").trim();
|
|
17
|
+
if (!stripped) return 0;
|
|
18
|
+
const tokens = stripped.match(/[ÿ-]|[a-zA-Z]+/g);
|
|
19
|
+
return tokens ? Math.max(1, Math.ceil(tokens.length / 200)) : 0;
|
|
20
|
+
}
|
|
21
|
+
|
|
15
22
|
function getSeason(month) {
|
|
16
23
|
if (month >= 2 && month <= 4) return "Spring";
|
|
17
24
|
if (month >= 5 && month <= 7) return "Summer";
|
|
@@ -44,6 +51,47 @@ function groupPostsBySeason(posts) {
|
|
|
44
51
|
}, []);
|
|
45
52
|
}
|
|
46
53
|
|
|
54
|
+
function groupSeasonGroupsByYear(seasonGroups) {
|
|
55
|
+
const years = [];
|
|
56
|
+
for (const group of seasonGroups) {
|
|
57
|
+
const last = years[years.length - 1];
|
|
58
|
+
if (last && last.year === group.year) {
|
|
59
|
+
last.groups.push(group);
|
|
60
|
+
last.total += group.posts.length;
|
|
61
|
+
} else {
|
|
62
|
+
years.push({ year: group.year, total: group.posts.length, groups: [group] });
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
return years;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function toRoman(num) {
|
|
69
|
+
const map = [
|
|
70
|
+
[1000, "M"],
|
|
71
|
+
[900, "CM"],
|
|
72
|
+
[500, "D"],
|
|
73
|
+
[400, "CD"],
|
|
74
|
+
[100, "C"],
|
|
75
|
+
[90, "XC"],
|
|
76
|
+
[50, "L"],
|
|
77
|
+
[40, "XL"],
|
|
78
|
+
[10, "X"],
|
|
79
|
+
[9, "IX"],
|
|
80
|
+
[5, "V"],
|
|
81
|
+
[4, "IV"],
|
|
82
|
+
[1, "I"],
|
|
83
|
+
];
|
|
84
|
+
let n = num;
|
|
85
|
+
let out = "";
|
|
86
|
+
for (const [value, sym] of map) {
|
|
87
|
+
while (n >= value) {
|
|
88
|
+
out += sym;
|
|
89
|
+
n -= value;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
return out;
|
|
93
|
+
}
|
|
94
|
+
|
|
47
95
|
function collectArchiveYears(posts) {
|
|
48
96
|
return Array.from(new Set(posts.map((post) => post.date.year()))).sort((a, b) => b - a);
|
|
49
97
|
}
|
|
@@ -58,104 +106,133 @@ function getPostDateParts(postDate, dateXml, date) {
|
|
|
58
106
|
};
|
|
59
107
|
}
|
|
60
108
|
|
|
109
|
+
function renderSeasonGroup({ posts, year, season, month, sectionTitle, url_for, date_xml, date }) {
|
|
110
|
+
const title = sectionTitle || getArchiveRangeLabel(year, month, season);
|
|
111
|
+
const kicker = year ? String(year) : "Archive";
|
|
112
|
+
const marker = season ? season.toLowerCase() : "all";
|
|
113
|
+
const sectionId = `archive-${kicker}-${marker}-${month || "all"}`;
|
|
114
|
+
|
|
115
|
+
return (
|
|
116
|
+
<section class={["archive-group", marker].filter(Boolean).join(" ")} aria-labelledby={sectionId}>
|
|
117
|
+
<header class="archive-group__header">
|
|
118
|
+
<h2 id={sectionId} class="archive-group__title">
|
|
119
|
+
{title}
|
|
120
|
+
</h2>
|
|
121
|
+
<span class="archive-group__count">{String(posts.length).padStart(2, "0")}</span>
|
|
122
|
+
</header>
|
|
123
|
+
<div class="timeline">
|
|
124
|
+
{posts.map((post) => {
|
|
125
|
+
const postDate = getPostDateParts(post.date, date_xml, date);
|
|
126
|
+
const readMinutes = estimateReadMinutes(post._content);
|
|
127
|
+
return (
|
|
128
|
+
<ArticleMedia
|
|
129
|
+
key={post.path}
|
|
130
|
+
url={url_for(post.link || post.path)}
|
|
131
|
+
title={post.title}
|
|
132
|
+
date={postDate.label}
|
|
133
|
+
dateXml={postDate.xml}
|
|
134
|
+
excerpt={post.excerpt || null}
|
|
135
|
+
readTime={readMinutes ? `${readMinutes} min` : null}
|
|
136
|
+
/>
|
|
137
|
+
);
|
|
138
|
+
})}
|
|
139
|
+
</div>
|
|
140
|
+
</section>
|
|
141
|
+
);
|
|
142
|
+
}
|
|
143
|
+
|
|
61
144
|
module.exports = class extends Component {
|
|
62
145
|
render() {
|
|
63
|
-
const { page, helper
|
|
146
|
+
const { page, helper } = this.props;
|
|
64
147
|
const { url_for, date_xml, date } = helper;
|
|
65
|
-
const langKey = helper.language_key(page);
|
|
66
|
-
|
|
67
|
-
function renderArticleList(posts, year, month = null, sectionTitle = null, season = null) {
|
|
68
|
-
const title = sectionTitle || getArchiveRangeLabel(year, month, season);
|
|
69
|
-
const kicker = year ? String(year) : "Archive";
|
|
70
|
-
const marker = season ? season.toLowerCase() : "all";
|
|
71
|
-
const countLabel = posts.length === 1 ? "1 entry" : `${posts.length} entries`;
|
|
72
|
-
const sectionId = `archive-${kicker}-${marker}-${month || "all"}`;
|
|
73
|
-
|
|
74
|
-
return (
|
|
75
|
-
<section class={["archive-group", marker].filter(Boolean).join(" ")} aria-labelledby={sectionId}>
|
|
76
|
-
<header class="archive-group__header">
|
|
77
|
-
<div>
|
|
78
|
-
<h2 id={sectionId} class="archive-group__title">
|
|
79
|
-
{title}
|
|
80
|
-
</h2>
|
|
81
|
-
</div>
|
|
82
|
-
<span class="archive-group__count">{countLabel}</span>
|
|
83
|
-
</header>
|
|
84
|
-
<div class="timeline">
|
|
85
|
-
{posts.map((post) => {
|
|
86
|
-
const postDate = getPostDateParts(post.date, date_xml, date);
|
|
87
|
-
return <ArticleMedia key={post.path} url={url_for(post.link || post.path)} title={post.title} date={postDate.label} dateXml={postDate.xml} />;
|
|
88
|
-
})}
|
|
89
|
-
</div>
|
|
90
|
-
</section>
|
|
91
|
-
);
|
|
92
|
-
}
|
|
93
148
|
|
|
94
149
|
const visiblePosts = collectPosts(page.posts);
|
|
95
150
|
const totalVisiblePosts = visiblePosts.length;
|
|
96
|
-
const latestPost = visiblePosts[0];
|
|
97
151
|
|
|
98
|
-
const
|
|
99
|
-
|
|
100
|
-
const
|
|
152
|
+
const years = collectArchiveYears(visiblePosts);
|
|
153
|
+
|
|
154
|
+
const currentYear = page.year ? Number(page.year) : null;
|
|
155
|
+
const currentMonth = page.month ? Number(page.month) : null;
|
|
156
|
+
const isTagPage = Boolean(page.tag);
|
|
157
|
+
const entriesLabel = `${totalVisiblePosts} ${totalVisiblePosts === 1 ? "entry" : "entries"}`;
|
|
158
|
+
|
|
101
159
|
let articleList;
|
|
102
160
|
if (!page.year) {
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
161
|
+
const seasonGroups = groupPostsBySeason(visiblePosts);
|
|
162
|
+
const yearBlocks = groupSeasonGroupsByYear(seasonGroups);
|
|
163
|
+
articleList = yearBlocks.map((block) => (
|
|
164
|
+
<Fragment key={block.year}>
|
|
165
|
+
<div class="archive-era" id={`archive-year-${block.year}`}>
|
|
166
|
+
<span class="archive-era__roman">{toRoman(block.year)}</span>
|
|
167
|
+
<span class="archive-era__year" aria-hidden="true">
|
|
168
|
+
{" "}
|
|
169
|
+
{block.year}{" "}
|
|
170
|
+
</span>
|
|
171
|
+
</div>
|
|
172
|
+
{block.groups.map((group) => (
|
|
173
|
+
<Fragment key={`${group.year}-${group.season}`}>
|
|
174
|
+
{renderSeasonGroup({
|
|
175
|
+
posts: group.posts,
|
|
176
|
+
year: group.year,
|
|
177
|
+
season: group.season,
|
|
178
|
+
sectionTitle: group.season,
|
|
179
|
+
url_for,
|
|
180
|
+
date_xml,
|
|
181
|
+
date,
|
|
182
|
+
})}
|
|
183
|
+
</Fragment>
|
|
184
|
+
))}
|
|
185
|
+
</Fragment>
|
|
186
|
+
));
|
|
107
187
|
} else {
|
|
108
188
|
const season = page.month ? getSeason(page.month - 1) : null;
|
|
109
|
-
articleList =
|
|
189
|
+
articleList = renderSeasonGroup({
|
|
190
|
+
posts: visiblePosts,
|
|
191
|
+
year: page.year,
|
|
192
|
+
season,
|
|
193
|
+
month: page.month,
|
|
194
|
+
url_for,
|
|
195
|
+
date_xml,
|
|
196
|
+
date,
|
|
197
|
+
});
|
|
110
198
|
}
|
|
111
199
|
|
|
112
|
-
const
|
|
113
|
-
const
|
|
114
|
-
const currentYear = page.year ? Number(page.year) : null;
|
|
115
|
-
const currentMonth = page.month ? Number(page.month) : null;
|
|
116
|
-
const activeScope = getArchiveRangeLabel(currentYear, currentMonth);
|
|
117
|
-
const yearCountLabel = years.length === 1 ? "1 year" : `${years.length} years`;
|
|
118
|
-
const scopeSummaryLabel = currentYear ? `from ${activeScope}` : `across ${yearCountLabel}`;
|
|
119
|
-
const latestLabel = latestPost ? date(latestPost.date) : "No posts yet";
|
|
200
|
+
const heroTitle = isTagPage ? page.tag : currentYear ? getArchiveRangeLabel(currentYear, currentMonth) : "Index";
|
|
201
|
+
const heroKind = isTagPage ? "Tag" : currentYear ? "Archive" : "Volume";
|
|
120
202
|
|
|
121
203
|
return (
|
|
122
204
|
<Fragment>
|
|
123
205
|
<link rel="stylesheet" href={url_for("/css/archive.css")} data-page-head />
|
|
124
206
|
<main class="archive-page">
|
|
125
207
|
<header class="archive-hero">
|
|
126
|
-
<
|
|
127
|
-
<
|
|
128
|
-
<
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
</
|
|
132
|
-
</
|
|
133
|
-
<
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
</
|
|
138
|
-
|
|
139
|
-
<dt>Years</dt>
|
|
140
|
-
<dd>{years.length}</dd>
|
|
141
|
-
</div>
|
|
142
|
-
<div>
|
|
143
|
-
<dt>Latest</dt>
|
|
144
|
-
<dd>{latestLabel}</dd>
|
|
145
|
-
</div>
|
|
146
|
-
</dl>
|
|
208
|
+
<p class="archive-hero__eyebrow">
|
|
209
|
+
<span>{heroKind}</span>
|
|
210
|
+
<span class="archive-hero__sep" aria-hidden="true">
|
|
211
|
+
·
|
|
212
|
+
</span>
|
|
213
|
+
<span class="archive-hero__count">{entriesLabel}</span>
|
|
214
|
+
</p>
|
|
215
|
+
<h1 class="archive-hero__title">{heroTitle}</h1>
|
|
216
|
+
{years.length > 0 && (
|
|
217
|
+
<span class="archive-hero__roman" aria-hidden="true">
|
|
218
|
+
{years.length === 1 ? toRoman(years[0]) : `${toRoman(years[years.length - 1])}–${toRoman(years[0])}`}
|
|
219
|
+
</span>
|
|
220
|
+
)}
|
|
147
221
|
</header>
|
|
148
222
|
|
|
149
|
-
|
|
150
|
-
<
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
223
|
+
{!page.year && years.length > 1 && (
|
|
224
|
+
<aside class="archive-rail" aria-label="Jump to year">
|
|
225
|
+
<ol class="archive-rail__list">
|
|
226
|
+
{years.map((year) => (
|
|
227
|
+
<li key={year} class="archive-rail__item">
|
|
228
|
+
<a href={`#archive-year-${year}`} class="archive-rail__link">
|
|
229
|
+
<span class="archive-rail__year">{year}</span>
|
|
230
|
+
</a>
|
|
231
|
+
</li>
|
|
232
|
+
))}
|
|
233
|
+
</ol>
|
|
234
|
+
</aside>
|
|
235
|
+
)}
|
|
159
236
|
|
|
160
237
|
<div class="archive-stack">{articleList}</div>
|
|
161
238
|
</main>
|
|
@@ -17,15 +17,14 @@ function getWordCount(content) {
|
|
|
17
17
|
|
|
18
18
|
module.exports = class extends Component {
|
|
19
19
|
render() {
|
|
20
|
-
|
|
21
|
-
const { config, helper, page, index } = this.props;
|
|
20
|
+
const { config, helper, page } = this.props;
|
|
22
21
|
|
|
23
22
|
const { url_for } = helper;
|
|
24
23
|
|
|
25
24
|
const cover = page.cover ? url_for(page.cover) : null;
|
|
26
25
|
const wordCount = getWordCount(page._content);
|
|
27
26
|
const readTime = Math.ceil(wordCount / 200); // 假设每分钟阅读200字
|
|
28
|
-
const hasComment =
|
|
27
|
+
const hasComment = config.comment && typeof config.comment.type === "string";
|
|
29
28
|
const translatedCommentsLabel = helper.__("article.comments");
|
|
30
29
|
const commentsLabel = translatedCommentsLabel === "article.comments" ? "Comments" : translatedCommentsLabel;
|
|
31
30
|
|
|
@@ -34,7 +33,7 @@ module.exports = class extends Component {
|
|
|
34
33
|
{/* Main content */}
|
|
35
34
|
<div class="card">
|
|
36
35
|
{/* Cover image */}
|
|
37
|
-
{cover ? <ArticleCover page={page} cover={cover}
|
|
36
|
+
{cover ? <ArticleCover page={page} cover={cover} helper={helper} /> : null}
|
|
38
37
|
<article class={`card-content article${"direction" in page ? ` ${page.direction}` : ""}`}>
|
|
39
38
|
{/* Metadata - Medium style */}
|
|
40
39
|
{page.layout !== "page" ? (
|
|
@@ -45,122 +44,110 @@ module.exports = class extends Component {
|
|
|
45
44
|
{dateFormatters.shortDay.format(page.date)}
|
|
46
45
|
</time>
|
|
47
46
|
)}
|
|
48
|
-
{page.date &&
|
|
47
|
+
{page.date && <span class="meta-separator">·</span>}
|
|
49
48
|
{wordCount > 0 && <span class="article-reading-time">{readTime} min</span>}
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
}}
|
|
59
|
-
></span>
|
|
60
|
-
</Fragment>
|
|
61
|
-
)}
|
|
49
|
+
<span class="meta-separator">·</span>
|
|
50
|
+
<span
|
|
51
|
+
class="article-visit-count"
|
|
52
|
+
data-flag-title={page.title}
|
|
53
|
+
dangerouslySetInnerHTML={{
|
|
54
|
+
__html: '<span id="busuanzi_page_pv"></span> PV',
|
|
55
|
+
}}
|
|
56
|
+
></span>
|
|
62
57
|
</div>
|
|
63
58
|
</div>
|
|
64
59
|
) : null}
|
|
65
60
|
|
|
66
61
|
{/* Title */}
|
|
67
|
-
{page.title !== ""
|
|
68
|
-
<h2 class="article-title">
|
|
69
|
-
<a href={url_for(page.link || page.path)}>{page.title}</a>
|
|
70
|
-
</h2>
|
|
71
|
-
) : null}
|
|
72
|
-
{page.title !== "" && !index ? <h1 class="article-title">{page.title}</h1> : null}
|
|
73
|
-
|
|
74
|
-
{!index && page.excerpt && <div class="article-excerpt" dangerouslySetInnerHTML={{ __html: page.excerpt }}></div>}
|
|
62
|
+
{page.title !== "" ? <h1 class="article-title">{page.title}</h1> : null}
|
|
75
63
|
|
|
76
|
-
{
|
|
77
|
-
<div
|
|
78
|
-
class={index && page.excerpt ? "article-excerpt" : "content"}
|
|
79
|
-
dangerouslySetInnerHTML={{
|
|
80
|
-
__html: index && page.excerpt ? page.excerpt : page.content,
|
|
81
|
-
}}
|
|
82
|
-
></div>
|
|
83
|
-
)}
|
|
64
|
+
{page.excerpt && <div class="article-excerpt" dangerouslySetInnerHTML={{ __html: page.excerpt }}></div>}
|
|
84
65
|
|
|
85
|
-
|
|
86
|
-
<div class="article-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
<
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
{
|
|
101
|
-
<
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
<
|
|
117
|
-
<
|
|
118
|
-
|
|
119
|
-
<path
|
|
120
|
-
fill="currentColor"
|
|
121
|
-
d="M21 12a1 1 0 0 1 1 1v6a1 1 0 0 1-1.911.412a4 4 0 1 1 0-6.824A1 1 0 0 1 21 12M8 4c.732 0 1.381.473 1.605 1.17l4.347 13.524a1 1 0 0 1-1.904.612L10.664 15H5.336l-1.384 4.306a1 1 0 0 1-1.904-.612L6.395 5.17A1.69 1.69 0 0 1 8 4m10 10a2 2 0 1 0 0 4a2 2 0 0 0 0-4M8 6.712L5.979 13h4.042z"
|
|
122
|
-
/>
|
|
123
|
-
</g>
|
|
124
|
-
</svg>
|
|
125
|
-
</button>
|
|
126
|
-
<button type="button" class="article-action-btn" popovertarget="article-info-popover" aria-label={helper.__("article.article_info")} title={helper.__("article.article_info")}>
|
|
127
|
-
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" role="img" aria-label={helper.__("article.article_info")}>
|
|
128
|
-
<title>{helper.__("article.article_info")}</title>
|
|
129
|
-
<g fill="none">
|
|
130
|
-
<path d="m12.593 23.258l-.011.002l-.071.035l-.02.004l-.014-.004l-.071-.035q-.016-.005-.024.005l-.004.01l-.017.428l.005.02l.01.013l.104.074l.015.004l.012-.004l.104-.074l.012-.016l.004-.017l-.017-.427q-.004-.016-.017-.018m.265-.113l-.013.002l-.185.093l-.01.01l-.003.011l.018.43l.005.012l.008.007l.201.093q.019.005.029-.008l.004-.014l-.034-.614q-.005-.018-.02-.022m-.715.002a.02.02 0 0 0-.027.006l-.006.014l-.034.614q.001.018.017.024l.015-.002l.201-.093l.01-.008l.004-.011l.017-.43l-.003-.012l-.01-.01z" />
|
|
131
|
-
<path
|
|
132
|
-
fill="currentColor"
|
|
133
|
-
d="M12 2c5.523 0 10 4.477 10 10s-4.477 10-10 10S2 17.523 2 12S6.477 2 12 2m0 2a8 8 0 1 0 0 16a8 8 0 0 0 0-16m-.01 6c.558 0 1.01.452 1.01 1.01v5.124A1 1 0 0 1 12.5 18h-.49A1.01 1.01 0 0 1 11 16.99V12a1 1 0 1 1 0-2zM12 7a1 1 0 1 1 0 2a1 1 0 0 1 0-2"
|
|
134
|
-
/>
|
|
135
|
-
</g>
|
|
66
|
+
<div class="article-meta-bar">
|
|
67
|
+
<div class="article-tags">
|
|
68
|
+
{page.tags?.length
|
|
69
|
+
? page.tags.map((tag, i) => (
|
|
70
|
+
<Fragment>
|
|
71
|
+
{i > 0 && <span class="meta-separator">·</span>}
|
|
72
|
+
<a class="article-tag" rel="tag" href={helper.localized_tag_url(tag, helper.language_key(page))}>
|
|
73
|
+
{tag.name}
|
|
74
|
+
</a>
|
|
75
|
+
</Fragment>
|
|
76
|
+
))
|
|
77
|
+
: null}
|
|
78
|
+
</div>
|
|
79
|
+
<div class="article-title-actions">
|
|
80
|
+
{hasComment && (
|
|
81
|
+
<button type="button" class="article-action-btn" popovertarget="article-comment-popover" aria-label={commentsLabel} title={commentsLabel}>
|
|
82
|
+
<svg
|
|
83
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
84
|
+
width="24"
|
|
85
|
+
height="24"
|
|
86
|
+
viewBox="0 0 24 24"
|
|
87
|
+
fill="none"
|
|
88
|
+
stroke="currentColor"
|
|
89
|
+
stroke-width="2"
|
|
90
|
+
stroke-linecap="round"
|
|
91
|
+
stroke-linejoin="round"
|
|
92
|
+
role="img"
|
|
93
|
+
aria-label={commentsLabel}
|
|
94
|
+
>
|
|
95
|
+
<title>{commentsLabel}</title>
|
|
96
|
+
<path d="M2.992 16.342a2 2 0 0 1 .094 1.167l-1.065 3.29a1 1 0 0 0 1.236 1.168l3.413-.998a2 2 0 0 1 1.099.092 10 10 0 1 0-4.777-4.719" />
|
|
97
|
+
<path d="M8 12h.01" />
|
|
98
|
+
<path d="M12 12h.01" />
|
|
99
|
+
<path d="M16 12h.01" />
|
|
136
100
|
</svg>
|
|
137
101
|
</button>
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
102
|
+
)}
|
|
103
|
+
<button type="button" class="article-action-btn" popovertarget="article-font-settings" aria-label={helper.__("article.font_settings")} title={helper.__("article.font_settings")}>
|
|
104
|
+
<svg
|
|
105
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
106
|
+
width="24"
|
|
107
|
+
height="24"
|
|
108
|
+
viewBox="0 0 24 24"
|
|
109
|
+
fill="none"
|
|
110
|
+
stroke="currentColor"
|
|
111
|
+
stroke-width="2"
|
|
112
|
+
stroke-linecap="round"
|
|
113
|
+
stroke-linejoin="round"
|
|
114
|
+
role="img"
|
|
115
|
+
aria-label={helper.__("article.font_settings")}
|
|
116
|
+
>
|
|
117
|
+
<title>{helper.__("article.font_settings")}</title>
|
|
118
|
+
<path d="M12 4v16" />
|
|
119
|
+
<path d="M4 7V5a1 1 0 0 1 1-1h14a1 1 0 0 1 1 1v2" />
|
|
120
|
+
<path d="M9 20h6" />
|
|
121
|
+
</svg>
|
|
122
|
+
</button>
|
|
123
|
+
<button type="button" class="article-action-btn" popovertarget="article-info-popover" aria-label={helper.__("article.article_info")} title={helper.__("article.article_info")}>
|
|
124
|
+
<svg
|
|
125
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
126
|
+
width="24"
|
|
127
|
+
height="24"
|
|
128
|
+
viewBox="0 0 24 24"
|
|
129
|
+
fill="none"
|
|
130
|
+
stroke="currentColor"
|
|
131
|
+
stroke-width="2"
|
|
132
|
+
stroke-linecap="round"
|
|
133
|
+
stroke-linejoin="round"
|
|
134
|
+
role="img"
|
|
135
|
+
aria-label={helper.__("article.article_info")}
|
|
136
|
+
>
|
|
137
|
+
<title>{helper.__("article.article_info")}</title>
|
|
138
|
+
<circle cx="12" cy="12" r="10" />
|
|
139
|
+
<path d="M12 16v-4" />
|
|
140
|
+
<path d="M12 8h.01" />
|
|
141
|
+
</svg>
|
|
142
|
+
</button>
|
|
156
143
|
</div>
|
|
157
|
-
|
|
144
|
+
</div>
|
|
145
|
+
|
|
146
|
+
<div class="content" dangerouslySetInnerHTML={{ __html: page.content }}></div>
|
|
158
147
|
|
|
159
|
-
{!index && page.excerpt && <div class="content" dangerouslySetInnerHTML={{ __html: page.content }}></div>}
|
|
160
148
|
</article>
|
|
161
149
|
|
|
162
|
-
|
|
163
|
-
<div id="article-font-settings" popover="auto" class="article-popover article-font-popover">
|
|
150
|
+
<div id="article-font-settings" popover="auto" class="article-popover article-font-popover">
|
|
164
151
|
<div class="article-popover-header">
|
|
165
152
|
<h3>Display Settings</h3>
|
|
166
153
|
<button type="button" class="article-popover-close" popovertarget="article-font-settings" popovertargetaction="hide" aria-label="Close">
|
|
@@ -341,7 +328,6 @@ module.exports = class extends Component {
|
|
|
341
328
|
</aside>
|
|
342
329
|
</div>
|
|
343
330
|
</div>
|
|
344
|
-
)}
|
|
345
331
|
|
|
346
332
|
{hasComment && (
|
|
347
333
|
<div id="article-comment-popover" popover="auto" class="article-popover article-comment-popover">
|
|
@@ -373,7 +359,7 @@ module.exports = class extends Component {
|
|
|
373
359
|
</div>
|
|
374
360
|
)}
|
|
375
361
|
|
|
376
|
-
|
|
362
|
+
<ArticleInfo page={page} config={config} helper={helper} />
|
|
377
363
|
</div>
|
|
378
364
|
</Fragment>
|
|
379
365
|
);
|
|
@@ -2,7 +2,7 @@ const { Component } = require("inferno");
|
|
|
2
2
|
|
|
3
3
|
module.exports = class extends Component {
|
|
4
4
|
render() {
|
|
5
|
-
const { page, cover, helper
|
|
5
|
+
const { page, cover, helper } = this.props;
|
|
6
6
|
const { url_for } = helper;
|
|
7
7
|
|
|
8
8
|
const imageSrcset = `${cover}?w=800 800w, ${cover}?w=1500 1500w, ${cover}?w=2000 2000w, ${cover} 6144w`;
|
|
@@ -19,8 +19,8 @@ module.exports = class extends Component {
|
|
|
19
19
|
sizes="(max-width: 768px) 100vw, (max-width: 1024px) 100vw, 960px"
|
|
20
20
|
referrerpolicy="no-referrer"
|
|
21
21
|
decoding="async"
|
|
22
|
-
loading=
|
|
23
|
-
fetchpriority=
|
|
22
|
+
loading="eager"
|
|
23
|
+
fetchpriority="high"
|
|
24
24
|
/>
|
|
25
25
|
</a>
|
|
26
26
|
);
|