hexo-theme-stellar 1.32.3 → 1.33.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/_config.yml +27 -7
- package/_data/icons.yml +9 -2
- package/languages/en.yml +1 -0
- package/languages/zh-CN.yml +1 -0
- package/languages/zh-TW.yml +1 -0
- package/layout/_partial/comments/artalk/script.ejs +8 -7
- package/layout/_partial/head.ejs +7 -5
- package/layout/_partial/main/article/article_footer.ejs +8 -0
- package/layout/_partial/main/article/contributors.ejs +34 -0
- package/layout/_partial/main/article/read_next.ejs +2 -2
- package/layout/_partial/main/navbar/article_banner.ejs +1 -1
- package/layout/_partial/main/navbar/breadcrumb/blog.ejs +3 -3
- package/layout/_partial/main/navbar/breadcrumb/note.ejs +2 -2
- package/layout/_partial/main/navbar/breadcrumb/page.ejs +1 -1
- package/layout/_partial/main/navbar/breadcrumb/wiki.ejs +2 -2
- package/layout/_partial/main/navbar/dateinfo.ejs +1 -1
- package/layout/_partial/main/navbar/ghinfo.ejs +1 -1
- package/layout/_partial/main/navbar/nav_tabs_blog.ejs +12 -12
- package/layout/_partial/main/navbar/nav_tabs_wiki.ejs +2 -2
- package/layout/_partial/main/notebook/note_tags.ejs +1 -1
- package/layout/_partial/scripts/lazyload.ejs +1 -1
- package/layout/_partial/scripts/utils.ejs +69 -37
- package/layout/_partial/sidebar/index_leftbar.ejs +1 -1
- package/layout/_partial/sidebar/logo.ejs +1 -1
- package/layout/_partial/sidebar/menu.ejs +1 -1
- package/layout/_partial/widgets/components/link.ejs +1 -1
- package/layout/_partial/widgets/ghissues.ejs +7 -1
- package/layout/_partial/widgets/ghrepo.ejs +2 -2
- package/layout/_partial/widgets/ghuser.ejs +1 -1
- package/layout/_partial/widgets/recent.ejs +1 -1
- package/layout/_partial/widgets/related.ejs +2 -2
- package/layout/_partial/widgets/tagtree.ejs +1 -1
- package/layout/_partial/widgets/timeline.ejs +7 -1
- package/layout/_partial/widgets/toc.ejs +1 -3
- package/layout/_partial/widgets/tree.ejs +1 -1
- package/layout/archive.ejs +1 -1
- package/layout/categories.ejs +1 -1
- package/layout/index.ejs +1 -1
- package/layout/index_topic.ejs +1 -1
- package/layout/index_wiki.ejs +2 -2
- package/layout/notebooks.ejs +1 -1
- package/layout/notes.ejs +1 -1
- package/layout/tags.ejs +1 -1
- package/package.json +1 -1
- package/scripts/events/index.js +1 -1
- package/scripts/events/lib/config.js +7 -1
- package/scripts/filters/pretty_urls.js +25 -0
- package/scripts/generators/notebooks.js +27 -26
- package/scripts/helpers/json_ld.js +5 -4
- package/scripts/helpers/pretty_url.js +22 -0
- package/scripts/tags/index.js +2 -0
- package/scripts/tags/lib/albums.js +1 -1
- package/scripts/tags/lib/chat.js +1 -1
- package/scripts/tags/lib/friends.js +1 -1
- package/scripts/tags/lib/link.js +1 -1
- package/scripts/tags/lib/posters.js +1 -1
- package/scripts/tags/lib/rating.js +32 -0
- package/scripts/tags/lib/sites.js +1 -1
- package/scripts/tags/lib/timeline.js +2 -1
- package/scripts/tags/lib/vote.js +28 -0
- package/source/css/_common/button.styl +1 -0
- package/source/css/_common/loading.styl +1 -0
- package/source/css/_components/pages/article-story.styl +2 -0
- package/source/css/_components/partial/article-footer.styl +48 -0
- package/source/css/_components/partial/paginator.styl +1 -1
- package/source/css/_components/tag-plugins/friends.styl +1 -1
- package/source/css/_components/tag-plugins/image.styl +1 -0
- package/source/css/_components/tag-plugins/rating.styl +39 -0
- package/source/css/_components/tag-plugins/timeline.styl +7 -4
- package/source/css/_components/tag-plugins/vote.styl +49 -0
- package/source/css/_components/widgets/timeline.styl +1 -1
- package/source/css/_defines/theme_base.styl +1 -0
- package/source/css/_plugins/comments/artalk.styl +53 -10
- package/source/css/_plugins/lazyload.styl +4 -0
- package/source/js/main.js +12 -5
- package/source/js/search/local-search.js +3 -1
- package/source/js/services/artalk_latest_comment.js +1 -1
- package/source/js/services/contributors.js +56 -0
- package/source/js/services/fcircle.js +1 -1
- package/source/js/services/friends.js +1 -1
- package/source/js/services/friends_and_posts.js +1 -1
- package/source/js/services/ghinfo.js +1 -1
- package/source/js/services/giscus_latest_comment.js +1 -1
- package/source/js/services/memos.js +1 -1
- package/source/js/services/rating.js +142 -0
- package/source/js/services/siteinfo.js +1 -1
- package/source/js/services/sites.js +1 -1
- package/source/js/services/timeline.js +1 -1
- package/source/js/services/twikoo_latest_comment.js +1 -1
- package/source/js/services/vote.js +113 -0
- package/source/js/services/waline_latest_comment.js +1 -1
- package/source/js/services/weibo.js +1 -1
- package/layout/_partial/widgets/components/edit.ejs +0 -24
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
function getVoteKey(id) {
|
|
2
|
+
return `vote-${id}`;
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
function hasVoted(id) {
|
|
6
|
+
return !!localStorage.getItem(getVoteKey(id));
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
function getVotedValue(id) {
|
|
10
|
+
return localStorage.getItem(getVoteKey(id)); // 'up' 或 'down'
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function storeVote(id, value) {
|
|
14
|
+
localStorage.setItem(getVoteKey(id), value);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function removeVote(id) {
|
|
18
|
+
localStorage.removeItem(getVoteKey(id));
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function markVoted(el, value) {
|
|
22
|
+
el.classList.add('voted');
|
|
23
|
+
if (value === 'up') {
|
|
24
|
+
el.querySelector('.vote-up')?.classList.add('active');
|
|
25
|
+
} else if (value === 'down') {
|
|
26
|
+
el.querySelector('.vote-down')?.classList.add('active');
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function revertVote(el, value) {
|
|
31
|
+
const id = el.dataset.id;
|
|
32
|
+
|
|
33
|
+
// 回退数值
|
|
34
|
+
if (value === 'up') {
|
|
35
|
+
const upEl = el.querySelector('.up');
|
|
36
|
+
if (upEl) upEl.textContent = Math.max(0, parseInt(upEl.textContent || '1') - 1);
|
|
37
|
+
} else if (value === 'down') {
|
|
38
|
+
const downEl = el.querySelector('.down');
|
|
39
|
+
if (downEl) downEl.textContent = Math.max(0, parseInt(downEl.textContent || '1') - 1);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// 回退样式和状态
|
|
43
|
+
el.classList.remove('voted', 'active');
|
|
44
|
+
el.querySelector('.vote-up')?.classList.remove('active');
|
|
45
|
+
el.querySelector('.vote-down')?.classList.remove('active');
|
|
46
|
+
removeVote(id);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
async function loadVote(el) {
|
|
50
|
+
const id = el.dataset.id;
|
|
51
|
+
const api = el.dataset.api;
|
|
52
|
+
if (!id || !api) return;
|
|
53
|
+
|
|
54
|
+
try {
|
|
55
|
+
const res = await fetch(`${api}/info?id=${encodeURIComponent(id)}`);
|
|
56
|
+
const data = await res.json();
|
|
57
|
+
|
|
58
|
+
el.querySelector('.up').textContent = data.votes?.up ?? 0;
|
|
59
|
+
el.querySelector('.down').textContent = data.votes?.down ?? 0;
|
|
60
|
+
} catch (e) {
|
|
61
|
+
console.warn(`[vote] 加载失败: id=${id}`, e);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function submitVote(el, value) {
|
|
66
|
+
const id = el.dataset.id;
|
|
67
|
+
const api = el.dataset.api;
|
|
68
|
+
if (!id || !api || hasVoted(id)) return;
|
|
69
|
+
|
|
70
|
+
const upEl = el.querySelector('.up');
|
|
71
|
+
const downEl = el.querySelector('.down');
|
|
72
|
+
|
|
73
|
+
// 乐观更新
|
|
74
|
+
if (value === 'up' && upEl) upEl.textContent = parseInt(upEl.textContent || '0') + 1;
|
|
75
|
+
if (value === 'down' && downEl) downEl.textContent = parseInt(downEl.textContent || '0') + 1;
|
|
76
|
+
|
|
77
|
+
storeVote(id, value);
|
|
78
|
+
markVoted(el, value);
|
|
79
|
+
|
|
80
|
+
// 后台同步
|
|
81
|
+
fetch(`${api}/update?id=${encodeURIComponent(id)}&value=${encodeURIComponent(value)}`, {
|
|
82
|
+
method: 'POST'
|
|
83
|
+
}).catch(e => {
|
|
84
|
+
console.warn(`[vote] 后台同步失败,撤销投票: id=${id}`, e);
|
|
85
|
+
revertVote(el, value);
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function initVotes() {
|
|
90
|
+
document.querySelectorAll('.ds-vote').forEach(el => {
|
|
91
|
+
const { id, api } = el.dataset;
|
|
92
|
+
if (!id || !api) return;
|
|
93
|
+
|
|
94
|
+
loadVote(el);
|
|
95
|
+
|
|
96
|
+
const votedValue = getVotedValue(id);
|
|
97
|
+
if (votedValue) markVoted(el, votedValue);
|
|
98
|
+
|
|
99
|
+
el.querySelector('.vote-up')?.addEventListener('click', () => {
|
|
100
|
+
if (!el.classList.contains('active')) submitVote(el, 'up');
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
el.querySelector('.vote-down')?.addEventListener('click', () => {
|
|
104
|
+
if (!el.classList.contains('active')) submitVote(el, 'down');
|
|
105
|
+
});
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
if (document.readyState === 'loading') {
|
|
110
|
+
window.addEventListener('DOMContentLoaded', initVotes);
|
|
111
|
+
} else {
|
|
112
|
+
initVotes();
|
|
113
|
+
}
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
<%
|
|
2
|
-
function parseURL() {
|
|
3
|
-
const source = page.source || ''
|
|
4
|
-
var url
|
|
5
|
-
for (let id of Object.keys(map)) {
|
|
6
|
-
if (source.startsWith(id) && map[id]) {
|
|
7
|
-
return source.replace(id, map[id])
|
|
8
|
-
}
|
|
9
|
-
}
|
|
10
|
-
}
|
|
11
|
-
function layoutDiv() {
|
|
12
|
-
const url = parseURL()
|
|
13
|
-
if (url == null) {
|
|
14
|
-
return ''
|
|
15
|
-
}
|
|
16
|
-
var el = ''
|
|
17
|
-
el += `<a class="edit" href="${url_for(url)}">`
|
|
18
|
-
el += icon('default:edit')
|
|
19
|
-
el += `<span>${__('btn.edit')}</span>`
|
|
20
|
-
el += `</a>`
|
|
21
|
-
return el
|
|
22
|
-
}
|
|
23
|
-
%>
|
|
24
|
-
<%- layoutDiv() %>
|