hexo-theme-stellar 1.33.0 → 1.34.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/CLAUDE.md +217 -0
- package/README.md +2 -0
- package/_config.yml +35 -26
- package/docs/audits/2026-08-08-stellar-analysis.md +267 -0
- package/docs/release-process.md +59 -0
- package/layout/_partial/comments/artalk/script.ejs +56 -41
- package/layout/_partial/comments/beaudar/script.ejs +35 -20
- package/layout/_partial/comments/giscus/script.ejs +34 -19
- package/layout/_partial/comments/twikoo/script.ejs +29 -14
- package/layout/_partial/comments/utterances/script.ejs +35 -20
- package/layout/_partial/comments/waline/script.ejs +40 -28
- package/layout/_partial/cover/wiki_cover.ejs +1 -1
- package/layout/_partial/head.ejs +53 -4
- package/layout/_partial/scripts/defines.ejs +21 -3
- package/layout/_partial/scripts/lazyload.ejs +2 -2
- package/layout/_partial/scripts/services.ejs +101 -41
- package/layout/_partial/scripts/utils.ejs +144 -5
- package/layout/_partial/sidebar/index_leftbar.ejs +3 -0
- package/layout/_partial/sidebar/search.ejs +3 -0
- package/layout/_partial/widgets/ghuser.ejs +18 -4
- package/layout/_partial/widgets/linklist.ejs +1 -1
- package/layout/_partial/widgets/timeline.ejs +36 -33
- package/layout/_plugins/copycode.ejs +9 -5
- package/layout/_plugins/mathjax.ejs +47 -18
- package/layout/_plugins/mermaid.ejs +28 -24
- package/layout/_plugins/pjax.ejs +8 -0
- package/layout/_plugins/scrollreveal.ejs +14 -13
- package/layout/_plugins/swiper.ejs +2 -2
- package/layout/index.ejs +4 -2
- package/layout/index_topic.ejs +4 -2
- package/layout/index_wiki.ejs +6 -4
- package/layout/layout.ejs +3 -2
- package/package.json +2 -1
- package/scripts/commands/new-note.js +49 -0
- package/scripts/filters/lib/img_onerror.js +0 -2
- package/scripts/helpers/json_ld.js +11 -8
- package/scripts/helpers/pretty_url.js +5 -0
- package/scripts/tags/lib/chat.js +16 -9
- package/scripts/tags/lib/frame.js +2 -1
- package/scripts/tags/lib/image.js +6 -5
- package/scripts/tags/lib/link.js +6 -4
- package/scripts/tags/lib/timeline.js +101 -79
- package/source/css/_common/canonical.styl +11 -6
- package/source/css/_common/highlight.styl +4 -1
- package/source/css/_common/html.styl +4 -0
- package/source/css/_common/loading.styl +5 -1
- package/source/css/_components/md.styl +3 -0
- package/source/css/_components/pages/article-story.styl +2 -0
- package/source/css/_components/partial/article-footer.styl +1 -0
- package/source/css/_components/partial/navbar.styl +4 -2
- package/source/css/_components/sidebar/menu.styl +1 -0
- package/source/css/_components/sidebar/search.styl +4 -0
- package/source/css/_components/sidebar/sidebar.styl +12 -5
- package/source/css/_components/tag-plugins/chat.styl +6 -8
- package/source/css/_components/tag-plugins/folding.styl +1 -0
- package/source/css/_components/tag-plugins/gallery.styl +2 -0
- package/source/css/_components/tag-plugins/grid.styl +1 -0
- package/source/css/_components/tag-plugins/image.styl +3 -0
- package/source/css/_components/tag-plugins/link.styl +1 -0
- package/source/css/_components/tag-plugins/navbar.styl +15 -13
- package/source/css/_components/tag-plugins/note.styl +1 -0
- package/source/css/_components/tag-plugins/okr.styl +1 -0
- package/source/css/_components/tag-plugins/sites.styl +2 -0
- package/source/css/_components/tag-plugins/timeline.styl +9 -0
- package/source/css/_components/tag-plugins/vote.styl +2 -0
- package/source/css/_components/widgets/components.styl +1 -0
- package/source/css/_components/widgets/ghuser.styl +19 -3
- package/source/css/_components/widgets/list.styl +1 -0
- package/source/css/_components/widgets/toc.styl +3 -0
- package/source/css/_components/widgets/widgets.styl +4 -0
- package/source/css/_custom.styl +6 -3
- package/source/css/_defines/func.styl +24 -8
- package/source/css/_defines/theme_base.styl +1 -1
- package/source/css/_plugins/comments/artalk.styl +6 -2
- package/source/css/_plugins/comments/twikoo.styl +2 -0
- package/source/css/_plugins/index.styl +2 -0
- package/source/css/_plugins/pjax.styl +61 -0
- package/source/js/main.js +80 -26
- package/source/js/plugins/copycode.js +34 -27
- package/source/js/plugins/pjax.js +646 -0
- package/source/js/search/local-search.js +5 -2
- package/source/js/services/memos.js +42 -4
- package/source/js/services/rss.js +200 -0
|
@@ -28,7 +28,7 @@ utils.jq(() => {
|
|
|
28
28
|
<div class="header">${!users.length && !hide.includes('user') ? await versionHandler.buildUser(item, memos, default_avatar) : ''}
|
|
29
29
|
<span>${versionHandler.buildDate(item).toLocaleString()}</span></div>
|
|
30
30
|
<div class="body">${marked.parse(item.content || '')}
|
|
31
|
-
<
|
|
31
|
+
<p>${versionHandler.buildImages(item, host).join('')}</p>
|
|
32
32
|
</div></div>`;
|
|
33
33
|
}
|
|
34
34
|
|
|
@@ -39,7 +39,7 @@ utils.jq(() => {
|
|
|
39
39
|
`<div class="user-info">${default_avatar ? `<img src="${default_avatar}">` : ''}<span>${item.creatorName}</span></div>`,
|
|
40
40
|
buildDate: item => new Date(item.createdTs * 1000),
|
|
41
41
|
buildImages: (item, host) => (item.resourceList || []).filter(res => res.type?.includes('image/')).map(res =>
|
|
42
|
-
`<
|
|
42
|
+
`<p><img src="${res.externalLink || `https://${host}/o/r/${res.id}`}"></p>`
|
|
43
43
|
)
|
|
44
44
|
},
|
|
45
45
|
"22+": {
|
|
@@ -69,7 +69,38 @@ utils.jq(() => {
|
|
|
69
69
|
},
|
|
70
70
|
buildDate: item => new Date(item.createTime),
|
|
71
71
|
buildImages: (item) => (item.resources || []).filter(res => res.type?.includes('image/')).map(res =>
|
|
72
|
-
`<
|
|
72
|
+
`<p><img src="${res.externalLink || `https://${host}/o/r/${res.id}`}"></p>`
|
|
73
|
+
)
|
|
74
|
+
},
|
|
75
|
+
"25+": {
|
|
76
|
+
buildUser: async (item, memos, default_avatar) => {
|
|
77
|
+
const creatorId = item?.creator.split('/')[1];
|
|
78
|
+
let user = memos.users.find(user => user.name.split('/')[1] === creatorId);
|
|
79
|
+
if (!user) {
|
|
80
|
+
if (!memos.requests[creatorId]) {
|
|
81
|
+
memos.requests[creatorId] = fetch(`${memos.site}/api/v1/users/${creatorId}`)
|
|
82
|
+
.then(response => response.json())
|
|
83
|
+
.then(data => {
|
|
84
|
+
if (data.username) {
|
|
85
|
+
user = data;
|
|
86
|
+
memos.users.push(data);
|
|
87
|
+
} else {
|
|
88
|
+
user = null;
|
|
89
|
+
}
|
|
90
|
+
})
|
|
91
|
+
.finally(() => delete memos.requests[creatorId]);
|
|
92
|
+
}
|
|
93
|
+
await memos.requests[creatorId];
|
|
94
|
+
user = memos.users.find(user => user.name.split('/')[1] === creatorId);
|
|
95
|
+
}
|
|
96
|
+
console.log(JSON.stringify(user));
|
|
97
|
+
const name = user ? user.displayName || user.username : 'memos';
|
|
98
|
+
const avatarUrl = user?.avatarUrl ? `${memos.site}${user.avatarUrl}` : default_avatar || '';
|
|
99
|
+
return `<div class="user-info">${avatarUrl ? `<img src="${avatarUrl}">` : ''}<span>${name}</span></div>`;
|
|
100
|
+
},
|
|
101
|
+
buildDate: item => new Date(item.createTime),
|
|
102
|
+
buildImages: (item) => (item.attachments || []).filter(res => res.type?.includes('image/')).map(res =>
|
|
103
|
+
`<div class="image-bg"><img src="${res.externalLink || `https://${host}/file/${res.name}/${res.filename}`}"></div>`
|
|
73
104
|
)
|
|
74
105
|
},
|
|
75
106
|
"feature": {
|
|
@@ -82,9 +113,15 @@ utils.jq(() => {
|
|
|
82
113
|
if (Array.isArray(data)) {
|
|
83
114
|
memos.version = "22-";
|
|
84
115
|
memos.data = data;
|
|
85
|
-
|
|
116
|
+
console.log("当前Memos版本为22-");
|
|
117
|
+
} else if (data.memos && !data.memos[0].attachments) {
|
|
86
118
|
memos.version = "22+";
|
|
87
119
|
memos.data = data.memos;
|
|
120
|
+
console.log("当前Memos版本为22+");
|
|
121
|
+
} else if (data.memos && data.memos[0].attachments) {
|
|
122
|
+
memos.version = "25+";
|
|
123
|
+
memos.data = data.memos;
|
|
124
|
+
console.log("当前Memos版本为25+");
|
|
88
125
|
} else {
|
|
89
126
|
memos.version = "feature";
|
|
90
127
|
console.log("当前Memos版本过高,请到Stellar社区反馈");
|
|
@@ -94,3 +131,4 @@ utils.jq(() => {
|
|
|
94
131
|
};
|
|
95
132
|
});
|
|
96
133
|
});
|
|
134
|
+
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
utils.jq(() => {
|
|
2
|
+
$(function () {
|
|
3
|
+
const els = document.getElementsByClassName('ds-rss');
|
|
4
|
+
|
|
5
|
+
for (let i = 0; i < els.length; i++) {
|
|
6
|
+
const el = els[i];
|
|
7
|
+
const api = el.dataset.api;
|
|
8
|
+
if (!api) continue;
|
|
9
|
+
|
|
10
|
+
utils.request(el, api, async resp => {
|
|
11
|
+
const text = await resp.text();
|
|
12
|
+
|
|
13
|
+
const head = text.slice(0, 1024).trim();
|
|
14
|
+
const content_type = el.getAttribute('content_type') || 'content';
|
|
15
|
+
const show_title = el.getAttribute('show_title') !== 'false';
|
|
16
|
+
const show_content = el.getAttribute('show_content') !== 'false';
|
|
17
|
+
const limit = parseInt(el.getAttribute('limit')) || 10;
|
|
18
|
+
// JSON Feed
|
|
19
|
+
if (head.startsWith('{') && head.includes('jsonfeed.org/version')) {
|
|
20
|
+
handleJsonFeed(el, JSON.parse(text), content_type, show_title, show_content, limit);
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const parser = new DOMParser();
|
|
25
|
+
const doc = parser.parseFromString(text, 'text/xml');
|
|
26
|
+
|
|
27
|
+
if (doc.querySelector('parsererror')) {
|
|
28
|
+
console.error('Failed to parse feed XML.');
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
// Atom Feed
|
|
32
|
+
if (doc.documentElement.nodeName === 'feed' &&
|
|
33
|
+
doc.documentElement.namespaceURI === 'http://www.w3.org/2005/Atom') {
|
|
34
|
+
handleAtom(el, doc, content_type, show_title, show_content, limit);
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
// RSS 2.0 Feed
|
|
38
|
+
if (doc.documentElement.nodeName === 'rss') {
|
|
39
|
+
handleRSS2(el, doc, content_type, show_title, show_content, limit);
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
// RSS 1.0 Feed
|
|
43
|
+
if (doc.documentElement.nodeName === 'rdf:RDF') {
|
|
44
|
+
handleRSS1(el, doc, content_type, show_title, show_content, limit);
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
function handleAtom(el, doc, content_type, show_title, show_content, limit) {
|
|
54
|
+
const entries = doc.querySelectorAll('entry');
|
|
55
|
+
const feedAuthorName = doc.querySelector('feed > author > name')?.textContent || '匿名';
|
|
56
|
+
|
|
57
|
+
const limitedEntries = Array.from(entries).slice(0, limit);
|
|
58
|
+
|
|
59
|
+
const htmlBuffer = limitedEntries.map((item, i) => {
|
|
60
|
+
const title = item.querySelector('title')?.textContent || '无题';
|
|
61
|
+
const link = item.querySelector('link')?.getAttribute('href') || '#';
|
|
62
|
+
const published = item.querySelector('published, updated')?.textContent;
|
|
63
|
+
const content = item.querySelector('content')?.textContent || '';
|
|
64
|
+
const summary = item.querySelector('summary')?.textContent || '';
|
|
65
|
+
const authorName = item.querySelector('author > name')?.textContent || feedAuthorName;
|
|
66
|
+
|
|
67
|
+
let cell = `<div class="timenode" index="${i}">`;
|
|
68
|
+
cell += `<div class="header">`;
|
|
69
|
+
cell += `<span class="user-info"><strong>${authorName}</strong></span>`;
|
|
70
|
+
|
|
71
|
+
if (published) {
|
|
72
|
+
const date = new Date(published);
|
|
73
|
+
cell += `<span>${date.toLocaleString()}</span>`;
|
|
74
|
+
}
|
|
75
|
+
cell += `</div>`;
|
|
76
|
+
|
|
77
|
+
cell += `<div class="body">`;
|
|
78
|
+
if (show_title) {
|
|
79
|
+
const titleAttr = show_content ? '' : ' style="border-bottom:none;"' ;
|
|
80
|
+
const linkAttr = show_content ? '' : ' style="padding-bottom:0"' ;
|
|
81
|
+
cell += `<p class="title"${titleAttr}><a href="${link}"${linkAttr} target="_blank" rel="external nofollow noopener noreferrer">${title}</a></p>`;
|
|
82
|
+
}
|
|
83
|
+
if (show_content){
|
|
84
|
+
cell += `<div class="content">${content_type === 'summary' ? summary : content}</div>`;
|
|
85
|
+
}
|
|
86
|
+
cell += `</div></div>`;
|
|
87
|
+
|
|
88
|
+
return cell;
|
|
89
|
+
}).join('');
|
|
90
|
+
|
|
91
|
+
$(el).append(htmlBuffer);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function handleRSS2(el, doc, content_type, show_title, show_content, limit) {
|
|
95
|
+
const items = Array.from(doc.querySelectorAll('item')).slice(0, limit);
|
|
96
|
+
const feedAuthorName = doc.querySelector('channel > managingEditor, channel > webMaster, channel > title')?.textContent || '匿名';
|
|
97
|
+
|
|
98
|
+
const htmlBuffer = items.map((item, i) => {
|
|
99
|
+
const title = item.querySelector('title')?.textContent || '无题';
|
|
100
|
+
const link = item.querySelector('link')?.textContent || '#';
|
|
101
|
+
const pubDate = item.querySelector('pubDate')?.textContent;
|
|
102
|
+
const content = item.getElementsByTagName('content:encoded')[0]?.textContent || '';
|
|
103
|
+
const description = item.getElementsByTagName('description')[0]?.textContent || '';
|
|
104
|
+
const authorName = item.querySelector('author, creator')?.textContent || feedAuthorName;
|
|
105
|
+
|
|
106
|
+
let cell = `<div class="timenode" index="${i}">`;
|
|
107
|
+
cell += `<div class="header">`;
|
|
108
|
+
cell += `<span class="user-info"><strong>${authorName}</strong></span>`;
|
|
109
|
+
if (pubDate) {
|
|
110
|
+
const date = new Date(pubDate);
|
|
111
|
+
cell += `<span>${isNaN(date) ? pubDate : date.toLocaleString()}</span>`;
|
|
112
|
+
}
|
|
113
|
+
cell += `</div>`;
|
|
114
|
+
cell += `<div class="body">`;
|
|
115
|
+
if (show_title) {
|
|
116
|
+
const titleAttr = show_content ? '' : ' style="border-bottom:none;"' ;
|
|
117
|
+
const linkAttr = show_content ? '' : ' style="padding-bottom:0"' ;
|
|
118
|
+
cell += `<p class="title"${titleAttr}><a href="${link}"${linkAttr} target="_blank" rel="external nofollow noopener noreferrer">${title}</a></p>`;
|
|
119
|
+
}
|
|
120
|
+
if (show_content){
|
|
121
|
+
cell += `<div class="content">${content_type === 'summary' ? description : content}</div>`;
|
|
122
|
+
}
|
|
123
|
+
cell += `</div></div>`;
|
|
124
|
+
return cell;
|
|
125
|
+
}).join('');
|
|
126
|
+
|
|
127
|
+
$(el).append(htmlBuffer);
|
|
128
|
+
}
|
|
129
|
+
function handleRSS1(el, doc, content_type, show_title, show_content, limit) {
|
|
130
|
+
const items = Array.from(doc.querySelectorAll('item')).slice(0, limit);
|
|
131
|
+
const feedTitle = doc.querySelector('channel > title')?.textContent || '匿名';
|
|
132
|
+
|
|
133
|
+
const htmlBuffer = items.map((item, i) => {
|
|
134
|
+
const title = item.querySelector('title')?.textContent || '无题';
|
|
135
|
+
const link = item.querySelector('link')?.textContent || '#';
|
|
136
|
+
const pubDate = (item.querySelector('pubDate') || item.getElementsByTagName('dc:date')[0])?.textContent;
|
|
137
|
+
const content = item.getElementsByTagName('content:encoded')[0]?.textContent || '';
|
|
138
|
+
const description = (item.querySelector('description') || item.querySelector('summary'))?.textContent || '';
|
|
139
|
+
const authorName = (item.querySelector('author') || item.getElementsByTagName('dc:creator')[0])?.textContent || feedTitle;
|
|
140
|
+
|
|
141
|
+
let cell = `<div class="timenode" index="${i}">`;
|
|
142
|
+
cell += `<div class="header">`;
|
|
143
|
+
cell += `<span class="user-info"><strong>${authorName}</strong></span>`;
|
|
144
|
+
if (pubDate) {
|
|
145
|
+
const date = new Date(pubDate);
|
|
146
|
+
cell += `<span>${isNaN(date) ? pubDate : date.toLocaleString()}</span>`;
|
|
147
|
+
}
|
|
148
|
+
cell += `</div>`;
|
|
149
|
+
cell += `<div class="body">`;
|
|
150
|
+
if (show_title) {
|
|
151
|
+
const titleAttr = show_content ? '' : ' style="border-bottom:none;"' ;
|
|
152
|
+
const linkAttr = show_content ? '' : ' style="padding-bottom:0"' ;
|
|
153
|
+
cell += `<p class="title"${titleAttr}><a href="${link}"${linkAttr} target="_blank" rel="external nofollow noopener noreferrer">${title}</a></p>`;
|
|
154
|
+
}
|
|
155
|
+
if (show_content){
|
|
156
|
+
cell += `<div class="content">${content_type === 'summary' ? description : content}</div>`;
|
|
157
|
+
}
|
|
158
|
+
cell += `</div></div>`;
|
|
159
|
+
return cell;
|
|
160
|
+
}).join('');
|
|
161
|
+
|
|
162
|
+
$(el).append(htmlBuffer);
|
|
163
|
+
}
|
|
164
|
+
function handleJsonFeed(el, data, content_type, show_title, show_content, limit) {
|
|
165
|
+
const items = (data.items || []).slice(0, limit);
|
|
166
|
+
const feedAuthorName = data.authors?.[0]?.name || data.title || '匿名';
|
|
167
|
+
|
|
168
|
+
const htmlBuffer = items.map((item, i) => {
|
|
169
|
+
const id = item.id || i;
|
|
170
|
+
const title = item.title || '无题';
|
|
171
|
+
const link = item.url || '#';
|
|
172
|
+
const pubDate = item.date_published;
|
|
173
|
+
const content = item.content_html || '';
|
|
174
|
+
const summary = item.summary || '';
|
|
175
|
+
|
|
176
|
+
let authorName = (item.authors || []).map(a => a.name).filter(Boolean).join(' ') || feedAuthorName;
|
|
177
|
+
|
|
178
|
+
let cell = `<div class="timenode" index="${id}">`;
|
|
179
|
+
cell += `<div class="header">`;
|
|
180
|
+
cell += `<span class="user-info"><strong>${authorName}</strong></span>`;
|
|
181
|
+
if (pubDate) {
|
|
182
|
+
const date = new Date(pubDate);
|
|
183
|
+
cell += `<span>${isNaN(date.getTime()) ? pubDate : date.toLocaleString()}</span>`;
|
|
184
|
+
}
|
|
185
|
+
cell += `</div>`;
|
|
186
|
+
cell += `<div class="body">`;
|
|
187
|
+
if (show_title) {
|
|
188
|
+
const titleAttr = show_content ? '' : ' style="border-bottom:none;"' ;
|
|
189
|
+
const linkAttr = show_content ? '' : ' style="padding-bottom:0"' ;
|
|
190
|
+
cell += `<p class="title"${titleAttr}><a href="${link}"${linkAttr} target="_blank" rel="external nofollow noopener noreferrer">${title}</a></p>`;
|
|
191
|
+
}
|
|
192
|
+
if (show_content){
|
|
193
|
+
cell += `<div class="content">${content_type === 'summary' ? summary : content}</div>`;
|
|
194
|
+
}
|
|
195
|
+
cell += `</div></div>`;
|
|
196
|
+
return cell;
|
|
197
|
+
}).join('');
|
|
198
|
+
|
|
199
|
+
$(el).append(htmlBuffer);
|
|
200
|
+
}
|