hexo-theme-gnix 12.0.0 → 13.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/i18n.js +11 -1
- 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/languages/en.yml +4 -10
- package/languages/zh-CN.yml +4 -10
- package/layout/common/article.jsx +49 -24
- package/layout/common/article_info.jsx +11 -48
- package/layout/common/footer.jsx +14 -106
- package/layout/common/head.jsx +3 -15
- package/layout/common/navbar.jsx +14 -80
- package/layout/layout.jsx +33 -16
- package/layout/plugin/goatcounter.jsx +25 -0
- package/package.json +7 -13
- package/scripts/index.js +1 -0
- package/source/css/archive.css +3 -5
- package/source/css/callout_blocks.css +41 -21
- package/source/css/default.css +58 -58
- package/source/css/optional/mermaid.css +12 -6
- package/source/css/shiki/shiki.css +5 -4
- package/source/js/components/friends-list.js +271 -0
- package/source/js/components/x-info-card.js +297 -0
- package/source/js/main.js +24 -21
- package/source/js/mdit/mermaid.js +10 -0
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"
|
|
@@ -99,40 +99,65 @@ module.exports = class extends Component {
|
|
|
99
99
|
<div class="article-title-actions">
|
|
100
100
|
{hasComment && (
|
|
101
101
|
<button type="button" class="article-action-btn" popovertarget="article-comment-popover" aria-label={commentsLabel} title={commentsLabel}>
|
|
102
|
-
<svg
|
|
102
|
+
<svg
|
|
103
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
104
|
+
width="24"
|
|
105
|
+
height="24"
|
|
106
|
+
viewBox="0 0 24 24"
|
|
107
|
+
fill="none"
|
|
108
|
+
stroke="currentColor"
|
|
109
|
+
stroke-width="2"
|
|
110
|
+
stroke-linecap="round"
|
|
111
|
+
stroke-linejoin="round"
|
|
112
|
+
role="img"
|
|
113
|
+
aria-label={commentsLabel}
|
|
114
|
+
>
|
|
103
115
|
<title>{commentsLabel}</title>
|
|
104
|
-
<
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
d="M16 4a3 3 0 0 1 2.995 2.824L19 7v2a3 3 0 0 1 2.995 2.824L22 12v4a3 3 0 0 1-2.824 2.995L19 19v.966c0 1.02-1.143 1.594-1.954 1.033l-.096-.072L14.638 19H11a3 3 0 0 1-1.998-.762l-.14-.134L7 19.5c-.791.593-1.906.075-1.994-.879L5 18.5V17a3 3 0 0 1-2.995-2.824L2 14V7a3 3 0 0 1 2.824-2.995L5 4zm3 7h-8a1 1 0 0 0-1 1v4a1 1 0 0 0 1 1h3.638a2 2 0 0 1 1.28.464l1.088.906A1.5 1.5 0 0 1 18.5 17h.5a1 1 0 0 0 1-1v-4a1 1 0 0 0-1-1m-3-5H5a1 1 0 0 0-1 1v7a1 1 0 0 0 1 1h.5A1.5 1.5 0 0 1 7 16.5v.5l1.01-.757A3 3 0 0 1 8 16v-4a3 3 0 0 1 3-3h6V7a1 1 0 0 0-1-1"
|
|
109
|
-
/>
|
|
110
|
-
</g>
|
|
116
|
+
<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" />
|
|
117
|
+
<path d="M8 12h.01" />
|
|
118
|
+
<path d="M12 12h.01" />
|
|
119
|
+
<path d="M16 12h.01" />
|
|
111
120
|
</svg>
|
|
112
121
|
</button>
|
|
113
122
|
)}
|
|
114
123
|
<button type="button" class="article-action-btn" popovertarget="article-font-settings" aria-label={helper.__("article.font_settings")} title={helper.__("article.font_settings")}>
|
|
115
|
-
<svg
|
|
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.font_settings")}
|
|
136
|
+
>
|
|
116
137
|
<title>{helper.__("article.font_settings")}</title>
|
|
117
|
-
<
|
|
118
|
-
|
|
119
|
-
|
|
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>
|
|
138
|
+
<path d="M12 4v16" />
|
|
139
|
+
<path d="M4 7V5a1 1 0 0 1 1-1h14a1 1 0 0 1 1 1v2" />
|
|
140
|
+
<path d="M9 20h6" />
|
|
124
141
|
</svg>
|
|
125
142
|
</button>
|
|
126
143
|
<button type="button" class="article-action-btn" popovertarget="article-info-popover" aria-label={helper.__("article.article_info")} title={helper.__("article.article_info")}>
|
|
127
|
-
<svg
|
|
144
|
+
<svg
|
|
145
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
146
|
+
width="24"
|
|
147
|
+
height="24"
|
|
148
|
+
viewBox="0 0 24 24"
|
|
149
|
+
fill="none"
|
|
150
|
+
stroke="currentColor"
|
|
151
|
+
stroke-width="2"
|
|
152
|
+
stroke-linecap="round"
|
|
153
|
+
stroke-linejoin="round"
|
|
154
|
+
role="img"
|
|
155
|
+
aria-label={helper.__("article.article_info")}
|
|
156
|
+
>
|
|
128
157
|
<title>{helper.__("article.article_info")}</title>
|
|
129
|
-
<
|
|
130
|
-
|
|
131
|
-
|
|
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>
|
|
158
|
+
<circle cx="12" cy="12" r="10" />
|
|
159
|
+
<path d="M12 16v-4" />
|
|
160
|
+
<path d="M12 8h.01" />
|
|
136
161
|
</svg>
|
|
137
162
|
</button>
|
|
138
163
|
</div>
|
|
@@ -1,36 +1,11 @@
|
|
|
1
1
|
const { Component } = require("../../include/util/common");
|
|
2
2
|
|
|
3
|
-
function
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
if (!method) return "";
|
|
10
|
-
const key = `article.translation_methods.${method}`;
|
|
11
|
-
return getTranslatedValue(helper, key, method);
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
function getOriginalWorkValue(page, helper) {
|
|
15
|
-
const value = page.i18n?.original ?? page.original;
|
|
16
|
-
if (typeof value !== "boolean") return null;
|
|
17
|
-
return value ? helper.__("article.yes") : helper.__("article.no");
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
function getTranslationNote(page, helper) {
|
|
21
|
-
const translation = page.i18n?.translation || page.translation;
|
|
22
|
-
if (!translation) return null;
|
|
23
|
-
if (typeof translation === "string") return translation;
|
|
24
|
-
|
|
25
|
-
const parts = [];
|
|
26
|
-
const method = getTranslationMethodLabel(translation.method, helper);
|
|
27
|
-
if (method) parts.push(method);
|
|
28
|
-
if (typeof translation.reviewed === "boolean") {
|
|
29
|
-
parts.push(helper.__(translation.reviewed ? "article.translation_reviewed" : "article.translation_not_reviewed"));
|
|
30
|
-
}
|
|
31
|
-
if (translation.note) parts.push(translation.note);
|
|
32
|
-
|
|
33
|
-
return parts.length ? parts.join(" · ") : null;
|
|
3
|
+
function getTranslationInfo(page, helper) {
|
|
4
|
+
if (!page.i18n) return null;
|
|
5
|
+
const t = page.i18n.translation;
|
|
6
|
+
if (t === 1) return helper.__("article.translation_llm_reviewed");
|
|
7
|
+
if (t === 2) return helper.__("article.translation_llm_unreviewed");
|
|
8
|
+
return helper.__("article.translation_original");
|
|
34
9
|
}
|
|
35
10
|
|
|
36
11
|
function LanguageIcon({ title }) {
|
|
@@ -51,8 +26,7 @@ module.exports = class extends Component {
|
|
|
51
26
|
render() {
|
|
52
27
|
const { page, config, helper } = this.props;
|
|
53
28
|
const { article } = config;
|
|
54
|
-
const
|
|
55
|
-
const translationNote = getTranslationNote(page, helper);
|
|
29
|
+
const translationInfo = getTranslationInfo(page, helper);
|
|
56
30
|
|
|
57
31
|
const markdownSourceUrl = page.markdown_path ? helper.url_for(page.markdown_path) : null;
|
|
58
32
|
const markdownSourceLabel = helper.__("article.markdown_source");
|
|
@@ -171,25 +145,14 @@ module.exports = class extends Component {
|
|
|
171
145
|
</div>
|
|
172
146
|
</div>
|
|
173
147
|
)}
|
|
174
|
-
{
|
|
175
|
-
<div class="article-info-item">
|
|
176
|
-
<div class="article-info-icon">
|
|
177
|
-
<LanguageIcon title={helper.__("article.original_work")} />
|
|
178
|
-
</div>
|
|
179
|
-
<div class="article-info-content">
|
|
180
|
-
<span class="article-info-label">{helper.__("article.original_work")}</span>
|
|
181
|
-
<span class="article-info-value">{originalWorkValue}</span>
|
|
182
|
-
</div>
|
|
183
|
-
</div>
|
|
184
|
-
)}
|
|
185
|
-
{translationNote && (
|
|
148
|
+
{translationInfo && (
|
|
186
149
|
<div class="article-info-item">
|
|
187
150
|
<div class="article-info-icon">
|
|
188
|
-
<LanguageIcon title={helper.__("article.
|
|
151
|
+
<LanguageIcon title={helper.__("article.translation_info")} />
|
|
189
152
|
</div>
|
|
190
153
|
<div class="article-info-content">
|
|
191
|
-
<span class="article-info-label">{helper.__("article.
|
|
192
|
-
<span class="article-info-value">{
|
|
154
|
+
<span class="article-info-label">{helper.__("article.translation_info")}</span>
|
|
155
|
+
<span class="article-info-value">{translationInfo}</span>
|
|
193
156
|
</div>
|
|
194
157
|
</div>
|
|
195
158
|
)}
|
package/layout/common/footer.jsx
CHANGED
|
@@ -2,92 +2,25 @@ const { Component, cacheComponent } = require("../../include/util/common");
|
|
|
2
2
|
|
|
3
3
|
class Footer extends Component {
|
|
4
4
|
render() {
|
|
5
|
-
const {
|
|
5
|
+
const { copyright, showVisitorCounter, visitorCounterTitle, ICPRecord } = this.props;
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
<
|
|
9
|
-
<
|
|
10
|
-
<
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
stroke="var(--lavender)"
|
|
14
|
-
stroke-linecap="square"
|
|
15
|
-
></path>
|
|
16
|
-
</g>
|
|
17
|
-
</pattern>
|
|
18
|
-
<rect width="100%" height="100%" fill="url(#a)"></rect>
|
|
19
|
-
</svg>
|
|
20
|
-
);
|
|
21
|
-
|
|
22
|
-
const footer_brand = (
|
|
23
|
-
<div class="footer-column footer-brand">
|
|
24
|
-
<p class="footer-title">{author || siteTitle}</p>
|
|
25
|
-
<p class="footer-meta">
|
|
26
|
-
<span
|
|
27
|
-
dangerouslySetInnerHTML={{
|
|
28
|
-
__html: `© 2022 - ${siteYear}`,
|
|
29
|
-
}}
|
|
30
|
-
></span>
|
|
31
|
-
Powered by Hexo
|
|
7
|
+
return (
|
|
8
|
+
<footer class="footer">
|
|
9
|
+
<div class="footer-brand">
|
|
10
|
+
<p class="footer-credit">
|
|
11
|
+
2022–PRESENT <span class="footer-author">© GnixAij Oag</span> CC BY-NC-SA 4.0
|
|
12
|
+
</p>
|
|
32
13
|
{showVisitorCounter ? (
|
|
33
|
-
|
|
34
|
-
<br />
|
|
14
|
+
<p class="footer-meta">
|
|
35
15
|
<span id="busuanzi_container_site_uv" dangerouslySetInnerHTML={{ __html: visitorCounterTitle }}></span>
|
|
36
|
-
|
|
16
|
+
</p>
|
|
37
17
|
) : null}
|
|
38
18
|
{ICPRecord ? (
|
|
39
|
-
|
|
40
|
-
<
|
|
41
|
-
|
|
42
|
-
</>
|
|
19
|
+
<p class="footer-meta">
|
|
20
|
+
<a href="https://beian.miit.gov.cn/" class="footer-icp" target="_blank" rel="noopener" dangerouslySetInnerHTML={{ __html: ICPRecord }}></a>
|
|
21
|
+
</p>
|
|
43
22
|
) : null}
|
|
44
|
-
|
|
45
|
-
{copyright ? <p class="footer-meta" dangerouslySetInnerHTML={{ __html: copyright }}></p> : null}
|
|
46
|
-
</div>
|
|
47
|
-
);
|
|
48
|
-
|
|
49
|
-
const footer_social = (
|
|
50
|
-
<div class="footer-column footer-social">
|
|
51
|
-
<p class="footer-heading">Social Media</p>
|
|
52
|
-
<div class="footer-links">
|
|
53
|
-
{Object.keys(links).length
|
|
54
|
-
? Object.keys(links).map((name) => {
|
|
55
|
-
const link = links[name];
|
|
56
|
-
return (
|
|
57
|
-
<a class="footer-link" target="_blank" rel="noopener" title={name} href={link.url}>
|
|
58
|
-
{link.icon ? <iconify-icon icon={link.icon}></iconify-icon> : name}
|
|
59
|
-
</a>
|
|
60
|
-
);
|
|
61
|
-
})
|
|
62
|
-
: null}
|
|
63
|
-
</div>
|
|
64
|
-
</div>
|
|
65
|
-
);
|
|
66
|
-
|
|
67
|
-
const footer_subdomains = (
|
|
68
|
-
<div class="footer-column footer-subdomains">
|
|
69
|
-
<p class="footer-heading">Quick Links</p>
|
|
70
|
-
<div class="footer-links">
|
|
71
|
-
{Object.keys(subdomains).length
|
|
72
|
-
? Object.keys(subdomains).map((name) => {
|
|
73
|
-
const link = subdomains[name];
|
|
74
|
-
return (
|
|
75
|
-
<a class="footer-link" target="_self" rel="noopener" title={name} href={link.url}>
|
|
76
|
-
{name}
|
|
77
|
-
</a>
|
|
78
|
-
);
|
|
79
|
-
})
|
|
80
|
-
: null}
|
|
81
|
-
</div>
|
|
82
|
-
</div>
|
|
83
|
-
);
|
|
84
|
-
|
|
85
|
-
return (
|
|
86
|
-
<footer class="footer">
|
|
87
|
-
<div class="footer-grid">
|
|
88
|
-
{footer_brand}
|
|
89
|
-
{footer_subdomains}
|
|
90
|
-
{footer_social}
|
|
23
|
+
{copyright ? <p class="footer-meta" dangerouslySetInnerHTML={{ __html: copyright }}></p> : null}
|
|
91
24
|
</div>
|
|
92
25
|
</footer>
|
|
93
26
|
);
|
|
@@ -96,33 +29,10 @@ class Footer extends Component {
|
|
|
96
29
|
|
|
97
30
|
module.exports = cacheComponent(Footer, "common.footer", (props) => {
|
|
98
31
|
const { config, helper, page, site } = props;
|
|
99
|
-
const {
|
|
32
|
+
const { _p, date } = helper;
|
|
100
33
|
const { title, author, footer, plugins } = config;
|
|
101
34
|
const langKey = helper.language_key(page);
|
|
102
35
|
|
|
103
|
-
const links = {};
|
|
104
|
-
if (footer?.links) {
|
|
105
|
-
Object.keys(footer.links).forEach((name) => {
|
|
106
|
-
const link = footer.links[name];
|
|
107
|
-
links[name] = {
|
|
108
|
-
url: url_for(typeof link === "string" ? link : link.url),
|
|
109
|
-
icon: link.icon,
|
|
110
|
-
};
|
|
111
|
-
});
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
const subdomains = {};
|
|
115
|
-
if (footer?.subdomains) {
|
|
116
|
-
Object.keys(footer.subdomains).forEach((name) => {
|
|
117
|
-
const link = footer.subdomains[name];
|
|
118
|
-
const targetUrl = typeof link === "string" ? link : link.url;
|
|
119
|
-
subdomains[name] = {
|
|
120
|
-
url: helper.localized_url_for(targetUrl, langKey),
|
|
121
|
-
};
|
|
122
|
-
});
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
// Build archives grouped by year from site posts
|
|
126
36
|
let archives = [];
|
|
127
37
|
if (site?.posts?.length) {
|
|
128
38
|
const archiveDir = config.archive_dir || "archives";
|
|
@@ -148,8 +58,6 @@ module.exports = cacheComponent(Footer, "common.footer", (props) => {
|
|
|
148
58
|
siteTitle: title,
|
|
149
59
|
siteYear: date(new Date(), "YYYY"),
|
|
150
60
|
author,
|
|
151
|
-
links,
|
|
152
|
-
subdomains,
|
|
153
61
|
archives,
|
|
154
62
|
copyright: footer?.copyright ?? "",
|
|
155
63
|
showVisitorCounter: plugins && plugins.busuanzi === true,
|
package/layout/common/head.jsx
CHANGED
|
@@ -5,7 +5,7 @@ const StructuredData = require("../../layout/misc/structured_data");
|
|
|
5
5
|
const Plugins = require("./plugins");
|
|
6
6
|
const { getArticleFontInitScript } = require("../../include/util/article_font");
|
|
7
7
|
const { getThemeInitScript } = require("../../include/util/theme");
|
|
8
|
-
const { getDefaultLanguageKey,
|
|
8
|
+
const { getDefaultLanguageKey, getLanguage, getPageLanguageKey, getPageLocale, isI18nEnabled, normalizeLocale } = require("../../include/util/i18n");
|
|
9
9
|
const fs = require("node:fs");
|
|
10
10
|
const path = require("node:path");
|
|
11
11
|
|
|
@@ -82,27 +82,15 @@ function addExplicitAlternates(links, alternates, helper, config) {
|
|
|
82
82
|
});
|
|
83
83
|
}
|
|
84
84
|
|
|
85
|
-
function collectDocuments(site) {
|
|
86
|
-
return [...toArray(site?.posts), ...toArray(site?.pages)];
|
|
87
|
-
}
|
|
88
|
-
|
|
89
85
|
function getHreflangLinks(site, page, config, helper) {
|
|
90
86
|
if (!isI18nEnabled(config)) return [];
|
|
91
87
|
|
|
92
88
|
const links = new Map();
|
|
93
|
-
const pageKey = getI18nKey(page);
|
|
94
89
|
const langKey = getPageLanguageKey(page, config);
|
|
95
90
|
const locale = getPageLocale(page, config);
|
|
96
91
|
|
|
97
92
|
addAlternateLink(links, locale, page.permalink || page.path, helper, config);
|
|
98
|
-
addExplicitAlternates(links, page.i18n
|
|
99
|
-
|
|
100
|
-
if (pageKey) {
|
|
101
|
-
collectDocuments(site).forEach((item) => {
|
|
102
|
-
if (!item || getI18nKey(item) !== pageKey) return;
|
|
103
|
-
addAlternateLink(links, getPageLocale(item, config), item.permalink || item.path, helper, config);
|
|
104
|
-
});
|
|
105
|
-
}
|
|
93
|
+
addExplicitAlternates(links, page.i18n, helper, config);
|
|
106
94
|
|
|
107
95
|
if (links.size > 1 && !links.has("x-default")) {
|
|
108
96
|
const defaultLanguage = getLanguage(config, getDefaultLanguageKey(config));
|
|
@@ -174,10 +162,10 @@ module.exports = class extends Component {
|
|
|
174
162
|
|
|
175
163
|
return (
|
|
176
164
|
<head>
|
|
165
|
+
<meta charset="utf-8" />
|
|
177
166
|
<script dangerouslySetInnerHTML={{ __html: themeInitScript }}></script>
|
|
178
167
|
<script dangerouslySetInnerHTML={{ __html: articleFontUtilsScript }}></script>
|
|
179
168
|
<script dangerouslySetInnerHTML={{ __html: articleFontInitScript }}></script>
|
|
180
|
-
<meta charset="utf-8" />
|
|
181
169
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
182
170
|
{noIndex ? <meta name="robots" content="noindex" /> : null}
|
|
183
171
|
{meta?.length ? <MetaTags meta={meta} /> : null}
|
package/layout/common/navbar.jsx
CHANGED
|
@@ -1,25 +1,5 @@
|
|
|
1
1
|
const { Component, Fragment, cacheComponent } = require("../../include/util/common");
|
|
2
|
-
const {
|
|
3
|
-
|
|
4
|
-
function isActiveMenuLink(menuUrl, pageUrl) {
|
|
5
|
-
const menuPath = sanitizeLink(menuUrl);
|
|
6
|
-
const pagePath = sanitizeLink(pageUrl);
|
|
7
|
-
if (menuPath === pagePath) return true;
|
|
8
|
-
if (!menuPath) return false;
|
|
9
|
-
return pagePath.startsWith(`${menuPath}/`);
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
function sanitizeLink(url) {
|
|
13
|
-
let paths = url
|
|
14
|
-
.replace(/(^\w+:|^)\/\//, "")
|
|
15
|
-
.split("#")[0]
|
|
16
|
-
.split("/")
|
|
17
|
-
.filter((p) => p.trim() !== "");
|
|
18
|
-
if (paths.length > 0 && paths[paths.length - 1].trim() === "index.html") {
|
|
19
|
-
paths = paths.slice(0, paths.length - 1);
|
|
20
|
-
}
|
|
21
|
-
return paths.join("/");
|
|
22
|
-
}
|
|
2
|
+
const { getLanguage, getLanguageKeys, getPageLanguageKey, isExternalUrl, isI18nEnabled } = require("../../include/util/i18n");
|
|
23
3
|
|
|
24
4
|
const renderLinkIcon = (link) => {
|
|
25
5
|
if (!link.icon) return null;
|
|
@@ -36,16 +16,6 @@ const renderLinkIcon = (link) => {
|
|
|
36
16
|
return <iconify-icon icon={link.icon}></iconify-icon>;
|
|
37
17
|
};
|
|
38
18
|
|
|
39
|
-
function collectDocuments(site) {
|
|
40
|
-
return [...toArray(site?.posts), ...toArray(site?.pages)];
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
function getDocumentUrl(helper, document) {
|
|
44
|
-
const href = document?.path || document?.permalink;
|
|
45
|
-
if (!href) return null;
|
|
46
|
-
return isExternalUrl(href) ? href : helper.url_for(href);
|
|
47
|
-
}
|
|
48
|
-
|
|
49
19
|
function getTargetLanguageKey(config, currentLanguageKey) {
|
|
50
20
|
const languageKeys = getLanguageKeys(config);
|
|
51
21
|
if (currentLanguageKey === "en" && languageKeys.includes("cn")) return "cn";
|
|
@@ -71,27 +41,24 @@ function getLanguageSwitch(site, page, config, helper) {
|
|
|
71
41
|
if (!targetLanguage || targetLanguageKey === currentLanguageKey) return null;
|
|
72
42
|
const targetLanguageName = getTargetLanguageDisplayName(currentLanguageKey, targetLanguageKey, targetLanguage);
|
|
73
43
|
|
|
74
|
-
const pageKey = getI18nKey(page);
|
|
75
44
|
let url = null;
|
|
76
|
-
|
|
77
|
-
if (
|
|
78
|
-
const
|
|
79
|
-
|
|
45
|
+
const pageI18n = page.i18n;
|
|
46
|
+
if (pageI18n && typeof pageI18n === "object" && targetLanguageKey) {
|
|
47
|
+
const altUrl = pageI18n[targetLanguageKey] || (targetLanguage ? pageI18n[targetLanguage.locale] : null);
|
|
48
|
+
if (altUrl) {
|
|
49
|
+
url = isExternalUrl(altUrl) ? altUrl : helper.url_for(altUrl);
|
|
50
|
+
}
|
|
80
51
|
}
|
|
81
52
|
|
|
82
53
|
const isDocumentPage = ["page", "post"].includes(page?.layout);
|
|
83
54
|
const title = helper.__("navbar.language_switch", targetLanguageName);
|
|
84
|
-
const homeUrl = helper.localized_url_for("/", currentLanguageKey);
|
|
85
|
-
const unavailableTitle = helper.__("navbar.language_unavailable_title");
|
|
86
55
|
const unavailableMessage = helper.__("navbar.language_unavailable", targetLanguageName);
|
|
87
|
-
const stayLabel = helper.__("navbar.language_stay");
|
|
88
|
-
const homeLabel = helper.__("navbar.language_home");
|
|
89
|
-
const closeLabel = helper.__("navbar.language_close");
|
|
90
56
|
|
|
91
57
|
const mode = !url && isDocumentPage ? "missing" : "link";
|
|
92
58
|
|
|
93
59
|
if (!url && mode === "link") {
|
|
94
|
-
|
|
60
|
+
const targetPath = page?.current > 1 ? "/" : (page?.path || "/");
|
|
61
|
+
url = helper.localized_url_for(targetPath, targetLanguageKey);
|
|
95
62
|
}
|
|
96
63
|
|
|
97
64
|
return {
|
|
@@ -100,12 +67,7 @@ function getLanguageSwitch(site, page, config, helper) {
|
|
|
100
67
|
locale: targetLanguage.locale,
|
|
101
68
|
label: targetLanguageName,
|
|
102
69
|
title,
|
|
103
|
-
homeUrl,
|
|
104
|
-
unavailableTitle,
|
|
105
70
|
unavailableMessage,
|
|
106
|
-
stayLabel,
|
|
107
|
-
homeLabel,
|
|
108
|
-
closeLabel,
|
|
109
71
|
};
|
|
110
72
|
}
|
|
111
73
|
|
|
@@ -127,7 +89,7 @@ class Navbar extends Component {
|
|
|
127
89
|
<Fragment>
|
|
128
90
|
<nav class="navbar navbar-main">
|
|
129
91
|
<div class="navbar-container" onclick="toggleNav(event)">
|
|
130
|
-
<a href={siteUrl} style={"font-family: homemade-apple; color: var(--text); display: flex; align-items: center; padding: 0 1em;"}>
|
|
92
|
+
<a id="navbar-logo-link" href={siteUrl} style={"font-family: homemade-apple; color: var(--text); display: flex; align-items: center; padding: 0 1em;"}>
|
|
131
93
|
GnixAij
|
|
132
94
|
</a>
|
|
133
95
|
<div class="navbar-menu">
|
|
@@ -135,9 +97,8 @@ class Navbar extends Component {
|
|
|
135
97
|
<div class="navbar-start">
|
|
136
98
|
{Object.keys(menu).map((name) => {
|
|
137
99
|
const item = menu[name];
|
|
138
|
-
const navbar_item_class = `navbar-item ${item.active ? "is-active" : ""}`;
|
|
139
100
|
return (
|
|
140
|
-
<a class=
|
|
101
|
+
<a class="navbar-item" href={item.url} data-navbar-menu={name}>
|
|
141
102
|
{name}
|
|
142
103
|
</a>
|
|
143
104
|
);
|
|
@@ -162,7 +123,7 @@ class Navbar extends Component {
|
|
|
162
123
|
<a id="language-switch-link" class="navbar-item" href={languageSwitch.url || '#'} title={languageSwitch.title} aria-label={languageSwitch.title} lang={languageSwitch.locale} hreflang={languageSwitch.locale} style={languageSwitch.mode === 'link' ? '' : 'display:none'}>
|
|
163
124
|
{languageIcon}
|
|
164
125
|
</a>
|
|
165
|
-
<button id="language-switch-button" type="button" class="navbar-item" title={languageSwitch.title} aria-label={languageSwitch.title} lang={languageSwitch.locale}
|
|
126
|
+
<button id="language-switch-button" type="button" class="navbar-item" title={languageSwitch.title} aria-label={languageSwitch.title} lang={languageSwitch.locale} data-toast-message={languageSwitch.unavailableMessage} onclick="window.showSiteToast?.(this.dataset.toastMessage); return false;" style={languageSwitch.mode === 'missing' ? '' : 'display:none'}>
|
|
166
127
|
{languageIcon}
|
|
167
128
|
</button>
|
|
168
129
|
</Fragment>
|
|
@@ -192,31 +153,6 @@ class Navbar extends Component {
|
|
|
192
153
|
</button>
|
|
193
154
|
</div>
|
|
194
155
|
</nav>
|
|
195
|
-
{languageSwitch ? (
|
|
196
|
-
<div id="language-switch-popover" class="article-popover language-switch-popover" popover="auto" tabindex="-1">
|
|
197
|
-
<div class="article-popover-header">
|
|
198
|
-
<h3>{languageSwitch.unavailableTitle}</h3>
|
|
199
|
-
<button type="button" class="article-popover-close" popovertarget="language-switch-popover" popovertargetaction="hide" aria-label={languageSwitch.closeLabel}>
|
|
200
|
-
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" role="img" aria-label={languageSwitch.closeLabel}>
|
|
201
|
-
<title>{languageSwitch.closeLabel}</title>
|
|
202
|
-
<path d="M18 6 6 18" />
|
|
203
|
-
<path d="m6 6 12 12" />
|
|
204
|
-
</svg>
|
|
205
|
-
</button>
|
|
206
|
-
</div>
|
|
207
|
-
<div class="article-popover-body language-switch-popover-body">
|
|
208
|
-
<p>{languageSwitch.unavailableMessage}</p>
|
|
209
|
-
<div class="language-switch-popover-actions">
|
|
210
|
-
<button type="button" class="language-switch-popover-action" popovertarget="language-switch-popover" popovertargetaction="hide">
|
|
211
|
-
{languageSwitch.stayLabel}
|
|
212
|
-
</button>
|
|
213
|
-
<a id="language-switch-home-link" class="language-switch-popover-action is-primary" href={languageSwitch.homeUrl} onclick="document.getElementById('language-switch-popover')?.hidePopover()">
|
|
214
|
-
{languageSwitch.homeLabel}
|
|
215
|
-
</a>
|
|
216
|
-
</div>
|
|
217
|
-
</div>
|
|
218
|
-
</div>
|
|
219
|
-
) : null}
|
|
220
156
|
</Fragment>
|
|
221
157
|
);
|
|
222
158
|
}
|
|
@@ -233,11 +169,9 @@ module.exports = cacheComponent(Navbar, "common.navbar", (props) => {
|
|
|
233
169
|
|
|
234
170
|
const menu = {};
|
|
235
171
|
if (navbar?.menu) {
|
|
236
|
-
const pageUrl = typeof page.path !== "undefined" ? url_for(page.path) : "";
|
|
237
172
|
Object.keys(navbar.menu).forEach((name) => {
|
|
238
|
-
const
|
|
239
|
-
|
|
240
|
-
menu[name] = { url, active };
|
|
173
|
+
const rawValue = navbar.menu[name];
|
|
174
|
+
menu[name] = { url: helper.localized_url_for(rawValue, langKey) };
|
|
241
175
|
});
|
|
242
176
|
}
|
|
243
177
|
|
package/layout/layout.jsx
CHANGED
|
@@ -9,30 +9,47 @@ const { DEFAULT_SETTINGS: ARTICLE_FONT_DEFAULT_SETTINGS } = require("../include/
|
|
|
9
9
|
|
|
10
10
|
function buildLangSwitchScript(site, page, config, helper) {
|
|
11
11
|
const lswitch = Navbar.getLanguageSwitch(site, page, config, helper);
|
|
12
|
-
if (!lswitch) return "";
|
|
13
12
|
|
|
14
|
-
const
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
13
|
+
const langKey = helper.language_key(page);
|
|
14
|
+
const menu = {};
|
|
15
|
+
if (config.navbar?.menu) {
|
|
16
|
+
Object.keys(config.navbar.menu).forEach((name) => {
|
|
17
|
+
const rawValue = config.navbar.menu[name];
|
|
18
|
+
menu[name] = { url: helper.localized_url_for(rawValue, langKey) };
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
const siteUrl = helper.localized_url_for("/", langKey);
|
|
22
|
+
|
|
23
|
+
const payload = lswitch
|
|
24
|
+
? JSON.stringify({
|
|
25
|
+
mode: lswitch.mode,
|
|
26
|
+
url: lswitch.url || "",
|
|
27
|
+
locale: lswitch.locale,
|
|
28
|
+
})
|
|
29
|
+
: "null";
|
|
20
30
|
|
|
21
31
|
return `<script data-swup-reload-script>
|
|
22
32
|
(function() {
|
|
23
33
|
var d = ${payload};
|
|
24
34
|
var l = document.getElementById('language-switch-link');
|
|
25
35
|
var b = document.getElementById('language-switch-button');
|
|
26
|
-
if (
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
if (h) h.href = d.homeUrl;
|
|
36
|
+
if (l || b) {
|
|
37
|
+
if (d && d.mode === 'link' && d.url) {
|
|
38
|
+
if (l) { l.href = d.url; l.style.display = ''; l.setAttribute('lang', d.locale); l.setAttribute('hreflang', d.locale); }
|
|
39
|
+
if (b) b.style.display = 'none';
|
|
40
|
+
} else {
|
|
41
|
+
if (l) l.style.display = 'none';
|
|
42
|
+
if (b) { b.style.display = ''; b.setAttribute('lang', d.locale); }
|
|
43
|
+
}
|
|
35
44
|
}
|
|
45
|
+
var menu = ${JSON.stringify(menu)};
|
|
46
|
+
Object.keys(menu).forEach(function(name) {
|
|
47
|
+
var link = document.querySelector('a[data-navbar-menu="' + name + '"]');
|
|
48
|
+
if (!link) return;
|
|
49
|
+
link.href = menu[name].url;
|
|
50
|
+
});
|
|
51
|
+
var logo = document.getElementById('navbar-logo-link');
|
|
52
|
+
if (logo) logo.href = ${JSON.stringify(siteUrl)};
|
|
36
53
|
})();
|
|
37
54
|
<\/script>`;
|
|
38
55
|
}
|