hexo-theme-gnix 8.0.0 → 10.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 +4 -2
- package/include/hexo/feed.js +6 -5
- package/include/hexo/filter.js +25 -1
- package/include/hexo/generator/archive.js +116 -0
- package/include/hexo/generator/home.js +64 -0
- package/include/hexo/generator/index.js +82 -0
- package/include/hexo/generator/md_generator.js +87 -0
- package/include/hexo/generator/page.js +55 -0
- package/include/hexo/generator/tag.js +84 -0
- package/include/hexo/helper.js +38 -0
- package/include/hexo/i18n.js +183 -0
- package/include/util/article_font.js +132 -0
- package/include/util/i18n.js +280 -0
- package/include/util/theme.js +84 -0
- package/languages/en.yml +28 -0
- package/languages/zh-CN.yml +28 -0
- package/layout/archive.jsx +131 -127
- package/layout/common/article.jsx +316 -34
- package/layout/common/article_info.jsx +339 -0
- package/layout/common/article_media.jsx +11 -4
- package/layout/common/comment.jsx +15 -7
- package/layout/common/footer.jsx +6 -5
- package/layout/common/head.jsx +122 -33
- package/layout/common/navbar.jsx +195 -65
- package/layout/common/theme_selector.jsx +16 -14
- package/layout/layout.jsx +43 -5
- package/layout/misc/open_graph.jsx +162 -66
- package/layout/misc/paginator.jsx +2 -8
- package/layout/plugin/cookie_consent.jsx +252 -53
- package/layout/plugin/swup.jsx +1 -1
- package/layout/search/insight.jsx +1 -1
- package/layout/tag.jsx +3 -2
- package/layout/tags.jsx +81 -73
- package/package.json +5 -5
- package/scripts/index.js +1 -0
- package/source/css/archive.css +225 -180
- package/source/css/default.css +1223 -126
- package/source/css/responsive.css +426 -0
- package/source/css/shiki/shiki.css +12 -2081
- package/source/css/tags.css +183 -0
- package/source/css/twikoo.css +1053 -1049
- package/source/img/favicon.svg +1 -6
- package/source/img/og_image.webp +0 -0
- package/source/js/article-font-utils.js +99 -0
- package/source/js/busuanzi.js +91 -24
- package/source/js/components/chat.js +169 -50
- package/source/js/components/image-carousel.js +152 -108
- package/source/js/components/sidenote.js +210 -0
- package/source/js/components/text-image-section.js +78 -90
- package/source/js/components/theme-stacked.js +65 -33
- package/source/js/components/tree.js +30 -16
- package/source/js/decrypt.js +7 -2
- package/source/js/main.js +428 -5
- package/source/js/swup.js +39 -0
- package/source/js/theme-selector.js +26 -16
- package/include/hexo/generator.js +0 -53
- package/layout/misc/article_licensing.jsx +0 -99
- package/source/css/responsive/desktop.css +0 -36
- package/source/css/responsive/mobile.css +0 -38
- package/source/css/responsive/tablet.css +0 -43
- package/source/css/responsive/touch.css +0 -155
- package/source/img/logo.svg +0 -9
- package/source/js/archive-breadcrumb.js +0 -132
- package/source/js/host/cookieconsent/3.1.1/build/cookieconsent.min.css +0 -6
- package/source/js/host/cookieconsent/3.1.1/build/cookieconsent.min.js +0 -1
- package/source/js/swup.bundle.js +0 -1
package/layout/common/navbar.jsx
CHANGED
|
@@ -1,18 +1,24 @@
|
|
|
1
1
|
const { Component, Fragment, cacheComponent } = require("../../include/util/common");
|
|
2
|
+
const { getI18nKey, getLanguage, getLanguageKeys, getPageLanguageKey, isExternalUrl, isI18nEnabled, toArray } = require("../../include/util/i18n");
|
|
2
3
|
|
|
3
|
-
function
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
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);
|
|
14
20
|
}
|
|
15
|
-
return
|
|
21
|
+
return paths.join("/");
|
|
16
22
|
}
|
|
17
23
|
|
|
18
24
|
const renderLinkIcon = (link) => {
|
|
@@ -30,76 +36,197 @@ const renderLinkIcon = (link) => {
|
|
|
30
36
|
return <iconify-icon icon={link.icon}></iconify-icon>;
|
|
31
37
|
};
|
|
32
38
|
|
|
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
|
+
function getTargetLanguageKey(config, currentLanguageKey) {
|
|
50
|
+
const languageKeys = getLanguageKeys(config);
|
|
51
|
+
if (currentLanguageKey === "en" && languageKeys.includes("cn")) return "cn";
|
|
52
|
+
if (currentLanguageKey !== "en" && languageKeys.includes("en")) return "en";
|
|
53
|
+
return languageKeys.find((key) => key !== currentLanguageKey) || null;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function getTargetLanguageDisplayName(currentLanguageKey, targetLanguageKey, targetLanguage) {
|
|
57
|
+
if (currentLanguageKey === "en" && targetLanguageKey === "cn") return "Chinese";
|
|
58
|
+
if (currentLanguageKey !== "en" && targetLanguageKey === "en") return "英文";
|
|
59
|
+
return targetLanguage.label;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function getLanguageSwitch(site, page, config, helper) {
|
|
63
|
+
if (!isI18nEnabled(config)) return null;
|
|
64
|
+
|
|
65
|
+
const languageKeys = getLanguageKeys(config);
|
|
66
|
+
if (languageKeys.length < 2) return null;
|
|
67
|
+
|
|
68
|
+
const currentLanguageKey = getPageLanguageKey(page, config);
|
|
69
|
+
const targetLanguageKey = getTargetLanguageKey(config, currentLanguageKey);
|
|
70
|
+
const targetLanguage = getLanguage(config, targetLanguageKey);
|
|
71
|
+
if (!targetLanguage || targetLanguageKey === currentLanguageKey) return null;
|
|
72
|
+
const targetLanguageName = getTargetLanguageDisplayName(currentLanguageKey, targetLanguageKey, targetLanguage);
|
|
73
|
+
|
|
74
|
+
const pageKey = getI18nKey(page);
|
|
75
|
+
let url = null;
|
|
76
|
+
|
|
77
|
+
if (pageKey) {
|
|
78
|
+
const alternate = collectDocuments(site).find((item) => getI18nKey(item) === pageKey && getPageLanguageKey(item, config) === targetLanguageKey);
|
|
79
|
+
url = getDocumentUrl(helper, alternate);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const isDocumentPage = ["page", "post"].includes(page?.layout);
|
|
83
|
+
const title = helper.__("navbar.language_switch", targetLanguageName);
|
|
84
|
+
const homeUrl = helper.localized_url_for("/", currentLanguageKey);
|
|
85
|
+
const unavailableTitle = helper.__("navbar.language_unavailable_title");
|
|
86
|
+
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
|
+
|
|
91
|
+
const mode = !url && isDocumentPage ? "missing" : "link";
|
|
92
|
+
|
|
93
|
+
if (!url && mode === "link") {
|
|
94
|
+
url = helper.localized_url_for(page?.path || "/", targetLanguageKey);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
return {
|
|
98
|
+
mode,
|
|
99
|
+
url: url || null,
|
|
100
|
+
locale: targetLanguage.locale,
|
|
101
|
+
label: targetLanguageName,
|
|
102
|
+
title,
|
|
103
|
+
homeUrl,
|
|
104
|
+
unavailableTitle,
|
|
105
|
+
unavailableMessage,
|
|
106
|
+
stayLabel,
|
|
107
|
+
homeLabel,
|
|
108
|
+
closeLabel,
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
|
|
33
112
|
class Navbar extends Component {
|
|
34
113
|
render() {
|
|
35
|
-
const { siteUrl, menu, links, searchTitle } = this.props;
|
|
114
|
+
const { siteUrl, menu, links, languageSwitch, searchTitle } = this.props;
|
|
115
|
+
|
|
116
|
+
const languageIcon = (
|
|
117
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
|
|
118
|
+
<title>translate_2_line</title>
|
|
119
|
+
<g id="translate_2_line" fill="currentColor">
|
|
120
|
+
<path d="M12.87 15.07c-1.01-.28-1.93-.79-2.72-1.48l-.16-.14-.19.18a9.96 9.96 0 0 1-3.27 1.98 1 1 0 0 1-.71-1.87 7.96 7.96 0 0 0 2.58-1.55 9.5 9.5 0 0 1-1.54-2.69 1 1 0 1 1 1.88-.69c.29.79.71 1.52 1.24 2.16A7.95 7.95 0 0 0 11.66 8H5a1 1 0 1 1 0-2h4V4a1 1 0 1 1 2 0v2h4a1 1 0 1 1 0 2h-1.29a9.95 9.95 0 0 1-2.27 4.44l.05.04c.55.38 1.18.67 1.86.86a1 1 0 1 1-.48 1.94z"></path>
|
|
121
|
+
<path d="M17.5 10a1 1 0 0 1 .93.63l3.5 8.75a1 1 0 0 1-1.86.74L19.42 18h-3.84l-.65 2.12a1 1 0 0 1-1.86-.74l3.5-8.75A1 1 0 0 1 17.5 10m-1.15 6h2.3l-1.15-3.03z"></path>
|
|
122
|
+
</g>
|
|
123
|
+
</svg>
|
|
124
|
+
);
|
|
36
125
|
|
|
37
126
|
return (
|
|
38
|
-
<
|
|
39
|
-
<
|
|
40
|
-
<
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
<a class={navbar_item_class} href={item.url}>
|
|
51
|
-
{name}
|
|
52
|
-
</a>
|
|
53
|
-
);
|
|
54
|
-
})}
|
|
55
|
-
</div>
|
|
56
|
-
) : null}
|
|
57
|
-
<div class="navbar-end">
|
|
58
|
-
{Object.keys(links).length ? (
|
|
59
|
-
<Fragment>
|
|
60
|
-
{Object.keys(links).map((name) => {
|
|
61
|
-
const link = links[name];
|
|
127
|
+
<Fragment>
|
|
128
|
+
<nav class="navbar navbar-main">
|
|
129
|
+
<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;"}>
|
|
131
|
+
GnixAij
|
|
132
|
+
</a>
|
|
133
|
+
<div class="navbar-menu">
|
|
134
|
+
{Object.keys(menu).length ? (
|
|
135
|
+
<div class="navbar-start">
|
|
136
|
+
{Object.keys(menu).map((name) => {
|
|
137
|
+
const item = menu[name];
|
|
138
|
+
const navbar_item_class = `navbar-item ${item.active ? "is-active" : ""}`;
|
|
62
139
|
return (
|
|
63
|
-
<a class=
|
|
64
|
-
{
|
|
140
|
+
<a class={navbar_item_class} href={item.url} aria-current={item.active ? "page" : null}>
|
|
141
|
+
{name}
|
|
65
142
|
</a>
|
|
66
143
|
);
|
|
67
144
|
})}
|
|
68
|
-
</
|
|
145
|
+
</div>
|
|
69
146
|
) : null}
|
|
70
|
-
<
|
|
71
|
-
|
|
72
|
-
<
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
147
|
+
<div class="navbar-end">
|
|
148
|
+
{Object.keys(links).length ? (
|
|
149
|
+
<Fragment>
|
|
150
|
+
{Object.keys(links).map((name) => {
|
|
151
|
+
const link = links[name];
|
|
152
|
+
return (
|
|
153
|
+
<a class="navbar-item" target="_blank" rel="noopener" title={name} href={link.url}>
|
|
154
|
+
{renderLinkIcon(link)}
|
|
155
|
+
</a>
|
|
156
|
+
);
|
|
157
|
+
})}
|
|
158
|
+
</Fragment>
|
|
159
|
+
) : null}
|
|
160
|
+
{languageSwitch ? (
|
|
161
|
+
<Fragment>
|
|
162
|
+
<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
|
+
{languageIcon}
|
|
164
|
+
</a>
|
|
165
|
+
<button id="language-switch-button" type="button" class="navbar-item" title={languageSwitch.title} aria-label={languageSwitch.title} lang={languageSwitch.locale} popovertarget="language-switch-popover" style={languageSwitch.mode === 'missing' ? '' : 'display:none'}>
|
|
166
|
+
{languageIcon}
|
|
167
|
+
</button>
|
|
168
|
+
</Fragment>
|
|
169
|
+
) : null}
|
|
170
|
+
<button type="button" class="navbar-item" title="Choose Theme" popovertarget="theme-selector-popover">
|
|
171
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
|
|
172
|
+
<title>brightness_fill</title>
|
|
173
|
+
<g id="brightness_fill" fill="currentColor">
|
|
174
|
+
<path d="M12 18.5a1.5 1.5 0 0 1 1.493 1.356L13.5 20v1a1.5 1.5 0 0 1-2.993.144L10.5 21v-1a1.5 1.5 0 0 1 1.5-1.5m4.596-1.904a1.5 1.5 0 0 1 2.008-.103l.114.103.707.707a1.5 1.5 0 0 1-2.008 2.225l-.114-.103-.707-.707a1.5 1.5 0 0 1 0-2.122m-11.314 0a1.5 1.5 0 0 1 2.225 2.008l-.103.114-.707.707a1.5 1.5 0 0 1-2.225-2.008l.103-.114zM12 6a6 6 0 1 1 0 12 6 6 0 0 1 0-12m0 3a3 3 0 0 0-.176 5.995L12 15zm-8 1.5a1.5 1.5 0 0 1 .144 2.993L4 13.5H3a1.5 1.5 0 0 1-.144-2.993L3 10.5zm17 0a1.5 1.5 0 0 1 .144 2.993L21 13.5h-1a1.5 1.5 0 0 1-.144-2.993L20 10.5zM4.575 4.575a1.5 1.5 0 0 1 2.008-.103l.114.103.707.707a1.5 1.5 0 0 1-2.008 2.225l-.114-.103-.707-.707a1.5 1.5 0 0 1 0-2.122m12.728 0a1.5 1.5 0 0 1 2.225 2.008l-.103.114-.707.707a1.5 1.5 0 0 1-2.225-2.008l.103-.114zM12 1.5a1.5 1.5 0 0 1 1.493 1.356L13.5 3v1a1.5 1.5 0 0 1-2.993.144L10.5 4V3A1.5 1.5 0 0 1 12 1.5"></path>
|
|
175
|
+
</g>
|
|
176
|
+
</svg>
|
|
177
|
+
</button>
|
|
178
|
+
<button type="button" class="navbar-item search" popovertarget="searchbox" title={searchTitle}>
|
|
179
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
|
|
180
|
+
<title>search_line</title>
|
|
181
|
+
<g id="search_line" fill="currentColor">
|
|
182
|
+
<path d="M10.5 2a8.5 8.5 0 1 0 5.262 15.176l3.652 3.652a1 1 0 0 0 1.414-1.414l-3.652-3.652A8.5 8.5 0 0 0 10.5 2M4 10.5a6.5 6.5 0 1 1 13 0 6.5 6.5 0 0 1-13 0"></path>
|
|
183
|
+
</g>
|
|
184
|
+
</svg>
|
|
185
|
+
</button>
|
|
186
|
+
</div>
|
|
187
|
+
</div>
|
|
188
|
+
<button type="button" class="navbar-burger" aria-label="menu" aria-expanded="false">
|
|
189
|
+
<span aria-hidden="true"></span>
|
|
190
|
+
<span aria-hidden="true"></span>
|
|
191
|
+
<span aria-hidden="true"></span>
|
|
192
|
+
</button>
|
|
193
|
+
</div>
|
|
194
|
+
</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" />
|
|
84
204
|
</svg>
|
|
85
205
|
</button>
|
|
86
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>
|
|
87
218
|
</div>
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
<span aria-hidden="true"></span>
|
|
91
|
-
<span aria-hidden="true"></span>
|
|
92
|
-
</button>
|
|
93
|
-
</div>
|
|
94
|
-
</nav>
|
|
219
|
+
) : null}
|
|
220
|
+
</Fragment>
|
|
95
221
|
);
|
|
96
222
|
}
|
|
97
223
|
}
|
|
98
224
|
|
|
99
225
|
module.exports = cacheComponent(Navbar, "common.navbar", (props) => {
|
|
100
|
-
const { config, helper, page } = props;
|
|
226
|
+
const { site, config, helper, page } = props;
|
|
101
227
|
const { url_for, _p, __ } = helper;
|
|
102
228
|
const { logo, title, navbar, widgets } = config;
|
|
229
|
+
const langKey = helper.language_key(page);
|
|
103
230
|
|
|
104
231
|
const hasTocWidget = Array.isArray(widgets) && widgets.find((widget) => widget.type === "toc");
|
|
105
232
|
const showToc = (config.toc === true || page.toc) && hasTocWidget && ["page", "post"].includes(page.layout);
|
|
@@ -108,8 +235,8 @@ module.exports = cacheComponent(Navbar, "common.navbar", (props) => {
|
|
|
108
235
|
if (navbar?.menu) {
|
|
109
236
|
const pageUrl = typeof page.path !== "undefined" ? url_for(page.path) : "";
|
|
110
237
|
Object.keys(navbar.menu).forEach((name) => {
|
|
111
|
-
const url =
|
|
112
|
-
const active =
|
|
238
|
+
const url = helper.localized_url_for(navbar.menu[name], langKey);
|
|
239
|
+
const active = isActiveMenuLink(url, pageUrl);
|
|
113
240
|
menu[name] = { url, active };
|
|
114
241
|
});
|
|
115
242
|
}
|
|
@@ -127,12 +254,15 @@ module.exports = cacheComponent(Navbar, "common.navbar", (props) => {
|
|
|
127
254
|
|
|
128
255
|
return {
|
|
129
256
|
logo: url_for(logo),
|
|
130
|
-
siteUrl:
|
|
257
|
+
siteUrl: helper.localized_url_for("/", langKey),
|
|
131
258
|
siteTitle: title,
|
|
132
259
|
menu,
|
|
133
260
|
links,
|
|
261
|
+
languageSwitch: getLanguageSwitch(site, page, config, helper),
|
|
134
262
|
showToc,
|
|
135
263
|
tocTitle: _p("widget.catalogue", Infinity),
|
|
136
264
|
searchTitle: __("search.search"),
|
|
137
265
|
};
|
|
138
266
|
});
|
|
267
|
+
|
|
268
|
+
module.exports.getLanguageSwitch = getLanguageSwitch;
|
|
@@ -1,23 +1,25 @@
|
|
|
1
1
|
const { Component, cacheComponent } = require("../../include/util/common");
|
|
2
|
-
|
|
3
|
-
const themes = [
|
|
4
|
-
{ name: "🖥️ SYSTEM", value: "system" },
|
|
5
|
-
{ name: "🌻 LATTE", value: "latte" },
|
|
6
|
-
{ name: "🦭 NORD", value: "nord" },
|
|
7
|
-
{ name: "🐻❄️ NORD NIGHT", value: "nord_night" },
|
|
8
|
-
{ name: "🌹 ROSE PINE", value: "rose_pine" },
|
|
9
|
-
{ name: "🌿 MOCHA", value: "mocha" },
|
|
10
|
-
{ name: "🏙 TOKYO NIGHT", value: "tokyo_night" },
|
|
11
|
-
];
|
|
2
|
+
const { THEME_OPTIONS } = require("../../include/util/theme");
|
|
12
3
|
|
|
13
4
|
class ThemeSelector extends Component {
|
|
14
5
|
render() {
|
|
15
6
|
return (
|
|
16
7
|
<div id="theme-selector-popover" popover="auto" tabindex="-1">
|
|
17
|
-
<div
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
8
|
+
<div
|
|
9
|
+
class="theme-selector-list"
|
|
10
|
+
role="listbox"
|
|
11
|
+
aria-label="Select theme"
|
|
12
|
+
>
|
|
13
|
+
{THEME_OPTIONS.map((theme, index) => (
|
|
14
|
+
<button
|
|
15
|
+
class="theme-option"
|
|
16
|
+
type="submit"
|
|
17
|
+
role="option"
|
|
18
|
+
data-theme-option={theme.value}
|
|
19
|
+
data-index={index}
|
|
20
|
+
onclick={`window.selectThemeOption?.(${index})`}
|
|
21
|
+
>
|
|
22
|
+
{theme.label}
|
|
21
23
|
</button>
|
|
22
24
|
))}
|
|
23
25
|
</div>
|
package/layout/layout.jsx
CHANGED
|
@@ -5,23 +5,61 @@ const Footer = require("./common/footer");
|
|
|
5
5
|
const Scripts = require("./common/scripts");
|
|
6
6
|
const Search = require("./common/search");
|
|
7
7
|
const ThemeSelector = require("./common/theme_selector");
|
|
8
|
+
const { DEFAULT_SETTINGS: ARTICLE_FONT_DEFAULT_SETTINGS } = require("../include/util/article_font");
|
|
9
|
+
|
|
10
|
+
function buildLangSwitchScript(site, page, config, helper) {
|
|
11
|
+
const lswitch = Navbar.getLanguageSwitch(site, page, config, helper);
|
|
12
|
+
if (!lswitch) return "";
|
|
13
|
+
|
|
14
|
+
const payload = JSON.stringify({
|
|
15
|
+
mode: lswitch.mode,
|
|
16
|
+
url: lswitch.url || "",
|
|
17
|
+
locale: lswitch.locale,
|
|
18
|
+
homeUrl: lswitch.homeUrl,
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
return `<script data-swup-reload-script>
|
|
22
|
+
(function() {
|
|
23
|
+
var d = ${payload};
|
|
24
|
+
var l = document.getElementById('language-switch-link');
|
|
25
|
+
var b = document.getElementById('language-switch-button');
|
|
26
|
+
if (!l && !b) return;
|
|
27
|
+
if (d.mode === 'link' && d.url) {
|
|
28
|
+
if (l) { l.href = d.url; l.style.display = ''; l.setAttribute('lang', d.locale); l.setAttribute('hreflang', d.locale); }
|
|
29
|
+
if (b) b.style.display = 'none';
|
|
30
|
+
} else {
|
|
31
|
+
if (l) l.style.display = 'none';
|
|
32
|
+
if (b) { b.style.display = ''; b.setAttribute('lang', d.locale); }
|
|
33
|
+
var h = document.getElementById('language-switch-home-link');
|
|
34
|
+
if (h) h.href = d.homeUrl;
|
|
35
|
+
}
|
|
36
|
+
})();
|
|
37
|
+
<\/script>`;
|
|
38
|
+
}
|
|
8
39
|
|
|
9
40
|
module.exports = class extends Component {
|
|
10
41
|
render() {
|
|
11
42
|
const { site, config, page, helper, body } = this.props;
|
|
12
43
|
|
|
13
|
-
const language = page.lang || page.language || config.language || "en";
|
|
44
|
+
const language = helper.language_locale ? helper.language_locale(page) : page.lang || page.language || config.language || "en";
|
|
45
|
+
const langSwitchScript = buildLangSwitchScript(site, page, config, helper);
|
|
14
46
|
|
|
15
47
|
return (
|
|
16
|
-
<html
|
|
48
|
+
<html
|
|
49
|
+
lang={language ? language : ""}
|
|
50
|
+
data-article-font-size={ARTICLE_FONT_DEFAULT_SETTINGS.size}
|
|
51
|
+
data-article-font-family={ARTICLE_FONT_DEFAULT_SETTINGS.type}
|
|
52
|
+
data-article-line-height={String(ARTICLE_FONT_DEFAULT_SETTINGS.lineHeight)}
|
|
53
|
+
data-article-font-weight={ARTICLE_FONT_DEFAULT_SETTINGS.weight}
|
|
54
|
+
>
|
|
17
55
|
<Head site={site} config={config} helper={helper} page={page} />
|
|
18
56
|
<body>
|
|
19
|
-
<Navbar config={config} helper={helper} page={page} />
|
|
57
|
+
<Navbar site={site} config={config} helper={helper} page={page} />
|
|
20
58
|
<ThemeSelector />
|
|
21
59
|
<section class="section">
|
|
22
|
-
<div class="main-content transition-fade" id="swup" dangerouslySetInnerHTML={{ __html: body }}></div>
|
|
60
|
+
<div class="main-content transition-fade" id="swup" dangerouslySetInnerHTML={{ __html: body + langSwitchScript }}></div>
|
|
23
61
|
</section>
|
|
24
|
-
<Footer site={site} config={config} helper={helper} />
|
|
62
|
+
<Footer site={site} config={config} helper={helper} page={page} />
|
|
25
63
|
<Scripts site={site} config={config} helper={helper} page={page} />
|
|
26
64
|
<Search config={config} helper={helper} />
|
|
27
65
|
</body>
|