fix theme...

This commit is contained in:
2024-08-01 08:43:15 +08:00
parent 192ef21b12
commit 02130fba76
371 changed files with 28176 additions and 3285 deletions

View File

@@ -0,0 +1,18 @@
/**
* AnZhiYu
* 404 error page
*/
'use strict'
hexo.extend.generator.register('404', function (locals) {
if (!hexo.theme.config.error_404.enable) return
return {
path: '404.html',
layout: ['page'],
data: {
type: '404',
top_img: false
}
}
})

View File

@@ -0,0 +1,126 @@
/**
* AnZhiYu
* 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-anzhiyu",
file: "js/main.js",
version,
},
utils: {
name: "hexo-theme-anzhiyu",
file: "js/utils.js",
version,
},
translate: {
name: "hexo-theme-anzhiyu",
file: "js/tw_cn.js",
version,
},
local_search: {
name: "hexo-theme-anzhiyu",
file: "js/search/local-search.js",
version,
},
algolia_js: {
name: "hexo-theme-anzhiyu",
file: "js/search/algolia.js",
version,
},
random_friends_post_js: {
name: "hexo-theme-anzhiyu",
file: "js/anzhiyu/random_friends_post.js",
version,
},
right_click_menu_js: {
name: "hexo-theme-anzhiyu",
file: "js/anzhiyu/right_click_menu.js",
version,
},
comment_barrage_js: {
name: "hexo-theme-anzhiyu",
file: "js/anzhiyu/comment_barrage.js",
version,
},
ai_abstract_js: {
name: "hexo-theme-anzhiyu",
file: "js/anzhiyu/ai_abstract.js",
version,
},
people_js: {
name: "hexo-theme-anzhiyu",
file: "js/anzhiyu/people.js",
version,
},
};
const minFile = file => {
return file.replace(/(?<!\.min)\.(js|css)$/g, ext => ".min" + ext);
};
const createCDNLink = (data, type, cond = "") => {
Object.keys(data).map(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 ? `@${version}` : "";
const value = {
version,
name,
file,
cdnjs_file,
min_file,
min_cdnjs_file,
cdnjs_name,
};
const cdnSource = {
local: cond === "internal" ? cdnjs_file : `/pluginsSrc/${name}/${file}`,
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}`,
elemecdn: `https://npm.elemecdn.com/${name}${verType}/${file}`,
onmicrosoft: `https://npm.onmicrosoft.cn/${name}${verType}/${file}`,
cbd: `https://cdn.cbd.int/${name}${verType}/${file}`,
anheyu: `https://cdn.anheyu.com/npm/${name}${verType}/${min_file}`,
custom: (CDN.custom_format || "").replace(/\$\{(.+?)\}/g, (match, $1) => value[$1]),
};
data[key] = cdnSource[type];
});
if (cond === "internal") data["main_css"] = "css/index.css";
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.asset = Object.assign(
createCDNLink(internalSrc, CDN.internal_provider, "internal"),
createCDNLink(thirdPartySrc, CDN.third_party_provider),
deleteNullValue(CDN.option)
);
});

View File

@@ -0,0 +1,14 @@
/**
* Capitalize the first letter of comment name
*/
hexo.extend.filter.register('before_generate', () => {
const themeConfig = hexo.theme.config
let { use } = themeConfig.comments
if (!use) return
if (typeof use === 'string') {
use = use.split(',')
}
const newArray = use.map(item => item.toLowerCase().replace(/\b[a-z]/g, s => s.toUpperCase()))
themeConfig.comments.use = newArray
})

View File

@@ -0,0 +1,20 @@
hexo.extend.filter.register("before_generate", () => {
// Get first two digits of the Hexo version number
const hexoVer = hexo.version.replace(/(^.*\..*)\..*/, "$1");
const logger = hexo.log;
if (hexoVer < 5.3) {
logger.error("Please update Hexo to V5.3.0 or higher!");
logger.error("请把 Hexo 升级到 V5.3.0 或更高的版本!");
process.exit(-1);
}
if (hexo.locals.get) {
const data = hexo.locals.get("data");
if (data && data.anzhiyu) {
logger.error(" 'anzhiyu.yml' is deprecated. Please use '_config.anzhiyu.yml' ");
logger.error(" 'anzhiyu.yml' 已经弃用,请使用 '_config.anzhiyu.yml' ");
process.exit(-1);
}
}
});

View File

@@ -0,0 +1,680 @@
hexo.extend.filter.register(
"before_generate",
() => {
const defaultConfig = {
nav: {
travelling: true,
clock: false,
},
menu: null,
highlight_theme: "light",
highlight_copy: true,
highlight_lang: true,
highlight_shrink: false,
highlight_height_limit: false,
code_word_wrap: false,
social: null,
favicon: "/favicon.ico",
avatar: {
img: "https://npm.elemecdn.com/anzhiyu-blog-static@1.0.4/img/avatar.jpg",
effect: false,
},
disable_top_img: false,
index_img: null,
default_top_img: null,
archive_img: null,
tag_img: null,
tag_per_img: null,
category_img: null,
category_per_img: null,
cover: {
index_enable: true,
aside_enable: true,
archives_enable: true,
position: "left",
default_cover: null,
},
error_img: {
flink: "/img/friend_404.gif",
post_page: "/img/404.jpg",
},
error_404: {
enable: true,
subtitle: "请尝试站内搜索寻找文章",
background: "https://bu.dusays.com/2023/05/08/645907596997d.gif",
},
post_meta: {
page: {
date_type: "created",
date_format: "simple",
categories: true,
tags: true,
label: false,
},
post: {
date_type: "both",
date_format: "date",
categories: true,
tags: true,
label: true,
unread: false,
},
},
index_post_content: {
method: 3,
length: 500,
},
anchor: false,
photofigcaption: false,
copy: {
enable: true,
copyright: {
enable: false,
limit_count: 50,
},
},
toc: {
post: true,
page: false,
number: true,
expand: false,
style_simple: false,
},
mainTone: {
enable: false,
mode: "api",
api: "https://img2color-go.vercel.app/api?img=",
cover_change: true,
},
post_copyright: {
enable: true,
decode: false,
author_href: null,
location: "长沙",
license: "CC BY-NC-SA 4.0",
license_url: "https://creativecommons.org/licenses/by-nc-sa/4.0/",
avatarSinks: false,
copyright_author_img_back: null,
copyright_author_img_front: null,
copyright_author_link: "/",
},
reward: {
enable: false,
text: null,
QR_code: null,
},
post_edit: {
enable: true,
github: false,
yuque: false,
},
related_post: {
enable: true,
limit: 6,
date_type: "created",
},
post_pagination: 2,
noticeOutdate: {
enable: false,
style: "flat",
limit_day: 365,
position: "top",
message_prev: "It has been",
message_next: "days since the last update, the content of the article may be outdated.",
},
footer: {
owner: {
enable: true,
since: 2020,
},
custom_text: null,
runtime: {
enable: false,
launch_time: "04/01/2021 00:00:00",
work_img: "https://npm.elemecdn.com/anzhiyu-blog@2.0.4/img/badge/安知鱼-上班摸鱼中.svg",
work_description: "距离月入25k也就还差一个大佬带我~",
offduty_img: "https://npm.elemecdn.com/anzhiyu-blog@2.0.4/img/badge/安知鱼-下班啦.svg",
offduty_description: "下班了就该开开心心的玩耍,嘿嘿~",
},
bdageitem: {
enable: false,
list: [
{
link: "https://hexo.io/",
shields: "https://npm.elemecdn.com/anzhiyu-blog@2.1.5/img/badge/Frame-Hexo.svg",
message: "博客框架为Hexo_v5.4.0",
},
{
link: "https://blog.anheyu.com/",
shields: "https://npm.elemecdn.com/anzhiyu-theme-static@1.0.9/img/Theme-AnZhiYu-2E67D3.svg",
message: "本站使用AnZhiYu主题",
},
],
},
socialBar: {
enable: false,
centerImg: null,
left: null,
right: null,
},
list: {
enable: false,
randomFriends: 3,
project: null,
},
footerBar: {
enable: true,
authorLink: "/",
cc: {
enable: false,
link: "/copyright",
},
linkList: [
{
link: "https://github.com/anzhiyu-c/hexo-theme-anzhiyu",
text: "主题",
},
],
subTitle: {
enable: false,
effect: true,
startDelay: 300,
typeSpeed: 150,
backSpeed: 50,
loop: true,
source: 1,
sub: null,
},
},
},
h2Divider: false,
table_interlaced_discoloration: false,
article_double_row: true,
aside: {
enable: true,
hide: false,
button: true,
mobile: true,
position: "right",
display: {
archive: true,
tag: true,
category: true,
},
card_author: {
enable: true,
description: null,
name_link: "/",
},
card_announcement: {
enable: false,
content: "欢迎来看我的博客鸭~",
},
card_weixin: {
enable: true,
face: "https://bu.dusays.com/2023/01/13/63c02edf44033.png",
backFace: "https://bu.dusays.com/2023/05/13/645fa415e8694.png",
},
card_recent_post: {
enable: true,
limit: 5,
sort: "date",
sort_order: null,
},
card_categories: {
enable: true,
limit: 8,
expand: "none",
sort_order: null,
},
card_tags: {
enable: true,
limit: 40,
color: false,
orderby: "random",
order: 1,
sort_order: null,
highlightTags: null,
},
card_archives: {
enable: true,
type: "monthly",
format: "MMMM YYYY",
order: -1,
limit: 8,
sort_order: null,
},
card_webinfo: {
enable: true,
post_count: true,
last_push_date: true,
sort_order: null,
},
card_post_series: {
enable: false,
orderBy: "date",
order: -1,
},
},
busuanzi: {
site_uv: true,
site_pv: true,
page_pv: true,
},
runtimeshow: {
enable: false,
publish_date: null,
},
newest_comments: {
enable: false,
sort_order: null,
limit: 6,
storage: 10,
avatar: true,
},
translate: {
enable: false,
default: "繁",
defaultEncoding: 2,
translateDelay: 0,
msgToTraditionalChinese: "繁",
msgToSimplifiedChinese: "簡",
rightMenuMsgToTraditionalChinese: "转为繁体",
rightMenuMsgToSimplifiedChinese: "转为简体",
},
readmode: true,
centerConsole: {
enable: true,
card_tags: {
enable: true,
limit: 40,
color: false,
sort_order: null,
highlightTags: null,
},
card_archives: {
enable: true,
type: "monthly",
format: "MMMM YYYY",
order: -1,
limit: 8,
sort_order: null,
},
},
darkmode: {
enable: true,
button: true,
autoChangeMode: false,
start: null,
end: null,
},
rightside_item_order: {
enable: false,
hide: null,
show: null,
},
mathjax: {
enable: false,
per_page: false,
},
katex: {
enable: false,
per_page: false,
hide_scrollbar: true,
},
algolia_search: {
enable: false,
hits: {
per_page: 6,
},
},
local_search: {
enable: false,
preload: false,
top_n_per_article: 1,
unescape: false,
CDN: null,
},
docsearch: {
enable: false,
appId: null,
apiKey: null,
indexName: null,
option: null,
},
sharejs: {
enable: true,
sites: "facebook,twitter,wechat,weibo,qq",
},
addtoany: {
enable: false,
item: "facebook,twitter,wechat,sina_weibo,facebook_messenger,email,copy_link",
},
comments: {
use: null,
text: true,
lazyload: false,
count: false,
card_post_count: false,
},
valine: {
appId: null,
appKey: null,
avatar: "monsterid",
serverURLs: null,
bg: null,
visitor: false,
option: null,
},
waline: {
serverURL: null,
bg: null,
pageview: false,
option: null,
},
facebook_comments: {
app_id: null,
user_id: null,
pageSize: 10,
order_by: "social",
lang: "zh_TW",
},
twikoo: {
envId: null,
region: null,
visitor: false,
option: null,
},
artalk: {
server: null,
site: null,
visitor: false,
option: null,
},
chat_btn: false,
chat_hide_show: false,
chatra: {
enable: false,
id: null,
},
tidio: {
enable: false,
public_key: null,
},
daovoice: {
enable: false,
app_id: null,
},
crisp: {
enable: false,
website_id: null,
},
baidu_analytics: null,
google_analytics: null,
cloudflare_analytics: null,
microsoft_clarity: null,
google_adsense: {
enable: false,
auto_ads: true,
js: "https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js",
client: null,
enable_page_level_ads: true,
},
site_verification: null,
index_site_info_top: null,
index_top_img_height: null,
category_ui: null,
tag_ui: null,
text_align_justify: false,
background: null,
footer_bg: false,
mask: {
header: true,
footer: true,
},
rightside_bottom: null,
enter_transitions: true,
activate_power_mode: {
enable: false,
colorful: true,
shake: true,
mobile: false,
},
canvas_ribbon: {
enable: false,
size: 150,
alpha: 0.6,
zIndex: -1,
click_to_change: false,
mobile: false,
},
canvas_fluttering_ribbon: {
enable: false,
mobile: false,
},
canvas_nest: {
enable: false,
color: "0,0,255",
opacity: 0.7,
zIndex: -1,
count: 99,
mobile: false,
},
fireworks: {
enable: false,
zIndex: 9999,
mobile: false,
},
click_heart: {
enable: false,
mobile: false,
},
clickShowText: {
enable: false,
text: null,
fontSize: "15px",
random: false,
mobile: false,
},
display_mode: "light",
beautify: {
enable: false,
field: "post",
"title-prefix-icon": null,
"title-prefix-icon-color": null,
},
font: {
"global-font-size": null,
"code-font-size": null,
"font-family": null,
"code-font-family": null,
},
blog_title_font: {
font_link: null,
"font-family": null,
},
hr_icon: {
enable: true,
icon: null,
"icon-top": null,
},
subtitle: {
enable: false,
effect: true,
typed_option: null,
source: false,
sub: null,
},
preloader: {
enable: false,
source: 1,
pace_css_url: null,
},
wordcount: {
enable: false,
post_wordcount: true,
min2read: true,
total_wordcount: true,
},
medium_zoom: false,
fancybox: true,
series: {
enable: true,
orderBy: "title",
order: 1,
number: true,
},
abcjs: {
enable: false,
per_page: true,
},
mermaid: {
enable: false,
theme: {
light: "default",
dark: "dark",
},
},
note: {
style: "flat",
icons: true,
border_radius: 3,
light_bg_offset: 0,
},
pjax: {
enable: true,
exclude: null,
},
universe: {
enable: true,
},
bubble: {
enable: false,
},
LA: {
enable: false,
ck: null,
LingQueMonitorID: null,
},
diytitle: {
enable: true,
leaveTitle: "w(゚Д゚)w 不要走!再看看嘛!",
backTitle: "♪(^∇^*)欢迎肥来!",
},
comment_barrage_config: {
enable: false,
maxBarrage: 1,
barrageTime: 4000,
accessToken: "",
mailMd5: "",
},
nav_music: {
enable: true,
console_widescreen_music: false,
id: 8152976493,
server: "netease",
all_playlist: "https://y.qq.com/n/ryqq/playlist/8802438608",
},
visitorMail: {
enable: true,
mail: "",
},
ptool: {
enable: true,
share_mobile: true,
share_weibo: true,
share_copyurl: true,
categories: false,
mode: null,
},
greetingBox: {
enable: false,
default: "晚上好👋",
list: null,
},
post_head_ai_description: {
enable: true,
gptName: "AnZhiYu",
mode: "local",
switchBtn: false,
btnLink: "https://afdian.net/item/886a79d4db6711eda42a52540025c377",
randomNum: 3,
basicWordCount: 1000,
key: null,
Referer: null,
},
accesskey: {
enable: true,
},
linkPageTop: {
enable: false,
title: "与数百名博主无限进步",
addFriendPlaceholder:
"昵称(请勿包含博客等字样):\n网站地址要求博客地址请勿提交个人主页\n头像图片url请提供尽可能清晰的图片我会上传到我自己的图床\n描述\n站点截图可选\n",
},
pageThumbnailSuffix: null,
agreementPopup: {
enable: false,
url: "/privacy",
},
rightClickMenu: { enable: false },
peoplecanvas: {
enable: true,
img: "https://upload-bbs.miyoushe.com/upload/2023/09/03/125766904/ee23df8517f3c3e3efc4145658269c06_5714860933110284659.png",
},
dynamicEffect: {
postTopWave: true,
postTopRollZoomInfo: false,
pageCommentsRollZoom: false,
},
shortcutKey: {
enable: false,
delay: 100,
shiftDelay: 200,
},
console: {
enable: true,
},
aplayerInject: {
enable: false,
per_page: true,
},
snackbar: {
enable: false,
position: "bottom-left",
bg_light: "#49b1f5",
bg_dark: "#1f1f1f",
},
instantpage: false,
pangu: {
enable: false,
field: "site",
},
lazyload: {
enable: false,
field: "site",
placeholder: null,
blur: false,
},
Open_Graph_meta: {
enable: true,
option: null,
},
css_prefix: true,
inject: {
head: null,
bottom: null,
},
CDN: {
internal_provider: "local",
third_party_provider: "cbd",
version: true,
custom_format: null,
option: null,
},
};
hexo.theme.config = Object.assign(defaultConfig, hexo.theme.config);
},
1
);

View File

@@ -0,0 +1,24 @@
/**
* Stylus renderer
*/
"use strict";
hexo.extend.filter.register("stylus:renderer", style => {
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)
.define("$highlight_line_number", highlightLineNumber)
.define("$prismjs_enable", prismjsEnable)
.define("$prismjs_line_number", prismjsLineNumber);
// .import(`${this.source_dir.replace(/\\/g, '/')}_data/css/*`)
});

View File

@@ -0,0 +1,15 @@
hexo.on("ready", () => {
const { version } = require("../../package.json");
hexo.log.info(`
===================================================================
█████╗ ███╗ ██╗███████╗██╗ ██╗██╗██╗ ██╗██╗ ██╗
██╔══██╗████╗ ██║╚══███╔╝██║ ██║██║╚██╗ ██╔╝██║ ██║
███████║██╔██╗ ██║ ███╔╝ ███████║██║ ╚████╔╝ ██║ ██║
██╔══██║██║╚██╗██║ ███╔╝ ██╔══██║██║ ╚██╔╝ ██║ ██║
██║ ██║██║ ╚████║███████╗██║ ██║██║ ██║ ╚██████╔╝
╚═╝ ╚═╝╚═╝ ╚═══╝╚══════╝╚═╝ ╚═╝╚═╝ ╚═╝ ╚═════╝
${version}
===================================================================`);
});

View File

@@ -0,0 +1,33 @@
/**
* AnZhiYu
* lazyload
* replace src to data-lazy-src
*/
"use strict";
const urlFor = require("hexo-util").url_for.bind(hexo);
const lazyload = htmlContent => {
const error_img = hexo.theme.config.error_img.post_page
const bg = hexo.theme.config.lazyload.placeholder
? urlFor(hexo.theme.config.lazyload.placeholder)
: "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7";
return htmlContent.replace(
/(<img(?!.class[\t]*=[\t]*['"].*?nolazyload.*?['"]).*? src=)/gi,
`$1 "${bg}" onerror="this.onerror=null,this.src=&quot;${error_img}&quot;" data-lazy-src=`
);
}
hexo.extend.filter.register('after_render:html', data => {
const { enable, field } = hexo.theme.config.lazyload
if (!enable || field !== 'site') return
return lazyload(data)
})
hexo.extend.filter.register('after_post_render', data => {
const { enable, field } = hexo.theme.config.lazyload
if (!enable || field !== 'post') return
data.content = lazyload(data.content)
return data
})

View File

@@ -0,0 +1,65 @@
/**
* Butterfly
* ramdom cover
*/
'use strict'
hexo.extend.filter.register('before_post_render', data => {
const imgTestReg = /\.(png|jpe?g|gif|svg|webp)(\?.*)?$/i
let { cover: coverVal, top_img: topImg } = data
// Add path to top_img and cover if post_asset_folder is enabled
if (hexo.config.post_asset_folder) {
if (topImg && topImg.indexOf('/') === -1 && imgTestReg.test(topImg)) data.top_img = `${data.path}${topImg}`
if (coverVal && coverVal.indexOf('/') === -1 && imgTestReg.test(coverVal)) data.cover = `${data.path}${coverVal}`
}
const randomCoverFn = () => {
const { cover: { default_cover: defaultCover } } = hexo.theme.config
if (!defaultCover) return false
if (!Array.isArray(defaultCover)) return defaultCover
const num = Math.floor(Math.random() * defaultCover.length)
return defaultCover[num]
}
if (coverVal === false) return data
const uuid = () => {
var timestamp = new Date().getTime()
return 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
var r = (timestamp + Math.random() * 16) % 16 | 0
timestamp = Math.floor(timestamp / 16)
return (c == 'x' ? r : (r & 0x3 | 0x8)).toString(16)
})
}
const addUuidToUrl = (url) => {
try {
let urlParts = new URL(url)
let params = urlParts.searchParams
if (params.size > 0) {
params.append('_r_', uuid())
} else {
params.set('_r_', uuid())
}
return urlParts.toString()
} catch (error) {
return url
}
}
// If cover is not set, use random cover
if (!coverVal) {
const randomCover = randomCoverFn()
const cover = randomCover ? addUuidToUrl(randomCover) : randomCover
data.cover = cover
coverVal = cover // update coverVal
}
if (coverVal && (coverVal.indexOf('//') !== -1 || imgTestReg.test(coverVal))) {
data.cover_type = 'img'
}
return data
})

View File

@@ -0,0 +1,116 @@
/**
* AnZhiYu
* for aside archives
*/
"use strict";
hexo.extend.helper.register("aside_archives", function (options = {}) {
const { config } = this;
const archiveDir = config.archive_dir;
const { timezone } = config;
const lang = toMomentLocale(this.page.lang || this.page.language || config.language);
let { format } = options;
const type = options.type || "monthly";
const { transform } = options;
const showCount = Object.prototype.hasOwnProperty.call(options, "show_count") ? options.show_count : true;
const order = options.order || -1;
const compareFunc =
type === "monthly"
? (yearA, monthA, yearB, monthB) => yearA === yearB && monthA === monthB
: (yearA, monthA, yearB, monthB) => yearA === yearB;
const limit = options.limit;
let result = "";
if (!format) {
format = type === "monthly" ? "MMMM YYYY" : "YYYY";
}
const posts = this.site.posts.sort("date", order);
if (!posts.length) return result;
const data = [];
let length = 0;
posts.forEach(post => {
// Clone the date object to avoid pollution
let date = post.date.clone();
if (timezone) date = date.tz(timezone);
const year = date.year();
const month = date.month() + 1;
const lastData = data[length - 1];
if (!lastData || !compareFunc(lastData.year, lastData.month, year, month)) {
if (lang) date = date.locale(lang);
const name = date.format(format);
length = data.push({
name,
year,
month,
count: 1,
});
} else {
lastData.count++;
}
});
const link = item => {
let url = `${archiveDir}/${item.year}/`;
if (type === "monthly") {
if (item.month < 10) url += "0";
url += `${item.month}/`;
}
return this.url_for(url);
};
const len = data.length;
const Judge = limit === 0 ? len : Math.min(len, limit);
result += `<div class="item-headline"><i class="anzhiyufont anzhiyu-icon-archive"></i><span>${this._p(
"aside.card_archives"
)}</span>`;
if (len > Judge) {
result += `<a class="card-more-btn" href="${this.url_for(archiveDir)}/" title="${this._p("aside.more_button")}">
<i class="anzhiyufont anzhiyu-icon-angle-right"></i></a>`;
}
result += '</div><ul class="card-archive-list">';
for (let i = 0; i < Judge; i++) {
const item = data[i];
result += '<li class="card-archive-list-item">';
result += `<a class="card-archive-list-link" href="${link(item)}">`;
result += '<span class="card-archive-list-date">';
result += transform ? transform(item.name) : item.name;
result += "</span>";
if (showCount) {
result += `<div class="card-archive-list-count-group"><span class="card-archive-list-count">${item.count}</span><span>篇</span></div>`;
}
result += "</a>";
result += "</li>";
}
result += "</ul>";
return result;
});
const toMomentLocale = function (lang) {
if (lang === undefined) {
return undefined;
}
// moment.locale('') equals moment.locale('en')
// moment.locale(null) equals moment.locale('en')
if (!lang || lang === "en" || lang === "default") {
return "en";
}
return lang.toLowerCase().replace("_", "-");
};

View File

@@ -0,0 +1,99 @@
/**
* AnZhiYu
* for aside categories
*/
'use strict'
hexo.extend.helper.register('aside_categories', function (categories, options) {
if (!options && (!categories || !Object.prototype.hasOwnProperty.call(categories, 'length'))
) {
options = categories
categories = this.site.categories
}
if (!categories || !categories.length) return ''
options = options || {}
const { config } = this
const showCount = Object.prototype.hasOwnProperty.call(options, 'show_count')
? options.show_count
: true
const depth = options.depth ? parseInt(options.depth, 10) : 0
const orderby = options.orderby || 'name'
const order = options.order || 1
const categoryDir = this.url_for(config.category_dir)
const limit = options.limit === 0 ? categories.length : options.limit
const isExpand = options.expand !== 'none'
const expandClass = isExpand && options.expand === true ? 'expand' : ''
const buttonLabel = this._p('aside.more_button')
const prepareQuery = (parent) => {
const query = {}
if (parent) { query.parent = parent } else { query.parent = { $exists: false } }
return categories.find(query).sort(orderby, order).filter((cat) => cat.length)
}
let expandBtn = ''
const hierarchicalList = (t, level, parent, topparent = true) => {
let result = ''
const isTopParent = topparent
if (t > 0) {
prepareQuery(parent).forEach((cat, i) => {
if (t > 0) {
t = t - 1
let child
if (!depth || level + 1 < depth) {
const childList = hierarchicalList(t, level + 1, cat._id, false)
child = childList[0]
t = childList[1]
}
const parentClass = isExpand && isTopParent && child ? 'parent' : ''
result += `<li class="card-category-list-item ${parentClass}">`
result += `<a class="card-category-list-link" href="${this.url_for(cat.path)}">`
result += `<span class="card-category-list-name">${cat.name}</span>`
if (showCount) {
result += `<span class="card-category-list-count">${cat.length}</span>`
}
if (isExpand && isTopParent && child) {
expandBtn = ' expandBtn'
result += `<i class="anzhiyufont anzhiyu-icon-caret-left ${expandClass}"></i>`
}
result += '</a>'
if (child) {
result += `<ul class="card-category-list child">${child}</ul>`
}
result += '</li>'
}
})
}
return [result, t]
}
const list = hierarchicalList(limit, 0)
const moreButton = function () {
if (categories.length <= limit) return ''
const moreHtml = `<a class="card-more-btn" href="${categoryDir}/" title="${buttonLabel}">
<i class="anzhiyufont anzhiyu-icon-angle-right"></i></a>`
return moreHtml
}
return `<div class="item-headline">
<i class="anzhiyufont anzhiyu-icon-folder-open"></i>
<span>${this._p('aside.card_categories')}</span>
${moreButton()}
</div>
<ul class="card-category-list${expandBtn}" id="aside-cat-list">
${list[0]}
</ul>`
})

View File

@@ -0,0 +1,13 @@
hexo.extend.helper.register("catalog_list", function (type) {
let html = ``;
hexo.locals.get(type).map(function (item) {
html += `
<div class="catalog-list-item" id="/${item.path}">
<a href="/${item.path}">
${item.name}
</a>
</div>
`;
});
return html;
});

View File

@@ -0,0 +1,58 @@
hexo.extend.helper.register('getArchiveLength', function () {
const { archive_generator: archiveGenerator } = hexo.config
if (archiveGenerator && archiveGenerator.enable === false) return this.site.posts.length
const { yearly, monthly, daily } = archiveGenerator
const { year, month, day } = this.page
if (yearly === false || !year) return this.site.posts.length
const posts = this.site.posts.sort('date')
const compareFunc = (type, y1, m1, d1, y2, m2, d2) => {
switch (type) {
case 'year':
return y1 === y2
case 'month':
return y1 === y2 && m1 === m2
case 'day':
return y1 === y2 && m1 === m2 && d1 === d2
default:
return false
}
}
const generateDateObj = (type) => {
return posts.reduce((dateObj, post) => {
const date = post.date.clone()
const year = date.year()
const month = date.month() + 1
const day = date.date()
const lastData = dateObj[dateObj.length - 1]
if (!lastData || !compareFunc(type, lastData.year, lastData.month, lastData.day, year, month, day)) {
const name = type === 'year' ? year : type === 'month' ? `${year}-${month}` : `${year}-${month}-${day}`
dateObj.push({
name,
year,
month,
day,
count: 1
})
} else {
lastData.count++
}
return dateObj
}, [])
}
const data = this.fragment_cache('createArchiveObj', () => {
const dateObjs = []
if (yearly) dateObjs.push(...generateDateObj('year'))
if (monthly) dateObjs.push(...generateDateObj('month'))
if (daily) dateObjs.push(...generateDateObj('day'))
return dateObjs
})
const name = month ? (day ? `${year}-${month}-${day}` : `${year}-${month}`) : year
return data.find(item => item.name === name).count
})

View File

@@ -0,0 +1,4 @@
hexo.extend.helper.register("get_version", function () {
const { version } = require("../../package.json");
return version;
});

View File

@@ -0,0 +1,190 @@
/**
* Butterfly
* inject js to head
*/
"use strict";
hexo.extend.helper.register("inject_head_js", function () {
const { darkmode, aside } = this.theme;
const start = darkmode.start || 6;
const end = darkmode.end || 18;
const { theme_color } = hexo.theme.config;
const themeColorLight = (theme_color && theme_color.enable && theme_color.meta_theme_color_light) || "#ffffff";
const themeColorDark = (theme_color && theme_color.enable && theme_color.meta_theme_color_dark) || "#0d0d0d";
const createLocalStore = () => {
return `
win.saveToLocal = {
set: (key, value, ttl) => {
if (ttl === 0) return
const now = Date.now()
const expiry = now + ttl * 86400000
const item = {
value,
expiry
}
localStorage.setItem(key, JSON.stringify(item))
},
get: key => {
const itemStr = localStorage.getItem(key)
if (!itemStr) {
return undefined
}
const item = JSON.parse(itemStr)
const now = Date.now()
if (now > item.expiry) {
localStorage.removeItem(key)
return undefined
}
return item.value
}
}
`;
};
// https://stackoverflow.com/questions/16839698/jquery-getscript-alternative-in-native-javascript
const createGetScript = () => {
return `
win.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)
})
`;
};
const createGetCSS = () => {
return `
win.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)
})
`;
};
const createDarkmodeJs = () => {
if (!darkmode.enable) return "";
let darkmodeJs = `
win.activateDarkMode = () => {
document.documentElement.setAttribute('data-theme', 'dark')
if (document.querySelector('meta[name="theme-color"]') !== null) {
document.querySelector('meta[name="theme-color"]').setAttribute('content', '${themeColorDark}')
}
}
win.activateLightMode = () => {
document.documentElement.setAttribute('data-theme', 'light')
if (document.querySelector('meta[name="theme-color"]') !== null) {
document.querySelector('meta[name="theme-color"]').setAttribute('content', '${themeColorLight}')
}
}
const t = saveToLocal.get('theme')
`;
const autoChangeMode = darkmode.autoChangeMode;
if (autoChangeMode === 1) {
darkmodeJs += `
const isDarkMode = window.matchMedia('(prefers-color-scheme: dark)').matches
const isLightMode = window.matchMedia('(prefers-color-scheme: light)').matches
const isNotSpecified = window.matchMedia('(prefers-color-scheme: no-preference)').matches
const hasNoSupport = !isDarkMode && !isLightMode && !isNotSpecified
if (t === undefined) {
if (isLightMode) activateLightMode()
else if (isDarkMode) activateDarkMode()
else if (isNotSpecified || hasNoSupport) {
const now = new Date()
const hour = now.getHours()
const isNight = hour <= ${start} || hour >= ${end}
isNight ? activateDarkMode() : activateLightMode()
}
window.matchMedia('(prefers-color-scheme: dark)').addListener(e => {
if (saveToLocal.get('theme') === undefined) {
e.matches ? activateDarkMode() : activateLightMode()
}
})
} else if (t === 'light') activateLightMode()
else activateDarkMode()
`;
} else if (autoChangeMode === 2) {
darkmodeJs += `
const now = new Date()
const hour = now.getHours()
const isNight = hour <= ${start} || hour >= ${end}
if (t === undefined) isNight ? activateDarkMode() : activateLightMode()
else if (t === 'light') activateLightMode()
else activateDarkMode()
`;
} else {
darkmodeJs += `
if (t === 'dark') activateDarkMode()
else if (t === 'light') activateLightMode()
`;
}
return darkmodeJs;
};
const createAsideStatus = () => {
if (!aside.enable || !aside.button) return "";
return `
const asideStatus = saveToLocal.get('aside-status')
if (asideStatus !== undefined) {
if (asideStatus === 'hide') {
document.documentElement.classList.add('hide-aside')
} else {
document.documentElement.classList.remove('hide-aside')
}
}
`;
};
const createDetectApple = () => {
return `
const detectApple = () => {
if(/iPad|iPhone|iPod|Macintosh/.test(navigator.userAgent)){
document.documentElement.classList.add('apple')
}
}
detectApple()
`;
};
return `<script>(win=>{${
createLocalStore() +
createGetScript() +
createGetCSS() +
createDarkmodeJs() +
createAsideStatus() +
createDetectApple()
}})(window)</script>`;
});

View File

@@ -0,0 +1,149 @@
/**
* AnZhiYu
* @example
* page_description()
* cloudTags(source, minfontsize, maxfontsize, limit)
*/
"use strict";
const { stripHTML, escapeHTML, prettyUrls } = require("hexo-util");
const crypto = require("crypto");
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, ' ')
return description
}
})
hexo.extend.helper.register("get_page_fill_description", function () {
const { config, page } = this;
let description = page.content || page.description || page.title || config.description;
if (description) {
// 使用正则表达式匹配 h1-h6 标签中的文本内容
const regex = /<h[1-6][^>]*>(.*?)<\/h[1-6]>/g;
const headings = [];
let match;
while ((match = regex.exec(description))) {
headings.push(match[0]);
}
const contents = headings.map(heading => {
// 去掉 a 标签及其内容
const text = heading.replace(/<a[^>]*>.*?<\/a>/g, "");
// 去除特殊符号 &,:,; 等
return text.replace(/<\/?[^>]+>|&|:|;|quot;||,|“|”|"|'|#/g, "");
});
// 排除 div.post-ai-description 元素中的内容
const excludedDivRegex = /<div[^>]*class="?post-ai-description"?.*?>[\s\S]*?<\/div>/gi;
description = description.replace(excludedDivRegex, "");
description = escapeHTML(stripHTML(description).trim())
.replace(/\n/g, " ")
.replace(/[^\u4e00-\u9fa5]/gi, "");
return contents.join(", ") + description;
}
});
hexo.extend.helper.register("cloudTags", function (options = {}) {
const env = this;
let source = options.source;
const minfontsize = options.minfontsize;
const maxfontsize = options.maxfontsize;
const limit = options.limit;
const unit = options.unit || "px";
const colorful = options.color || false;
const highlightTags = options.highlightTags || [];
let result = "";
if (limit > 0) {
source = source.limit(limit);
}
const sizes = [];
source.sort("length").forEach(tag => {
const { length } = tag;
if (sizes.includes(length)) return;
sizes.push(length);
});
const length = sizes.length - 1;
source.sort("name").forEach(tag => {
const ratio = length ? sizes.indexOf(tag.length) / length : 0;
const size = minfontsize + (maxfontsize - minfontsize) * ratio;
let style = `font-size: ${parseFloat(size.toFixed(2))}${unit};`;
if (colorful) {
const color =
"rgb(" +
Math.floor(Math.random() * 201) +
", " +
Math.floor(Math.random() * 201) +
", " +
Math.floor(Math.random() * 201) +
")"; // 0,0,0 -> 200,200,200
style += ` color: ${color};`;
}
const matchingTag = highlightTags.find(highlightTag => highlightTag === tag.name);
if (matchingTag) {
style += ` font-weight: 500; color: var(--anzhiyu-lighttext)`;
}
result += `<a href="${env.url_for(tag.path)}" style="${style}">${tag.name}<sup>${tag.length}</sup></a>`;
});
return result;
});
hexo.extend.helper.register("urlNoIndex", function (url = null) {
return prettyUrls(url || this.url, { trailing_index: false, trailing_html: false });
});
hexo.extend.helper.register("md5", function (path) {
return crypto
.createHash("md5")
.update(decodeURI(this.url_for(path)))
.digest("hex");
});
hexo.extend.helper.register('injectHtml', function (data) {
if (!data) return ''
return data.join('')
})
hexo.extend.helper.register("findArchivesTitle", function (page, menu, date) {
if (page.year) {
const dateStr = page.month ? `${page.year}-${page.month}` : `${page.year}`;
const date_format = page.month ? hexo.theme.config.aside.card_archives.format : "YYYY";
return date(dateStr, date_format);
}
const defaultTitle = this._p("page.archives");
if (!menu) return defaultTitle;
const loop = m => {
for (const key in m) {
if (typeof m[key] === "object") {
loop(m[key]);
}
if (/\/archives\//.test(m[key])) {
return key;
}
}
};
return loop(menu) || defaultTitle;
});
hexo.extend.helper.register('isImgOrUrl', function (path) {
const imgTestReg = /\.(png|jpe?g|gif|svg|webp)(\?.*)?$/i
return path.indexOf('//') !== -1 || imgTestReg.test(path)
})

View File

@@ -0,0 +1,86 @@
hexo.extend.generator.register("random", function (locals) {
const config = hexo.config.random || {};
const themeConfig = hexo.theme.config;
const pjaxEn = themeConfig.pjax.enable;
const randomNumberFriend = themeConfig.footer.list.randomFriends || 0;
const posts = [];
const link = locals.data.link || [];
for (const post of locals.posts.data) {
if (post.random !== false) posts.push(post.path);
}
const link_list = [];
link.forEach(element => {
element.link_list.forEach(link_list_item => {
link_list.push(link_list_item);
});
});
let result = `var posts=${JSON.stringify(
posts
)};function toRandomPost(){
${pjaxEn ? "pjax.loadUrl('/'+posts[Math.floor(Math.random() * posts.length)]);" : "window.location.href='/'+posts[Math.floor(Math.random() * posts.length)];"}
};`;
if (themeConfig.footer.list.enable && randomNumberFriend > 0) {
result += `var friend_link_list=${JSON.stringify(link_list)};
var refreshNum = 1;
function friendChainRandomTransmission() {
const randomIndex = Math.floor(Math.random() * friend_link_list.length);
const { name, link } = friend_link_list.splice(randomIndex, 1)[0];
Snackbar.show({
text:
"点击前往按钮进入随机一个友链,不保证跳转网站的安全性和可用性。本次随机到的是本站友链:「" + name + "」",
duration: 8000,
pos: "top-center",
actionText: "前往",
onActionClick: function (element) {
element.style.opacity = 0;
window.open(link, "_blank");
},
});
}
function addFriendLinksInFooter() {
var footerRandomFriendsBtn = document.getElementById("footer-random-friends-btn");
if(!footerRandomFriendsBtn) return;
footerRandomFriendsBtn.style.opacity = "0.2";
footerRandomFriendsBtn.style.transitionDuration = "0.3s";
footerRandomFriendsBtn.style.transform = "rotate(" + 360 * refreshNum++ + "deg)";
const finalLinkList = [];
let count = 0;
while (friend_link_list.length && count < ${randomNumberFriend}) {
const randomIndex = Math.floor(Math.random() * friend_link_list.length);
const { name, link, avatar } = friend_link_list.splice(randomIndex, 1)[0];
finalLinkList.push({
name,
link,
avatar,
});
count++;
}
let html = finalLinkList
.map(({ name, link }) => {
const returnInfo = "<a class='footer-item' href='" + link + "' target='_blank' rel='noopener nofollow'>" + name + "</a>"
return returnInfo;
})
.join("");
html += "<a class='footer-item' href='/link/'>更多</a>";
document.getElementById("friend-links-in-footer").innerHTML = html;
setTimeout(()=>{
footerRandomFriendsBtn.style.opacity = "1";
}, 300)
};`;
}
return {
path: config.path || "anzhiyu/random.js",
data: result,
};
});

View File

@@ -0,0 +1,102 @@
/**
* AnZhiYu
* Related Posts
* According the tag
*/
"use strict";
hexo.extend.helper.register("related_posts", function (currentPost, allPosts) {
let relatedPosts = [];
currentPost.tags.forEach(function (tag) {
allPosts.forEach(function (post) {
if (isTagRelated(tag.name, post.tags)) {
const relatedPost = {
title: post.title,
path: post.path,
cover: post.cover,
randomcover: post.randomcover,
weight: 1,
updated: post.updated,
created: post.date,
};
const index = findItem(relatedPosts, "path", post.path);
if (index !== -1) {
relatedPosts[index].weight += 1;
} else {
if (currentPost.path !== post.path) {
relatedPosts.push(relatedPost);
}
}
}
});
});
if (relatedPosts.length === 0) {
return "";
}
let result = "";
const hexoConfig = hexo.config;
const config = hexo.theme.config;
const limitNum = config.related_post.limit || 6;
const dateType = config.related_post.date_type || "created";
const headlineLang = this._p("post.recommend");
relatedPosts = relatedPosts.sort(compare("weight"));
if (relatedPosts.length > 0) {
result += '<div class="relatedPosts">';
result += `<div class="headline"><i class="anzhiyufont anzhiyu-icon-thumbs-up fa-fw" style="font-size: 1.5rem; margin-right: 4px"></i><span>${headlineLang}</span></div>`;
result += '<div class="relatedPosts-list">';
for (let i = 0; i < Math.min(relatedPosts.length, limitNum); i++) {
const cover = relatedPosts[i].cover === false ? relatedPosts[i].randomcover : relatedPosts[i].cover;
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">`;
if (dateType === "created") {
result += `<div class="content is-center"><div class="date"><i class="anzhiyufont anzhiyu-icon-calendar-days fa-fw"></i> ${this.date(
relatedPosts[i].created,
hexoConfig.date_format
)}</div>`;
} else {
result += `<div class="content is-center"><div class="date"><i class="anzhiyufont anzhiyu-icon-history fa-fw"></i> ${this.date(
relatedPosts[i].updated,
hexoConfig.date_format
)}</div>`;
}
result += `<div class="title">${title}</div>`;
result += "</div></a></div>";
}
result += "</div></div>";
return result;
}
});
function isTagRelated(tagName, TBDtags) {
let result = false;
TBDtags.forEach(function (tag) {
if (tagName === tag.name) {
result = true;
}
});
return result;
}
function findItem(arrayToSearch, attr, val) {
for (let i = 0; i < arrayToSearch.length; i++) {
if (arrayToSearch[i][attr] === val) {
return i;
}
}
return -1;
}
function compare(attr) {
return function (a, b) {
const val1 = a[attr];
const val2 = b[attr];
return val2 - val1;
};
}

View File

@@ -0,0 +1,65 @@
hexo.extend.helper.register("sort_attr_post", function (type) {
// 获取所有文章
var posts_list = hexo.locals.get("posts").data;
var swiper_list = [];
var top_group_list = [];
// 判断是否开启swiper
const swiper_enable = hexo.theme.config.home_top.swiper.enable;
const targetLength = swiper_enable ? 4 : 6;
// 若文章的front_matter内设置了index和描述则将其放到swiper_list内
for (var item of posts_list) {
if (item.swiper_index) {
swiper_list.push(item);
}
if (item.top_group_index) {
top_group_list.push(item);
}
}
// 对swiper_list进行处理使其按照index大小进行排序
function sortNumber(a, b) {
return a.swiper_index - b.swiper_index;
}
// 对top_group_list进行处理使其按照index大小进行排序
function sortNumberGroupList(a, b) {
return a.top_group_index - b.top_group_index;
}
swiper_list = swiper_list.sort(sortNumber);
top_group_list = top_group_list.sort(sortNumberGroupList);
// 排序反转,使得数字越大越靠前
swiper_list = swiper_list.reverse();
top_group_list = top_group_list.reverse();
// 当top_group_list长度小于目标长度时使用最新的可用文章来补足到目标长度
if (top_group_list.length < targetLength) {
const newPosts = posts_list
.filter(item => !top_group_list.includes(item))
.slice(0, targetLength - top_group_list.length);
top_group_list = [...top_group_list, ...newPosts];
}
// 当swiper_list长度小于目标长度时使用最新的可用文章来补足到目标长度
if (swiper_list.length < targetLength) {
const newPosts = posts_list.filter(item => !swiper_list.includes(item)).slice(0, targetLength - swiper_list.length);
swiper_list = [...swiper_list, ...newPosts];
}
// 当top_group_list或swiper_list的长度大于目标长度时使用最新的可用文章来替换已经添加的文章
if (top_group_list.length > targetLength) {
const newPosts = posts_list
.filter(item => !top_group_list.slice(0, targetLength).includes(item))
.slice(0, top_group_list.length - targetLength);
top_group_list = [...top_group_list.slice(0, targetLength), ...newPosts];
}
if (swiper_list.length > targetLength) {
const newPosts = posts_list
.filter(item => !swiper_list.slice(0, targetLength).includes(item))
.slice(0, swiper_list.length - targetLength);
swiper_list = [...swiper_list.slice(0, targetLength), ...newPosts];
}
if (type === "swiper_list") {
return swiper_list;
} else if (type === "top_group_list") {
return top_group_list;
}
});

View File

@@ -0,0 +1,26 @@
hexo.extend.helper.register('tags_page_list', function (type) {
const tags = hexo.locals.get(type);
// Manually sort tags based on the length of tag names
const sortedTags = tags.reduce((acc, tag) => {
const index = acc.findIndex((t) => t.length < tag.length);
if (index === -1) {
acc.push(tag);
} else {
acc.splice(index, 0, tag);
}
return acc;
}, []);
let html = ``;
sortedTags.forEach(function (item) {
html += `
<a href="/${item.path}" id="/${item.path}">
<span class="tags-punctuation">#</span>${item.name}
<span class="tagsPageCount">${item.length}</span>
</a>
`;
});
return html;
});

View File

@@ -0,0 +1,18 @@
hexo.extend.helper.register("getAnimalIcon", function (year) {
var index = parseInt(year) % 12;
var icon = {
0: "anzhiyu-colorful-icon-monkey",
1: "anzhiyu-colorful-icon-rooster",
2: "anzhiyu-colorful-icon-dog",
3: "anzhiyu-colorful-icon-boar",
4: "anzhiyu-colorful-icon-rat",
5: "anzhiyu-colorful-icon-ox",
6: "anzhiyu-colorful-icon-tiger",
7: "anzhiyu-colorful-icon-rabbit",
8: "anzhiyu-colorful-icon-dragon",
9: "anzhiyu-colorful-icon-snake",
10: "anzhiyu-colorful-icon-horse",
11: "anzhiyu-colorful-icon-goat",
};
return icon[index];
});

View File

@@ -0,0 +1,56 @@
/**
* Introduction-card 介绍卡片
* {% intCard link img tip cardTitle logo title subTitle %}
*/
'use strict';
const urlFor = require('hexo-util').url_for.bind(hexo);
function intCard(args) {
const [link, img, tip, cardTitle, logo, title, subTitle] = args;
const defaultTip = '最爱';
const defaultCardTitle = '最爱';
const defaultLogo = '';
const defaultTitle = '';
const defaultSubTitle = '';
const renderIntroductionCardBottom = (args) => {
const [logo, title, subTitle] = args;
return `
<div class="introduction-card-bottom">
<div class="left">
<img src="${urlFor(logo)}" class="no-lightbox" alt="introduction"/>
<div class="info">
<div class="title">${title}</div>
<div class="subTitle">${subTitle}</div>
</div>
</div>
<div class="right">
<a href="${urlFor(link)}" tableindex="-1" class="no-text-decoration">前往</a>
</div>
</div>
`;
};
const introductionCardBottom = (logo || title || subTitle) ? renderIntroductionCardBottom([logo || defaultLogo, title || defaultTitle, subTitle || defaultSubTitle]) : '';
const radius = introductionCardBottom ? "" : "height: 100%;border-radius:15px;";
const height = introductionCardBottom ? "" : "height: 416px;";
return `
<div class="introduction-card" style="${height}">
<div class="introduction-card-top" style="${radius}">
<div class="int-card-info">
<div class="int-tip">${tip || defaultTip}</div>
<div class="int-cardTitle">${cardTitle || defaultCardTitle}</div>
</div>
<img src="${urlFor(img)}" class="no-lightbox" alt="introduction"/>
</div>
${introductionCardBottom}
</div>
`;
}
hexo.extend.tag.register('intCard', intCard, { ends: false });

View File

@@ -0,0 +1,47 @@
"use strict";
let playIcon = `<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20" fill="none" class="icon"><path fill-rule="evenodd" clip-rule="evenodd" d="M4.67735 4.2798C5.98983 4.1725 7.85812 4.0625 10 4.0625C12.1421 4.0625 14.0105 4.17252 15.323 4.27983C16.2216 4.3533 16.9184 5.04049 16.9989 5.9318C17.0962 7.00837 17.1875 8.43614 17.1875 10C17.1875 11.5639 17.0962 12.9916 16.9989 14.0682C16.9184 14.9595 16.2216 15.6467 15.323 15.7202C14.0105 15.8275 12.1421 15.9375 10 15.9375C7.85812 15.9375 5.98983 15.8275 4.67735 15.7202C3.77861 15.6467 3.08174 14.9593 3.00119 14.0678C2.90388 12.9908 2.8125 11.5627 2.8125 10C2.8125 8.43727 2.90388 7.00924 3.00119 5.93221C3.08174 5.04067 3.77861 4.35327 4.67735 4.2798ZM10 2.8125C7.81674 2.8125 5.9136 2.92456 4.5755 3.03395C3.07738 3.15643 1.8921 4.31616 1.75626 5.81973C1.65651 6.92379 1.5625 8.39058 1.5625 10C1.5625 11.6094 1.65651 13.0762 1.75626 14.1803C1.8921 15.6838 3.07738 16.8436 4.5755 16.966C5.9136 17.0754 7.81674 17.1875 10 17.1875C12.1835 17.1875 14.0868 17.0754 15.4249 16.966C16.9228 16.8436 18.108 15.6841 18.2438 14.1807C18.3435 13.077 18.4375 11.6105 18.4375 10C18.4375 8.38948 18.3435 6.92296 18.2438 5.81931C18.108 4.31588 16.9228 3.15645 15.4249 3.03398C14.0868 2.92458 12.1835 2.8125 10 2.8125ZM12.1876 10.722C12.7431 10.4013 12.7431 9.59941 12.1876 9.27866L9.06133 7.47373C8.50577 7.15298 7.81133 7.55392 7.81133 8.19542V11.8053C7.81133 12.4468 8.50577 12.8477 9.06133 12.527L12.1876 10.722Z" fill="#9499A0"/></svg>`;
let likeIcon = `<svg width="36" height="36" viewBox="0 0 36 36" xmlns="http://www.w3.org/2000/svg" class="icon"><path fill-rule="evenodd" clip-rule="evenodd" d="M9.77234 30.8573V11.7471H7.54573C5.50932 11.7471 3.85742 13.3931 3.85742 15.425V27.1794C3.85742 29.2112 5.50932 30.8573 7.54573 30.8573H9.77234ZM11.9902 30.8573V11.7054C14.9897 10.627 16.6942 7.8853 17.1055 3.33591C17.2666 1.55463 18.9633 0.814421 20.5803 1.59505C22.1847 2.36964 23.243 4.32583 23.243 6.93947C23.243 8.50265 23.0478 10.1054 22.6582 11.7471H29.7324C31.7739 11.7471 33.4289 13.402 33.4289 15.4435C33.4289 15.7416 33.3928 16.0386 33.3215 16.328L30.9883 25.7957C30.2558 28.7683 27.5894 30.8573 24.528 30.8573H11.9911H11.9902Z"></path></svg>`;
let coinIcon = `<svg width="28" height="28" viewBox="0 0 28 28" xmlns="http://www.w3.org/2000/svg" class="icon" style="fill:;"><path fill-rule="evenodd" clip-rule="evenodd" d="M14.045 25.5454C7.69377 25.5454 2.54504 20.3967 2.54504 14.0454C2.54504 7.69413 7.69377 2.54541 14.045 2.54541C20.3963 2.54541 25.545 7.69413 25.545 14.0454C25.545 17.0954 24.3334 20.0205 22.1768 22.1771C20.0201 24.3338 17.095 25.5454 14.045 25.5454ZM9.66202 6.81624H18.2761C18.825 6.81624 19.27 7.22183 19.27 7.72216C19.27 8.22248 18.825 8.62807 18.2761 8.62807H14.95V10.2903C17.989 10.4444 20.3766 12.9487 20.3855 15.9916V17.1995C20.3854 17.6997 19.9799 18.1052 19.4796 18.1052C18.9793 18.1052 18.5738 17.6997 18.5737 17.1995V15.9916C18.5667 13.9478 16.9882 12.2535 14.95 12.1022V20.5574C14.95 21.0577 14.5444 21.4633 14.0441 21.4633C13.5437 21.4633 13.1382 21.0577 13.1382 20.5574V12.1022C11.1 12.2535 9.52148 13.9478 9.51448 15.9916V17.1995C9.5144 17.6997 9.10883 18.1052 8.60856 18.1052C8.1083 18.1052 7.70273 17.6997 7.70265 17.1995V15.9916C7.71158 12.9487 10.0992 10.4444 13.1382 10.2903V8.62807H9.66202C9.11309 8.62807 8.66809 8.22248 8.66809 7.72216C8.66809 7.22183 9.11309 6.81624 9.66202 6.81624Z"></path></svg>`;
function bilibili(args) {
const id = args[0].replace(/.*video\/(.*)\/?.*/, "$1");
const time = args[1];
const hidden_desc = args[2];
const API = hexo.bilibiliApi ? hexo.bilibiliApi : "https://api.320.ink/api/b";
return `
<a href="https://www.bilibili.com/video/${id}/" class="bilibili_box" id="${id}"></a>
<script>
bilibili()
function bilibili() {
let dom = document.getElementById('${id}')
fetch('${API}?id=${id}').then(res=>res.json()).then(data=>{
dom.innerHTML = \`
<div class="bilibili_cover">
<img src="https://s1.hdslb.com/bfs/static/player/img/play.svg" class="play_icon no-lazyload">
<img src="\${data.pic + '&h=300'}" class="no-lazyload">
${time ? `<span>${time}</span>` : ""}
</div>
<div class="bilibili_info">
<div class="title">\${data.title}</div>
${hidden_desc == "true" ? "" : '<div class="desc">${data.desc}</div>'}
<div class="stat">
<span>${playIcon}\${data.view >= 10000 ? (data.view / 10000).toFixed(1) + "w" : data.view}</span>
<span>${likeIcon}\${data.like >= 10000 ? (data.like / 10000).toFixed(1) + "w" : data.view}</span>
<span>${coinIcon}\${data.coin >= 10000 ? (data.coin / 10000).toFixed(1) + "w" : data.coin}</span>
</div>
<div class="owner">
<span class="tip">视频</span>
<img src="\${data.face + '&h=100'}" class="no-lazyload">
<span>\${data.owner}</span>
</div>
</div>
\`
})
}
</script>
`;
}
hexo.extend.tag.register("bilibili", bilibili, { ends: false });

View File

@@ -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(" anzhiyufont") > -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);

View File

@@ -0,0 +1,28 @@
/**
* Button
* {% btn url text icon option %}
* option: color outline center block larger
* color : default/blue/pink/red/purple/orange/green
*/
"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 `<a class="btn-anzhiyu ${option}" href="${urlFor(url)}"
title="${text}">${icon.length ? `<i class="${icon}"></i>` : ""}${text.length ? `<span>${text}</span>` : ""}</a>`;
}
hexo.extend.tag.register("btn", btn, { ends: false });

View File

@@ -0,0 +1,53 @@
'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>`
}
}
// {% checkbox text %}
// {% checkbox checked, text %}
// {% checkbox color checked, text %}
hexo.extend.tag.register('checkbox', postCheckbox);
hexo.extend.tag.register('radio', postRadio);

View File

@@ -0,0 +1,34 @@
/**
* Hexo tag for generating a DogePlayer audio player.
* Usage: {% dogeplayer userId vcode %}
*/
hexo.extend.tag.register("dogeplayer", function (args) {
var userId = args[0];
var vcode = args[1];
var divId = "player_" + vcode;
var html =
'<div id="' +
divId +
'"></div>\n' +
'<script type="text/javascript" data-pjax src="https://player.dogecloud.com/js/loader"></script>\n' +
'<script type="text/javascript" data-pjax defer>\n' +
" setTimeout(() => {\n" +
" var dogePlayer = new DogePlayer({\n" +
' container: document.getElementById("' +
divId +
'"),\n' +
" userId: " +
userId +
",\n" +
' vcode: "' +
vcode +
'",\n' +
" autoPlay: false\n" +
" });\n" +
" }, 300);\n" +
"</script>\n";
return html;
});

View File

@@ -0,0 +1,70 @@
/**
* flink
*/
"use strict";
const urlFor = require("hexo-util").url_for.bind(hexo);
const flinkFn = (args, content) => {
content = hexo.render.renderSync({ text: content, engine: "yaml" });
let result = "";
content.forEach(i => {
const className = i.class_name ? `<div class="flink-name">${i.class_name}</div>` : "";
const classDesc = i.class_desc ? `<div class="flink-desc">${i.class_desc}</div>` : "";
let listResult = "";
let listContainerClass = "";
if (i.flink_style === "anzhiyu") {
listContainerClass = "anzhiyu-flink-list";
i.link_list.forEach(j => {
listResult += `
<div class="flink-list-item">
<a href="${j.link}" title="${j.name}" class="cf-friends-link" target="_blank">
<div class="flink-item-icon">
<img class="no-lightbox cf-friends-avatar" src="${
j.avatar
}" onerror='this.onerror=null;this.src="${urlFor(hexo.theme.config.error_img.flink)}"' alt="${
j.name
}" />
</div>
<div class="flink-item-info">
<div class="flink-item-name">${j.name}</div>
<div class="flink-item-desc" title="${j.descr}">${j.descr}</div>
</div>
</a>
</div>`;
});
} else {
listContainerClass = "flexcard-flink-list";
i.link_list.forEach(j => {
listResult += `
<a href="${j.link}" title="${j.name}" target="_blank" class="flink-list-card cf-friends-link">
<div class="wrapper cover">
<img class="no-lightbox cover fadeIn" src="${
j.siteshot
}" onerror='this.onerror=null;this.src="${urlFor(hexo.theme.config.error_img.flink)}"' alt="${
j.name
}" />
</div>
<div class="info">
<img class="no-lightbox cf-friends-avatar flink-avatar" src="${
j.avatar
}" onerror='this.onerror=null;this.src="${urlFor(hexo.theme.config.error_img.flink)}"' alt="${
j.name
}"/>
<span class="flink-sitename cf-friends-name">${j.name}</span>
</div>
</a>`;
});
}
result += `${className}${classDesc} <div class="flink-list"><div class="${listContainerClass}">${listResult}</div></div>`;
});
return `<div class="flink">${result}</div>`;
};
hexo.extend.tag.register("flink", flinkFn, { ends: true });

View File

@@ -0,0 +1,29 @@
'use strict';
function postFolding(args, content) {
args = args.join(' ').split(',');
let style = ''
let title = ''
if (args.length > 1) {
style = args[0].trim()
title = args[1].trim()
} else if (args.length > 0) {
title = args[0].trim()
}
if (style != undefined) {
return `<details class="folding-tag" ${style}><summary> ${title} </summary>
<div class='content'>
${hexo.render.renderSync({text: content, engine: 'markdown'}).split('\n').join('')}
</div>
</details>`;
} else {
return `<details class="folding-tag"><summary> ${title} </summary>
<div class='content'>
${hexo.render.renderSync({text: content, engine: 'markdown'}).split('\n').join('')}
</div>
</details>`;
}
}
hexo.extend.tag.register('folding', postFolding, {ends: true});

View File

@@ -0,0 +1,81 @@
/**
* AnZhiYu
* galleryGroup and gallery
* {% galleryGroup [name] [descr] [url] [img] %}
* {% gallery [lazyload],[rowHeight],[limit] %}
* {% gallery url,[url],[lazyload],[rowHeight],[limit] %}
*/
"use strict";
const urlFor = require("hexo-util").url_for.bind(hexo);
function gallery(args, content) {
const { data, languages } = hexo.theme.i18n;
args = args.join(" ").split(",");
let rowHeight, limit, lazyload, type, dataStr, lazyloadBtn;
if (args[0] === "url") {
[type, dataStr, lazyload, rowHeight = 220, limit = 10, lazyloadBtn = false] = args; // url,[link],[lazyload],[rowHeight],[limit]
rowHeight = rowHeight == "" ? 220 : rowHeight;
limit = limit == "" ? 10 : limit;
lazyloadBtn = lazyloadBtn == false ? false : lazyloadBtn;
} else {
[lazyload, rowHeight = 220, limit = 10, lazyloadBtn = false] = args; // [lazyload],[rowHeight],[limit]
rowHeight = rowHeight == "" ? 220 : rowHeight;
limit = limit == "" ? 10 : limit;
lazyloadBtn = lazyloadBtn == false ? false : lazyloadBtn;
const regex = /!\[(.*?)\]\(([^\s]*)\s*(?:["'](.*?)["']?)?\s*\)/g;
let m;
const arr = [];
while ((m = regex.exec(content)) !== null) {
if (m.index === regex.lastIndex) {
regex.lastIndex++;
}
arr.push({
url: m[2],
alt: m[1],
title: m[3],
});
}
dataStr = JSON.stringify(arr);
}
type = type ? " url" : " data";
const lazyloadClass = lazyload === "true" ? "lazyload btn_album_detail_lazyload" : "";
const pageImgLazyloadClass = lazyloadBtn == true ? "" : "page_img_lazyload ";
let html = `<div class="gallery">
<div class="fj-gallery ${
pageImgLazyloadClass + lazyloadClass + type
}" data-rowHeight="${rowHeight}" data-limit="${limit}">
<span class="gallery-data">${dataStr}</span>
</div><button class="gallery-load-more" style="${!lazyloadBtn ? "opacity:0" : ""}">
<span>${data[languages[0]].load_more}</span>
<i class="anzhiyufont anzhiyu-icon-arrow-down"></i>
</button>`;
return (html += `</div>`);
}
function galleryGroup(args) {
const name = args[0];
const descr = args[1];
const url = urlFor(args[2]);
const img = urlFor(args[3]);
return `
<figure class="gallery-group">
<img class="gallery-group-img no-lightbox" src='${img}' alt="Group Image Gallery">
<figcaption>
<div class="gallery-group-name">${name}</div>
<p>${descr}</p>
<a href='${url}'></a>
</figcaption>
</figure>
`;
}
hexo.extend.tag.register("gallery", gallery, { ends: true });
hexo.extend.tag.register("galleryGroup", galleryGroup);

View File

@@ -0,0 +1,70 @@
/**
* AnZhiYu
* @example
* hideInline
* {% hideInline content,display,bg,color %}
* content不能包含當引號可用 &apos;
* hideBlock
* {% hideBlock display,bg,color %}
* content
* {% endhideBlock %}
* hideToggle
* {% hideToggle display,bg,color %}
* content
* {% endhideToggle %}
*/
'use strict'
function hideInline (args) {
args = args.join(' ').split(',')
const content = args[0]
const display = args[1] || 'Click'
const bg = args[2] || false
const color = args[3] || false
let group = 'style="'
if (bg) group += `background-color: ${bg};`
if (color) group += `color: ${color}`
group += '"'
return `<span class="hide-inline"><button type="button" class="hide-button" ${group}>${display}
</button><span class="hide-content">${content}</span></span>`
}
function hideBlock (args, content) {
args = args.join(' ').split(',')
const display = args[0] || 'Click'
const bg = args[1] || false
const color = args[2] || false
let group = 'style="'
if (bg) group += `background-color: ${bg};`
if (color) group += `color: ${color}`
group += '"'
return `<div class="hide-block"><button type="button" class="hide-button" ${group}>${display}
</button><div class="hide-content">${hexo.render.renderSync({ text: content, engine: 'markdown' })}</div></div>`
}
function hideToggle (args, content) {
args = args.join(' ').split(',')
const display = args[0]
const bg = args[1] || false
const color = args[2] || false
let group = 'style="'
let border = ''
if (bg) {
border = `style="border: 1px solid ${bg}"`
group += `background-color: ${bg};`
}
if (color) group += `color: ${color}`
group += '"'
return `<details class="toggle" ${border}><summary class="toggle-button" ${group}>${display}</summary><div class="toggle-content">${hexo.render.renderSync({ text: content, engine: 'markdown' })}</div></details>`
}
hexo.extend.tag.register('hideInline', hideInline)
hexo.extend.tag.register('hideBlock', hideBlock, { ends: true })
hexo.extend.tag.register('hideToggle', hideToggle, { ends: true })

View File

@@ -0,0 +1,9 @@
'use strict';
function iconFont(args) {
args = args.join(' ').split(',');
let p0 = args[0];
let p1 = args[1] ? args[1] : 1;
return `<svg class="icon" style="width:${p1}em; height:${p1}em" aria-hidden="true"><use xlink:href="#${p0}"></use></svg>`;
}
hexo.extend.tag.register('icon', iconFont);

View File

@@ -0,0 +1,91 @@
/**
* image.js v4 | https://volantis.js.org
*/
'use strict';
// {% image url %}
// {% image url, alt=haha %}
// {% image url, width=50% %}
// {% image url, height=32px %}
// {% image url, bg=#eee %}
// {% image url, alt=haha, width=400px %}
// {% image url, alt=haha, width=400px, bg=#eee %}
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 = '';
// wrap
ret += '<div class="img-wrap">';
// bg
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;
});
// {% inlineimage url %}
// {% inlineimage url, height=22px %}
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;
});

View File

@@ -0,0 +1,21 @@
'use strict';
hexo.extend.tag.register('u', function(args) {
return `<u>${args.join(' ')}</u>`;
});
hexo.extend.tag.register('emp', function(args) {
return `<emp>${args.join(' ')}</emp>`;
});
hexo.extend.tag.register('wavy', function(args) {
return `<wavy>${args.join(' ')}</wavy>`;
});
hexo.extend.tag.register('del', function(args) {
return `<del>${args.join(' ')}</del>`;
});
hexo.extend.tag.register('kbd', function(args) {
return `<kbd>${args.join(' ')}</kbd>`;
});
hexo.extend.tag.register('psw', function(args) {
return `<psw>${args.join(' ')}</psw>`;
});

View File

@@ -0,0 +1,17 @@
/**
* inlineImg 圖片
* {% inlineImg src height %}
*/
'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('inlineImg', inlineImg, { ends: false })

View File

@@ -0,0 +1,16 @@
/**
* AnZhiYu
* label
* {% label text color %}
*/
'use strict'
function addLabel (args, content) {
const text = args[0]
const className = args[1] || 'default'
return `<mark class="hl-label ${className}">${text}</mark> `
}
hexo.extend.tag.register('label', addLabel, { ends: false })

View File

@@ -0,0 +1,34 @@
const urlFor = require("hexo-util").url_for.bind(hexo);
function link(args) {
args = args.join(" ").split(",");
let title = args[0];
let sitename = args[1];
let link = args[2];
let imgUrl = args[3] || "";
let InsideStation = false;
link = link.trim();
imgUrl = imgUrl.trim();
if (imgUrl == "true") {
InsideStation = true;
}
return `<div calss='anzhiyu-tag-link'><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="${
imgUrl ? `background-image: url(${InsideStation ? "/img/512.png" : imgUrl})` : ""
}">
<i class="anzhiyufont anzhiyu-icon-link" style="${imgUrl ? "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="anzhiyufont anzhiyu-icon-angle-right"></i>
</div>
</a></div>`;
}
hexo.extend.tag.register("link", link, { ends: false });

View File

@@ -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});

View File

@@ -0,0 +1,17 @@
/**
* AnZhiYu
* mermaid
* https://github.com/mermaid-js/mermaid
*/
'use strict'
const { escapeHTML } = require('hexo-util')
function mermaid (args, content) {
return `<div class="mermaid-wrap"><pre class="mermaid-src" hidden>
${escapeHTML(content)}
</pre></div>`
}
hexo.extend.tag.register('mermaid', mermaid, { ends: true })

View File

@@ -0,0 +1,27 @@
/**
* note.js
* transplant from hexo-theme-next
* Modify by Jerry
*/
'use strict'
function postNote (args, content) {
const styleConfig = hexo.theme.config.note.style
const lastArgs = args[args.length - 1]
if (!(lastArgs === 'flat' || lastArgs === 'modern' || lastArgs === 'simple' || lastArgs === 'disabled')) {
args.push(styleConfig)
}
let icon = ''
const iconArray = args[args.length - 2]
if (iconArray && iconArray.startsWith('fa')) {
icon = `<i class="note-icon ${iconArray}"></i>`
args[args.length - 2] = 'icon-padding'
}
return `<div class="note ${args.join(' ')}">${icon + hexo.render.renderSync({ text: content, engine: 'markdown' })}</div>`
}
hexo.extend.tag.register('note', postNote, { ends: true })
hexo.extend.tag.register('subnote', postNote, { ends: true })

View File

@@ -0,0 +1,54 @@
'use strict';
function postSiteCardGroup(args, content) {
if (args.length > 0) {
return `<div class="site-card-group"><p class='p h2'>${args}</p>${content}</div>`;
} else {
return `<div class="site-card-group">${content}</div>`;
}
}
function postSiteCard(args) {
args = args.join(' ').split(', ')
// 所有支持的参数
let title = args[0].trim();
let url = '';
let screenshot = '';
let avatar = '';
let description = '';
// 解析
if (args.length > 1) {
for (let i = 1; i < args.length; i++) {
let tmp = args[i].trim();
if (tmp.includes('url=')) {
url = tmp.substring(4, tmp.length);
} else if (tmp.includes('screenshot=')) {
screenshot = tmp.substring(11, tmp.length);
} else if (tmp.includes('avatar=')) {
avatar = tmp.substring(7, tmp.length);
} else if (tmp.includes('description=')) {
description = tmp.substring(12, tmp.length);
}
}
}
// 布局
let result = '';
result += `<a class="site-card" href="${url}" data-title=${description}>`;
result += '<div class="wrapper cover"><img class="cover fadeIn" src="' + screenshot + '"/></div>';
result += '<div class="info">';
if (avatar.length > 0) {
result += `<img class="flink-avatar" src="${avatar}"/>`;
} else {
}
result += '<span class="site-title">' + title + '</span>';
result += '</div></a>';
return result;
}
// {% site link, img, title %}
// {% site link, img, title, description %}
hexo.extend.tag.register('site', postSiteCard);
hexo.extend.tag.register('sitegroup', postSiteCardGroup, {ends: true});

View File

@@ -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);

View File

@@ -0,0 +1,64 @@
/**
* Tabs
* transplant from hexo-theme-next
* modify by Jerry
*/
'use strict'
const 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 = ''
let noDefault = true
!tabName && hexo.log.warn('Tabs block must have unique name!')
while ((match = tabBlock.exec(content)) !== null) {
matches.push(match[1], 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 class="${icon}"${isOnlyicon}></i>`)
let isActive = ''
if ((tabActive > 0 && tabActive === tabId) || (tabActive === 0 && tabId === 1)) {
isActive = ' active'
noDefault = false
}
tabNav += `<button type="button" class="tab ${isActive}" data-href="${tabHref}">${tabIcon + tabCaption.trim()}</button>`
tabContent += `<div class="tab-item-content${isActive}" id="${tabHref}">${postContent}</div>`
}
const toTop = '<div class="tab-to-top"><button type="button" aria-label="scroll to top"><i class="anzhiyufont anzhiyu-icon-arrow-up"></i></button></div>'
tabNav = `<ul class="nav-tabs${noDefault ? ' no-default' : ''}">${tabNav}</ul>`
tabContent = `<div class="tab-contents">${tabContent}</div>`
return `<div class="tabs" id="${tabName.toLowerCase().split(' ').join('-')}">${tabNav + tabContent + toTop}</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 })

View File

@@ -0,0 +1,41 @@
/**
* timeline
* by Jerry
*/
'use strict'
function timeLineFn (args, content) {
const tlBlock = /<!--\s*timeline (.*?)\s*-->\n([\w\W\s\S]*?)<!--\s*endtimeline\s*-->/g
let result = ''
let color = ''
if (args.length) {
args = args.join(' ').split(',')
color = args[1]
const mdContent = hexo.render.renderSync({ text: args[0], engine: 'markdown' })
result += `<div class='timeline-item headline'><div class='timeline-item-title'><div class='item-circle'>${mdContent}</div></div></div>`
}
const matches = []
let match
while ((match = tlBlock.exec(content)) !== null) {
matches.push(match[1])
matches.push(match[2])
}
for (let i = 0; i < matches.length; i += 2) {
const tlChildTitle = hexo.render.renderSync({ text: matches[i], engine: 'markdown' })
const tlChildContent = hexo.render.renderSync({ text: matches[i + 1], engine: 'markdown' })
const tlTitleHtml = `<div class='timeline-item-title'><div class='item-circle'>${tlChildTitle}</div></div>`
const tlContentHtml = `<div class='timeline-item-content'>${tlChildContent}</div>`
result += `<div class='timeline-item'>${tlTitleHtml + tlContentHtml}</div>`
}
return `<div class="timeline ${color}">${result}</div>`
}
hexo.extend.tag.register('timeline', timeLineFn, { ends: true })

View File

@@ -0,0 +1,16 @@
// 'use strict'
//
// function poem (args, content) {
// return `<div class="tip"><b>${content}<b></div>`
// }
//
// hexo.extend.tag.register('tip', tip, { ends: true })
'use strict'
function tip (args, content) {
const tipclass = args ? args.join(' ') : 'info'
return `<div class="tip ${args.join(' ')}">${hexo.render.renderSync({ text: content, engine: 'markdown' })}</div>`
}
hexo.extend.tag.register('tip',tip, { ends: true })