This commit is contained in:
xaoxuu 2021-03-03 22:05:29 +08:00
parent f8747a726b
commit d7a78bdce0
11 changed files with 400 additions and 222 deletions

View File

@ -124,7 +124,8 @@ plugins:
css: https://unpkg.com/swiper/swiper-bundle.min.css css: https://unpkg.com/swiper/swiper-bundle.min.css
js: https://unpkg.com/swiper/swiper-bundle.min.js js: https://unpkg.com/swiper/swiper-bundle.min.js
# issues api # issues api
issuesjs: /js/issues.js sitesjs: /js/plugins/sites.js
friendsjs: /js/plugins/friends.js
## optional plugins ## ## optional plugins ##
# preload # preload

View File

@ -13,7 +13,8 @@
// required plugins (only load if needs) // required plugins (only load if needs)
stellar.plugins = { stellar.plugins = {
jQuery: '<%- url_for(theme.plugins.jquery || "https://cdn.jsdelivr.net/npm/jquery@latest/dist/jquery.min.js") %>', jQuery: '<%- url_for(theme.plugins.jquery || "https://cdn.jsdelivr.net/npm/jquery@latest/dist/jquery.min.js") %>',
issuesjs: '<%- url_for(theme.plugins.issuesjs || "/js/issues.js") %>', sitesjs: '<%- url_for(theme.plugins.sitesjs) %>',
friendsjs: '<%- url_for(theme.plugins.friendsjs) %>',
}; };
// optional plugins // optional plugins

View File

@ -2,40 +2,25 @@
* friends.js v1 | https://github.com/xaoxuu/hexo-theme-stellar/ * friends.js v1 | https://github.com/xaoxuu/hexo-theme-stellar/
* 格式与官方标签插件一致使用空格分隔中括号内的是可选参数中括号不需要写出来 * 格式与官方标签插件一致使用空格分隔中括号内的是可选参数中括号不需要写出来
* *
* {% friends [style:rect] [group:name] %} * {% friends [group:name] %}
* {% friends [api:https://issues-api.vercel.app] [repo:xaoxuu/friends] %}
*/ */
'use strict'; 'use strict';
hexo.extend.tag.register('friends', function(args) { hexo.extend.tag.register('friends', function(args) {
args = hexo.args.map(args, ['style', 'group', 'repo']); args = hexo.args.map(args, ['group']);
var friends = hexo.locals.get('data').friends; var friends = hexo.locals.get('data').friends;
if (friends == undefined) { if (friends == undefined) {
friends = {}; friends = {};
} }
var el = '<div class="tag-plugin friends-wrap issues-wrap '; var el = '<div class="tag-plugin friends-wrap">';
if (args.style && args.style.length > 0) {
el += args.style;
} else {
el += 'round';
}
el += '"';
if (args.repo) {
el += ' id="issues-api"';
el += ' api="' + (args.api || 'https://issues-api.vercel.app') + '/' + args.repo + '"';
}
el += '>';
if (args.repo) {
el += '<div class="group-body"></div>';
} else {
function groupHeader(group) { function groupHeader(group) {
var header = '<div class="group-header">'; var header = '<div class="group-header">';
if (!!group.title) { if (group.title) {
header += '<p class="title">' + group.title + '</p>'; header += hexo.render.renderSync({text: group.title, engine: 'markdown'}).split('\n').join('');
} }
if (!!group.description) { if (group.description) {
header += '<p class="description">' + group.description + '</p>'; header += hexo.render.renderSync({text: group.description, engine: 'markdown'}).split('\n').join('');
} }
header += '</div>'; header += '</div>';
return header; return header;
@ -43,8 +28,8 @@ hexo.extend.tag.register('friends', function(args) {
function cell(friend) { function cell(friend) {
if (friend.url && friend.title) { if (friend.url && friend.title) {
var cell = '<div class="user-simple">'; var cell = '<div class="user-simple">';
cell += '<a href="' + friend.url + '">'; cell += '<a class="user-link" target="_blank" rel="external nofollow noopener noreferrer" href="' + friend.url + '">';
cell += '<img src="' + friend.avatar + '"/>'; cell += '<img src="' + (friend.avatar || 'https://7.dusays.com/2021/03/03/87519671e4837.svg') + '" onerror="javascript:this.src=\'https://7.dusays.com/2021/03/03/87519671e4837.svg\';"/>';
cell += '<div class="name"><span>' + friend.title + '</span></div>'; cell += '<div class="name"><span>' + friend.title + '</span></div>';
cell += '</a></div>' cell += '</a></div>'
return cell; return cell;
@ -56,7 +41,17 @@ hexo.extend.tag.register('friends', function(args) {
function f() { function f() {
if (groupId in friends) { if (groupId in friends) {
let group = friends[groupId]; let group = friends[groupId];
if (group.title || group.description) {
el += groupHeader(group); el += groupHeader(group);
}
if (group.repo) {
el += '<div class="friendsjs-wrap"';
el += ' id="friends-api"';
el += ' api="' + (group.api || 'https://issues-api.vercel.app') + '/' + group.repo + '"';
el += '>';
el += '<div class="group-body"></div>';
el += '</div>';
} else if (group.items) {
el += '<div class="group-body">'; el += '<div class="group-body">';
group.items.forEach((friend, i) => { group.items.forEach((friend, i) => {
el += cell(friend); el += cell(friend);
@ -64,6 +59,7 @@ hexo.extend.tag.register('friends', function(args) {
el += '</div>'; el += '</div>';
} }
} }
}
if (args.group && args.group.length > 0) { if (args.group && args.group.length > 0) {
if (args.group == groupId) { if (args.group == groupId) {
f(); f();
@ -72,7 +68,6 @@ hexo.extend.tag.register('friends', function(args) {
f(); f();
} }
} }
}
el += '</div>'; el += '</div>';
return el; return el;
}); });

77
scripts/tags/site.js Normal file
View File

@ -0,0 +1,77 @@
/**
* sites.js v1 | https://github.com/xaoxuu/hexo-theme-stellar/
* 格式与官方标签插件一致使用空格分隔中括号内的是可选参数中括号不需要写出来
*
* {% site [group:name] %}
*/
'use strict';
hexo.extend.tag.register('sites', function(args) {
args = hexo.args.map(args, ['group']);
var sites = hexo.locals.get('data').sites;
if (sites == undefined) {
sites = {};
}
var el = '<div class="tag-plugin sites-wrap">';
function groupHeader(group) {
var header = '<div class="group-header">';
if (group.title) {
header += hexo.render.renderSync({text: group.title, engine: 'markdown'}).split('\n').join('');
}
if (group.description) {
header += hexo.render.renderSync({text: group.description, engine: 'markdown'}).split('\n').join('');
}
header += '</div>';
return header;
}
function cell(site) {
if (site.url && site.title) {
var cell = '<div class="site-card">';
cell += '<a class="site-link" target="_blank" rel="external nofollow noopener noreferrer" href="' + site.url + '">';
cell += '<img src="' + (site.screenshot || ('https://image.thum.io/get/width/1024/crop/768/' + site.url)) + '" onerror="javascript:this.src=\'https://7.dusays.com/2021/02/20/76b86c0226ffd.svg\';"/>';
cell += '<div class="info">';
cell += '<img src="' + (site.avatar || 'https://7.dusays.com/2021/02/20/8f277b4ee0ecd.svg') + '" onerror="javascript:this.src=\'https://7.dusays.com/2021/02/20/8f277b4ee0ecd.svg\';"/>';
cell += '<span class="title">' + site.title + '</span>';
cell += '<span class="desc">' + (site.description || site.url) + '</span>';
cell += '</div>';
cell += '</a></div>'
return cell;
} else {
return '';
}
}
for (let groupId of Object.keys(sites)) {
function f() {
if (groupId in sites) {
let group = sites[groupId];
if (group.title || group.description) {
el += groupHeader(group);
}
if (group.repo) {
el += '<div class="sitesjs-wrap"';
el += ' id="sites-api"';
el += ' api="' + (group.api || 'https://issues-api.vercel.app') + '/' + group.repo + '"';
el += '>';
el += '<div class="group-body"></div>';
el += '</div>';
} else if (group.items) {
el += '<div class="group-body">';
group.items.forEach((site, i) => {
el += cell(site);
});
el += '</div>';
}
}
}
if (args.group && args.group.length > 0) {
if (args.group == groupId) {
f();
}
} else {
f();
}
}
el += '</div>';
return el;
});

View File

@ -1,73 +0,0 @@
.friends-wrap
.group-header
margin: 1rem 0
p
margin: 0
p.title
font-size: 1.125rem
font-weight: 500
p.description
font-size: $fs14
.group-body
display: grid
grid-gap: 4px 4px
grid-template-columns: repeat(auto-fill, 96px)
margin-bottom: 2rem
.friends-wrap .user-simple
a
margin: auto
color: var(--text-p1)
font-size: $fs12
display: flex
flex-direction: column
align-items: center
text-align: center
line-height: 1.2
border-radius: 4px
overflow: hidden
position: relative
background: var(--card)
img
object-fit: cover
display: block
width: 64px
height: 64px
.name
padding-top: 0.5em
// style
.friends-wrap.round .user-simple
a
padding: 0.5rem
trans1: background
img
border-radius: 64px
margin-top: 0.5rem
margin-bottom: 2rem
.name
position: absolute
height: 2rem
bottom: 0
&:hover
background: var(--hover-block)
.friends-wrap.rect .user-simple
a
padding: 0
display: block
trans1: box-shadow
img
width: 96px
height: 96px
border-radius: 0
.name
padding: 0 0.5em
height: 2rem
display: flex
justify-content: center
align-items: center
&:hover
box-shadow: $boxshadow-card-float

View File

@ -0,0 +1,68 @@
.friends-wrap
overflow: hidden
.group-header
margin: 0 0 1rem
p
margin: 0
font-size: $fs14
&:first-child
font-size: 1.25rem
font-weight: 500
.group-body
width: 100%
display: flex
flex-wrap: wrap
align-items: stretch
margin-bottom: 2rem
.friendsjs-wrap
display: block
.loading-wrap
min-height: 50px
margin: 2rem 0
text-align: center
.friends-wrap .user-simple
flex-shrink: 1
display: flex
align-items: stretch
width: 12.5%
@media screen and (max-width: 980px)
width: 14.28%
@media screen and (max-width: 900px)
width: 16.66%
@media screen and (max-width: 820px)
width: 20%
@media screen and (max-width: $device-tablet)
width: 16.66%
@media screen and (max-width: $device-mobile)
width: 25%
a
margin: 0
width: 100%
color: var(--text-p1)
font-size: 10px
font-weight: 500
display: flex
justify-content: flex-start
flex-direction: column
align-items: center
text-align: center
line-height: 1.2
border-radius: 4px
overflow: hidden
position: relative
padding: 1rem 0.5rem
img
object-fit: cover
display: block
width: 48px
height: 48px
background: var(--card)
border-radius: 64px
margin: 0 0 0.5rem
trans2 transform box-shadow
&:hover
background: var(--hover-block)
img
transform: scale(1.2) rotate(8deg)
box-shadow: $boxshadow-card-float

View File

@ -1,68 +0,0 @@
.site-card-group
display: grid
grid-gap: $gap $gap
grid-template-columns: repeat(auto-fill, "calc((100% - 3 * %s) / 4)" % $gap)
@media screen and (max-width: $device-laptop)
grid-template-columns: repeat(auto-fill, "calc((100% - 2 * %s) / 3)" % $gap)
@media screen and (max-width: $device-mobile)
grid-template-columns: repeat(auto-fill, "calc((100% - 1 * %s) / 2)" % $gap)
margin-bottom: 2rem
.site-card-group .site-card
line-height: 1.2
disable-select()
color: var(--text-p1)
.img
width: 100%
height 100px
@media screen and (max-width: $device-mobile)
height 80px
overflow: hidden
border-radius: $border-card * 0.5
box-shadow: 0 1px 2px 0px rgba(0, 0, 0, 0.2)
background: var(--color-block)
img
width: 100%
height 100%
transition: transform 2s ease
object-fit: cover
.info
margin-top: $gap * 0.5
img
width: 32px
height: 32px
border-radius: 16px
float: left
margin-right: 8px
margin-top: 2px
span
display: block
.title
font-weight: 600
color: var(--text-p1)
font-size: $fs15
margin-top: 1px
color: var(--color-p)
display: -webkit-box
-webkit-box-orient: vertical
overflow: hidden
-webkit-line-clamp: 1
.desc
font-size: $fs12
color: var(--text-p2)
margin-top: 2px
word-wrap: break-word;
color: var(--color-meta)
display: -webkit-box
-webkit-box-orient: vertical
overflow: hidden
-webkit-line-clamp: 2
.img
trans1 box-shadow
&:hover
.img
box-shadow: $boxshadow-float, $boxshadow-card-float
.info .title
color: $color-hover

View File

@ -0,0 +1,83 @@
.sites-wrap
.group-header
margin: 0 0 1rem
p
margin: 0
font-size: $fs14
&:first-child
font-size: 1.25rem
font-weight: 500
.group-body
width: 100%
margin-bottom: 2rem
.sitesjs-wrap
display: block
.loading-wrap
min-height: 50px
margin: 2rem 0
text-align: center
.sites-wrap .group-body
display: grid
grid-gap: $gap $gap
grid-template-columns: repeat(auto-fill, "calc((100% - 3 * %s) / 4)" % $gap)
@media screen and (max-width: $device-laptop)
grid-template-columns: repeat(auto-fill, "calc((100% - 2 * %s) / 3)" % $gap)
@media screen and (max-width: 900px)
grid-template-columns: repeat(auto-fill, "calc((100% - 1 * %s) / 2)" % $gap)
@media screen and (max-width: $device-tablet)
grid-template-columns: repeat(auto-fill, "calc((100% - 2 * %s) / 3)" % $gap)
@media screen and (max-width: $device-mobile)
grid-template-columns: repeat(auto-fill, "calc((100% - 1 * %s) / 2)" % $gap)
margin-bottom: 2rem
.sites-wrap .group-body .site-card .site-link
width: 100%
display: flex
flex-direction: column
>img
width: 100%
height 100px
@media screen and (max-width: $device-laptop)
height: 120px
@media screen and (max-width: 900px)
height: 150px
@media screen and (max-width: $device-tablet)
height: 120px
object-fit: cover
box-shadow: 0 1px 2px 0px rgba(0, 0, 0, 0.2)
trans1: box-shadow
.info
margin-top: $gap * 0.5
line-height: 1.2
>img
width: 28px
height: @width
border-radius: @width
float: left
margin-right: 8px
margin-top: 2px
span
display: block
.title
font-weight: 500
color: var(--text-p1)
font-size: $fs14
margin-top: 1px
display: -webkit-box
-webkit-box-orient: vertical
overflow: hidden
-webkit-line-clamp: 1
.desc
font-size: 10px
margin-top: 2px
word-wrap: break-word
color: var(--text-p3)
display: -webkit-box
-webkit-box-orient: vertical
overflow: hidden
-webkit-line-clamp: 2
.sites-wrap .group-body .site-card .site-link:hover
>img
box-shadow: $boxshadow-float, $boxshadow-card-float

View File

@ -278,11 +278,20 @@ if (stellar.plugins.lazyload) {
} }
// issuesjs // issuesjs
if (stellar.plugins.issuesjs) { if (stellar.plugins.sitesjs) {
const issues_api = document.getElementById('issues-api'); const issues_api = document.getElementById('sites-api');
if (issues_api != undefined) { if (issues_api != undefined) {
util.jQuery( () => { util.jQuery( () => {
util.loadScript(stellar.plugins.issuesjs, {defer:true}) util.loadScript(stellar.plugins.sitesjs, {defer:true})
})
}
}
if (stellar.plugins.friendsjs) {
const issues_api = document.getElementById('friends-api');
if (issues_api != undefined) {
console.log(issues_api);
util.jQuery( () => {
util.loadScript(stellar.plugins.friendsjs, {defer:true})
}) })
} }
} }

View File

@ -1,5 +1,5 @@
const IssuesAPI = { const friendsjs = {
requestIssuesAPI(url, callback, timeout) { requestAPI: (url, callback, timeout) => {
let retryTimes = 5; let retryTimes = 5;
function request() { function request() {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
@ -42,29 +42,31 @@ const IssuesAPI = {
} }
request(); request();
}, },
getIssuesAPIForFriends(cfg) { layout: (cfg) => {
const el = $(cfg.el)[0]; const el = $(cfg.el)[0];
$(el).append('<div class="loading"><p>正在加载</p></div>'); $(el).append('<div class="loading-wrap"><svg class="loading" style="vertical-align: middle;fill: currentColor;overflow: hidden;" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2709"><path d="M832 512c0-176-144-320-320-320V128c211.2 0 384 172.8 384 384h-64zM192 512c0 176 144 320 320 320v64C300.8 896 128 723.2 128 512h64z" p-id="2710"></path></svg><p></p></div>');
this.requestIssuesAPI(cfg.api, function(data) { friendsjs.requestAPI(cfg.api, function(data) {
$(el).find('.loading').remove(); $(el).find('.loading-wrap').remove();
const arr = data.content; const arr = data.content;
arr.forEach((item, i) => { arr.forEach((item, i) => {
var user = '<div class="user-simple">'; var user = '<div class="user-simple">';
user += '<a class="user-link" target="_blank" rel="external nofollow noopener noreferrer"'; user += '<a class="user-link" target="_blank" rel="external nofollow noopener noreferrer"';
user += ' href="' + item.url + '">'; user += ' href="' + item.url + '">';
user += '<img src="' + item.avatar + '" onerror="javascript:this.src=\'https://image.thum.io/get/width/1024/crop/768/' + item.url + '\';"/>'; user += '<img src="' + (item.avatar || 'https://7.dusays.com/2021/03/03/87519671e4837.svg') + '" onerror="javascript:this.src=\'https://7.dusays.com/2021/03/03/87519671e4837.svg\';">';
user += '<div class="name"><span>' + item.title + '</span></div>'; user += '<div class="name"><span>' + item.title + '</span></div>';
user += '</a>'; user += '</a>';
user += '</div>'; user += '</div>';
$(el).find('.group-body').append(user); $(el).find('.group-body').append(user);
}); });
}, function() { }, function() {
$(el).find('.loading i').remove(); $(el).find('.loading-wrap svg').remove();
$(el).find('.loading p').text('加载失败,请稍后重试。'); $(el).find('.loading-wrap p').text('加载失败,请稍后重试。');
}); });
}, },
request() { }
const els = document.getElementsByClassName('issues-wrap');
$(function () {
const els = document.getElementsByClassName('friendsjs-wrap');
for (var i = 0; i < els.length; i++) { for (var i = 0; i < els.length; i++) {
const el = els[i]; const el = els[i];
const api = el.getAttribute('api'); const api = el.getAttribute('api');
@ -77,10 +79,6 @@ const IssuesAPI = {
cfg.el = el; cfg.el = el;
cfg.api = api; cfg.api = api;
cfg.group = group; cfg.group = group;
this.getIssuesAPIForFriends(cfg); friendsjs.layout(cfg);
} }
}
};
$(function () {
IssuesAPI.request();
}); });

View File

@ -0,0 +1,87 @@
const sitesjs = {
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();
},
layout: (cfg) => {
const el = $(cfg.el)[0];
$(el).append('<div class="loading-wrap"><svg class="loading" style="vertical-align: middle;fill: currentColor;overflow: hidden;" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2709"><path d="M832 512c0-176-144-320-320-320V128c211.2 0 384 172.8 384 384h-64zM192 512c0 176 144 320 320 320v64C300.8 896 128 723.2 128 512h64z" p-id="2710"></path></svg><p></p></div>');
sitesjs.requestAPI(cfg.api, function(data) {
$(el).find('.loading-wrap').remove();
const arr = data.content;
arr.forEach((item, i) => {
var cell = '<div class="site-card">';
cell += '<a class="site-link" target="_blank" rel="external nofollow noopener noreferrer" href="' + item.url + '">';
cell += '<img src="' + (item.screenshot || ('https://image.thum.io/get/width/1024/crop/768/' + site.url)) + '" onerror="javascript:this.src=\'https://7.dusays.com/2021/02/20/76b86c0226ffd.svg\';"/>';
cell += '<div class="info">';
cell += '<img src="' + (item.avatar || 'https://7.dusays.com/2021/02/20/8f277b4ee0ecd.svg') + '" onerror="javascript:this.src=\'https://7.dusays.com/2021/02/20/8f277b4ee0ecd.svg\';"/>';
cell += '<span class="title">' + item.title + '</span>';
cell += '<span class="desc">' + (item.description || item.url) + '</span>';
cell += '</div>';
cell += '</a>';
cell += '</div>';
$(el).find('.group-body').append(cell);
});
}, function() {
$(el).find('.loading-wrap svg').remove();
$(el).find('.loading-wrap p').text('加载失败,请稍后重试。');
});
},
}
$(function () {
const els = document.getElementsByClassName('sitesjs-wrap');
for (var i = 0; i < els.length; i++) {
const el = els[i];
const api = el.getAttribute('api');
const group = el.getAttribute('group');
if (api == null) {
continue;
}
var cfg = new Object();
cfg.class = el.getAttribute('class');
cfg.el = el;
cfg.api = api;
cfg.group = group;
sitesjs.layout(cfg);
}
});