-
+
<%- __('page.error.what') %>
diff --git a/layout/_partial/main/article/article_footer.ejs b/layout/_partial/main/article/article_footer.ejs
index 0a91d90..64654a8 100644
--- a/layout/_partial/main/article/article_footer.ejs
+++ b/layout/_partial/main/article/article_footer.ejs
@@ -114,13 +114,13 @@ function layoutDiv() {
}
el += '>';
if (item == 'wechat') {
- el += '';
+ el += '';
} else if (item == 'weibo') {
- el += '';
+ el += '';
} else if (item == 'email') {
- el += '';
+ el += '';
} else if (item == 'link') {
- el += '';
+ el += '';
}
el += '';
}
diff --git a/layout/_partial/main/article/read_next.ejs b/layout/_partial/main/article/read_next.ejs
index b025379..8067ee1 100644
--- a/layout/_partial/main/article/read_next.ejs
+++ b/layout/_partial/main/article/read_next.ejs
@@ -1,15 +1,31 @@
<%
function layoutDiv() {
- var prev,next;
- var title = __('meta.read_next');
- var title_prev = __('meta.prev');
- var title_next = __('meta.next');
+ var prev,next
+ var title = __('meta.read_next')
+ title_prev = __('meta.newer')
+ title_next = __('meta.older')
if (page.layout === 'post') {
- prev = page.prev;
- next = page.next;
- title_prev = __('meta.newer');
- title_next = __('meta.older');
- } else if (page.layout === 'wiki' && page.wiki && page.wiki.length > 0) {
+ prev = page.prev
+ next = page.next
+ } else if (page.layout === 'topic' && page.topic?.length > 0) {
+ const topicObject = theme.topic.tree[page.topic]
+ if (topicObject) {
+ const current_page_date = topicObject.pages.filter(p => p.path == page.path)[0].date
+ for (let p of topicObject.pages) {
+ if (p.date > current_page_date) {
+ if (prev == undefined || p.date < prev.date) {
+ prev = p
+ }
+ } else if (p.date < current_page_date) {
+ if (next == undefined || p.date > next.date) {
+ next = p
+ }
+ }
+ }
+ }
+ } else if (page.layout === 'wiki' && page.wiki?.length > 0) {
+ var title_prev = __('meta.prev');
+ var title_next = __('meta.next');
let proj = theme.wiki.tree[page.wiki];
if (proj) {
let ps = proj.pages?.filter(p => p.path == page.path)
diff --git a/layout/_partial/main/navbar/breadcrumb.ejs b/layout/_partial/main/navbar/breadcrumb.ejs
index 87f403c..34a04db 100644
--- a/layout/_partial/main/navbar/breadcrumb.ejs
+++ b/layout/_partial/main/navbar/breadcrumb.ejs
@@ -63,7 +63,38 @@ function layoutDiv() {
el += '';
el += '';
- } else if (page.layout === "wiki" && page.wiki && page.wiki.length > 0) {
+ } else if (page.layout === 'topic' && page.topic?.length > 0) {
+ el += '';
+ el += '
';
+ el += '
';
+ var nodes = [];
+ // home
+ el += '
' + home_title + '';
+ nodes.push('/');
+ // menu_id
+ el += '
';
+ let url = url_for(theme.base_dir.topic);
+ nodes.push(url);
+ el += '';
+ // 专栏名
+ let topicObject = theme.topic.tree[page.topic];
+ if (topicObject != null) {
+ let url_proj = url_for(topicObject.homepage?.path);
+ if (nodes.includes(url_proj) === false) {
+ el += '
';
+ el += '
' + (topicObject.name || topicObject.title) + '';
+ }
+ }
+ el += '
';
+ // 更新日期
+ el += '
';
+ el += `
+ ${__("meta.updated")}
+ `;
+ el += '
';
+ el += '
';
+ el += '
';
+ } else if (page.layout === "wiki" && page.wiki?.length > 0) {
el += '';
el += '
';
el += '
';
diff --git a/layout/_partial/main/navbar/list_post.ejs b/layout/_partial/main/navbar/list_post.ejs
index 646692a..715fccd 100644
--- a/layout/_partial/main/navbar/list_post.ejs
+++ b/layout/_partial/main/navbar/list_post.ejs
@@ -36,6 +36,13 @@ function layoutDiv() {
el += '
' + __("btn.archives") + '';
}
}
+ if (theme.topic?.publish_list?.length > 0) {
+ if (page.layout == 'index_topic') {
+ el += '
' + __("btn.topic") + '';
+ } else {
+ el += '
' + __("btn.topic") + '';
+ }
+ }
if (theme['post-index']) {
const obj = theme['post-index'];
diff --git a/layout/_partial/main/post_list/post_card.ejs b/layout/_partial/main/post_list/post_card.ejs
index dfeeef4..b0adf7a 100755
--- a/layout/_partial/main/post_list/post_card.ejs
+++ b/layout/_partial/main/post_list/post_card.ejs
@@ -102,7 +102,7 @@ function div_default() {
}
}
if (post.pin) {
- el += '
';
+ el += '
';
}
el += '
';
el += '';
diff --git a/layout/_partial/main/post_list/topic_card.ejs b/layout/_partial/main/post_list/topic_card.ejs
new file mode 100644
index 0000000..79b2348
--- /dev/null
+++ b/layout/_partial/main/post_list/topic_card.ejs
@@ -0,0 +1,16 @@
+<%
+function layoutDiv() {
+ var el = '';
+ el += '
';
+ el += ``
+ el += '';
+ el += '
' + (topic.title || topic.name) + '
';
+ if (topic.description) {
+ el += '
' + topic.description + '
';
+ }
+ el += '
';
+ el += '';
+ return el;
+}
+%>
+<%- layoutDiv() %>
diff --git a/layout/_partial/sidebar/index.ejs b/layout/_partial/sidebar/index.ejs
index 9761664..b30ed5e 100755
--- a/layout/_partial/sidebar/index.ejs
+++ b/layout/_partial/sidebar/index.ejs
@@ -1,8 +1,4 @@
<%
-var proj;
-if (page.layout === 'wiki' && page.wiki) {
- proj = theme.wiki.tree[page.wiki];
-}
// 默认组件
if (page.sidebar == undefined) {
if (page.layout == 'post' && page.content) {
@@ -14,6 +10,14 @@ if (page.sidebar == undefined) {
} else {
page.sidebar = theme.sidebar.widgets.wiki;
}
+ } else if (page.layout === 'topic') {
+ if (page.topic && theme.topic?.tree[page.topic]?.sidebar) {
+ page.sidebar = theme.topic.tree[page.topic].sidebar;
+ } else {
+ page.sidebar = theme.sidebar.widgets.topic;
+ }
+ } else if (page.layout === 'index_topic') {
+ page.sidebar = theme.sidebar.widgets.index_topic
} else if (is_home()) {
page.sidebar = theme.sidebar.widgets.home;
} else if (is_category() || is_tag() || is_archive() || ['categories', 'tags', 'archives'].includes(page.layout)) {
@@ -60,6 +64,10 @@ function layoutWidgets() {
el += __('btn.all_wiki');
el += '';
// this product
+ var proj;
+ if (page.layout === 'wiki' && page.wiki) {
+ proj = theme.wiki.tree[page.wiki];
+ }
if (proj == undefined) {
// 如果没有项目名,则使用menu中显示的名字
if (page.menu_id && theme.sidebar.menu[page.menu_id] && md_link(theme.sidebar.menu[page.menu_id])) {
diff --git a/layout/_partial/widgets/related.ejs b/layout/_partial/widgets/related.ejs
index a902ed3..6733ebe 100644
--- a/layout/_partial/widgets/related.ejs
+++ b/layout/_partial/widgets/related.ejs
@@ -8,7 +8,7 @@ function relatedPosts() {
var el = ''
el += `
`
el += ``
el += ``
relatedItem.posts.sort('date', -1).each(function(post) {
@@ -20,6 +20,29 @@ function relatedPosts() {
el += ``
return el
}
+function relatedPostsInTopic() {
+ if (page.topic?.length == 0) {
+ return ''
+ }
+ const topic = theme.topic.tree[page.topic]
+ if (topic == null) {
+ return ''
+ }
+ var el = ''
+ el += `
`
+ el += ``
+ el += ``
+ el += ``
+ return el
+}
function relatedWiki() {
let thisItemObject = theme.wiki.tree[page.wiki]
if (thisItemObject == null) {
@@ -53,6 +76,8 @@ function layoutDiv() {
return relatedWiki()
} else if (page.layout == 'post') {
return relatedPosts()
+ } else if (page.layout == 'topic') {
+ return relatedPostsInTopic()
}
}
%>
diff --git a/layout/index_topic.ejs b/layout/index_topic.ejs
new file mode 100644
index 0000000..ca776e1
--- /dev/null
+++ b/layout/index_topic.ejs
@@ -0,0 +1,36 @@
+<%
+if (page.menu_id == undefined) {
+ if (page.layout === 'wiki_topic' && page.topic) {
+ page.menu_id = 'blog'
+ } else {
+ page.menu_id = 'post'
+ }
+}
+
+function layout_topic_list(partial) {
+ var el = ''
+ const { publish_list, tree } = theme.topic
+ for (let id of publish_list) {
+ const topic = tree[id]
+ if (topic == null) {
+ continue
+ }
+ el += `
`
+ }
+ return el
+}
+function layoutDiv() {
+ var el = ''
+ el += partial('_partial/main/navbar/list_post')
+ el += layout_topic_list(function(topic) {
+ return partial('_partial/main/post_list/topic_card', {topic: topic})
+ })
+ return el
+}
+%>
+
+<%- layoutDiv() %>
\ No newline at end of file
diff --git a/layout/topic.ejs b/layout/topic.ejs
new file mode 100644
index 0000000..f6fb264
--- /dev/null
+++ b/layout/topic.ejs
@@ -0,0 +1,39 @@
+<%
+if (page.menu_id == undefined) {
+ page.menu_id = 'post'
+}
+if (page.layout == undefined) {
+ page.layout = 'index_topic'
+}
+if (page.title == undefined) {
+ page.title = __('btn.wiki')
+}
+function layoutTitle() {
+ const title = page.h1 != null ? page.h1 : page.title;
+ if (title && title.length > 0) {
+ return '
' + title + '
';
+ } else {
+ return '';
+ }
+}
+%>
+<% if (page.layout === 'index_topic') { %>
+ <%- partial('index') %>
+<% } else { %>
+ <%
+ if (page.header == undefined) {
+ page.header = 'auto';
+ }
+ %>
+ <%- partial('_partial/main/navbar/breadcrumb') %>
+
<%- scrollreveal() %>'>
+ <%- layoutTitle() %>
+ <%- markdown(page.content) %>
+ <% if (theme.plugins.tianli_gpt.enable && ['all', 'topic'].includes(theme.plugins.tianli_gpt.field)) { %>
+ <%- partial('_partial/plugins/ai/tianli_gpt') %>
+ <% } %>
+ <%- partial('_partial/main/article/article_footer') %>
+
+ <%- partial('_partial/main/article/read_next') %>
+ <%- partial('_partial/plugins/comments/layout') %>
+<% } %>
diff --git a/scripts/events/index.js b/scripts/events/index.js
index b7e05c2..924e80c 100644
--- a/scripts/events/index.js
+++ b/scripts/events/index.js
@@ -8,9 +8,14 @@ hexo.on('generateBefore', () => {
require('./lib/links')(hexo);
require('./lib/authors')(hexo);
require('./lib/doc_tree')(hexo);
+ require('./lib/topic_tree')(hexo);
require('./lib/utils')(hexo);
});
+hexo.on('generateAfter', () => {
+ require('./lib/merge_posts')(hexo);
+});
+
hexo.on('ready', () => {
const { version, homepage, repository } = require('../../package.json');
hexo.log.info(`Welcome to Stellar ${version}
diff --git a/scripts/events/lib/merge_posts.js b/scripts/events/lib/merge_posts.js
new file mode 100644
index 0000000..e431f61
--- /dev/null
+++ b/scripts/events/lib/merge_posts.js
@@ -0,0 +1,47 @@
+/**
+ * merge_posts.js v1 | https://github.com/xaoxuu/hexo-theme-stellar/
+ *
+ */
+
+'use strict';
+
+class RelatedPage {
+ constructor(page) {
+ this.id = page._id
+ this.wiki = page.wiki
+ this.topic = page.topic
+ this.title = page.title
+ this.seo_title = page.seo_title
+ this.path = page.path
+ this.path_key = page.path.replace('.html', '')
+ this.layout = page.layout
+ this.date = page.date
+ this.updated = page.updated
+ }
+}
+
+module.exports = ctx => {
+ var topic = ctx.theme.config.topic
+ const posts = ctx.locals.get('posts')
+ posts.sort('date').each(function(post) {
+ let obj = new RelatedPage(post)
+ // 合并拥有共同 topic 的文章到 topic.tree
+ if (post.topic?.length > 0) {
+ var topicObject = topic.tree[post.topic]
+ if (topicObject) {
+ obj.page_number = topicObject.pages.length + 1
+ topicObject.pages.push(obj)
+ }
+ }
+ })
+
+ // topic homepage
+ for (let tid of Object.keys(topic.tree)) {
+ let topicObject = topic.tree[tid]
+ if (topicObject.order_by == '-date') {
+ topicObject.pages = topicObject.pages.reverse()
+ }
+ topicObject.homepage = topicObject.pages[0]
+ }
+
+}
diff --git a/scripts/events/lib/topic_tree.js b/scripts/events/lib/topic_tree.js
new file mode 100644
index 0000000..3647e95
--- /dev/null
+++ b/scripts/events/lib/topic_tree.js
@@ -0,0 +1,45 @@
+/**
+ * topic.js v1 | https://github.com/xaoxuu/hexo-theme-stellar/
+ * 用于专栏/专题文章,一个专栏类似于 wiki 模块中的一个项目文档
+ * 区别是:
+ * 1. 按发布日期排序,无需手动排序
+ *
+ */
+
+'use strict';
+
+function getTopicTree(ctx) {
+ var tree = {}
+ const data = ctx.locals.get('data')
+ var list = []
+ for (let key of Object.keys(data)) {
+ if (key.startsWith('topic/') && key.length > 5) {
+ let newKey = key.replace('topic/', '')
+ let obj = data[key]
+ obj.id = newKey
+ if (obj.order_by == null) {
+ obj.order_by = '-date'
+ }
+ if (obj.path == null) {
+ obj.path = `/topic/${newKey}/`
+ }
+ obj.pages = []
+ list.push(obj)
+ }
+ }
+ for (let item of list) {
+ tree[item.id] = item
+ }
+ return tree
+}
+
+module.exports = ctx => {
+ var topic = ctx.locals.get('data').topic || {}
+ // 专栏结构树
+ topic.tree = getTopicTree(ctx)
+ // 索引页显示的专栏列表
+ if (topic.publish_list == null) {
+ topic.publish_list = Object.keys(topic.tree)
+ }
+ ctx.theme.config.topic = topic
+}
diff --git a/scripts/generators/topic.js b/scripts/generators/topic.js
new file mode 100644
index 0000000..e1f7777
--- /dev/null
+++ b/scripts/generators/topic.js
@@ -0,0 +1,20 @@
+/**
+ * topic v1 | https://github.com/xaoxuu/hexo-theme-stellar/
+ */
+
+hexo.extend.generator.register('topic', function (locals) {
+ const { topic } = hexo.theme.config
+ const topicIdList = Object.keys(topic.tree)
+ if (topicIdList.length == 0) {
+ return {}
+ }
+ var ret = []
+ ret.push({
+ path: (hexo.theme.config.base_dir.topic) + '/index.html',
+ data: {
+ layout: 'index_topic'
+ },
+ layout: ['index_topic']
+ })
+ return ret
+})
diff --git a/source/css/_layout/partial/paginator.styl b/source/css/_layout/partial/paginator.styl
index 797bc7e..8d2a107 100644
--- a/source/css/_layout/partial/paginator.styl
+++ b/source/css/_layout/partial/paginator.styl
@@ -28,10 +28,10 @@
background-clip: content-box
&.next
border-left: 1px dashed var(--block-border)
- background-image: url('https://gcore.jsdelivr.net/gh/cdn-x/placeholder@1.0.9/arrow/064b95430caf4.svg')
+ background-image: url('https://gcore.jsdelivr.net/gh/cdn-x/placeholder@1.0.12/arrow/064b95430caf4.svg')
&.prev
border-right: 1px dashed var(--block-border)
- background-image: url('https://gcore.jsdelivr.net/gh/cdn-x/placeholder@1.0.9/arrow/f049bbd4e88ec.svg')
+ background-image: url('https://gcore.jsdelivr.net/gh/cdn-x/placeholder@1.0.12/arrow/f049bbd4e88ec.svg')
.current
font-family: $ff-code
background: var(--block)
diff --git a/source/css/_layout/tag-plugins/frame.styl b/source/css/_layout/tag-plugins/frame.styl
index 84c13d5..92018f0 100644
--- a/source/css/_layout/tag-plugins/frame.styl
+++ b/source/css/_layout/tag-plugins/frame.styl
@@ -27,7 +27,7 @@
margin-top: 19px
margin-bottom: 20px
.frame
- background-image: url(https://gcore.jsdelivr.net/gh/cdn-x/placeholder@1.0.9/frame/iphone11.svg);
+ background-image: url(https://gcore.jsdelivr.net/gh/cdn-x/placeholder@1.0.12/frame/iphone11.svg);
width: 329px
height: 658px
&[focus='top']
diff --git a/source/js/plugins/fcircle.js b/source/js/plugins/fcircle.js
index 4bfba97..4021956 100644
--- a/source/js/plugins/fcircle.js
+++ b/source/js/plugins/fcircle.js
@@ -86,7 +86,7 @@ $(function () {
var cfg = new Object();
cfg.el = el;
cfg.api = api;
- cfg.avatar = 'https://gcore.jsdelivr.net/gh/cdn-x/placeholder@1.0.9/avatar/round/3442075.svg';
+ cfg.avatar = 'https://gcore.jsdelivr.net/gh/cdn-x/placeholder@1.0.12/avatar/round/3442075.svg';
FCircle.layoutDiv(cfg);
}
});
diff --git a/source/js/plugins/friends.js b/source/js/plugins/friends.js
index 3a42bde..3ed4070 100644
--- a/source/js/plugins/friends.js
+++ b/source/js/plugins/friends.js
@@ -78,7 +78,7 @@ $(function () {
cfg.el = el;
cfg.api = api;
cfg.class = el.getAttribute('class');
- cfg.avatar = 'https://gcore.jsdelivr.net/gh/cdn-x/placeholder@1.0.9/avatar/round/3442075.svg';
+ cfg.avatar = 'https://gcore.jsdelivr.net/gh/cdn-x/placeholder@1.0.12/avatar/round/3442075.svg';
friendsjs.layout(cfg);
}
});
diff --git a/source/js/plugins/memos.js b/source/js/plugins/memos.js
index 1e8f579..9efa7b1 100644
--- a/source/js/plugins/memos.js
+++ b/source/js/plugins/memos.js
@@ -126,7 +126,7 @@ $(function () {
cfg.host = api.replace(/https:\/\/(.*?)\/(.*)/i, '$1');
cfg.avatar = el.getAttribute('avatar');
if (!cfg.avatar) {
- cfg.avatar = 'https://gcore.jsdelivr.net/gh/cdn-x/placeholder@1.0.9/avatar/round/3442075.svg';
+ cfg.avatar = 'https://gcore.jsdelivr.net/gh/cdn-x/placeholder@1.0.12/avatar/round/3442075.svg';
}
MemosJS.layoutDiv(cfg);
}
diff --git a/source/js/plugins/sites.js b/source/js/plugins/sites.js
index 77fc169..4136d9f 100644
--- a/source/js/plugins/sites.js
+++ b/source/js/plugins/sites.js
@@ -80,8 +80,8 @@ $(function () {
cfg.class = el.getAttribute('class');
cfg.el = el;
cfg.api = api;
- cfg.avatar = 'https://gcore.jsdelivr.net/gh/cdn-x/placeholder@1.0.9/link/8f277b4ee0ecd.svg';
- cfg.screenshot = 'https://gcore.jsdelivr.net/gh/cdn-x/placeholder@1.0.9/cover/76b86c0226ffd.svg';
+ cfg.avatar = 'https://gcore.jsdelivr.net/gh/cdn-x/placeholder@1.0.12/link/8f277b4ee0ecd.svg';
+ cfg.screenshot = 'https://gcore.jsdelivr.net/gh/cdn-x/placeholder@1.0.12/cover/76b86c0226ffd.svg';
sitesjs.layout(cfg);
}
});
diff --git a/source/js/plugins/weibo.js b/source/js/plugins/weibo.js
index 271e87a..69c872b 100644
--- a/source/js/plugins/weibo.js
+++ b/source/js/plugins/weibo.js
@@ -110,7 +110,7 @@ $(function () {
var cfg = new Object();
cfg.el = el;
cfg.api = api;
- cfg.avatar = 'https://gcore.jsdelivr.net/gh/cdn-x/placeholder@1.0.9/avatar/round/3442075.svg';
+ cfg.avatar = 'https://gcore.jsdelivr.net/gh/cdn-x/placeholder@1.0.12/avatar/round/3442075.svg';
weibojs.layoutDiv(cfg);
}
});