hexo-theme-stellar 1.29.0 → 1.30.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 (48) hide show
  1. package/_config.yml +29 -9
  2. package/_data/chat_users.yml +0 -0
  3. package/_data/widgets.yml +7 -0
  4. package/languages/zh-TW.yml +2 -2
  5. package/layout/_partial/head.ejs +2 -1
  6. package/layout/_partial/main/navbar/nav_tabs_blog.ejs +10 -10
  7. package/layout/_partial/scripts/defines.ejs +3 -0
  8. package/layout/_partial/scripts/services.ejs +91 -0
  9. package/layout/_partial/scripts/theme.ejs +5 -0
  10. package/layout/_partial/scripts/utils.ejs +67 -7
  11. package/layout/_partial/scripts.ejs +1 -1
  12. package/layout/_plugins/mermaid.ejs +1 -1
  13. package/layout/_plugins/scrollreveal.ejs +1 -0
  14. package/layout/_plugins/search/algolia_search.ejs +11 -12
  15. package/layout/layout.ejs +1 -1
  16. package/package.json +1 -1
  17. package/scripts/events/lib/config.js +3 -0
  18. package/scripts/events/lib/doc_tree.js +1 -6
  19. package/scripts/filters/index.js +26 -0
  20. package/scripts/generators/notebooks.js +1 -1
  21. package/scripts/generators/search.js +21 -2
  22. package/scripts/helpers/dynamic_color.js +138 -0
  23. package/scripts/tags/index.js +1 -0
  24. package/scripts/tags/lib/box.js +1 -1
  25. package/scripts/tags/lib/chat.js +515 -0
  26. package/scripts/tags/lib/folders.js +1 -1
  27. package/scripts/tags/lib/folding.js +2 -2
  28. package/scripts/tags/lib/sites.js +1 -1
  29. package/scripts/tags/lib/video.js +7 -2
  30. package/source/css/_components/tag-plugins/chat.styl +621 -0
  31. package/source/css/_components/tag-plugins/friends.styl +10 -0
  32. package/source/css/_components/tag-plugins/sites.styl +12 -0
  33. package/source/css/_components/tag-plugins/tabs.styl +5 -2
  34. package/source/css/_custom.styl +1 -0
  35. package/source/css/_defines/func.styl +7 -6
  36. package/source/css/_defines/theme.styl +38 -0
  37. package/source/css/_plugins/katex.styl +0 -1
  38. package/source/js/plugins/download-file.js +198 -0
  39. package/source/js/plugins/video.js +65 -0
  40. package/source/js/plugins/voice.js +438 -0
  41. package/source/js/search/algolia-search.js +63 -61
  42. package/source/js/services/artalk_latest_comment.js +33 -0
  43. package/source/js/services/friends.js +4 -0
  44. package/source/js/services/giscus_latest_comment.js +36 -0
  45. package/source/js/services/memos.js +91 -69
  46. package/source/js/services/sites.js +4 -0
  47. package/source/js/services/twikoo_latest_comment.js +47 -0
  48. package/source/js/services/waline_latest_comment.js +32 -0
@@ -1,73 +1,95 @@
1
1
  utils.jq(() => {
2
- $(function () {
3
- const els = document.getElementsByClassName('ds-memos');
4
- for (var i = 0; i < els.length; i++) {
5
- const el = els[i];
6
- const api = el.getAttribute('api');
7
- if (api == null) {
8
- continue;
9
- }
10
- const default_avatar = el.getAttribute('avatar') || def.avatar;
11
- const limit = el.getAttribute('limit');
12
- const host = api.replace(/https:\/\/(.*?)\/(.*)/i, '$1');
13
- // layout
14
- utils.request(el, api, function(data) {
15
- var users = [];
16
- const filter = el.getAttribute('user');
17
- if (filter && filter.length > 0) {
18
- users = filter.split(",");
19
- }
20
- var hide = [];
21
- const hideStr = el.getAttribute('hide');
22
- if (hideStr && hideStr.length > 0) {
23
- hide = hideStr.split(",");
24
- }
25
- data.forEach((item, i) => {
26
- if (limit && i >= limit) {
27
- return;
28
- }
29
- if (item.user && item.user.login && users.length > 0) {
30
- if (!users.includes(item.user.login)) {
31
- return;
32
- }
33
- }
34
- let date = new Date(item.createdTs * 1000)
35
- var cell = '<div class="timenode" index="' + i + '">';
36
- cell += '<div class="header">';
37
- if (!users.length && !hide.includes('user')) {
38
- cell += '<div class="user-info">';
39
- if (default_avatar.length > 0) {
40
- cell += `<img src="${default_avatar}">`;
41
- }
42
- cell += '<span>' + item.creatorName + '</span>';
43
- cell += '</div>';
44
- }
45
- cell += '<span>' + date.toLocaleString() + '</span>';
46
- cell += '</div>';
47
- cell += '<div class="body">';
48
- cell += marked.parse(item.content || '');
49
- var imgs = [];
50
- for (let res of item.resourceList) {
51
- if (res.type?.includes('image/')) {
52
- imgs.push(res);
53
- }
54
- }
55
- if (imgs.length > 0) {
56
- cell += '<div class="tag-plugin image">';
57
- for (let img of imgs) {
58
- if (img.externalLink?.length > 0) {
59
- cell += `<div class="image-bg"><img src="${img.externalLink}" data-fancybox="memos"></div>`;
60
- } else {
61
- cell += `<div class="image-bg"><img src="https://${host}/o/r/${img.id}" data-fancybox="memos"></div>`;
62
- }
2
+ const els = Array.from(document.getElementsByClassName('ds-memos'));
3
+
4
+ els.forEach(el => {
5
+ const api = el.getAttribute('api');
6
+ if (!api) return;
7
+
8
+ const default_avatar = el.getAttribute('avatar') || def.avatar;
9
+ const limit = el.getAttribute('limit');
10
+ const host = api.match(/https:\/\/(.*?)\/(.*)/i)[1];
11
+
12
+ utils.request(el, api, async data => {
13
+ let memos = versionHandlers.identify(data);
14
+ if (memos.version === "feature" )return;
15
+
16
+ const users = el.getAttribute('user')?.split(",") || [];
17
+ const hide = el.getAttribute('hide')?.split(",") || [];
18
+
19
+ await Promise.all(memos.data.slice(0, limit || memos.data.length).map(item =>
20
+ createMemoCell(item, memos, users, hide, default_avatar, host).then(cell => $(el).append(cell))
21
+ ));
22
+ });
23
+
24
+ async function createMemoCell(item, memos, users, hide, default_avatar, host) {
25
+ const versionHandler = versionHandlers[memos.version] || versionHandlers["feature"];
26
+ return `<div class="timenode">
27
+ <div class="header">${!users.length && !hide.includes('user') ? await versionHandler.buildUser(item, memos, default_avatar) : ''}
28
+ <span>${versionHandler.buildDate(item).toLocaleString()}</span></div>
29
+ <div class="body">${marked.parse(item.content || '')}
30
+ <div class="tag-plugin image">${versionHandler.buildImages(item, host).join('')}</div>
31
+ </div></div>`;
32
+ }
33
+
34
+ // Memos版本管理
35
+ const versionHandlers = {
36
+ "22-": {
37
+ buildUser: async (item, memos, default_avatar) =>
38
+ `<div class="user-info">${default_avatar ? `<img src="${default_avatar}">` : ''}<span>${item.creatorName}</span></div>`,
39
+ buildDate: item => new Date(item.createdTs * 1000),
40
+ buildImages: (item, host) => (item.resourceList || []).filter(res => res.type?.includes('image/')).map(res =>
41
+ `<div class="image-bg"><img src="${res.externalLink || `https://${host}/o/r/${res.id}`}"></div>`
42
+ )
43
+ },
44
+ "22+": {
45
+ buildUser: async (item, memos, default_avatar) => {
46
+ const creatorId = item?.creator.split('/')[1];
47
+ let user = memos.users.find(user => user.id === parseInt(creatorId));
48
+ if (!user) {
49
+ if (!memos.requests[creatorId]) {
50
+ memos.requests[creatorId] = fetch(`${memos.site}/api/v1/users/${creatorId}`)
51
+ .then(response => response.json())
52
+ .then(data => {
53
+ if (data.username) {
54
+ user = data;
55
+ memos.users.push(data);
56
+ } else {
57
+ user = null;
58
+ }
59
+ })
60
+ .finally(() => delete memos.requests[creatorId]);
63
61
  }
64
- cell += '</div>';
62
+ await memos.requests[creatorId];
63
+ user = memos.users.find(user => user.id === parseInt(creatorId));
65
64
  }
66
- cell += '</div>';
67
- cell += '</div>';
68
- $(el).append(cell);
69
- });
70
- });
71
- }
65
+ const name = user ? user.nickname || user.username : 'memos';
66
+ const avatarUrl = user?.avatarUrl ? `${memos.site}${user.avatarUrl}` : default_avatar || '';
67
+ return `<div class="user-info">${avatarUrl ? `<img src="${avatarUrl}">` : ''}<span>${name}</span></div>`;
68
+ },
69
+ buildDate: item => new Date(item.createTime),
70
+ buildImages: (item) => (item.resources || []).filter(res => res.type?.includes('image/')).map(res =>
71
+ `<div class="image-bg"><img src="${res.externalLink || `https://${host}/o/r/${res.id}`}"></div>`
72
+ )
73
+ },
74
+ "feature": {
75
+ buildUser: async () => "memos",
76
+ buildDate: () => new Date(),
77
+ buildImages: () => []
78
+ },
79
+ identify: (data) => {
80
+ let memos = { version: "feature", users: [], site: api.split('/api/v1')[0], requests: {}, data: [] }
81
+ if (Array.isArray(data)) {
82
+ memos.version = "22-";
83
+ memos.data = data;
84
+ } else if (data.memos) {
85
+ memos.version = "22+";
86
+ memos.data = data.memos;
87
+ } else {
88
+ memos.version = "feature";
89
+ console.log("当前Memos版本过高,请到Stellar社区反馈");
90
+ }
91
+ return memos
92
+ }
93
+ };
72
94
  });
73
- });
95
+ });
@@ -19,6 +19,10 @@ utils.jq(() => {
19
19
  cell += `<img src="${item.icon || item.avatar || default_avatar}" onerror="javascript:this.removeAttribute(\'data-src\');this.src=\'${default_avatar}\';"/>`;
20
20
  cell += `<span class="title">${item.title}</span>`;
21
21
  cell += `<span class="desc">${item.description || item.url}</span>`;
22
+ if (item.labels && item.labels.length > 0) {
23
+ let label = item.labels[0];
24
+ cell += `<span class="label" style="background:#${label.color};">${label.name}</span>`;
25
+ }
22
26
  cell += `</div>`;
23
27
  cell += `</a>`;
24
28
  cell += `</div>`;
@@ -0,0 +1,47 @@
1
+ utils.jq(() => {
2
+ $(function () {
3
+ const el = document.querySelector('.ds-twikoo');
4
+ utils.onLoading(el); // 加载动画
5
+
6
+ const api = el.getAttribute('api');
7
+ const limit = parseInt(el.getAttribute('limit')) || 10;
8
+ const reply = el.getAttribute('hide') !== 'reply';
9
+ if (!api) return;
10
+
11
+ fetch(api, {
12
+ method: "POST",
13
+ body: JSON.stringify({
14
+ "event": "GET_RECENT_COMMENTS",
15
+ "envId": api,
16
+ "pageSize": limit,
17
+ "includeReply": reply
18
+ }),
19
+ headers: { 'Content-Type': 'application/json' }
20
+ })
21
+ .then(res => res.json())
22
+ .then(({ data }) => {
23
+ utils.onLoadSuccess(el); // 移除动画
24
+ data.forEach((comment, j) => {
25
+ let commentText = comment.commentText;
26
+ if (!commentText || commentText.trim() === '') return; // 跳过空评论
27
+ // 转义字符
28
+ commentText = commentText.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#039;");
29
+ commentText = commentText.length > 50 ? commentText.substring(0, 50) + '...' : commentText;
30
+ var cell = '<div class="timenode" index="' + j + '">';
31
+ cell += '<div class="header">';
32
+ cell += '<div class="user-info">';
33
+ cell += '<span>' + comment.nick + '</span>';
34
+ cell += '</div>';
35
+ cell += '<span>' + new Date(comment.created).toLocaleString('zh-CN', {month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit', hour12: false}) + '</span>';
36
+ cell += '</div>';
37
+ cell += '<a class="body" href="' + comment.url + '#' + comment.id + '">';
38
+ cell += commentText;
39
+ cell += '</a>';
40
+ cell += '</div>';
41
+ $(el).append(cell);
42
+ });
43
+ })
44
+ .catch(() => utils.onLoadFailure(el));
45
+ });
46
+ });
47
+
@@ -0,0 +1,32 @@
1
+ utils.jq(() => {
2
+ $(function () {
3
+ const els = document.getElementsByClassName('ds-waline');
4
+ for (var i = 0; i < els.length; i++) {
5
+ const el = els[i];
6
+ const limit = parseInt(el.getAttribute('limit')) || 10;
7
+ const apiBase = el.getAttribute('api');
8
+ if (apiBase == null) {
9
+ continue;
10
+ }
11
+ const api = apiBase + '/comment?type=recent&count=' + limit;
12
+ const default_avatar = def.avatar;
13
+ utils.request(el, api, function(data) {
14
+ data.forEach((item, i) => {
15
+ var cell = '<div class="timenode" index="' + i + '">';
16
+ cell += '<div class="header">';
17
+ cell += '<div class="user-info">';
18
+ cell += '<img src="' + (item.avatar || default_avatar) + '" onerror="javascript:this.src=\'' + default_avatar + '\';">';
19
+ cell += '<span>' + item.nick + '</span>';
20
+ cell += '</div>';
21
+ cell += '<span>' + new Date(item.time).toLocaleString() + '</span>';
22
+ cell += '</div>';
23
+ cell += '<a class="body" href="' + item.url + '#' + item.objectId + '" target="_blank" rel="external nofollow noopener noreferrer">';
24
+ cell += item.comment.replace(/<a\b[^>]*>(.*?)<\/a>/g, '$1');
25
+ cell += '</a>';
26
+ cell += '</div>';
27
+ $(el).append(cell);
28
+ });
29
+ });
30
+ }
31
+ });
32
+ });