编写文章时,通常需要插入各种标签,以实现更丰富的内容展示

note 标签

写法如下;

1
2
3
{% box [title] [color:color] [child:codeblock/tabs] %}
...
{% endbox %}

其中title为标签标题,color为标签颜色,child为标签内容。

知识点补充

这里是盒子的正文内容,可以写 Markdown 语法.比如;

1
hexo v
  • 支持列表
  • 支持加粗

插入图片

使用image插件控制图片大小和图片描述

写法如下:

1
{% image /path/photo.jpg width:400px 图片说明 %}

其中/img/bg.png为图片路径,width:500px为图片宽度,图片说明为图片描述。

图片说明
图片说明

fancybox插件

图片缩放功能,插件默认启用,在任意 image 标签中增加 fancybox:true 参数,即可为特定图片开启缩放功能
所有的 image 标签都开启此功能,可在主题配置文件中修改以下参数:

_config.stellar.yml
1
2
3
4
tag_plugins:
# {% image %}
image:
fancybox: true

彩色可折叠代码块

备注标签可以实现更多种颜色,还可以通过设置child:codeblock来实现可折叠的代码块,示例如下;

1
2
3
{% folding child:codeblock open:true color:yellow 默认打开的代码折叠框 %}
代码块
{% endfolding %}

其中open:true为默认打开代码折叠框,color:yellow为黄色。
可以嵌套使用,当使用child:codeblock参数只需要在包含代码块的折叠框中添加,外层添加会影响会影响折叠感。

危险,请不要打开这个

通过设置颜色,以实现更醒目的作用,但不要滥用色彩哦~

警告,真的很危险

通过设置颜色,以实现更醒目的作用,但不要滥用色彩哦~

最后一次警告,千万不要打开这个

1
hexo v #不是新版的赶紧更新吧

外链卡片标签的语法格式为:

1
{% link href [title] [icon:src] [desc:true/false] %}
1
2
3
4
href: 链接地址
title: 可选,手动设置标题(为空时会自动抓取页面标题)
icon: 可选,手动设置图标(为空时会自动抓取页面图标)
desc: 可选,是否显示摘要描述,为true时将会显示页面描述

示例:

1
2
3
4
不带摘要的样式:
{% link https://xaoxuu.com/blog/20221029/ %} #如评论插件配置
带摘要的样式:
{% link https://xaoxuu.com/blog/20221029/ desc:true %} #如site-info-api

自部署的 api 抓取网站信息

1、fork 本仓库
2、打开 vercel.com,部署该项目
3、进入 Environment Variables 页面,设置白名单 ,注意必须加上括号 [ ]

key Value
HOSTS [‘’, ‘localhost’, ‘yourdomain.com’]
环境变量键名 允许访问的域名列表

在给出的domain后添加/api/v1?url= url 调用,浏览器输入

1
https://yourdomain.vercel.app/api/v1?url=https://youtube.com

有返回值则api调用成功

1
2
3
4
5
6
{
"title": "YouTube",
"desc": "Enjoy the videos and music you love, upload original content, and share it all with friends, family, and the world on YouTube.",
"icon": "https://www.youtube.com/s/desktop/ab292bc1/img/favicon_32x32.png",
"url": "https://www.youtube.com/"
}

配置到 Stellar 主题中

_config.stellar.yml
1
2
3
4
5
siteinfo:
js: /js/services/siteinfo.js
# 设置 api 可以自动提取网页标题、图标,服务部署方法:https://github.com/xaoxuu/site-info-api/
# 接口测试通过后,把按钮的 href 部分替换成 {href} 之后填写到下方,例如:https://api.xaox.cc/site_info/v1?url={href}
api: https://yourdomain.vercel.app/api/v1?url={href}

利用link做摘要卡片

设置 link 可以让整个卡片响应点击事件,实现点击跳转到对应文章/页面:

1
2
{% banner 博客进阶:自动化部署 本文讲了如何利用脚本和 GitHub Actions 简化博客搭建和部署流程,提高效率。 bg:https://res.xaox.cc/gh/cdn-x/xaoxuu@main/posts/20250706160404696.webp link:/blog/20221126/ %}
{% endbanner %}

其中bg为背景图片,link为外部/内部跳转链接。

小技巧,可以通过修改banner.js文件,增加height高度,width宽度, margin对齐位置,来实现自定义banner样式。

修改源码后,升级主题会导致改动丢失,建议备份

blog\themes\stellar\scripts\tags\lib\banner.js
1
2
3
4
5
6
7
8
9
10
11
12
13
module.exports = ctx => function(args, content) {
args = ctx.args.map(args, ['bg', 'avatar', 'link', 'height', 'width', 'margin'], ['title', 'subtitle'])
var el = ''
var styles = []
if (args.height) styles.push(`height:${args.height}`)
if (args.width) styles.push(`width:${args.width}`)
if (args.margin) styles.push(`margin:${args.margin}`)

if (styles.length > 0) {
el += `<div class="tag-plugin banner" style="${styles.join(';')}">`
} else {
el += `<div class="tag-plugin banner">`
}

效果1 原高度

效果2 130px高度

也可以在不修改源代码的情况下,通过新建blog\scripts\banner.js粘贴以下内容,实现相同效果

blog\scripts\banner.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
'use strict';

console.log('Load custom banner tag plugin...');

// Helper function to parse arguments
function parseArgs(args, keys, others) {
if (Array.isArray(args) == false) {
return args;
}
var map = {others: Array()};
args.forEach((arg, i) => {
let kv = arg.trim();
if (kv.includes('://') && kv.split(':').length == 2) {
// Pure URL
map.others.push(kv);
} else {
kv = kv.split(':');
if (kv.length > 1) {
if (keys.includes(kv[0]) == true) {
map[kv.shift()] = kv.join(':');
} else {
map.others.push(kv.join(':'));
}
} else if (kv.length == 1) {
map.others.push(kv[0]);
}
}
});
// Parse unnamed arguments
if (others && others.length > 0 && map.others.length > 0) {
if (Array.isArray(others) == false) {
others = [others];
}
others.forEach((arg, i) => {
map[arg] = map.others.shift();
});
// Merge the last part into the last argument
if (map.others.length > 0) {
map[others[others.length-1]] += ' ' + map.others.join(' ');
map.others = [];
}
}
return map;
}

// Custom banner implementation
const customBanner = function(args, content) {
const ctx = hexo;

// Use local parseArgs
args = parseArgs(args, ['bg', 'avatar', 'link', 'height', 'width', 'margin'], ['title', 'subtitle'])

var el = ''
var styles = []
if (args.height) styles.push(`height:${args.height}`)
if (args.width) styles.push(`width:${args.width}`)
if (args.margin) styles.push(`margin:${args.margin}`)

if (styles.length > 0) {
el += `<div class="tag-plugin banner" style="${styles.join(';')}">`
} else {
el += `<div class="tag-plugin banner">`
}

// bg
const defaultBanner = ctx.theme.config.default && ctx.theme.config.default.banner ? ctx.theme.config.default.banner : '';
el += `<img class="lazy bg" data-src="${args.bg ? args.bg : defaultBanner}">`

// content
el += `<div class="content">`
// content.top
el += `<div class="top">`
// content.top.back
if (args.link?.length > 0) {
el += `<div></div>`
} else {
el += `
<button class="back cap" onclick="window.history.back()">
<svg aria-hidden="true" viewBox="0 0 16 16" fill="currentColor"><path fill-rule="evenodd" d="M7.78 12.53a.75.75 0 01-1.06 0L2.47 8.28a.75.75 0 010-1.06l4.25-4.25a.75.75 0 011.06 1.06L4.81 7h7.44a.75.75 0 010 1.5H4.81l2.97 2.97a.75.75 0 010 1.06z"></path></svg>
</button>
`
}

// content.top.menus
if (content) {
const rows = content.split('\n').filter(item => item.trim().length > 0)
for (let row of rows) {
if (row.includes('tag-plugin navbar')) {
el += row
break
}
}
}

el += `</div>`
// content.bottom
el += `<div class="bottom">`
// content.bottom.avatar
if (args.avatar?.length > 0) {
el += `<img class="avatar" src="${args.avatar}">`
}
// content.bottom.text-area
if (args.title?.length > 0 || args.subtitle?.length > 0) {
el += `<div class="text-area">`
if (args.title?.length > 0) {
el += `<div class="text title">${args.title}</div>`
}
if (args.subtitle?.length > 0) {
el += `<div class="text subtitle">${args.subtitle}</div>`
}
el += `</div>`
}
el += `</div>`
el += `</div>`
// link
if (args.link?.length > 0) {
el += `<a class="banner-link" href="${args.link}"></a>`
}
el += `</div>`
return el
};

// 1. Register custom banner immediately
// Note: We use the original register method if possible, but hexo.extend.tag.register is bound to hexo.extend.tag
hexo.extend.tag.register('banner', customBanner, true);

// 2. Intercept future registrations to prevent overwrite by theme
const originalRegister = hexo.extend.tag.register;

// We need to bind the new function to hexo.extend.tag context or ensure 'this' is correct
hexo.extend.tag.register = function(name, fn, options) {
if (name === 'banner') {
// Check if the function being registered is our custom one (by comparing reference or just assuming)
// Since we already registered ours, any subsequent registration for 'banner' is likely from the theme
if (fn !== customBanner) {
return; // Block the theme's registration
}
}
return originalRegister.apply(this, arguments);
};

quot 强调引用

适合居中且醒目的引用

1
{% quot 特别引用 icon:default %}

特别引用

支持自定义引号

1
{% quot 热门话题 icon:hashtag %}

热门话题