[feat] plugins refactoring

This commit is contained in:
xaoxuu 2024-02-12 23:07:56 +08:00
parent 97d3bb4efb
commit 23aab88e04
71 changed files with 1119 additions and 1485 deletions

View File

@ -289,11 +289,6 @@ footer:
######## Tag Plugins ########
tag_plugins:
# {% link %}
linkcard:
# 设置 api 可以自动提取网页标题、图标服务部署方法https://github.com/xaoxuu/site-info-api/
# 接口测试通过后,把按钮的 href 部分替换成 ${href} 之后填写到下方例如https://api.vlts.cc/site_info/v1?url=${href}
api:
# {% box %} / {% note %}
note:
default_color: '' # light, dark, red, orange, yellow, green, cyan, blue, purple, warning, error
@ -366,43 +361,83 @@ tag_plugins:
size: mix # s / m / l / xl / mix
ratio: square # origin / square
######## JS Plugins ########
plugins:
## required plugins ##
# jquery
# 基础依赖
dependencies:
jquery: https://cdn.bootcdn.net/ajax/libs/jquery/3.7.1/jquery.min.js
# stellar api
stellar:
sites: /js/plugins/sites.js
friends: /js/plugins/friends.js
ghinfo: /js/plugins/ghinfo.js
timeline: /js/plugins/timeline.js
linkcard: /js/plugins/linkcard.js
fcircle: /js/plugins/fcircle.js
weibo: /js/plugins/weibo.js
memos: /js/plugins/memos.js
marked: /js/plugins/marked.js
marked: https://cdn.bootcdn.net/ajax/libs/marked/4.0.18/marked.min.js
## optional plugins ##
# 内置服务,按需加载(页面内用到了就会加载,没有用到就不会加载)
services:
# 外部 md 渲染
mdrender:
js: /js/services/mdrender.js
# 数据填充类
siteinfo:
js: /js/services/siteinfo.js
# 设置 api 可以自动提取网页标题、图标服务部署方法https://github.com/xaoxuu/site-info-api/
# 接口测试通过后,把按钮的 href 部分替换成 ${href} 之后填写到下方例如https://api.vlts.cc/site_info/v1?url=${href}
api:
ghinfo:
js: /js/services/ghinfo.js
# 网格布局类
sites:
js: /js/services/sites.js
friends:
js: /js/services/friends.js
# 列表布局类
timeline:
js: /js/services/timeline.js
fcircle:
js: /js/services/fcircle.js
weibo:
js: /js/services/weibo.js
memos:
js: /js/services/memos.js
# 扩展插件接入方法:(插件名下面用 #plugin# 代替)
# 1. 在这里增加 #plugin# 配置,至少赢含有 enable 字段,默认为空(不启用)
# 2. 新建文件 layout/_plugins/#plugin#.ejs 文件中设置编写加载代码。
# 2.1. 在该文件中可以直接使用 conf 来读取用户在【步骤 1】填写的配置字段内容
# 2.2. 如果需要引入 css 或 js可以使用 utils.css(xxx)、utils.js(xxx),具体可参考 layout/_plugins/fancybox.ejs
# 2.3. 如果需要本地 js 文件,请放入 /source/js/plugins 文件夹中引入方式为utils.js('/js/plugins/xxx.js');
# 3. 如果这个插件只需要引入外部文件,可以在【步骤 1】处增加 inject 字段,而无需进入【步骤 2】创建 ejs参考 katex
plugins:
# preload
preload:
enable: true
service: flying_pages # flying_pages
flying_pages: https://cdn.bootcdn.net/ajax/libs/flying-pages/2.1.2/flying-pages.min.js
# image lazyload
# lazyload
# https://www.npmjs.com/package/vanilla-lazyload
lazyload:
enable: true # [hexo clean && hexo s] is required after changing this value.
js: https://cdn.bootcdn.net/ajax/libs/vanilla-lazyload/17.8.4/lazyload.min.js
transition: fade # blur, fade
# https://fancyapps.com/docs/ui/fancybox/
# available for {% image xxx %}
fancybox:
enable: true
loader: /js/plugins/fancybox-loader.js
js: https://cdn.bootcdn.net/ajax/libs/fancyapps-ui/5.0.22/fancybox/fancybox.umd.min.js
css: https://cdn.bootcdn.net/ajax/libs/fancyapps-ui/5.0.22/fancybox/fancybox.min.css
# 让 md 语法图片支持放大可以这样写: .md-text img:not([class]), .md-text .image img
# 可以处理评论区的图片(不支持 iframe 类评论系统)例如:
# 使用 twikoo 评论可以写: .tk-content img:not([class*="emo"])
# 使用 waline 评论可以写: #waline_container .vcontent img
selector: .timenode p>img # 多个选择器用英文逗号隔开
# swiper
swiper:
enable: true
css: https://unpkg.com/swiper@10.3.1/swiper-bundle.min.css
js: https://unpkg.com/swiper@10.3.1/swiper-bundle.min.js
# https://scrollrevealjs.org/api/reveal.html
scrollreveal:
enable: #true
@ -411,33 +446,28 @@ plugins:
duration: 800 # ms
interval: 100 # ms
scale: 1 # 0.1~1
# https://fancyapps.com/docs/ui/fancybox/
# available for {% image xxx %}
fancybox:
enable: true
js: https://cdn.bootcdn.net/ajax/libs/fancyapps-ui/5.0.22/fancybox/fancybox.umd.min.js
css: https://cdn.bootcdn.net/ajax/libs/fancyapps-ui/5.0.22/fancybox/fancybox.min.css
# 让 md 语法图片支持放大可以这样写: .md-text img:not([class]), .md-text .image img
# 可以处理评论区的图片(不支持 iframe 类评论系统)例如:
# 使用 twikoo 评论可以写: .tk-content img:not([class*="emo"])
# 使用 waline 评论可以写: #waline_container .vcontent img
selector: # 多个选择器用英文逗号隔开
# swiper
swiper:
enable: true
css: https://unpkg.com/swiper@10.3/swiper-bundle.min.css
js: https://unpkg.com/swiper@10.3/swiper-bundle.min.js
# 赫蹏 (Heti) - 专为中文网页内容设计的排版样式增强
# https://github.com/sivan/heti
heti:
enable: false # 此插件会和代码块冲突,仅适用于纯中文博主。
css: https://unpkg.com/heti@0.9.2/umd/heti.min.css
js: https://unpkg.com/heti@0.9.2/umd/heti-addon.min.js
# AI 摘要
# https://github.com/zhheo/Post-Abstract-AI
tianli_gpt:
enable: #true
js: https://cdn1.tianli0.top/gh/zhheo/Post-Abstract-AI@0.15.2/tianli_gpt.min.js
field: post # all, post, wiki
api: 5Q5mpqRK5DkwT1X9Gi5e # tianli_gpt key
limit: 1000 # 设置提交的字数限制默认为1000字上限为5000超过5000字符将被截断不能为空
typingAnimate: true # 打字机动画
# Katex - The fastest math typesetting library for the web
# https://katex.org/docs/autorender.html
# https://github.com/KaTeX/KaTeX
# 使用 hexo-renderer-markdown-it-plus 作为公式渲染器npm uninstall hexo-renderer-marked --save npm install hexo-renderer-markdown-it-plus --save
katex:
enable: #true # 可以在特定文章的 front-matter 中设置 katex: true 来开启,也可以在这里设置全局开启
inject: |
<link rel="stylesheet" href="https://gcore.jsdelivr.net/npm/katex@0.16.4/dist/katex.min.css" integrity="sha384-vKruj+a13U8yHIkAyGgK1J3ArTLzrFGBbBc0tDp4ad/EyewESeXE/Iv67Aj8gKZ0" crossorigin="anonymous">
<script defer src="https://gcore.jsdelivr.net/npm/katex@0.16.4/dist/katex.min.js" integrity="sha384-PwRUT/YqbnEjkZO0zZxNqcxACrXe+j766U2amXcgMg5457rve2Y7I6ZJSm2A0mS4" crossorigin="anonymous"></script>
<script defer src="https://gcore.jsdelivr.net/npm/katex@0.16.4/dist/contrib/auto-render.min.js" integrity="sha384-+VBxd3r6XgURycqtZ117nYw44OOcIax56Z4dCRWbxyPt0Koah1uHoK0o4+/RRE05" crossorigin="anonymous"onload="renderMathInElement(document.body);"></script>
# MathJax
# 需在Markdown文件开头加入mathjax: true
# 推荐使用Pandoc: npm uninstall hexo-renderer-marked --save & npm install hexo-renderer-pandoc --save
@ -445,16 +475,6 @@ plugins:
enable: # true # 可以在特定文章的 front-matter 中设置 mathjax: true 来开启,也可以在这里设置全局开启
js: https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.6/MathJax.js?config=TeX-AMS-MML_HTMLorMML
# Katex - The fastest math typesetting library for the web
# https://katex.org/docs/autorender.html
# https://github.com/KaTeX/KaTeX
# 使用 hexo-renderer-markdown-it-plus 作为公式渲染器npm uninstall hexo-renderer-marked --save npm install hexo-renderer-markdown-it-plus --save
katex:
enable: # true # 可以在特定文章的 front-matter 中设置 katex: true 来开启,也可以在这里设置全局开启
min_css: <link rel="stylesheet" href="https://gcore.jsdelivr.net/npm/katex@0.16.4/dist/katex.min.css" integrity="sha384-vKruj+a13U8yHIkAyGgK1J3ArTLzrFGBbBc0tDp4ad/EyewESeXE/Iv67Aj8gKZ0" crossorigin="anonymous">
min_js: <script defer src="https://gcore.jsdelivr.net/npm/katex@0.16.4/dist/katex.min.js" integrity="sha384-PwRUT/YqbnEjkZO0zZxNqcxACrXe+j766U2amXcgMg5457rve2Y7I6ZJSm2A0mS4" crossorigin="anonymous"></script>
auto_render_min_js: <script defer src="https://gcore.jsdelivr.net/npm/katex@0.16.4/dist/contrib/auto-render.min.js" integrity="sha384-+VBxd3r6XgURycqtZ117nYw44OOcIax56Z4dCRWbxyPt0Koah1uHoK0o4+/RRE05" crossorigin="anonymous"onload="renderMathInElement(document.body);"></script>
# Mermaid - markdwon to flow chart, seq chart, class chart ...
# 需要安装 npm install --save hexo-filter-mermaid-diagrams
# 使用时 需要在Markdown文件开头加入 mermaid: true
@ -471,23 +491,22 @@ plugins:
js: https://cdn.jsdelivr.net/npm/mermaid@v9/dist/mermaid.min.js
# Available themes: default | dark | forest | neutral
theme: neutral
# 代码块复制按钮
copycode:
enable: true
js: /js/plugins/copycode.js
default_text: 'Copy'
success_text: 'Copied'
toast: 复制成功
# AI 摘要
# https://github.com/zhheo/Post-Abstract-AI
tianli_gpt:
enable: false
field: post # all, post, wiki
api: 5Q5mpqRK5DkwT1X9Gi5e # tianli_gpt key
limit: 1000 # 设置提交的字数限制默认为1000字上限为5000超过5000字符将被截断不能为空
typingAnimate: true # 打字机动画
# 赫蹏 (Heti) - 专为中文网页内容设计的排版样式增强
# https://github.com/sivan/heti
heti:
enable: false # 此插件会和代码块冲突,仅适用于纯中文博主。
css: https://unpkg.com/heti@0.9.2/umd/heti.min.css
js: https://unpkg.com/heti@0.9.2/umd/heti-addon.min.js
style:
prefers_theme: auto # auto / light / dark

View File

@ -16,4 +16,4 @@ page.robots = 'none';
<br><br>
<a class='button' id='back' href="<%- config.root %>"><%- __('page.error.action') %></a>
</article>
<%- partial('_partial/plugins/comments/layout') %>
<%- partial('_partial/comments/layout') %>

View File

@ -1,8 +1,8 @@
<script>
function load_artalk() {
if (!document.querySelectorAll("#artalk_container")[0]) return;
stellar.loadCSS('<%- theme.comments.artalk.css %>');
stellar.loadScript('<%- theme.comments.artalk.js %>', {defer: true}).then(function () {
utils.css('<%- theme.comments.artalk.css %>');
utils.js('<%- theme.comments.artalk.js %>', {defer: true}).then(function () {
const el = document.getElementById("artalk_container");
var path = el.getAttribute('comment_id');
if (!path) {

View File

@ -1,5 +1,5 @@
<script>
function loadJS() {
window.addEventListener('DOMContentLoaded', (event) => {
const els = document.querySelectorAll("#comments #giscus");
if (els.length === 0) return;
els.forEach((el, i) => {
@ -18,8 +18,5 @@
}
el.appendChild(script);
});
}
window.addEventListener('DOMContentLoaded', (event) => {
loadJS();
});
</script>

View File

@ -1,7 +1,7 @@
<script>
function load_twikoo() {
if (!document.querySelectorAll("#twikoo_container")[0]) return;
stellar.loadScript('<%- theme.comments.twikoo.js %>', {defer: true}).then(function () {
utils.js('<%- theme.comments.twikoo.js %>', {defer: true}).then(function () {
const el = document.getElementById("twikoo_container");
var path = el.getAttribute('comment_id');
if (!path) {

View File

@ -1,8 +1,8 @@
<script>
function load_comment(){
if(!document.getElementById("waline_container"))return;
stellar.loadCSS('<%- theme.comments.waline.css %>');
stellar.loadScript('<%- theme.comments.waline.js %>', {defer:true}).then(function () {
utils.css('<%- theme.comments.waline.css %>');
utils.js('<%- theme.comments.waline.js %>', {defer:true}).then(function () {
const el = document.getElementById("waline_container");
var path = el.getAttribute('comment_id');
if (!path) {

View File

@ -128,6 +128,5 @@ function custom_inject() {
<%- css(theme.style.codeblock.highlightjs_theme) %>
<% } %>
<%- partial('plugins/parser/head') %>
<%- custom_inject() %>
</head>

View File

@ -51,7 +51,7 @@ function div_default() {
// 摘要
el += '<div class="excerpt';
if (theme.plugins.heti && theme.plugins.heti.enable) {
if (theme.plugins.heti?.enable) {
el += ' heti';
}
el += '">';

View File

@ -1,9 +0,0 @@
<% if (page.layout === 'post' || (page.wiki?.length > 0)) { %>
<script>
let tianliGPT_postSelector = 'article.content';
let tianliGPT_key = '<%= theme.plugins.tianli_gpt.api %>';
let tianliGPT_typingAnimate = '<%= theme.plugins.tianli_gpt.typingAnimate %>';
let tianliGPT_wordLimit = <%= theme.plugins.tianli_gpt.limit %>;
</script>
<script defer src="https://cdn1.tianli0.top/gh/zhheo/Post-Abstract-AI@0.15.2/tianli_gpt.min.js"></script>
<% } %>

View File

@ -1,3 +0,0 @@
<% if (page.katex == true || theme.plugins.katex.enable == true) { %>
<%- partial('katex/head') %>
<% } %>

View File

@ -1,3 +0,0 @@
<% if (theme.plugins.katex) { %>
<%- theme.plugins.katex.min_css %>
<% } %>

View File

@ -1,4 +0,0 @@
<% if (theme.plugins.katex) { %>
<%- theme.plugins.katex.min_js %>
<%- theme.plugins.katex.auto_render_min_js %>
<% } %>

View File

@ -1,29 +0,0 @@
<script type="text/javascript" src="<%- theme.plugins.mermaid.js %>"></script>
<script>
var mermaid_config = {
startOnLoad: true,
theme:
"<%- theme.style.darkmode %>" == "auto" &&
window.matchMedia("(prefers-color-scheme: dark)").matches
? "dark"
: "<%- theme.plugins.mermaid.theme %>",
logLevel: 3,
themeVariables: {
darkMode: true
},
flowchart: {
useMaxWidth: false,
htmlLabels: true,
curve: "linear"
},
gantt: {
axisFormat: "%Y/%m/%d"
},
sequence: {
actorMargin: 50
}
}
if (window.mermaid) {
mermaid.initialize(mermaid_config);
}
</script>

View File

@ -1,9 +0,0 @@
<% if (page.katex == true || theme.plugins.katex.enable) { %>
<%- partial('katex/script') %>
<% } %>
<% if (page.mathjax == true || theme.plugins.mathjax.enable) { %>
<%- partial('mathjax/script') %>
<% } %>
<% if (page.mermaid == true || theme.plugins.mermaid.enable) { %>
<%- partial('mermaid/script') %>
<% } %>

View File

@ -0,0 +1,32 @@
<%
function custom_inject() {
var el = '';
for (let item of (config.inject?.script || [])) {
el += item;
}
for (let item of (theme.inject?.script || [])) {
el += item;
}
for (let item of (page.inject?.script || [])) {
el += item;
}
return el;
}
%>
<%- partial('scripts/defines') %>
<%- partial('scripts/utils') %>
<%- partial('scripts/sidebar') %>
<!-- required -->
<script src="<%- `${theme.stellar.main_js}?v=${stellar_info('version')}` %>" async></script>
<!-- optional -->
<%- partial('comments/script') %>
<%- partial('scripts/services') %>
<%- partial('../_plugins/index') %>
<!-- inject -->
<%- custom_inject() %>

View File

@ -0,0 +1,31 @@
<script type="text/javascript">
const ctx = {
date_suffix: {
just: `<%- __('meta.date_suffix.just') %>`,
min: `<%- __('meta.date_suffix.min') %>`,
hour: `<%- __('meta.date_suffix.hour') %>`,
day: `<%- __('meta.date_suffix.day') %>`,
},
root : `<%- config.root %>`,
};
// required plugins (only load if needs)
if (`<%- theme.search.service %>`) {
ctx.search = {};
ctx.search.service = `<%- theme.search.service %>`;
if (ctx.search.service == 'local_search') {
let service_obj = Object.assign({}, `<%- JSON.stringify(theme.search.local_search) %>`);
ctx.search[ctx.search.service] = service_obj;
}
}
const def = {
avatar: `<%- theme.default.avatar %>`,
cover: `<%- theme.default.cover %>`,
};
const deps = {
jquery: `<%- url_for(theme.dependencies.jquery) %>`,
marked: `<%- url_for(theme.dependencies.marked) %>`
}
</script>

View File

@ -1,175 +0,0 @@
<%
function custom_inject() {
var el = '';
for (let item of (config.inject?.script || [])) {
el += item;
}
for (let item of (theme.inject?.script || [])) {
el += item;
}
for (let item of (page.inject?.script || [])) {
el += item;
}
return el;
}
%>
<script type="text/javascript">
const stellar = {
// 懒加载 css https://github.com/filamentgroup/loadCSS
loadCSS: (href, before, media, attributes) => {
var doc = window.document;
var ss = doc.createElement("link");
var ref;
if (before) {
ref = before;
} else {
var refs = (doc.body || doc.getElementsByTagName("head")[0]).childNodes;
ref = refs[refs.length - 1];
}
var sheets = doc.styleSheets;
if (attributes) {
for (var attributeName in attributes) {
if (attributes.hasOwnProperty(attributeName)) {
ss.setAttribute(attributeName, attributes[attributeName]);
}
}
}
ss.rel = "stylesheet";
ss.href = href;
ss.media = "only x";
function ready(cb) {
if (doc.body) {
return cb();
}
setTimeout(function () {
ready(cb);
});
}
ready(function () {
ref.parentNode.insertBefore(ss, before ? ref : ref.nextSibling);
});
var onloadcssdefined = function (cb) {
var resolvedHref = ss.href;
var i = sheets.length;
while (i--) {
if (sheets[i].href === resolvedHref) {
return cb();
}
}
setTimeout(function () {
onloadcssdefined(cb);
});
};
function loadCB() {
if (ss.addEventListener) {
ss.removeEventListener("load", loadCB);
}
ss.media = media || "all";
}
if (ss.addEventListener) {
ss.addEventListener("load", loadCB);
}
ss.onloadcssdefined = onloadcssdefined;
onloadcssdefined(loadCB);
return ss;
},
// 从 butterfly 和 volantis 获得灵感
loadScript: (src, opt) => new Promise((resolve, reject) => {
var script = document.createElement('script');
if (src.startsWith('/')){
src = stellar.config.root + src.substring(1);
}
script.src = src;
if (opt) {
for (let key of Object.keys(opt)) {
script[key] = opt[key]
}
} else {
// 默认异步,如果需要同步,第二个参数传入 {} 即可
script.async = true
}
script.onerror = reject
script.onload = script.onreadystatechange = function() {
const loadState = this.readyState
if (loadState && loadState !== 'loaded' && loadState !== 'complete') return
script.onload = script.onreadystatechange = null
resolve()
}
document.head.appendChild(script)
}),
// https://github.com/jerryc127/hexo-theme-butterfly
jQuery: (fn) => {
if (typeof jQuery === 'undefined') {
stellar.loadScript(stellar.plugins.jQuery).then(fn)
} else {
fn()
}
}
};
stellar.version = '<%- theme.stellar.version %>';
stellar.github = 'https://github.com/xaoxuu/hexo-theme-stellar/tree/<%- theme.stellar.version %>';
stellar.config = {
date_suffix: {
just: '<%- __('meta.date_suffix.just') %>',
min: '<%- __('meta.date_suffix.min') %>',
hour: '<%- __('meta.date_suffix.hour') %>',
day: '<%- __('meta.date_suffix.day') %>',
},
root : '<%- config.root %>',
};
// required plugins (only load if needs)
stellar.plugins = {
jQuery: '<%- url_for(theme.plugins.jquery || "https://gcore.jsdelivr.net/npm/jquery@3.6.2/dist/jquery.min.js") %>'
};
if ('<%- theme.search.service %>') {
stellar.search = {};
stellar.search.service = '<%- theme.search.service %>';
if (stellar.search.service == 'local_search') {
let service_obj = Object.assign({}, <%- JSON.stringify(theme.search.local_search) %>);
stellar.search[stellar.search.service] = service_obj;
}
}
// stellar js
stellar.plugins.stellar = Object.assign(<%- JSON.stringify(theme.plugins.stellar) %>);
stellar.plugins.marked = Object.assign(<%- JSON.stringify(theme.plugins.marked) %>);
// optional plugins
if ('<%- theme.plugins.lazyload.enable %>' == 'true') {
stellar.plugins.lazyload = Object.assign(<%- JSON.stringify(theme.plugins.lazyload) %>);
}
if ('<%- theme.plugins.swiper.enable %>' == 'true') {
stellar.plugins.swiper = Object.assign(<%- JSON.stringify(theme.plugins.swiper) %>);
}
if ('<%- theme.plugins.scrollreveal.enable %>' == 'true') {
stellar.plugins.scrollreveal = Object.assign(<%- JSON.stringify(theme.plugins.scrollreveal) %>);
}
if ('<%- theme.plugins.preload.enable %>' == 'true') {
stellar.plugins.preload = Object.assign(<%- JSON.stringify(theme.plugins.preload) %>);
}
if ('<%- theme.plugins.fancybox.enable %>' == 'true') {
stellar.plugins.fancybox = Object.assign(<%- JSON.stringify(theme.plugins.fancybox) %>);
}
if ('<%- theme.plugins.heti.enable %>' == 'true') {
stellar.plugins.heti = Object.assign(<%- JSON.stringify(theme.plugins.heti) %>);
}
if ('<%- theme.plugins.copycode.enable %>' == 'true') {
stellar.plugins.copycode = Object.assign(<%- JSON.stringify(theme.plugins.copycode) %>);
}
</script>
<!-- required -->
<script src="<%- `${theme.stellar.main_js}?v=${stellar_info('version')}` %>" async></script>
<!-- optional -->
<%- partial('../plugins/comments/script') %>
<%- partial('../plugins/parser/script') %>
<!-- inject -->
<%- custom_inject() %>

View File

@ -0,0 +1,39 @@
<script>
ctx.services = {
fcircle: `<%- theme.services.fcircle?.js %>`,
friends: `<%- theme.services.friends?.js %>`,
ghinfo: `<%- theme.services.ghinfo?.js %>`,
siteinfo: `<%- theme.services.siteinfo?.js %>`,
mdrender: `<%- theme.services.mdrender?.js %>`,
memos: `<%- theme.services.memos?.js %>`,
sites: `<%- theme.services.sites?.js %>`,
timeline: `<%- theme.services.timeline?.js %>`,
weibo: `<%- theme.services.weibo?.js %>`,
}
window.addEventListener('DOMContentLoaded', (event) => {
for (let id of Object.keys(ctx.services)) {
const js = ctx.services[id];
if (id == 'siteinfo') {
const els = document.querySelectorAll('a.link-card[cardlink]');
if (els?.length > 0) {
utils.js(js, { defer: true }).then(function () {
setCardLink(els);
});
}
} else {
const els = document.getElementsByClassName(`stellar-${id}-api`);
if (els?.length > 0) {
utils.jq(() => {
if (id == 'timeline' || 'memos' || 'marked') {
utils.js(deps.marked).then(function () {
utils.js(js, { defer: true });
});
} else {
utils.js(js, { defer: true });
}
});
}
}
}
});
</script>

View File

@ -0,0 +1,25 @@
<script>
const sidebar = {
leftbar: () => {
if (l_body) {
l_body.toggleAttribute('leftbar');
l_body.removeAttribute('rightbar');
}
},
rightbar: () => {
if (l_body) {
l_body.toggleAttribute('rightbar');
l_body.removeAttribute('leftbar');
}
},
dismiss: () => {
if (l_body) {
l_body.removeAttribute('leftbar');
l_body.removeAttribute('rightbar');
}
},
toggleTOC: () => {
document.querySelector('#data-toc').classList.toggle('collapse');
}
}
</script>

View File

@ -0,0 +1,158 @@
<script type="text/javascript">
const utils = {
// 懒加载 css https://github.com/filamentgroup/loadCSS
css: (href, before, media, attributes) => {
var doc = window.document;
var ss = doc.createElement("link");
var ref;
if (before) {
ref = before;
} else {
var refs = (doc.body || doc.getElementsByTagName("head")[0]).childNodes;
ref = refs[refs.length - 1];
}
var sheets = doc.styleSheets;
if (attributes) {
for (var attributeName in attributes) {
if (attributes.hasOwnProperty(attributeName)) {
ss.setAttribute(attributeName, attributes[attributeName]);
}
}
}
ss.rel = "stylesheet";
ss.href = href;
ss.media = "only x";
function ready(cb) {
if (doc.body) {
return cb();
}
setTimeout(function () {
ready(cb);
});
}
ready(function () {
ref.parentNode.insertBefore(ss, before ? ref : ref.nextSibling);
});
var onloadcssdefined = function (cb) {
var resolvedHref = ss.href;
var i = sheets.length;
while (i--) {
if (sheets[i].href === resolvedHref) {
return cb();
}
}
setTimeout(function () {
onloadcssdefined(cb);
});
};
function loadCB() {
if (ss.addEventListener) {
ss.removeEventListener("load", loadCB);
}
ss.media = media || "all";
}
if (ss.addEventListener) {
ss.addEventListener("load", loadCB);
}
ss.onloadcssdefined = onloadcssdefined;
onloadcssdefined(loadCB);
return ss;
},
js: (src, opt) => new Promise((resolve, reject) => {
var script = document.createElement('script');
if (src.startsWith('/')){
src = ctx.root + src.substring(1);
}
script.src = src;
if (opt) {
for (let key of Object.keys(opt)) {
script[key] = opt[key]
}
} else {
// 默认异步,如果需要同步,第二个参数传入 {} 即可
script.async = true
}
script.onerror = reject
script.onload = script.onreadystatechange = function() {
const loadState = this.readyState
if (loadState && loadState !== 'loaded' && loadState !== 'complete') return
script.onload = script.onreadystatechange = null
resolve()
}
document.head.appendChild(script)
}),
jq: (fn) => {
if (typeof jQuery === 'undefined') {
utils.js(deps.jquery).then(fn)
} else {
fn()
}
},
onLoading: (el) => {
if (el) {
$(el).append('<div class="loading-wrap"><svg xmlns="http://www.w3.org/2000/svg" width="2em" height="2em" 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>');
}
},
onLoadSuccess: (el) => {
if (el) {
$(el).find('.loading-wrap').remove();
}
},
onLoadFailure: (el) => {
if (el) {
$(el).find('.loading-wrap svg').remove();
$(el).find('.loading-wrap').append('<svg xmlns="http://www.w3.org/2000/svg" width="2em" height="2em" 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');
}
},
request: (el, url, callback, onFailure) => {
let retryTimes = 3;
utils.onLoading(el);
function req() {
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) {
onFailure();
}
}
}, 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;
utils.onLoadSuccess(el);
callback(data);
}).catch(function(error) {
if (retryTimes > 0) {
retryTimes -= 1;
setTimeout(() => {
req();
}, 5000);
} else {
utils.onLoadFailure(el);
onFailure();
}
});
});
}
req();
},
};
</script>

View File

@ -0,0 +1,13 @@
<script>
document.addEventListener('DOMContentLoaded', function () {
window.codeElements = document.querySelectorAll('.code');
if (window.codeElements.length > 0) {
ctx.copycode = {
default_text: `<%- conf.default_text %>`,
success_text: `<%- conf.success_text %>`,
toast: `<%- conf.toast %>`,
};
utils.js('/js/plugins/copycode.js');
}
});
</script>

View File

@ -0,0 +1,32 @@
<script>
ctx.fancybox = {
selector: `<%- conf.selector %>`,
css: `<%- conf.css %>`,
js: `<%- conf.js %>`
};
var selector = '[data-fancybox]:not(.error)';
if (ctx.fancybox.selector) {
selector += `, ${ctx.fancybox.selector}`
}
var needFancybox = document.querySelectorAll(selector).length !== 0;
if (!needFancybox) {
const els = document.getElementsByClassName('stellar-memos-api');
if (els != undefined && els.length > 0) {
needFancybox = true;
}
}
if (needFancybox) {
utils.css(ctx.fancybox.css);
utils.js(ctx.fancybox.js, { defer: true }).then(function () {
Fancybox.bind(selector, {
hideScrollbar: false,
Thumbs: {
autoStart: false,
},
caption: (fancybox, slide) => {
return slide.triggerEl.alt || null
}
});
})
}
</script>

21
layout/_plugins/heti.ejs Normal file
View File

@ -0,0 +1,21 @@
<script>
utils.css(`<%- conf.css %>`);
utils.js(`<%- conf.js %>`, { defer: true }).then(function () {
const heti = new Heti('.heti');
// Copied from heti.autoSpacing() without DOMContentLoaded.
// https://github.com/sivan/heti/blob/eadee6a3b748b3b7924a9e7d5b395d4bce479c9a/js/heti-addon.js
//
// We managed to minimize the code modification to ensure .autoSpacing()
// is synced with upstream; therefore, we use `.bind()` to emulate the
// behavior of .autoSpacing() so we can even modify almost no code.
void (function () {
const $$rootList = document.querySelectorAll(this.rootSelector)
for (let $$root of $$rootList) {
this.spacingElement($$root)
}
}).bind(heti)();
});
</script>

24
layout/_plugins/index.ejs Normal file
View File

@ -0,0 +1,24 @@
<%
function loadPlugins() {
var el = ''
// search
if (theme.search[theme.search.service]) {
el += partial(`search/${theme.search.service}`, {conf: theme.search[theme.search.service]});
}
// others
for (let id of Object.keys(theme.plugins)) {
const conf = Object.assign({}, theme.plugins[id], page[id])
if (page[id] == true || conf.enable) {
if (conf.inject?.length > 0) {
el += conf.inject
} else {
el += partial(`${id}`, {conf: conf})
}
}
}
return el
}
%>
<%- loadPlugins() %>

View File

@ -0,0 +1,21 @@
<script defer src="<%- conf.js %>"></script>
<script>
// https://www.npmjs.com/package/vanilla-lazyload
// Set the options globally
// to make LazyLoad self-initialize
window.lazyLoadOptions = {
elements_selector: ".lazy",
};
// Listen to the initialization event
// and get the instance of LazyLoad
window.addEventListener(
"LazyLoad::Initialized",
function (event) {
window.lazyLoadInstance = event.detail.instance;
},
false
);
document.addEventListener('DOMContentLoaded', function () {
window.lazyLoadInstance?.update();
});
</script>

View File

@ -1,4 +1,4 @@
<script type="text/javascript" src="<%- theme.plugins.mathjax.js %>"></script>
<script type="text/javascript" src="<%- conf.js %>"></script>
<script type="text/x-mathjax-config">
MathJax.Hub.Config({
tex2jax: {

29
layout/_plugins/mermaid.ejs Executable file
View File

@ -0,0 +1,29 @@
<script defer type="text/javascript" src="<%- conf.js %>"></script>
<script>
window.addEventListener('DOMContentLoaded', (event) => {
var mermaid_config = {
startOnLoad: true,
theme:
"<%- theme.style.darkmode %>" == "auto" &&
window.matchMedia("(prefers-color-scheme: dark)").matches
? "dark"
: "<%- conf.theme %>",
logLevel: 3,
themeVariables: {
darkMode: true
},
flowchart: {
useMaxWidth: false,
htmlLabels: true,
curve: "linear"
},
gantt: {
axisFormat: "%Y/%m/%d"
},
sequence: {
actorMargin: 50
}
}
mermaid.initialize(mermaid_config);
});
</script>

View File

@ -0,0 +1,9 @@
<script>
window.FPConfig = {
delay: 0,
ignoreKeywords: [],
maxRPS: 5,
hoverDelay: 25
};
</script>
<script defer src="<%- conf.flying_pages %>"></script>

View File

@ -0,0 +1,15 @@
<script defer src="<%- conf.js %>"></script>
<script>
window.addEventListener('DOMContentLoaded', (event) => {
const slideUp = {
distance: `<%- conf.distance %>`,
duration: `<%- conf.duration %>`,
interval: `<%- conf.interval %>`,
scale: `<%- conf.scale %>`,
opacity: 0,
easing: "ease-out"
};
ScrollReveal().reveal('.l_left .slide-up', slideUp);
ScrollReveal().reveal('.l_main .slide-up', slideUp);
});
</script>

View File

@ -0,0 +1,8 @@
<script>
window.addEventListener('DOMContentLoaded', (event) => {
ctx.search = {
path: `<%- conf.path || '/search.json' %>`,
}
utils.js('/js/search/local-search.js', { defer: true });
});
</script>

View File

@ -0,0 +1,26 @@
<script>
window.addEventListener('DOMContentLoaded', (event) => {
const swiper_api = document.getElementById('swiper-api');
if (swiper_api != undefined) {
utils.css(`<%- conf.css %>`);
utils.js(`<%- conf.js %>`, { defer: true }).then(function () {
const effect = swiper_api.getAttribute('effect') || '';
var swiper = new Swiper('.swiper#swiper-api', {
slidesPerView: 'auto',
spaceBetween: 8,
centeredSlides: true,
effect: effect,
loop: true,
pagination: {
el: '.swiper-pagination',
clickable: true,
},
navigation: {
nextEl: '.swiper-button-next',
prevEl: '.swiper-button-prev',
},
});
})
}
});
</script>

View File

@ -0,0 +1,9 @@
<% if (['all', page.layout].includes(theme.plugins.tianli_gpt.field)) { %>
<script>
let tianliGPT_postSelector = 'article.content';
let tianliGPT_key = `<%= theme.plugins.tianli_gpt?.api %>`;
let tianliGPT_typingAnimate = `<%= theme.plugins.tianli_gpt?.typingAnimate %>`;
let tianliGPT_wordLimit = `<%= theme.plugins.tianli_gpt?.limit %>`;
</script>
<script defer src="<%- theme.plugins.tianli_gpt?.js %>"></script>
<% } %>

View File

@ -42,7 +42,7 @@ html += `<html lang="${page.lang}">`
html += `<body>`
html += site_background
html += partial('_partial/cover/index')
html += `<div class="l_body ${page_type} ${article_type}" id="start" layout="${page.layout}" ${indent ? 'text-indent' : ''}>`
html += `<div class="l_body s:aa ${page_type} ${article_type}" id="start" layout="${page.layout}" ${indent ? 'text-indent' : ''}>`
html += `<aside class="l_left">`
html += `<div class="leftbar-container${theme.style.leftbar?.blur ? ' leftbar-blur' : ''}">`
html += partial('_partial/sidebar/index_leftbar')
@ -60,7 +60,7 @@ html += `<html lang="${page.lang}">`
html += partial('_partial/menubtn')
html += `</div>`
html += `<div class="scripts">`
html += partial('_partial/scripts/index')
html += partial('_partial/scripts')
html += `</div>`
html += `</body>`
html += `</html>`

View File

@ -1,9 +1,7 @@
<%
const { layout } = page
// 是否使用 Heti 布局插件
const isUsingHeti = theme.plugins.heti && theme.plugins.heti.enable
// 是否使用 TianliGPT 插件
const isUsingTianliGPT = theme.plugins.tianli_gpt.enable && ['all', page.layout].includes(theme.plugins.tianli_gpt.field)
const isUsingHeti = theme.plugins.heti?.enable
// 默认的 menu_id
if (page.menu_id == null) {
@ -27,9 +25,6 @@ function articleClass() {
if (isUsingHeti) {
str += ' heti'
}
if (isUsingTianliGPT) {
str += ' '
}
return str
}
@ -52,13 +47,10 @@ function layoutDiv() {
if (layout === 'post' || page.wiki) {
el += partial('_partial/main/article/read_next')
}
if (isUsingTianliGPT) {
el += partial('_partial/plugins/ai/tianli_gpt')
}
if (layout === 'post') {
el += partial('_partial/main/article/related_posts')
}
el += partial('_partial/plugins/comments/layout')
el += partial('_partial/comments/layout')
return el
}
%>

View File

@ -14,7 +14,7 @@ module.exports = ctx => function(args) {
return '';
}
const url = full_url_for(args.url)
args.api = ctx.theme.config.tag_plugins.linkcard.api
args.api = ctx.theme.config.services.siteinfo?.api
if (args.api) {
args.api = args.api.replace('${href}', url)
}

View File

@ -101,3 +101,7 @@ article.md-text.content+.related-wrap
position: relative
svg.loading
top: 60px
iframe
border-radius: $border-card
border: none
width: 100%

View File

@ -75,6 +75,8 @@
max-width: 100%
text-align: justify
margin-top: .5rem
overflow: scroll
scrollbar(0,0)
.tab-pane
&:not(.active)
display: none

View File

@ -1,4 +1,4 @@
.md-text .tag-plugin.timeline
.tag-plugin.timeline
position: relative
padding-left: 16px
&:before
@ -16,7 +16,7 @@
&:before
display: none
.md-text .tag-plugin.timeline .timenode
.tag-plugin.timeline .timenode
position: relative
display: flex
flex-direction: column
@ -31,12 +31,8 @@
&+.timenode
margin-top: 1rem
&:hover .header
p
span
color: var(--text-p1)
.user-info
background: $color-theme
span
color: var(--card)
&:before
background: $color-theme
height: 16px
@ -49,17 +45,17 @@
position: relative
margin: 0.25rem 0
font-size: $fs-13
a.user-info span
font-weight: 600
.user-info
display: flex
align-items: center
font-size: $fs-13
font-weight: 500
color: var(--text-p1)
margin-right: 4px
margin-right: 8px
line-height: 1
border-radius: 16px
padding-right: 6px
trans2 color background
img
background: white
height: 16px
@ -67,19 +63,10 @@
display: inline
margin: 0 4px 0 0
object-fit: contain
&:hover
background: $color-hover
&,p
&,span
font-weight: 500
color: var(--text-p3)
trans1 color
line-height: 1
p
margin: 0 !important
font-size: $fs-13 !important
a
color: inherit
font-weight: inherit
&:before
content: ''
position: absolute
@ -112,11 +99,6 @@
width: 240px
.tag-plugin.timeline[api]
&.stellar-fcircle-api .timenode:hover .header
.user-info
background: inherit
span
color: inherit
a.body
display: block
color: var(--text-p1)
@ -187,6 +169,8 @@
flex-wrap: wrap
font-size: $fs-13
align-items: stretch
.left+.right
margin-left: 4px
.tag-plugin.timeline[api] .body .footer
.item
@ -202,8 +186,13 @@
margin-left: 0
&:last-child
margin-right: 0
a:hover
border-color: $color-hover
a.item
background: var(--block)
border-color: var(--block-border)
color: inherit
&:hover
background: var(--block-hover)
.reaction
border-color: var(--block)
@ -237,8 +226,9 @@
p:last-child
margin-bottom: 2px
img
margin: 0
margin: .5rem 0
max-height: 128px
cursor: zoom-in
.tag-plugin.image
display: flex
.image-bg+.image-bg

View File

@ -1,4 +1,8 @@
.widget-wrapper.timeline
.tag-plugin.timeline
padding-left: 0
&:before
left: 6px
.widget-body
overflow hidden
.body
@ -7,22 +11,23 @@
word-break: break-all
--fsp: $fsp2
.tag-plugin.timeline .timenode
z-index 1
margin-top: 0.5rem
.header
margin: 0.5rem var(--gap-padding)
txt-ellipsis()
margin: 0.25rem var(--gap-padding)
.user-info
background: var(--alpha50)
&:hover
background: $color-hover
color: var(--card)
&:before
background: none
padding-right: 0
img
display: none
.header:before
left: calc(6px - var(--gap-padding))
&+.timenode
margin-top: 0.75rem
.header p
color: var(--text-p2)
.body
border-radius: $border-card
padding: 0.5rem 1rem
p,li
--fsp: $fsp3
code
@ -35,10 +40,12 @@
.tag-plugin.timeline[api] .body .footer
background: none
a.item
border-color: var(--text)
.l_left .widget-wrapper.timeline
.tag-plugin.timeline
padding-left: 0
&:before
content: none
.l_left .widget-wrapper.timeline .body
box-shadow: none
background: var(--alpha50)

View File

@ -1,6 +1,6 @@
.widget-wrapper.toc
background: var(--site-bg)
z-index 1
z-index 3
.widget-body
position relative
&:before

View File

@ -19,13 +19,13 @@ const util = {
if (dayCount > 14) {
result = null
} else if (dayCount >= 1) {
result = parseInt(dayCount) + ' ' + stellar.config.date_suffix.day
result = parseInt(dayCount) + ' ' + ctx.date_suffix.day
} else if (hourCount >= 1) {
result = parseInt(hourCount) + ' ' + stellar.config.date_suffix.hour
result = parseInt(hourCount) + ' ' + ctx.date_suffix.hour
} else if (minuteCount >= 1) {
result = parseInt(minuteCount) + ' ' + stellar.config.date_suffix.min
result = parseInt(minuteCount) + ' ' + ctx.date_suffix.min
} else {
result = stellar.config.date_suffix.just
result = ctx.date_suffix.just
}
} else {
result = parseInt(dateDiff / day)
@ -75,33 +75,10 @@ const hud = {
const l_body = document.querySelector('.l_body');
const sidebar = {
leftbar: () => {
if (l_body) {
l_body.toggleAttribute('leftbar');
l_body.removeAttribute('rightbar');
}
},
rightbar: () => {
if (l_body) {
l_body.toggleAttribute('rightbar');
l_body.removeAttribute('leftbar');
}
},
dismiss: () => {
if (l_body) {
l_body.removeAttribute('leftbar');
l_body.removeAttribute('rightbar');
}
},
toggleTOC: () => {
document.querySelector('#data-toc').classList.toggle('collapse');
}
}
const init = {
toc: () => {
stellar.jQuery(() => {
utils.jq(() => {
const scrollOffset = 32;
var segs = [];
$("article.md-text :header").each(function (idx, node) {
@ -160,7 +137,7 @@ const init = {
})
},
sidebar: () => {
stellar.jQuery(() => {
utils.jq(() => {
$("#data-toc a.toc-link").click(function (e) {
sidebar.dismiss();
});
@ -213,203 +190,3 @@ init.toc()
init.sidebar()
init.relativeDate(document.querySelectorAll('#post-meta time'))
init.registerTabsTag()
// scrollreveal
if (stellar.plugins.scrollreveal) {
stellar.loadScript(stellar.plugins.scrollreveal.js).then(function () {
const slideUp = {
distance: stellar.plugins.scrollreveal.distance,
duration: stellar.plugins.scrollreveal.duration,
interval: stellar.plugins.scrollreveal.interval,
scale: stellar.plugins.scrollreveal.scale,
opacity: 0,
easing: "ease-out"
}
ScrollReveal().reveal('.l_left .slide-up', slideUp)
ScrollReveal().reveal('.l_main .slide-up', slideUp)
})
}
// lazyload
if (stellar.plugins.lazyload) {
stellar.loadScript(stellar.plugins.lazyload.js, { defer: true })
// https://www.npmjs.com/package/vanilla-lazyload
// Set the options globally
// to make LazyLoad self-initialize
window.lazyLoadOptions = {
elements_selector: ".lazy",
};
// Listen to the initialization event
// and get the instance of LazyLoad
window.addEventListener(
"LazyLoad::Initialized",
function (event) {
window.lazyLoadInstance = event.detail.instance;
},
false
);
document.addEventListener('DOMContentLoaded', function () {
window.lazyLoadInstance?.update();
});
}
// stellar js
if (stellar.plugins.stellar) {
for (let key of Object.keys(stellar.plugins.stellar)) {
let js = stellar.plugins.stellar[key];
if (key == 'linkcard') {
stellar.loadScript(js, { defer: true }).then(function () {
setCardLink(document.querySelectorAll('a.link-card[cardlink]'));
});
} else {
const els = document.getElementsByClassName('stellar-' + key + '-api');
if (els != undefined && els.length > 0) {
stellar.jQuery(() => {
if (key == 'timeline' || 'memos' || 'marked') {
stellar.loadScript(stellar.plugins.marked).then(function () {
stellar.loadScript(js, { defer: true });
});
} else {
stellar.loadScript(js, { defer: true });
}
})
}
}
}
}
// swiper
if (stellar.plugins.swiper) {
const swiper_api = document.getElementById('swiper-api');
if (swiper_api != undefined) {
stellar.loadCSS(stellar.plugins.swiper.css);
stellar.loadScript(stellar.plugins.swiper.js, { defer: true }).then(function () {
const effect = swiper_api.getAttribute('effect') || '';
var swiper = new Swiper('.swiper#swiper-api', {
slidesPerView: 'auto',
spaceBetween: 8,
centeredSlides: true,
effect: effect,
loop: true,
pagination: {
el: '.swiper-pagination',
clickable: true,
},
navigation: {
nextEl: '.swiper-button-next',
prevEl: '.swiper-button-prev',
},
});
})
}
}
// preload
if (stellar.plugins.preload) {
if (stellar.plugins.preload.service == 'flying_pages') {
window.FPConfig = {
delay: 0,
ignoreKeywords: [],
maxRPS: 5,
hoverDelay: 25
};
stellar.loadScript(stellar.plugins.preload.flying_pages, { defer: true })
}
}
// fancybox
if (stellar.plugins.fancybox) {
let selector = '[data-fancybox]:not(.error)';
if (stellar.plugins.fancybox.selector) {
selector += `, ${stellar.plugins.fancybox.selector}`
}
var needFancybox = document.querySelectorAll(selector).length !== 0;
if (!needFancybox) {
const els = document.getElementsByClassName('stellar-memos-api');
if (els != undefined && els.length > 0) {
needFancybox = true;
}
}
if (needFancybox) {
stellar.loadCSS(stellar.plugins.fancybox.css);
stellar.loadScript(stellar.plugins.fancybox.js, { defer: true }).then(function () {
Fancybox.bind(selector, {
hideScrollbar: false,
Thumbs: {
autoStart: false,
},
caption: (fancybox, slide) => {
return slide.triggerEl.alt || null
}
});
})
}
}
if (stellar.search.service) {
if (stellar.search.service == 'local_search') {
stellar.jQuery(() => {
stellar.loadScript('/js/search/local-search.js', { defer: true }).then(function () {
var $inputArea = $("input#search-input");
if ($inputArea.length == 0) {
return;
}
var $resultArea = document.querySelector("div#search-result");
$inputArea.focus(function() {
var path = stellar.search[stellar.search.service]?.path || '/search.json';
if (path.startsWith('/')) {
path = path.substring(1);
}
path = stellar.config.root + path;
const filter = $inputArea.attr('data-filter') || '';
searchFunc(path, filter, 'search-wrapper', 'search-input', 'search-result');
});
$inputArea.keydown(function(e) {
if (e.which == 13) {
e.preventDefault();
}
});
var observer = new MutationObserver(function(mutationsList, observer) {
if (mutationsList.length == 1) {
if (mutationsList[0].addedNodes.length) {
$('.search-wrapper').removeClass('noresult');
} else if (mutationsList[0].removedNodes.length) {
$('.search-wrapper').addClass('noresult');
}
}
});
observer.observe($resultArea, { childList: true });
});
})
}
}
// heti
if (stellar.plugins.heti) {
stellar.loadCSS(stellar.plugins.heti.css);
stellar.loadScript(stellar.plugins.heti.js, { defer: true }).then(function () {
const heti = new Heti('.heti');
// Copied from heti.autoSpacing() without DOMContentLoaded.
// https://github.com/sivan/heti/blob/eadee6a3b748b3b7924a9e7d5b395d4bce479c9a/js/heti-addon.js
//
// We managed to minimize the code modification to ensure .autoSpacing()
// is synced with upstream; therefore, we use `.bind()` to emulate the
// behavior of .autoSpacing() so we can even modify almost no code.
void (function () {
const $$rootList = document.querySelectorAll(this.rootSelector)
for (let $$root of $$rootList) {
this.spacingElement($$root)
}
}).bind(heti)();
stellar.plugins.heti.enable = false;
});
}
if (stellar.plugins.copycode) {
stellar.loadScript(stellar.plugins.copycode.js, { defer: true })
}

View File

@ -1,45 +1,41 @@
const codeElementArr = document.querySelectorAll('.code')
codeElementArr.forEach(code => {
window.codeElements.forEach(code => {
// copy btn
const codeCopyBtn = document.createElement('div')
codeCopyBtn.classList.add('copy-btn')
codeCopyBtn.innerHTML = stellar.plugins.copycode.default_text
code.appendChild(codeCopyBtn)
const codeCopyBtn = document.createElement('div');
codeCopyBtn.classList.add('copy-btn');
codeCopyBtn.innerHTML = ctx.copycode.default_text;
code.appendChild(codeCopyBtn);
codeCopyBtn.addEventListener('click', async () => {
const currentCodeElement = code.children[0]?.innerText
await copyCode(currentCodeElement)
codeCopyBtn.innerHTML = stellar.plugins.copycode.success_text
codeCopyBtn.classList.add('success')
hud.toast(stellar.plugins.copycode.toast, 2500)
const currentCodeElement = code.children[0]?.innerText;
await copyCode(currentCodeElement);
codeCopyBtn.innerHTML = ctx.copycode.success_text;
codeCopyBtn.classList.add('success');
hud.toast(ctx.copycode.toast, 2500);
setTimeout(() => {
codeCopyBtn.innerHTML = stellar.plugins.copycode.default_text
codeCopyBtn.classList.remove('success')
},3000)
codeCopyBtn.innerHTML = ctx.copycode.default_text;
codeCopyBtn.classList.remove('success');
},3000);
})
})
async function copyCode(currentCode) {
if (navigator.clipboard) {
try {
await navigator.clipboard.writeText(currentCode)
await navigator.clipboard.writeText(currentCode);
} catch (error) {
// 未获得用户许可
codeCopyBtn.innerText = '未获得用户许可'
codeCopyBtn.classList.add('warning')
codeCopyBtn.innerText = '未获得用户许可';
codeCopyBtn.classList.add('warning');
setTimeout(() => {
codeCopyBtn.innerText = stellar.plugins.copycode.default_text
codeCopyBtn.classList.remove('warning')
},3000)
codeCopyBtn.innerText = ctx.copycode.default_text;
codeCopyBtn.classList.remove('warning');
},3000);
}
} else {
codeCopyBtn.innerText = '当前浏览器不支持此api'
codeCopyBtn.classList.add('warning')
codeCopyBtn.innerText = '当前浏览器不支持此api';
codeCopyBtn.classList.add('warning');
setTimeout(() => {
codeCopyBtn.innerText = stellar.plugins.copycode.default_text
codeCopyBtn.classList.remove('warning')
},3000)
codeCopyBtn.innerText = ctx.copycode.default_text;
codeCopyBtn.classList.remove('warning');
},3000);
}
}

View File

@ -1,92 +0,0 @@
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="2em" height="2em" 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 || cfg.avatar) + '" onerror="javascript:this.src=\'' + cfg.avatar + '\';">';
cell += '<span>' + item.author + '</span>';
cell += '</div>';
cell += '<span>' + item.created + '</span>';
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="2em" height="2em" 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 cfg = new Object();
cfg.el = el;
cfg.api = api;
cfg.avatar = 'https://gcore.jsdelivr.net/gh/cdn-x/placeholder@1.0.12/avatar/round/3442075.svg';
FCircle.layoutDiv(cfg);
}
});

View File

@ -1,84 +0,0 @@
const friendsjs = {
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 xmlns="http://www.w3.org/2000/svg" width="2em" height="2em" 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>');
friendsjs.requestAPI(cfg.api, function(data) {
$(el).find('.loading-wrap').remove();
for (let item of (data.content || data)) {
var cell = `<div class="grid-cell user-card">`;
cell += `<a class="card-link" target="_blank" rel="external nofollow noopener noreferrer" href="${item.html_url || item.url}">`;;
cell += `<img src="${item.avatar_url || item.avatar || item.icon || cfg.avatar}" onerror="javascript:this.removeAttribute(\'data-src\');this.src=\'${cfg.avatar}\';"/>`;
cell += `<div class="name image-meta">`;
cell += `<span class="image-caption">${item.title || item.login}</span>`;
cell += `</div>`;
cell += `</a>`;
cell += `</div>`;
$(el).find('.grid-box').append(cell);
}
}, function() {
$(el).find('.loading-wrap svg').remove();
$(el).find('.loading-wrap').append('<svg xmlns="http://www.w3.org/2000/svg" width="2em" height="2em" 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-friends-api');
for (var i = 0; i < els.length; i++) {
const el = els[i];
const api = el.getAttribute('api');
if (api == null) {
continue;
}
var cfg = new Object();
cfg.el = el;
cfg.api = api;
cfg.class = el.getAttribute('class');
cfg.avatar = 'https://gcore.jsdelivr.net/gh/cdn-x/placeholder@1.0.12/avatar/round/3442075.svg';
friendsjs.layout(cfg);
}
});

View File

@ -1,85 +0,0 @@
const GitHubInfo = {
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];
function fill(data) {
for (let key of Object.keys(data)) {
$(el).find("[type=text]#" + key).text(data[key]);
$(el).find("[type=link]#" + key).attr("href", data[key]);
$(el).find("[type=img]#" + key).attr("src", data[key]);
}
}
GitHubInfo.requestAPI(cfg.api, function(data) {
const idx = el.getAttribute('index');
if (idx != undefined) {
const arr = data.content || data;
if (arr && arr.length > idx) {
let obj = arr[idx];
obj['latest-tag-name'] = obj['name'];
fill(arr[idx]);
}
} else {
fill(data);
}
}, function() {
});
},
}
$(function () {
const els = document.getElementsByClassName('stellar-ghinfo-api');
for (var i = 0; i < els.length; i++) {
const el = els[i];
const api = el.getAttribute('api');
if (api == null) {
continue;
}
var cfg = new Object();
cfg.el = el;
cfg.api = api;
cfg.class = el.getAttribute('class');
GitHubInfo.layout(cfg);
}
});

View File

@ -1,48 +0,0 @@
// 本插件由CardLink定制而成原项目源码: https://github.com/Lete114/CardLink
function renderer(el, obj) {
var autofill = [];
const autofillStr = el.getAttribute('autofill');
if (autofillStr) {
autofill = autofillStr.split(',');
}
if (obj.title && obj.title.length > 0 && autofill.includes('title')) {
el.querySelector('.title').innerHTML = obj.title;
el.title = obj.title;
}
if (obj.icon && obj.icon.length > 0 && autofill.includes('icon')) {
el.querySelector('.img').style = 'background-image: url("' + obj.icon + '");';
el.querySelector('.img').setAttribute('data-bg', obj.icon);
}
let desc = el.querySelector('.desc');
if (desc && obj.desc && obj.desc.length > 0 && autofill.includes('desc')) {
desc.innerHTML = obj.desc;
}
}
/**
* Create card links
* @param {NodeList} nodes A collection of nodes or a collection of arrays,
* if it is an array then the array must always contain node element
*/
function setCardLink(nodes) {
// If the `nodes` do not contain a `forEach` method, then the default `a[cardlink]` is used
nodes = 'forEach' in (nodes || {}) ? nodes : document.querySelectorAll('a[cardlink]')
nodes.forEach((el) => {
// If it is not a tag element then it is not processed
if (el.nodeType !== 1) return;
el.removeAttribute('cardlink');
const api = el.getAttribute('api');
if (api == null) return;
fetch(api).then(function(response) {
if (response.ok) {
return response.json();
}
throw new Error('Network response was not ok.');
}).then(function(data) {
renderer(el, data);
}).catch(function(error) {
console.error(error);
});
})
}

View File

@ -1,50 +0,0 @@
const loadMarkdown = (cfg) => {
if (!window.fetch) {
cfg.el.innerHTML =
'<div style="font-size: 24px"><p>Your browser outdated. Please use the latest version of Chrome or Firefox!</p><p>您的浏览器版本过低,请使用最新版的 Chrome 或 Firefox 浏览器!</p></div>';
} else {
cfg.el.innerHTML =
'<div class="loading-wrap"><svg xmlns="http://www.w3.org/2000/svg" width="2em" height="2em" 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>';
fetch(cfg.src, { method: "GET" })
.then((resp) => {
return Promise.all([
resp.ok,
resp.status,
resp.text(),
resp.headers,
]);
})
.then(([ok, status, data, headers]) => {
if (ok) {
return {
ok,
status,
data,
headers,
};
} else {
throw new Error(JSON.stringify(json.error));
}
})
.then((resp) => {
let data = marked.parse(resp.data);
cfg.el.innerHTML = data;
})
.catch((error) => {
console.error(error);
cfg.el.innerHTML =
'<div class="loading-wrap error"><svg xmlns="http://www.w3.org/2000/svg" width="2em" height="2em" 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></div>';
});
};
};
$(function () {
const els = document.getElementsByClassName('stellar-marked-api');
for (var i = 0; i < els.length; i++) {
var cfg = new Object();
const el = els[i];
cfg.src = `${el.getAttribute('src')}?t=${new Date().getTime()}`;
cfg.el = el;
loadMarkdown(cfg);
}
});

View File

@ -1,132 +0,0 @@
const MemosJS = {
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="2em" height="2em" 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>');
MemosJS.requestAPI(cfg.api, function(data) {
$(el).find('.loading-wrap').remove();
var users = [];
const filter = el.getAttribute('user');
if (filter && filter.length > 0) {
users = filter.split(",");
}
var hide = [];
const hideStr = el.getAttribute('hide');
if (hideStr && hideStr.length > 0) {
hide = hideStr.split(",");
}
data.forEach((item, i) => {
if (cfg.limit && i >= cfg.limit) {
return;
}
if (item.user && item.user.login && users.length > 0) {
if (!users.includes(item.user.login)) {
return;
}
}
let date = new Date(item.createdTs * 1000)
var cell = '<div class="timenode" index="' + i + '">';
cell += '<div class="header">';
if (!users.length && !hide.includes('user')) {
cell += '<div class="user-info">';
if (cfg.avatar?.length > 0) {
cell += `<img src="${cfg.avatar}">`;
}
cell += '<span>' + item.creatorName + '</span>';
cell += '</div>';
}
cell += '<span>' + date.toLocaleString() + '</span>';
cell += '</div>';
cell += '<div class="body">';
cell += marked.parse(item.content || '');
var imgs = [];
for (let res of item.resourceList) {
if (res.type?.includes('image/')) {
imgs.push(res);
}
}
if (imgs.length > 0) {
cell += '<div class="tag-plugin image">';
for (let img of imgs) {
if (img.externalLink?.length > 0) {
cell += `<div class="image-bg"><img src="${img.externalLink}" data-fancybox="memos"></div>`;
} else {
cell += `<div class="image-bg"><img src="https://${cfg.host}/o/r/${img.id}" data-fancybox="memos"></div>`;
}
}
cell += '</div>';
}
cell += '</div>';
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="2em" height="2em" 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-memos-api');
for (var i = 0; i < els.length; i++) {
const el = els[i];
const api = el.getAttribute('api');
if (api == null) {
continue;
}
var cfg = new Object();
cfg.el = el;
cfg.api = api;
cfg.limit = el.getAttribute('limit');
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.12/avatar/round/3442075.svg';
}
MemosJS.layoutDiv(cfg);
}
});

View File

@ -1,87 +0,0 @@
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 xmlns="http://www.w3.org/2000/svg" width="2em" height="2em" 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>');
sitesjs.requestAPI(cfg.api, function(data) {
$(el).find('.loading-wrap').remove();
for (let item of data.content) {
var cell = `<div class="grid-cell site-card">`;
cell += `<a class="card-link" target="_blank" rel="external nofollow noopener noreferrer" href="${item.url}">`;
cell += `<img src="${item.cover || item.screenshot}" onerror="javascript:this.removeAttribute(\'data-src\');this.src=\'${cfg.screenshot}\';"/>`;
cell += `<div class="info">`;
cell += `<img src="${item.icon || item.avatar || cfg.avatar}" onerror="javascript:this.removeAttribute(\'data-src\');this.src=\'${cfg.avatar}\';"/>`;
cell += `<span class="title">${item.title}</span>`;
cell += `<span class="desc">${item.description || item.url}</span>`;
cell += `</div>`;
cell += `</a>`;
cell += `</div>`;
$(el).find('.grid-box').append(cell);
}
}, function() {
$(el).find('.loading-wrap svg').remove();
$(el).find('.loading-wrap').append('<svg xmlns="http://www.w3.org/2000/svg" width="2em" height="2em" 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-sites-api');
for (var i = 0; i < els.length; i++) {
const el = els[i];
const api = el.getAttribute('api');
if (api == null) {
continue;
}
var cfg = new Object();
cfg.class = el.getAttribute('class');
cfg.el = el;
cfg.api = api;
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);
}
});

View File

@ -1,162 +0,0 @@
const StellarTimeline = {
reactions: {
'+1': '👍',
'-1': '👎',
'laugh': '😀',
'hooray': '🎉',
'confused': '😕',
'heart': '❤️',
'rocket': '🚀',
'eyes': '👀'
},
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="2em" height="2em" 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>');
StellarTimeline.requestAPI(cfg.api, function(data) {
$(el).find('.loading-wrap').remove();
const query = new URL(cfg.api).search;
const arr = data.content || data;
var users = [];
const filter = el.getAttribute('user');
if (filter && filter.length > 0) {
users = filter.split(",");
}
var hide = [];
const hideStr = el.getAttribute('hide');
if (hideStr && hideStr.length > 0) {
hide = hideStr.split(",");
}
arr.forEach((item, i) => {
if (item.user && item.user.login && users.length > 0) {
if (!users.includes(item.user.login)) {
return;
}
}
var cell = '<div class="timenode" index="' + i + '">';
cell += '<div class="header">';
if (!users.length && item.user && !hide.includes('user')) {
cell += '<a class="user-info" href="' + item.user.html_url + '" target="_blank" rel="external nofollow noopener noreferrer">';
cell += '<img src="' + item.user.avatar_url + '">';
cell += '<span>' + item.user.login + '</span>';
cell += '</a>';
}
let date = new Date(item.created_at);
cell += '<span>' + date.toLocaleString() + '</span>';
cell += '</div>';
cell += '<div class="body">';
if (!hide.includes('title')) {
cell += '<p class="title">';
cell += '<a href="' + item.html_url + '" target="_blank" rel="external nofollow noopener noreferrer">';
cell += item.title || item.name || item.tag_name;
cell += '</a>';
cell += '</p>';
}
cell += marked.parse(item.body || '');
if (!hide.includes('footer')) {
cell += '<div class="footer">';
cell += '<div class="flex left">';
if (item.labels) {
item.labels.forEach((label, i) => {
if (!query || !query.includes(encodeURI(label.name))) {
cell += '<div class="item label ' + label.name + '" style="background:#' + label.color + '18;border-color:#' + label.color + '36">';
cell += '<span>' + label.name + '</span>';
cell += '</div>';
}
});
} else if (item.zipball_url) {
cell += '<a class="item download" href="' + item.zipball_url + '" target="_blank" rel="external nofollow noopener noreferrer">';
cell += '<span>📦 ' + item.tag_name + '.zip</span>';
cell += '</a>';
}
cell += '</div>';
cell += '<div class="flex right">';
if (item.reactions && item.reactions.total_count > 0) {
for (let key of Object.keys(StellarTimeline.reactions)) {
let num = item.reactions[key];
if (num > 0) {
cell += '<div class="item reaction ' + key + '">';
cell += '<span>' + StellarTimeline.reactions[key] + ' ' + item.reactions[key] + '</span>';
cell += '</div>';
}
}
}
if (item.comments != null) {
cell += '<a class="item comments last" href="' + item.html_url + '#issuecomment-new" target="_blank" rel="external nofollow noopener noreferrer">';
cell += '<span><svg t="1666270368054" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2528" width="200" height="200"><path d="M952 64H72C32.3 64 0 96.3 0 136v508c0 39.7 32.3 72 72 72h261l128 128c14 14 32.5 21.1 50.9 21.1s36.9-7 50.9-21.1l128-128h261c39.7 0 72-32.3 72-72V136c0.2-39.7-32.1-72-71.8-72zM222 462c-39.8 0-72-32.2-72-72s32.2-72 72-72 72 32.2 72 72-32.2 72-72 72z m290-7.7c-39.8 0-72-32.2-72-72s32.2-72 72-72 72 32.2 72 72c0 39.7-32.2 72-72 72z m290 8c-39.8 0-72-32.2-72-72s32.2-72 72-72 72 32.2 72 72c0 39.7-32.2 72-72 72z" p-id="2529"></path></svg> ' + (item.comments || 0) + '</span>';
cell += '</a>';
}
cell += '</div>';
cell += '</div>';
}
cell += '</div>';
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="2em" height="2em" 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-timeline-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;
StellarTimeline.layoutDiv(obj);
}
});

View File

@ -1,116 +0,0 @@
const weibojs = {
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="2em" height="2em" 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>');
weibojs.requestAPI(cfg.api, function(data) {
$(el).find('.loading-wrap').remove();
const arr = data.tweets || [];
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="' + (data.user.avatar_hd || cfg.avatar) + '" onerror="javascript:this.src=\'' + cfg.avatar + '\';">';
cell += '<span>' + data.user.nick_name + '</span>';
cell += '</div>';
cell += '<span>' + item.created_at + '</span>';
cell += '</div>';
cell += '<div class="body">';
cell += '<a class="body" href="' + item.url + '" target="_blank" rel="external nofollow noopener noreferrer">';
cell += item.content;
cell += '</a>';
// cell += '</div>';
// 每条微博的右下角 转发 评论 点赞
cell += '<div class="footer">';
cell += '<div class="flex left">';
cell += '</div>';
cell += '<div class="flex right">';
cell += '<div class="item reaction repost">';
cell += '<a class="item comments last" href="' + item.url + '#issuecomment-new" target="_blank" rel="external nofollow noopener noreferrer">';
cell += '<span>' + '🔗' + ' ' + item.reposts_count + '</span>';
cell += '</a>';
cell += '</div>';
cell += '<a class="item comments last" href="' + item.url + '#issuecomment-new" target="_blank" rel="external nofollow noopener noreferrer">';
cell += '<span><svg t="1666270368054" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2528" width="200" height="200"><path d="M952 64H72C32.3 64 0 96.3 0 136v508c0 39.7 32.3 72 72 72h261l128 128c14 14 32.5 21.1 50.9 21.1s36.9-7 50.9-21.1l128-128h261c39.7 0 72-32.3 72-72V136c0.2-39.7-32.1-72-71.8-72zM222 462c-39.8 0-72-32.2-72-72s32.2-72 72-72 72 32.2 72 72-32.2 72-72 72z m290-7.7c-39.8 0-72-32.2-72-72s32.2-72 72-72 72 32.2 72 72c0 39.7-32.2 72-72 72z m290 8c-39.8 0-72-32.2-72-72s32.2-72 72-72 72 32.2 72 72c0 39.7-32.2 72-72 72z" p-id="2529"></path></svg> '
+ (item.comments_count || 0) + '</span>';
cell += '</a>';
cell += '<div class="item reaction attitudes">';
cell += '<a class="item comments last" href="' + item.url + '#issuecomment-new" target="_blank" rel="external nofollow noopener noreferrer">';
cell += '<span>' + '👍' + ' ' + item.attitudes_count + '</span>';
cell += '</a>';
cell += '</div>';
cell += '</div>';
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="2em" height="2em" 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-weibo-api');
for (var i = 0; i < els.length; i++) {
const el = els[i];
const api = el.getAttribute('api'); // 这个API可以返回微博的json文件
if (api == null) {
continue;
}
var cfg = new Object();
cfg.el = el;
cfg.api = api;
cfg.avatar = 'https://gcore.jsdelivr.net/gh/cdn-x/placeholder@1.0.12/avatar/round/3442075.svg';
weibojs.layoutDiv(cfg);
}
});

View File

@ -136,3 +136,35 @@ var searchFunc = function(path, filter, wrapperId, searchId, contentId) {
}
});
};
utils.jq(() => {
var $inputArea = $("input#search-input");
if ($inputArea.length == 0) {
return;
}
var $resultArea = document.querySelector("div#search-result");
$inputArea.focus(function() {
var path = ctx.search.path;
if (path.startsWith('/')) {
path = path.substring(1);
}
path = ctx.root + path;
const filter = $inputArea.attr('data-filter') || '';
searchFunc(path, filter, 'search-wrapper', 'search-input', 'search-result');
});
$inputArea.keydown(function(e) {
if (e.which == 13) {
e.preventDefault();
}
});
var observer = new MutationObserver(function(mutationsList, observer) {
if (mutationsList.length == 1) {
if (mutationsList[0].addedNodes.length) {
$('.search-wrapper').removeClass('noresult');
} else if (mutationsList[0].removedNodes.length) {
$('.search-wrapper').addClass('noresult');
}
}
});
observer.observe($resultArea, { childList: true });
});

View File

@ -0,0 +1,36 @@
utils.jq(() => {
$(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;
}
const default_avatar = def.avatar;
// layout
utils.request(el, api, function(data) {
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 || default_avatar) + '" onerror="javascript:this.src=\'' + default_avatar + '\';">';
cell += '<span>' + item.author + '</span>';
cell += '</div>';
cell += '<span>' + item.created + '</span>';
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);
});
});
}
});
});

View File

@ -0,0 +1,27 @@
utils.jq(() => {
$(function () {
const els = document.getElementsByClassName('stellar-friends-api');
for (var i = 0; i < els.length; i++) {
const el = els[i];
const api = el.getAttribute('api');
if (api == null) {
continue;
}
const default_avatar = def.avatar;
// layout
utils.request(el, api, function(data) {
for (let item of (data.content || data)) {
var cell = `<div class="grid-cell user-card">`;
cell += `<a class="card-link" target="_blank" rel="external nofollow noopener noreferrer" href="${item.html_url || item.url}">`;;
cell += `<img src="${item.avatar_url || item.avatar || item.icon || default_avatar}" onerror="javascript:this.removeAttribute(\'data-src\');this.src=\'${default_avatar}\';"/>`;
cell += `<div class="name image-meta">`;
cell += `<span class="image-caption">${item.title || item.login}</span>`;
cell += `</div>`;
cell += `</a>`;
cell += `</div>`;
$(el).find('.grid-box').append(cell);
}
});
}
});
});

View File

@ -0,0 +1,33 @@
utils.jq(() => {
$(function () {
const els = document.getElementsByClassName('stellar-ghinfo-api');
for (var i = 0; i < els.length; i++) {
const el = els[i];
const api = el.getAttribute('api');
if (api == null) {
continue;
}
// layout
utils.request(null, api, function(data) {
function fill(data) {
for (let key of Object.keys(data)) {
$(el).find("[type=text]#" + key).text(data[key]);
$(el).find("[type=link]#" + key).attr("href", data[key]);
$(el).find("[type=img]#" + key).attr("src", data[key]);
}
}
const idx = el.getAttribute('index');
if (idx != undefined) {
const arr = data.content || data;
if (arr && arr.length > idx) {
let obj = arr[idx];
obj['latest-tag-name'] = obj['name'];
fill(arr[idx]);
}
} else {
fill(data);
}
});
}
});
});

View File

@ -0,0 +1,10 @@
utils.jq(() => {
const els = document.getElementsByClassName('stellar-marked-api');
for (var i = 0; i < els.length; i++) {
const el = els[i];
const src = `${el.getAttribute('src')}?t=${new Date().getTime()}`;
utils.request(el, src, function(data) {
el.innerHTML = marked.parse(resp.data);
});
}
});

View File

@ -0,0 +1,73 @@
utils.jq(() => {
$(function () {
const els = document.getElementsByClassName('stellar-memos-api');
for (var i = 0; i < els.length; i++) {
const el = els[i];
const api = el.getAttribute('api');
if (api == null) {
continue;
}
const default_avatar = el.getAttribute('avatar') || def.avatar;
const limit = el.getAttribute('limit');
const host = api.replace(/https:\/\/(.*?)\/(.*)/i, '$1');
// layout
utils.request(el, api, function(data) {
var users = [];
const filter = el.getAttribute('user');
if (filter && filter.length > 0) {
users = filter.split(",");
}
var hide = [];
const hideStr = el.getAttribute('hide');
if (hideStr && hideStr.length > 0) {
hide = hideStr.split(",");
}
data.forEach((item, i) => {
if (limit && i >= limit) {
return;
}
if (item.user && item.user.login && users.length > 0) {
if (!users.includes(item.user.login)) {
return;
}
}
let date = new Date(item.createdTs * 1000)
var cell = '<div class="timenode" index="' + i + '">';
cell += '<div class="header">';
if (!users.length && !hide.includes('user')) {
cell += '<div class="user-info">';
if (default_avatar.length > 0) {
cell += `<img src="${default_avatar}">`;
}
cell += '<span>' + item.creatorName + '</span>';
cell += '</div>';
}
cell += '<span>' + date.toLocaleString() + '</span>';
cell += '</div>';
cell += '<div class="body">';
cell += marked.parse(item.content || '');
var imgs = [];
for (let res of item.resourceList) {
if (res.type?.includes('image/')) {
imgs.push(res);
}
}
if (imgs.length > 0) {
cell += '<div class="tag-plugin image">';
for (let img of imgs) {
if (img.externalLink?.length > 0) {
cell += `<div class="image-bg"><img src="${img.externalLink}" data-fancybox="memos"></div>`;
} else {
cell += `<div class="image-bg"><img src="https://${host}/o/r/${img.id}" data-fancybox="memos"></div>`;
}
}
cell += '</div>';
}
cell += '</div>';
cell += '</div>';
$(el).append(cell);
});
});
}
});
});

View File

@ -0,0 +1,38 @@
// 本插件由CardLink定制而成原项目源码: https://github.com/Lete114/CardLink
function setCardLink(nodes) {
// If the `nodes` do not contain a `forEach` method, then the default `a[cardlink]` is used
nodes = 'forEach' in (nodes || {}) ? nodes : document.querySelectorAll('a[cardlink]')
nodes.forEach((el) => {
// If it is not a tag element then it is not processed
if (el.nodeType !== 1) return;
el.removeAttribute('cardlink');
const api = el.getAttribute('api');
if (api == null) return;
fetch(api).then(function(response) {
if (response.ok) {
return response.json();
}
throw new Error('Network response was not ok.');
}).then(function(data) {
var autofill = [];
const autofillStr = el.getAttribute('autofill');
if (autofillStr) {
autofill = autofillStr.split(',');
}
if (data.title && data.title.length > 0 && autofill.includes('title')) {
el.querySelector('.title').innerHTML = data.title;
el.title = data.title;
}
if (data.icon && data.icon.length > 0 && autofill.includes('icon')) {
el.querySelector('.img').style = 'background-image: url("' + data.icon + '");';
el.querySelector('.img').setAttribute('data-bg', data.icon);
}
let desc = el.querySelector('.desc');
if (desc && data.desc && data.desc.length > 0 && autofill.includes('desc')) {
desc.innerHTML = data.desc;
}
}).catch(function(error) {
console.error(error);
});
})
}

View File

@ -0,0 +1,30 @@
utils.jq(() => {
$(function () {
const els = document.getElementsByClassName('stellar-sites-api');
for (var i = 0; i < els.length; i++) {
const el = els[i];
const api = el.getAttribute('api');
if (api == null) {
continue;
}
const default_avatar = def.avatar;
const default_cover = def.cover;
// layout
utils.request(el, api, function(data) {
for (let item of data.content) {
var cell = `<div class="grid-cell site-card">`;
cell += `<a class="card-link" target="_blank" rel="external nofollow noopener noreferrer" href="${item.url}">`;
cell += `<img src="${item.cover || item.screenshot}" onerror="javascript:this.removeAttribute(\'data-src\');this.src=\'${default_cover}\';"/>`;
cell += `<div class="info">`;
cell += `<img src="${item.icon || item.avatar || default_avatar}" onerror="javascript:this.removeAttribute(\'data-src\');this.src=\'${default_avatar}\';"/>`;
cell += `<span class="title">${item.title}</span>`;
cell += `<span class="desc">${item.description || item.url}</span>`;
cell += `</div>`;
cell += `</a>`;
cell += `</div>`;
$(el).find('.grid-box').append(cell);
}
});
}
});
});

View File

@ -0,0 +1,108 @@
utils.jq(() => {
$(function () {
const reactions = {
'+1': '👍',
'-1': '👎',
'laugh': '😀',
'hooray': '🎉',
'confused': '😕',
'heart': '❤️',
'rocket': '🚀',
'eyes': '👀'
}
const timelines = document.getElementsByClassName('stellar-timeline-api');
for (var i = 0; i < timelines.length; i++) {
const el = timelines[i];
const api = el.getAttribute('api');
if (api == null) {
continue;
}
// layout
utils.request(el, api, function(data) {
const query = new URL(api).search;
const arr = data.content || data;
var users = [];
const filter = el.getAttribute('user');
if (filter && filter.length > 0) {
users = filter.split(",");
}
var hide = [];
const hideStr = el.getAttribute('hide');
if (hideStr && hideStr.length > 0) {
hide = hideStr.split(",");
}
console.log('arr', arr);
arr.forEach((item, i) => {
if (item.user && item.user.login && users.length > 0) {
if (!users.includes(item.user.login)) {
return;
}
}
var cell = '<div class="timenode" index="' + i + '">';
cell += '<div class="header">';
if (!users.length && item.user && !hide.includes('user')) {
cell += '<a class="user-info" href="' + item.user.html_url + '" target="_blank" rel="external nofollow noopener noreferrer">';
cell += '<img src="' + item.user.avatar_url + '">';
cell += '<span>' + item.user.login + '</span>';
cell += '</a>';
}
let date = new Date(item.created_at);
cell += '<span>' + date.toLocaleString() + '</span>';
cell += '</div>';
cell += '<div class="body">';
if (!hide.includes('title')) {
cell += '<p class="title">';
cell += '<a href="' + item.html_url + '" target="_blank" rel="external nofollow noopener noreferrer">';
cell += item.title || item.name || item.tag_name;
cell += '</a>';
cell += '</p>';
}
cell += marked.parse(item.body || '');
if (!hide.includes('footer')) {
cell += '<div class="footer">';
cell += '<div class="flex left">';
if (item.labels) {
item.labels.forEach((label, i) => {
if (!query || !query.includes(encodeURI(label.name))) {
cell += '<div class="item label ' + label.name + '" style="background:#' + label.color + '18;border-color:#' + label.color + '36">';
cell += '<span>' + label.name + '</span>';
cell += '</div>';
}
});
} else if (item.zipball_url) {
cell += '<a class="item download" href="' + item.zipball_url + '" target="_blank" rel="external nofollow noopener noreferrer">';
cell += '<span>📦 ' + item.tag_name + '.zip</span>';
cell += '</a>';
}
cell += '</div>';
cell += '<div class="flex right">';
if (item.reactions?.total_count > 0) {
for (let key of Object.keys(reactions)) {
let num = item.reactions[key];
if (num > 0) {
cell += '<div class="item reaction ' + key + '">';
cell += '<span>' + reactions[key] + ' ' + item.reactions[key] + '</span>';
cell += '</div>';
}
}
}
if (item.comments != null) {
cell += '<a class="item comments last" href="' + item.html_url + '#issuecomment-new" target="_blank" rel="external nofollow noopener noreferrer">';
cell += '<span><svg t="1666270368054" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2528" width="200" height="200"><path d="M952 64H72C32.3 64 0 96.3 0 136v508c0 39.7 32.3 72 72 72h261l128 128c14 14 32.5 21.1 50.9 21.1s36.9-7 50.9-21.1l128-128h261c39.7 0 72-32.3 72-72V136c0.2-39.7-32.1-72-71.8-72zM222 462c-39.8 0-72-32.2-72-72s32.2-72 72-72 72 32.2 72 72-32.2 72-72 72z m290-7.7c-39.8 0-72-32.2-72-72s32.2-72 72-72 72 32.2 72 72c0 39.7-32.2 72-72 72z m290 8c-39.8 0-72-32.2-72-72s32.2-72 72-72 72 32.2 72 72c0 39.7-32.2 72-72 72z" p-id="2529"></path></svg> ' + (item.comments || 0) + '</span>';
cell += '</a>';
}
cell += '</div>';
cell += '</div>';
}
cell += '</div>';
cell += '</div>';
console.log('cell', cell, el);
$(el).append(cell);
});
});
}
});
});

View File

@ -0,0 +1,60 @@
utils.jq(() => {
$(function () {
const els = document.getElementsByClassName('stellar-weibo-api');
for (var i = 0; i < els.length; i++) {
const el = els[i];
const api = el.getAttribute('api');
if (api == null) {
continue;
}
const default_avatar = el.getAttribute('avatar') || def.avatar;
// layout
utils.request(el, api, function(data) {
const arr = data.tweets || [];
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="' + (data.user.avatar_hd || default_avatar) + '" onerror="javascript:this.src=\'' + default_avatar + '\';">';
cell += '<span>' + data.user.nick_name + '</span>';
cell += '</div>';
cell += '<span>' + item.created_at + '</span>';
cell += '</div>';
cell += '<div class="body">';
cell += '<a class="body" href="' + item.url + '" target="_blank" rel="external nofollow noopener noreferrer">';
cell += item.content;
cell += '</a>';
// cell += '</div>';
// 每条微博的右下角 转发 评论 点赞
cell += '<div class="footer">';
cell += '<div class="flex left">';
cell += '</div>';
cell += '<div class="flex right">';
cell += '<div class="item reaction repost">';
cell += '<a class="item comments last" href="' + item.url + '#issuecomment-new" target="_blank" rel="external nofollow noopener noreferrer">';
cell += '<span>' + '🔗' + ' ' + item.reposts_count + '</span>';
cell += '</a>';
cell += '</div>';
cell += '<a class="item comments last" href="' + item.url + '#issuecomment-new" target="_blank" rel="external nofollow noopener noreferrer">';
cell += '<span><svg t="1666270368054" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2528" width="200" height="200"><path d="M952 64H72C32.3 64 0 96.3 0 136v508c0 39.7 32.3 72 72 72h261l128 128c14 14 32.5 21.1 50.9 21.1s36.9-7 50.9-21.1l128-128h261c39.7 0 72-32.3 72-72V136c0.2-39.7-32.1-72-71.8-72zM222 462c-39.8 0-72-32.2-72-72s32.2-72 72-72 72 32.2 72 72-32.2 72-72 72z m290-7.7c-39.8 0-72-32.2-72-72s32.2-72 72-72 72 32.2 72 72c0 39.7-32.2 72-72 72z m290 8c-39.8 0-72-32.2-72-72s32.2-72 72-72 72 32.2 72 72c0 39.7-32.2 72-72 72z" p-id="2529"></path></svg> '
+ (item.comments_count || 0) + '</span>';
cell += '</a>';
cell += '<div class="item reaction attitudes">';
cell += '<a class="item comments last" href="' + item.url + '#issuecomment-new" target="_blank" rel="external nofollow noopener noreferrer">';
cell += '<span>' + '👍' + ' ' + item.attitudes_count + '</span>';
cell += '</a>';
cell += '</div>';
cell += '</div>';
cell += '</div>';
// 右下角结束
$(el).append(cell);
});
});
}
});
});