diff --git a/_config.yml b/_config.yml index a439d14..1629d35 100755 --- a/_config.yml +++ b/_config.yml @@ -124,7 +124,8 @@ plugins: css: https://unpkg.com/swiper/swiper-bundle.min.css js: https://unpkg.com/swiper/swiper-bundle.min.js # issues api - issuesjs: /js/issues.js + sitesjs: /js/plugins/sites.js + friendsjs: /js/plugins/friends.js ## optional plugins ## # preload diff --git a/layout/_partial/scripts/index.ejs b/layout/_partial/scripts/index.ejs index 5c82982..b14d8b7 100644 --- a/layout/_partial/scripts/index.ejs +++ b/layout/_partial/scripts/index.ejs @@ -13,7 +13,8 @@ // required plugins (only load if needs) stellar.plugins = { 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 diff --git a/scripts/tags/friends.js b/scripts/tags/friends.js index db0e1aa..86f4ebc 100644 --- a/scripts/tags/friends.js +++ b/scripts/tags/friends.js @@ -2,61 +2,56 @@ * friends.js v1 | https://github.com/xaoxuu/hexo-theme-stellar/ * 格式与官方标签插件一致使用空格分隔,中括号内的是可选参数(中括号不需要写出来) * - * {% friends [style:rect] [group:name] %} - * {% friends [api:https://issues-api.vercel.app] [repo:xaoxuu/friends] %} + * {% friends [group:name] %} */ 'use strict'; 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; if (friends == undefined) { friends = {}; } - var el = '
'; - } - if (!!group.description) { - header += '

' + group.description + '

'; - } - header += '
'; - return header; + var el = '
'; + function groupHeader(group) { + var header = '
'; + if (group.title) { + header += hexo.render.renderSync({text: group.title, engine: 'markdown'}).split('\n').join(''); } - function cell(friend) { - if (friend.url && friend.title) { - var cell = '' - return cell; - } else { - return ''; - } + if (group.description) { + header += hexo.render.renderSync({text: group.description, engine: 'markdown'}).split('\n').join(''); } - for (let groupId of Object.keys(friends)) { - function f() { - if (groupId in friends) { - let group = friends[groupId]; + header += '
'; + return header; + } + function cell(friend) { + if (friend.url && friend.title) { + var cell = '
'; + cell += ''; + cell += ''; + cell += '
' + friend.title + '
'; + cell += '
' + return cell; + } else { + return ''; + } + } + for (let groupId of Object.keys(friends)) { + function f() { + if (groupId in friends) { + let group = friends[groupId]; + if (group.title || group.description) { el += groupHeader(group); + } + if (group.repo) { + el += '
{ el += cell(friend); @@ -64,13 +59,13 @@ hexo.extend.tag.register('friends', function(args) { el += '
'; } } - if (args.group && args.group.length > 0) { - if (args.group == groupId) { - f(); - } - } else { + } + if (args.group && args.group.length > 0) { + if (args.group == groupId) { f(); } + } else { + f(); } } el += '
'; diff --git a/scripts/tags/site.js b/scripts/tags/site.js new file mode 100644 index 0000000..4da120c --- /dev/null +++ b/scripts/tags/site.js @@ -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 = '
'; + function groupHeader(group) { + var 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 += '
'; + return header; + } + function cell(site) { + if (site.url && site.title) { + var cell = '
'; + cell += ''; + cell += ''; + cell += '
'; + cell += ''; + cell += '' + site.title + ''; + cell += '' + (site.description || site.url) + ''; + cell += '
'; + cell += '
' + 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 += '
{ + el += cell(site); + }); + el += '
'; + } + } + } + if (args.group && args.group.length > 0) { + if (args.group == groupId) { + f(); + } + } else { + f(); + } + } + el += '
'; + return el; +}); diff --git a/source/css/_layout/pages/friends.styl b/source/css/_layout/pages/friends.styl deleted file mode 100644 index e053c6e..0000000 --- a/source/css/_layout/pages/friends.styl +++ /dev/null @@ -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 diff --git a/source/css/_layout/tag-plugins/friends.styl b/source/css/_layout/tag-plugins/friends.styl new file mode 100644 index 0000000..8853fde --- /dev/null +++ b/source/css/_layout/tag-plugins/friends.styl @@ -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 diff --git a/source/css/_layout/tag-plugins/site-card.styl b/source/css/_layout/tag-plugins/site-card.styl deleted file mode 100644 index 04f97bb..0000000 --- a/source/css/_layout/tag-plugins/site-card.styl +++ /dev/null @@ -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 diff --git a/source/css/_layout/tag-plugins/sites.styl b/source/css/_layout/tag-plugins/sites.styl new file mode 100644 index 0000000..fbcaece --- /dev/null +++ b/source/css/_layout/tag-plugins/sites.styl @@ -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 diff --git a/source/js/main.js b/source/js/main.js index 37db151..8c57daa 100644 --- a/source/js/main.js +++ b/source/js/main.js @@ -278,11 +278,20 @@ if (stellar.plugins.lazyload) { } // issuesjs -if (stellar.plugins.issuesjs) { - const issues_api = document.getElementById('issues-api'); +if (stellar.plugins.sitesjs) { + const issues_api = document.getElementById('sites-api'); if (issues_api != undefined) { 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}) }) } } diff --git a/source/js/issues.js b/source/js/plugins/friends.js similarity index 55% rename from source/js/issues.js rename to source/js/plugins/friends.js index 697ae1f..dedc657 100644 --- a/source/js/issues.js +++ b/source/js/plugins/friends.js @@ -1,5 +1,5 @@ -const IssuesAPI = { - requestIssuesAPI(url, callback, timeout) { +const friendsjs = { + requestAPI: (url, callback, timeout) => { let retryTimes = 5; function request() { return new Promise((resolve, reject) => { @@ -42,45 +42,43 @@ const IssuesAPI = { } request(); }, - getIssuesAPIForFriends(cfg) { + layout: (cfg) => { const el = $(cfg.el)[0]; - $(el).append('

正在加载

'); - this.requestIssuesAPI(cfg.api, function(data) { - $(el).find('.loading').remove(); + $(el).append('

'); + friendsjs.requestAPI(cfg.api, function(data) { + $(el).find('.loading-wrap').remove(); const arr = data.content; arr.forEach((item, i) => { var user = '
'; user += ''; - user += ''; + user += ''; user += '
' + item.title + '
'; user += '
'; user += '
'; $(el).find('.group-body').append(user); }); }, function() { - $(el).find('.loading i').remove(); - $(el).find('.loading p').text('加载失败,请稍后重试。'); + $(el).find('.loading-wrap svg').remove(); + $(el).find('.loading-wrap p').text('加载失败,请稍后重试。'); }); }, - request() { - const els = document.getElementsByClassName('issues-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; - this.getIssuesAPIForFriends(cfg); - } - } -}; +} + $(function () { - IssuesAPI.request(); + const els = document.getElementsByClassName('friendsjs-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; + friendsjs.layout(cfg); + } }); diff --git a/source/js/plugins/sites.js b/source/js/plugins/sites.js new file mode 100644 index 0000000..969c16c --- /dev/null +++ b/source/js/plugins/sites.js @@ -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('

'); + sitesjs.requestAPI(cfg.api, function(data) { + $(el).find('.loading-wrap').remove(); + const arr = data.content; + arr.forEach((item, i) => { + var cell = '
'; + cell += ''; + cell += ''; + cell += '
'; + cell += ''; + cell += '' + item.title + ''; + cell += '' + (item.description || item.url) + ''; + cell += '
'; + cell += '
'; + cell += '
'; + $(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); + } +});