NexT 8.20 Update Log

Update Log of my blog. This time, there weren't many adjustments — just a simple refresh of the version number and a slight enhancement of the reading experience.

Upgrade Content

  • Upgraded Hexo version: 6.3.0 → 7.3.0
  • Upgraded NexT version: 8.18.2 → 8.20.0
  • Changed website icon
  • Changed fonts
  • Automatically switched background image based on browser theme
  • Adjusted pagination settings for archives, directory, and tags
  • Redirected some URLs
  • Removed click effects on mobile
  • Added image carousel functionality

NPM Package Upgrade

During this upgrade, I discovered a very useful package called npm-check-updates that can check which packages can be upgraded.

Installation command:

1
npm i -g npm-check-updates

To check for upgradable packages:

1
ncu -u

My output was as follows:

1
2
3
4
5
6
7
8
9
hexo                   ^6.3.0  →   ^7.3.0
hexo-blog-encrypt ^3.1.6 → ^3.1.9
hexo-deployer-git ^3.0.0 → ^4.0.0
hexo-generator-index ^3.0.0 → ^4.0.0
hexo-hide-posts ^0.2.0 → ^0.4.3
hexo-renderer-marked ^6.0.0 → ^6.3.0
hexo-renderer-stylus ^2.1.0 → ^3.0.1
hexo-theme-next ^8.18.2 → ^8.20.0
hexo-word-counter ^0.1.0 → ^0.2.0

To upgrade all components directly:

1
sudo npm install

Update Configuration File

It’s been years since I updated the NexT configuration file. While it doesn’t really affect usage, it triggers my OCD a bit.

  1. Rename ./_config.next.yml to ./_old_next_config.yml.
  2. Copy ./node_modules/hexo-theme-next/_config.yml to the blog root directory and rename it to _config.next.yml.
  3. Open both files in VSCode, hold Shift to select both, right-click the file tabs, and choose “Compare Selected”. Then copy and paste the necessary sections.

Change Website Icon

I’m simply tired of the current icon and want a new one.

  1. Open Photoshop (PS) and sketch a random design, then export it with a higher resolution.
  2. Upload the image to Favicon Generator to generate all required icons.
  3. Place the generated images in the ./source/images/ directory, replacing the old ones.
  4. Be sure to update android_manifest in ./_config.next.yml to /images/site.webmanifest since the auto-generated filenames might differ.

Change Website Font

I’ve changed the website’s global font to the Noto Sans, while the blog content uses the more readable Noto Serif. You just need to tweak a few lines in ./_config.next.yml.

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
# Font options:
# `external: true` will load this font family from `host` above.
# `family: Times New Roman`. Without any quotes.
# `size: x.x`. Use `em` as unit. Default: 1 (16px)

# Global font settings used for all elements inside <body>.
global:
external: true
family: Noto Sans
size:

# Font settings for site title (.site-title).
title:
external: true
family:
size:

# Font settings for headlines (<h1> to <h6>).
headings:
external: true
family:
size:

# Font settings for posts (.post-body).
posts:
external: true
family: Noto Serif

# Font settings for <code> and code blocks.
codes:
external: true
family: Fira Code, Noto Serif SC

Background Image Adjustments

Same reason as before — I’m tired of the old look. Here’s what I’ve changed:

  1. The original background image was way too bright, especially in dark mode. It felt out of place, and honestly, it was blinding during those late-night sessions. So, I went ahead and set different background images for light and dark modes.
  2. No more semi-transparent background images. This should make the text way easier to read.
  3. Oh, and I scrapped the gradient background for mobile devices.

Just add the following styles in D:\Project\Blog\cn_Siriusq\source\_data\styles.styl:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
// Background Image
/* Desktop Background */
@media screen and (min-width: 768px) {
/* Light Background */
@media (prefers-color-scheme: light) {
body {
background-image: url('https://s2.loli.net/2024/09/11/ZyWBVcA5F2bodgw.webp');
background-repeat: no-repeat;
background-attachment: fixed;
background-size: cover;
background-position: center;
-webkit-background-size: cover;
-o-background-size: cover;
-moz-background-size: cover;
-ms-background-size: cover;
footer > div > div {
color:#ffffff;//Bottom Text Colour
}
}
}

/* Dark Background */
@media (prefers-color-scheme: dark) {
body {
background-image: url('https://s2.loli.net/2024/09/11/YHxg9RsTUDKvBPr.webp');
background-repeat: no-repeat;
background-attachment: fixed;
background-size: cover;
background-position: center;
-webkit-background-size: cover;
-o-background-size: cover;
-moz-background-size: cover;
-ms-background-size: cover;
footer > div > div {
color:#dddddd;//Bottom Text Colour
}
}
}
}

/* Do not show background image on mobile */
@media screen and (max-width: 767px) {
body {
background-image: none;
}
}

Pagination Adjustments

When animations are enabled, the NexT theme uses a waterfall-like effect to gradually reveal elements on the page, including blog post titles in the archives. This creates a bit of a problem: if there are too many titles on one page, the ones at the bottom won’t show up until the animation finishes. I originally had it set to display 50 titles per page, but waiting a few seconds for the animation to complete is just inconvenient. So, I’ve now changed it to display 20 titles per page.

Adjust the following settings in Hexo’s config file _config.yml:

1
2
3
4
5
6
7
8
9
10
11
# Archive Pagination
archive_generator:
per_page: 20

# Tag Pagination
tag_generator:
per_page: 20

# Category Pagination
category_generator:
per_page: 20

URL Redirection

Currently, the blog URLs are generated based on the filenames of the markdown files. There are a few filenames I’ve been wanting to change for a while, but renaming them directly would result in broken links. To solve this, I installed the hexo-generator-alias plugin.

Installation command:

1
npm install hexo-generator-alias --save

How to use it:

  1. Rename the relevant markdown files.
  2. Open the file and add alias: [relative path of the old markdown filename].html in the front-matter section.

Example:
My old filename was Win10-Reinstall-Guide.md, I’d rename it to Windows-Reinstall-Guide.md, then open the file and modify it like this:

1
2
3
4
5
6
7
8
---
title: Windows Reinstall Guide
date: 2020-07-13 12:28:34
lang: zh-CN
tags: [Windows, Office, Reinstall]
categories: Windows
+ alias: Win10-Reinstall-Guide.html
---

Remove Click Effects on Mobile

The current click effect is a bit laggy on mobile devices, so I’m removing it for now. Maybe in a few years, when mobile performance improves, I’ll bring it back. To do this, go to the CursorSpecialEffects class in the existing ./source/js/firework.js file, and add a conditional statement in the init method: if (window.innerWidth > 768){}. Then, move the original content inside this block.

Complete Guide

./source/js/firework.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
class Circle {
constructor({ origin, speed, color, angle, context }) {
this.origin = origin
this.position = { ...this.origin }
this.color = color
this.speed = speed
this.angle = angle
this.context = context
this.renderCount = 0
}

draw() {
this.context.fillStyle = this.color
this.context.beginPath()
this.context.arc(this.position.x, this.position.y, 2, 0, Math.PI * 2)
this.context.fill()
}

move() {
this.position.x = (Math.sin(this.angle) * this.speed) + this.position.x
this.position.y = (Math.cos(this.angle) * this.speed) + this.position.y + (this.renderCount * 0.3)
this.renderCount++
}
}

class Boom {
constructor ({ origin, context, circleCount = 16, area }) {
this.origin = origin
this.context = context
this.circleCount = circleCount
this.area = area
this.stop = false
this.circles = []
}

randomArray(range) {
const length = range.length
const randomIndex = Math.floor(length * Math.random())
return range[randomIndex]
}

randomColor() {
const range = ['8', '9', 'A', 'B', 'C', 'D', 'E', 'F']
return '#' + this.randomArray(range) + this.randomArray(range) + this.randomArray(range) + this.randomArray(range) + this.randomArray(range) + this.randomArray(range)
}

randomRange(start, end) {
return (end - start) * Math.random() + start
}

init() {
for(let i = 0; i < this.circleCount; i++) {
const circle = new Circle({
context: this.context,
origin: this.origin,
color: this.randomColor(),
angle: this.randomRange(Math.PI - 1, Math.PI + 1),
speed: this.randomRange(1, 6)
})
this.circles.push(circle)
}
}

move() {
this.circles.forEach((circle, index) => {
if (circle.position.x > this.area.width || circle.position.y > this.area.height) {
return this.circles.splice(index, 1)
}
circle.move()
})
if (this.circles.length == 0) {
this.stop = true
}
}

draw() {
this.circles.forEach(circle => circle.draw())
}
}

class CursorSpecialEffects {
constructor() {
this.computerCanvas = document.createElement('canvas')
this.renderCanvas = document.createElement('canvas')

this.computerContext = this.computerCanvas.getContext('2d')
this.renderContext = this.renderCanvas.getContext('2d')

this.globalWidth = window.innerWidth
this.globalHeight = window.innerHeight

this.booms = []
this.running = false
}

handleMouseDown(e) {
const boom = new Boom({
origin: { x: e.clientX, y: e.clientY },
context: this.computerContext,
area: {
width: this.globalWidth,
height: this.globalHeight
}
})
boom.init()
this.booms.push(boom)
this.running || this.run()
}

handlePageHide() {
this.booms = []
this.running = false
}

init() {
// Only works on the desktop, determines if the screen width is greater than 768px
if (window.innerWidth > 768) {
const style = this.renderCanvas.style
style.position = 'fixed'
style.top = style.left = 0
style.zIndex = '999999999999999999999999999999999999999999'
style.pointerEvents = 'none'

style.width = this.renderCanvas.width = this.computerCanvas.width = this.globalWidth
style.height = this.renderCanvas.height = this.computerCanvas.height = this.globalHeight

document.body.append(this.renderCanvas)

window.addEventListener('mousedown', this.handleMouseDown.bind(this))
window.addEventListener('pagehide', this.handlePageHide.bind(this))
}
}

run() {
this.running = true
if (this.booms.length == 0) {
return this.running = false
}

requestAnimationFrame(this.run.bind(this))

this.computerContext.clearRect(0, 0, this.globalWidth, this.globalHeight)
this.renderContext.clearRect(0, 0, this.globalWidth, this.globalHeight)

this.booms.forEach((boom, index) => {
if (boom.stop) {
return this.booms.splice(index, 1)
}
boom.move()
boom.draw()
})
this.renderContext.drawImage(this.computerCanvas, 0, 0, this.globalWidth, this.globalHeight)
}
}

const cursorSpecialEffects = new CursorSpecialEffects()
cursorSpecialEffects.init()

Then import it in ./source/_data/body-end.njk:

1
2
{# Click Effect #}
<script async src="/js/fireworks.js"></script>

Add Image Carousel Functionality

Wrote my own plugin based on Splide: hexo-splide-carousel.