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/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
- original_work: "Original work"
44
- translation_note: "Translation note"
45
- translation_reviewed: "manually reviewed"
46
- translation_not_reviewed: "not manually reviewed"
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"
@@ -40,16 +40,10 @@ article:
40
40
  article_title: "标题"
41
41
  url: "链接"
42
42
  markdown_source: "Markdown 源码"
43
- original_work: "原语言作品"
44
- translation_note: "翻译说明"
45
- translation_reviewed: "已人工审阅"
46
- translation_not_reviewed: "未人工审阅"
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 xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" role="img" aria-label={commentsLabel}>
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
- <g fill="none">
105
- <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" />
106
- <path
107
- fill="currentColor"
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 xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" role="img" aria-label={helper.__("article.font_settings")}>
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
- <g fill="none" fill-rule="evenodd">
118
- <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" />
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>
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 xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" role="img" aria-label={helper.__("article.article_info")}>
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
- <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>
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 getTranslatedValue(helper, key, fallback) {
4
- const translated = helper.__(key);
5
- return translated === key ? fallback : translated;
6
- }
7
-
8
- function getTranslationMethodLabel(method, helper) {
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 originalWorkValue = getOriginalWorkValue(page, helper);
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
- {originalWorkValue && (
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.translation_note")} />
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.translation_note")}</span>
192
- <span class="article-info-value">{translationNote}</span>
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
  )}
@@ -2,92 +2,25 @@ const { Component, cacheComponent } = require("../../include/util/common");
2
2
 
3
3
  class Footer extends Component {
4
4
  render() {
5
- const { siteTitle, siteYear, author, links, subdomains, copyright, showVisitorCounter, visitorCounterTitle, ICPRecord } = this.props;
5
+ const { copyright, showVisitorCounter, visitorCounterTitle, ICPRecord } = this.props;
6
6
 
7
- const svg_line = (
8
- <svg aria-hidden="true" width="100%" height="8" fill="none" xmlns="http://www.w3.org/2000/svg">
9
- <pattern id="a" width="91" height="8" patternUnits="userSpaceOnUse">
10
- <g clip-path="url(#clip0_2426_11367)">
11
- <path
12
- d="M114 4c-5.067 4.667-10.133 4.667-15.2 0S88.667-.667 83.6 4 73.467 8.667 68.4 4 58.267-.667 53.2 4 43.067 8.667 38 4 27.867-.667 22.8 4 12.667 8.667 7.6 4-2.533-.667-7.6 4s-10.133 4.667-15.2 0S-32.933-.667-38 4s-10.133 4.667-15.2 0-10.133-4.667-15.2 0-10.133 4.667-15.2 0-10.133-4.667-15.2 0-10.133 4.667-15.2 0-10.133-4.667-15.2 0-10.133 4.667-15.2 0-10.133-4.667-15.2 0-10.133 4.667-15.2 0-10.133-4.667-15.2 0-10.133 4.667-15.2 0-10.133-4.667-15.2 0-10.133 4.667-15.2 0-10.133-4.667-15.2 0-10.133 4.667-15.2 0-10.133-4.667-15.2 0-10.133 4.667-15.2 0-10.133-4.667-15.2 0-10.133 4.667-15.2 0-10.133-4.667-15.2 0-10.133 4.667-15.2 0-10.133-4.667-15.2 0-10.133 4.667-15.2 0-10.133-4.667-15.2 0-10.133 4.667-15.2 0"
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: `&copy; 2022 - ${siteYear}`,
29
- }}
30
- ></span>
31
- &nbsp;Powered by Hexo
7
+ return (
8
+ <footer class="footer">
9
+ <div class="footer-brand">
10
+ <p class="footer-credit">
11
+ 2022&ndash;PRESENT&ensp;<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
- <br />
41
- <a href="https://beian.miit.gov.cn/" style={"color: inherit"} target="_blank" rel="noopener" dangerouslySetInnerHTML={{ __html: ICPRecord }}></a>
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
- </p>
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 { url_for, _p, date } = helper;
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,
@@ -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, getI18nKey, getLanguage, getPageLanguageKey, getPageLocale, isI18nEnabled, normalizeLocale, toArray } = require("../../include/util/i18n");
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?.alternates || page.alternates || page.hreflang, helper, config);
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}
@@ -1,25 +1,5 @@
1
1
  const { Component, Fragment, cacheComponent } = require("../../include/util/common");
2
- const { getI18nKey, getLanguage, getLanguageKeys, getPageLanguageKey, isExternalUrl, isI18nEnabled, toArray } = require("../../include/util/i18n");
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 (pageKey) {
78
- const alternate = collectDocuments(site).find((item) => getI18nKey(item) === pageKey && getPageLanguageKey(item, config) === targetLanguageKey);
79
- url = getDocumentUrl(helper, alternate);
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
- url = helper.localized_url_for(page?.path || "/", targetLanguageKey);
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={navbar_item_class} href={item.url} aria-current={item.active ? "page" : null}>
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} popovertarget="language-switch-popover" style={languageSwitch.mode === 'missing' ? '' : 'display:none'}>
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 url = helper.localized_url_for(navbar.menu[name], langKey);
239
- const active = isActiveMenuLink(url, pageUrl);
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 payload = JSON.stringify({
15
- mode: lswitch.mode,
16
- url: lswitch.url || "",
17
- locale: lswitch.locale,
18
- homeUrl: lswitch.homeUrl,
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 (!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;
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
  }