hexo-theme-stellar 1.40.0 → 1.41.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/CHANGELOG.md +41 -0
- package/_config.yml +33 -10
- package/_data/icons.yml +250 -37
- package/languages/en.yml +6 -0
- package/languages/zh-CN.yml +6 -0
- package/languages/zh-TW.yml +6 -0
- package/layout/_partial/comments/artalk/script.ejs +25 -8
- package/layout/_partial/comments/beaudar/script.ejs +1 -0
- package/layout/_partial/comments/twikoo/script.ejs +1 -0
- package/layout/_partial/comments/utterances/script.ejs +1 -0
- package/layout/_partial/comments/waline/script.ejs +1 -0
- package/layout/_partial/head.ejs +43 -7
- package/layout/_partial/main/article/article_tags.ejs +16 -0
- package/layout/_partial/main/navbar/article_banner.ejs +11 -1
- package/layout/_partial/main/notebook/note_card.ejs +1 -1
- package/layout/_partial/main/notebook/paginator.ejs +2 -2
- package/layout/_partial/main/pin_slider.ejs +2 -2
- package/layout/_partial/main/post_list/paginator.ejs +2 -2
- package/layout/_partial/menubtn.ejs +2 -2
- package/layout/_partial/scripts/defines.ejs +26 -2
- package/layout/_partial/scripts.ejs +30 -7
- package/layout/_partial/sidebar/logo.ejs +1 -1
- package/layout/_partial/sidebar/menu.ejs +1 -1
- package/layout/_partial/sidebar/search.ejs +1 -1
- package/layout/_partial/widgets/author.ejs +1 -1
- package/layout/_partial/widgets/components/link.ejs +2 -2
- package/layout/_partial/widgets/ghuser.ejs +1 -1
- package/layout/_partial/widgets/related.ejs +1 -1
- package/layout/_partial/widgets/toc.ejs +1 -1
- package/layout/_partial/widgets/tree.ejs +1 -1
- package/layout/_plugins/fancybox.ejs +4 -2
- package/layout/_plugins/mermaid.ejs +2 -1
- package/layout/_plugins/search/local_search.ejs +4 -3
- package/layout/_plugins/swiper.ejs +1 -0
- package/layout/categories.ejs +1 -1
- package/layout/page.ejs +3 -0
- package/layout/tags.ejs +1 -0
- package/package.json +1 -1
- package/scripts/events/lib/doc_tree.js +12 -208
- package/scripts/events/lib/notebooks.js +8 -148
- package/scripts/events/lib/utils.js +10 -1
- package/scripts/filters/index.js +1 -0
- package/scripts/filters/lib/img_lazyload.js +4 -0
- package/scripts/filters/lib/img_onerror.js +4 -0
- package/scripts/filters/lib/md_table.js +46 -0
- package/scripts/generators/search.js +12 -18
- package/scripts/generators/stellar-icons.js +47 -0
- package/scripts/helpers/ai_label.js +29 -0
- package/scripts/helpers/icon.js +2 -2
- package/scripts/helpers/json_ld.js +10 -13
- package/scripts/helpers/related_posts.js +0 -7
- package/scripts/helpers/seo.js +9 -0
- package/scripts/lib/ai_label.js +55 -0
- package/scripts/lib/doc_tree.js +267 -0
- package/scripts/lib/notebooks.js +181 -0
- package/scripts/lib/search_index.js +82 -0
- package/scripts/lib/seo.js +79 -0
- package/scripts/tags/lib/about.js +2 -2
- package/scripts/tags/lib/albums.js +1 -1
- package/scripts/tags/lib/banner.js +1 -1
- package/scripts/tags/lib/chat.js +49 -49
- package/scripts/tags/lib/copy.js +1 -1
- package/scripts/tags/lib/friends.js +1 -1
- package/scripts/tags/lib/gallery.js +1 -1
- package/scripts/tags/lib/hashtag.js +1 -1
- package/scripts/tags/lib/image.js +3 -3
- package/scripts/tags/lib/posters.js +1 -1
- package/scripts/tags/lib/sites.js +2 -2
- package/source/css/_common/base.styl +5 -9
- package/source/css/_common/device.styl +3 -3
- package/source/css/_components/md-table.styl +23 -0
- package/source/css/_components/pages/archives.styl +2 -22
- package/source/css/_components/pages/article-story.styl +4 -4
- package/source/css/_components/partial/article-tags.styl +10 -0
- package/source/css/_components/partial/bread-nav.styl +14 -0
- package/source/css/_components/partial/navbar.styl +10 -2
- package/source/css/_components/sidebar/search.styl +24 -4
- package/source/css/_components/tag-plugins/table.styl +16 -11
- package/source/css/_components/widgets/components.styl +6 -0
- package/source/css/_components/widgets/list.styl +6 -0
- package/source/css/_components/widgets/toc.styl +1 -1
- package/source/css/_custom.styl +1 -12
- package/source/css/_defines/func.styl +28 -3
- package/source/css/_plugins/index.styl +0 -18
- package/source/css/{_plugins/comments → comments}/artalk.styl +4 -0
- package/source/css/{_plugins/comments → comments}/twikoo.styl +4 -0
- package/source/css/{_plugins → plugins}/mermaid.styl +3 -0
- package/source/css/{_plugins → plugins}/swiper.styl +5 -1
- package/source/js/icons.js +60 -0
- package/source/js/main.js +114 -0
- package/source/js/search/highlight.js +82 -0
- package/source/js/search/local-search.js +294 -103
- package/source/js/services/timeline.js +1 -1
- package/source/js/services/weibo.js +3 -3
- package/source/js/services.js +179 -0
- package/source/js/tagtree.js +29 -0
- package/source/js/theme.js +61 -0
- package/{layout/_partial/scripts/utils.ejs → source/js/utils.js} +13 -10
- package/layout/_partial/scripts/services.ejs +0 -178
- package/layout/_partial/scripts/sidebar.ejs +0 -25
- package/layout/_partial/scripts/tagtree.ejs +0 -29
- package/layout/_partial/scripts/theme.ejs +0 -67
- /package/source/css/{_plugins/comments → comments}/beaudar.styl +0 -0
- /package/source/css/{_plugins/comments → comments}/utterances.styl +0 -0
- /package/source/css/{_plugins/comments → comments}/waline.styl +0 -0
- /package/source/css/{_plugins → plugins}/fancybox.styl +0 -0
package/languages/en.yml
CHANGED
|
@@ -39,6 +39,11 @@ meta:
|
|
|
39
39
|
contributors: Page Contributors
|
|
40
40
|
word_count: '%s words'
|
|
41
41
|
reading_time: '%s min read'
|
|
42
|
+
ai_label:
|
|
43
|
+
manual: Written entirely by a human
|
|
44
|
+
reviewed: AI-reviewed
|
|
45
|
+
polished: AI-polished
|
|
46
|
+
generated: AI-generated
|
|
42
47
|
date_suffix:
|
|
43
48
|
just: Just
|
|
44
49
|
min: minutes ago
|
|
@@ -70,6 +75,7 @@ symbol:
|
|
|
70
75
|
colon: ": "
|
|
71
76
|
brackets_l: "("
|
|
72
77
|
brackets_r: ")"
|
|
78
|
+
page: "Page %s"
|
|
73
79
|
|
|
74
80
|
tag_plugins:
|
|
75
81
|
mbti:
|
package/languages/zh-CN.yml
CHANGED
|
@@ -39,6 +39,11 @@ meta:
|
|
|
39
39
|
contributors: 本文贡献者
|
|
40
40
|
word_count: '%s 字'
|
|
41
41
|
reading_time: '预计阅读 %s 分钟'
|
|
42
|
+
ai_label:
|
|
43
|
+
manual: 本文完全由人类完成
|
|
44
|
+
reviewed: 已 AI 审核
|
|
45
|
+
polished: 已 AI 润色
|
|
46
|
+
generated: 由 AI 生成
|
|
42
47
|
date_suffix:
|
|
43
48
|
just: 刚刚
|
|
44
49
|
min: 分钟前
|
|
@@ -70,6 +75,7 @@ symbol:
|
|
|
70
75
|
colon: ":"
|
|
71
76
|
brackets_l: "("
|
|
72
77
|
brackets_r: ")"
|
|
78
|
+
page: "第 %s 页"
|
|
73
79
|
|
|
74
80
|
tag_plugins:
|
|
75
81
|
mbti:
|
package/languages/zh-TW.yml
CHANGED
|
@@ -39,6 +39,11 @@ meta:
|
|
|
39
39
|
contributors: 本文貢獻者
|
|
40
40
|
word_count: '%s 字'
|
|
41
41
|
reading_time: '預計閱讀 %s 分鐘'
|
|
42
|
+
ai_label:
|
|
43
|
+
manual: 本文完全由人類完成
|
|
44
|
+
reviewed: 已 AI 審核
|
|
45
|
+
polished: 已 AI 潤飾
|
|
46
|
+
generated: 由 AI 生成
|
|
42
47
|
date_suffix:
|
|
43
48
|
just: 剛剛
|
|
44
49
|
min: 分鐘前
|
|
@@ -70,6 +75,7 @@ symbol:
|
|
|
70
75
|
colon: ":"
|
|
71
76
|
brackets_l: "("
|
|
72
77
|
brackets_r: ")"
|
|
78
|
+
page: "第 %s 頁"
|
|
73
79
|
|
|
74
80
|
tag_plugins:
|
|
75
81
|
mbti:
|
|
@@ -4,8 +4,13 @@
|
|
|
4
4
|
function initArtalk() {
|
|
5
5
|
const el = document.getElementById('artalk_container');
|
|
6
6
|
if (!el) return;
|
|
7
|
+
|
|
8
|
+
// artalk 邮件通知链接携带 ?atk_comment=<id> / #atk-comment-<id> 定位目标,
|
|
9
|
+
// 命中时跳过视口懒加载立即初始化,让 Artalk 自身的 list-goto 逻辑完成定位。
|
|
10
|
+
const hasAtkTarget = /[?&]atk_comment=\d+/.test(window.location.search) || /#atk-comment-\d+/.test(window.location.hash);
|
|
7
11
|
|
|
8
12
|
function load_artalk() {
|
|
13
|
+
utils.css('<%- url_for('/css/comments/artalk.css') %>?v=<%- stellar_info('version') %>');
|
|
9
14
|
utils.css('<%- theme.comments.artalk.css %>');
|
|
10
15
|
utils.js('<%- theme.comments.artalk.js %>', {defer: true}).then(function () {
|
|
11
16
|
// 监听 Artalk 事件
|
|
@@ -13,6 +18,17 @@
|
|
|
13
18
|
// Artalk.use((ctx) => {
|
|
14
19
|
// ctx.on('list-loaded', () => window.lazyLoadInstance?.update())
|
|
15
20
|
// })
|
|
21
|
+
// 邮件通知链接以 ?atk_comment=<id> 定位,Artalk 在 list-loaded 时才重新读取 URL,
|
|
22
|
+
// 固定延时清理会与之竞态(#598)。先把评论 id 改写到 hash(Artalk 读取优先级高于 query),
|
|
23
|
+
// 同时立即移除 atk_comment 查询参数,避免其 hash 监听干扰目录定位;
|
|
24
|
+
// atk_notify_key 保留到 list-loaded 完成定位与已读回执后再清理。
|
|
25
|
+
const atkComment = window.location.search.match(/[?&]atk_comment=(\d+)/);
|
|
26
|
+
if (atkComment && !/#atk-comment-\d+/.test(window.location.hash)) {
|
|
27
|
+
const params = new URLSearchParams(window.location.search);
|
|
28
|
+
const notifyKey = params.get('atk_notify_key');
|
|
29
|
+
const query = notifyKey ? '?atk_notify_key=' + encodeURIComponent(notifyKey) : '';
|
|
30
|
+
window.history.replaceState(null, '', window.location.pathname + query + '#atk-comment-' + atkComment[1]);
|
|
31
|
+
}
|
|
16
32
|
const path = el.getAttribute('comment_id') ?? decodeURI(window.location.pathname);
|
|
17
33
|
const artalk = Artalk.init({
|
|
18
34
|
el: '#artalk_container',
|
|
@@ -39,18 +55,19 @@
|
|
|
39
55
|
},
|
|
40
56
|
<% } %>
|
|
41
57
|
});
|
|
42
|
-
//
|
|
43
|
-
//
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
58
|
+
// list-loaded 时 Artalk 已读取 atk_comment / atk_notify_key 并触发定位与已读回执,
|
|
59
|
+
// 此时再清理残留的 ?atk_* 参数,避免固定延时与异步加载竞态(#598)。
|
|
60
|
+
if (hasAtkTarget && window.location.search.indexOf('atk_') !== -1) {
|
|
61
|
+
artalk.on('list-loaded', function () {
|
|
62
|
+
window.setTimeout(function () {
|
|
63
|
+
window.history.replaceState(null, '', window.location.pathname + window.location.hash);
|
|
64
|
+
}, 0);
|
|
65
|
+
});
|
|
49
66
|
}
|
|
50
67
|
});
|
|
51
68
|
}
|
|
52
69
|
|
|
53
|
-
util.viewportLazyload(el, load_artalk);
|
|
70
|
+
util.viewportLazyload(el, load_artalk, !hasAtkTarget);
|
|
54
71
|
}
|
|
55
72
|
|
|
56
73
|
// Initialize on page load
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
if (!el) return;
|
|
7
7
|
|
|
8
8
|
function load_twikoo() {
|
|
9
|
+
utils.css('<%- url_for('/css/comments/twikoo.css') %>?v=<%- stellar_info('version') %>');
|
|
9
10
|
utils.js('<%- theme.comments.twikoo.js %>', {defer: true}).then(function () {
|
|
10
11
|
const path = el.getAttribute('comment_id') ?? decodeURI(window.location.pathname);
|
|
11
12
|
twikoo.init(Object.assign(<%- JSON.stringify(theme.comments.twikoo) %>, {
|
package/layout/_partial/head.ejs
CHANGED
|
@@ -1,13 +1,28 @@
|
|
|
1
1
|
<%
|
|
2
|
+
function strip_wiki_title(title, wiki) {
|
|
3
|
+
if (!wiki) { return title; }
|
|
4
|
+
var t = String(title || '');
|
|
5
|
+
if (t.toLowerCase() === String(wiki).toLowerCase()) { return ''; }
|
|
6
|
+
// wiki 名中的空格/连字符在标题中可能写为另一种形态(如 cloud shell / cloud-shell)
|
|
7
|
+
var flex = String(wiki).replace(/[.*+?^${}()|[\]\\]/g, '\\$&').replace(/[\s-]+/g, '[\\s-]*');
|
|
8
|
+
var m = t.match(new RegExp('^' + flex + '[\\s-]*[::\\-](.*)$', 'i'));
|
|
9
|
+
if (m && m[1]) {
|
|
10
|
+
return m[1].trim();
|
|
11
|
+
}
|
|
12
|
+
return t;
|
|
13
|
+
}
|
|
14
|
+
|
|
2
15
|
function generate_title() {
|
|
3
16
|
if (page.wiki) {
|
|
4
17
|
const proj = theme.wiki.tree[page.wiki]
|
|
5
18
|
const wiki = proj?.name || page.wiki
|
|
6
19
|
if (page.title) {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
20
|
+
var stripped = strip_wiki_title(page.title, wiki)
|
|
21
|
+
if (stripped) {
|
|
22
|
+
return wiki + __('symbol.colon') + stripped + ' - ' + config.title;
|
|
23
|
+
}
|
|
10
24
|
}
|
|
25
|
+
return wiki + ' - ' + config.title;
|
|
11
26
|
} else {
|
|
12
27
|
if (page.title) {
|
|
13
28
|
return page.title + ' - ' + config.title;
|
|
@@ -17,6 +32,9 @@ function generate_title() {
|
|
|
17
32
|
return __('btn.tag') + __('symbol.colon') + page.tag + ' - ' + config.title;
|
|
18
33
|
}
|
|
19
34
|
}
|
|
35
|
+
if (is_home() && page.current && page.current > 1) {
|
|
36
|
+
return config.title + ' - ' + __('symbol.page', page.current);
|
|
37
|
+
}
|
|
20
38
|
return config.title;
|
|
21
39
|
}
|
|
22
40
|
function generate_description() {
|
|
@@ -75,7 +93,7 @@ function og_args() {
|
|
|
75
93
|
args.description = proj.description;
|
|
76
94
|
}
|
|
77
95
|
}
|
|
78
|
-
args.image = config.avatar || (config.email ? gravatar(config.email) : null);
|
|
96
|
+
args.image = page.cover || page.banner || first_content_image(page.content) || config.avatar || (config.email ? gravatar(config.email) : null);
|
|
79
97
|
return Object.assign(args, page.open_graph);
|
|
80
98
|
}
|
|
81
99
|
|
|
@@ -92,9 +110,6 @@ function generate_og_title() {
|
|
|
92
110
|
}
|
|
93
111
|
|
|
94
112
|
function generate_og_site_name() {
|
|
95
|
-
if (page.layout === 'post' && page.title) {
|
|
96
|
-
return generate_og_title();
|
|
97
|
-
}
|
|
98
113
|
return escape_meta_content(strip_html(config.title));
|
|
99
114
|
}
|
|
100
115
|
|
|
@@ -207,4 +222,25 @@ function generate_canonical() {
|
|
|
207
222
|
|
|
208
223
|
<%- json_ld() %>
|
|
209
224
|
<%- custom_inject() %>
|
|
225
|
+
|
|
226
|
+
<!-- icons.yml 驱动的 CSS 装饰图标 -->
|
|
227
|
+
<%
|
|
228
|
+
const iconCssVars = (() => {
|
|
229
|
+
const map = {
|
|
230
|
+
'--icon-h3-left': 'default:arrow-left',
|
|
231
|
+
'--icon-h3-right': 'default:arrow-right',
|
|
232
|
+
'--icon-quote-left': 'quot:quote-left',
|
|
233
|
+
'--icon-quote-right': 'quot:quote-right'
|
|
234
|
+
};
|
|
235
|
+
let vars = [];
|
|
236
|
+
for (const [name, key] of Object.entries(map)) {
|
|
237
|
+
const raw = theme.icons && theme.icons[key];
|
|
238
|
+
if (raw) vars.push(` ${name}: url("data:image/svg+xml,${encodeURIComponent(raw)}");`);
|
|
239
|
+
}
|
|
240
|
+
return vars.length > 0 ? `:root {\n${vars.join('\n')}\n}` : '';
|
|
241
|
+
})();
|
|
242
|
+
%>
|
|
243
|
+
<% if (iconCssVars) { %>
|
|
244
|
+
<style><%- iconCssVars %></style>
|
|
245
|
+
<% } %>
|
|
210
246
|
</head>
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
<%# 文章标签行(layout: post,位于 article-footer 之前) %>
|
|
2
|
+
<%
|
|
3
|
+
function layoutDiv() {
|
|
4
|
+
var el = '';
|
|
5
|
+
if (!page.tags || page.tags.length === 0) {
|
|
6
|
+
return el;
|
|
7
|
+
}
|
|
8
|
+
el += `<div class="article-tags${scrollreveal(' ')}">`
|
|
9
|
+
page.tags.forEach((tag, i) => {
|
|
10
|
+
el += `<a class="tag" href="${pretty_url(tag.path)}">${icon('default:hashtag')}${escape_html(tag.name)}</a>`
|
|
11
|
+
})
|
|
12
|
+
el += '</div>'
|
|
13
|
+
return el;
|
|
14
|
+
}
|
|
15
|
+
%>
|
|
16
|
+
<%- layoutDiv(); %>
|
|
@@ -42,12 +42,22 @@ function layoutBreadcrumb() {
|
|
|
42
42
|
el += partial('breadcrumb/page')
|
|
43
43
|
}
|
|
44
44
|
// 字数和预计阅读时长,置于面包屑行右侧(#302)
|
|
45
|
+
var readingHtml = ''
|
|
45
46
|
if (page.layout == 'post' && theme.article.reading_time) {
|
|
46
47
|
var _wc = word_count(page)
|
|
47
48
|
if (_wc > 0) {
|
|
48
|
-
|
|
49
|
+
readingHtml = `<span class="cap reading right">${__("meta.word_count", _wc)} · ${__("meta.reading_time", reading_time(page))}</span>`
|
|
49
50
|
}
|
|
50
51
|
}
|
|
52
|
+
el += readingHtml
|
|
53
|
+
// AI 成分标签:置于面包屑行最右(阅读时长右侧);
|
|
54
|
+
// banner 含图片时不用配置色,继承默认文字色(--text-banner)
|
|
55
|
+
const bannerHasImage = banner.url && banner.url.length > 0
|
|
56
|
+
if (readingHtml.length > 0) {
|
|
57
|
+
el += ai_label(page.ai_label, 'cap', bannerHasImage)
|
|
58
|
+
} else {
|
|
59
|
+
el += ai_label(page.ai_label, 'cap right', bannerHasImage)
|
|
60
|
+
}
|
|
51
61
|
// end 3.left.top
|
|
52
62
|
el += `</div>`
|
|
53
63
|
// 3.left.bottom
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
<% if ((page.total || 0) > 1) { %>
|
|
2
2
|
<div class="paginator-wrap dis-select<%= scrollreveal(' ') %>">
|
|
3
3
|
<%- paginator({
|
|
4
|
-
prev_text: icon('
|
|
5
|
-
next_text: icon('
|
|
4
|
+
prev_text: icon('default:arrow-left'),
|
|
5
|
+
next_text: icon('default:arrow-right'),
|
|
6
6
|
force_prev_next: true,
|
|
7
7
|
escape: false,
|
|
8
8
|
}) %>
|
|
@@ -137,8 +137,8 @@ if (pinItems.length > 0) {
|
|
|
137
137
|
el += '</div>'
|
|
138
138
|
if (dotsHtml.length > 0) {
|
|
139
139
|
el += '<div class="pin-slider-dots">' + dotsHtml + '</div>'
|
|
140
|
-
el += '<button type="button" class="pin-slider-nav prev">' + icon('
|
|
141
|
-
el += '<button type="button" class="pin-slider-nav next">' + icon('
|
|
140
|
+
el += '<button type="button" class="pin-slider-nav prev">' + icon('default:arrow-left') + '</button>'
|
|
141
|
+
el += '<button type="button" class="pin-slider-nav next">' + icon('default:arrow-right') + '</button>'
|
|
142
142
|
}
|
|
143
143
|
el += '</div>'
|
|
144
144
|
%>
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
<% if ((is_home() || is_category() || is_tag()) && page.total > 1) { %>
|
|
2
2
|
<div class='paginator-wrap dis-select<%- scrollreveal(' ') %>'>
|
|
3
3
|
<%- paginator({
|
|
4
|
-
prev_text: icon('
|
|
5
|
-
next_text: icon('
|
|
4
|
+
prev_text: icon('default:arrow-left'),
|
|
5
|
+
next_text: icon('default:arrow-right'),
|
|
6
6
|
force_prev_next: true,
|
|
7
7
|
escape: false
|
|
8
8
|
}) %>
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
<div class='float-panel'>
|
|
2
2
|
<button type='button' style='display:none' class='laptop-only rightbar-toggle mobile' onclick='sidebar.rightbar()'>
|
|
3
|
-
<%- icon('default:rightbar') %>
|
|
3
|
+
<%- icon('default:rightbar', '', true) %>
|
|
4
4
|
</button>
|
|
5
5
|
<button type='button' style='display:none' class='mobile-only leftbar-toggle mobile' onclick='sidebar.leftbar()'>
|
|
6
|
-
<%- icon('default:leftbar') %>
|
|
6
|
+
<%- icon('default:leftbar', '', true) %>
|
|
7
7
|
</button>
|
|
8
8
|
</div>
|
|
@@ -156,7 +156,10 @@
|
|
|
156
156
|
root : `<%- config.root %>`,
|
|
157
157
|
tag_plugins: {
|
|
158
158
|
chat: Object.assign(<%- JSON.stringify(theme.tag_plugins.chat) %>),
|
|
159
|
-
}
|
|
159
|
+
},
|
|
160
|
+
// 图标由构建期生成的 /js/stellar-icons.js 填充(defer,早于 DOMContentLoaded 就绪)
|
|
161
|
+
icons: {},
|
|
162
|
+
services: <%- JSON.stringify(theme.data_services || {}) %>,
|
|
160
163
|
};
|
|
161
164
|
|
|
162
165
|
// required plugins (only load if needs)
|
|
@@ -171,11 +174,32 @@
|
|
|
171
174
|
const def = {
|
|
172
175
|
avatar: `<%- theme.default.avatar %>`,
|
|
173
176
|
cover: `<%- theme.default.cover %>`,
|
|
174
|
-
loading: `<%- theme.default.loading %>`,
|
|
177
|
+
loading: `<%- theme.default.loading || (theme.icons && theme.icons['default:loading-placeholder']) %>`,
|
|
175
178
|
data_cache: <%- JSON.stringify(theme.data_cache || {}) %>,
|
|
176
179
|
};
|
|
177
180
|
const deps = {
|
|
178
181
|
marked: `<%- url_for(theme.dependencies.marked) %>`,
|
|
179
182
|
lazyload: `<%- url_for(theme.dependencies.lazyload.js) %>`
|
|
180
183
|
}
|
|
184
|
+
|
|
185
|
+
// 主题切换提示文案(供 /js/theme.js 使用)
|
|
186
|
+
window.__STELLAR_I18N__ = {
|
|
187
|
+
light: `<%- __('message.theme_switched.light') %>`,
|
|
188
|
+
dark: `<%- __('message.theme_switched.dark') %>`,
|
|
189
|
+
auto: `<%- __('message.theme_switched.auto') %>`,
|
|
190
|
+
};
|
|
191
|
+
|
|
192
|
+
// 搜索跳转高亮:URL 带 ?kw= 时按需加载,定位正文中的匹配词
|
|
193
|
+
(function () {
|
|
194
|
+
try {
|
|
195
|
+
if (!window.location.search) return;
|
|
196
|
+
if (!new URLSearchParams(window.location.search).has('kw')) return;
|
|
197
|
+
document.addEventListener('DOMContentLoaded', function () {
|
|
198
|
+
// utils 为全局词法绑定(顶层 const),不能通过 window.utils 访问
|
|
199
|
+
if (typeof utils === 'object' && typeof utils.js === 'function') {
|
|
200
|
+
utils.js('<%- url_for('/js/search/highlight.js') %>', { defer: true }).catch(function () {});
|
|
201
|
+
}
|
|
202
|
+
});
|
|
203
|
+
} catch (e) {}
|
|
204
|
+
})();
|
|
181
205
|
</script>
|
|
@@ -14,22 +14,45 @@ function custom_inject() {
|
|
|
14
14
|
return el;
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
+
// tagtree 脚本仅在与 tagtree 小部件渲染相同的条件下加载(见 _partial/sidebar/index_leftbar.ejs)
|
|
18
|
+
function tagtreeWidgetOnPage() {
|
|
19
|
+
const leftbar = page && page.leftbar;
|
|
20
|
+
if (!Array.isArray(leftbar)) {
|
|
21
|
+
return false;
|
|
22
|
+
}
|
|
23
|
+
return leftbar.some(function (w) {
|
|
24
|
+
if (typeof w === 'string') {
|
|
25
|
+
return w === 'tagtree';
|
|
26
|
+
}
|
|
27
|
+
if (w && typeof w === 'object') {
|
|
28
|
+
return w.override === 'tagtree' || w.layout === 'tagtree';
|
|
29
|
+
}
|
|
30
|
+
return false;
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
|
|
17
34
|
%>
|
|
18
35
|
<%- partial('scripts/defines') %>
|
|
19
|
-
<%- partial('scripts/utils') %>
|
|
20
|
-
<%- partial('scripts/sidebar') %>
|
|
21
|
-
<%- partial('scripts/tagtree') %>
|
|
22
|
-
<%- partial('scripts/lazyload') %>
|
|
23
36
|
|
|
24
|
-
<!--
|
|
37
|
+
<!-- core: utils 必须同步加载(页尾内联插件片段在解析期即调用 utils.initPlugin) -->
|
|
38
|
+
<script src="<%- url_for('/js/utils.js') %>?v=<%- stellar_info('version') %>"></script>
|
|
39
|
+
<script defer src="<%- url_for('/js/stellar-icons.js') %>?v=<%- stellar_info('version') %>"></script>
|
|
40
|
+
<!-- 非首屏图标异步加载:占位符替换依赖构建期生成的 js/icons/{ns}.json -->
|
|
41
|
+
<script defer src="<%- url_for('/js/icons.js') %>?v=<%- stellar_info('version') %>" data-version="<%- stellar_info('version') %>"></script>
|
|
25
42
|
<script src="<%- url_for(`${theme.stellar.main_js}?v=${stellar_info('version')}`) %>" defer></script>
|
|
43
|
+
<script defer src="<%- url_for('/js/theme.js') %>?v=<%- stellar_info('version') %>"></script>
|
|
44
|
+
|
|
45
|
+
<% if (tagtreeWidgetOnPage()) { %>
|
|
46
|
+
<script>window.__STELLAR_TAGTREE__ = { expand_active: <%- JSON.stringify(!!(theme.widgets.tagtree && theme.widgets.tagtree.expand_active)) %> };</script>
|
|
47
|
+
<script defer src="<%- url_for('/js/tagtree.js') %>?v=<%- stellar_info('version') %>"></script>
|
|
48
|
+
<% } %>
|
|
26
49
|
|
|
27
|
-
<%- partial('scripts/
|
|
50
|
+
<%- partial('scripts/lazyload') %>
|
|
28
51
|
|
|
29
52
|
<!-- optional -->
|
|
30
53
|
<%- partial('comments/script') %>
|
|
31
54
|
|
|
32
|
-
<%-
|
|
55
|
+
<script defer src="<%- url_for('/js/services.js') %>?v=<%- stellar_info('version') %>"></script>
|
|
33
56
|
<%- partial('../_plugins/index') %>
|
|
34
57
|
|
|
35
58
|
<!-- inject -->
|
|
@@ -50,7 +50,7 @@ function layoutBack() {
|
|
|
50
50
|
var el = ''
|
|
51
51
|
el += `<div class="wiki-home-wrap">`
|
|
52
52
|
el += `<a class="wiki-home cap" href="${pretty_url(theme.site_tree.index_wiki.base_dir)}">`
|
|
53
|
-
el += icon('default:goback')
|
|
53
|
+
el += icon('default:goback', '', true)
|
|
54
54
|
el += `<span>${__('btn.all_wiki')}</span>`
|
|
55
55
|
el += `</a>`
|
|
56
56
|
el += `</div>`
|
|
@@ -15,7 +15,7 @@ function layoutDiv() {
|
|
|
15
15
|
el += ` style="${style}"`
|
|
16
16
|
el += ` title="${item.title}" href="${pretty_url(item.url)}">`
|
|
17
17
|
if (item.icon?.length > 0) {
|
|
18
|
-
el += icon(item.icon, 'no-lazy')
|
|
18
|
+
el += icon(item.icon, 'no-lazy', true)
|
|
19
19
|
}
|
|
20
20
|
el += `<span>${__(item.title)}</span>`
|
|
21
21
|
if (active) {
|
|
@@ -32,7 +32,7 @@ function layoutDiv() {
|
|
|
32
32
|
}
|
|
33
33
|
}
|
|
34
34
|
el += `<a class="search-button" onclick="document.getElementById("search-input").focus();">`
|
|
35
|
-
el += icon('default:search')
|
|
35
|
+
el += icon('default:search', '', true)
|
|
36
36
|
el += `</a>`
|
|
37
37
|
el += `<input type="text" class="search-input" id="search-input"`
|
|
38
38
|
if (filter.length > 0) {
|
|
@@ -12,10 +12,10 @@ function layoutDiv() {
|
|
|
12
12
|
}
|
|
13
13
|
el += `</div>`
|
|
14
14
|
if (columns == 1 && isActive) {
|
|
15
|
-
el +=
|
|
15
|
+
el += '<span class="active-dot"></span>'
|
|
16
16
|
}
|
|
17
17
|
el += `</a>`
|
|
18
18
|
return el
|
|
19
19
|
}
|
|
20
20
|
%>
|
|
21
|
-
<%- layoutDiv() %>
|
|
21
|
+
<%- layoutDiv() %>
|
|
@@ -30,7 +30,7 @@ function layoutDiv() {
|
|
|
30
30
|
if (item.header) {
|
|
31
31
|
el += `<div class="widget-header">`
|
|
32
32
|
el += `<a class="gh-url" href="https://github.com/${item.username}">
|
|
33
|
-
|
|
33
|
+
${icon('github:logo-alt')}
|
|
34
34
|
<span>github/${item.username}</span>
|
|
35
35
|
</a>`
|
|
36
36
|
el += `</div>`
|
|
@@ -18,7 +18,7 @@ function relatedPostsInTopic() {
|
|
|
18
18
|
el += `<a class="item${isActive ? ' active' : ''}" href="${pretty_url(post.path)}">`
|
|
19
19
|
el += `<span class="title">${post.title}</span>`
|
|
20
20
|
if (isActive) {
|
|
21
|
-
el +=
|
|
21
|
+
el += '<span class="active-dot"></span>'
|
|
22
22
|
}
|
|
23
23
|
el += `</a>`
|
|
24
24
|
}
|
|
@@ -15,7 +15,7 @@ function layoutTocHeader(title) {
|
|
|
15
15
|
var el = ''
|
|
16
16
|
el += `<div class="widget-header dis-select">`
|
|
17
17
|
el += `<span class="name">${title || __("meta.toc")}</span>`
|
|
18
|
-
el += `<a class="cap-action" onclick="sidebar.toggleTOC()" >${icon('default:rightbar')}</a>`
|
|
18
|
+
el += `<a class="cap-action" onclick="sidebar.toggleTOC()" >${icon('default:rightbar', '', true)}</a>`
|
|
19
19
|
el += `</div>`
|
|
20
20
|
return el
|
|
21
21
|
}
|
|
@@ -27,7 +27,7 @@ function layoutDocTree(pages) {
|
|
|
27
27
|
el += `<a class="link${isActive}" href="${href}">`
|
|
28
28
|
el += `<span class="toc-text">${p.title}</span>`
|
|
29
29
|
if (isActive.length > 0) {
|
|
30
|
-
el +=
|
|
30
|
+
el += '<span class="active-dot"></span>'
|
|
31
31
|
}
|
|
32
32
|
el += `</a>`
|
|
33
33
|
}
|
|
@@ -7,8 +7,9 @@
|
|
|
7
7
|
};
|
|
8
8
|
// auto=按需:页面存在可弹窗图片才加载;global=全局:所有页面加载
|
|
9
9
|
const isGlobal = ctx.fancybox.mode === 'global';
|
|
10
|
-
// 评论区图片(artalk/twikoo/waline
|
|
11
|
-
|
|
10
|
+
// 评论区图片(artalk/twikoo/waline)显示较小,自动支持放大;
|
|
11
|
+
// 仅绑定各评论服务的评论内容区,编辑器、表情面板等非内容区图片不弹窗
|
|
12
|
+
var selector = '[data-fancybox]:not(.error), .with-fancybox .atk-content img:not([atk-emoticon]):not([class*="emo"]), .with-fancybox .tk-content img:not([atk-emoticon]):not([class*="emo"]), .with-fancybox .wl-content img:not([atk-emoticon]):not([class*="emo"])';
|
|
12
13
|
if (ctx.fancybox.selector) {
|
|
13
14
|
selector += `, ${ctx.fancybox.selector}`
|
|
14
15
|
}
|
|
@@ -31,6 +32,7 @@
|
|
|
31
32
|
}
|
|
32
33
|
}
|
|
33
34
|
if (needFancybox) {
|
|
35
|
+
utils.css(`<%- url_for('/css/plugins/fancybox.css') %>?v=<%- stellar_info('version') %>`);
|
|
34
36
|
utils.css(ctx.fancybox.css);
|
|
35
37
|
utils.js(ctx.fancybox.js, { defer: true }).then(function () {
|
|
36
38
|
if (isGlobal) {
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
utils.initPlugin(() => {
|
|
4
4
|
const els = document.querySelectorAll('.mermaid');
|
|
5
5
|
if (els.length > 0) {
|
|
6
|
+
utils.css(`<%- url_for('/css/plugins/mermaid.css') %>?v=<%- stellar_info('version') %>`);
|
|
6
7
|
const mermaid_config = {
|
|
7
8
|
startOnLoad: false,
|
|
8
9
|
theme:
|
|
@@ -30,4 +31,4 @@
|
|
|
30
31
|
mermaid.run();
|
|
31
32
|
}
|
|
32
33
|
}, 'mermaid');
|
|
33
|
-
</script>
|
|
34
|
+
</script>
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
<script>
|
|
2
2
|
window.addEventListener('DOMContentLoaded', (event) => {
|
|
3
|
-
ctx.search = {
|
|
3
|
+
ctx.search = Object.assign({}, ctx.search, {
|
|
4
4
|
path: `<%- conf.path || '/search.json' %>`,
|
|
5
|
-
|
|
5
|
+
local_search: <%- JSON.stringify(conf) %>,
|
|
6
|
+
});
|
|
6
7
|
utils.js('/js/search/local-search.js', { defer: true });
|
|
7
8
|
});
|
|
8
|
-
</script>
|
|
9
|
+
</script>
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
utils.initPlugin(() => {
|
|
3
3
|
const swiper_api = document.getElementById('swiper-api');
|
|
4
4
|
if (swiper_api != undefined) {
|
|
5
|
+
utils.css(`<%- url_for('/css/plugins/swiper.css') %>?v=<%- stellar_info('version') %>`);
|
|
5
6
|
utils.css(`<%- conf.css %>`);
|
|
6
7
|
utils.js(`<%- conf.js %>`, { defer: true }).then(function () {
|
|
7
8
|
const effect = swiper_api.getAttribute('effect') || '';
|
package/layout/categories.ejs
CHANGED
|
@@ -16,7 +16,7 @@ if (page.menu_id == undefined) {
|
|
|
16
16
|
nodes.forEach(function(node) {
|
|
17
17
|
el += `<div class="cat-item">`
|
|
18
18
|
el += `<a class="cat${node.parentId ? ' child' : ''}" href="${pretty_url(node.path)}">`
|
|
19
|
-
el += `<span class="name">${icon('default:category')}${escape_html(node.name)}</span>`
|
|
19
|
+
el += `<span class="name">${icon(node.children && node.children.length > 0 ? 'default:category-open' : 'default:category')}${escape_html(node.name)}</span>`
|
|
20
20
|
el += `<span class="badge">(${node.count})</span>`
|
|
21
21
|
el += `</a>`
|
|
22
22
|
if (node.children && node.children.length > 0) {
|
package/layout/page.ejs
CHANGED
|
@@ -56,6 +56,9 @@ function layoutDiv() {
|
|
|
56
56
|
}
|
|
57
57
|
el += `</article>`
|
|
58
58
|
if (layout === 'post' || page.wiki || notebook) {
|
|
59
|
+
if (layout === 'post' && theme.article.tags) {
|
|
60
|
+
el += partial('_partial/main/article/article_tags')
|
|
61
|
+
}
|
|
59
62
|
el += partial('_partial/main/article/article_footer')
|
|
60
63
|
}
|
|
61
64
|
if (layout === 'post' || page.wiki) {
|
package/layout/tags.ejs
CHANGED
|
@@ -12,6 +12,7 @@ if (page.menu_id == undefined) {
|
|
|
12
12
|
<article class='<%- scrollreveal("") %>' id='tags'>
|
|
13
13
|
<% site.tags.sort('length', -1).each(function(tag){ %>
|
|
14
14
|
<a class='tag' href="<%= pretty_url(tag.path) %>">
|
|
15
|
+
<%- icon('default:hashtag') %>
|
|
15
16
|
<span class='name'><%= tag.name %></span>
|
|
16
17
|
</a>
|
|
17
18
|
<% }) %>
|