hexo-theme-gnix 1.1.0 → 1.2.1

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 CHANGED
@@ -1,10 +1,13 @@
1
- # Hexo Theme Icarus
1
+ ## Installation
2
2
 
3
- ## Demo & Preview
3
+ ```shell
4
+ bun add hexo-theme-gnix
5
+ hexo config theme gnix
6
+ ```
4
7
 
5
- [vluv's space](https://vluv.space/)
8
+ ## Features
6
9
 
7
- ### Multiple Theme Support
10
+ ### Multiple-Theme Support
8
11
 
9
12
  Support multiple light and dark themes:
10
13
 
@@ -12,95 +15,40 @@ Support multiple light and dark themes:
12
15
  - **Light Themes**: `Nord`, `Cattpuccin Latte`
13
16
  - **Dark Themes**: `Catppuccin Mocha`, `Catppuccin Macchiato`, `Tokyo Night`
14
17
 
15
- | ![](assets/README/nord.png) | ![](assets/README/mocha.png) |
16
- | --------------------------- | ---------------------------- |
17
-
18
- ### Mermaid Filter [^2]
19
-
20
- [^2]:
21
- Require [Efterklang/hexo-mermaid-diagram](https://github.com/Efterklang/hexo-mermaid-diagram)
22
- 🚧 Dark mode WIP...
23
-
24
- ![image](https://github.com/user-attachments/assets/3bd2d897-721d-4505-8194-6a592bbceb31)
25
-
26
- ### Components
18
+ <table border="1">
19
+ <tr>
20
+ <td><img width="3074" height="2060" alt="image" src="https://github.com/user-attachments/assets/80f772e7-2d91-4bd2-bfbe-bf73753721dc" /></td>
21
+ <td><img width="3074" height="2060" alt="image" src="https://github.com/user-attachments/assets/0ae6a569-5e88-41a2-92f3-e08b9d3e5531" /></td>
22
+ <td><img width="1758" height="2060" alt="image" src="https://github.com/user-attachments/assets/673a89fa-0ab0-43bb-a9e8-8dfd8eebaa90" /></td>
23
+ </tr>
24
+ </table>
27
25
 
28
- #### Table
29
-
30
- | ![1763371106238](assets/README/table_nord.png) | ![1763371131768](assets/README/table_tokyo.png) |
31
- | ---------------------------------------------- | ----------------------------------------------- |
32
-
33
- #### Quote
34
-
35
- | ![1763371059037](assets/README/quote_light.png) |
36
- | ----------------------------------------------- |
37
- | ![1763371021736](assets/README/quote_dark.png) |
38
-
39
- #### Footer
40
-
41
- | ![1763371250167](assets/README/footer_nord.png) |
42
- | ----------------------------------------------- |
43
- | ![1763371215054](assets/README/footer_dark.png) |
44
-
45
- ## Installation
46
-
47
- ### Using git submodule(Recommended)
48
-
49
- Using git submodule instead of bun add is recommended if you want to make any customizations to the theme
26
+ ## Components
50
27
 
51
28
  ```shell
52
- $ git submodule add https://github.com/Efterklang/hexo-theme-icarus themes/icarus
53
- $ hexo config theme icarus
54
- ```
55
-
56
- ```diff package.json
57
- {
58
- "dependencies": {
59
- + "hexo": "^7.2.0",
60
- + "hexo-cli": "^4.3.2",
61
- + "hexo-generator-archive": "^2.0.0",
62
- + "hexo-generator-category": "^2.0.0",
63
- + "hexo-generator-tag": "^2.0.0",
64
- + "hexo-pagination": "^3.0.0",
65
- + "hexo-renderer-inferno": "^1.0.2",
66
- + "hexo-server": "^3.0.0",
67
- + "hexo-util": "^3.3.0",
68
- + "inferno": "^9.0.3",
69
- + "inferno-create-element": "^9.0.3",
70
- + "moment": "^2.30.1"
71
- }
72
- }
29
+ bun i hexo-renderer-markdown-exit
73
30
  ```
74
31
 
75
- ### Using Bun
76
-
77
- ```shell
78
- $ bun add git+https://github.com/Efterklang/hexo-theme-icarus
79
- $ hexo config theme icarus
80
- ```
32
+ ### Table, Math, Quote, Callout & Tabs, Highlight
81
33
 
82
- ## Setup
34
+ <table>
35
+ <tr>
36
+ <td><img width="1806" height="378" alt="image" src="https://github.com/user-attachments/assets/63712c7c-4c4c-4a9e-89cb-1b558769e438" /></td>
37
+ <td><img width="1754" height="394" alt="image" src="https://github.com/user-attachments/assets/4055601f-da4f-4643-8eaf-7965afe3836f" /></td>
38
+ </tr>
39
+ <tr>
40
+ <td><img width="1314" height="508" alt="image" src="https://github.com/user-attachments/assets/26c31f7d-55dd-4e3f-994f-99492bb801f0" /></td>
41
+ <td><img width="1798" height="372" alt="image" src="https://github.com/user-attachments/assets/13251a06-444b-4aaf-aed4-c9f436f10393" /></td>
42
+ </tr>
43
+ </table>
83
44
 
84
- <details>
85
- <summary>Math Rendering Setup</summary>
45
+ ---
86
46
 
87
- To enable math rendering with optimized performance, use [markdown-it-mathjax3-pro](https://github.com/NeoNexusX/markdown-it-mathjax3-pro), which supports both SSR and CSR modes
88
-
89
- </details>
90
-
91
- <details>
92
- <summary>Code Highlight Setup</summary>
93
-
94
- Use [hexo-shiki-highlight](https://github.com/Efterklang/hexo-shiki-highlight) plugin for code block highlighting, support multiple themes as well;
95
-
96
- Set `syntax_highlighter` to `shiki` in your hexo `_config.yml`:
97
-
98
- ```yaml _config.yml
99
- # Syntax Highlighter
100
- syntax_highlighter: shiki
101
- ```
47
+ <table>
48
+ <tr>
49
+ <td><img width="1750" height="330" alt="image" src="https://github.com/user-attachments/assets/976531e7-6988-476f-a24b-d3aa40b53cab" /></td>
50
+ <td><img width="976" height="330" alt="image" src="https://github.com/user-attachments/assets/8ee76260-8054-41a2-8d89-2b982d4ef2bc" /></td>
51
+ </tr>
52
+ </table>
102
53
 
103
- | <img width="1386" height="720" alt="image" src="https://github.com/user-attachments/assets/f0435c12-5140-4ca4-86bb-e5237039cc2d" /> | <img width="1394" height="736" alt="image" src="https://github.com/user-attachments/assets/406a656f-9e99-4fb7-bb34-a2e1078451e4" /> |
104
- | ----------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------- |
105
54
 
106
- </details>
@@ -1,8 +1,3 @@
1
- /**
2
- * Register the Hexo filter for merging theme and site config, and add all helper functions to a
3
- * dedicated property (<code>helper</code>) in the locals.
4
- * @module hexo/filter/locals
5
- */
6
1
  const fs = require("node:fs");
7
2
  const path = require("node:path");
8
3
  const yaml = require("js-yaml");
@@ -1,6 +1,5 @@
1
- const moment = require("moment");
1
+ const { format, isValid, parseISO } = require("date-fns");
2
2
  const { Component, Fragment } = require("../include/util/common");
3
- const { toMomentLocale } = require("hexo/dist/plugins/helper/date");
4
3
  const Paginator = require("./misc/paginator");
5
4
  const ArticleMedia = require("./common/article_media");
6
5
 
@@ -9,9 +8,6 @@ module.exports = class extends Component {
9
8
  const { config, page, helper } = this.props;
10
9
  const { url_for, __, date_xml, date } = helper;
11
10
 
12
- const language = toMomentLocale(
13
- page.lang || page.language || config.language,
14
- );
15
11
  const timelineCss = `
16
12
  span.year {
17
13
  position: absolute;
@@ -44,18 +40,20 @@ module.exports = class extends Component {
44
40
  }
45
41
  `;
46
42
  function renderArticleList(posts, year, month = null) {
47
- const time = moment(
48
- [page.year, page.month ? page.month - 1 : null].filter(
49
- (i) => i !== null,
50
- ),
51
- );
43
+ let time = null;
44
+ if (page.year) {
45
+ const mm = page.month ? String(page.month).padStart(2, "0") : "01";
46
+ time = parseISO(`${page.year}-${mm}-01T00:00:00.000Z`);
47
+ }
52
48
  return (
53
49
  <div class="card">
54
50
  <div class="card-content">
55
51
  <span class="year">
56
52
  {month === null
57
53
  ? year
58
- : time.locale(language).format("MMMM YYYY")}
54
+ : isValid(time)
55
+ ? format(time, "LLLL yyyy")
56
+ : year}
59
57
  </span>
60
58
  <div class="timeline">
61
59
  {posts.map((post) => {
@@ -2,13 +2,15 @@
2
2
  * Article media component, used in article lists such as archive page and recent posts widget
3
3
  */
4
4
  const { Component } = require("inferno");
5
- const moment = require("moment");
5
+ const { format, parseISO, isValid } = require("date-fns");
6
6
 
7
7
  module.exports = class extends Component {
8
8
  render() {
9
9
  const { url, title, date, categories } = this.props;
10
10
  // Formatted like May.15
11
- const formattedDate = moment(date).format("MMM.DD");
11
+ let formattedDate = "";
12
+ const d = typeof date === "string" ? parseISO(date) : date;
13
+ formattedDate = isValid(d) ? format(d, "MMM.dd") : "";
12
14
  const categoryTags = [];
13
15
  categories.forEach((category, i) => {
14
16
  categoryTags.push(<a href={category.url}>{category.name}</a>);
@@ -1,13 +1,8 @@
1
- const {
2
- Component,
3
- loadComponent,
4
- handleWidgetError,
5
- } = require("../../include/util/common");
1
+ const { Component, loadComponent } = require("../../include/util/common");
6
2
 
7
3
  module.exports = class extends Component {
8
4
  render() {
9
5
  const { config, page, helper } = this.props;
10
- const { __ } = helper;
11
6
  const { comment } = config;
12
7
  if (!comment || typeof comment.type !== "string") {
13
8
  return null;
@@ -18,10 +13,6 @@ module.exports = class extends Component {
18
13
  <div class="card-content">
19
14
  {(() => {
20
15
  const Comment = loadComponent(`comment/${comment.type}`);
21
- if (!Comment) {
22
- handleWidgetError(`comment "${comment.type}"`);
23
- return null;
24
- }
25
16
  return (
26
17
  <Comment
27
18
  config={config}
@@ -83,23 +83,23 @@ class Footer extends Component {
83
83
  <div class="footer-links">
84
84
  {Object.keys(links).length
85
85
  ? Object.keys(links).map((name) => {
86
- const link = links[name];
87
- return (
88
- <a
89
- class="footer-link"
90
- target="_blank"
91
- rel="noopener"
92
- title={name}
93
- href={link.url}
94
- >
95
- {link.icon ? (
96
- <iconify-icon icon={link.icon}></iconify-icon>
97
- ) : (
98
- name
99
- )}
100
- </a>
101
- );
102
- })
86
+ const link = links[name];
87
+ return (
88
+ <a
89
+ class="footer-link"
90
+ target="_blank"
91
+ rel="noopener"
92
+ title={name}
93
+ href={link.url}
94
+ >
95
+ {link.icon ? (
96
+ <iconify-icon icon={link.icon}></iconify-icon>
97
+ ) : (
98
+ name
99
+ )}
100
+ </a>
101
+ );
102
+ })
103
103
  : null}
104
104
  </div>
105
105
  </div>
@@ -111,19 +111,19 @@ class Footer extends Component {
111
111
  <div class="footer-links">
112
112
  {Object.keys(subdomains).length
113
113
  ? Object.keys(subdomains).map((name) => {
114
- const link = subdomains[name];
115
- return (
116
- <a
117
- class="footer-link"
118
- target="_blank"
119
- rel="noopener"
120
- title={name}
121
- href={link.url}
122
- >
123
- {name}
124
- </a>
125
- );
126
- })
114
+ const link = subdomains[name];
115
+ return (
116
+ <a
117
+ class="footer-link"
118
+ target="_blank"
119
+ rel="noopener"
120
+ title={name}
121
+ href={link.url}
122
+ >
123
+ {name}
124
+ </a>
125
+ );
126
+ })
127
127
  : null}
128
128
  </div>
129
129
  </div>
@@ -135,10 +135,10 @@ class Footer extends Component {
135
135
  <div class="footer-links">
136
136
  {archives?.length
137
137
  ? archives.map((item) => (
138
- <a class="footer-link" href={item.url}>
139
- {item.year}
140
- </a>
141
- ))
138
+ <a class="footer-link" href={item.url}>
139
+ {item.year}
140
+ </a>
141
+ ))
142
142
  : null}
143
143
  </div>
144
144
  </div>
@@ -209,7 +209,7 @@ module.exports = class extends Component {
209
209
  href={url_for("/css/callout_blocks.css")}
210
210
  onload="this.onload=null;this.rel='stylesheet'"
211
211
  />
212
- <link rel="stylesheet" href="/css/shiki/shiki.min.css" />
212
+ <link rel="stylesheet" href="/css/shiki/shiki.css" />
213
213
  {/* Iconify Icons */}
214
214
  <script
215
215
  async
@@ -24,7 +24,7 @@ module.exports = class extends Component {
24
24
  ></script>
25
25
  <script async src="/js/shiki/shiki.js"></script>
26
26
  <script async src="/js/instant-page.min.js" type="module"></script>
27
- {config.plugins.live2d_Asoul && (
27
+ {config?.plugins?.live2d_Asoul && (
28
28
  <>
29
29
  <script src="/js/live2d_Asoul/TweenLite.js" defer></script>
30
30
  <script
@@ -14,7 +14,11 @@ class FloatingToc extends Component {
14
14
 
15
15
  return (
16
16
  <div class="toc-container" id="icarus-toc-container">
17
- <button class="toc-button" onclick="document.getElementById('icarus-toc-container').classList.toggle('is-open')">
17
+ <button
18
+ class="toc-button"
19
+ type="button"
20
+ onclick="document.getElementById('icarus-toc-container').classList.toggle('is-open')"
21
+ >
18
22
  <svg
19
23
  xmlns="http://www.w3.org/2000/svg"
20
24
  width="24"
@@ -36,7 +40,10 @@ class FloatingToc extends Component {
36
40
  <line x1="3" y1="18" x2="3.01" y2="18"></line>
37
41
  </svg>
38
42
  </button>
39
- <div class="toc-body" onclick="if(event.target === this || event.target.closest('.toc-link')) { document.getElementById('icarus-toc-container').classList.remove('is-open'); }">
43
+ <div
44
+ class="toc-body"
45
+ onclick="if(event.target === this || event.target.closest('.toc-link')) { document.getElementById('icarus-toc-container').classList.remove('is-open'); }"
46
+ >
40
47
  <div dangerouslySetInnerHTML={{ __html: tocContent }} />
41
48
  </div>
42
49
  </div>
@@ -1,12 +1,4 @@
1
- /**
2
- * A JSX component that renders Open Graph tags.
3
- * @module view/misc/open_graph
4
- *
5
- * @see https://hexo.io/docs/helpers#open-graph
6
- * @see https://github.com/hexojs/hexo/blob/4.2.0/lib/plugins/helper/open_graph.js
7
- */
8
- const urlFn = require("node:url");
9
- const moment = require("moment");
1
+ const { isDate, parseISO, isValid } = require("date-fns");
10
2
  const { Component } = require("inferno");
11
3
  const { encodeURL, stripHTML, escapeHTML } = require("hexo-util");
12
4
  const localeMap = {
@@ -82,38 +74,29 @@ module.exports = class extends Component {
82
74
  }
83
75
  images
84
76
  .map((path) => {
85
- if (!urlFn.parse(path).host) {
86
- // resolve `path`'s absolute path relative to current page's url
87
- // `path` can be both absolute (starts with `/`) or relative.
88
- return urlFn.resolve(url, path);
89
- }
90
- return path;
77
+ const parsed = new URL(path, url);
78
+ return parsed.toString();
91
79
  })
92
80
  .forEach((path) => {
93
81
  htmlTags.push(<meta property="og:image" content={path} />);
94
82
  });
95
83
 
96
- if (
97
- date &&
98
- (moment.isMoment(date) || moment.isDate(date)) &&
99
- !Number.isNaN(date.valueOf())
100
- ) {
101
- htmlTags.push(
102
- <meta property="article:published_time" content={date.toISOString()} />,
103
- );
84
+ if (date) {
85
+ const d = typeof date === "string" ? parseISO(date) : date;
86
+ if ((isDate(d) || d instanceof Date) && isValid(d)) {
87
+ htmlTags.push(
88
+ <meta property="article:published_time" content={d.toISOString()} />,
89
+ );
90
+ }
104
91
  }
105
92
 
106
- if (
107
- updated &&
108
- (moment.isMoment(updated) || moment.isDate(updated)) &&
109
- !Number.isNaN(updated.valueOf())
110
- ) {
111
- htmlTags.push(
112
- <meta
113
- property="article:modified_time"
114
- content={updated.toISOString()}
115
- />,
116
- );
93
+ if (updated) {
94
+ const u = typeof updated === "string" ? parseISO(updated) : updated;
95
+ if ((isDate(u) || u instanceof Date) && isValid(u)) {
96
+ htmlTags.push(
97
+ <meta property="article:modified_time" content={u.toISOString()} />,
98
+ );
99
+ }
117
100
  }
118
101
 
119
102
  if (author) {
@@ -1,28 +1,7 @@
1
- /**
2
- * A JSX component that renders simple Google structured data.
3
- * @module view/misc/structured_data
4
- */
5
- const urlFn = require("node:url");
6
- const moment = require("moment");
1
+ const { isDate, parseISO, isValid } = require("date-fns");
7
2
  const { Component } = require("inferno");
8
3
  const { stripHTML, escapeHTML } = require("hexo-util");
9
4
 
10
- /**
11
- * A JSX component that renders simple Google structured data.
12
- *
13
- * @name StructuredData
14
- * @example
15
- * <StructuredData
16
- * title="Page title"
17
- * url="/page/url"
18
- * author="Page author name"
19
- * publisher="Page publisher name"
20
- * publisherLogo="/path/to/logo"
21
- * description="Page description"
22
- * images={[ '/path/to/image' ]}
23
- * date="Page publish date"
24
- * updated="Page update date" />
25
- */
26
5
  module.exports = class extends Component {
27
6
  render() {
28
7
  const { title, url, author, publisher } = this.props;
@@ -39,12 +18,8 @@ module.exports = class extends Component {
39
18
  }
40
19
  images = images
41
20
  .map((path) => {
42
- if (!urlFn.parse(path).host) {
43
- // resolve `path`'s absolute path relative to current page's url
44
- // `path` can be both absolute (starts with `/`) or relative.
45
- return urlFn.resolve(url, path);
46
- }
47
- return path;
21
+ const parsed = new URL(path, url);
22
+ return parsed.toString();
48
23
  })
49
24
  .filter(
50
25
  (url) =>
@@ -54,24 +29,23 @@ module.exports = class extends Component {
54
29
  url.endsWith(".webp"),
55
30
  );
56
31
 
57
- if (typeof publisherLogo === "string" && !urlFn.parse(publisherLogo).host) {
58
- publisherLogo = urlFn.resolve(url, publisherLogo);
32
+ if (typeof publisherLogo === "string") {
33
+ const parsedLogo = new URL(publisherLogo, url);
34
+ publisherLogo = parsedLogo.toString();
59
35
  }
60
36
 
61
- if (
62
- date &&
63
- (moment.isMoment(date) || moment.isDate(date)) &&
64
- !Number.isNaN(date.valueOf())
65
- ) {
66
- date = date.toISOString();
37
+ if (date) {
38
+ const d = typeof date === "string" ? parseISO(date) : date;
39
+ if ((isDate(d) || d instanceof Date) && isValid(d)) {
40
+ date = d.toISOString();
41
+ }
67
42
  }
68
43
 
69
- if (
70
- updated &&
71
- (moment.isMoment(updated) || moment.isDate(updated)) &&
72
- !Number.isNaN(updated.valueOf())
73
- ) {
74
- updated = updated.toISOString();
44
+ if (updated) {
45
+ const u = typeof updated === "string" ? parseISO(updated) : updated;
46
+ if ((isDate(u) || u instanceof Date) && isValid(u)) {
47
+ updated = u.toISOString();
48
+ }
75
49
  }
76
50
 
77
51
  const data = {
@@ -1,15 +1,5 @@
1
- /**
2
- * Busuanzi visitor counter plugin JSX component.
3
- * @module view/plugin/baidu_analytics
4
- */
5
1
  const { Component, cacheComponent } = require("../../include/util/common");
6
- /**
7
- * Busuanzi visitor counter plugin JSX component.
8
- *
9
- * @see https://busuanzi.ibruce.info/
10
- * @example
11
- * <Busuanzi />
12
- */
2
+
13
3
  class Busuanzi extends Component {
14
4
  render() {
15
5
  return (
@@ -20,16 +10,6 @@ class Busuanzi extends Component {
20
10
  }
21
11
  }
22
12
 
23
- /**
24
- * Cacheable Busuanzi visitor counter plugin JSX component.
25
- * <p>
26
- * This class is supposed to be used in combination with the <code>locals</code> hexo filter
27
- * ({@link module:hexo/filter/locals}).
28
- *
29
- * @see module:util/cache.cacheComponent
30
- * @example
31
- * <Busuanzi.Cacheable head={true} />
32
- */
33
13
  Busuanzi.Cacheable = cacheComponent(Busuanzi, "plugin.busuanzi", (props) => {
34
14
  if (!props.head) {
35
15
  return null;
package/package.json CHANGED
@@ -1,25 +1,27 @@
1
1
  {
2
2
  "name": "hexo-theme-gnix",
3
- "version": "1.1.0",
3
+ "version": "1.2.1",
4
4
  "author": "Efterklang <gaojiaxing0220@gmail.com>",
5
5
  "license": "MIT",
6
6
  "description": "Second generation of Hexo theme Icarus, now with Catppuccin flavor and night mode support.",
7
7
  "keywords": [
8
8
  "hexo",
9
9
  "theme",
10
- "icarus",
11
10
  "catppuccin"
12
11
  ],
13
- "homepage": "https://github.com/Efterklang/hexo-theme-icarus",
14
- "repository": "https://github.com/Efterklang/hexo-theme-icarus.git",
12
+ "homepage": "https://github.com/Efterklang/gnix-blog-theme",
13
+ "repository": "https://github.com/Efterklang/gnix-blog-theme.git",
15
14
  "bugs": {
16
- "url": "https://github.com/Efterklang/hexo-theme-icarus/issues"
15
+ "url": "https://github.com/Efterklang/gnix-blog-theme/issues"
17
16
  },
18
17
  "engines": {
19
18
  "node": ">=14"
20
19
  },
21
20
  "scripts": {
22
- "lint": "biome check --write ."
21
+ "lint": "biome check --write .",
22
+ "format": "biome format .",
23
+ "check": "biome check",
24
+ "test": "echo \"No tests configured\" && exit 0"
23
25
  },
24
26
  "files": [
25
27
  "include",
@@ -31,12 +33,13 @@
31
33
  "README.md"
32
34
  ],
33
35
  "dependencies": {
36
+ "date-fns": "^2.30.0",
37
+ "hexo-pagination": "^4.0.0",
34
38
  "hexo-renderer-inferno": "^1.0.2",
35
- "moment": "^2.30.1"
39
+ "js-yaml": "^4.1.1"
36
40
  },
37
41
  "peerDependencies": {
38
42
  "hexo": ">=7.0.0",
39
- "hexo-util": ">=4.0.0",
40
- "hexo-pagination": ">=3.0.0"
43
+ "hexo-util": ">=4.0.0"
41
44
  }
42
45
  }
@@ -13,5 +13,5 @@
13
13
  }
14
14
 
15
15
  .content {
16
- font-family: "Huiwen-mincho";
16
+ font-family: "Huiwen-mincho", sans-serif;
17
17
  }