hexo-theme-gnix 7.0.0 → 9.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.
Files changed (53) hide show
  1. package/README.md +6 -2
  2. package/include/hexo/encrypt.js +42 -0
  3. package/include/hexo/feed.js +330 -0
  4. package/include/util/common.js +7 -16
  5. package/languages/en.yml +5 -2
  6. package/languages/zh-CN.yml +5 -2
  7. package/layout/archive.jsx +8 -204
  8. package/layout/comment/twikoo.jsx +2 -11
  9. package/layout/common/article.jsx +45 -32
  10. package/layout/common/article_cover.jsx +11 -1
  11. package/layout/common/article_media.jsx +2 -4
  12. package/layout/common/footer.jsx +10 -14
  13. package/layout/common/head.jsx +7 -15
  14. package/layout/common/navbar.jsx +3 -18
  15. package/layout/common/scripts.jsx +6 -5
  16. package/layout/common/theme_selector.jsx +5 -6
  17. package/layout/common/toc.jsx +8 -14
  18. package/layout/index.jsx +2 -4
  19. package/layout/misc/open_graph.jsx +4 -4
  20. package/layout/misc/paginator.jsx +10 -4
  21. package/layout/misc/structured_data.jsx +3 -4
  22. package/layout/plugin/busuanzi.jsx +1 -1
  23. package/layout/plugin/cookie_consent.jsx +40 -31
  24. package/layout/plugin/swup.jsx +2 -22
  25. package/layout/search/insight.jsx +16 -3
  26. package/package.json +12 -8
  27. package/scripts/hot-reload.js +92 -0
  28. package/scripts/index.js +2 -0
  29. package/source/css/archive.css +251 -0
  30. package/source/css/default.css +300 -309
  31. package/source/css/encrypt.css +55 -0
  32. package/source/css/responsive/desktop.css +0 -119
  33. package/source/css/responsive/mobile.css +2 -22
  34. package/source/css/responsive/touch.css +9 -103
  35. package/source/css/twikoo.css +265 -249
  36. package/source/img/og_image.webp +0 -0
  37. package/source/js/archive-breadcrumb.js +1 -5
  38. package/source/js/busuanzi.js +1 -12
  39. package/source/js/components/chat.js +239 -0
  40. package/source/js/components/image-carousel.js +410 -0
  41. package/source/js/components/text-image-section.js +180 -0
  42. package/source/js/components/theme-stacked.js +165 -246
  43. package/source/js/components/tree.js +437 -0
  44. package/source/js/decrypt.js +112 -0
  45. package/source/js/insight.js +75 -65
  46. package/source/js/main.js +48 -31
  47. package/source/js/mdit/mermaid.js +12 -4
  48. package/source/js/swup.bundle.js +1 -0
  49. package/source/js/theme-selector.js +94 -113
  50. package/source/img/og_image.png +0 -0
  51. package/source/js/host/swup/Swup.umd.min.js +0 -1
  52. package/source/js/host/swup/head-plugin.umd.min.js +0 -1
  53. package/source/js/host/swup/scripts-plugin.umd.min.js +0 -2
@@ -1,5 +1,4 @@
1
- const { format, isValid, parseISO } = require("date-fns");
2
- const { Component, Fragment } = require("../include/util/common");
1
+ const { Component, Fragment, isValidDate, parseISO, dateFormatters } = require("../include/util/common");
3
2
  const ArticleMedia = require("./common/article_media");
4
3
 
5
4
  module.exports = class extends Component {
@@ -7,201 +6,6 @@ module.exports = class extends Component {
7
6
  const { page, helper, site, config } = this.props;
8
7
  const { url_for, date_xml, date } = helper;
9
8
 
10
- const inlineCSS = `
11
- @keyframes blink {
12
- 0%, 100% { opacity: 1; }
13
- 50% { opacity: 0; }
14
- }
15
-
16
- .article-meta {
17
- font-size: 0.8rem;
18
- color: var(--subtext1);
19
- font-family: var(--font-handwriting);
20
- }
21
- a.archive-title {
22
- font-family: var(--font-sans-serif);
23
- font-weight: 400;
24
- color: var(--text);
25
-
26
- &:hover {
27
- color: var(--accent);
28
- }
29
- }
30
-
31
- .archive-breadcrumb {
32
- color: var(--blue);
33
- font-family: var(--font-mono);
34
- margin: 0 0 1rem 0;
35
- padding-left: 1em;
36
- display: flex;
37
- flex-wrap: wrap;
38
- align-items: center;
39
- gap: 0;
40
- }
41
- .archive-breadcrumb .prompt {
42
- color: var(--green);
43
- user-select: none;
44
- margin-right: 0.25em;
45
- }
46
- .archive-breadcrumb .cursor {
47
- display: inline-block;
48
- color: var(--mauve);
49
- font-weight: bold;
50
- margin-left: 2px;
51
- animation: blink 1s step-end infinite;
52
- user-select: none;
53
- }
54
- .archive-breadcrumb__cmd {
55
- color: var(--yellow);
56
- user-select: none;
57
- padding-right: 0.5em;
58
- }
59
- .archive-breadcrumb__picker {
60
- position: relative;
61
- display: inline-flex;
62
- align-items: center;
63
- }
64
- .archive-breadcrumb__trigger {
65
- display: inline-flex;
66
- align-items: center;
67
- border: none;
68
- background: transparent;
69
- color: var(--yellow);
70
- font-family: var(--font-mono);
71
- padding: 0.05em 0.15em;
72
- border-radius: 4px;
73
- text-decoration: underline;
74
- text-decoration-color: hsl(from var(--yellow) h s l / 0.6);
75
- text-decoration-thickness: 1px;
76
- text-underline-offset: 0.22em;
77
- cursor: pointer;
78
- transition: transform 120ms ease, color 120ms ease, background 120ms ease, text-decoration-color 120ms ease;
79
- }
80
- .archive-breadcrumb__trigger:hover {
81
- color: var(--mauve);
82
- background: hsl(from var(--base) h s l / 0.35);
83
- text-decoration-color: hsl(from var(--mauve) h s l / 0.75);
84
- }
85
- .archive-breadcrumb__trigger:focus-visible {
86
- outline: 2px solid hsl(from var(--mauve) h s l / 0.7);
87
- outline-offset: 2px;
88
- background: hsl(from var(--base) h s l / 0.35);
89
- }
90
- .archive-breadcrumb__trigger[aria-expanded="true"] {
91
- transform: translateY(-1px);
92
- color: var(--mauve);
93
- text-decoration-color: hsl(from var(--mauve) h s l / 0.9);
94
- }
95
- .archive-breadcrumb__trigger[disabled] {
96
- opacity: 0.45;
97
- cursor: not-allowed;
98
- text-decoration-color: hsl(from var(--subtext1) h s l / 0.4);
99
- }
100
- .archive-breadcrumb__menu {
101
- position: absolute;
102
- top: calc(100% + 6px);
103
- left: 0;
104
- min-width: 12rem;
105
- max-height: 15rem;
106
- overflow: auto;
107
- background: hsl(from var(--base) h s l / 0.9);
108
- border: 1px solid hsl(from var(--surface1) h s l / 0.9);
109
- border-radius: 10px;
110
- padding: 0.35rem;
111
- box-shadow: 0 18px 50px hsl(from var(--crust) h s l / 0.45);
112
- opacity: 0;
113
- transform: translateY(-6px);
114
- visibility: hidden;
115
- pointer-events: none;
116
- transition: opacity 160ms ease, transform 160ms ease, visibility 0s linear 160ms;
117
- z-index: 20;
118
- }
119
- .archive-breadcrumb__trigger[aria-expanded="true"] + .archive-breadcrumb__menu {
120
- opacity: 1;
121
- transform: translateY(0);
122
- visibility: visible;
123
- pointer-events: auto;
124
- transition: opacity 160ms ease, transform 160ms ease, visibility 0s;
125
- }
126
- .archive-breadcrumb__option {
127
- width: 100%;
128
- display: flex;
129
- justify-content: space-between;
130
- align-items: center;
131
- gap: 0.5rem;
132
- padding: 0.35rem 0.5rem;
133
- border-radius: 8px;
134
- border: none;
135
- background: transparent;
136
- color: var(--text);
137
- font-family: var(--font-mono);
138
- font-size: 0.9rem;
139
- cursor: pointer;
140
- transition: background 120ms ease, color 120ms ease;
141
- text-align: left;
142
- }
143
- .archive-breadcrumb__option:hover,
144
- .archive-breadcrumb__option:focus-visible {
145
- background: hsl(from var(--surface1) h s l / 0.55);
146
- color: var(--yellow);
147
- outline: none;
148
- }
149
- .archive-breadcrumb__option[aria-selected="true"] {
150
- background: hsl(from var(--surface1) h s l / 0.75);
151
- color: var(--mauve);
152
- }
153
- @media (max-width: 480px) {
154
- .archive-breadcrumb {
155
- padding-left: 0.5em;
156
- }
157
- .archive-breadcrumb__menu {
158
- min-width: 8rem;
159
- max-width: calc(100vw - 2rem);
160
- }
161
- }
162
-
163
- span.year {
164
- position: absolute;
165
- top: 1.5rem;
166
- right: 1.5rem;
167
- z-index: 0;
168
- font-weight: bolder;
169
- font-family: var(--font-handwriting);
170
- font-size: 4em;
171
- font-style: italic;
172
- color: hsl(from var(--accent, var(--lavender)) h s l / 0.3);
173
- line-height: 1;
174
- user-select: none;
175
- }
176
-
177
- .winter {
178
- --accent: var(--blue);
179
- }
180
- .autumn {
181
- --accent: var(--red);
182
- }
183
- .summer {
184
- --accent: var(--green);
185
- }
186
- .spring {
187
- --accent: var(--peach);
188
- }
189
- .archive-item {
190
- display: flex;
191
- text-align: left;
192
- align-items: flex-start;
193
- }
194
- .archive-item > div {
195
- display: flex;
196
- align-items: baseline; /* 时间和标题的文字基线对齐 */
197
- gap: 0.75rem;
198
- }
199
- .archive-item + .archive-item {
200
- border: none;
201
- margin-top: 0;
202
- padding-top: 1em;
203
- }
204
- `;
205
9
  function getSeason(month) {
206
10
  if (month >= 2 && month <= 4) return "Spring";
207
11
  if (month >= 5 && month <= 7) return "Summer";
@@ -219,8 +23,8 @@ module.exports = class extends Component {
219
23
  let title = `'${String(year).slice(-2)}`;
220
24
  if (sectionTitle) {
221
25
  title = sectionTitle;
222
- } else if (month !== null && isValid(time)) {
223
- title = format(time, "LLLL");
26
+ } else if (month !== null && isValidDate(time)) {
27
+ title = dateFormatters.longMonth.format(time);
224
28
  }
225
29
 
226
30
  return (
@@ -266,14 +70,14 @@ module.exports = class extends Component {
266
70
  articleList = renderArticleList(page.posts, page.year, page.month, null, season);
267
71
  }
268
72
 
269
- const archiveDir = (config && config.archive_dir) || "archives";
73
+ const archiveDir = config?.archive_dir || "archives";
270
74
  const archiveBasePath = url_for(`/${archiveDir}/`);
271
75
  const currentYear = page.year ? Number(page.year) : null;
272
76
  const currentMonth = page.month ? Number(page.month) : null;
273
77
 
274
78
  const yearToMonths = new Map();
275
- const allPosts = site && site.posts ? site.posts.sort("date", -1) : page.posts;
276
- if (allPosts && allPosts.each) {
79
+ const allPosts = site?.posts ? site.posts.sort("date", -1) : page.posts;
80
+ if (allPosts?.each) {
277
81
  allPosts.each((p) => {
278
82
  const y = p.date.year();
279
83
  const m = p.date.month() + 1;
@@ -290,8 +94,8 @@ module.exports = class extends Component {
290
94
 
291
95
  return (
292
96
  <Fragment>
293
- <script data-swup-ignore-script defer src="/js/archive-breadcrumb.js"></script>
294
- <style dangerouslySetInnerHTML={{ __html: inlineCSS }}></style>
97
+ <script data-swup-reload-script defer src="/js/archive-breadcrumb.js"></script>
98
+ <link rel="stylesheet" href="/css/archive.css" />
295
99
  <nav class="archive-breadcrumb" aria-label="archive breadcrumb" data-archive-breadcrumb data-archive-dir={archiveDir}>
296
100
  <span class="prompt">$</span>{" "}
297
101
  <span class="archive-breadcrumb__cmd" style="color: var(--blue)">
@@ -1,18 +1,9 @@
1
- const { Component, Fragment, cacheComponent, lazy_load_css } = require("../../include/util/common");
1
+ const { Component, cacheComponent } = require("../../include/util/common");
2
2
 
3
3
  class Twikoo extends Component {
4
4
  render() {
5
5
  const { envId, region, lang, jsUrl } = this.props;
6
- const configJs = `window.twikooConfig = { envId: '${envId}', ${region ? `region: ${JSON.stringify(region)},` : ""} ${lang ? `lang: ${JSON.stringify(lang)},` : ""} el: '#tko' };`;
7
- const lazy_load_css_script = lazy_load_css("/css/twikoo.css");
8
- return (
9
- <Fragment>
10
- <div id="tko" class="content twikoo"></div>
11
- <script dangerouslySetInnerHTML={{ __html: lazy_load_css_script }}></script>
12
- <script dangerouslySetInnerHTML={{ __html: configJs }}></script>
13
- <script defer src={jsUrl}></script>
14
- </Fragment>
15
- );
6
+ return <div id="tko" class="content twikoo" data-env-id={envId} data-region={JSON.stringify(region)} data-lang={JSON.stringify(lang)} data-js-url={jsUrl} data-css-url="/css/twikoo.css"></div>;
16
7
  }
17
8
  }
18
9
 
@@ -1,6 +1,4 @@
1
- import { format } from "date-fns";
2
-
3
- const { Component, Fragment } = require("../../include/util/common");
1
+ const { Component, Fragment, dateFormatters } = require("../../include/util/common");
4
2
  const Comment = require("./comment");
5
3
  const ArticleLicensing = require("../misc/article_licensing");
6
4
  const ArticleCover = require("./article_cover");
@@ -36,28 +34,20 @@ module.exports = class extends Component {
36
34
  {/* Cover image */}
37
35
  {cover ? <ArticleCover page={page} cover={cover} index={index} helper={helper} /> : null}
38
36
  <article class={`card-content article${"direction" in page ? ` ${page.direction}` : ""}`}>
39
- {/* Title */}
40
- {page.title !== "" && index ? (
41
- <h2 class="article-title">
42
- <a href={url_for(page.link || page.path)}>{page.title}</a>
43
- </h2>
44
- ) : null}
45
- {page.title !== "" && !index ? <h1 class="article-title">{page.title}</h1> : null}
46
-
47
37
  {/* Metadata - Medium style */}
48
38
  {page.layout !== "page" ? (
49
39
  <div class="article-header-meta">
50
40
  <div class="article-meta-info">
51
41
  {page.date && (
52
42
  <time class="article-date" datetime={page.date.toISOString()}>
53
- {format(page.date, "LLL dd")}
43
+ {dateFormatters.shortDay.format(page.date)}
54
44
  </time>
55
45
  )}
56
- {page.date && (wordCount > 0 || !index) && <span class="meta-separator">/</span>}
46
+ {page.date && (wordCount > 0 || !index) && <span class="meta-separator">·</span>}
57
47
  {wordCount > 0 && <span class="article-reading-time">{readTime} min</span>}
58
48
  {!index && (
59
49
  <Fragment>
60
- <span class="meta-separator">/</span>
50
+ <span class="meta-separator">·</span>
61
51
  <span
62
52
  class="article-visit-count"
63
53
  data-flag-title={page.title}
@@ -68,27 +58,50 @@ module.exports = class extends Component {
68
58
  </Fragment>
69
59
  )}
70
60
  </div>
71
- {page.tags?.length ? (
72
- <div class="article-tags-inline">
73
- {page.tags.map((tag) => (
74
- <Fragment>
75
- <a class="article-tag" rel="tag" href={url_for(tag.path)}>
76
- {tag.name}
77
- </a>
78
- </Fragment>
79
- ))}
80
- </div>
81
- ) : null}
82
61
  </div>
83
62
  ) : null}
84
63
 
85
- {/* Content/Excerpt */}
86
- <div
87
- class="content"
88
- dangerouslySetInnerHTML={{
89
- __html: index && page.excerpt ? page.excerpt : page.content,
90
- }}
91
- ></div>
64
+ {/* Title */}
65
+ {page.title !== "" && index ? (
66
+ <h2 class="article-title">
67
+ <a href={url_for(page.link || page.path)}>{page.title}</a>
68
+ </h2>
69
+ ) : null}
70
+ {page.title !== "" && !index ? <h1 class="article-title">{page.title}</h1> : null}
71
+
72
+ {!index && page.excerpt && <div class="content article-excerpt" dangerouslySetInnerHTML={{ __html: page.excerpt }}></div>}
73
+
74
+ {(index || !page.excerpt) && (
75
+ <div
76
+ class={index && page.excerpt ? "content article-excerpt" : "content"}
77
+ dangerouslySetInnerHTML={{
78
+ __html: index && page.excerpt ? page.excerpt : page.content,
79
+ }}
80
+ ></div>
81
+ )}
82
+
83
+ {page.tags?.length && (
84
+ <div class="article-footer">
85
+ <div class="article-tags">
86
+ {page.tags.map((tag, i) => (
87
+ <Fragment>
88
+ {i > 0 && <span class="meta-separator">·</span>}
89
+ <a class="article-tag" rel="tag" href={url_for(tag.path)}>
90
+ {tag.name}
91
+ </a>
92
+ </Fragment>
93
+ ))}
94
+ </div>
95
+ {index && (
96
+ <a class="article-read-more" href={url_for(page.link || page.path)}>
97
+ Read More →
98
+ </a>
99
+ )}
100
+ </div>
101
+ )}
102
+
103
+ {!index && page.excerpt && <div class="content" dangerouslySetInnerHTML={{ __html: page.content }}></div>}
104
+
92
105
  {/* Licensing block */}
93
106
  {!index && article && article.licenses && Object.keys(article.licenses) ? <ArticleLicensing.Cacheable page={page} config={config} helper={helper} /> : null}
94
107
  </article>
@@ -11,7 +11,17 @@ module.exports = class extends Component {
11
11
  return (
12
12
  <a href={url_for(page.link || page.path)} class="cover-image">
13
13
  <img class="cover-lqip" src={lqip_src} alt="placeholder" />
14
- <img class="cover-origin" src={cover} alt={page.title || cover} srcset={imageSrcset} referrerpolicy="no-referrer" decoding="async" loading={index ? "lazy" : "eager"} />
14
+ <img
15
+ class="cover-origin"
16
+ src={cover}
17
+ alt={page.title || cover}
18
+ srcset={imageSrcset}
19
+ sizes="(max-width: 768px) 100vw, (max-width: 1024px) 100vw, 960px"
20
+ referrerpolicy="no-referrer"
21
+ decoding="async"
22
+ loading={index ? "lazy" : "eager"}
23
+ fetchpriority={index ? undefined : "high"}
24
+ />
15
25
  </a>
16
26
  );
17
27
  }
@@ -1,14 +1,12 @@
1
1
  /**
2
2
  * Article media component, used in article lists such as archive page and recent posts widget
3
3
  */
4
- const { Component } = require("inferno");
5
- const { format, parseISO } = require("date-fns");
4
+ const { Component, dateFormatters, parseISO } = require("../../include/util/common");
6
5
 
7
6
  module.exports = class extends Component {
8
7
  render() {
9
8
  const { url, title, date } = this.props;
10
- // Formatted like May.15
11
- const formattedDate = format(parseISO(date), "MMM dd");
9
+ const formattedDate = dateFormatters.shortDay.format(parseISO(date));
12
10
 
13
11
  return (
14
12
  <article class="archive-item">
@@ -25,10 +25,10 @@ class Footer extends Component {
25
25
  <p class="footer-meta">
26
26
  <span
27
27
  dangerouslySetInnerHTML={{
28
- __html: `&copy; ${siteYear} ${author || siteTitle}`,
28
+ __html: `&copy; 2022 - ${siteYear}`,
29
29
  }}
30
30
  ></span>
31
- &nbsp;Powered by Hexo&nbsp;& Icarus
31
+ &nbsp;Powered by Hexo
32
32
  {showVisitorCounter ? (
33
33
  <>
34
34
  <br />
@@ -72,7 +72,7 @@ class Footer extends Component {
72
72
  ? Object.keys(subdomains).map((name) => {
73
73
  const link = subdomains[name];
74
74
  return (
75
- <a class="footer-link" target="_blank" rel="noopener" title={name} href={link.url}>
75
+ <a class="footer-link" target="_self" rel="noopener" title={name} href={link.url}>
76
76
  {name}
77
77
  </a>
78
78
  );
@@ -83,17 +83,13 @@ class Footer extends Component {
83
83
  );
84
84
 
85
85
  return (
86
- <>
87
- {" "}
88
- {svg_line}
89
- <footer class="footer">
90
- <div class="footer-grid">
91
- {footer_brand}
92
- {footer_subdomains}
93
- {footer_social}
94
- </div>
95
- </footer>
96
- </>
86
+ <footer class="footer">
87
+ <div class="footer-grid">
88
+ {footer_brand}
89
+ {footer_subdomains}
90
+ {footer_social}
91
+ </div>
92
+ </footer>
97
93
  );
98
94
  }
99
95
  }
@@ -28,7 +28,7 @@ module.exports = class extends Component {
28
28
  const { site, config, helper, page } = this.props;
29
29
  const { url_for, is_post } = helper;
30
30
  const { url, head = {}, article } = config;
31
- const { meta = [], open_graph = {}, structured_data = {}, canonical_url = page.permalink, rss, favicon } = head;
31
+ const { meta = [], open_graph = {}, structured_data = {}, canonical_url = page.permalink, favicon } = head;
32
32
 
33
33
  const noIndex = helper.is_archive() || helper.is_tag();
34
34
 
@@ -51,15 +51,7 @@ module.exports = class extends Component {
51
51
  images.push(img[1]);
52
52
  }
53
53
  } else {
54
- images = [url_for("/img/og_image.png")];
55
- }
56
-
57
- let adsenseClientId = null;
58
- if (Array.isArray(config.widgets)) {
59
- const widget = config.widgets.find((widget) => widget.type === "adsense");
60
- if (widget) {
61
- adsenseClientId = widget.client_id;
62
- }
54
+ images = [url_for("/img/og_image.webp")];
63
55
  }
64
56
 
65
57
  let openGraphImages = images;
@@ -100,7 +92,7 @@ module.exports = class extends Component {
100
92
 
101
93
  return (
102
94
  <head>
103
- <script data-swup-ignore-script dangerouslySetInnerHTML={{ __html: themeInitScript }}></script>
95
+ <script dangerouslySetInnerHTML={{ __html: themeInitScript }}></script>
104
96
  <meta charset="utf-8" />
105
97
  <meta name="viewport" content="width=device-width, initial-scale=1" />
106
98
  {noIndex ? <meta name="robots" content="noindex" /> : null}
@@ -141,7 +133,6 @@ module.exports = class extends Component {
141
133
  />
142
134
  ) : null}
143
135
  {canonical_url ? <link rel="canonical" href={canonical_url} /> : null}
144
- {rss ? <link rel="alternate" href={url_for(rss)} title={config.title} type="application/atom+xml" /> : null}
145
136
  {favicon ? <link rel="icon" href={url_for(favicon)} /> : null}
146
137
  <link rel="stylesheet" href={url_for("/css/default.css")} />
147
138
  <link rel="stylesheet" href={url_for("/css/responsive/mobile.css")} media="screen and (max-width:768px)" />
@@ -149,12 +140,13 @@ module.exports = class extends Component {
149
140
  <link rel="stylesheet" href={url_for("/css/responsive/touch.css")} media="screen and (max-width:1023px)" />
150
141
  <link rel="stylesheet" href={url_for("/css/responsive/desktop.css")} media="screen and (min-width:1024px)" />
151
142
  <link rel="preload" as="style" href={url_for("/css/callout_blocks.css")} onload="this.onload=null;this.rel='stylesheet'" />
152
- {/* Maple Mono CN */}
143
+ <link rel="preload" href={url_for("/css/font/woff2/HomemadeApple.woff2")} as="font" type="font/woff2" crossorigin />
153
144
  <link rel="preconnect" href="https://fontsapi.zeoseven.com" />
145
+ <link rel="preload" as="style" href="https://fontsapi.zeoseven.com/285/main/result.css" onload="this.onload=null;this.rel='stylesheet'" />
154
146
  <link rel="preload" as="style" href="https://fontsapi.zeoseven.com/442/main/result.css" onload="this.onload=null;this.rel='stylesheet'" />
155
- <link rel="stylesheet" href="/css/shiki/shiki.css" />
147
+ <link rel="preload" as="style" href="/css/shiki/shiki.css" onload="this.onload=null;this.rel='stylesheet'" />
148
+ {page.encrypt ? <link rel="stylesheet" href={url_for("/css/encrypt.css")} /> : null}
156
149
  <Plugins site={site} config={config} helper={helper} page={page} head={true} />
157
- {adsenseClientId ? <script data-swup-ignore-script data-ad-client={adsenseClientId} src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js" async></script> : null}
158
150
  </head>
159
151
  );
160
152
  }
@@ -36,22 +36,7 @@ class Navbar extends Component {
36
36
 
37
37
  return (
38
38
  <nav class="navbar navbar-main">
39
- <div
40
- class="navbar-container"
41
- onclick="
42
- const burger = this.querySelector('.navbar-burger');
43
- const menu = this.querySelector('.navbar-menu');
44
- const target = event.target;
45
-
46
- if (target.closest('.navbar-burger')) {
47
- burger.classList.toggle('is-active');
48
- menu.classList.toggle('is-active');
49
- } else if (target.closest('.navbar-item')) { // 点击菜单项:自动关闭菜单
50
- burger.classList.remove('is-active');
51
- menu.classList.remove('is-active');
52
- }
53
- "
54
- >
39
+ <div class="navbar-container" onclick="toggleNav(event)">
55
40
  <a href={siteUrl} style={"font-family: homemade-apple; color: var(--text); display: flex; align-items: center; padding: 0 1em;"}>
56
41
  GnixAij
57
42
  </a>
@@ -82,7 +67,7 @@ class Navbar extends Component {
82
67
  })}
83
68
  </Fragment>
84
69
  ) : null}
85
- <button type="button" class="navbar-item" id="theme-selector-trigger" title="Choose Theme" onclick="window.openThemeModal?.()">
70
+ <button type="button" class="navbar-item" title="Choose Theme" popovertarget="theme-selector-popover">
86
71
  <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
87
72
  <title>brightness_fill</title>
88
73
  <g id="brightness_fill" fill="currentColor">
@@ -90,7 +75,7 @@ class Navbar extends Component {
90
75
  </g>
91
76
  </svg>
92
77
  </button>
93
- <button type="button" class="navbar-item search" title={searchTitle}>
78
+ <button type="button" class="navbar-item search" popovertarget="searchbox" title={searchTitle}>
94
79
  <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
95
80
  <title>search_line</title>
96
81
  <g id="search_line" fill="currentColor">
@@ -10,11 +10,12 @@ 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 data-swup-ignore-script defer src="/js/host/iconify-icon/3.0.2/iconify-icon.min.js"></script>
14
- <script data-swup-ignore-script defer src="/js/theme-selector.js"></script>
15
- <script data-swup-ignore-script defer src="/js/host/medium-zoom/dist/medium-zoom.min.js"></script>
16
- <script data-swup-ignore-script defer src="/js/main.js"></script>
17
- <script data-swup-ignore-script async src="/js/instant-page.min.js" type="module"></script>
13
+ <script defer src="/js/host/iconify-icon/3.0.2/iconify-icon.min.js"></script>
14
+ <script defer src="/js/theme-selector.js"></script>
15
+ <script defer src="/js/host/medium-zoom/dist/medium-zoom.min.js"></script>
16
+ <script defer src="/js/main.js"></script>
17
+ {page.encrypt ? <script src="/js/decrypt.js" type="module"></script> : null}
18
+ <script async src="/js/instant-page.min.js" type="module"></script>
18
19
  </Fragment>
19
20
  );
20
21
  }
@@ -13,13 +13,12 @@ const themes = [
13
13
  class ThemeSelector extends Component {
14
14
  render() {
15
15
  return (
16
- <div id="theme-selector-modal" onclick="window.handleThemeModalClick?.(event)">
17
- <div class="theme-selector-backdrop"></div>
18
- <div class="theme-selector-list">
16
+ <div id="theme-selector-popover" popover="auto" tabindex="-1">
17
+ <div class="theme-selector-list" role="listbox" aria-label="Select theme">
19
18
  {themes.map((theme, index) => (
20
- <div class="theme-option" data-theme-option={theme.value} data-index={index} onclick={`window.selectThemeOption?.(event, ${index})`}>
21
- <span class="theme-name">{theme.name}</span>
22
- </div>
19
+ <button class="theme-option" type="submit" data-theme-option={theme.value} data-index={index} onclick={`window.selectThemeOption?.(${index})`}>
20
+ {theme.name}
21
+ </button>
23
22
  ))}
24
23
  </div>
25
24
  </div>
@@ -8,25 +8,19 @@ class FloatingToc extends Component {
8
8
  list_number: false,
9
9
  });
10
10
 
11
- if (!tocContent) {
11
+ if (!tocContent && !page.encrypt) {
12
12
  return null;
13
13
  }
14
14
 
15
15
  return (
16
- <div class="toc-container" id="icarus-toc-container">
17
- <button class="toc-button" type="button" onclick="document.getElementById('icarus-toc-container').classList.toggle('is-open')">
18
- <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
19
- <title>Table of Contents</title>
20
- <line x1="8" y1="6" x2="21" y2="6"></line>
21
- <line x1="8" y1="12" x2="21" y2="12"></line>
22
- <line x1="8" y1="18" x2="21" y2="18"></line>
23
- <line x1="3" y1="6" x2="3.01" y2="6"></line>
24
- <line x1="3" y1="12" x2="3.01" y2="12"></line>
25
- <line x1="3" y1="18" x2="3.01" y2="18"></line>
26
- </svg>
16
+ <div class="toc-container" id="icarus-toc-container" style={page.encrypt ? "display:none" : null}>
17
+ <button class="toc-button" type="button" popovertarget="toc-body" aria-label="Table of Contents">
18
+ <span aria-hidden="true"></span>
19
+ <span aria-hidden="true"></span>
20
+ <span aria-hidden="true"></span>
27
21
  </button>
28
- <div class="toc-body" onclick="if(event.target === this || event.target.matches('.toc-link')) { document.getElementById('icarus-toc-container').classList.remove('is-open'); }">
29
- <div dangerouslySetInnerHTML={{ __html: tocContent }} />
22
+ <div id="toc-body" popover="auto" class="toc-body" onclick="if(event.target===this||event.target.closest('.toc-link'))this.hidePopover();">
23
+ <div id="toc-insert" dangerouslySetInnerHTML={{ __html: tocContent || "" }} />
30
24
  </div>
31
25
  </div>
32
26
  );