fcircle & custom index navbar & timeline

This commit is contained in:
xaoxuu 2022-10-28 22:58:20 +08:00
parent fb7a4ae58f
commit 517327ca77
9 changed files with 212 additions and 65 deletions

View File

@ -30,6 +30,10 @@ sidebar:
post: [toc, ghrepo, ghissues] # for pages using 'layout:post' post: [toc, ghrepo, ghissues] # for pages using 'layout:post'
wiki: [toc, ghrepo, ghissues, related] # for pages using 'layout:wiki' wiki: [toc, ghrepo, ghissues, related] # for pages using 'layout:wiki'
######## Index ########
post-index: # 近期发布 分类 标签 归档 and ...
# '朋友文章': /friends/rss/
######## Main ######## ######## Main ########
breadcrumb: breadcrumb:
@ -251,6 +255,7 @@ plugins:
ghinfo: /js/plugins/ghinfo.js ghinfo: /js/plugins/ghinfo.js
timeline: /js/plugins/timeline.js timeline: /js/plugins/timeline.js
linkcard: /js/plugins/linkcard.js linkcard: /js/plugins/linkcard.js
fcircle: /js/plugins/fcircle.js
marked: https://cdn.bootcdn.net/ajax/libs/marked/4.0.18/marked.min.js marked: https://cdn.bootcdn.net/ajax/libs/marked/4.0.18/marked.min.js

View File

@ -1,34 +1,57 @@
<div class='nav-wrap'> <%
<nav class='sub post cap'> function layoutDiv() {
<% if (is_home()) { %> var el = '';
<a class='active' href='<%- url_for("/") %>'><%- __('btn.recent_publish') %></a> el += '<div class="nav-wrap">';
<% } else { %> el += '<nav class="sub post cap">';
<a href='<%- url_for("/") %>'><%- __('btn.recent_publish') %></a> if (is_home()) {
<% } %> el += '<a class="active" href="' + url_for("/") + '">' + __("btn.recent_publish") + '</a>';
<% if (site.categories && site.categories.length > 0) { %> } else {
<% if (page.category) { %> el += '<a href="' + url_for("/") + '">' + __("btn.recent_publish") + '</a>';
<a class='active' href='<%- url_for(config.category_dir) %>'><%- __('btn.category') + __('symbol.colon') + page.category %></a> }
<% } else if (page.layout == 'categories') { %>
<a class='active' href='<%- url_for(config.category_dir) %>'><%- __('btn.categories') %></a> if (site.categories && site.categories.length > 0) {
<% } else { %> if (page.category) {
<a href='<%- url_for(config.category_dir) %>'><%- __('btn.categories') %></a> el += '<a class="active" href="' + url_for(config.category_dir) + '">' + __("btn.category") + __("symbol.colon") + page.category + '</a>';
<% } %> } else if (page.layout == "categories") {
<% } %> el += '<a class="active" href="' + url_for(config.category_dir) + '">' + __("btn.categories") + '</a>';
<% if (site.tags && site.tags.length > 0) { %> } else {
<% if (page.tag) { %> el += '<a href="' + url_for(config.category_dir) + '">' + __("btn.categories") + '</a>';
<a class='active' href='<%- url_for(config.tag_dir) %>'><%- __('btn.tag') + __('symbol.colon') + page.tag %></a> }
<% } else if (page.layout == 'tags') { %> }
<a class='active' href='<%- url_for(config.tag_dir) %>'><%- __('btn.tags') %></a>
<% } else { %> if (site.tags && site.tags.length > 0) {
<a href='<%- url_for(config.tag_dir) %>'><%- __('btn.tags') %></a> if (page.tag) {
<% } %> el += '<a class="active" href="' + url_for(config.tag_dir) + '">' + __("btn.tag") + __("symbol.colon") + page.tag + '</a>';
<% } %> } else if (page.layout == "tags") {
<% if (site.posts && site.posts.length > 0) { %> el += '<a class="active" href="' + url_for(config.tag_dir) + '">' + __("btn.tags") + '</a>';
<% if (is_archive()) { %> } else {
<a class='active' href='<%- url_for(config.archive_dir) %>'><%- __('btn.archives') %></a> el += '<a href="' + url_for(config.tag_dir) + '">' + __("btn.tags") + '</a>';
<% } else { %> }
<a href='<%- url_for(config.archive_dir) %>'><%- __('btn.archives') %></a> }
<% } %>
<% } %> if (site.posts && site.posts.length > 0) {
</nav> if (is_archive()) {
</div> el += '<a class="active" href="' + url_for(config.archive_dir) + '">' + __("btn.archives") + '</a>';
} else {
el += '<a href="' + url_for(config.archive_dir) + '">' + __("btn.archives") + '</a>';
}
}
if (theme['post-index']) {
const obj = theme['post-index'];
for (let key of Object.keys(obj)) {
if (full_url_for(page.path) == full_url_for(obj[key])) {
el += '<a class="active" href="' + url_for(obj[key]) + '">' + key + '</a>';
} else {
el += '<a href="' + url_for(obj[key]) + '">' + key + '</a>';
}
}
}
el += '</nav>';
el += '</div>';
return el;
}
%>
<%- layoutDiv() %>

View File

@ -7,14 +7,23 @@ function layoutTitle() {
return ''; return '';
} }
} }
function layoutDiv() {
var el = '';
if (page.post_list) {
el += partial('_partial/main/navbar/list_post');
}
if (page.h1 || page.title || (page.content && page.content.length > 0)) {
el += partial('_partial/main/navbar/breadcrumb');
}
el += '<article class="content md ' + page.layout + (page.indent ? ' indent' : '') + scrollreveal() + '">';
el += layoutTitle();
if (page.content && page.content.length > 0) {
el += page.content;
}
el += '</article>';
el += partial('_partial/plugins/comments/layout');
return el;
}
%> %>
<% if (page.h1 || page.title || (page.content && page.content.length > 0)) { %>
<%- partial('_partial/main/navbar/breadcrumb') %> <%- layoutDiv() %>
<article class='content md <%- page.layout %><%- page.indent ? ' indent' : '' %><%- scrollreveal() %>'>
<%- layoutTitle() %>
<% if (page.content && page.content.length > 0) { %>
<%- page.content %>
<% } %>
</article>
<% } %>
<%- partial('_partial/plugins/comments/layout') %>

View File

@ -36,12 +36,14 @@ function layoutNodeContent(content) {
function postTimeline(args, content) { function postTimeline(args, content) {
args = hexo.args.map(args, ['api', 'user']); args = hexo.args.map(args, ['api', 'user', 'type', 'limit']);
var el = ''; var el = '';
if (!args.type) {
args.type = 'timeline';
}
if (args.api && args.api.length > 0) { if (args.api && args.api.length > 0) {
el += '<div class="tag-plugin timeline stellar-timeline-api"'; el += '<div class="tag-plugin timeline stellar-' + args.type + '-api"';
el += ' ' + hexo.args.joinTags(args, ['api', 'user']).join(' '); el += ' ' + hexo.args.joinTags(args, ['api', 'user', 'limit']).join(' ');
el += '>'; el += '>';
} else { } else {
el += '<div class="tag-plugin timeline">'; el += '<div class="tag-plugin timeline">';

View File

@ -68,9 +68,6 @@ article.md.content
.tag-plugin,iframe .tag-plugin,iframe
margin-top: var(--gap-p) margin-top: var(--gap-p)
margin-bottom: var(--gap-p) margin-bottom: var(--gap-p)
p,.tag-plugin
.highlight,table
--gap-p: 1rem
iframe iframe
display: block display: block

View File

@ -100,5 +100,4 @@
display: none display: none
&+.timenode &+.timenode
margin-top: 0.75rem margin-top: 0.75rem
.body
max-height: 40vh

View File

@ -1,10 +1,10 @@
.md .tag-plugin.split
margin: 0.5rem 0
.tag-plugin.split .tag-plugin.split
display: grid display: grid
grid-gap: 16px grid-gap: 16px
grid-template-columns: repeat(auto-fill, "calc((100% - 1 * %s) / 2)" % 16px) grid-template-columns: repeat(auto-fill, "calc((100% - 1 * %s) / 2)" % 16px)
>div> >.cell
margin: 1rem 0
>.cell>
p p
line-height: 1.5 line-height: 1.5
:first-child :first-child
@ -18,11 +18,15 @@
.tag-plugin.split .tag-plugin.split
&[bg]>div @media screen and (max-width: $device-tablet)
display: block
.tag-plugin.split
&[bg]>.cell
padding: 1rem padding: 1rem
border-radius: $border-card border-radius: $border-card
&[bg='block']>div &[bg='block']>.cell
background: var(--block) background: var(--block)
&[bg='card']>div &[bg='card']>.cell
background: var(--card) background: var(--card)
box-shadow: $boxshadow-card box-shadow: $boxshadow-card

View File

@ -113,15 +113,32 @@
.tag-plugin.copy .tag-plugin.copy
width: 240px width: 240px
.tag-plugin.timeline[api]
&.stellar-fcircle-api .timenode:hover .header
.user-info
background: inherit
span
color: inherit
a.body
color: var(--text-p1)
trans2: transform box-shadow
line-height: 1.25
padding: 0.75rem 1rem
&:hover
transform: translateY(-1px)
box-shadow: $boxshadow-card-float
.tag-plugin.timeline.stellar-timeline-api .body
max-height: convert(hexo-config('tag_plugins.timeline.max-height')) .tag-plugin.timeline[api] .body
overflow: scroll overflow: scroll
p.title p.title
font-size: 1rem font-size: 1rem
font-weight: 700 font-weight: 700
margin: 0.5rem 0 0.75rem margin: 0.5rem 0 0.75rem
line-height: 1.25 line-height: 1.25
&:only-child
margin-bottom: 0.5rem
font-weight: 500
a a
color: inherit color: inherit
&:hover &:hover
@ -136,7 +153,7 @@
pre code pre code
font-size: $fs-12 font-size: $fs-12
.tag-plugin.timeline.stellar-timeline-api .body .footer .tag-plugin.timeline[api] .body .footer
margin: 0 0 -0.5rem margin: 0 0 -0.5rem
padding: 0.5rem 0 1rem padding: 0.5rem 0 1rem
user-select: none user-select: none
@ -159,7 +176,7 @@
font-size: $fs-12 font-size: $fs-12
align-items: stretch align-items: stretch
.tag-plugin.timeline.stellar-timeline-api .body .footer .tag-plugin.timeline[api] .body .footer
.item .item
border-width: 1px border-width: 1px
border-style: solid border-style: solid

View File

@ -0,0 +1,91 @@
const FCircle = {
requestAPI: (url, callback, timeout) => {
let retryTimes = 5;
function request() {
return new Promise((resolve, reject) => {
let status = 0; // 0 等待 1 完成 2 超时
let timer = setTimeout(() => {
if (status === 0) {
status = 2;
timer = null;
reject('请求超时');
if (retryTimes == 0) {
timeout();
}
}
}, 5000);
fetch(url).then(function(response) {
if (status !== 2) {
clearTimeout(timer);
resolve(response);
timer = null;
status = 1;
}
if (response.ok) {
return response.json();
}
throw new Error('Network response was not ok.');
}).then(function(data) {
retryTimes = 0;
callback(data);
}).catch(function(error) {
if (retryTimes > 0) {
retryTimes -= 1;
setTimeout(() => {
request();
}, 5000);
} else {
timeout();
}
});
});
}
request();
},
layoutDiv: (cfg) => {
const el = $(cfg.el)[0];
$(el).append('<div class="loading-wrap"><svg xmlns="http://www.w3.org/2000/svg" width="2rem" height="2rem" preserveAspectRatio="xMidYMid meet" viewBox="0 0 24 24"><g fill="none" stroke="currentColor" stroke-linecap="round" stroke-width="2"><path stroke-dasharray="60" stroke-dashoffset="60" stroke-opacity=".3" d="M12 3C16.9706 3 21 7.02944 21 12C21 16.9706 16.9706 21 12 21C7.02944 21 3 16.9706 3 12C3 7.02944 7.02944 3 12 3Z"><animate fill="freeze" attributeName="stroke-dashoffset" dur="1.3s" values="60;0"/></path><path stroke-dasharray="15" stroke-dashoffset="15" d="M12 3C16.9706 3 21 7.02944 21 12"><animate fill="freeze" attributeName="stroke-dashoffset" dur="0.3s" values="15;0"/><animateTransform attributeName="transform" dur="1.5s" repeatCount="indefinite" type="rotate" values="0 12 12;360 12 12"/></path></g></svg></div>');
FCircle.requestAPI(cfg.api, function(data) {
$(el).find('.loading-wrap').remove();
const arr = data.article_data || [];
const limit = el.getAttribute('limit');
arr.forEach((item, i) => {
if (limit && i >= limit) {
return;
}
var cell = '<div class="timenode" index="' + i + '">';
cell += '<div class="header">';
cell += '<div class="user-info">';
cell += '<img src="' + item.avatar + '">';
cell += '<span>' + item.author + '</span>';
cell += '</div>';
cell += '<p>' + item.updated + '</p>';
cell += '</div>';
cell += '<a class="body" href="' + item.link + '" target="_blank" rel="external nofollow noopener noreferrer">';
cell += item.title;
cell += '</a>';
cell += '</div>';
$(el).append(cell);
});
}, function() {
$(el).find('.loading-wrap svg').remove();
$(el).find('.loading-wrap').append('<svg xmlns="http://www.w3.org/2000/svg" width="2rem" height="2rem" preserveAspectRatio="xMidYMid meet" viewBox="0 0 24 24"><g fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"><path stroke-dasharray="60" stroke-dashoffset="60" d="M12 3L21 20H3L12 3Z"><animate fill="freeze" attributeName="stroke-dashoffset" dur="0.5s" values="60;0"/></path><path stroke-dasharray="6" stroke-dashoffset="6" d="M12 10V14"><animate fill="freeze" attributeName="stroke-dashoffset" begin="0.6s" dur="0.2s" values="6;0"/></path></g><circle cx="12" cy="17" r="1" fill="currentColor" fill-opacity="0"><animate fill="freeze" attributeName="fill-opacity" begin="0.8s" dur="0.4s" values="0;1"/></circle></svg>');
$(el).find('.loading-wrap').addClass('error');
});
},
}
$(function () {
const els = document.getElementsByClassName('stellar-fcircle-api');
for (var i = 0; i < els.length; i++) {
const el = els[i];
const api = el.getAttribute('api');
if (api == null) {
continue;
}
var obj = new Object();
obj.el = el;
obj.api = api;
FCircle.layoutDiv(obj);
}
});