Hexo-icarus主题黑夜模式以及背景

Hexo-icarus主题黑夜模式以及背景

对主题增改代码实现夜间模式,以及模式切换。夜间模式增加使用canvas绘图的背景。

对更新时需要备份的代码文件作记录(大改过的都要)。

因为我不会写前端(我不会写代码,我是弱智),写得很烂(这玩意标准怎么乱七八糟的),东拼西凑 Ctrl+CV 整好了,为了避免下次更新把这一块更挂掉,所以都得记录下来。

修改

icarus 也可能是 node_modules/hexo-theme-icarus 文件夹

  • icarus/source/js 下增加 night.js

  • icarus/source/css 下增加 night.styl

  • icarus/source/css 下修改 default.styl ,末尾新增一行 @import 'night'

  • icarus/layout/common 下修改 scripts.jsx<Fragment> 标签间添加 <script> 标签索引

1
<script src={url_for('/js/night.js')} defer={true}></script>
  • icarus/layout/common 下修改 navbar.jsxfooter.jsx

大改的见下代码增改各分段的代码。

代码增改

night.js

night.js >folded
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

(function() {
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);
}());

night.styl

night.styl >folded
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

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

night()
background: #0e1225

// code highlight (https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/styles/atom-one-dark.min.css)
.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}

.content code
color: rgb(203,186,125)

// night icon changed to fas fa-sun
#night-nav #night-icon:before
content: '\f185'

// global background
#universe
background: radial-gradient(1600px at 70% 120%, #212750 10%, #020409 100%)
display: block
position: fixed
margin: 0
padding: 0
border: 0
outline: 0
left: 0
top: 0
width: 100%
height: 100%
pointer-events: none

// global brightness
img, video, iframe, .waifu, .donate
filter: brightness(0.8)
-webkit-filter: brightness(0.8)

// logo
.navbar-logo,
.footer-logo
.logo-img
display: none
.logo-img-dark
display: inline-block

// navigation bar, cards
.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
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

// 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
.v code,
.v pre
background-color: transparent

// 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
.timeline a,
[data-type="recent-posts"] a
color: dark-font-color
&:hover
color: #ffffff

// quote
.content blockquote,
.article-licensing
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 a
background-image: linear-gradient(transparent calc(100% - 1px), dark-font-color 1px)
.title:hover a
// override anotherr !important
color: dark-font-color !important
.tag:not(body)
color: dark-font-color
background-color: dark-primary-color
.widget .tags .tag:first-child,
.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

// twikoo
.twikoo
pre
background-color: dark-primary-color
code
color: rgb(203,186,125)
background-color: dark-primary-color

body.night
night()

@media (prefers-color-scheme: dark)
body:not(.light)
night()

navbar.jsxfooter.jsx 的修改差不多

添加logo的两种模式,主题配置处也要相应改变为logo: logo.lightlogo.dark 两个分项

  • render(){const} 下将 logoUrl 改为 logoLightUrllogoDarkUrl

  • let navbarLogo ='' 的第一个 else 添加

    1
    2
    3
    4
    navbarLogo = [
    <img class="logo-img" src={logoLightUrl} alt={siteTitle} height="28" />,
    <img class="logo-img-dark" src={logoDarkUrl} alt={siteTitle} height="28" />
    ];
  • return 标签内,{showtoc} 前添加黑夜切换图标的链接,切回白天的图标在 night.styl 里设置,图标都是用的 fontawesome-icon-免费图标。

    1
    2
    3
    <a class="navbar-item night" id="night-nav" title="Night Mode" href="javascript:;">
    <i class="fas fa-moon" id="night-icon"></i>
    </a>
  • module.exports 添加

    1
    2
    const logoLight = logo instanceof String ? logo : logo.light
    const logoDark = logo instanceof String ? logo : logo.dark
  • return 修改 logoUrl

    1
    2
    logoLightUrl: url_for(logoLight),
    logoDarkUrl: url_for(logoDark),

添加夜空流星背景

  • icarus/source/js 下增加 universe.js
universe.js >folded
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

/**
* created by lvfan
* 2018-09-04
*/


(function drawBg() {
window.requestAnimationFrame = window.requestAnimationFrame || window.mozRequestAnimationFrame ||
window.webkitRequestAnimationFrame || window.msRequestAnimationFrame;
// const
var starDensity = 0.216;
var speedCoeff = 0.05;
var canva = document.getElementById('universe');

// let
var width;
var height;
var starCount;
/* no-unused-vars */
// var circleRadius;
// var circleCenter;
var first = true;
var giantColor = '180,184,240';
var starColor = '226,225,142';
var cometColor = '226,225,224';
var stars = [];
var universe;

windowResizeHandler();
window.addEventListener('resize', windowResizeHandler, false);

function windowResizeHandler() {
width = window.innerWidth;
height = window.innerHeight;
starCount = width * starDensity;
// circleRadius = (width > height ? height / 2 : width / 2);
// circleCenter = {
// x: width / 2,
// y: height / 2
// };
canva.setAttribute('width', width);
canva.setAttribute('height', height);
}

createUniverse();

function createUniverse() {
universe = canva.getContext('2d');
for (var i = 0; i < starCount; i++) {
stars[i] = new Star();
stars[i].reset();
}
draw();
}

function draw() {
universe.clearRect(0, 0, width, height);
var starsLength = stars.length;
for (var i = 0; i < starsLength; i++) {
var star = stars[i];
star.move();
star.fadeIn();
star.fadeOut();
star.draw();
}
}

function Star() {
this.reset = function () {
this.giant = getProbability(3);
this.comet = this.giant || first ? false : getProbability(10);
this.x = getRandInterval(0, width - 10);
this.y = getRandInterval(0, height);
this.r = getRandInterval(1.1, 2.6);
this.dx = getRandInterval(speedCoeff, 6 * speedCoeff) + (this.comet + 1 - 1) * speedCoeff * getRandInterval(50, 120) + speedCoeff * 2;
this.dy = -getRandInterval(speedCoeff, 6 * speedCoeff) - (this.comet + 1 - 1) * speedCoeff * getRandInterval(50, 120);
this.fadingOut = null;
this.fadingIn = true;
this.opacity = 0;
this.opacityTresh = getRandInterval(0.2, 1 - (this.comet + 1 - 1) * 0.4);
this.do = getRandInterval(0.0005, 0.002) + (this.comet + 1 - 1) * 0.001;
};
this.fadeIn = function () {
if (this.fadingIn) {
this.fadingIn = !(this.opacity > this.opacityTresh);
this.opacity += this.do;
}
};
this.fadeOut = function () {
if (this.fadingOut) {
this.fadingOut = !(this.opacity < 0);
this.opacity -= this.do / 2;
if (this.x > width || this.y < 0) {
this.fadingOut = false;
this.reset();
}
}
};
this.draw = function () {
universe.beginPath();
if (this.giant) {
universe.fillStyle = 'rgba(' + giantColor + ',' + this.opacity + ')';
universe.arc(this.x, this.y, 2, 0, 2 * Math.PI, false);
} else if (this.comet) {
universe.fillStyle = 'rgba(' + cometColor + ',' + this.opacity + ')';
universe.arc(this.x, this.y, 1.5, 0, 2 * Math.PI, false);
// comet tail
for (var i = 0; i < 30; i++) {
universe.fillStyle = 'rgba(' + cometColor + ',' + (this.opacity - (this.opacity / 20) * i) + ')';
universe.rect(this.x - this.dx / 4 * i, this.y - this.dy / 4 * i - 2, 2, 2);
universe.fill();
}
} else {
universe.fillStyle = 'rgba(' + starColor + ',' + this.opacity + ')';
universe.rect(this.x, this.y, this.r, this.r);
}
universe.closePath();
universe.fill();
};
this.move = function () {
this.x += this.dx;
this.y += this.dy;
if (this.fadingOut === false) {
this.reset();
}
if (this.x > width - (width / 4) || this.y < 0) {
this.fadingOut = true;
}
};
(function () {
setTimeout(function () {
first = false;
}, 50);
})();
}

function getProbability(percents) {
return ((Math.floor(Math.random() * 1000) + 1) < percents * 10);
}

function getRandInterval(min, max) {
return (Math.random() * (max - min) + min);
}

/* ---------------------------------
* www.imaegoo.com
* NO DRAW IN LIGHT MODE
* --------------------------------- */
(function imaegoo () {
if (document.body.classList.contains('night')) {
draw();
}
window.requestAnimationFrame(imaegoo);
})();
}());

  • 修改 layout/layout.jsx ,添加canvas 和星空绘图的script 路径
1
2
3
4
5
6
7
8
<body class={}>
<script ......></script>
<canvas id="universe"></canvas>
...
...
...
<script type="text/javascript" src="/js/universe.js"></script>
</body>

添加日间模式背景

方案有几种,我选最懒的改最少代码的。由于是日间模式的背景图片,而 navbarfooter 的透明度不是100%(懒得改了),所以背景尽量是上下白色的比较合适,同时不要太大,影响加载,随便挑一张。

  • 图片塞进 icarus\theme\source\img 里。

  • 修改 icarus\source\css icarus\include\style\base.style 反正 body 的样式在哪就修改哪里。

    1
    2
    3
    4
    5
    body
    /*添加下列代码*/
    background: url(../img/mount.jpg) no-repeat
    background-attachment: fixed
    background-size: cover
  • 随便写一个不包括上级目录的路径,发现返回 404 not found /css/path/background.jpg ,说明索引目录在 icarus\source\css ,照着写相对路径即可。

  • background的属性主要要写好

    • url 图片路径(网络路径也可以,API也可以),
    • attachment 是否滚动:fixed 不滚动,scoll 滚动,
    • size 图像的大小:原始尺寸 auto ,覆盖容器 cover ,拉伸以显示全图 contain 等,
    • 如果图片够大,什么 positionclip 都可以不管了,适配需要的话再查,添加即可。

备份列表

但我好像已经都 gitgithub 的私有仓库上了。

  • icarus\source\js\night.js
  • icarus\source\css\night.styl
  • icarus\layout\common\navbar.jsx
  • icarus\layout\common\footer.jsx
  • icarus\source\js\universe.js
  • icarus\theme\source\img

参考

cdnjs-开源前端库文件:https://cdnjs.com/

highlight.js-代码块样式:https://highlightjs.org/

fontawesome-icon-免费图标:https://fontawesome.com/icons

icarus夜间主题配置:http://blog.sbx0.cn/2020/04/07/icarus-3-night-mode/

icarus 4 配置夜间模式:https://blog.asahih.com/hexo-icarus-night-mode/

support night dark mode:https://github.com/ppoffice/hexo-theme-icarus/issues/564

hexo-theme-icarus 3 食用经验分享:https://www.imaegoo.com/2020/icarus-3-guide/

如何给 Icarus 增加夜间模式:https://www.imaegoo.com/2019/icarus-night-mode-2/

icarus-一个hexo主题美化过程:https://purplezi.gitee.io/2021/01/15/icarus/

icarus-github-issues主题背景 #612:https://github.com/ppoffice/hexo-theme-icarus/issues/612

W3Schools-background:https://www.w3schools.com/css/css_background.asp

W3Schools-background-properties:https://www.w3schools.com/cssref/css3_pr_background.asp

作者

ivy

发布于

2021-09-15

更新于

2023-03-25

许可协议

CC BY-NC-SA 4.0

评论