Next主题配置及修改(持续更新中)

对next主题的一些配置修改,涉及对源代码的修改。next主题的基础配置对于大多数人来说已经能够用了,但是爱折腾的人来说还能修改很多地方。next主题存在时间较长,在整个hexo主题里是比较完善稳定的,用来修改是非常适合的。

huanggua-wuti.webp

图片来源:#東方 无题 - 黄瓜的插画 - pixiv

添加sitemap

安装插件hexo-generator-sitemap

1
npm install hexo-generator-sitemap --save

hexo配置文件添加如下:

1
2
3
4
5
6
7
8
9
sitemap:
path:
- sitemap.xml
- sitemap.txt
template: ./sitemap.xml
template_txt: ./sitemap.txt
rel: false
tags: true
categories: true

添加sitemap.txt到主目录:

1
2
3
4
5
{% for post in posts %}{{ post.permalink | uriencode }}
{% endfor %}{{ config.url | uriencode }}
{% for tag in tags %}{{ tag.permalink | uriencode }}
{% endfor %}{% for cat in categories %}{{ cat.permalink | uriencode }}
{% endfor %}

添加sitemap.xml到主目录:

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
<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
{% for post in posts %}
<url>
<loc>{{ post.permalink | uriencode }}</loc>
{% if post.updated %}
<lastmod>{{ post.updated | formatDate }}</lastmod>
{% elif post.date %}
<lastmod>{{ post.date | formatDate }}</lastmod>
{% endif %}
<changefreq>monthly</changefreq>
<priority>0.6</priority>
</url>
{% endfor %}

<url>
<loc>{{ config.url | uriencode }}</loc>
<lastmod>{{ sNow | formatDate }}</lastmod>
<changefreq>daily</changefreq>
<priority>1.0</priority>
</url>

{% for tag in tags %}
<url>
<loc>{{ tag.permalink | uriencode }}</loc>
<lastmod>{{ sNow | formatDate }}</lastmod>
<changefreq>weekly</changefreq>
<priority>0.2</priority>
</url>
{% endfor %}

{% for cat in categories %}
<url>
<loc>{{ cat.permalink | uriencode }}</loc>
<lastmod>{{ sNow | formatDate }}</lastmod>
<changefreq>weekly</changefreq>
<priority>0.2</priority>
</url>
{% endfor %}
</urlset>

给文章添加永久链接

安装插件hexo-abbrlink

1
npm install hexo-abbrlink --save

hexo配置文件添加如下:

1
2
3
4
5
6
7
8
9
10
# 修改
permalink: posts/:abbrlink/

# 添加
abbrlink:
alg: crc32
rep: hex
drafts: false
force: false
writeback: true

添加RSS

安装插件hexo-generator-feed

1
npm install hexo-generator-feed --save

next主题配置文件添加:

1
2
3
4
5
6
# RSS
sidebar_rss:
text: RSS
icon: fa fa-rss
color: burlywood
link: atom.xml

修改文件:themes\next\layout\_partials\sidebar\site-overview.njk

末尾添加以下代码:

1
2
3
4
5
6
7
8
9
10
{%- if theme.sidebar_rss %}
<div class="" >
<a target="_blank" class="social-link" href="{{ url_for(theme.sidebar_rss.link) }}" style="color: {{ theme.sidebar_rss.color }};">
<span class="icon">
<i class="{{ theme.sidebar_rss.icon }}"></i>
</span>
<span class="label">{{ theme.sidebar_rss.text }}</span>
</a>
</div>
{%- endif %}

使用本地字体并设置首行缩进

next配置文件修改:

1
2
3
# 取消注释
custom_file_path:
style: source\_data/styles.styl

添加文件:source\_data\styles.styl

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/* 首行缩进2个汉字的宽度,段落间距 */
.post-body p {
text-indent: 2em;
margin: 0 0 0.5em;
}

/* 声明字体 */
@font-face {
font-family: 'LXGWWenKaiMono-Medium';
src: url('/fonts/LXGWWenKaiMono-Medium.ttf') format('truetype');
font-weight: normal;
font-style: normal;
}

* {
font-family: 'LXGWWenKaiMono-Medium';
}

修改文件:themes\next\source\css\_variables\base.styl

1
2
3
4
5
6
7
8
9
10
11
12
// Font families.
$font-family-chinese = LXGWWenKaiMono-Medium;

$font-family-base = LXGWWenKaiMono-Medium;

$font-family-logo = LXGWWenKaiMono-Medium;

$font-family-headings = LXGWWenKaiMono-Medium;

$font-family-posts = LXGWWenKaiMono-Medium;

$font-family-monospace = LXGWWenKaiMono-Medium;

将字体文件放入source\fonts中。

添加开关TOC配置

修改文件:themes\next\layout\_macro\sidebar.njk

1
2
3
4
5
6
7
{% macro render(display_toc) %}
<aside class="sidebar">

{# 这行代码检查是否启用了 TOC,同时确保 page.etoc 不存在时默认为 true #}
{%- set display_toc = page.toc.enable and (page.etoc | default(true)) and display_toc %}

{%- if display_toc %}

同时文章添加etoc: false来关闭文章目录。

添加动画卡片

灵感来源于:HEXO-DOUBAN-CARD

添加文件:themes\next\scripts\tags\animation.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
'use strict';

const fs = require('hexo-fs');
const path = require('path');

let animationData = null;
let lastCacheTime = 0;
const CACHE_TTL = 5 * 60 * 1000;

module.exports = function getAnimationByName(name) {
const filePath = path.join(__dirname, '../../../../animation.json');

try {
const now = Date.now();
if (!animationData || now - lastCacheTime > CACHE_TTL) {
const rawData = fs.readFileSync(filePath, { encoding: 'utf8' });
animationData = JSON.parse(rawData);
lastCacheTime = now;
}

if (!Array.isArray(animationData)) {
return '<div class="animation-error">数据格式错误</div>';
}

if (Array.isArray(name)) {
if (name.length === 0) return '<div class="animation-error">名称无效</div>';
name = name[0];
}

if (typeof name !== 'string') {
return '<div class="animation-error">名称无效</div>';
}

name = name.trim();
if (name.length === 0) {
return '<div class="animation-error">名称无效</div>';
}

const foundAnimation = animationData.find(item =>
item?.title?.toLowerCase() === name.toLowerCase()
);

if (!foundAnimation) {
return '<div class="animation-error">未找到番剧信息</div>';
}

return `
<div class="animation-card-block">
<a class="animation-card" href="${foundAnimation.bangumi_url || '#'}">
<div bg-lazy class="animation-card-bgimg" style="background-image: url('${foundAnimation.img_url || ''}');"></div>
<div class="animation-card-left">
<div bg-lazy class="animation-card-img" style="background-image: url('${foundAnimation.img_url || ''}');"></div>
</div>
<div class="animation-card-right">
<div class="animation-card-item"><span>动画名: </span><strong>${foundAnimation.title || '无标题'}</strong></div>
<div class="animation-card-item"><span>播放时间: </span><span>${foundAnimation.data || '未公布'}</span></div>
<div class="animation-card-item"><span>简介: </span><strong>${foundAnimation.synopsis || '暂无简介'}</strong></div>
</div>
</a>
</div>
`;

} catch (err) {
const errorMessage = `[动画卡片插件] 获取番剧卡片失败: ${err.message}`;
console.error(errorMessage);

switch (err.code) {
case 'ENOENT':
return '<div class="animation-error">数据文件不存在</div>';
case 'EACCES':
return '<div class="animation-error">无数据文件访问权限</div>';
case 'EISDIR':
return '<div class="animation-error">路径指向了目录而非文件</div>';
default:
return '<div class="animation-error">数据加载失败</div>';
}
}
};

修改文件:themes\next\scripts\tags\index.js,末尾添加以下内容。

1
2
3
const postAnimation = require('./animation');

hexo.extend.tag.register('animation', postAnimation);

修改文件:source\_data\styles.styl,添加卡片样式。

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
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
.animation-card-block {
display: flex;
justify-content: center;
align-items: center;
width: 100%;
perspective: 1000px;
margin: 20px 0;
}

.animation-card {
display: flex;
margin: 20px 0;
padding: 20px;
border-radius: 16px;
position: relative;
overflow: hidden;
color: #f8f8ff;
text-decoration: none;
width: 90%;
max-width: 800px;
box-shadow: 0 10px 25px rgba(0, 0, 0, 0.3);
background: rgba(30, 30, 50, 0.85);
backdrop-filter: blur(4px);
border: 1px solid rgba(255, 255, 255, 0.1);
transition: all 0.3s ease;
flex-direction: row;
}

.animation-card:hover {
transform: translateY(-5px);
box-shadow: 0 15px 35px rgba(0, 0, 0, 0.4);
}

.animation-card-bgimg {
position: absolute;
width: 115%;
height: 115%;
filter: blur(12px) brightness(0.5) saturate(140%);
background-size: cover;
background-position: center;
background-repeat: no-repeat;
top: -7.5%;
left: -7.5%;
z-index: -1;
opacity: 0.7;
image-rendering: -webkit-optimize-contrast;
}

.animation-card-left {
position: relative;
display: flex;
flex-direction: column;
align-items: center;
z-index: 2;
min-width: 140px;
margin-right: 20px;
}

.animation-card-img {
position: relative;
height: 180px;
width: 120px;
background-size: cover;
background-position: center;
background-repeat: no-repeat;
border-radius: 8px;
box-shadow: 0 6px 15px rgba(0, 0, 0, 0.25);
transform: translateZ(0);
}

.animation-card-right {
position: relative;
display: flex;
flex-direction: column;
z-index: 2;
width: calc(100% - 160px);
font-size: 16px;
line-height: 1.5;
color: #f0f0ff;
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.3);
}

.animation-card-item {
margin-top: 8px;
padding-bottom: 8px;
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
}

.animation-card-item:last-child {
border-bottom: none;
}

.animation-card-item span:first-child {
display: inline-block;
width: 80px;
color: #c0b0ff;
font-weight: 500;
margin-right: 10px;
}

.animation-card-item strong {
color: #ffffff;
font-weight: 600;
letter-spacing: 0.2px;
}

@media (max-width: 1024px) {
.animation-card {
width: 95%;
padding: 18px;
}

.animation-card-img {
height: 160px;
width: 110px;
}

.animation-card-right {
font-size: 15px;
}
}

@media (max-width: 768px) {
.animation-card {
flex-direction: column;
padding: 18px 15px;
width: 98%;
max-width: 500px;
text-align: center;
}

.animation-card-left {
margin-right: 0;
margin-bottom: 15px;
width: 100%;
}

.animation-card-img {
height: 180px;
width: 130px;
}

.animation-card-right {
width: 100%;
font-size: 15px;
}

.animation-card-item {
margin-top: 10px;
}

.animation-card-item span:first-child {
display: block;
width: 100%;
margin-right: 0;
margin-bottom: 5px;
font-size: 14px;
}

.animation-card-item strong {
display: block;
font-size: 15px;
}
}

@media (max-width: 480px) {
.animation-card {
padding: 15px 12px;
border-radius: 14px;
}

.animation-card-bgimg {
filter: blur(10px) brightness(0.55) saturate(130%);
}

.animation-card-img {
height: 160px;
width: 120px;
}

.animation-card-right {
font-size: 14px;
}

.animation-card-item span:first-child {
font-size: 13px;
}

.animation-card-item strong {
font-size: 14px;
}
}

添加文件:animation.json

1
2
3
4
5
6
7
8
9
[
{
"bangumi_url": "https://bgm.tv/subject/284",
"img_url": "https://images.endlesssolo.com/file/caomeimianhuatang-fengmian.webp",
"title": "草莓棉花糖",
"data": "2005年7月14日",
"synopsis": "TVアニメ「苺ましまろ」は、とってもキュートで個性的な4人の小学生と 1人の二十歳の短大生の女の子が繰り広げる、 一見どこでもありそうなゆる~い日常をコミカルに描いた作品です。おしゃれなファッション、ちょっとおませな行動、そしてボケとツッコミの連続。 思わずクスっとしてしまうシーンがいっぱい。 男の子にも女の子にもおススメのポップでキュートな オフビート感覚のアニメーションをどうぞお楽しみください!"
}
]

样例:

缺点十分明显,就是要自己添加json。暂时不考虑自动获取。