Icarus主题魔改

Icarus主题布局、夜间模式设置

Icarus布局加宽

两栏布局

由于原版的三栏模式对文章而言,中间栏实在拥挤了,一行没几个字就换行,加上图片显示太小。可按照一下步骤将二三栏宽度合并。

layout/layout.jsx

1
2
3
4
5
6
'is-12': columnCount === 1,
// 修改宽度为 8 9 9
// 'is-8-tablet is-8-desktop is-8-widescreen': columnCount === 2,
'is-8-tablet is-9-desktop is-9-widescreen': columnCount === 2,
'is-8-tablet is-8-desktop is-6-widescreen': columnCount === 3

include/style/responsive.styl

1
2
3
4
5
6
7
8
9
10
11
12
13
14
/* 修改对应的布局 */
+widescreen()
.is-1-column .container, .is-2-column .container
/* max-width: $desktop - 2 * $gap */
/* width: $desktop - 2 * $gap */
max-width: $widescreen - 2 * $gap
width: $widescreen - 2 * $gap

+fullhd()
.is-2-column .container
/* max-width: $widescreen - 2 * $gap */
/* width: $widescreen - 2 * $gap */
max-width: $fullhd - 2 * $gap
width: $fullhd - 2 * $gap

layout/common/widgets.jsx

1
2
3
4
5
6
7
8
9
function getColumnSizeClass(columnCount) {
switch (columnCount) {
case 2:
// 修改为 4 3 3
// return 'is-4-tablet is-4-desktop is-4-widescreen';
return 'is-4-tablet is-3-desktop is-3-widescreen';
case 3:
return 'is-4-tablet is-4-desktop is-3-widescreen';
}

固定目录在左侧

在 icarus 3.0 中, 类似于 toc, tag 等小部件不在默认的主题文件家中, 而是集成到了 hexo-component-inferno 这个依赖模块中. 因此想要改动这些内容的话, 需要手动地将toc.jsx 文件复制到 layout/widget/toc.jsx 中.

因为在使用时并不想简单地将左右两栏固定, 而是想要实现对于不同的卡片, 设置不同的滚动方式. 比如, 对于文章内现实的目录卡片, 设置成固定, 并进入滚动条, 代码修改的内容如下:

  • 加入了 column-left is-sticky 这两个 class
  • 设置滚动条: style="max-height: calc(100vh - 5rem); overflow-y: auto;"

layout/widget/toc.jsx

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// 第 5 行
const { tocObj: getTocObj, unescapeHTML } = require('hexo-util');
const { Component } = require('inferno');
const { cacheComponent } = require('hexo-component-inferno/lib/util/cache');

//修改render()内容
render() {
const toc = getToc(this.props.content);
if (!Object.keys(toc).length) {
return null;
}

// return <div class="card widget" id="toc">
return <div class="card widget column-left is-sticky" id="toc">
<div class="card-content">
<div class="menu" style="max-height: calc(100vh - 5rem); overflow-y: auto;">
<h3 class="menu-label">{this.props.title}</h3>
{this.renderToc(toc)}
</div>
</div>
</div>;
}

主页三栏,文章两栏

_config.icarus.yml复制一份,命名为_config.post.yml,在post中将左右组件全部设置为左侧。

主题夜间模式

效果展示

新增night.styl

icarus/source/css 目录下创建 night.sytl 文件(展开显示代码)

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
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
dark-primary-color = rgb(55, 61, 72)
dark-primary-color-hover = rgb(67, 74, 86)
dark-primary-color-active = rgb(44, 49, 58)
dark-font-color = #c0c0c0



#universe
display: none

.navbar-logo,
.footer-logo
.logo-img-dark
display: none

body.night
background: #0e1225

.night
// code highlight (https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/styles/atom-one-dark.min.css)
// navigation bar, cards
.content code
color: rgb(203,186,125)

// night icon changed to fas fa-moon-o
#night-nav #night-icon:before
content: '\f186'

.navbar-menu
background-color: inherit
.navbar-main .navbar-menu .navbar-item
&:hover,
&:focus
color: #ffffff
background-color: dark-primary-color
.navbar,
.card
background-color: rgba(40, 44, 52, 0.5)
backdrop-filter: none
-webkit-backdrop-filter: none

.card
&:hover
background-color: rgba(40, 44, 52, 0.8)

.footer
background-color: rgba(40, 44, 52, 0.5)
backdrop-filter: none
-webkit-backdrop-filter: none

&:before
background-color: rgba(40, 44, 52, 0.5)

// input

.input, .textarea
background-color: dark-primary-color-hover
border-color: dark-primary-color

// message
.message.message-immersive
background-color: #c2c2c2
.message-body
color: #222222
.message.message-immersive.is-info
background-color: #bdc3c8
.message-body
color: #004779
.message.message-immersive.is-warning
background-color: #cbc8ba
.message-body
color: #5b4b00
.message.message-immersive.is-danger
background-color: #c6babe
.message-body
color: #79000f
.message.message-immersive.is-success
background-color: #bfc7c0
.message-body
color: #1e4d1c
.message.message-immersive.is-primary
background-color: #bdc0c9
.message-body
color: #003790





// button

.button.is-primary, .button.is-light, .button.is-small
background-color: dark-primary-color
color: dark-font-color

&:hover, &.is-hovered
color: #ffffff
background-color: dark-primary-color-hover

&:active, &.is-active
color: #ffffff
background-color: dark-primary-color-active

.button.is-white,
.button.is-transparent
background-color: transparent

&:hover
background-color: dark-primary-color !important

.pagination .pagination-next,
.pagination .pagination-previous
.pagination-link:not(.is-current)
color: dark-font-color





// button

.button.is-primary, .button.is-light, .button.is-small
background-color: dark-primary-color
color: dark-font-color

&:hover, &.is-hovered
color: #ffffff
background-color: dark-primary-color-hover

&:active, &.is-active
color: #ffffff
background-color: dark-primary-color-active

.button.is-white,
.button.is-transparent
background-color: transparent

&:hover
background-color: dark-primary-color !important

.pagination .pagination-next,
.pagination .pagination-previous
.pagination-link:not(.is-current)
color: dark-font-color
background-color: dark-primary-color

a
color: dark-font-color

.pagination-link.is-current
background-color: dark-primary-color-hover
border-color: dark-primary-color-hover

// comment

.v .vwrap,
.v .vwrap .vheader .vinput
border-color: dark-primary-color

.v .vwrap .vheader .vinput:focus
border-color: dark-primary-color-hover

.v .vbtn
color: dark-font-color
background-color: dark-primary-color
border-color: dark-primary-color

&:hover
background-color: dark-primary-color-hover

&:active
background-color: dark-primary-color-active

.v .vlist .vcard .vhead .vsys
background-color: dark-primary-color

.v a:hover,
.v .vlist .vcard .vh .vmeta .vat
color: #ffffff

.v .vlist .vcard .vcontent.expand:before
background: -webkit-gradient(linear, left top, left bottom, from(rgba(37, 41, 54, 0)), to(rgba(37, 41, 54, 1)))
background: linear-gradient(180deg, rgba(37, 41, 54, 0), rgba(37, 41, 54, 1))

.v .vlist .vcard .vcontent.expand:after
background: rgba(37, 41, 54, 1)

.v .vlist .vcard .vh,
.v .vlist .vcard .vquote
border-color: dark-primary-color-hover

// font color

body,
strong,
time,
.title,
.footer,
.card,
.content h1,
.content h2,
.content h3,
.content h4,
.content h5,
.content h6,
.navbar-item,
.navbar-item.is-active,
.navbar-link,
.menu-list a,
.menu-label,
.level-item,
.input,
.textarea,
.button.is-white,
.button.is-transparent,
.article-licensing,
.v *
color: dark-font-color

.media-content,
.has-text-grey,
.link-muted
color: dark-font-color !important

a
color: rgb(82, 153, 224)

&:hover
color: #ffffff

// quote

.content blockquote,
.article-licensing
background-color: dark-primary-color
border-color: dark-primary-color-hover

.post-copyright
background-color: dark-primary-color
border-color: dark-primary-color-hover

// table

.content table thead td,
.content table thead th
color: dark-font-color

.content table td,
.content table th
border-color: dark-primary-color-hover

// break line

hr
background-color: dark-primary-color-hover

// tags and menus

article.article, article.media

.title:hover a
// override anotherr !important
color: dark-font-color !important

.tag:not(body)
color: dark-font-color
background-color: dark-primary-color

.tag.is-grey
background-color: dark-primary-color-hover

.menu-list a:hover
background-color: dark-primary-color

.menu-list a.is-active
background-color: dark-primary-color-hover

.menu-list li ul
border-color: dark-primary-color

// time line

.timeline .media:last-child:after
background-color: rgb(37, 41, 54)

.timeline
border-color: dark-primary-color-hover

.timeline .media:before
background-color: dark-primary-color-hover

// search box

.searchbox
.searchbox-container,
.searchbox-header,
.searchbox-header .searchbox-input,
.searchbox-header .searchbox-close,
.searchbox-body,
.searchbox-result-section,
.searchbox-result-item
color: dark-font-color
background-color: dark-primary-color
border-color: dark-primary-color-hover

.searchbox-container .searchbox-result-section .searchbox-result-item:hover,
.searchbox-container .searchbox-result-section .searchbox-result-item.active,
.searchbox-container .searchbox-header .searchbox-close:hover
color: #ffffff
background-color: dark-primary-color-hover

// selection

::selection
color: #ffffff
background-color: rgba(52, 109, 167, 0.8)

::-moz-selection
color: #ffffff
background-color: rgba(52, 109, 167, 0.8)

input:-webkit-autofill
-webkit-text-fill-color: dark-font-color !important
box-shadow: 0 0 0px 1000px dark-primary-color inset

.hljs {
display: block;
overflow-x: auto;

padding: 0.5em;
color: #abb2bf;
background: #282c34
}

.hljs-comment, .hljs-quote {
color: #5c6370;
font-style: italic
}

.hljs-doctag, .hljs-keyword, .hljs-formula {
color: #c678dd
}

.hljs-section, .hljs-name, .hljs-selector-tag, .hljs-deletion, .hljs-subst {
color: #e06c75
}

.hljs-literal {
color: #56b6c2
}

.hljs-string, .hljs-regexp, .hljs-addition, .hljs-attribute, .hljs-meta-string {
color: #98c379
}

.hljs-built_in, .hljs-class .hljs-title {
color: #e6c07b
}

.hljs-attr, .hljs-variable, .hljs-template-variable, .hljs-type, .hljs-selector-class, .hljs-selector-attr, .hljs-selector-pseudo, .hljs-number {
color: #d19a66
}

.hljs-symbol, .hljs-bullet, .hljs-link, .hljs-meta, .hljs-selector-id, .hljs-title {
color: #61aeee
}

.hljs-emphasis {
font-style: italic
}

.hljs-strong {
font-weight: bold
}

.hljs-link {
text-decoration: underline
}

修改 default.styl 文件

icarus/source/css/default.styl末尾新增@import 'night'

1
2
@import 'style'
@import 'night'

新增 night.js 文件

icarus/source/js 目录下创建 night.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
(function () {
/**

* Icarus 夜间模式 by iMaeGoo
* https://www.imaegoo.com/
*/

var isNight = localStorage.getItem('night');
var nightNav;

function applyNight(value) {
if (value.toString() === 'true') {
document.body.classList.remove('light');
document.body.classList.add('night');
} else {
document.body.classList.remove('night');
document.body.classList.add('light');
}
}

function findNightNav() {
nightNav = document.getElementById('night-nav');
if (!nightNav) {
setTimeout(findNightNav, 100);
} else {
nightNav.addEventListener('click', switchNight);
}
}

function switchNight() {
isNight = isNight ? isNight.toString() !== 'true' : true;
applyNight(isNight);
localStorage.setItem('night', isNight);
}

findNightNav();
isNight && applyNight(isNight);
}());

修改 scripts.jsx

icarus/layout/common/scripts.jsx 中的 return <Fragment></Fragment>里新增

1
<script src={url_for('/js/night.js')} defer={true}></script>

修改 navbar.jsx

icarus/layout/common/navbar.jsx中的 <div class="navbar-end">下新增

1
2
3
<a class="navbar-item night" id="night-nav" title="Night Mode" href="javascript:;">
<i class="fas fa-lightbulb" id="night-icon"></i>
</a>

固定导航栏

不得不说,导航栏上还是有很多功能随时需要使用的,例如切换模式、搜索等等。Icarus模板的导航栏会随着文章滚动消失。

我想我需要一个会跟随页面的导航栏,它得是贴心的——当你需要它的时候,比如回首页、切换浅色/深色模式、搜索,它就在那里;它还得是不恼人的——它不应该遮挡太多,影响到正文或视觉平衡,它得是灵巧的,且更好的适配响应式设计。

缩短高度

icarus\include\style\navbar.styl添加一个 position 为 fixed 的样式。这么做的同时还需要调整 width 为 100% 并将下一个元素 section 下移:

1
2
3
4
5
6
7
.navbar-main
position: fixed !important
width: 100% !important
top: 0px

.section
margin-top: 45px

通过修改 navbar-item 的内外边距来缩窄高度:

1
2
3
.navbar-item
margin: 4px !important
padding: 8.5px !important

再将 navbar-menu 背景设为透明,这样小尺寸屏幕下也能正常显示:

1
2
.navbar-main .navbar-menu
background-color: transparent

文章置顶

默认的文章排列顺序是根据文章的记录时间来的,但是有些需要置顶的内容,通过修改排列评判标准可以实现。

打开博客目录,打开博客目录下的“node_modules\hexo-generator-index\lib”目录,其中的“generator.js”文件就是我们所要修改的文件。

实现该功能需要在const posts = locals.posts.sort(config.index_generator.order_by);
代码下添加一下内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
posts.data = posts.data.sort(function(a, b) {
if(a.top && b.top) { // 两篇文章都有top,top大的在前
if(a.top == b.top)
return b.date - a.date; // 若top值一样,最新的文章在前面
else
return b.top - a.top; // top大的在前面
}
else if(a.top && !b.top) { // 以下是只有一篇文章top有定义,那么将有top的排在前面
return -1;
}
else if(!a.top && b.top) {
return 1;
}
else return b.date - a.date; //都没有top标签,最新的文章在前面
});

在使用过程中,对文章添加top属性即可,top越大越靠前。

文章发表更新显示具体日期

直接使用日期,不许要计算距离现在的天数

source/js/main.js

1
2
3
4
5
-    if (typeof moment === 'function') {
- $('.article-meta time').each(function() {
- $(this).text(moment($(this).attr('datetime')).fromNow());
- });
- }

给卡片增加浮动阴影效果&圆角

include/style/card.styl

1
2
3
4
5
.card
overflow: visible
border-radius: $card-radius
+ &:hover
+ box-shadow: 0 6px 15px rgba(0,0,0,0.15), 0 0 1px rgba(0,0,0,0.1)

修改\themes\icarus\include\style\base.styl$card-radius的值为15px

引入busuanzi记录主页访客与阅读数

官网:http://ibruce.info/2015/04/04/busuanzi/

_config.icarus.yml_config.post.yml中配置

1
2
3
4
5
6
7
8
9
10
plugins: 
busuanzi: true

busuanzi:
enable: true
site_uv: true
site_pv: true
page_pv: true
site_uv_offset: 0
site_pv_offset: 0

icarus主题在启用busuanzi插件之后,只会显示网站的UV数据,没有显示PV,自己添加一个

node_modules\hexo-theme-icarus\layout\common\footer.jsx

1
2
3
-visitorCounterTitle: _p('plugin.visitor_count', '<span id="busuanzi_value_site_uv">0</span>'))
+visitorCounterTitle: _p('plugin.visitor_count', '<span id="busuanzi_value_site_uv">0</span>') + _p('plugin.visit_count', ', <span id="busuanzi_value_site_pv">0</span>')

引入计时功能

网上找到的都是ejs的写法,其实jsx的写法也很简单,只要把js的代码嵌入jsx中就可以了。

themes\icarus\layout\common\footer.jsx中找到要添加运行时间的位置,比我在最下方加入一个计时模块,代码如下:

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
 <p class="is-size-7">
<span dangerouslySetInnerHTML={{ __html: `&copy; ${siteYear} ${author || siteTitle}` }}></span>
&nbsp;&nbsp;
当一个人的征途是星辰大海时,长路漫漫间,虽寂静,但永不孤独……
&nbsp;&nbsp;
{showVisitorCounter ? <br /> : null}
{showVisitorCounter ? <span id="busuanzi_container_site_uv"
dangerouslySetInnerHTML={{ __html: visitorCounterTitle }}></span> : null}
<br></br>
+ <span id="timeDate">载入天数...</span><span id="times">载入时分秒...</span>
+ <script dangerouslySetInnerHTML={{
+ __html: `
+ var now = new Date();
+ function createtime() {
+ var grt= new Date("2/27/2020 16:23:00");//此处修改你的建站时间或者网站上线时间
+ now.setTime(now.getTime()+250);
+ days = (now - grt ) / 1000 / 60 / 60 / 24; dnum = Math.floor(days);
+ hours = (now - grt ) / 1000 / 60 / 60 - (24 * dnum); hnum = Math.floor(hours);
+ if(String(hnum).length ==1 ){hnum = "0" + hnum;} minutes = (now - grt ) / 1000 /60 - (24 * 60 * dnum) - (60 * hnum);
+ mnum = Math.floor(minutes); if(String(mnum).length ==1 ){mnum = "0" + mnum;}
+ seconds = (now - grt ) / 1000 - (24 * 60 * 60 * dnum) - (60 * 60 * hnum) - (60 * mnum);
+ snum = Math.round(seconds); if(String(snum).length ==1 ){snum = "0" + snum;}
+ document.getElementById("timeDate").innerHTML = "| 本站已运行 "+dnum+" 天 ";
+ document.getElementById("times").innerHTML = hnum + " 小时 " + mnum + " 分 " + snum + " 秒";
+ }
+ setInterval("createtime()",250);
+ `,
+ }}
+ />
</p>

评论