hexo-theme-gnix 1.1.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 +106 -0
- package/include/hexo/filter/locals.js +109 -0
- package/include/hexo/generator/categories.js +12 -0
- package/include/hexo/generator/category.js +52 -0
- package/include/hexo/generator/insight.js +50 -0
- package/include/hexo/generator/manifest.js +23 -0
- package/include/hexo/generator/tags.js +12 -0
- package/include/hexo/helper/cdn.js +21 -0
- package/include/hexo/helper/page.js +27 -0
- package/include/hexo/view.js +40 -0
- package/include/register.js +11 -0
- package/include/util/common.js +33 -0
- package/languages/en.yml +47 -0
- package/languages/fr.yml +46 -0
- package/languages/ja.yml +46 -0
- package/languages/zh-CN.yml +47 -0
- package/languages/zh-TW.yml +47 -0
- package/layout/archive.jsx +118 -0
- package/layout/categories.jsx +137 -0
- package/layout/category.jsx +38 -0
- package/layout/comment/disqus.jsx +79 -0
- package/layout/comment/disqusjs.jsx +127 -0
- package/layout/comment/giscus.jsx +193 -0
- package/layout/comment/gitalk.jsx +141 -0
- package/layout/comment/twikoo.jsx +63 -0
- package/layout/comment/utterances.jsx +86 -0
- package/layout/comment/valine.jsx +143 -0
- package/layout/comment/waline.jsx +156 -0
- package/layout/common/article.jsx +131 -0
- package/layout/common/article_cover.jsx +33 -0
- package/layout/common/article_media.jsx +34 -0
- package/layout/common/comment.jsx +38 -0
- package/layout/common/footer.jsx +228 -0
- package/layout/common/head.jsx +242 -0
- package/layout/common/navbar.jsx +219 -0
- package/layout/common/plugins.jsx +39 -0
- package/layout/common/scripts.jsx +49 -0
- package/layout/common/search.jsx +22 -0
- package/layout/common/theme_selector.jsx +79 -0
- package/layout/common/toc.jsx +53 -0
- package/layout/index.jsx +29 -0
- package/layout/layout.jsx +34 -0
- package/layout/misc/article_licensing.jsx +114 -0
- package/layout/misc/meta.jsx +61 -0
- package/layout/misc/open_graph.jsx +164 -0
- package/layout/misc/paginator.jsx +90 -0
- package/layout/misc/structured_data.jsx +110 -0
- package/layout/misc/web_app.jsx +106 -0
- package/layout/page.jsx +12 -0
- package/layout/plugin/bing_webmaster.jsx +47 -0
- package/layout/plugin/busuanzi.jsx +40 -0
- package/layout/plugin/clarity.jsx +22 -0
- package/layout/plugin/cookie_consent.jsx +136 -0
- package/layout/plugin/google_analytics.jsx +66 -0
- package/layout/plugin/google_tag_mamager.jsx +41 -0
- package/layout/plugin/netlify.jsx +39 -0
- package/layout/plugin/pjax.jsx +20 -0
- package/layout/plugin/statcounter.jsx +69 -0
- package/layout/plugin/twitter_conversion_tracking.jsx +51 -0
- package/layout/post.jsx +16 -0
- package/layout/search/insight.jsx +53 -0
- package/layout/tag.jsx +29 -0
- package/layout/tags.jsx +55 -0
- package/package.json +42 -0
- package/scripts/index.js +1 -0
- package/source/css/callout_blocks.css +204 -0
- package/source/css/default.css +1590 -0
- package/source/css/font/woff2/Futura-Book.woff2 +0 -0
- package/source/css/font/woff2/Paris2024-Variable.woff2 +0 -0
- package/source/css/font/woff2/doto.woff2 +0 -0
- package/source/css/optional/chinese.css +17 -0
- package/source/css/responsive/desktop.css +164 -0
- package/source/css/responsive/mobile.css +46 -0
- package/source/css/responsive/tablet.css +46 -0
- package/source/css/responsive/touch.css +254 -0
- package/source/css/shiki/shiki.min.css +1 -0
- package/source/css/twikoo.css +2143 -0
- package/source/img/avatar.webp +0 -0
- package/source/img/background.webp +0 -0
- package/source/img/favicon.svg +6 -0
- package/source/img/logo.svg +9 -0
- package/source/img/og_image.png +0 -0
- package/source/js/busuanzi.js +46 -0
- package/source/js/host/cookieconsent/3.1.1/build/cookieconsent.min.css +6 -0
- package/source/js/host/cookieconsent/3.1.1/build/cookieconsent.min.js +1 -0
- package/source/js/host/iconify-icon/3.0.2/iconify-icon.min.js +12 -0
- package/source/js/host/medium-zoom/dist/medium-zoom.min.js +2 -0
- package/source/js/host/mermaid/mermaid.min.js +2811 -0
- package/source/js/host/pjax/0.2.8/pjax.min.js +1 -0
- package/source/js/host/twikoo/1.6.41/dist/twikoo.all.min.js +2 -0
- package/source/js/insight.js +330 -0
- package/source/js/instant-page.min.js +1 -0
- package/source/js/live2d_Asoul/Model/Ava/Ava.4096/texture_00.webp +0 -0
- package/source/js/live2d_Asoul/Model/Ava/Ava.moc3 +0 -0
- package/source/js/live2d_Asoul/Model/Ava/Ava.model3.json +323 -0
- package/source/js/live2d_Asoul/Model/Ava/Ava.physics3.json +1225 -0
- package/source/js/live2d_Asoul/Model/Ava/motions/Ava_idle.motion3.json +1 -0
- package/source/js/live2d_Asoul/Model/Ava/motions/Ava_shake01.motion3.json +1 -0
- package/source/js/live2d_Asoul/Model/Ava/motions/Ava_shake02.motion3.json +1 -0
- package/source/js/live2d_Asoul/Model/Ava/motions/Ava_tap01.motion3.json +1 -0
- package/source/js/live2d_Asoul/Model/Ava/motions/Ava_tap02.motion3.json +1 -0
- package/source/js/live2d_Asoul/Model/Ava/motions/Ava_tap03.motion3.json +1 -0
- package/source/js/live2d_Asoul/Model/Ava/motions/Ava_tap04.motion3.json +1 -0
- package/source/js/live2d_Asoul/Model/Ava/motions/Ava_tap05.motion3.json +1 -0
- package/source/js/live2d_Asoul/Model/Ava/motions/Ava_tap06.motion3.json +1 -0
- package/source/js/live2d_Asoul/Model/Ava/motions/Ava_tap07.motion3.json +1 -0
- package/source/js/live2d_Asoul/Model/Ava/motions/Ava_tap08.motion3.json +1 -0
- package/source/js/live2d_Asoul/Model/Ava/motions/Ava_tap09.motion3.json +1 -0
- package/source/js/live2d_Asoul/Model/Ava/motions/Ava_tap10.motion3.json +1 -0
- package/source/js/live2d_Asoul/Model/Ava/motions/Ava_tap11.motion3.json +1 -0
- package/source/js/live2d_Asoul/Model/Ava/raw.ex.json +16 -0
- package/source/js/live2d_Asoul/Model/Ava/raw.model3.json +321 -0
- package/source/js/live2d_Asoul/Model/Diana/Diana.4096/texture_00.webp +0 -0
- package/source/js/live2d_Asoul/Model/Diana/Diana.moc3 +0 -0
- package/source/js/live2d_Asoul/Model/Diana/Diana.model3.json +212 -0
- package/source/js/live2d_Asoul/Model/Diana/Diana.physics3.json +764 -0
- package/source/js/live2d_Asoul/Model/Diana/motions/Diana_idle.motion3.json +1 -0
- package/source/js/live2d_Asoul/Model/Diana/motions/Diana_tap01.motion3.json +1 -0
- package/source/js/live2d_Asoul/Model/Diana/motions/Diana_tap02.motion3.json +1 -0
- package/source/js/live2d_Asoul/Model/Diana/motions/Diana_tap03.motion3.json +1 -0
- package/source/js/live2d_Asoul/Model/Diana/motions/Diana_tap04.motion3.json +1 -0
- package/source/js/live2d_Asoul/Model/Diana/motions/Diana_tap05.motion3.json +1 -0
- package/source/js/live2d_Asoul/Model/Diana/motions/Diana_tap06.motion3.json +1 -0
- package/source/js/live2d_Asoul/Model/Diana/motions/Diana_tap07.motion3.json +1 -0
- package/source/js/live2d_Asoul/Model/Diana/motions/Diana_tap08.motion3.json +1 -0
- package/source/js/live2d_Asoul/Model/Diana/motions/Diana_tap09.motion3.json +1 -0
- package/source/js/live2d_Asoul/Model/Diana/motions/Diana_tap10.motion3.json +1 -0
- package/source/js/live2d_Asoul/Model/Diana/motions/Diana_tap11.motion3.json +1 -0
- package/source/js/live2d_Asoul/Model/Diana/raw.ex.json +16 -0
- package/source/js/live2d_Asoul/Model/Diana/raw.model3.json +210 -0
- package/source/js/live2d_Asoul/TweenLite.js +12 -0
- package/source/js/live2d_Asoul/cubism4.min.js +2 -0
- package/source/js/live2d_Asoul/live2dcubismcore.min.js +9 -0
- package/source/js/live2d_Asoul/load.js +231 -0
- package/source/js/live2d_Asoul/pio.css +161 -0
- package/source/js/live2d_Asoul/pio.js +296 -0
- package/source/js/live2d_Asoul/pio_sdk4.js +149 -0
- package/source/js/live2d_Asoul/pixi.min.js +9 -0
- package/source/js/main.js +218 -0
- package/source/js/pjax.js +29 -0
- package/source/js/shiki/shiki.js +191 -0
- package/source/js/theme-selector.js +206 -0
- package/util/cache.js +47 -0
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Waline comment JSX component.
|
|
3
|
+
* @module view/comment/waline
|
|
4
|
+
*/
|
|
5
|
+
const { Component, cacheComponent } = require("../../include/util/common");
|
|
6
|
+
/**
|
|
7
|
+
* Waline comment JSX component.
|
|
8
|
+
*
|
|
9
|
+
* @see https://waline.js.org/guide/get-started.html
|
|
10
|
+
* @example
|
|
11
|
+
* <Waline
|
|
12
|
+
* serverURL="https://path/to/waline/server"
|
|
13
|
+
* path="window.location.pathname"
|
|
14
|
+
* lang="zh-CN"
|
|
15
|
+
* locale={{placeholder: "", ...}}
|
|
16
|
+
* emoji={["https://cdn.jsdelivr.net/gh/walinejs/emojis/weibo"]}
|
|
17
|
+
* dark="auto"
|
|
18
|
+
* meta={["nick", "mail", "link"]}
|
|
19
|
+
* requiredMeta={[]}
|
|
20
|
+
* login="enable"
|
|
21
|
+
* wordLimit={0},
|
|
22
|
+
* pageSize={10}
|
|
23
|
+
* imageUploader={true}
|
|
24
|
+
* highlighter={true}
|
|
25
|
+
* texRenderer={false}
|
|
26
|
+
* search={true}
|
|
27
|
+
* visitor={false}
|
|
28
|
+
* pageview={false}
|
|
29
|
+
* comment={false}
|
|
30
|
+
* copyright={true}
|
|
31
|
+
* jsUrl="/path/to/Waline.js" />
|
|
32
|
+
*/
|
|
33
|
+
class Waline extends Component {
|
|
34
|
+
render() {
|
|
35
|
+
const {
|
|
36
|
+
serverURL,
|
|
37
|
+
path = "window.location.pathname",
|
|
38
|
+
lang = "zh-CN",
|
|
39
|
+
locale,
|
|
40
|
+
emoji = ["https://cdn.jsdelivr.net/gh/walinejs/emojis/weibo"],
|
|
41
|
+
dark = "",
|
|
42
|
+
meta = ["nick", "mail", "link"],
|
|
43
|
+
requiredMeta = [],
|
|
44
|
+
login = "enable",
|
|
45
|
+
wordLimit = 0,
|
|
46
|
+
pageSize = 10,
|
|
47
|
+
imageUploader = false,
|
|
48
|
+
highlighter = false,
|
|
49
|
+
texRenderer = false,
|
|
50
|
+
search = false,
|
|
51
|
+
pageview = false,
|
|
52
|
+
comment = false,
|
|
53
|
+
copyright = true,
|
|
54
|
+
jsUrl,
|
|
55
|
+
cssUrl,
|
|
56
|
+
} = this.props;
|
|
57
|
+
if (!serverURL) {
|
|
58
|
+
return (
|
|
59
|
+
<div class="notification is-danger">
|
|
60
|
+
You forgot to set the <code>server_url</code> for Waline. Please set
|
|
61
|
+
it in <code>_config.yml</code>.
|
|
62
|
+
</div>
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
const js = `import { init } from "${jsUrl}";
|
|
66
|
+
init({
|
|
67
|
+
el: '#waline-thread',
|
|
68
|
+
serverURL: ${JSON.stringify(serverURL)},
|
|
69
|
+
path: ${path},
|
|
70
|
+
${lang ? `lang: ${JSON.stringify(lang)},` : ""}
|
|
71
|
+
${locale ? `locale: ${JSON.stringify(locale)},` : ""}
|
|
72
|
+
${emoji ? `emoji: ${JSON.stringify(emoji)},` : ""}
|
|
73
|
+
${dark ? `dark: ${JSON.stringify(dark)},` : ""}
|
|
74
|
+
${meta ? `meta: ${JSON.stringify(meta)},` : ""}
|
|
75
|
+
${Array.isArray(requiredMeta) ? `requiredMeta: ${JSON.stringify(requiredMeta)},` : ""}
|
|
76
|
+
${login ? `login: ${JSON.stringify(login)},` : ""}
|
|
77
|
+
${wordLimit ? `wordLimit: ${JSON.stringify(wordLimit)},` : ""}
|
|
78
|
+
${pageSize ? `pageSize: ${JSON.stringify(pageSize)},` : ""}
|
|
79
|
+
${imageUploader === false ? `imageUploader: false,` : ""}
|
|
80
|
+
${highlighter === false ? `highlighter: false,` : ""}
|
|
81
|
+
${texRenderer === false ? `texRenderer: false,` : ""}
|
|
82
|
+
${search === false ? `search: false,` : ""}
|
|
83
|
+
${typeof pageview !== "undefined" ? `pageview: ${JSON.stringify(pageview)},` : ""}
|
|
84
|
+
${typeof comment !== "undefined" ? `comment: ${JSON.stringify(comment)},` : ""}
|
|
85
|
+
${`copyright: ${JSON.stringify(copyright)},`}
|
|
86
|
+
});`;
|
|
87
|
+
return (
|
|
88
|
+
<>
|
|
89
|
+
<div id="waline-thread" class="content"></div>
|
|
90
|
+
<link rel="stylesheet" href={cssUrl} />
|
|
91
|
+
<script type="module" dangerouslySetInnerHTML={{ __html: js }} />
|
|
92
|
+
</>
|
|
93
|
+
);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Cacheable Waline comment JSX component.
|
|
99
|
+
* <p>
|
|
100
|
+
* This class is supposed to be used in combination with the <code>locals</code> hexo filter
|
|
101
|
+
* ({@link module:hexo/filter/locals}).
|
|
102
|
+
*
|
|
103
|
+
* @see module:util/cache.cacheComponent
|
|
104
|
+
* @example
|
|
105
|
+
* <Waline.Cacheable
|
|
106
|
+
* comment={{
|
|
107
|
+
* server_url: "https://path/to/waline/server",
|
|
108
|
+
* path: "window.location.pathname",
|
|
109
|
+
* lang: "zh-CN",
|
|
110
|
+
* locale: {placeholder: "", ...},
|
|
111
|
+
* emoji: "https://cdn.jsdelivr.net/gh/walinejs/emojis/weibo",
|
|
112
|
+
* dark: "",
|
|
113
|
+
* meta: ["nick", "mail", "link"],
|
|
114
|
+
* required_meta: [],
|
|
115
|
+
* login: false,
|
|
116
|
+
* word_limit: 0,
|
|
117
|
+
* page_size: 10,
|
|
118
|
+
* image_uploader: true,
|
|
119
|
+
* highlighter: true,
|
|
120
|
+
* tex_renderer: false,
|
|
121
|
+
* search: true,
|
|
122
|
+
* pageview: false,
|
|
123
|
+
* comment: false,
|
|
124
|
+
* copyright: true,
|
|
125
|
+
* }}
|
|
126
|
+
* helper={{ cdn: function() {...} }} />
|
|
127
|
+
*/
|
|
128
|
+
Waline.Cacheable = cacheComponent(Waline, "comment.waline", (props) => {
|
|
129
|
+
const { comment, helper, page, config } = props;
|
|
130
|
+
|
|
131
|
+
return {
|
|
132
|
+
serverURL: comment.server_url,
|
|
133
|
+
path: comment.path,
|
|
134
|
+
lang:
|
|
135
|
+
comment.lang || page.lang || page.language || config.language || "zh-CN",
|
|
136
|
+
locale: comment.locale,
|
|
137
|
+
emoji: comment.emoji,
|
|
138
|
+
dark: comment.dark,
|
|
139
|
+
meta: comment.meta,
|
|
140
|
+
requiredMeta: comment.required_meta,
|
|
141
|
+
login: comment.login,
|
|
142
|
+
wordLimit: comment.word_limit,
|
|
143
|
+
pageSize: comment.page_size,
|
|
144
|
+
imageUploader: comment.image_uploader,
|
|
145
|
+
highlighter: comment.highlighter,
|
|
146
|
+
texRenderer: comment.tex_renderer,
|
|
147
|
+
search: comment.search,
|
|
148
|
+
pageview: comment.pageview,
|
|
149
|
+
comment: comment.comment,
|
|
150
|
+
copyright: comment.copyright,
|
|
151
|
+
jsUrl: helper.cdn("@waline/client", "3.3.0", "dist/waline.js"),
|
|
152
|
+
cssUrl: helper.cdn("@waline/client", "3.3.0", "dist/waline.css"),
|
|
153
|
+
};
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
module.exports = Waline;
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
const { Component, Fragment } = require("../../include/util/common");
|
|
2
|
+
const Comment = require("./comment");
|
|
3
|
+
const ArticleLicensing = require("../misc/article_licensing");
|
|
4
|
+
const ArticleCover = require("./article_cover");
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Get the word count of text.
|
|
8
|
+
*/
|
|
9
|
+
function getWordCount(content) {
|
|
10
|
+
if (typeof content === "undefined") {
|
|
11
|
+
return 0;
|
|
12
|
+
}
|
|
13
|
+
content = content.replace(/<\/?[a-z][^>]*>/gi, "");
|
|
14
|
+
content = content.trim();
|
|
15
|
+
return content
|
|
16
|
+
? (content.match(/[\u00ff-\uffff]|[a-zA-Z]+/g) || []).length
|
|
17
|
+
: 0;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
module.exports = class extends Component {
|
|
21
|
+
render() {
|
|
22
|
+
// index: true if in article list, false if in article page
|
|
23
|
+
const { config, helper, page, index } = this.props;
|
|
24
|
+
|
|
25
|
+
const { article } = config;
|
|
26
|
+
const { url_for, date, _p } = helper;
|
|
27
|
+
|
|
28
|
+
const cover = page.cover ? url_for(page.cover) : null;
|
|
29
|
+
|
|
30
|
+
return (
|
|
31
|
+
<Fragment>
|
|
32
|
+
{/* Main content */}
|
|
33
|
+
<div class="card">
|
|
34
|
+
{/* Cover image */}
|
|
35
|
+
{cover ? (
|
|
36
|
+
<ArticleCover
|
|
37
|
+
page={page}
|
|
38
|
+
cover={cover}
|
|
39
|
+
index={index}
|
|
40
|
+
helper={helper}
|
|
41
|
+
/>
|
|
42
|
+
) : null}
|
|
43
|
+
<article
|
|
44
|
+
class={`card-content article${"direction" in page ? ` ${page.direction}` : ""}`}
|
|
45
|
+
>
|
|
46
|
+
{/* Metadata */}
|
|
47
|
+
{page.layout !== "page" ? (
|
|
48
|
+
<div class="article-meta">
|
|
49
|
+
<p>
|
|
50
|
+
{page.date && <span>{date(page.date)}</span>}
|
|
51
|
+
{page.categories?.length ? (
|
|
52
|
+
<span>
|
|
53
|
+
{page.categories.map((category) => (
|
|
54
|
+
<a href={url_for(category.path)}>/{category.name}</a>
|
|
55
|
+
))}
|
|
56
|
+
</span>
|
|
57
|
+
) : null}
|
|
58
|
+
<span
|
|
59
|
+
dangerouslySetInnerHTML={{
|
|
60
|
+
__html: _p(
|
|
61
|
+
"article.word_count",
|
|
62
|
+
getWordCount(page._content),
|
|
63
|
+
),
|
|
64
|
+
}}
|
|
65
|
+
></span>
|
|
66
|
+
{/* Visitor counter */}
|
|
67
|
+
{!index ? (
|
|
68
|
+
<span
|
|
69
|
+
id={url_for(page.link || page.path)}
|
|
70
|
+
data-flag-title={page.title}
|
|
71
|
+
dangerouslySetInnerHTML={{
|
|
72
|
+
__html: _p(
|
|
73
|
+
"plugin.visit_count",
|
|
74
|
+
'<span id="busuanzi_page_pv" style="padding-right: 0"></span>',
|
|
75
|
+
),
|
|
76
|
+
}}
|
|
77
|
+
></span>
|
|
78
|
+
) : null}
|
|
79
|
+
</p>
|
|
80
|
+
</div>
|
|
81
|
+
) : null}
|
|
82
|
+
{/* Title */}
|
|
83
|
+
{page.title !== "" && index ? (
|
|
84
|
+
<p class="title">
|
|
85
|
+
<a href={url_for(page.link || page.path)}>{page.title}</a>
|
|
86
|
+
</p>
|
|
87
|
+
) : null}
|
|
88
|
+
{page.title !== "" && !index ? (
|
|
89
|
+
<h1 class="title">{page.title}</h1>
|
|
90
|
+
) : null}
|
|
91
|
+
{/* Content/Excerpt */}
|
|
92
|
+
<div
|
|
93
|
+
class="content"
|
|
94
|
+
dangerouslySetInnerHTML={{
|
|
95
|
+
__html: index && page.excerpt ? page.excerpt : page.content,
|
|
96
|
+
}}
|
|
97
|
+
></div>
|
|
98
|
+
{/* Tags */}
|
|
99
|
+
{!index && page.tags && page.tags.length ? (
|
|
100
|
+
<div class="article-tags">
|
|
101
|
+
{page.tags.map((tag) => {
|
|
102
|
+
return (
|
|
103
|
+
<a class="tags" rel="tag" href={url_for(tag.path)}>
|
|
104
|
+
<span class="tag">{tag.name}</span>
|
|
105
|
+
<span class="tag">{tag.length}</span>
|
|
106
|
+
</a>
|
|
107
|
+
);
|
|
108
|
+
})}
|
|
109
|
+
</div>
|
|
110
|
+
) : null}
|
|
111
|
+
{/* Licensing block */}
|
|
112
|
+
{!index &&
|
|
113
|
+
article &&
|
|
114
|
+
article.licenses &&
|
|
115
|
+
Object.keys(article.licenses) ? (
|
|
116
|
+
<ArticleLicensing.Cacheable
|
|
117
|
+
page={page}
|
|
118
|
+
config={config}
|
|
119
|
+
helper={helper}
|
|
120
|
+
/>
|
|
121
|
+
) : null}
|
|
122
|
+
</article>
|
|
123
|
+
</div>
|
|
124
|
+
{/* Comment */}
|
|
125
|
+
{!index ? (
|
|
126
|
+
<Comment config={config} page={page} helper={helper} />
|
|
127
|
+
) : null}
|
|
128
|
+
</Fragment>
|
|
129
|
+
);
|
|
130
|
+
}
|
|
131
|
+
};
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
const { Component } = require("inferno");
|
|
2
|
+
|
|
3
|
+
module.exports = class extends Component {
|
|
4
|
+
render() {
|
|
5
|
+
const { page, cover, helper } = this.props;
|
|
6
|
+
const { url_for } = helper;
|
|
7
|
+
|
|
8
|
+
const imageSrcset = `${cover}?w=256 256w, ${cover}?w=800 800w, ${cover}?w=1500 1500w, ${cover}?w=2000 2000w, ${cover} 6144w`;
|
|
9
|
+
const coverLQIP = (
|
|
10
|
+
<img class="cover-lqip" alt="lqip" src={`${cover}?q=10&blur=25`} />
|
|
11
|
+
);
|
|
12
|
+
const CoverImage = (
|
|
13
|
+
<img
|
|
14
|
+
class="fill"
|
|
15
|
+
src={cover}
|
|
16
|
+
alt={page.title || cover}
|
|
17
|
+
onLoad={"this.classList.add('loaded')"}
|
|
18
|
+
srcset={imageSrcset}
|
|
19
|
+
referrerpolicy="no-referrer"
|
|
20
|
+
decoding="async"
|
|
21
|
+
loading="lazy"
|
|
22
|
+
/>
|
|
23
|
+
);
|
|
24
|
+
return (
|
|
25
|
+
<div class="card-image">
|
|
26
|
+
<a href={url_for(page.link || page.path)} class="image is-7by3">
|
|
27
|
+
{CoverImage}
|
|
28
|
+
{coverLQIP}
|
|
29
|
+
</a>
|
|
30
|
+
</div>
|
|
31
|
+
);
|
|
32
|
+
}
|
|
33
|
+
};
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Article media component, used in article lists such as archive page and recent posts widget
|
|
3
|
+
*/
|
|
4
|
+
const { Component } = require("inferno");
|
|
5
|
+
const moment = require("moment");
|
|
6
|
+
|
|
7
|
+
module.exports = class extends Component {
|
|
8
|
+
render() {
|
|
9
|
+
const { url, title, date, categories } = this.props;
|
|
10
|
+
// Formatted like May.15
|
|
11
|
+
const formattedDate = moment(date).format("MMM.DD");
|
|
12
|
+
const categoryTags = [];
|
|
13
|
+
categories.forEach((category, i) => {
|
|
14
|
+
categoryTags.push(<a href={category.url}>{category.name}</a>);
|
|
15
|
+
if (i < categories.length - 1) {
|
|
16
|
+
categoryTags.push("/");
|
|
17
|
+
}
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
return (
|
|
21
|
+
<article class="archive-item">
|
|
22
|
+
<div>
|
|
23
|
+
<p class="article-meta">
|
|
24
|
+
<span>{formattedDate}</span>
|
|
25
|
+
{categoryTags.length ? <span>{categoryTags}</span> : null}
|
|
26
|
+
</p>
|
|
27
|
+
<p class="title" style="font-size: 1em;">
|
|
28
|
+
<a href={url}>{title}</a>
|
|
29
|
+
</p>
|
|
30
|
+
</div>
|
|
31
|
+
</article>
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
};
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
const {
|
|
2
|
+
Component,
|
|
3
|
+
loadComponent,
|
|
4
|
+
handleWidgetError,
|
|
5
|
+
} = require("../../include/util/common");
|
|
6
|
+
|
|
7
|
+
module.exports = class extends Component {
|
|
8
|
+
render() {
|
|
9
|
+
const { config, page, helper } = this.props;
|
|
10
|
+
const { __ } = helper;
|
|
11
|
+
const { comment } = config;
|
|
12
|
+
if (!comment || typeof comment.type !== "string") {
|
|
13
|
+
return null;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
return (
|
|
17
|
+
<div class="card" id="comments">
|
|
18
|
+
<div class="card-content">
|
|
19
|
+
{(() => {
|
|
20
|
+
const Comment = loadComponent(`comment/${comment.type}`);
|
|
21
|
+
if (!Comment) {
|
|
22
|
+
handleWidgetError(`comment "${comment.type}"`);
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
return (
|
|
26
|
+
<Comment
|
|
27
|
+
config={config}
|
|
28
|
+
page={page}
|
|
29
|
+
helper={helper}
|
|
30
|
+
comment={comment}
|
|
31
|
+
/>
|
|
32
|
+
);
|
|
33
|
+
})()}
|
|
34
|
+
</div>
|
|
35
|
+
</div>
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
};
|
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
const { Component, cacheComponent } = require("../../include/util/common");
|
|
2
|
+
|
|
3
|
+
class Footer extends Component {
|
|
4
|
+
render() {
|
|
5
|
+
const {
|
|
6
|
+
siteTitle,
|
|
7
|
+
siteYear,
|
|
8
|
+
author,
|
|
9
|
+
links,
|
|
10
|
+
subdomains,
|
|
11
|
+
archives,
|
|
12
|
+
copyright,
|
|
13
|
+
showVisitorCounter,
|
|
14
|
+
visitorCounterTitle,
|
|
15
|
+
ICPRecord,
|
|
16
|
+
} = this.props;
|
|
17
|
+
|
|
18
|
+
const svg_line = (
|
|
19
|
+
<svg
|
|
20
|
+
aria-hidden="true"
|
|
21
|
+
width="100%"
|
|
22
|
+
height="8"
|
|
23
|
+
fill="none"
|
|
24
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
25
|
+
>
|
|
26
|
+
<pattern id="a" width="91" height="8" patternUnits="userSpaceOnUse">
|
|
27
|
+
<g clip-path="url(#clip0_2426_11367)">
|
|
28
|
+
<path
|
|
29
|
+
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"
|
|
30
|
+
stroke="var(--lavender)"
|
|
31
|
+
stroke-linecap="square"
|
|
32
|
+
></path>
|
|
33
|
+
</g>
|
|
34
|
+
</pattern>
|
|
35
|
+
<rect width="100%" height="100%" fill="url(#a)"></rect>
|
|
36
|
+
</svg>
|
|
37
|
+
);
|
|
38
|
+
|
|
39
|
+
const footer_brand = (
|
|
40
|
+
<div class="footer-column footer-brand">
|
|
41
|
+
<p class="footer-title">{author || siteTitle}</p>
|
|
42
|
+
<p class="footer-meta">
|
|
43
|
+
<span
|
|
44
|
+
dangerouslySetInnerHTML={{
|
|
45
|
+
__html: `© ${siteYear} ${author || siteTitle}`,
|
|
46
|
+
}}
|
|
47
|
+
></span>
|
|
48
|
+
Powered by Hexo & Icarus
|
|
49
|
+
{showVisitorCounter ? (
|
|
50
|
+
<>
|
|
51
|
+
<br />
|
|
52
|
+
<span
|
|
53
|
+
id="busuanzi_container_site_uv"
|
|
54
|
+
dangerouslySetInnerHTML={{ __html: visitorCounterTitle }}
|
|
55
|
+
></span>
|
|
56
|
+
</>
|
|
57
|
+
) : null}
|
|
58
|
+
{ICPRecord ? (
|
|
59
|
+
<>
|
|
60
|
+
<br />
|
|
61
|
+
<a
|
|
62
|
+
href="https://beian.miit.gov.cn/"
|
|
63
|
+
style={"color: inherit"}
|
|
64
|
+
target="_blank"
|
|
65
|
+
rel="noopener"
|
|
66
|
+
dangerouslySetInnerHTML={{ __html: ICPRecord }}
|
|
67
|
+
></a>
|
|
68
|
+
</>
|
|
69
|
+
) : null}
|
|
70
|
+
</p>
|
|
71
|
+
{copyright ? (
|
|
72
|
+
<p
|
|
73
|
+
class="footer-meta"
|
|
74
|
+
dangerouslySetInnerHTML={{ __html: copyright }}
|
|
75
|
+
></p>
|
|
76
|
+
) : null}
|
|
77
|
+
</div>
|
|
78
|
+
);
|
|
79
|
+
|
|
80
|
+
const footer_social = (
|
|
81
|
+
<div class="footer-column footer-social">
|
|
82
|
+
<p class="footer-heading">Social Media</p>
|
|
83
|
+
<div class="footer-links">
|
|
84
|
+
{Object.keys(links).length
|
|
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
|
+
})
|
|
103
|
+
: null}
|
|
104
|
+
</div>
|
|
105
|
+
</div>
|
|
106
|
+
);
|
|
107
|
+
|
|
108
|
+
const footer_subdomains = (
|
|
109
|
+
<div class="footer-column footer-subdomains">
|
|
110
|
+
<p class="footer-heading">Sub Domains</p>
|
|
111
|
+
<div class="footer-links">
|
|
112
|
+
{Object.keys(subdomains).length
|
|
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
|
+
})
|
|
127
|
+
: null}
|
|
128
|
+
</div>
|
|
129
|
+
</div>
|
|
130
|
+
);
|
|
131
|
+
|
|
132
|
+
const footer_archives = (
|
|
133
|
+
<div class="footer-column footer-archives">
|
|
134
|
+
<p class="footer-heading">Archives</p>
|
|
135
|
+
<div class="footer-links">
|
|
136
|
+
{archives?.length
|
|
137
|
+
? archives.map((item) => (
|
|
138
|
+
<a class="footer-link" href={item.url}>
|
|
139
|
+
{item.year}
|
|
140
|
+
</a>
|
|
141
|
+
))
|
|
142
|
+
: null}
|
|
143
|
+
</div>
|
|
144
|
+
</div>
|
|
145
|
+
);
|
|
146
|
+
|
|
147
|
+
return (
|
|
148
|
+
<>
|
|
149
|
+
{" "}
|
|
150
|
+
{svg_line}
|
|
151
|
+
<footer class="footer">
|
|
152
|
+
<div class="footer-grid">
|
|
153
|
+
{footer_brand}
|
|
154
|
+
{footer_subdomains}
|
|
155
|
+
{footer_archives}
|
|
156
|
+
{footer_social}
|
|
157
|
+
</div>
|
|
158
|
+
</footer>
|
|
159
|
+
</>
|
|
160
|
+
);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
module.exports = cacheComponent(Footer, "common.footer", (props) => {
|
|
165
|
+
const { config, helper, site } = props;
|
|
166
|
+
const { url_for, _p, date } = helper;
|
|
167
|
+
const { title, author, footer, plugins } = config;
|
|
168
|
+
|
|
169
|
+
const links = {};
|
|
170
|
+
if (footer?.links) {
|
|
171
|
+
Object.keys(footer.links).forEach((name) => {
|
|
172
|
+
const link = footer.links[name];
|
|
173
|
+
links[name] = {
|
|
174
|
+
url: url_for(typeof link === "string" ? link : link.url),
|
|
175
|
+
icon: link.icon,
|
|
176
|
+
};
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
const subdomains = {};
|
|
181
|
+
if (footer?.subdomains) {
|
|
182
|
+
Object.keys(footer.subdomains).forEach((name) => {
|
|
183
|
+
const link = footer.subdomains[name];
|
|
184
|
+
const targetUrl = typeof link === "string" ? link : link.url;
|
|
185
|
+
subdomains[name] = {
|
|
186
|
+
url: url_for(targetUrl),
|
|
187
|
+
};
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
// Build archives grouped by year from site posts
|
|
192
|
+
let archives = [];
|
|
193
|
+
if (site?.posts?.length) {
|
|
194
|
+
const archiveDir = config.archive_dir || "archives";
|
|
195
|
+
const byYear = {};
|
|
196
|
+
const posts = site.posts.sort("date", -1);
|
|
197
|
+
|
|
198
|
+
posts.forEach((post) => {
|
|
199
|
+
let d = post.date.clone();
|
|
200
|
+
if (config.timezone) {
|
|
201
|
+
d = d.tz(config.timezone);
|
|
202
|
+
}
|
|
203
|
+
const year = d.year();
|
|
204
|
+
byYear[year] = (byYear[year] || 0) + 1;
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
archives = Object.keys(byYear)
|
|
208
|
+
.sort((a, b) => Number(b) - Number(a))
|
|
209
|
+
.map((year) => ({ year, url: url_for(`${archiveDir}/${year}/`) }));
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
return {
|
|
213
|
+
siteUrl: url_for("/"),
|
|
214
|
+
siteTitle: title,
|
|
215
|
+
siteYear: date(new Date(), "YYYY"),
|
|
216
|
+
author,
|
|
217
|
+
links,
|
|
218
|
+
subdomains,
|
|
219
|
+
archives,
|
|
220
|
+
copyright: footer?.copyright ?? "",
|
|
221
|
+
showVisitorCounter: plugins && plugins.busuanzi === true,
|
|
222
|
+
visitorCounterTitle: _p(
|
|
223
|
+
"plugin.visitor_count",
|
|
224
|
+
'<span id="busuanzi_value_site_uv">0</span>',
|
|
225
|
+
),
|
|
226
|
+
ICPRecord: footer?.ICPRecord || "",
|
|
227
|
+
};
|
|
228
|
+
});
|