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
|
@@ -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
|
)}
|
|
@@ -12,11 +12,15 @@ function formatDate(date, dateXml) {
|
|
|
12
12
|
|
|
13
13
|
module.exports = class extends Component {
|
|
14
14
|
render() {
|
|
15
|
-
const { url, title, date, dateXml } = this.props;
|
|
15
|
+
const { url, title, date, dateXml, excerpt, readTime } = this.props;
|
|
16
16
|
const formattedDate = formatDate(date, dateXml);
|
|
17
|
+
const hasPreview = excerpt || readTime;
|
|
17
18
|
|
|
18
19
|
return (
|
|
19
|
-
<article
|
|
20
|
+
<article
|
|
21
|
+
class={hasPreview ? "archive-item has-preview" : "archive-item"}
|
|
22
|
+
data-read-time={readTime || null}
|
|
23
|
+
>
|
|
20
24
|
<div>
|
|
21
25
|
<p class="article-meta">
|
|
22
26
|
<time dateTime={dateXml || null}>{formattedDate}</time>
|
|
@@ -25,6 +29,9 @@ module.exports = class extends Component {
|
|
|
25
29
|
{title}
|
|
26
30
|
</a>
|
|
27
31
|
</div>
|
|
32
|
+
{excerpt && (
|
|
33
|
+
<template class="archive-item__excerpt" dangerouslySetInnerHTML={{ __html: excerpt }}></template>
|
|
34
|
+
)}
|
|
28
35
|
</article>
|
|
29
36
|
);
|
|
30
37
|
}
|
package/layout/common/footer.jsx
CHANGED
|
@@ -2,92 +2,28 @@ 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
|
-
|
|
14
|
-
|
|
15
|
-
|
|
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> 
|
|
12
|
+
<a href="https://creativecommons.org/licenses/by-nc-sa/4.0/" target="_blank" rel="license noopener noreferrer">
|
|
13
|
+
CC BY-NC-SA 4.0
|
|
14
|
+
</a>
|
|
15
|
+
</p>
|
|
32
16
|
{showVisitorCounter ? (
|
|
33
|
-
|
|
34
|
-
<br />
|
|
17
|
+
<p class="footer-meta">
|
|
35
18
|
<span id="busuanzi_container_site_uv" dangerouslySetInnerHTML={{ __html: visitorCounterTitle }}></span>
|
|
36
|
-
|
|
19
|
+
</p>
|
|
37
20
|
) : null}
|
|
38
21
|
{ICPRecord ? (
|
|
39
|
-
|
|
40
|
-
<
|
|
41
|
-
|
|
42
|
-
</>
|
|
22
|
+
<p class="footer-meta">
|
|
23
|
+
<a href="https://beian.miit.gov.cn/" class="footer-icp" target="_blank" rel="noopener" dangerouslySetInnerHTML={{ __html: ICPRecord }}></a>
|
|
24
|
+
</p>
|
|
43
25
|
) : 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}
|
|
26
|
+
{copyright ? <p class="footer-meta" dangerouslySetInnerHTML={{ __html: copyright }}></p> : null}
|
|
91
27
|
</div>
|
|
92
28
|
</footer>
|
|
93
29
|
);
|
|
@@ -96,33 +32,10 @@ class Footer extends Component {
|
|
|
96
32
|
|
|
97
33
|
module.exports = cacheComponent(Footer, "common.footer", (props) => {
|
|
98
34
|
const { config, helper, page, site } = props;
|
|
99
|
-
const {
|
|
35
|
+
const { _p, date } = helper;
|
|
100
36
|
const { title, author, footer, plugins } = config;
|
|
101
37
|
const langKey = helper.language_key(page);
|
|
102
38
|
|
|
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
39
|
let archives = [];
|
|
127
40
|
if (site?.posts?.length) {
|
|
128
41
|
const archiveDir = config.archive_dir || "archives";
|
|
@@ -148,8 +61,6 @@ module.exports = cacheComponent(Footer, "common.footer", (props) => {
|
|
|
148
61
|
siteTitle: title,
|
|
149
62
|
siteYear: date(new Date(), "YYYY"),
|
|
150
63
|
author,
|
|
151
|
-
links,
|
|
152
|
-
subdomains,
|
|
153
64
|
archives,
|
|
154
65
|
copyright: footer?.copyright ?? "",
|
|
155
66
|
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;
|
|
@@ -33,19 +13,8 @@ const renderLinkIcon = (link) => {
|
|
|
33
13
|
</svg>
|
|
34
14
|
);
|
|
35
15
|
}
|
|
36
|
-
return <iconify-icon icon={link.icon}></iconify-icon>;
|
|
37
16
|
};
|
|
38
17
|
|
|
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
18
|
function getTargetLanguageKey(config, currentLanguageKey) {
|
|
50
19
|
const languageKeys = getLanguageKeys(config);
|
|
51
20
|
if (currentLanguageKey === "en" && languageKeys.includes("cn")) return "cn";
|
|
@@ -71,22 +40,18 @@ function getLanguageSwitch(site, page, config, helper) {
|
|
|
71
40
|
if (!targetLanguage || targetLanguageKey === currentLanguageKey) return null;
|
|
72
41
|
const targetLanguageName = getTargetLanguageDisplayName(currentLanguageKey, targetLanguageKey, targetLanguage);
|
|
73
42
|
|
|
74
|
-
const pageKey = getI18nKey(page);
|
|
75
43
|
let url = null;
|
|
76
|
-
|
|
77
|
-
if (
|
|
78
|
-
const
|
|
79
|
-
|
|
44
|
+
const pageI18n = page.i18n;
|
|
45
|
+
if (pageI18n && typeof pageI18n === "object" && targetLanguageKey) {
|
|
46
|
+
const altUrl = pageI18n[targetLanguageKey] || (targetLanguage ? pageI18n[targetLanguage.locale] : null);
|
|
47
|
+
if (altUrl) {
|
|
48
|
+
url = isExternalUrl(altUrl) ? altUrl : helper.url_for(altUrl);
|
|
49
|
+
}
|
|
80
50
|
}
|
|
81
51
|
|
|
82
52
|
const isDocumentPage = ["page", "post"].includes(page?.layout);
|
|
83
53
|
const title = helper.__("navbar.language_switch", targetLanguageName);
|
|
84
|
-
const homeUrl = helper.localized_url_for("/", currentLanguageKey);
|
|
85
|
-
const unavailableTitle = helper.__("navbar.language_unavailable_title");
|
|
86
54
|
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
55
|
|
|
91
56
|
const mode = !url && isDocumentPage ? "missing" : "link";
|
|
92
57
|
|
|
@@ -100,12 +65,7 @@ function getLanguageSwitch(site, page, config, helper) {
|
|
|
100
65
|
locale: targetLanguage.locale,
|
|
101
66
|
label: targetLanguageName,
|
|
102
67
|
title,
|
|
103
|
-
homeUrl,
|
|
104
|
-
unavailableTitle,
|
|
105
68
|
unavailableMessage,
|
|
106
|
-
stayLabel,
|
|
107
|
-
homeLabel,
|
|
108
|
-
closeLabel,
|
|
109
69
|
};
|
|
110
70
|
}
|
|
111
71
|
|
|
@@ -127,7 +87,7 @@ class Navbar extends Component {
|
|
|
127
87
|
<Fragment>
|
|
128
88
|
<nav class="navbar navbar-main">
|
|
129
89
|
<div class="navbar-container" onclick="toggleNav(event)">
|
|
130
|
-
<a
|
|
90
|
+
<a id="navbar-logo-link" class="navbar-logo" href={siteUrl}>
|
|
131
91
|
GnixAij
|
|
132
92
|
</a>
|
|
133
93
|
<div class="navbar-menu">
|
|
@@ -135,9 +95,8 @@ class Navbar extends Component {
|
|
|
135
95
|
<div class="navbar-start">
|
|
136
96
|
{Object.keys(menu).map((name) => {
|
|
137
97
|
const item = menu[name];
|
|
138
|
-
const navbar_item_class = `navbar-item ${item.active ? "is-active" : ""}`;
|
|
139
98
|
return (
|
|
140
|
-
<a class=
|
|
99
|
+
<a class="navbar-item" href={item.url} data-navbar-menu={name}>
|
|
141
100
|
{name}
|
|
142
101
|
</a>
|
|
143
102
|
);
|
|
@@ -158,14 +117,19 @@ class Navbar extends Component {
|
|
|
158
117
|
</Fragment>
|
|
159
118
|
) : null}
|
|
160
119
|
{languageSwitch ? (
|
|
161
|
-
<
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
120
|
+
<a
|
|
121
|
+
id="language-switch"
|
|
122
|
+
class="navbar-item"
|
|
123
|
+
href={languageSwitch.url || "#"}
|
|
124
|
+
title={languageSwitch.title}
|
|
125
|
+
aria-label={languageSwitch.title}
|
|
126
|
+
lang={languageSwitch.locale}
|
|
127
|
+
hreflang={languageSwitch.locale}
|
|
128
|
+
data-mode={languageSwitch.mode}
|
|
129
|
+
data-toast-message={languageSwitch.unavailableMessage}
|
|
130
|
+
>
|
|
131
|
+
{languageIcon}
|
|
132
|
+
</a>
|
|
169
133
|
) : null}
|
|
170
134
|
<button type="button" class="navbar-item" title="Choose Theme" popovertarget="theme-selector-popover">
|
|
171
135
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
|
|
@@ -192,31 +156,6 @@ class Navbar extends Component {
|
|
|
192
156
|
</button>
|
|
193
157
|
</div>
|
|
194
158
|
</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
159
|
</Fragment>
|
|
221
160
|
);
|
|
222
161
|
}
|
|
@@ -233,11 +172,9 @@ module.exports = cacheComponent(Navbar, "common.navbar", (props) => {
|
|
|
233
172
|
|
|
234
173
|
const menu = {};
|
|
235
174
|
if (navbar?.menu) {
|
|
236
|
-
const pageUrl = typeof page.path !== "undefined" ? url_for(page.path) : "";
|
|
237
175
|
Object.keys(navbar.menu).forEach((name) => {
|
|
238
|
-
const
|
|
239
|
-
|
|
240
|
-
menu[name] = { url, active };
|
|
176
|
+
const rawValue = navbar.menu[name];
|
|
177
|
+
menu[name] = { url: helper.localized_url_for(rawValue, langKey) };
|
|
241
178
|
});
|
|
242
179
|
}
|
|
243
180
|
|
|
@@ -10,9 +10,9 @@ module.exports = class extends Component {
|
|
|
10
10
|
<Fragment>
|
|
11
11
|
<Plugins site={site} config={config} page={page} helper={helper} head={false} />
|
|
12
12
|
<Swup head={false} />
|
|
13
|
-
<script defer src="/js/host/iconify-icon/3.0.2/iconify-icon.min.js"></script>
|
|
14
13
|
<script defer src="/js/theme-selector.js"></script>
|
|
15
14
|
<script defer src="/js/host/medium-zoom/dist/medium-zoom.min.js"></script>
|
|
15
|
+
<script defer src="/js/components/archive-popup.js"></script>
|
|
16
16
|
<script defer src="/js/main.js"></script>
|
|
17
17
|
{page.encrypt ? <script src="/js/decrypt.js" type="module"></script> : null}
|
|
18
18
|
<script async src="/js/instant-page.min.js" type="module"></script>
|
package/layout/layout.jsx
CHANGED
|
@@ -9,32 +9,50 @@ 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
|
+
title: lswitch.title,
|
|
29
|
+
unavailableMessage: lswitch.unavailableMessage,
|
|
30
|
+
})
|
|
31
|
+
: "null";
|
|
20
32
|
|
|
21
33
|
return `<script data-swup-reload-script>
|
|
22
34
|
(function() {
|
|
23
35
|
var d = ${payload};
|
|
24
|
-
var
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
var h = document.getElementById('language-switch-home-link');
|
|
34
|
-
if (h) h.href = d.homeUrl;
|
|
36
|
+
var el = document.getElementById('language-switch');
|
|
37
|
+
if (el && d) {
|
|
38
|
+
el.href = d.mode === 'link' && d.url ? d.url : '#';
|
|
39
|
+
el.title = d.title;
|
|
40
|
+
el.setAttribute('aria-label', d.title);
|
|
41
|
+
el.setAttribute('lang', d.locale);
|
|
42
|
+
el.setAttribute('hreflang', d.locale);
|
|
43
|
+
el.dataset.mode = d.mode;
|
|
44
|
+
el.dataset.toastMessage = d.unavailableMessage;
|
|
35
45
|
}
|
|
46
|
+
var menu = ${JSON.stringify(menu)};
|
|
47
|
+
Object.keys(menu).forEach(function(name) {
|
|
48
|
+
var link = document.querySelector('a[data-navbar-menu="' + name + '"]');
|
|
49
|
+
if (!link) return;
|
|
50
|
+
link.href = menu[name].url;
|
|
51
|
+
});
|
|
52
|
+
var logo = document.getElementById('navbar-logo-link');
|
|
53
|
+
if (logo) logo.href = ${JSON.stringify(siteUrl)};
|
|
36
54
|
})();
|
|
37
|
-
|
|
55
|
+
</script>`;
|
|
38
56
|
}
|
|
39
57
|
|
|
40
58
|
module.exports = class extends Component {
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
const { Component, Fragment, cacheComponent } = require("../../include/util/common");
|
|
2
|
+
|
|
3
|
+
class Goatcounter extends Component {
|
|
4
|
+
render() {
|
|
5
|
+
const { url } = this.props;
|
|
6
|
+
|
|
7
|
+
return (
|
|
8
|
+
<Fragment>
|
|
9
|
+
<script data-goatcounter={url} async src="//gc.zgo.at/count.js"></script>
|
|
10
|
+
</Fragment>
|
|
11
|
+
);
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
Goatcounter.Cacheable = cacheComponent(Goatcounter, "plugin.goatcounter", (props) => {
|
|
16
|
+
const { head, plugin } = props;
|
|
17
|
+
if (!head || !plugin.url) {
|
|
18
|
+
return null;
|
|
19
|
+
}
|
|
20
|
+
return {
|
|
21
|
+
url: plugin.url,
|
|
22
|
+
};
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
module.exports = Goatcounter;
|