前言

鸽了几万年的楠终于开始重构自己的屎山博客了,此贴来记录楠是用了什么东西堆成新的 屎山

部署

  • GitHub 储存
  • Vercel 托管部署
  • 更换 vercel.cdn.yt-blog.top 节点加快国内访问速度
  • 版本:hexo: 6.3.0 butterfly: 4.7.0

整理配置文件

  • 将主题配置文件复制出来,方便更改
  • 将配置文件注释汉化

图床

本来想搞个 cdn 来加速 GitHub 仓库当图床的,结果 https 要证书,就开始了艰辛的坐牢一日。

证书

  1. 安装 wsl ,在微软商店下载了个 Ubuntu 2204 版本。

  2. 启动的时候出错了,一直报错 0x8004032d 。上网查找之后使用下面的命令安装并初始化(前提是已经开启 Hype-v 适用于Linux的Windows子系统 虚拟机平台)。

    1
    wsl --install
  3. 就是正常配置用户名密码啥的,成功进入 wsl。并使用 sudo 命令设置 root 密码。

    1
    sudo passwd root
  4. 安装 acme.sh 的时候又出问题了,没有代理连接不上 Github 。解决方法来自博客园的一篇文章 传送门
    省流:
    就是在 Windows中的C:\Users\<your_username> 目录下创建一个.wslconfig 文件,并写入以下代码。

    1
    2
    3
    4
    5
    6
    [experimental]
    autoMemoryReclaim=gradual
    networkingMode=mirrored
    dnsTunneling=true
    firewall=true
    autoProxy=true

    再使用终端重启 wsl。

    1
    wsl --shutdown

    注意,每次开关梯子都要重新启动 wsl

  5. 成功安装 acme.sh 后便开始手动生成证书

    • 第一次要先使用

      1
      ~/.acme.sh/acme.sh --register-account -m <你的邮箱>

      来注册账户

    • 注册成功后使用

      1
      ~/.acme.sh/acme.sh --issue -d <域名> --dns dns-01

      生成证书

    • 按照要求在域名服务商添加 TXT 解析,等候片刻再次运行命令就生成证书了
  6. 生成的证书在/root 目录,这里又出现个问题,无法访问,显示没有权限。
    解决方法:

    1
    2
    cd /
    sudo nano /etc/wsl.conf

    wsl.cong 里面添加

    1
    2
    [user]
    default=root

    让默认账户是 root 就解决了

配置 cdn

自己搞半天没成功,最后问了一下 煮雪话河山 大佬,并跟着大佬一步一步走才成功

  • 绑定的加速网站:要加速的网站
  • 源站:加速网站绑定的源站,如 vercel 绑定域名的时候的 cname.vercel-dns.com 或者是 cf page 绑定域名时候的 xxx.pages.dev
  • https 证书:证书

外挂标签

使用的是店长的 Tag Plugins Plus 用的是源码部署,站外卡片的样式因为看到 June 的样式很喜欢,所以就也去洪哥的帖子 cv 了一个下来,略微改改。

文章版权卡片美化

使用的是 Fomalhaut 和 店长 的样式,并自己修改了一点 css。

修改过的 css:

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
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
beautify()
headStyle(fontsize)
padding-left: unit(fontsize + 12, 'px')

&:before
margin-left: unit((-(fontsize + 6)), 'px')
font-size: unit(fontsize, 'px')

&:hover
padding-left: unit(fontsize + 18, 'px')

h1,
h2,
h3,
h4,
h5,
h6
transition: all .2s ease-out

&:before
position: absolute
top: calc(50% - 7px)
color: $title-prefix-icon-color
content: $title-prefix-icon
line-height: 1
transition: all .2s ease-out
@extend .fontawesomeIcon

&:hover
&:before
color: $light-blue

h1
headStyle(20)

h2
headStyle(18)

h3
headStyle(16)

h4
headStyle(14)

h5
headStyle(12)

h6
headStyle(12)

ol,
ul
p
margin: 0 0 8px

li
&::marker
color: $light-blue
font-weight: 600
font-size: 1.05em

&:hover
&::marker
color: var(--pseudo-hover)

ul > li
list-style-type: circle

#article-container
word-wrap: break-word
overflow-wrap: break-word

a
color: $theme-link-color

&:hover
text-decoration: underline

img
display: block
margin: 0 auto 20px
max-width: 100%
transition: filter 375ms ease-in .2s

p
margin: 0 0 16px

iframe
margin: 0 0 20px

if hexo-config('anchor')
a.headerlink
&:after
@extend .fontawesomeIcon
float: right
color: var(--headline-presudo)
content: '\f0c1'
font-size: .95em
opacity: 0
transition: all .3s

&:hover
&:after
color: var(--pseudo-hover)

h1,
h2,
h3,
h4,
h5,
h6
&:hover
a.headerlink
&:after
opacity: 1

ol,
ul
ol,
ul
padding-left: 20px

li
margin: 4px 0

p
margin: 0 0 8px

if hexo-config('beautify.enable')
if hexo-config('beautify.field') == 'site'
beautify()
else if hexo-config('beautify.field') == 'post'
&.post-content
beautify()

> :last-child
margin-bottom: 0 !important

#post
.tag_share
.post-meta
&__tag-list
display: inline-block

&__tags
display: inline-block
margin: 8px 8px 8px 0
padding: 0 12px
width: fit-content
border: 1px solid $light-blue
border-radius: 12px
color: $light-blue
font-size: .85em
transition: all .2s ease-in-out

&:hover
background: $light-blue
color: var(--white)

.post_share
display: inline-block
float: right
margin: 8px 0
width: fit-content

.social-share
font-size: .85em

.social-share-icon
margin: 0 4px
width: w = 1.85em
height: w
font-size: 1.2em
line-height: w

.post-copyright
position: relative
margin: 40px 0 10px
padding: 10px 16px
border: 1px solid var(--light-grey)
transition: box-shadow .3s ease-in-out
overflow: hidden
border-radius: 12px!important
background: none;

&:before
background var(--heo-post-blockquote-bg)
position absolute
right -26px
top -120px
content '\f25e'
font-size 200px
font-family 'Font Awesome 5 Brands'
opacity .2

&:hover
box-shadow: 0px 0px 8px 1px #e5e5e5

.post-copyright
&-meta
color: $light-blue
font-weight: bold

&-info
padding-left: 6px

a
text-decoration: none
word-break: break-word

&:hover
text-decoration: none

.post-copyright-cc-info
color: $theme-color;

.post-outdate-notice
position: relative
margin: 0 0 20px
padding: .5em 1.2em
border-radius: 3px
background-color: $noticeOutdate-bg
color: $noticeOutdate-color

if hexo-config('noticeOutdate.style') == 'flat'
padding: .5em 1em .5em 2.6em
border-left: 5px solid $noticeOutdate-border

&:before
@extend .fontawesomeIcon
position: absolute
top: 50%
left: .9em
color: $noticeOutdate-border
content: '\f071'
transform: translateY(-50%)

.ads-wrap
margin: 40px 0
.post-copyright-m-info
.post-copyright-a,
.post-copyright-c,
.post-copyright-u
display inline-block
width fit-content
padding 2px 5px
[data-theme="dark"]
#post
.post-copyright
background #07080a
text-shadow #bfbeb8 0 0 2px
border 1px solid rgb(19 18 18 / 35%)
animation flashlight 1s linear infinite alternate
.post-copyright-info
color #e0e0e4

#post
.post-copyright__title
font-size 22px
.post-copyright__notice
font-size 15px

返回顶部显示网页阅读进度

虽然 Buttrtfly 4.6 版本 就加入了内置了这个功能,可以在配置文件开启,但是内置的的滑动没有 Leonus 的丝滑,所以还是选择自己动手。

用了 Leonus 的教程,但是发现 Leonus 大佬的 js 在我这里有点小问题,所以也自己修改了一下。

这是我修改过的 js(把 childNodes 改成了 children

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
window.onscroll = percent; // 执行函数
// 页面百分比
function percent() {
let a = document.documentElement.scrollTop || window.pageYOffset, // 卷去高度
b =
Math.max(
document.body.scrollHeight,
document.documentElement.scrollHeight,
document.body.offsetHeight,
document.documentElement.offsetHeight,
document.body.clientHeight,
document.documentElement.clientHeight
) - document.documentElement.clientHeight, // 整个网页高度
result = Math.round((a / b) * 100), // 计算百分比
up = document.querySelector("#go-up"); // 获取按钮
percentSpan = document.querySelector("#percent"); // 获取显示的按钮

if (result <= 95) {
up.children[0].style.display = "none";
up.children[1].style.display = "block";
percentSpan.children[0].innerHTML = result;
} else {
up.children[1].style.display = "none";
up.children[0].style.display = "block";
}
}

打开控制台和复制提醒

按键防抖:

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
// 按键防抖

let TT = null; // 防抖全局计时器
/**
* 防抖函数
* @param {逻辑} fn
* @param {防抖时间} time
*/
function debounce(fn, time) {
if (TT !== null) clearTimeout(TT);
TT = setTimeout(fn, time);
}

// 按键防抖 end --

// 检测事件并弹窗

document.onkeydown = function (e) {
// 复制
if (e.ctrlKey && e.key === "c") {
debounce(function () {
Snackbar.show({
text: "复制成功啦🌞若要转载最好保留原文链接!",
pos: "top-right",
actionText: "版权声明",
actionTextColor: "#FF8599",
onActionClick: function () {
location.assign("/privacy");
},
});
}, 300);
}

// 打开控制台
if (
123 == e.keyCode ||
(e.ctrlKey &&
e.shiftKey &&
(74 === e.keyCode || 73 === e.keyCode || 67 === e.keyCode)) ||
(e.ctrlKey && 85 === e.keyCode)
) {
debounce(function () {
Snackbar.show({
text: "开发者模式已打开🍟记住要遵循GPL协议吖!",
pos: "top-right",
showAction: false,
});
}, 300);
}
};

// 检测事件并弹窗 end --
1
2
3
4
5
6
7
/* Snackbar弹窗 */

.snackbar-container {
border-radius: 15px;
}

/* Snackbar弹窗 end */

Heo 加载动画

博客宽屏适配

文章双栏

在店长的教程上做了一点自己的修改

替换 [themes]\butterfly\layout\includes\mixins\post-ui.pug 为下面代码(用的是店长的,删减了一些东西)

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
mixin postUI(posts)
each article , index in page.posts.data
.recent-post-item
-
let link = article.link || article.path
let title = article.title || _p('no_title')
const position = theme.cover.position
let leftOrRight = position === 'both'
? index%2 == 0 ? 'left' : 'right'
: position === 'left' ? 'left' : 'right'
let post_cover = article.cover
let no_cover = article.cover === false || !theme.cover.index_enable ? 'no-cover' : ''
-
.recent-post-content(class=leftOrRight)
.recent-post-cover
img.article-cover(src=url_for(post_cover) onerror=`this.onerror=null;this.src='`+ url_for(theme.error_img.post_page) + `'` alt=title)
.recent-post-info
a.article-title(href=url_for(link) title=title)
.article-title-link= title
.recent-post-meta
.article-meta-wrap
if (is_home() && (article.top || article.sticky > 0))
span.article-meta
i.fas.fa-thumbtack.sticky
span.sticky= _p('sticky')
span.article-meta-separator |
if (theme.post_meta.page.date_type)
span.post-meta-date
if (theme.post_meta.page.date_type === 'both')
i.far.fa-calendar-alt
span.article-meta-label=_p('post.created')
time.post-meta-date-created(datetime=date_xml(article.date) title=_p('post.created') + ' ' + full_date(article.date))=date(article.date, config.date_format)
span.article-meta-separator |
i.fas.fa-history
span.article-meta-label=_p('post.updated')
time.post-meta-date-updated(datetime=date_xml(article.updated) title=_p('post.updated') + ' ' + full_date(article.updated))=date(article.updated, config.date_format)
else
- let data_type_updated = theme.post_meta.page.date_type === 'updated'
- let date_type = data_type_updated ? 'updated' : 'date'
- let date_icon = data_type_updated ? 'fas fa-history' :'far fa-calendar-alt'
- let date_title = data_type_updated ? _p('post.updated') : _p('post.created')
i(class=date_icon)
span.article-meta-label=date_title
time(datetime=date_xml(article[date_type]) title=date_title + ' ' + full_date(article[date_type]))=date(article[date_type], config.date_format)
if (theme.post_meta.page.categories && article.categories.data.length > 0)
span.article-meta
span.article-meta-separator |
i.fas.fa-inbox
each item, index in article.categories.data
a(href=url_for(item.path)).article-meta__categories #[=item.name]
if (index < article.categories.data.length - 1)
i.fas.fa-angle-right.article-meta-link
if (theme.post_meta.page.tags && article.tags.data.length > 0)
span.article-meta.tags
span.article-meta-separator |
i.fas.fa-tag
each item, index in article.tags.data
a(href=url_for(item.path)).article-meta__tags #[=item.name]
if (index < article.tags.data.length - 1)
span.article-meta-link #[='•']

mixin countBlockInIndex
- needLoadCountJs = true
span.article-meta
span.article-meta-separator |
i.fas.fa-comments
if block
block
span.article-meta-label= ' ' + _p('card_post_count')

if theme.comments.card_post_count
case theme.comments.use[0]
when 'Disqus'
+countBlockInIndex
a(href=full_url_for(link) + '#disqus_thread')
i.fa-solid.fa-spinner.fa-spin
when 'Disqusjs'
+countBlockInIndex
a(href=full_url_for(link) + '#disqusjs')
span.disqus-comment-count(data-disqus-url=full_url_for(link))
i.fa-solid.fa-spinner.fa-spin
when 'Valine'
+countBlockInIndex
a(href=url_for(link) + '#post-comment')
span.valine-comment-count(data-xid=url_for(link))
i.fa-solid.fa-spinner.fa-spin
when 'Waline'
+countBlockInIndex
a(href=url_for(link) + '#post-comment')
span.waline-comment-count(id=url_for(link))
i.fa-solid.fa-spinner.fa-spin
when 'Twikoo'
+countBlockInIndex
a.twikoo-count(href=url_for(link) + '#post-comment')
i.fa-solid.fa-spinner.fa-spin
when 'Facebook Comments'
+countBlockInIndex
a(href=url_for(link) + '#post-comment')
span.fb-comments-count(data-href=urlNoIndex(article.permalink))
when 'Remark42'
+countBlockInIndex
a(href=url_for(link) + '#post-comment')
span.remark42__counter(data-url=urlNoIndex(article.permalink))
i.fa-solid.fa-spinner.fa-spin
when 'Artalk'
+countBlockInIndex
a(href=url_for(link) + '#post-comment')
span.artalk-count(data-page-key=url_for(link))
i.fa-solid.fa-spinner.fa-spin
a.article-content(href=url_for(link) title=title)

if theme.ad && theme.ad.index
if (index + 1) % 3 == 0
.recent-post-item.ads-wrap!=theme.ad.index

用的是 模式二 并且将三栏修改成双栏,加上自己的一些修改

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
// 默认的首页卡片容器布局
.recent-posts
padding 0 15px 0 15px
height fit-content
.recent-post-item
margin-bottom 15px
background var(--recent-post-bgcolor)
overflow hidden
border-radius 15px
.recent-post-content
display flex
background var(--recent-post-bgcolor)
position relative
.recent-post-cover
display flex
background transparent
.recent-post-info
display flex
background transparent
flex-direction column
justify-content center
align-items center
.article-title
height 50%
display: flex
text-align: center
align-items: center
justify-content: flex-end
flex-direction: column
.article-title-link
color: var(--text-highlight-color)
font-size: 20px
-webkit-line-clamp: 2
line-height: 30px
margin-top: 0
font-weight: 700
margin-bottom: 0
width: 100%
-webkit-transition: .3s
-moz-transition: .3s
-o-transition: .3s
-ms-transition: .3s
transition: .3s
display: -webkit-box
overflow: hidden
-webkit-box-orient: vertical
&:hover
color: $text-hover
.recent-post-meta
height 50%
display: flex
text-align: center
flex-direction: row
align-items: center
.article-meta-wrap
color #969797
display: -webkit-box;
-webkit-box-orient: vertical
overflow: hidden
a
color: var(--text-highlight-color)
transition: all .2s ease-in-out
color #969797
&:hover
color: $text-hover
.article-content
display flex
text-align: center
flex-direction row
align-items center
justify-content center
.article-content-text
display -webkit-box
-webkit-box-orient vertical
text-overflow: ellipsis
overflow hidden
color #fff
text-shadow 1px 2px 3px #000
&.ads-wrap
display: block !important
height: auto !important
nav#pagination
width: 100%
// 卡片单元布局样式
.recent-posts
padding 0 15px 0 15px
display flex
flex-direction row
flex-wrap wrap
justify-content: space-between
.recent-post-item
border-radius 15px
overflow hidden
.recent-post-content
flex-direction column
flex-wrap nowrap
align-items center
max-height 400px
height: auto
width 100%
.recent-post-cover
width 100%
height 200px
// clip-path polygon(0 130px,0 0,100% 0,100% 130px,50% 100%)
img
height 200px
width 100%
object-fit cover
.recent-post-info
height 150px
width 100%
padding 0px 25px 5px 25px
.article-title
margin: 0px 40px
font-size 18px
.article-title-link
-webkit-line-clamp: 2;
.recent-post-meta
.article-meta-wrap
font-size 95%
-webkit-line-clamp: 3;
.article-content
position absolute
height 200px
width 100%
.article-content-text
-webkit-line-clamp 3
font-size 16px
margin 0px 25px 30px 25px
&::before
content "❝"
font-size 20px
&::after
content "❞"
font-size 20px
// 双栏布局卡片自适应适配
@media screen and (min-width:572px)
.recent-posts
.recent-post-item
width 49%
border 2px solid var(--recent-post-borderColor)
box-shadow: var(--card-box-shadow)
transition: .5s
&:hover
box-shadow: var(--card-hover-box-shadow)
border 2px solid var(--recent-post-hover-borderColor)
// 单栏布局卡片自适应适配
@media screen and (max-width:572px)
.recent-posts
.recent-post-item
width 100%
transition: .5s
1
2
3
4
5
.article-meta-separator,
.article-meta-wrap i,
.article-meta-link {
margin: 0 6px;
}

信息卡片头像状态

  • 2024-8-28 更新
    原本的样式有问题,无法居中,扒了一下鱼佬的导航栏,重新改了一版

部分来自于

  • 分离搜索栏与菜单栏
  • 子菜单横向布局
  • 网站标题部分的增强版 (自己修改了一些)
  • 显示标题 (自己修改了上下滑动动画和去除 jq 依赖)

上下滑动动画

修改 [themes]\butterfly\layout\includes\header\nav.pug: (注意缩进)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
nav#nav
+ #navBox
span#blog-info
a(href=url_for('/') title=config.title)
if theme.nav.logo
img.site-icon(src=url_for(theme.nav.logo))
if theme.nav.display_title
span.site-name=config.title

#menus
!=partial('includes/header/menu_item', {}, {cache: true})
+ #menuTitleBox
+ center(id="name-container")
+ a(id="page-name" href="javascript:scrollToTop()") PAGE_NAME
#nav-right
if (theme.algolia_search.enable || theme.local_search.enable)
#search-button
a.site-page.social-icon.search
i.fas.fa-search.fa-fw
#toggle-menu
a.site-page
i.fas.fa-bars.fa-fw

添加 nav.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
document.addEventListener("pjax:complete", tonav);
document.addEventListener("DOMContentLoaded", tonav);

function tonav() {
function up() {
document.querySelector("#name-container").style.transform =
"translate(-50%, 60px)";
document.querySelector("#nav .menus_items").style.transform =
"translateY(0)";
document.querySelector("#menuTitleBox").style.zIndex = "-1";
}

function scrollToTop() {
btf.scrollToDest(0, 500);
}

function updatePageName() {
const pageNameElement = document.getElementById("page-name");
if (pageNameElement) {
pageNameElement.innerText = document.title.split(" | 鹊楠の小窝")[0];
} else {
// 使用 MutationObserver 监听 DOM 变化,确保元素加载后更新标题
const observer = new MutationObserver((mutations, observer) => {
const pageNameElement = document.getElementById("page-name");
if (pageNameElement) {
pageNameElement.innerText = document.title.split(" | 鹊楠の小窝")[0];
observer.disconnect(); // 元素找到后停止观察
}
});

// 开始观察整个文档
observer.observe(document.body, { childList: true, subtree: true });
}
}

up();

var position = window.scrollY;

window.addEventListener("scroll", function () {
var scroll = window.scrollY;

if (scroll > position) {
document.querySelector("#name-container").style.transform =
"translate(-50%, 0)";
document.querySelector("#nav .menus_items").style.transform =
"translateY(-60px)";
document.querySelector("#menuTitleBox").style.zIndex = "1";
} else {
up();
}

position = scroll;
});

document
.querySelector("#name-container")
.addEventListener("click", function () {
scrollToTop();
});

updatePageName(); // 调用更新页面标题的函数
}

完整 css (我也挑不出来了,混在一起)

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
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
/* Nav导航栏 */
#nav #navBox {
width: 100%;
height: 60px;
position: relative;
display: flex;
align-items: center;
}

#nav .site-page:not(.child):after {
display: none;
}

.nav-fixed #nav {
backdrop-filter: blur(5px) saturate(150%);
}

.menus_item_child li:not(#sidebar-menus li) {
float: left;
border-radius: 6px !important;
-webkit-border-radius: 6px !important;
-moz-border-radius: 6px !important;
-ms-border-radius: 6px !important;
-o-border-radius: 6px !important;
}

.menus_item_child:not(#sidebar-menus ul) {
/*
left:calc(-150%)!important;这是估算值,为了保持元素居中的,如果不合适可以自己调
改为:*/
left: 50%;
translate: -50%;
}

#nav #blog-info {
overflow: visible;
flex: none;
z-index: 100;
}

#nav #blog-info a {
position: relative;
font-size: 1.2em;
}

#nav #blog-info a::before {
opacity: 0;
background-color: var(--theme-color) !important;
border-radius: 8px;
-webkit-border-radius: 8px;
-moz-border-radius: 8px;
-ms-border-radius: 8px;
-o-border-radius: 8px;

transition: 0.3s;
-webkit-transition: 0.3s;
-moz-transition: 0.3s;
-ms-transition: 0.3s;
-o-transition: 0.3s;

position: absolute;
transform: translate(-50%, -50%);
top: 55%;
left: 50%;
width: 120%;
height: 120%;
content: "\f015";
box-shadow: 0 0 5px var(--theme-color);
font-family: "Font Awesome 6 Free";
text-align: center;
color: white;
line-height: 34px;
font-size: 18px;
font-weight: 900;
}

#nav #blog-info a:hover::before {
opacity: 1;
scale: 1.03;
}

#nav.hide-menu .menus_items {
display: inline-block;
transition: 0.3s;
}

#nav .menus_items .menus_item,
#nav .site-page.social-icon.search {
padding: 0 10px;
margin: 0 5px;
border-radius: 10px;
transition: 0.5s;
}

#nav .menus_items .menus_item:hover,
#nav .site-page.social-icon.search:hover {
background: var(--theme-color);
box-shadow: 0 0 5px var(--theme-color);
}

#nav .menus_items .menus_item:hover a {
color: #fff;
}

#page-header.nav-fixed #nav .menus_items .menus_item:hover a,
#page-header.nav-fixed #nav .site-page.social-icon.search:hover {
color: #fff;
}

#menuTitleBox {
position: absolute;
z-index: -1;
width: 100%;
height: 100%;
top: 0;
left: 0;
overflow: hidden;
}

#menuTitleBox #name-container {
height: 100%;
line-height: 60px;
position: absolute;
left: 50%;
transform: translateX(-50%);
transition: 0.3s;
}

#menuTitleBox #name-container::before {
opacity: 0;
background-color: var(--theme-color) !important;
border-radius: 8px;
-webkit-border-radius: 8px;
-moz-border-radius: 8px;
-ms-border-radius: 8px;
-o-border-radius: 8px;

transition: 0.3s;
-webkit-transition: 0.3s;
-moz-transition: 0.3s;
-ms-transition: 0.3s;
-o-transition: 0.3s;

position: absolute;
transform: translate(-50%, -50%);
top: 50%;
left: 50%;
width: 100%;
height: 60%;
content: "回到顶部";
box-shadow: 0 0 5px var(--theme-color);
text-align: center;
color: white;
line-height: 36px;
font-size: 18px;
font-weight: 900;
}

#menuTitleBox #name-container:hover::before {
opacity: 1;
scale: 1.03;
cursor: pointer;
}

#nav.hide-menu #toggle-menu {
display: none !important;
}

#nav #nav-right {
z-index: 100;
position: absolute;
right: 0;
}

#nav a.site-page {
padding-bottom: 6px;
display: inline-block;
}

#nav a.site-page span {
padding-left: 4px;
}

#nav a.site-page::before {
display: none;
}

#nav #menus {
position: absolute;
display: flex;
width: 100%;
align-items: center;
justify-content: center;
}

#nav #menus .menus_items {
transition: 0.3s;
}

#nav .menus_items .menus_item .menus_item_child {
padding: 5px;
border-radius: 15px;
}

#nav .menus_items .menus_item .menus_item_child li {
transition: 0.3s;
border-radius: 10px !important;
margin: 0 2px;
}

#nav .menus_items .menus_item .menus_item_child li:hover {
background: var(--theme-color);
}

#nav .menus_items .menus_item .menus_item_child li:hover a {
color: #fff !important;
}

@media screen and (max-width: 768px) {
/* 菜单修复 */
#nav.hide-menu #toggle-menu {
display: inline-block !important;
}

#nav #menus,
#nav #menuTitleBox {
display: none;
}

#nav #blog-info a {
font-size: 1em;
}
}

/* Nav导航栏 */
以前的版本

修改 [themes]\butterfly\layout\includes\header\nav.pug

1
2
3
4
5
6
  #menus
!=partial('includes/header/menu_item', {}, {cache: true})
+ #menuTitleBox
+ center(id="name-container")
+ a(id="page-name" href="javascript:scrollToTop()") PAGE_NAME
...

在 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
document.addEventListener("pjax:complete", tonav);
document.addEventListener("DOMContentLoaded", tonav);

function up() {
document.querySelector("#name-container").style.top = "60px";
document.querySelector("#nav.hide-menu .menus_items").style.transform =
"translateY(0)";
document.querySelector("#menuTitleBox").style.zIndex = "-1";
}

function scrollToTop() {
btf.scrollToDest(0, 500);
}

function tonav() {
up();

var position = window.scrollY;

window.addEventListener("scroll", function () {
var scroll = window.scrollY;

if (scroll > position) {
document.querySelector("#name-container").style.top = "0";
document.querySelector("#nav.hide-menu .menus_items").style.transform =
"translateY(-60px)";
document.querySelector("#menuTitleBox").style.zIndex = "1";
} else {
up();
}

position = scroll;
});

document
.querySelector("#name-container")
.addEventListener("click", function () {
scrollToTop();
});

document.getElementById("page-name").innerText =
document.title.split(" | 鹊楠の小窝")[0];
}

最后是 css 部分 (仅实现这个功能)

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
#nav #blog-info {
overflow: visible;
flex: none;
z-index: 99;
}

#menuTitleBox {
position: absolute;
z-index: -1;
width: 100%;
height: 100%;
top: 0;
left: 0;
overflow: hidden;
}

#menuTitleBox #name-container {
height: 100%;
line-height: 60px;
position: absolute;
left: 50%;
transform: translateX(-50%);
transition: 0.5s;
}

#nav.hide-menu #toggle-menu {
display: none !important;
}

#nav #nav-right {
z-index: 99;
}

@media screen and (max-width: 572px) {
/* 菜单修复 */
#nav.hide-menu #toggle-menu {
display: inline-block !important;
}

#menus {
display: none;
}

#nav #blog-info a {
font-size: 1em;
}
}

完整 css

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
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
/* Nav导航栏 */
#nav {
justify-content: space-between;
user-select: none;
}

#nav .site-page:not(.child):after {
display: none;
}

.nav-fixed #nav {
backdrop-filter: blur(5px) saturate(150%);
}

.menus_item_child li:not(#sidebar-menus li) {
float: left;
border-radius: 6px !important;
-webkit-border-radius: 6px !important;
-moz-border-radius: 6px !important;
-ms-border-radius: 6px !important;
-o-border-radius: 6px !important;
}

.menus_item_child:not(#sidebar-menus ul) {
/*
left:calc(-150%)!important;这是估算值,为了保持元素居中的,如果不合适可以自己调
改为:*/
left: 50%;
translate: -50%;
}

#nav #blog-info {
overflow: visible;
flex: none;
z-index: 99;
}

#nav #blog-info a {
position: relative;
font-size: 1.2em;
}

#nav #blog-info a::before {
opacity: 0;
background-color: var(--theme-color) !important;
border-radius: 8px;
-webkit-border-radius: 8px;
-moz-border-radius: 8px;
-ms-border-radius: 8px;
-o-border-radius: 8px;

transition: 0.3s;
-webkit-transition: 0.3s;
-moz-transition: 0.3s;
-ms-transition: 0.3s;
-o-transition: 0.3s;

position: absolute;
transform: translate(-50%, -50%);
top: 55%;
left: 50%;
width: 120%;
height: 120%;
content: "\f015";
box-shadow: 0 0 5px var(--theme-color);
font-family: "Font Awesome 6 Free";
text-align: center;
color: white;
line-height: 34px;
font-size: 18px;
font-weight: 900;
}

#nav #blog-info a:hover::before {
opacity: 1;
scale: 1.03;
}

#nav.hide-menu .menus_items {
display: inline-block;
transition: 0.3s;
}

#nav .menus_items .menus_item,
#nav .site-page.social-icon.search {
padding: 0 10px;
margin: 0 5px;
border-radius: 10px;
transition: 0.5s;
}

#nav .menus_items .menus_item:hover,
#nav .site-page.social-icon.search:hover {
background: var(--theme-color);
box-shadow: 0 0 5px var(--theme-color);
}

#nav .menus_items .menus_item:hover a {
color: #fff;
}

#page-header.nav-fixed #nav .menus_items .menus_item:hover a,
#page-header.nav-fixed #nav .site-page.social-icon.search:hover {
color: #fff;
}

#menuTitleBox {
position: absolute;
z-index: -1;
width: 100%;
height: 100%;
top: 0;
left: 0;
overflow: hidden;
}

#menuTitleBox #name-container {
height: 100%;
line-height: 60px;
position: absolute;
left: 50%;
transform: translateX(-50%);
transition: 0.3s;
}

#menuTitleBox #name-container::before {
opacity: 0;
background-color: var(--theme-color) !important;
border-radius: 8px;
-webkit-border-radius: 8px;
-moz-border-radius: 8px;
-ms-border-radius: 8px;
-o-border-radius: 8px;

transition: 0.3s;
-webkit-transition: 0.3s;
-moz-transition: 0.3s;
-ms-transition: 0.3s;
-o-transition: 0.3s;

position: absolute;
transform: translate(-50%, -50%);
top: 50%;
left: 50%;
width: 100%;
height: 60%;
content: "回到顶部";
box-shadow: 0 0 5px var(--theme-color);
text-align: center;
color: white;
line-height: 36px;
font-size: 18px;
font-weight: 900;
}

#menuTitleBox #name-container:hover::before {
opacity: 1;
scale: 1.03;
}

#nav.hide-menu #toggle-menu {
display: none !important;
}

#nav #nav-right {
z-index: 99;
}

#nav a.site-page {
padding-bottom: 6px;
display: inline-block;
}

#nav a.site-page span {
padding-left: 4px;
}

#nav a.site-page::before {
display: none;
}

#nav .menus_items .menus_item .menus_item_child {
padding: 5px;
border-radius: 15px;
}

#nav .menus_items .menus_item .menus_item_child li {
transition: 0.3s;
border-radius: 10px !important;
margin: 0 2px;
}

#nav .menus_items .menus_item .menus_item_child li:hover a {
color: #fff !important;
}

@media screen and (max-width: 768px) {
/* 菜单修复 */
#nav.hide-menu #toggle-menu {
display: inline-block !important;
}

#menus {
display: none;
}

#nav #blog-info a {
font-size: 1em;
}
}

/* Nav导航栏 */

首页分类磁贴

使用的是小冰大佬的插件

其中深色模式适配我是用了 css 变量

1
2
3
4
5
6
# 小冰分类磁贴
color_setting:
text_color: var(--fl-text)
text_hover_color: var(--fl-hover-text)
background_color: var(--fl-bg)
background_hover_color: var(--theme-color)
1
2
3
4
5
6
7
8
9
10
11
12
:root {
/* 首页分类磁贴 */
--fl-bg: #e5e5e5;
--fl-text: #000;
--fl-hover-text: #fff;
}

[data-theme="dark"] {
/* 首页分类磁贴 */
--fl-bg: #222;
--fl-text: #fff;
}

首页置顶轮播

参考

再加上自己微调

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/* 首页轮播图 */

#swiper_container .blog-slider__content {
height: 250px;
}

#swiper_container a.blog-slider__title {
font-weight: bold;
}

#swiper_container .blog-slider__text {
font-size: 1em;
}

#swiper_container .swiper-button-next:after,
#swiper_container .swiper-button-prev:after {
color: var(--theme-color);
}

/* 首页轮播图 */

归档、分类、标签页美化

参考

自己修改的 css:

归档

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
/* 归档、标签、分类页 */

#archive,
#tag,
#category {
padding: 25px 10px;
}

.article-sort-title {
margin-top: 30px;
margin-bottom: 20px;
}

.article-sort-item::before,
.article-sort-title::before,
.article-sort-title::after {
content: none;
}

.article-sort .year {
width: 100% !important;
border-bottom: dashed 5px var(--theme-color);
font-size: 26px;
margin-top: 20px;
}

.article-sort {
border: none;
display: flex;
flex-wrap: wrap;
margin: 20px 20px;
padding: 0;
}

.article-sort-item:not(.year) {
padding: 8px 10px;
width: calc(50% - 0.8rem);
margin: 0.4rem;
border: 2px solid var(--theme-color);
border-radius: 15px;
background: var(--card-bg);
transition: 0.5s;
height: 120px;
}

.article-sort-item-a {
position: absolute;
width: 100%;
height: 100%;
}

.article-sort-item-img {
transition: 0.5s;
height: 90px;
width: 140px;
}

.article-sort-item > a > img {
border-radius: 15px;
}

.article-sort-item-title {
font-size: 22px;
padding-left: 10px;
margin: 10px 0;
line-height: 25px;
text-overflow: ellipsis;
}

.article-sort-item-title:hover {
transform: none;
}

.article-sort-meta {
height: max-content;
position: relative;
}

.article-sort-meta > .article-meta-wrap {
float: left;
}

.article-sort-meta > .article-sort-item-time {
float: right;
}

.article-sort-item-categories,
.article-sort-item-tags {
margin: 0 3px;
padding: 5px 8px;
border-radius: 25px;
border: var(--archives-categories-border);
font-size: 12px;
transition: 0.5s;
}

.article-sort-item-info > div:not(.article-sort-meta) {
display: flex;
align-items: center;
justify-content: space-between;
}

.article-sort-item > i {
position: absolute;
right: 10px;
color: var(--archives-hover-font);
}

.article-sort-description,
.article-sort-item > i {
width: 0;
opacity: 0;
overflow: hidden;
transition: 0.5s;
}

.article-sort-description {
width: 0;
height: 59px;
line-height: 59px;
vertical-align: middle;
margin: 5px 10px 0 15px;
text-overflow: ellipsis;
}

.article-sort-item:hover:not(.year) {
background-color: var(--theme-color);
box-shadow: 0 0 10px var(--theme-color);
}

.article-sort-item:hover:not(.year) {
background-color: var(--theme-color);
box-shadow: 0 0 10px var(--theme-color);
}

.article-sort-item:hover:not(.year) .article-sort-description,
.article-sort-item:hover:not(.year) > i {
width: auto;
opacity: 1;
}

.article-sort-item:hover:not(.year) .article-sort-description {
width: auto;
}

.article-sort-item:hover:not(.year) .article-sort-item-img {
transition: 0.5s;
width: 0;
}

.article-sort-item:hover:not(.year) .article-sort-item-title {
color: var(--archives-hover-font) !important;
}

.article-sort-item:hover:not(.year) .article-meta-wrap a,
.article-sort-item:hover:not(.year) .article-sort-description,
.article-sort-item:hover:not(.year) .article-sort-item-time {
color: var(--archives-hover-timeColor) !important;
}

.article-sort-item:hover:not(.year) .article-sort-item-categories {
border: var(--archives-categories-border);
}

.article-sort-item:hover:not(.year) .article-sort-item-tags {
border: var(--archives-categories-border);
}

#pagination .page-number {
border-radius: 6px;
}

@media screen and (max-width: 768px) {
.article-sort-item:not(.year) {
width: 100%;
}

.article-sort-meta > .article-meta-wrap {
display: none;
}

.article-sort-item-title {
font-size: 16px;
}

.article-sort-item-img {
width: 90px;
}
}

/* 归档、标签、分类页 end */

踩了个坑,归档页显示标签(tags)要在配置文件开启,浪费了我好多时间 😭😭

分类

只参考了一下 meuicat 大佬的页面,css 是自己手搓的绝对不是因为懒得改变量 (确信)

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
/* 分类 */
.category-lists ul li:before {
content: "\f550";
font-weight: 900;
cursor: pointer;
font-family: "Font Awesome 6 Free";
position: static;
border: none;
font-size: 20px;
width: auto;
height: auto;
}

.category-lists .category-list .category-list-count:before,
.category-lists .category-list .category-list-count:after {
display: none;
}

.category-lists ul {
padding: 0;
margin: 20px 0;
display: flex;
justify-content: center;
flex-direction: row;
flex-wrap: wrap;
}

.category-lists ul li {
padding: 0.5em;
border: 1px solid #cacaca;
border-radius: 15px;
margin: 10px;
padding: 10px;
box-shadow: 0 0 8px 6px #2c2d300c;
display: flex;
justify-content: center;
align-items: center;
transition: 0.5s;
}

.category-lists ul li:hover {
box-shadow: 0 0 8px 5px var(--theme-color);
background: var(--theme-color);
border-color: var(--theme-color);
transform: scale(1.1);
}

.category-lists ul li:hover a {
color: #fff;
}

.category-lists ul li a:hover {
color: #fff !important;
}

.category-lists .category-list a {
font-size: 1.2em;
margin: 0 10px;
}

.category-lists .category-list .category-list-count {
color: #858585;
background: #e5e5e5;
padding: 2px 15px;
margin: 0;
border-radius: 10px;
}

标签

如果标签页的标签没有数字的话看这里

修改 [themes]\butterfly\scripts\helpers\page.js

1
2
3
4
5
6
7
8
9
10
11
  const length = sizes.length - 1
source.sort(orderby, order).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};`
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}`
- result += `<a href="${env.url_for(tag.path)}" style="${style}">${tag.name}</a>`
+ result += `<a href="${env.url_for(tag.path)}" style="${style}">${tag.name}<span>${tag.length}</span></a>`
})
return result
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
/* 标签 */
.tag-cloud-list.is-center {
display: flex;
justify-content: center;
flex-direction: row;
flex-wrap: wrap;
}

.tag-cloud-list a {
color: var(--font-color) !important;
padding: 0.5em;
border: 1px solid #cacaca;
border-radius: 15px;
margin: 10px;
padding: 10px;
box-shadow: 0 0 8px 6px #2c2d300c;
display: flex;
justify-content: center;
align-items: center;
transition: 0.3s;
}

.tag-cloud-list a:hover {
color: #fff !important;
box-shadow: 0 0 8px 5px var(--theme-color);
background: var(--theme-color);
border-color: var(--theme-color);
transform: scale(1.1);
}

.tag-cloud-list a span {
margin-left: 10px;
color: #858585;
background: #e5e5e5;
padding: 2px 15px;
border-radius: 10px;
}

.tag-cloud-list a:before {
content: "\f02b";
color: var(--tag-icon-color);
font-weight: 900;
cursor: pointer;
font-family: "Font Awesome 6 Free";
position: static;
border: none;
font-size: 20px;
width: auto;
height: auto;
margin-right: 10px;
}

右下角菜单修改

添加直达底部

修改 [themes]\butterfly\layout\includes\rightside.pug , 在最下面添加代码 (注意缩进)

1
2
button#go-down(type="button" title="直达底部" onclick="btf.scrollToDest(document.body.scrollHeight, 500);")
i.fas.fa-arrow-down

样式美化

1
2
3
4
5
6
7
8
/* 右下角菜单 */

#rightside #rightside-config-show > button,
#rightside #rightside-config-hide > button {
border-radius: 50%;
}

/* 右下角菜单 end */

持久化 url

安装 hexo-abbrlink2 插件

1
npm install hexo-abbrlink2 --save

修改 _config.ymlpermalink

1
permalink: posts/:abbrlink/ # 永久链接格式

_config.yml 添加配置

1
2
3
4
# hexo-abbrlink2
# 持久化url
abbrlink:
start: 0 # 启起始文章id,默认为0 ,可以自定义,比如100

Foot 页脚

参考

我的 footer.pugfooter.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
#footer-wrap
.wordcount
- let allword = totalcount(site)
span= '楠居然写了 ' + allword + ' 字'
br
if isNaN(allword)
- allword= Number(allword.replace('k', ''))
if allword< 50
span= "还在努力更新中.. 咕咕咕"
else if allword< 70
span= "好像写完一本 埃克苏佩里 的 《小王子》 了啊"
else if allword< 90
span= "好像写完一本 鲁迅 的 《呐喊》 了啊"
else if allword< 100
span= "好像写完一本 林海音 的 《城南旧事》 了啊"
else if allword< 110
span= "好像写完一本 马克·吐温 的 《王子与乞丐》了! 了啊"
else if allword< 120
span= "好像写完一本 鲁迅 的 《彷徨》 了啊"
else if allword< 130
span= "好像写完一本 余华 的 《活着》 了啊"
else if allword< 140
span= "好像写完一本 曹禺 的 《雷雨》 了啊"
else if allword< 150
span= "好像写完一本 史铁生 的 《宿命的写作》 了啊"
else if allword< 160
span= "好像写完一本 伯内特 的 《秘密花园》 了啊"
else if allword< 170
span= "好像写完一本 曹禺 的 《日出》 了啊"
else if allword< 180
span= "好像写完一本 马克·吐温 的 《汤姆·索亚历险记》 了啊"
else if allword< 190
span= "好像写完一本 沈从文 的 《边城》 了啊"
else if allword< 200
span= "好像写完一本 亚米契斯 的 《爱的教育》 了啊"
else if allword< 210
span= "好像写完一本 巴金 的 《寒夜》 了啊"
else if allword< 220
span= "好像写完一本 东野圭吾 的 《解忧杂货店》 了啊"
else if allword< 230
span= "好像写完一本 莫泊桑 的 《一生》 了啊"
else if allword< 250
span= "好像写完一本 简·奥斯汀 的 《傲慢与偏见》 了啊"
else if allword< 280
span= "好像写完一本 钱钟书 的 《围城》 了啊"
else if allword< 300
span= "好像写完一本 张炜 的 《古船》 了啊"
else if allword< 310
span= "好像写完一本 茅盾 的 《子夜》 了啊"
else if allword< 320
span= "好像写完一本 阿来 的 《尘埃落定》 了啊"
else if allword< 340
span= "好像写完一本 艾米莉·勃朗特 的 《呼啸山庄》 了啊"
else if allword< 350
span= "好像写完一本 雨果 的 《巴黎圣母院》 了啊"
else if allword< 360
span= "好像写完一本 东野圭吾 的 《白夜行》 了啊"
else
span= "好像写完一本我国著名的 四大名著 了!!!"
else
span= "还在努力更新中.. 咕咕咕"

.footer-content
div(style="font-size: 0.7rem")
span#timeDate= '载入天数...'
span= ' '
span#times= '载入时分秒...'
script(src="/static/js/duration.js")

if theme.footer.owner.enable
- var now = new Date()
- var nowYear = now.getFullYear()
if theme.footer.owner.since && theme.footer.owner.since != nowYear
.copyright!= `&copy;${theme.footer.owner.since} - ${nowYear} By ${config.author}`
else
.copyright!= `&copy;${nowYear} By ${config.author}`
if theme.footer.copyright
.framework-info
span= _p('footer.framework') + ' '
a(href='https://hexo.io')= 'Hexo'
span.footer-separator |
span= _p('footer.theme') + ' '
a(href='https://github.com/jerryc127/hexo-theme-butterfly')= 'Butterfly'
if theme.footer.custom_text
.footer_custom_text!=`${theme.footer.custom_text}`

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
#footer
position: relative

.wordcount
text-align: center
font-family: 'Noto Serif SC', -apple-system,BlinkMacSystemFont,Roboto,Segoe UI,Helvetica,Arial,serif
font-size: large
padding: 2rem 0 0 0

&::before
display: none

#footer-wrap
position: relative
padding: 40px 20px
color: var(--font-color)
text-align: center

a
color: var(--light-grey)
margin: 0 5px

&:hover
text-decoration: underline

img
max-height: 20px

&>div
margin: 10px 0

.footer-separator
margin: 0 4px

.icp-icon
padding: 0 4px
max-height: 1.4em
width: auto
vertical-align: text-bottom

首页封面样式

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
/* 首页修改 */

body {
background: var(--qn-body-bg);
/* 确保伪元素相对于容器定位 */
}

@media screen and (min-width: 768px) {
.page {
position: relative;
}

.page::before {
content: "";
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
z-index: -1;
/* 确保伪元素在内容的下方 */
background: var(--qn-body-bg);
background-attachment: local;
background-position: center;
background-repeat: initial;
background-image: var(--qn-bg-img);
will-change: opacity, transform, filter;
opacity: calc(1 - var(--process) * 1) !important;
filter: blur(calc(var(--process) * 10px));
transform: scale(calc(1 + var(--process) * 0.1));
/* 可选,增加平滑过渡效果 */
}

[data-theme="dark"] .page.home::before {
height: 100vh;
}

[data-theme="dark"] .page::before {
width: 100%;
height: 400px;
background: var(--qn-body-bg);
background-attachment: local;
background-position: center;
background-repeat: no-repeat;
background-size: cover;
/* 保持背景图片的原始尺寸 */
background-image: var(--qn-bg-img);
}
}

@media screen and (max-width: 768px) {
.page::before {
content: "";
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
z-index: -1;
/* 确保伪元素在内容的下方 */
background: var(--qn-body-bg);
background-attachment: local;
background-position: center;
background-repeat: initial;
background-image: var(--qn-bg-img);
}

[data-theme="dark"] .page::before {
width: 100%;
height: 100vh;
background: var(--qn-body-bg);
background-attachment: local;
background-position: center;
background-repeat: no-repeat;
background-size: cover;
position: fixed;
background-image: var(--qn-bg-img);
}
}

.article-meta-separator,
.article-meta-wrap i,
.article-meta-link {
margin: 0 6px;
}

.home #page-header:not(.not-top-img):before,
.page #page-header::before {
display: none;
}

#page-header {
background: none;
}

/* 导航栏 */
/* 封面标题 */
/* 封面副标题 */
/* 手机端Icon */
#nav a,
#page-header #site-title,
#page-header #site-subtitle,
#page-header #site_social_icons .social-icon {
color: var(--header-font-color);
}

/* 首页修改 end */
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
// 首页封面样式

window.addEventListener("scroll", function () {
// 获取当前页面滚动的高度
const scrollTop = window.scrollY || document.documentElement.scrollTop;

// 获取90%视口高度,即页面90vh对应的像素值
const thresholdHeight = window.innerHeight * 0.8;

// 计算scrollTop占thresholdHeight的比例,并限制在0-1之间
let scrollPercentage = scrollTop / thresholdHeight;
if (scrollPercentage > 1) {
scrollPercentage = 1;
} else if (scrollPercentage < 0) {
scrollPercentage = 0;
}

// 输出或使用这个scrollPercentage值
console.log(scrollPercentage);

// 将这个值应用于其他操作,例如CSS变量
document.documentElement.style.setProperty("--process", scrollPercentage);
});

// 首页封面样式 end --

文章页样式

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
/* 文章页 */

/* 顶部封面 */
.post-bg {
position: relative;
}

#page-header:not(.not-top-img):before {
position: absolute;
width: 100%;
height: 100%;
background-color: var(--mark-bg);
content: "";
backdrop-filter: blur(8px) brightness(0.5);
}

.post #page-header {
background-position: center center;
background-size: cover;
background-repeat: no-repeat;
}

/* 导航栏 */
.post #page-header #nav a {
color: var(--post-header-font-color);
}

.post #page-header.nav-fixed #nav a {
color: var(--post-fixed-nav-font-color);
}

/* 目录 */
#aside-content #card-toc .toc-content .toc-link.active {
border-radius: 5px;
}

/* 文章页 end */

波浪线

参考

搜索时滚动条消失恢复

我发现在打开搜索弹窗的时候会禁止滚动页面,并且滚动条会消失,造成页面宽度变化,很丑,所以就找办法给他干掉了

修改 [themes]\butterfly\source\js\search\local-search.js 大约第 7 行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
window.addEventListener('load', () => {
let loadFlag = false
let dataObj = []
const $searchMask = document.getElementById('search-mask')

const openSearch = () => {
- const bodyStyle = document.body.style
- bodyStyle.width = '100%'
- bodyStyle.overflow = 'hidden'
btf.animateIn($searchMask, 'to_show 0.5s')
btf.animateIn(document.querySelector('#local-search .search-dialog'), 'titleScale 0.5s')
setTimeout(() => { document.querySelector('#local-search-input input').focus() }, 100)
if (!loadFlag) {
search()
loadFlag = true
}
...

修改网站 cdn

优化一下加载速度

cdn 大部分来自 Heo 佬

我的 option

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
option:
countup_js: /static/js/countup.js
# main_css:
# main:
# utils:
translate: https://cdn1.tianli0.top/npm/js-heo@1.0.6/translate/tw_cn.js
# local_search:
algolia_js: https://cdn1.tianli0.top/npm/js-heo@1.0.11/algolia/algolia.js
algolia_search_v4: https://cdn.staticfile.org/algoliasearch/4.14.3/algoliasearch-lite.umd.min.js
instantsearch_v4: https://cdn.staticfile.org/instantsearch.js/4.49.2/instantsearch.production.min.js
# docsearch_js:
# docsearch_css:
pjax: https://lib.baomitu.com/pjax/0.2.8/pjax.min.js
gitalk: https://lf6-cdn-tos.bytecdntp.com/cdn/expire-1-M/gitalk/1.7.2/gitalk.min.js
gitalk_css: https://lf6-cdn-tos.bytecdntp.com/cdn/expire-1-M/gitalk/1.7.2/gitalk.min.css
# blueimp_md5:
valine: https://lf3-cdn-tos.bytecdntp.com/cdn/expire-1-M/valine/1.4.16/Valine.min.js
disqusjs: https://lf3-cdn-tos.bytecdntp.com/cdn/expire-1-M/disqusjs/1.3.0/disqus.js
disqusjs_css: https://lf6-cdn-tos.bytecdntp.com/cdn/expire-1-M/disqusjs/1.3.0/disqusjs.css
twikoo: https://lf6-cdn-tos.bytecdntp.com/cdn/expire-1-M/twikoo/1.4.18/twikoo.all.min.js
# waline_js:
# waline_css:
sharejs: https://lib.baomitu.com/social-share.js/1.0.16/js/social-share.min.js
sharejs_css: https://lib.baomitu.com/social-share.js/1.0.16/css/share.min.css
# mathjax:
# katex:
# katex_copytex:
# mermaid:
# canvas_ribbon:
# canvas_fluttering_ribbon:
# canvas_nest:
lazyload: https://lf3-cdn-tos.bytecdntp.com/cdn/expire-1-M/vanilla-lazyload/17.3.1/lazyload.iife.min.js
instantpage: https://lf3-cdn-tos.bytecdntp.com/cdn/expire-1-M/instant.page/5.1.0/instantpage.min.js
typed: https://lf9-cdn-tos.bytecdntp.com/cdn/expire-1-M/typed.js/2.0.12/typed.min.js
# pangu:
fancybox_css_v4: https://cdn.staticfile.org/fancyapps-ui/4.0.31/fancybox.min.css
fancybox_v4: https://cdn.staticfile.org/fancyapps-ui/4.0.31/fancybox.umd.min.js
medium_zoom: https://lf6-cdn-tos.bytecdntp.com/cdn/expire-1-M/medium-zoom/1.0.6/medium-zoom.min.js
snackbar_css: https://lf3-cdn-tos.bytecdntp.com/cdn/expire-1-M/node-snackbar/0.1.16/snackbar.min.css
snackbar: https://lf6-cdn-tos.bytecdntp.com/cdn/expire-1-M/node-snackbar/0.1.16/snackbar.min.js
# activate_power_mode:
# fireworks:
# click_heart:
# ClickShowText:
fontawesomeV6: https://lf6-cdn-tos.bytecdntp.com/cdn/expire-1-M/font-awesome/6.0.0/css/all.min.css
# flickr_justified_gallery_js:
# flickr_justified_gallery_css:
aplayer_css: https://lf6-cdn-tos.bytecdntp.com/cdn/expire-1-M/aplayer/1.10.1/APlayer.min.css
aplayer_js: https://lf6-cdn-tos.bytecdntp.com/cdn/expire-1-M/aplayer/1.10.1/APlayer.min.js
meting_js: https://cdn1.tianli0.top/npm/js-heo@1.0.12/metingjs/Meting.min.js
prismjs_js: https://cdn1.tianli0.top/npm/prismjs@1.1.0/prism.js
prismjs_lineNumber_js: https://cdn1.tianli0.top/npm/prismjs/plugins/line-numbers/prism-line-numbers.min.js
prismjs_autoloader: https://cdn1.tianli0.top/npm/prismjs/plugins/autoloader/prism-autoloader.min.js
# artalk_js:
# artalk_css:
busuanzi: //npm.elemecdn.com/penndu@1.0.0/bsz.js

那年今日

点击文章卡片进入文章页

参考

看不懂的看这里

修改 [themes]\butterfly\layout\includes\mixins\post-ui.pug :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
mixin postUI(posts)
each article , index in page.posts.data
+ - let link = article.link || article.path
+ .recent-post-item(onclick=`pjax.loadUrl('${url_for(link)}')`)
- .recent-post-item
-
- let link = article.link || article.path
let title = article.title || _p('no_title')
const position = theme.cover.position
let leftOrRight = position === 'both'
? index%2 == 0 ? 'left' : 'right'
: position === 'left' ? 'left' : 'right'
let post_cover = article.cover
let no_cover = article.cover === false || !theme.cover.index_enable ? 'no-cover' : ''
-

往下翻找到 .article-meta__categories.article-meta__tags , 在 a 标签后的括号内添加 onclick="window.event.cancelBubble=true;" (注意,要加个空格)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
if (theme.post_meta.page.categories && article.categories.data.length > 0)
span.article-meta
span.article-meta-separator |
i.fas.fa-inbox
each item, index in article.categories.data
+ a(href=url_for(item.path) onclick="window.event.cancelBubble=true;").article-meta__categories #[=item.name]
if (index < article.categories.data.length - 1)
i.fas.fa-angle-right.article-meta-link
if (theme.post_meta.page.tags && article.tags.data.length > 0)
span.article-meta.tags
span.article-meta-separator |
i.fas.fa-tag
each item, index in article.tags.data
+ a(href=url_for(item.path) onclick="window.event.cancelBubble=true;").article-meta__tags #[=item.name]
if (index < article.tags.data.length - 1)
span.article-meta-link #[='•']

外挂标签之折叠栏

店长的外挂标签里的折叠栏不是很喜欢,因为用的是 details 元素实现的,没有过渡动画,所以就自己重写了一下源码和样式

展示
默认打开

内容

默认关闭

内容

示例代码 (其实和店长的没啥区别,就是少了个颜色的选项)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
{% folding, 展示 %}

{% folding open, 默认打开 %}

内容

{% endfolding %}

{% folding, 默认关闭 %}

内容

{% endfolding %}

{% endfolding %}

[themes]\butterfly\scripts\tag 目录下新建 folding.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
"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 `<div class="details" ${style}>
<div class="collapsible"> ${title} </div>
<div class="content">
${hexo.render
.renderSync({ text: content, engine: "markdown" })
.split("\n")
.join("")}
</div>
</div>`;
} else {
return `<div class="details">
<div class="collapsible"> ${title} </div>
<div class="content">
${hexo.render
.renderSync({ text: content, engine: "markdown" })
.split("\n")
.join("")}
</div>
</div>`;
}
}

hexo.extend.tag.register("folding", postFolding, { ends: true });

[themes]\butterfly\source\css\_tags 目录下新建 folding.styl 文件
Tips:如果需要修改颜色,改颜色变量就好了

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
.details
margin: 1em 0
border: 1px solid transparent
border-radius: 10px
transition: all 0.3s

.content
padding: 0 20px
height: 0
overflow: hidden
transition: all 0.3s

.collapsible
background-color: var(--linkDiv-bgColor)
color: white
cursor: pointer
padding: 8px
text-align: left
outline: none
font-size: 15px
border-radius: 10px
transition: all 0.3s
color: var(--linkDiv-titleColor)
display: flex
align-items: center
position: relative
user-select: none

&:hover
cursor: pointer
background-color: var(--theme-color)
color: var(--linkDiv-hoverColor)

&:after
opacity: 1
color: var(--linkDiv-hoverColor)

&:before
color: var(--linkDiv-hoverColor)

&:before
content: "\f0da"
font-weight: 900
font-family: "Font Awesome 6 Free"
font-size: 1.3em
color: var(--theme-color)
margin-right: 10px
transition: all 0.3s

&:after
content: '\002B'
color: var(--linkDiv-titleColor)
opacity: 0
font-weight: bold
float: right
position: absolute
right: 15px
transition: 0.3s

.details[open]>.collapsible:after
content: "\2212"

.details[open]>.collapsible
border-radius: 9px 9px 0 0
background-color: var(--theme-color)
color: var(--linkDiv-hoverColor)
margin-bottom: 20px

.details[open]>.collapsible:after
opacity: 1
color: var(--linkDiv-hoverColor)

.details[open]>.collapsible:before
transform: rotate(90deg)
color: var(--linkDiv-hoverColor)

.details[open]>.content
border-radius: 0 0 10px 10px

.details[open]
border: 1px solid var(--theme-color)

在自己的 js 文件夹下新建 foldMain.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
document.querySelectorAll(".collapsible").forEach((button) => {
var heightTimeOut;
button.addEventListener("click", function () {
const details = this.parentElement;
const content = details.querySelector(".content");
const contentTranTime =
parseFloat(window.getComputedStyle(content).transitionDuration) * 1000;

// 切换 open 属性
if (details.hasAttribute("open")) {
if (heightTimeOut) {
clearTimeout(heightTimeOut);
}

content.style.height = content.scrollHeight + "px";
setTimeout(() => {
details.removeAttribute("open");
content.style.height = 0 + "px"; // 收起时,重置 max-height
}, 1);
} else {
details.setAttribute("open", "");
content.style.height = content.scrollHeight + "px"; // 展开时,设置 max-height 为内容高度
heightTimeOut = setTimeout(() => {
content.style.height = "auto";
}, contentTranTime);
}
});
});

// 页面加载时,为已展开的内容设置 max-height
document.querySelectorAll(".details[open]").forEach((details) => {
const content = details.querySelector(".content");
content.style.height = "auto";
});

引入 foldMain.js 并适配 Pjax

1
- <script data-pjax src="/static/js/foldMain.js?1"></script> # 外挂标签-折叠栏

说说

因为我没有服务器 😭,所以使用的是本地静态的说说,正好浮杨大佬新开发了一个说说,我就试试水

浮杨佬说说的项目地址

正常插件安装版

没有自定义需求的直接 npm 安装就好了

1
npm install hexo-butterfly-statictalk

鹊楠魔改免安装版

这个是我自己改给自己用的,舍弃掉了自动生成时间,可能不是那么好看和好用,可以自己改改

2024/9/2 更新

修复 bug

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
function arrangeItems() {
var container = document.querySelector("#talk-container");
var items = document.querySelectorAll(".talk-wrapper");

if (container && items) {
var containerWidth = container.clientWidth;
var columns = 3; // 默认列数

if (containerWidth <= 768) {
columns = 1; // 窗口宽度 <= 768px 时为单列布局
} else if (containerWidth <= 1000) {
columns = 2; // 窗口宽度 <= 1000px 时为双列布局
}

var columnHeights = Array(columns).fill(0); // 初始化每列高度为0
var columnWidth = containerWidth / columns; // 计算每列宽度
var margin = 20; // 间隔

// 从后往前遍历 items
for (var i = items.length - 1; i >= 0; i--) {
var item = items[i];
var itemHeight = item.offsetHeight;

var minHeight = Math.min(...columnHeights); // 获取最短列的高度
var minIndex = columnHeights.indexOf(minHeight); // 获取最短列的索引

var translateX = minIndex * columnWidth;
var translateY = minHeight;

var isLastColumn = minIndex === columns - 1;

item.style.transform = `translate(${translateX}px, ${translateY}px)`;
item.style.width = isLastColumn
? `${columnWidth}px`
: `${columnWidth - margin}px`;

columnHeights[minIndex] += itemHeight + margin;
}

container.style.height = `${Math.max(...columnHeights)}px`;
} else {
return;
}
}

function todo() {
if (location.pathname.startsWith("/talk")) {
arrangeItems();

window.addEventListener("scroll", arrangeItems);

window.addEventListener("resize", arrangeItems);
}
}

document.addEventListener("pjax:complete", todo);
document.addEventListener("DOMContentLoaded", todo);

新建 talk 页面

1
hexo new page talk

打开 source\talk\index.md 添加

1
2
3
4
5
---
title: 说说
date: 2024-08-10 23:25:34
type: talk
---

修改 [themes]\butterfly\layout\page.pug

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
extends includes/layout.pug

block content
#page
if top_img === false
h1.page-title= page.title

case page.type
when 'tags'
include includes/page/tags.pug
when 'link'
include includes/page/flink.pug
when 'categories'
include includes/page/categories.pug
+ when 'talk'
+ include includes/page/talk.pug

default
include includes/page/default-page.pug

if page.comments !== false && theme.comments && theme.comments.use
- var commentsJsLoad = true
!=partial('includes/third-party/comments/index', {}, {cache: true})

[themes]\butterfly\layout\includes\page 文件夹下新建 talk.pug 文件,写入

1
2
3
4
5
6
7
8
9
10
11
12
13
if site.data.talk
#talk-container
each i in site.data.talk
- let content = markdown(i.content)
- let time = i.time

- content = content.replace(/<img src="(.*?)"[^>]*>/g, '<a href="$1" data-fancybox="gallery" data-caption="" data-thumb="$1">$&</a>')

div.talk-wrapper
div.talk-content!= content
div.talk-footer
div.talk-time= time

[themes]\butterfly\source\css\_page 文件夹下新建 talk.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
#talk-container
width 100%
position relative

.talk-wrapper
width 30%
position absolute
/* 默认宽度,适用于三列布局 */
box-sizing border-box
padding 1em
border-radius 10px
transform translate(0, 0)
/* 初始位置 */
transition all 0.3s
box-shadow var(--card-box-shadow)
border 1px solid var(--talk-time-bg)

.talk-content
img
display: block
margin: 0 auto 20px
max-width: 100%
-webkit-transition: filter 375ms ease-in 0.2s
-moz-transition: filter 375ms ease-in 0.2s
-o-transition: filter 375ms ease-in 0.2s
-ms-transition: filter 375ms ease-in 0.2s
transition: filter 375ms ease-in 0.2s

.talk-wrapper:hover
box-shadow var(--card-hover-box-shadow)
border-color var(--theme-color)

.talk-content h1,
.talk-content h2,
.talk-content h3,
.talk-content h4,
.talk-content h5,
.talk-content h6
color var(--font-color)

.talk-footer
border-top 2px dotted var(--talk-time-bg)
padding 5px
display flex
justify-content flex-end

.talk-time
padding 3px 7px
background var(--talk-time-bg)
font-size .7rem
border-radius 25px
margin-top 5px

.talk-time::before
content "\f017"
font-weight 900
font-family "Font Awesome 6 Free"
margin-right 5px

@media (max-width: 768px)
.talk-wrapper
width 100% !important
/* 单列布局 */

在自己的 js 文件夹下新建 talk.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
function arrangeItems() {
var container = document.querySelector("#talk-container");
var items = document.querySelectorAll(".talk-wrapper");

if (container && items) {
var columns = 3; // 默认列数
var containerWidth = container.clientWidth;

if (containerWidth <= 768) {
columns = 1; // 窗口宽度 <= 768px 时为单列布局
} else if (containerWidth <= 1000) {
columns = 2; // 窗口宽度 <= 1000px 时为双列布局
}

var columnHeights = Array(columns).fill(0); // 初始化每列高度为0
var columnWidth = containerWidth / columns; // 计算每列宽度
var margin = 20; // 间隔

items.forEach((item, index) => {
// 获取当前元素的高度
var itemHeight = item.offsetHeight;

var minHeight = Math.min(...columnHeights); // 获取最短列的高度
var minIndex = columnHeights.indexOf(minHeight); // 获取最短列的索引

// 计算transform位置
var translateX = minIndex * columnWidth;
var translateY = minHeight;

// 判断是否为最后一列
var isLastColumn = minIndex === columns - 1;

// 设置transform位置
item.style.transform = `translate(${translateX}px, ${translateY}px)`;
item.style.width = isLastColumn
? `${columnWidth}px`
: `${columnWidth - margin}px`; // 最后一列不减去间隔

// 更新列高度
columnHeights[minIndex] += itemHeight + margin; // 加上底部间距
});

// 更新容器的高度以适应所有列
container.style.height = `${Math.max(...columnHeights)}px`;
} else {
return;
}
}

if (location.pathname.startsWith("/talk")) {
window.onload = arrangeItems();

// 滚动后重新布局
window.addEventListener("scroll", arrangeItems);

// 当窗口大小改变时重新布局
window.addEventListener("resize", arrangeItems);
}

并在配置文件引入该 js

1
2
bottom:
- <script data-pjax src="/static/js/talk.js?1"></script> # 说说

最后在 source\_data 文件夹下新建 talk.yml

参考写法

1
2
3
4
5
6
7
8
9
10
11
- content: |
1
test
# test1
![](https://tuchuang.voooe.cn/images/2024/06/19/MUICanvas.webp)
![](https://tuchuang.voooe.cn/images/2024/06/19/InstallDolby.webp)
time: "2024-09-01"
- content: |
2
# test1
time: "2024-09-01"

关于我

直接从鱼那里搬过来的关于页面,做了一点点自己的修改

  • 删除捐赠 楠的破烂博客还敢开捐赠?!
  • 修改 51LA 的统计数据为 Hexo 自带数据

统计数据部分

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#statistic
div
span 文章数量
span= site.posts.length
div
span 运行时间
span#runtimeshow(data-publishDate=date_xml(theme.runtimeshow.publish_date))
div
span 访客数量
span#busuanzi_value_site_uv
div
span 总访问量
span#busuanzi_value_site_pv
div
span 最近更新
span#last-push-date(data-lastPushDate=date_xml(Date.now()))

修改国内不蒜子统计平台

来自杜老师的教程

压缩静态资源

来自 空梦大佬

Todo

自己用 md 写的太丑辣,懒得动脑,直接拿 亦小封 佬的用

不过佬的瀑布流代码在我这里有点小问题,我就用我自己的屎山代码代替了))

外挂标签之外链卡片

参考洪哥的样式

做出了自己的修改

修改 [themes]\butterfly\scripts\tag\link.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
function link(args) {
args = args.join(' ').split(',');
let title = args[0];
let sitename = args[1];
let link = args[2];

let isLocalLink = link.startsWith('/');

let tipsText = isLocalLink ? "✅此为本站站点,可以放心食用~" : "❗这是个站外网站呢,不保证站点的可用性和安全性哟~";
let imgUrl = isLocalLink
? "https://tuchuang.voooe.cn/images/2024/01/29/logo_icon.png"
: "https://api.iowen.cn/favicon/" + link.replace(/^https?\:\/\//i, "") + ".png";

let targetAttr = isLocalLink ? "" : 'target="_blank"';

return `<a class="tag-Link" ${targetAttr} href="${link}">
<div class="tag-link-tips">${tipsText}</div>
<div class="tag-link-bottom">
<div class="tag-link-left" style="background-image: url(${imgUrl});"></div>
<div class="tag-link-right">
<div class="tag-link-title">${title}</div>
<div class="tag-link-sitename">${sitename}</div>
</div>
<i class="fa-solid fa-angle-right"></i>
</div>
</a>`;
}

hexo.extend.tag.register('link', link, { ends: false });

修改 [themes]\butterfly\source\css\_tags\link.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
#article-container
.tag.link
text-align center
a
&.link-card
margin 0.25rem auto
background #f6f6f6
display inline-flex
align-items center
cursor pointer
text-align center
min-width 200px
max-width 361px
color #444
border-radius 12px
text-decoration none
&:hover
box-shadow 0 4px 8px 0 rgba(0, 0, 0, 0.1)
div
&.left
width 48px
height 48px
margin 12px
overflow hidden
flex-shrink 0
position relative
i
font-size 32px
line-height 48px
margin-left 4px
img
display block
position absolute
border-radius 2px
top 50%
left 50%
transform translate(-50%, -50%)
&.right
overflow hidden
margin-right 12px
p
margin 0
&.text
font-weight bold
&.url
flex-shrink 0
color rgba(68, 68, 68, 0.65)
font-size 13px

@media screen and (max-width: 425px)
#article-container
a
&.link-card
max-width 100%

@media screen and (max-width: 375px)
#article-container
a
&.link-card
width 100%

#article-container a.link-card div.left,
#article-container a.link-card div.right
pointer-events none

[data-theme="dark"]
#article-container
a
&.link-card
filter brightness(0.7)
img
filter brightness(1)

评论样式

参考了 Ariasaka店长 的一些样式

css

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
/* 评论 */

#twikoo .tk-admin {
position: fixed !important;
right: -50%;
z-index: 999;
}

#twikoo .tk-admin.__show {
left: 100% !important;
transform: translateX(-100%);
}

.tk-input.el-textarea textarea {
min-height: 120px !important;
}

.tk-content {
border-radius: 2px 10px 10px 10px;
background: #e5e5e5;
padding: 5px 20px;
color: #000;
}

.tk-content-expand {
max-width: 90%;
}

.tk-comment .tk-submit .tk-avatar,
.tk-replies .tk-avatar {
width: 2.5rem !important;
height: 2.5rem !important;
}

.tk-comment.tk-master .tk-avatar.tk-clickable.tk-has-avatar {
margin: 0 0 0 1rem !important;
}

.tk-comment .tk-submit .tk-avatar .tk-avatar-img,
.tk-replies .tk-avatar .tk-avatar-img {
height: 2.5rem !important;
}

.tk-comment.tk-master .tk-content {
border-radius: 10px 2px 10px 10px;
}

.tk-comment.tk-master,
.tk-comment.tk-master .tk-row,
.tk-comment.tk-master .tk-extras {
flex-direction: row-reverse;
width: 100%;
}

.tk-comment.tk-master .tk-main {
display: flex;
flex-direction: column;
align-items: flex-end;
}

.twikoo .el-button--primary.is-disabled,
.twikoo .el-button--primary.is-disabled:active,
.twikoo .el-button--primary.is-disabled:focus,
.twikoo .el-button--primary.is-disabled:hover {
background: #fb85999e !important;
}

.el-button--primary {
background-color: var(--theme-color) !important;
border-color: var(--theme-color) !important;
}

.el-button--primary:focus,
.el-button--primary:hover {
background: #fb8599d9 !important;
border-color: #fb8599d9 !important;
}

.twikoo .el-input__inner:focus,
.twikoo .el-textarea__inner:focus,
.el-button--primary:focus,
.el-button--primary:hover {
border-color: #fb8599d9 !important;
}

.tk-icon.__comments,
.tk-action-icon.tk-action-icon-solid,
.tk-action-icon,
.tk-action-count {
color: var(--theme-color) !important;
}

.tk-tag-green.tk-tag-green {
background-color: var(--theme-color);
border: none;
border-radius: 5px;
color: #fff;
margin: 0 10px;
}

#article-container strong:not(strong:has(code)) {
background: linear-gradient(rgba(255, 51, 184, .15), rgba(255, 51, 184, .15)) no-repeat bottom / 100% 30%;
}

a.tk-ruser {
color: #000;
margin: 0 5px;
font-weight: 900;
font-size: 15px;
}

.tk-collapse-wrap,
.tk-expand-wrap {
box-shadow: 0 0 5px;
margin-top: 10px;
border-radius: 10px;
overflow: hidden;
transition: .3s;
}

.tk-collapse-wrap:hover,
.tk-expand-wrap:hover {
border-color: var(--theme-color);
}

.tk-expand {
font-size: 12px;
}

.tk-expand-wrap .tk-expand:hover {
background-color: var(--theme-color);
color: #fff;
}

/* 设置文字内容 :nth-child(1)的作用是选择第几个 */
.el-input.el-input--small.el-input-group.el-input-group--prepend:nth-child(1):before {
content: '输入您的昵称🍟';
}

.el-input.el-input--small.el-input-group.el-input-group--prepend:nth-child(2):before {
content: '收到回复将会发送到您的邮箱,使用QQ邮箱自动获取头像📧';
}

.el-input.el-input--small.el-input-group.el-input-group--prepend:nth-child(3):before {
content: '可以通过昵称访问您的网站🔗';
}

/* 当用户点击输入框时显示 */
.el-input.el-input--small.el-input-group.el-input-group--prepend:focus-within::before,
.el-input.el-input--small.el-input-group.el-input-group--prepend:focus-within::after {
display: block;
}

/* 主内容区 */
.el-input.el-input--small.el-input-group.el-input-group--prepend::before {
/* 先隐藏起来 */
display: none;
/* 绝对定位 */
position: absolute;
/* 向上移动60像素 */
top: -60px;
/* 文字强制不换行,防止left:50%导致的文字换行 */
white-space: nowrap;
/* 圆角 */
border-radius: 10px;
/* 距离左边50% */
left: 50%;
/* 然后再向左边挪动自身的一半,即可实现居中 */
transform: translate(-50%);
/* 填充 */
padding: 14px 18px;
background: #444;
color: #fff;
}

/* 小角标 */
.el-input.el-input--small.el-input-group.el-input-group--prepend::after {
display: none;
content: '';
position: absolute;
/* 内容大小(宽高)为0且边框大小不为0的情况下,每一条边(4个边)都是一个三角形,组成一个正方形。
我们先将所有边框透明,再给其中的一条边添加颜色就可以实现小三角图标 */
border: 12px solid transparent;
border-top-color: #444;
left: 50%;
transform: translate(-50%, -48px);
}

/* 评论 end */