mirror of
https://github.com/KivotosRailway/website.git
synced 2026-11-03 19:07:56 +09:00
Add solitude
This commit is contained in:
@@ -0,0 +1,142 @@
|
||||
/**
|
||||
* Solitude
|
||||
* Merge CDN
|
||||
*/
|
||||
|
||||
'use strict'
|
||||
|
||||
const { version } = require('../../package.json')
|
||||
const path = require('path')
|
||||
|
||||
hexo.extend.filter.register('before_generate', () => {
|
||||
const themeConfig = hexo.theme.config
|
||||
const { CDN } = themeConfig
|
||||
|
||||
const thirdPartySrc = hexo.render.renderSync({ path: path.join(hexo.theme_dir, '/plugins.yml'), engine: 'yaml' })
|
||||
const internalSrc = {
|
||||
main: {
|
||||
name: 'hexo-theme-solitude',
|
||||
file: 'js/main.js',
|
||||
version
|
||||
},
|
||||
utils: {
|
||||
name: 'hexo-theme-solitude',
|
||||
file: 'js/utils.js',
|
||||
version
|
||||
},
|
||||
local_search: {
|
||||
name: 'hexo-theme-solitude',
|
||||
file: 'js/search/local.js',
|
||||
version
|
||||
},
|
||||
algolia_js: {
|
||||
name: 'hexo-theme-solitude',
|
||||
file: 'js/search/algolia.js',
|
||||
version
|
||||
},
|
||||
cover_local: {
|
||||
name: 'hexo-theme-solitude',
|
||||
file: 'js/covercolor/local.js',
|
||||
version
|
||||
},
|
||||
cover_api: {
|
||||
name: 'hexo-theme-solitude',
|
||||
file: 'js/covercolor/api.js',
|
||||
version
|
||||
},
|
||||
music_js: {
|
||||
name: 'hexo-theme-solitude',
|
||||
file: 'js/music.js',
|
||||
version
|
||||
},
|
||||
right_menu_js: {
|
||||
name: 'hexo-theme-solitude',
|
||||
file: 'js/right_menu.js',
|
||||
version
|
||||
},
|
||||
translate_js:{
|
||||
name: 'hexo-theme-solitude',
|
||||
file: 'js/tw_cn.js',
|
||||
version
|
||||
},
|
||||
efu_ai: {
|
||||
name: 'hexo-theme-solitude',
|
||||
file: 'js/third_party/efu_ai.min.js',
|
||||
version
|
||||
},
|
||||
commentBarrage: {
|
||||
name: 'hexo-theme-solitude',
|
||||
file: 'js/third_party/barrage.min.js',
|
||||
version
|
||||
},
|
||||
waterfall: {
|
||||
name: 'hexo-theme-solitude',
|
||||
file: 'js/third_party/waterfall.min.js',
|
||||
version
|
||||
},
|
||||
universe_js: {
|
||||
name: 'hexo-theme-solitude',
|
||||
file: 'js/third_party/universe.min.js',
|
||||
version
|
||||
},
|
||||
envelope_js: {
|
||||
name: 'hexo-theme-solitude',
|
||||
file: 'js/third_party/envelope.min.js',
|
||||
version
|
||||
}
|
||||
}
|
||||
|
||||
const minFile = file => {
|
||||
return file.replace(/(?<!\.min)\.(js|css)$/g, ext => '.min' + ext)
|
||||
}
|
||||
|
||||
const createCDNLink = (data, type, cond = '') => {
|
||||
Object.keys(data).forEach(key => {
|
||||
let { name, version, file, other_name } = data[key]
|
||||
const cdnjs_name = other_name || name
|
||||
const cdnjs_file = file.replace(/^[lib|dist]*\/|browser\//g, '')
|
||||
const min_cdnjs_file = minFile(cdnjs_file)
|
||||
if (cond === 'internal') file = `source/${file}`
|
||||
const min_file = minFile(file)
|
||||
const verType = CDN.version ? (type === 'local' ? `?v=${version}` : `@${version}`) : ''
|
||||
|
||||
const value = {
|
||||
version,
|
||||
name,
|
||||
file,
|
||||
cdnjs_file,
|
||||
min_file,
|
||||
min_cdnjs_file,
|
||||
cdnjs_name
|
||||
}
|
||||
|
||||
const cdnSource = {
|
||||
local: cond === 'internal' ? `${cdnjs_file + verType}` : `/pluginsSrc/${name}/${file + verType}`,
|
||||
jsdelivr: `https://cdn.jsdelivr.net/npm/${name}${verType}/${min_file}`,
|
||||
unpkg: `https://unpkg.com/${name}${verType}/${file}`,
|
||||
cdnjs: `https://cdnjs.cloudflare.com/ajax/libs/${cdnjs_name}/${version}/${min_cdnjs_file}`,
|
||||
custom: (CDN.custom_format || '').replace(/\$\{(.+?)}/g, (match, $1) => value[$1]),
|
||||
}
|
||||
|
||||
data[key] = cdnSource[type]
|
||||
})
|
||||
|
||||
if (cond === 'internal') data.main_css = 'css/index.css' + (CDN.version ? `?v=${version}` : '')
|
||||
return data
|
||||
}
|
||||
|
||||
// delete null value
|
||||
const deleteNullValue = obj => {
|
||||
if (!obj) return
|
||||
for (const i in obj) {
|
||||
obj[i] === null && delete obj[i]
|
||||
}
|
||||
return obj
|
||||
}
|
||||
|
||||
themeConfig.cdn = Object.assign(
|
||||
createCDNLink(internalSrc, CDN.internal, 'internal'),
|
||||
createCDNLink(thirdPartySrc, CDN.third_party),
|
||||
deleteNullValue(CDN.option)
|
||||
)
|
||||
})
|
||||
@@ -0,0 +1,19 @@
|
||||
hexo.extend.filter.register('before_generate', () => {
|
||||
const hexoVer = hexo.version.replace(/(^.*\..*)\..*/, '$1');
|
||||
const nodeVer = process.version.replace(/^v/, '');
|
||||
const [majorVer] = nodeVer.split('.');
|
||||
const logger = hexo.log;
|
||||
const config = hexo.config;
|
||||
|
||||
if (hexoVer < 7.0) {
|
||||
logger.error('请把 Hexo 升级到 V7.0.0 或更高的版本!');
|
||||
logger.error('Please upgrade your Hexo to V7.0.0 or higher!');
|
||||
process.exit(-1);
|
||||
}
|
||||
|
||||
if (Number(majorVer) < 14) {
|
||||
logger.error('请将 Node.js 升级到 v14.0.0 或更高的版本!');
|
||||
logger.error('Please upgrade Node.js to v14.0.0 or later!');
|
||||
process.exit(-1);
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,390 @@
|
||||
hexo.extend.filter.register('before_generate', () => {
|
||||
const defaultConfig = {
|
||||
site: {
|
||||
name: {
|
||||
class: 'text',
|
||||
custom: 'Solitude'
|
||||
},
|
||||
siteIcon: '/img/pwa/favicon.ico',
|
||||
icon: 'icon'
|
||||
},
|
||||
nav: {
|
||||
group: null,
|
||||
menu: null,
|
||||
right: {
|
||||
random: false,
|
||||
console: false,
|
||||
custom: [],
|
||||
}
|
||||
},
|
||||
hometop: {
|
||||
enable: false,
|
||||
banner: {
|
||||
title: 'Solitude',
|
||||
url: 'A simple theme for Hexo',
|
||||
icon: null,
|
||||
},
|
||||
group: null,
|
||||
recommendList: {
|
||||
sup: 'Recommend',
|
||||
title: 'Solitude Docs',
|
||||
url: 'https://solitude.js.org/',
|
||||
img: '/img/default.avif',
|
||||
color: 'none',
|
||||
}
|
||||
},
|
||||
aside: {
|
||||
home: {
|
||||
noSticky: 'about',
|
||||
Sticky: 'allInfo'
|
||||
},
|
||||
post: {
|
||||
noSticky: 'about',
|
||||
Sticky: 'allInfo'
|
||||
},
|
||||
page: {
|
||||
noSticky: 'about',
|
||||
Sticky: 'allInfo'
|
||||
},
|
||||
card: {
|
||||
style: 0,
|
||||
author: {
|
||||
img: '/img/logo.png',
|
||||
sticker: '/img/happy-sticker.avif',
|
||||
},
|
||||
url: '/about/',
|
||||
background: null,
|
||||
content1: 'Solitude',
|
||||
content2: 'A simple theme for Hexo',
|
||||
sayhello: {
|
||||
morning: 'Good Morning',
|
||||
noon: 'Good Noon',
|
||||
afternoon: 'Good Afternoon',
|
||||
night: 'Good Night',
|
||||
goodnight: 'Good Night',
|
||||
},
|
||||
sayhello2: ['Welcome to Solitude', 'A simple theme for Hexo', 'Enjoy your time', 'Have a nice day', 'Good luck'],
|
||||
information: null,
|
||||
},
|
||||
flip: {
|
||||
favicon: '',
|
||||
face: '',
|
||||
backface: '',
|
||||
backcolor: 'var(--efu-blue)'
|
||||
},
|
||||
newest_comment: {
|
||||
enable: false,
|
||||
storage: .5,
|
||||
limit: 5
|
||||
},
|
||||
toc: {
|
||||
post: true,
|
||||
page: false,
|
||||
vague: true,
|
||||
},
|
||||
tags: {
|
||||
enable: true,
|
||||
limit: 20,
|
||||
highlight: false,
|
||||
list: [],
|
||||
},
|
||||
archive: {
|
||||
enable: true,
|
||||
type: 'month'
|
||||
},
|
||||
siteinfo: {
|
||||
postcount: true,
|
||||
wordcount: false,
|
||||
pv: true,
|
||||
uv: true,
|
||||
updatetime: true,
|
||||
runtimeenable: true,
|
||||
runtime: "2023-04-20 00:00:00",
|
||||
},
|
||||
},
|
||||
index_post_list: {
|
||||
direction: 'column',
|
||||
column: 2,
|
||||
content: false,
|
||||
length: 500,
|
||||
cover: 'both'
|
||||
},
|
||||
page: {
|
||||
error: true,
|
||||
tags: true,
|
||||
categories: true,
|
||||
default: {
|
||||
cover: ['/img/default.avif'],
|
||||
}
|
||||
},
|
||||
post: {
|
||||
default: {
|
||||
cover: ['/img/default.avif'],
|
||||
locate: 'China, Changsha',
|
||||
copyright: {
|
||||
enable: true,
|
||||
license: 'CC BY-NC-SA 4.0',
|
||||
licenurl: 'https://creativecommons.org/licenses/by-nc-sa/4.0/',
|
||||
}
|
||||
},
|
||||
meta: {
|
||||
date: false,
|
||||
updated: false,
|
||||
locate: false,
|
||||
wordcount: false,
|
||||
readtime: false,
|
||||
pv: false,
|
||||
uv: false,
|
||||
comment: false,
|
||||
},
|
||||
award: {
|
||||
enable: false,
|
||||
appreciators: '/',
|
||||
title: '感谢您的赞赏。',
|
||||
desc: '因为有你们的支持,我才体会到写文章的价值。',
|
||||
list: [],
|
||||
},
|
||||
rss: null,
|
||||
covercolor: {
|
||||
enable: false,
|
||||
mode: 'local',
|
||||
api: 'https://api.qjqq.cn/api/Imgcolor?img=',
|
||||
time: 43200000,
|
||||
},
|
||||
footer: {
|
||||
enable: true,
|
||||
desc: "来自 Efu 的文章",
|
||||
button: {
|
||||
enable: true,
|
||||
name: '返回首页',
|
||||
url: '/'
|
||||
}
|
||||
}
|
||||
},
|
||||
theme_color: {
|
||||
dark: "#ffc848",
|
||||
dark_op: "#f2b94b23",
|
||||
dark_op_deep: "#f2b94bdd",
|
||||
dark_none: "#f2b94b00",
|
||||
light: "#425AEF",
|
||||
light_op: "#4259ef23",
|
||||
light_op_deep: "#4259efdd",
|
||||
light_none: "#4259ef01"
|
||||
},
|
||||
display_mode: {
|
||||
type: 'auto',
|
||||
universe: false
|
||||
},
|
||||
related_post: {
|
||||
enable: false,
|
||||
limit: 2,
|
||||
date_type: 'created'
|
||||
},
|
||||
footer: {
|
||||
information: {
|
||||
author: false,
|
||||
left: null,
|
||||
right: null,
|
||||
},
|
||||
group: null,
|
||||
randomlink: false,
|
||||
privacy: null,
|
||||
license: null,
|
||||
links: [{
|
||||
name: 'Solitude',
|
||||
url: 'https://github.com/everfu/hexo-theme-solitude',
|
||||
}]
|
||||
},
|
||||
errorpage: {
|
||||
img: 'https://7.isyangs.cn/34/65f2e65eae32a-34.png',
|
||||
text: '404 Not Found',
|
||||
recommendList: true
|
||||
},
|
||||
says: {
|
||||
enable: false,
|
||||
home_mini: false,
|
||||
style: 1,
|
||||
strip: 30
|
||||
},
|
||||
recent_comments: {
|
||||
enable: false,
|
||||
limit: 50,
|
||||
console: false,
|
||||
page: '/recentcomments/'
|
||||
},
|
||||
envelope: {
|
||||
enable: false,
|
||||
line: 10,
|
||||
speed: 20,
|
||||
hover: true,
|
||||
loop: true,
|
||||
page: '/message/'
|
||||
},
|
||||
meting_api: "https://meting.qjqq.cn/?server=:server&type=:type&id=:id&auth=:auth&r=:r",
|
||||
music: {
|
||||
enable: false,
|
||||
id: '8407304077',
|
||||
server: 'netease',
|
||||
type: 'playlist',
|
||||
volume: 0.8,
|
||||
mutex: true,
|
||||
},
|
||||
capsule: {
|
||||
enable: false,
|
||||
id: '8407304077',
|
||||
server: 'netease',
|
||||
type: 'playlist',
|
||||
},
|
||||
keyboard: {
|
||||
enable: false,
|
||||
list: []
|
||||
},
|
||||
lazyload: {
|
||||
enable: false,
|
||||
field: 'site',
|
||||
placeholder: '/img/loading.avif',
|
||||
errorimg: '/img/error_load.avif'
|
||||
},
|
||||
loading: {
|
||||
fullpage: false,
|
||||
pace: true,
|
||||
},
|
||||
highlight: {
|
||||
enable: true,
|
||||
limit: 200,
|
||||
copy: true,
|
||||
expand: true,
|
||||
theme: 'default',
|
||||
color: 'default',
|
||||
},
|
||||
lightbox: false,
|
||||
fancybox: false,
|
||||
mediumZoom: false,
|
||||
mermaid: false,
|
||||
OpenGraph: {
|
||||
enable: false,
|
||||
options: null
|
||||
},
|
||||
wordcount: false,
|
||||
busuanzi: false,
|
||||
search: {
|
||||
enable: false,
|
||||
type: 'local',
|
||||
tags: [],
|
||||
algolia: null,
|
||||
local: {
|
||||
preload: false,
|
||||
CDN: null,
|
||||
}
|
||||
},
|
||||
rightside: {
|
||||
enable: false
|
||||
},
|
||||
copy: {
|
||||
enable: true,
|
||||
copyright: {
|
||||
enable: false,
|
||||
limit: 50
|
||||
}
|
||||
},
|
||||
post_ai: {
|
||||
enable: false,
|
||||
modelName: 'GPT 3',
|
||||
key: 'your key',
|
||||
talk: 'I am a AI.',
|
||||
randomPost: false,
|
||||
tips: 'AI is not perfect, please use it with caution.'
|
||||
},
|
||||
katex: {
|
||||
enable: false,
|
||||
per_page: false,
|
||||
copytex: false,
|
||||
},
|
||||
comment: {
|
||||
use: null,
|
||||
commentBarrage: false,
|
||||
lazyload: false,
|
||||
count: false,
|
||||
avatar: 'https://cravatar.cn',
|
||||
},
|
||||
twikoo: {
|
||||
envId: 'your envId',
|
||||
region: null,
|
||||
style: true,
|
||||
accessToken: null,
|
||||
option: null,
|
||||
},
|
||||
waline: {
|
||||
envId: 'your envId',
|
||||
pageview: true,
|
||||
option: null,
|
||||
},
|
||||
valine: {
|
||||
appId: 'your appId',
|
||||
appKey: 'your appKey',
|
||||
serverURLs: 'your serverURLs',
|
||||
avatar: 'monsterid',
|
||||
visitor: false,
|
||||
style: true,
|
||||
option: null,
|
||||
},
|
||||
artalk: {
|
||||
server: 'your server',
|
||||
site: 'your site-name',
|
||||
option: null,
|
||||
},
|
||||
verify_site: [],
|
||||
css_prefix: false,
|
||||
font: {
|
||||
'font-size': '16px',
|
||||
'code-font-size': '16px',
|
||||
'font-family': 'PingFang SC, Hiragino Sans GB,Microsoft YaHei',
|
||||
'code-font-family': 'monospace, monospace',
|
||||
},
|
||||
extends: {
|
||||
head: [],
|
||||
body: [],
|
||||
},
|
||||
pwa: {
|
||||
enable: false,
|
||||
manifest: '/manifest.json',
|
||||
theme_color: "#006a73",
|
||||
mask_icon: '/img/pwa/favicon.ico',
|
||||
apple_touch_icon: '/img/pwa/favicon.ico',
|
||||
bookmark_icon: '/img/pwa/favicon.ico',
|
||||
favicon_32_32: '/img/pwa/favicon_32.ico',
|
||||
favicon_16_16: '/img/pwa/favicon_16.ico'
|
||||
},
|
||||
google_adsense: {
|
||||
enable: false,
|
||||
auto_ads: false,
|
||||
aside_card: false,
|
||||
post_card: false,
|
||||
post_content: false,
|
||||
enable_page_level_ads: false,
|
||||
js: 'https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js',
|
||||
client: '',
|
||||
slot: '',
|
||||
},
|
||||
right_menu: {
|
||||
enable: false,
|
||||
commentBarrage: false,
|
||||
translate: {
|
||||
enable: false,
|
||||
defaultEncoding: 2,
|
||||
translateDelay: 0,
|
||||
},
|
||||
custom_list: []
|
||||
},
|
||||
CDN: {
|
||||
internal: 'local',
|
||||
third_party: 'cdnjs',
|
||||
version: true,
|
||||
custom_format: 'https://cdn.staticfile.net/${cdnjs_name}/${version}/${min_cdnjs_file}',
|
||||
option: {
|
||||
solitude_css: 'https://cdn2.codesign.qq.com/icons/7pOrz0WXB5ZWJPX/latest/iconfont.css',
|
||||
}
|
||||
}
|
||||
}
|
||||
hexo.theme.config = Object.assign(defaultConfig, hexo.theme.config)
|
||||
}, 1)
|
||||
@@ -0,0 +1,33 @@
|
||||
hexo.extend.generator.register('404', function (locals) {
|
||||
if(!this.theme.config.page.error)return
|
||||
return {
|
||||
path: '404.html',
|
||||
layout: ['404'],
|
||||
data: {
|
||||
type: '404',
|
||||
comment: false
|
||||
}
|
||||
}
|
||||
})
|
||||
hexo.extend.generator.register('tags', function(locals) {
|
||||
if(!this.theme.config.page.tags)return
|
||||
return {
|
||||
path: 'tags/index.html',
|
||||
layout: ['page'],
|
||||
data: {
|
||||
type: 'tags',
|
||||
comment: false
|
||||
}
|
||||
};
|
||||
});
|
||||
hexo.extend.generator.register('categories', function(locals) {
|
||||
if(!this.theme.config.page.categories)return
|
||||
return {
|
||||
path: 'categories/index.html',
|
||||
layout: ['page'],
|
||||
data: {
|
||||
type: 'categories',
|
||||
comment: false
|
||||
}
|
||||
};
|
||||
});
|
||||
@@ -0,0 +1,14 @@
|
||||
hexo.on('ready', () => {
|
||||
const {version} = require('../../package.json')
|
||||
hexo.log.info(`
|
||||
===================================================================
|
||||
##### #### # ##### ###### # # ###### ######
|
||||
# # # # # # # # # # #
|
||||
##### # # # # # # # # # ######
|
||||
# # # # # # # # # # #
|
||||
###### #### ##### ##### # ### ###### ######
|
||||
${version}
|
||||
===================================================================
|
||||
GitHub: https://github.com/everfu/hexo-theme-solitude
|
||||
`)
|
||||
})
|
||||
@@ -0,0 +1,28 @@
|
||||
'use strict';
|
||||
|
||||
hexo.extend.filter.register('before_post_render', () => {
|
||||
const data = hexo.locals.get('data');
|
||||
const logger = hexo.log;
|
||||
const theme = hexo.theme.config;
|
||||
if (theme.hometop.enable && !theme.hometop.banner.icon) {
|
||||
logger.error('\n 启用banner的情况下,必须提供 icon 图片!\n 请在主题配置文件中设置 hometop.banner.icon 选项。');
|
||||
logger.error('\n If banner is enabled, icon image must be supplied! \n Please set the hometop.banner.icon option in the theme configuration file.');
|
||||
process.exit(-1);
|
||||
}
|
||||
if (theme.says.enable && !data.essay) {
|
||||
logger.error('\n 启用说说的情况下,必须提供 essay 数据文件!\n 请新建 essay.yaml。');
|
||||
logger.error('\n If says is enabled, essay data must be supplied! \n Please create essay.yaml.');
|
||||
process.exit(-1);
|
||||
}
|
||||
if (theme.footer.randomlink && !data.links){
|
||||
logger.error('\n 启用随机链接的情况下,必须提供 links 数据!\n 请新建 links.yaml。');
|
||||
logger.error('\n If randomlink is enabled, links data must be supplied! \n Please create links.yaml.');
|
||||
process.exit(-1);
|
||||
}
|
||||
if (theme.lightbox && !theme.fancybox && !theme.mediumZoom){
|
||||
logger.error('\n 启用 lightbox 的情况下,必须提供 fancybox 或 mediumZoom 选项!\n 请在主题配置文件中设置 fancybox 或 mediumZoom 选项。');
|
||||
logger.error('\n If lightbox is enabled, fancybox or mediumZoom option must be supplied! \n Please set the fancybox or mediumZoom option in the theme configuration file.');
|
||||
process.exit(-1);
|
||||
}
|
||||
}
|
||||
);
|
||||
@@ -0,0 +1,13 @@
|
||||
/**
|
||||
* 将 use 分拆并将首字大写
|
||||
*/
|
||||
|
||||
hexo.extend.filter.register('before_generate', () => {
|
||||
const themeConfig = hexo.theme.config
|
||||
let { use } = themeConfig.comment
|
||||
if (!use) return
|
||||
if (typeof use === 'string') {
|
||||
use = use.split(',').slice(0,2)
|
||||
}
|
||||
themeConfig.comment.use = use.map(item => item.toLowerCase().replace(/\b[a-z]/g, s => s.toUpperCase()))
|
||||
})
|
||||
@@ -0,0 +1,31 @@
|
||||
'use strict';
|
||||
|
||||
hexo.extend.filter.register('after_post_render', function (data) {
|
||||
data.title = data.title || 'Untitled';
|
||||
const {config} = hexo.theme;
|
||||
if (data.layout === 'post') {
|
||||
let {copyright, locate, cover} = hexo.theme.config.post.default
|
||||
cover = cover !== null ? cover : ['/img/default.avif']
|
||||
data.locate = data.locate || locate
|
||||
data.cc = data.cc || copyright
|
||||
data.cover = data.cover || cover[getRandomInt(0, cover?.length)]
|
||||
data.excerpt = data.description || data.excerpt
|
||||
data.toc = !!(config.aside.toc.post && data.toc !== false)
|
||||
data.ai = data.ai !== false
|
||||
}
|
||||
if (data.layout === 'page') {
|
||||
let {cover} = hexo.theme.config.page.default
|
||||
cover = cover !== null ? cover : ['/img/default.avif']
|
||||
data.cover = data.cover || cover[getRandomInt(0, cover?.length)]
|
||||
data.excerpt = data.title
|
||||
data.toc = !!(config.aside.toc.page && data.toc !== false && data.aside);
|
||||
}
|
||||
data.comment = !!(config.comment.use && data.comment !== false);
|
||||
return data;
|
||||
});
|
||||
|
||||
function getRandomInt(min, max) {
|
||||
min = Math.ceil(min);
|
||||
max = Math.floor(max);
|
||||
return Math.floor(Math.random() * (max - min)) + min;
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
'use strict'
|
||||
|
||||
const urlFor = require('hexo-util').url_for.bind(hexo)
|
||||
|
||||
const lazyload = (content, img) => {
|
||||
return content.replace(/(<img(?!.*?class[\t]*=[\t]*['"].*?nolazyload.*?['"]).*? src=)/gi, `$1 "${img}" data-lazy-src=`)
|
||||
}
|
||||
|
||||
hexo.extend.filter.register('after_render:html', function (data) {
|
||||
const { enable, placeholder ,field } = hexo.theme.config.lazyload
|
||||
if (!enable || field !== 'site') return;
|
||||
return lazyload(data, urlFor(placeholder))
|
||||
})
|
||||
|
||||
hexo.extend.filter.register('after_post_render', data => {
|
||||
const { enable, placeholder, field } = hexo.theme.config.lazyload
|
||||
if (!enable || field !== 'post') return
|
||||
data.content = lazyload(data.content, urlFor(placeholder))
|
||||
return data
|
||||
})
|
||||
@@ -0,0 +1,13 @@
|
||||
'use strict'
|
||||
|
||||
hexo.extend.filter.register('before_post_render', data => {
|
||||
const imgTestReg = /\.(png|jpe?g|gif|svg|webp)(\?.*)?$/i
|
||||
let { cover: coverVal } = data
|
||||
|
||||
// Add path to top_img and cover if post_asset_folder is enabled
|
||||
if (hexo.config.post_asset_folder) {
|
||||
if (coverVal && coverVal.indexOf('/') === -1 && imgTestReg.test(coverVal)) data.cover = `${data.path}${coverVal}`
|
||||
}
|
||||
|
||||
return data
|
||||
})
|
||||
@@ -0,0 +1,5 @@
|
||||
hexo.extend.filter.register('after_render:html', function (data) {
|
||||
const posts = hexo.locals.get('posts').filter(post => post.random !== false).map(post => post.path);
|
||||
data += `<script>const posts=${JSON.stringify(posts)};function toRandomPost(){ pjax.loadUrl('/'+posts[Math.floor(Math.random()*posts.length)]); }</script>`;
|
||||
return data;
|
||||
});
|
||||
@@ -0,0 +1,14 @@
|
||||
const moment = require('moment')
|
||||
|
||||
hexo.extend.helper.register('getArchiveLength', function (type) {
|
||||
if (type !== 'year' && type !== 'month') {
|
||||
type = 'year';
|
||||
}
|
||||
const posts = this.site.posts.sort('-date').data
|
||||
let archive = {}
|
||||
for (const post of posts) {
|
||||
const postdate = type === 'year' ? moment(post.date).format('YYYY') : moment(post.date).format('YYYY/MM');
|
||||
archive[postdate] = (archive[postdate] || 0) + 1;
|
||||
}
|
||||
return archive;
|
||||
});
|
||||
@@ -0,0 +1,86 @@
|
||||
/**
|
||||
* Solitude
|
||||
* inject is to head
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
hexo.extend.helper.register('inject_head_js', function () {
|
||||
const createJS = () => `
|
||||
const saveToLocal = {
|
||||
set: function setWithExpiry(key, value, ttl) {
|
||||
if (ttl === 0)
|
||||
return
|
||||
const now = new Date()
|
||||
const expiryDay = ttl * 86400000
|
||||
const item = {
|
||||
value: value,
|
||||
expiry: now.getTime() + expiryDay
|
||||
}
|
||||
localStorage.setItem(key, JSON.stringify(item))
|
||||
},
|
||||
get: function getWithExpiry(key) {
|
||||
const itemStr = localStorage.getItem(key)
|
||||
|
||||
if (!itemStr) {
|
||||
return undefined
|
||||
}
|
||||
const item = JSON.parse(itemStr)
|
||||
const now = new Date()
|
||||
|
||||
if (now.getTime() > item.expiry) {
|
||||
localStorage.removeItem(key)
|
||||
return undefined
|
||||
}
|
||||
return item.value
|
||||
}
|
||||
};
|
||||
window.utils = {
|
||||
saveToLocal: saveToLocal,
|
||||
getCSS: (url, id = false) => new Promise((resolve, reject) => {
|
||||
const link = document.createElement('link')
|
||||
link.rel = 'stylesheet'
|
||||
link.href = url
|
||||
if (id) link.id = id
|
||||
link.onerror = reject
|
||||
link.onload = link.onreadystatechange = function() {
|
||||
const loadState = this.readyState
|
||||
if (loadState && loadState !== 'loaded' && loadState !== 'complete') return
|
||||
link.onload = link.onreadystatechange = null
|
||||
resolve()
|
||||
}
|
||||
document.head.appendChild(link)
|
||||
}),
|
||||
getScript: (url, attr = {}) => new Promise((resolve, reject) => {
|
||||
const script = document.createElement('script')
|
||||
script.src = url
|
||||
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()
|
||||
}
|
||||
|
||||
Object.keys(attr).forEach(key => {
|
||||
script.setAttribute(key, attr[key])
|
||||
})
|
||||
|
||||
document.head.appendChild(script)
|
||||
}),
|
||||
addGlobalFn: (key, fn, name = false, parent = window) => {
|
||||
const globalFn = parent.globalFn || {}
|
||||
const keyObj = globalFn[key] || {}
|
||||
|
||||
if (name && keyObj[name]) return
|
||||
|
||||
name = name || Object.keys(keyObj).length
|
||||
keyObj[name] = fn
|
||||
globalFn[key] = keyObj
|
||||
parent.globalFn = globalFn
|
||||
},
|
||||
}
|
||||
`
|
||||
return `<script>(()=>{${createJS()}})()</script>`
|
||||
})
|
||||
@@ -0,0 +1,17 @@
|
||||
"use strict";
|
||||
const { stripHTML, escapeHTML, prettyUrls } = require("hexo-util");
|
||||
hexo.extend.helper.register('page_description', function () {
|
||||
const { config, page } = this
|
||||
let description = page.description || page.content || page.title || config.description
|
||||
|
||||
if (description) {
|
||||
description = escapeHTML(stripHTML(description).substring(0, 150)
|
||||
.trim()
|
||||
).replace(/\n/g, ' ').replace(/\s+/g, ' ');
|
||||
return description
|
||||
}
|
||||
})
|
||||
|
||||
hexo.extend.helper.register("urlNoIndex", function (url = null) {
|
||||
return prettyUrls(url || this.url, { trailing_index: false, trailing_html: true });
|
||||
});
|
||||
@@ -0,0 +1,85 @@
|
||||
/**
|
||||
* related post
|
||||
* from solitude
|
||||
*/
|
||||
|
||||
'use strict'
|
||||
|
||||
hexo.extend.helper.register('related_posts', function (currentPost, allPosts) {
|
||||
const relatedPosts = []
|
||||
const config = hexo.theme.config
|
||||
const limitNum = config.related_post.limit || 6
|
||||
const dateType = config.related_post.date_type || 'created'
|
||||
const headlineLang = this._p('star')
|
||||
|
||||
currentPost.tags.forEach(function (tag) {
|
||||
allPosts.forEach(function (post) {
|
||||
if (isTagRelated(tag.name, post.tags) && currentPost.path !== post.path) {
|
||||
const relatedPost = {
|
||||
title: post.title,
|
||||
path: post.path,
|
||||
cover: post.cover,
|
||||
cover_type: post.cover_type,
|
||||
weight: 1,
|
||||
updated: post.updated,
|
||||
created: post.date
|
||||
}
|
||||
const index = findItem(relatedPosts, 'path', post.path)
|
||||
if (index !== -1) {
|
||||
relatedPosts[index].weight += 1
|
||||
} else {
|
||||
relatedPosts.push(relatedPost)
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
if (relatedPosts.length === 0) {
|
||||
return ''
|
||||
}
|
||||
|
||||
relatedPosts.sort(compare('weight', dateType))
|
||||
|
||||
let result = '<div class="relatedPosts">'
|
||||
result += `<div class="headline"><i class="solitude st-star-smile-fill"></i><span>${headlineLang}</span><div class="relatedPosts-link"><a onclick="event.preventDefault(); toRandomPost();" href="javascript:void(0);" rel="external nofollow" data-pjax-state="">${this._p('random')}</a></div></div>`
|
||||
result += '<div class="relatedPosts-list">'
|
||||
|
||||
for (let i = 0; i < Math.min(relatedPosts.length, limitNum); i++) {
|
||||
const cover = relatedPosts[i].cover || 'var(--default-bg-color)'
|
||||
const title = this.escape_html(relatedPosts[i].title)
|
||||
result += `<div><a href="${this.url_for(relatedPosts[i].path)}" title="${title}">`
|
||||
result += `<img class="cover" src="${this.url_for(cover)}" alt="cover">`
|
||||
result += `<div class="content is-center"><div class="title">${title}</div></div>`
|
||||
result += '</a></div>'
|
||||
}
|
||||
|
||||
result += '</div></div>'
|
||||
return result
|
||||
})
|
||||
|
||||
function isTagRelated(tagName, TBDtags) {
|
||||
return TBDtags.some(function (tag) {
|
||||
return tagName === tag.name
|
||||
})
|
||||
}
|
||||
|
||||
function findItem(arrayToSearch, attr, val) {
|
||||
return arrayToSearch.findIndex(function (item) {
|
||||
return item[attr] === val
|
||||
})
|
||||
}
|
||||
|
||||
function compare(attr, dateType) {
|
||||
return function (a, b) {
|
||||
const val1 = a[attr]
|
||||
const val2 = b[attr]
|
||||
if (val1 === val2) {
|
||||
if (dateType === 'created') {
|
||||
return b.created - a.created
|
||||
} else if (dateType === 'updated') {
|
||||
return b.updated - a.updated
|
||||
}
|
||||
}
|
||||
return val2 - val1
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
hexo.extend.filter.register('stylus:renderer', function (style) {
|
||||
const {config, theme} = this;
|
||||
const data = hexo.locals.get('data');
|
||||
|
||||
style.define('$about', data && data.about ? Object.keys(data.about) : false);
|
||||
style.define('$link', !!(data && data.links) || !!(data && data.tlink))
|
||||
style.define('$equipment', !!(data && data.equipment))
|
||||
|
||||
// highlight
|
||||
const {syntax_highlighter: syntaxHighlighter, highlight, prismjs} = hexo.config
|
||||
let {enable: highlightEnable, line_number: highlightLineNumber} = highlight
|
||||
let {enable: prismjsEnable, line_number: prismjsLineNumber} = prismjs
|
||||
|
||||
// for hexo > 7.0
|
||||
if (syntaxHighlighter) {
|
||||
highlightEnable = syntaxHighlighter === 'highlight.js'
|
||||
prismjsEnable = syntaxHighlighter === 'prismjs'
|
||||
}
|
||||
|
||||
style.define('$highlight_enable', highlightEnable)
|
||||
style.define('$highlight_line_number', highlightLineNumber)
|
||||
style.define('$prismjs_enable', prismjsEnable)
|
||||
style.define('$prismjs_line_number', prismjsLineNumber)
|
||||
});
|
||||
@@ -0,0 +1,35 @@
|
||||
"use strict";
|
||||
|
||||
function postBtns(args, content) {
|
||||
return `<div class="btns ${args.join(" ")}">
|
||||
${content}
|
||||
</div>`;
|
||||
}
|
||||
|
||||
function postCell(args, content) {
|
||||
args = args.join(" ").split(",");
|
||||
let text = args[0] || "";
|
||||
let url = args[1] || "";
|
||||
text = text.trim();
|
||||
url = url.trim();
|
||||
if (url.length > 0) {
|
||||
url = "href='" + url + "'";
|
||||
}
|
||||
let icon = "";
|
||||
let img = "https://npm.elemecdn.com/hexo-butterfly-tag-plugins-plus/lib/assets/default.svg";
|
||||
if (args.length > 2) {
|
||||
if (args[2].indexOf(" solitude") > -1) {
|
||||
icon = args[2].trim();
|
||||
} else {
|
||||
img = args[2].trim();
|
||||
}
|
||||
}
|
||||
if (icon.length > 0) {
|
||||
return `<a class="button no-text-decoration" ${url} title='${text}'><i class='${icon}'></i>${text}</a>`;
|
||||
} else {
|
||||
return `<a class="button no-text-decoration" ${url} title='${text}'><img src='${img}'>${text}</a>`;
|
||||
}
|
||||
}
|
||||
|
||||
hexo.extend.tag.register("btns", postBtns, { ends: true });
|
||||
hexo.extend.tag.register("cell", postCell);
|
||||
@@ -0,0 +1,21 @@
|
||||
"use strict";
|
||||
|
||||
const urlFor = require("hexo-util").url_for.bind(hexo);
|
||||
|
||||
function btn(args) {
|
||||
args = args.join(" ").split(",");
|
||||
let url = args[0] || "";
|
||||
let text = args[1] || "";
|
||||
let icon = args[2] || "";
|
||||
let option = args[3] || "";
|
||||
|
||||
url = url.trim();
|
||||
text = text.trim();
|
||||
icon = icon.trim();
|
||||
option = option.trim();
|
||||
|
||||
return `<button class="btn-sco ${option}" onclick="${url.startsWith("http") ? `window.open('${url}')` : `pjax.loadUrl('${urlFor(url)}')`}"
|
||||
title="${text}">${icon.length ? `<i class="solitude ${icon}"></i>` : ""}${text.length ? `<span>${text}</span>` : ""}</button>`;
|
||||
}
|
||||
|
||||
hexo.extend.tag.register("btn", btn, { ends: false });
|
||||
@@ -0,0 +1,7 @@
|
||||
'use strict'
|
||||
|
||||
function bilibili(args) {
|
||||
return `<iframe class="bvideo" width="100%" height="600" src="//player.bilibili.com/player.html?autoplay=0&bvid=${args}" border="0" frameBorder="no" framespacing="0" allowFullScreen="true"></iframe>`
|
||||
}
|
||||
|
||||
hexo.extend.tag.register('bvideo', bilibili, {ends: false})
|
||||
@@ -0,0 +1,51 @@
|
||||
'use strict';
|
||||
|
||||
function postCheckbox(args) {
|
||||
args = args.join(' ').split(',')
|
||||
var cls = ''
|
||||
var text = ''
|
||||
var checked = false
|
||||
if (args.length > 1) {
|
||||
cls = (args[0] || '').trim()
|
||||
if (cls.length > 0) {
|
||||
cls = ' ' + cls
|
||||
}
|
||||
if (cls.indexOf('checked') > -1) {
|
||||
checked = true
|
||||
}
|
||||
text = (args[1] || '').trim()
|
||||
} else if (args.length > 0) {
|
||||
text = (args[0] || '').trim()
|
||||
}
|
||||
if (text.length > 0) {
|
||||
return `<div class='checkbox${cls}'><input type="checkbox" ${ checked ? 'checked="checked"' : '' }/>
|
||||
${hexo.render.renderSync({text: text, engine: 'markdown'}).split('\n').join('')}
|
||||
</div>`
|
||||
}
|
||||
}
|
||||
function postRadio(args) {
|
||||
args = args.join(' ').split(',')
|
||||
var cls = ''
|
||||
var text = ''
|
||||
var checked = false
|
||||
if (args.length > 1) {
|
||||
cls = (args[0] || '').trim()
|
||||
if (cls.length > 0) {
|
||||
cls = ' ' + cls
|
||||
}
|
||||
if (cls.indexOf('checked') > -1) {
|
||||
checked = true
|
||||
}
|
||||
text = (args[1] || '').trim()
|
||||
} else if (args.length > 0) {
|
||||
text = (args[0] || '').trim()
|
||||
}
|
||||
if (text.length > 0) {
|
||||
return `<div class='checkbox${cls}'><input type="radio" ${ checked ? 'checked="checked"' : '' }/>
|
||||
${hexo.render.renderSync({text: text, engine: 'markdown'}).split('\n').join('')}
|
||||
</div>`
|
||||
}
|
||||
}
|
||||
|
||||
hexo.extend.tag.register('checkbox', postCheckbox);
|
||||
hexo.extend.tag.register('radio', postRadio);
|
||||
@@ -0,0 +1,13 @@
|
||||
'use strict'
|
||||
|
||||
function postTabs(args, content) {
|
||||
const title = args[0] ? args[0] : ""
|
||||
const open = args[1] ? args[1] : ""
|
||||
|
||||
return `<details ${open}><summary>${title}</summary><div class="content">${hexo.render.renderSync({
|
||||
text: content,
|
||||
engine: 'markdown'
|
||||
})}</div></details>`
|
||||
}
|
||||
|
||||
hexo.extend.tag.register('fold', postTabs, {ends: true})
|
||||
@@ -0,0 +1,37 @@
|
||||
'use strict';
|
||||
|
||||
const urlFor = require('hexo-util').url_for.bind(hexo)
|
||||
|
||||
const galleryBox = args => {
|
||||
const [name, descr, url, img] = args
|
||||
const imgUrl = urlFor(img)
|
||||
const urlLink = urlFor(url)
|
||||
|
||||
return `<figure class="gallery-group">
|
||||
<img class="gallery-group-img no-lightbox" src='${imgUrl}' alt="Group Image Gallery">
|
||||
<figcaption>
|
||||
<div class="gallery-group-name">${name}</div>
|
||||
<p>${descr}</p>
|
||||
<a href='${urlLink}'></a>
|
||||
</figcaption>
|
||||
</figure>
|
||||
`
|
||||
}
|
||||
|
||||
const gallery = (args, content) => {
|
||||
let html = ""
|
||||
const regex = /!\[(.*?)\]\(([^\s]*)\s*(?:["'](.*?)["']?)?\s*\)/g
|
||||
let m
|
||||
while ((m = regex.exec(content)) !== null) {
|
||||
if (m.index === regex.lastIndex) {
|
||||
regex.lastIndex++
|
||||
}
|
||||
html += `<div class="gallery-item"><img class="nolazyload" src=${m[2]} alt="${m[1]}" /></div>`
|
||||
}
|
||||
return `<div class="gallery-container waterfall">
|
||||
${html}
|
||||
</div>`
|
||||
}
|
||||
|
||||
hexo.extend.tag.register('gallery', gallery, {ends: true})
|
||||
hexo.extend.tag.register('galleryGroup', galleryBox)
|
||||
@@ -0,0 +1,75 @@
|
||||
'use strict';
|
||||
|
||||
hexo.extend.tag.register('image', function(args) {
|
||||
args = args.join(' ').split(',');
|
||||
let url = args[0].trim();
|
||||
let alt = '';
|
||||
let bg = '';
|
||||
let style = '';
|
||||
if (args.length > 1) {
|
||||
for (let i = 1; i < args.length; i++) {
|
||||
let tmp = args[i].trim();
|
||||
if (tmp.includes('alt=')) {
|
||||
alt = tmp.substring(4, tmp.length);
|
||||
} else if (tmp.includes('width=')) {
|
||||
style += 'width:' + tmp.substring(6, tmp.length) + ';';
|
||||
} else if (tmp.includes('height=')) {
|
||||
style += 'height:' + tmp.substring(7, tmp.length) + ';';
|
||||
} else if (tmp.includes('bg=')) {
|
||||
bg = tmp.substring(3, tmp.length);
|
||||
}
|
||||
}
|
||||
}
|
||||
function img(url, alt, style) {
|
||||
let img = '';
|
||||
img += '<img class="img" src="' + url + '"';
|
||||
if (alt.length > 0) {
|
||||
img += ' alt="' + alt + '"';
|
||||
}
|
||||
if (style.length > 0) {
|
||||
img += ' style="' + style + '"';
|
||||
}
|
||||
img += '/>';
|
||||
return img;
|
||||
}
|
||||
|
||||
let ret = '';
|
||||
ret += '<div class="img-wrap">';
|
||||
ret += '<div class="img-bg"';
|
||||
if (bg.length > 0) {
|
||||
ret += ' style="background:' + bg + '"';
|
||||
}
|
||||
ret += '>';
|
||||
ret += img(url, alt, style);
|
||||
ret += '</div>';
|
||||
|
||||
if (alt.length > 0) {
|
||||
ret += '<span class="image-caption">' + alt + '</span>';
|
||||
}
|
||||
|
||||
ret += '</div>';
|
||||
return ret;
|
||||
});
|
||||
|
||||
hexo.extend.tag.register('inlineimage', function(args) {
|
||||
args = args.join(' ').split(', ');
|
||||
let url = args[0].trim();
|
||||
let ret = '';
|
||||
ret += '<img no-lazy class="inline" src="' + url + '"';
|
||||
let style = '';
|
||||
if (args.length > 1) {
|
||||
for (let i = 1; i < args.length; i++) {
|
||||
let tmp = args[i].trim();
|
||||
if (tmp.includes('height=')) {
|
||||
style += 'height:' + tmp.substring(7, tmp.length) + ';';
|
||||
}
|
||||
}
|
||||
}
|
||||
if (style.length > 0) {
|
||||
ret += ' style="' + style + '"';
|
||||
} else {
|
||||
ret += ' style="height:1.5em"';
|
||||
}
|
||||
ret += '/>';
|
||||
return ret;
|
||||
});
|
||||
@@ -0,0 +1,12 @@
|
||||
'use strict'
|
||||
|
||||
const urlFor = require('hexo-util').url_for.bind(hexo)
|
||||
|
||||
function inlineImg (args) {
|
||||
const img = args[0]
|
||||
const height = args[1] ? `style="height:${args[1]}"` : ''
|
||||
|
||||
return `<img class="inline-img" src="${urlFor(img)}" ${height}/>`
|
||||
}
|
||||
|
||||
hexo.extend.tag.register('inlineimage', inlineImg, { ends: false })
|
||||
@@ -0,0 +1,10 @@
|
||||
'use strict'
|
||||
|
||||
function addLabel (args, content) {
|
||||
const text = args[0]
|
||||
const className = args[1] || 'default'
|
||||
|
||||
return `<label class="hl-label bg-${className}">${text}</label> `
|
||||
}
|
||||
|
||||
hexo.extend.tag.register('label', addLabel, { ends: false })
|
||||
@@ -0,0 +1,50 @@
|
||||
const urlFor = require("hexo-util").url_for.bind(hexo);
|
||||
function link(args) {
|
||||
const themeConfig = hexo.theme.config;
|
||||
args = args.join(" ").split(",");
|
||||
let title = args[0];
|
||||
let sitename = args[1];
|
||||
let link = args[2];
|
||||
let imgUrl = args[3] || "";
|
||||
let favicon = themeConfig.site.siteIcon;
|
||||
let insideStation = false;
|
||||
|
||||
link = link.trim();
|
||||
imgUrl = imgUrl.trim();
|
||||
favicon = favicon.trim();
|
||||
|
||||
try {
|
||||
new URL(link);
|
||||
insideStation = false;
|
||||
} catch (err) {
|
||||
insideStation = true;
|
||||
}
|
||||
|
||||
if ((imgUrl === "") && (insideStation === false)) {
|
||||
let domain = new URL(link).hostname
|
||||
if (domain) {
|
||||
imgUrl_online = "https://api.iowen.cn/favicon/" + domain + ".png";
|
||||
}
|
||||
}
|
||||
|
||||
return `<a class="tag-link" target="_blank" href="${urlFor(link)}">
|
||||
<div class="tag-link-tips">${insideStation ? "站内链接" : "引用站外链接"
|
||||
}</div>
|
||||
<div class="tag-link-bottom">
|
||||
<div class="tag-link-left" style="${insideStation
|
||||
? `background-image: url(${imgUrl ? imgUrl : favicon})`
|
||||
: `background-image: url(${imgUrl ? imgUrl : imgUrl_online})`
|
||||
}">
|
||||
<i class="solitude st-link-m-line" style="${`(imgUrl) || (imgUrl_online)` ? "display: none" : ""
|
||||
}"></i>
|
||||
</div>
|
||||
<div class="tag-link-right">
|
||||
<div class="tag-link-title">${title}</div>
|
||||
<div class="tag-link-sitename">${sitename}</div>
|
||||
</div>
|
||||
<i class="solitude st-arrow-right-bold"></i>
|
||||
</div>
|
||||
</a>`;
|
||||
}
|
||||
|
||||
hexo.extend.tag.register("link", link, { ends: false });
|
||||
@@ -0,0 +1,29 @@
|
||||
'use strict';
|
||||
|
||||
function postAudio(args) {
|
||||
let src = args[0].trim()
|
||||
return `<div class="audio"><audio controls preload><source src='${src}' type='audio/mp3'>Your browser does not support the audio tag.</audio></div>`;
|
||||
}
|
||||
|
||||
function postVideo(args) {
|
||||
let src = args[0].trim()
|
||||
return `<div class="video"><video controls preload><source src='${src}' type='video/mp4'>Your browser does not support the video tag.</video></div>`;
|
||||
}
|
||||
|
||||
function postVideos(args, content) {
|
||||
args = args.join(' ').split(',')
|
||||
var cls = args[0]
|
||||
if (cls.length > 0) {
|
||||
cls = ' ' + cls
|
||||
}
|
||||
var col = Number(args[1]) || 0;
|
||||
if (col > 0) {
|
||||
return `<div class="videos${cls}" col='${col}'>${content}</div>`
|
||||
} else {
|
||||
return `<div class="videos${cls}">${content}</div>`
|
||||
}
|
||||
}
|
||||
|
||||
hexo.extend.tag.register('audio', postAudio);
|
||||
hexo.extend.tag.register('video', postVideo);
|
||||
hexo.extend.tag.register('videos', postVideos, {ends: true});
|
||||
@@ -0,0 +1,9 @@
|
||||
'use strict';
|
||||
|
||||
const {escapeHTML} = require('hexo-util')
|
||||
|
||||
function postMermaid(args, content) {
|
||||
return `<div class="mermaid">${escapeHTML(content)}</div>`;
|
||||
}
|
||||
|
||||
hexo.extend.tag.register('mermaid', postMermaid, {ends: true});
|
||||
@@ -0,0 +1,13 @@
|
||||
/**
|
||||
* note.js
|
||||
* transplant from hexo-theme-next
|
||||
* modified by @efu
|
||||
*/
|
||||
|
||||
hexo.extend.tag.register('note', function (types, content) {
|
||||
let type = ""
|
||||
for (let i = 0; i < types.length; i++) {
|
||||
type += " " + types[i]
|
||||
}
|
||||
return `<div class="note ${type}">${hexo.render.renderSync({text: content, engine: 'markdown'})}</div>`
|
||||
}, {ends: true});
|
||||
@@ -0,0 +1,17 @@
|
||||
'use strict';
|
||||
|
||||
function postP(args) {
|
||||
args = args.join(' ').split(',')
|
||||
let p0 = args[0].trim()
|
||||
let p1 = args[1].trim()
|
||||
return `<p class='p ${p0}'>${p1}</p>`;
|
||||
}
|
||||
function postSpan(args) {
|
||||
args = args.join(' ').split(',')
|
||||
let p0 = args[0].trim()
|
||||
let p1 = args[1].trim()
|
||||
return `<span class='p ${p0}'>${p1}</span>`;
|
||||
}
|
||||
|
||||
hexo.extend.tag.register('p', postP);
|
||||
hexo.extend.tag.register('span', postSpan);
|
||||
@@ -0,0 +1,61 @@
|
||||
/**
|
||||
* Tabs
|
||||
* from solitude
|
||||
*/
|
||||
|
||||
'use strict'
|
||||
|
||||
function postTabs (args, content) {
|
||||
const tabBlock = /<!--\s*tab (.*?)\s*-->\n([\w\W\s\S]*?)<!--\s*endtab\s*-->/g
|
||||
|
||||
args = args.join(' ').split(',')
|
||||
const tabName = args[0]
|
||||
const tabActive = Number(args[1]) || 0
|
||||
|
||||
const matches = []
|
||||
let match
|
||||
let tabId = 0
|
||||
let tabNav = ''
|
||||
let tabContent = ''
|
||||
|
||||
!tabName && hexo.log.warn('Tabs block must have unique name!')
|
||||
|
||||
while ((match = tabBlock.exec(content)) !== null) {
|
||||
matches.push(match[1])
|
||||
matches.push(match[2])
|
||||
}
|
||||
|
||||
for (let i = 0; i < matches.length; i += 2) {
|
||||
const tabParameters = matches[i].split('@')
|
||||
let postContent = matches[i + 1]
|
||||
let tabCaption = tabParameters[0] || ''
|
||||
let tabIcon = tabParameters[1] || ''
|
||||
let tabHref = ''
|
||||
|
||||
postContent = hexo.render.renderSync({ text: postContent, engine: 'markdown' }).trim()
|
||||
|
||||
tabId += 1
|
||||
tabHref = (tabName + ' ' + tabId).toLowerCase().split(' ').join('-');
|
||||
|
||||
((tabCaption.length === 0) && (tabIcon.length === 0)) && (tabCaption = tabName + ' ' + tabId)
|
||||
|
||||
const isOnlyicon = tabIcon.length > 0 && tabCaption.length === 0 ? ' style="text-align: center;"' : ''
|
||||
const icon = tabIcon.trim()
|
||||
tabIcon.length > 0 && (tabIcon = `<i ${isOnlyicon} class="tab solitude ${icon}"></i>`)
|
||||
|
||||
const toTop = '<button type="button" class="tab-to-top" aria-label="scroll to top"><i class="solitude st-arrow-up-line"></i></button>'
|
||||
|
||||
const isActive = (tabActive > 0 && tabActive === tabId) || (tabActive === 0 && tabId === 1) ? ' active' : ''
|
||||
tabNav += `<li class="tab${isActive}"><button type="button" data-href="#${tabHref}">${tabIcon + tabCaption.trim()}</button></li>`
|
||||
tabContent += `<div class="tab-item-content${isActive}" id="${tabHref}">${postContent + toTop}</div>`
|
||||
}
|
||||
|
||||
tabNav = `<ul class="nav-tabs">${tabNav}</ul>`
|
||||
tabContent = `<div class="tab-contents">${tabContent}</div>`
|
||||
|
||||
return `<div class="tabs" id="${tabName.toLowerCase().split(' ').join('-')}">${tabNav + tabContent}</div>`
|
||||
}
|
||||
|
||||
hexo.extend.tag.register('tabs', postTabs, { ends: true })
|
||||
hexo.extend.tag.register('subtabs', postTabs, { ends: true })
|
||||
hexo.extend.tag.register('subsubtabs', postTabs, { ends: true })
|
||||
@@ -0,0 +1,22 @@
|
||||
"use strict"
|
||||
|
||||
function postTimeline(args, content) {
|
||||
if (args.length > 0) {
|
||||
return `<div class="timeline"><h1>${args}</h1>${content}</div>`;
|
||||
} else {
|
||||
return `<div class="timeline">${content}</div>`;
|
||||
}
|
||||
}
|
||||
|
||||
function postTimenode(args, content) {
|
||||
args = args.join(" ").split(",");
|
||||
var time = args[0];
|
||||
return `<div class="timenode"><div class="meta"><p>${time}</p></div><div class="body">${hexo.render
|
||||
.renderSync({ text: content, engine: "markdown" })
|
||||
.split("\n")
|
||||
.join("")}</div></div>`;
|
||||
}
|
||||
|
||||
hexo.extend.tag.register("timeline", postTimeline, { ends: true });
|
||||
|
||||
hexo.extend.tag.register("timenode", postTimenode, { ends: true });
|
||||
Reference in New Issue
Block a user