hexo-theme-particlex 2.5.7 → 2.5.9
Sign up to get free protection for your applications and to get access to all the features.
- package/README.md +282 -276
- package/_config.yml +4 -6
- package/layout/card.ejs +1 -1
- package/layout/comment.ejs +1 -1
- package/layout/index.ejs +7 -7
- package/layout/layout.ejs +14 -23
- package/layout/menu.ejs +4 -4
- package/layout/post.ejs +6 -13
- package/package.json +2 -2
- package/source/css/main.css +13 -17
- package/source/js/lib/crypto.js +18 -27
- package/source/js/lib/highlight.js +17 -12
- package/source/js/lib/home.js +5 -6
- package/source/js/lib/preview.js +4 -5
- package/source/js/main.js +14 -13
package/README.md
CHANGED
@@ -8,15 +8,15 @@
|
|
8
8
|
|
9
9
|
> 目前有 Full、Night 和 Maiden **两个**主题样式
|
10
10
|
|
11
|
-
虽然更改后只有一种了,如果你想改颜色就在 `
|
11
|
+
虽然更改后只有一种了,如果你想改颜色就在 `main.css` 里替换吧
|
12
12
|
|
13
|
-
|
13
|
+
# 1. 演示
|
14
14
|
|
15
15
|
- [GitHub Pages](https://argvchs.github.io)
|
16
16
|
- [Netlify](https://argvchs.netlify.app)
|
17
17
|
- [Vercel](https://argvchs.vercel.app)
|
18
18
|
|
19
|
-
|
19
|
+
# 2. 安装
|
20
20
|
|
21
21
|
```bash
|
22
22
|
cd themes
|
@@ -29,319 +29,325 @@ git clone https://github.com/argvchs/hexo-theme-particlex.git particlex --depth=
|
|
29
29
|
theme: particlex
|
30
30
|
```
|
31
31
|
|
32
|
-
|
32
|
+
## 2.1. 关闭自带代码高亮
|
33
33
|
|
34
|
-
|
34
|
+
Hexo 有自带的代码高亮,但是和 ParticleX 的不兼容
|
35
35
|
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
36
|
+
```yaml
|
37
|
+
highlight:
|
38
|
+
enable: false
|
39
|
+
prismjs:
|
40
|
+
enable: false
|
41
|
+
```
|
42
42
|
|
43
|
-
|
43
|
+
如果使用 Pandoc 还需要设置一下
|
44
44
|
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
45
|
+
```yaml
|
46
|
+
pandoc:
|
47
|
+
extra:
|
48
|
+
- no-highlight:
|
49
|
+
```
|
50
50
|
|
51
|
-
|
51
|
+
## 2.2. 禁用年度月度归档
|
52
52
|
|
53
|
-
|
53
|
+
Hexo 会自动生成年度月度归档,可是 ParticleX 主题没有这个功能 ~~我太懒了~~
|
54
54
|
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
55
|
+
```yaml
|
56
|
+
archive_generator:
|
57
|
+
enabled: true
|
58
|
+
per_page: 0
|
59
|
+
yearly: false
|
60
|
+
monthly: false
|
61
|
+
daily: false
|
62
|
+
```
|
63
63
|
|
64
64
|
修改完请 `hexo cl` 清除缓存
|
65
65
|
|
66
|
-
|
66
|
+
# 3. 配置
|
67
|
+
|
68
|
+
## 3.1. 基本配置
|
67
69
|
|
68
70
|
```yaml
|
69
71
|
# Avatar image
|
70
72
|
avatar: /images/avatar.jpg
|
71
73
|
|
72
|
-
# Home page info block
|
73
|
-
headBlockEnable: true
|
74
|
-
|
75
74
|
# Home page background image
|
76
|
-
background:
|
75
|
+
background:
|
76
|
+
- /images/background.jpg
|
77
77
|
```
|
78
78
|
|
79
|
-
其中 Background
|
80
|
-
|
81
|
-
- 导航栏
|
82
|
-
|
83
|
-
为了方便,主题使用的图标是 Font Awesome 6 图标
|
84
|
-
|
85
|
-
```yaml
|
86
|
-
# ParticleX theme icon is adopts the Font Awesome 6
|
87
|
-
# https://fontawesome.com
|
88
|
-
|
89
|
-
# Main menu navigation
|
90
|
-
menu:
|
91
|
-
Home:
|
92
|
-
name: house
|
93
|
-
theme: solid
|
94
|
-
link: /
|
95
|
-
About:
|
96
|
-
name: id-card
|
97
|
-
theme: solid
|
98
|
-
link: /about
|
99
|
-
Archives:
|
100
|
-
name: box-archive
|
101
|
-
theme: solid
|
102
|
-
link: /archives
|
103
|
-
Categories:
|
104
|
-
name: bookmark
|
105
|
-
theme: solid
|
106
|
-
link: /categories
|
107
|
-
Tags:
|
108
|
-
name: tags
|
109
|
-
theme: solid
|
110
|
-
link: /tags
|
111
|
-
```
|
112
|
-
|
113
|
-
- 主页信息卡片
|
114
|
-
|
115
|
-
`description` 支持 Markdown 格式
|
116
|
-
|
117
|
-
图标链接配置和导航栏配置相同
|
118
|
-
|
119
|
-
**如果图标链接或友链为空,请在 `iconLinks:` 或 `friendLinks:` 后添加一个 `{}`**
|
120
|
-
|
121
|
-
```yaml
|
122
|
-
# Side info card
|
123
|
-
card:
|
124
|
-
enable: true
|
125
|
-
description: |
|
126
|
-
Description
|
127
|
-
...
|
128
|
-
iconLinks:
|
129
|
-
{}
|
130
|
-
friendLinks:
|
131
|
-
Argvchs: https://argvchs.netlify.app
|
132
|
-
```
|
133
|
-
|
134
|
-
- 页脚
|
135
|
-
|
136
|
-
考虑到博客部署在服务器并使用自己域名的情况,按规定需要在网站下边添加备案消息
|
137
|
-
|
138
|
-
如没有需要显示备案消息的可以关闭
|
139
|
-
|
140
|
-
```yaml
|
141
|
-
# Footer info
|
142
|
-
footer:
|
143
|
-
since: 2022
|
144
|
-
# Customize the server domain name ICP
|
145
|
-
ICP:
|
146
|
-
enable: false
|
147
|
-
code:
|
148
|
-
link:
|
149
|
-
```
|
150
|
-
|
151
|
-
- Polyfill
|
152
|
-
|
153
|
-
使用 [Polyfill.io](https://polyfill.io) 自动根据 UA 处理新的 JS API 兼容
|
154
|
-
|
155
|
-
可以配合 [Hexo-Babel](https://github.com/argvchs/hexo-babel) 插件处理 JS 语法兼容
|
156
|
-
|
157
|
-
```yaml
|
158
|
-
# Polyfill
|
159
|
-
# https://polyfill.io
|
160
|
-
polyfill:
|
161
|
-
enable: true
|
162
|
-
features:
|
163
|
-
- default
|
164
|
-
```
|
165
|
-
|
166
|
-
- 代码高亮
|
167
|
-
|
168
|
-
使用 Highlight.js 代码高亮
|
169
|
-
|
170
|
-
样式可以在[这里](https://highlightjs.org/static/demo)选择,默认为 GitHub
|
171
|
-
|
172
|
-
```yaml
|
173
|
-
# Highlight.js
|
174
|
-
# https://highlightjs.org
|
175
|
-
highlight:
|
176
|
-
enable: true
|
177
|
-
style: github
|
178
|
-
```
|
179
|
-
|
180
|
-
- 数学渲染
|
181
|
-
|
182
|
-
使用 KaTeX 渲染数学公式
|
183
|
-
|
184
|
-
```yaml
|
185
|
-
# Rendering math with KaTeX
|
186
|
-
math:
|
187
|
-
enable: false
|
188
|
-
```
|
79
|
+
其中 Background 是一个列表,打开时会随机加载一个背景
|
189
80
|
|
190
|
-
|
81
|
+
## 3.2. 内容配置
|
191
82
|
|
192
|
-
|
83
|
+
### 3.2.1. 导航栏
|
193
84
|
|
194
|
-
|
195
|
-
# Image Preview
|
196
|
-
preview:
|
197
|
-
enable: true
|
198
|
-
```
|
85
|
+
为了方便,主题使用的图标是 Font Awesome 6 图标
|
199
86
|
|
200
|
-
|
87
|
+
```yaml
|
88
|
+
# ParticleX theme icon is adopts the Font Awesome 6
|
89
|
+
# https://fontawesome.com
|
90
|
+
|
91
|
+
# Main menu navigation
|
92
|
+
menu:
|
93
|
+
Home:
|
94
|
+
name: house
|
95
|
+
theme: solid
|
96
|
+
link: /
|
97
|
+
About:
|
98
|
+
name: id-card
|
99
|
+
theme: solid
|
100
|
+
link: /about
|
101
|
+
Archives:
|
102
|
+
name: box-archive
|
103
|
+
theme: solid
|
104
|
+
link: /archives
|
105
|
+
Categories:
|
106
|
+
name: bookmark
|
107
|
+
theme: solid
|
108
|
+
link: /categories
|
109
|
+
Tags:
|
110
|
+
name: tags
|
111
|
+
theme: solid
|
112
|
+
link: /tags
|
113
|
+
```
|
201
114
|
|
202
|
-
|
115
|
+
### 3.2.2. 主页信息卡片
|
203
116
|
|
204
|
-
|
117
|
+
`description` 支持 Markdown 格式
|
205
118
|
|
206
|
-
|
119
|
+
图标链接配置和导航栏配置相同
|
207
120
|
|
208
|
-
|
209
|
-
description: |
|
210
|
-
Normal _Italic_ **Strong**
|
211
|
-
```
|
121
|
+
**如果图标链接或友链为空,请在 `iconLinks:` 或 `friendLinks:` 后添加一个 `{}`**
|
212
122
|
|
213
|
-
|
123
|
+
```yaml
|
124
|
+
# Side info card
|
125
|
+
card:
|
126
|
+
enable: true
|
127
|
+
description: |
|
128
|
+
Description
|
129
|
+
...
|
130
|
+
iconLinks:
|
131
|
+
{}
|
132
|
+
friendLinks:
|
133
|
+
Argvchs: https://argvchs.netlify.app
|
134
|
+
```
|
214
135
|
|
215
|
-
|
136
|
+
### 3.2.3. 页脚
|
216
137
|
|
217
|
-
|
138
|
+
考虑到博客部署在服务器并使用自己域名的情况,按规定需要在网站下边添加备案消息
|
218
139
|
|
219
|
-
|
140
|
+
如没有需要显示备案消息的可以关闭
|
220
141
|
|
221
|
-
|
222
|
-
|
223
|
-
|
142
|
+
```yaml
|
143
|
+
# Footer info
|
144
|
+
footer:
|
145
|
+
since: 2022
|
146
|
+
# Customize the server domain name ICP
|
147
|
+
ICP:
|
224
148
|
enable: false
|
225
|
-
|
149
|
+
code:
|
150
|
+
link:
|
151
|
+
```
|
226
152
|
|
227
|
-
|
153
|
+
## 3.3. 功能配置
|
228
154
|
|
229
|
-
|
155
|
+
### 3.3.1. Polyfill
|
230
156
|
|
231
|
-
|
157
|
+
使用 [Polyfill.io](https://polyfill.io) 自动根据 UA 处理新的 JS API 兼容
|
232
158
|
|
233
|
-
|
234
|
-
# Search
|
235
|
-
search:
|
236
|
-
enable: false
|
237
|
-
```
|
159
|
+
可以配合 [Hexo-Babel](https://github.com/argvchs/hexo-babel) 插件处理 JS 语法兼容
|
238
160
|
|
239
|
-
|
161
|
+
```yaml
|
162
|
+
# Polyfill
|
163
|
+
# https://polyfill.io
|
164
|
+
polyfill:
|
165
|
+
enable: true
|
166
|
+
features:
|
167
|
+
- default
|
168
|
+
```
|
240
169
|
|
241
|
-
|
170
|
+
### 3.3.2. 代码高亮
|
242
171
|
|
243
|
-
|
172
|
+
使用 Highlight.js 代码高亮
|
244
173
|
|
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
|
-
|
174
|
+
样式可以在[这里](https://highlightjs.org/static/demo)选择,默认为 GitHub
|
175
|
+
|
176
|
+
```yaml
|
177
|
+
# Highlight.js
|
178
|
+
# https://highlightjs.org
|
179
|
+
highlight:
|
180
|
+
enable: true
|
181
|
+
style: github
|
182
|
+
```
|
183
|
+
|
184
|
+
### 3.3.3. 数学渲染
|
185
|
+
|
186
|
+
使用 KaTeX 渲染数学公式
|
187
|
+
|
188
|
+
```yaml
|
189
|
+
# KaTeX math rendering
|
190
|
+
math:
|
191
|
+
enable: false
|
192
|
+
```
|
193
|
+
|
194
|
+
### 3.3.4. 图片预览
|
195
|
+
|
196
|
+
简单的点击图片放大缩小的预览
|
197
|
+
|
198
|
+
```yaml
|
199
|
+
# Image preview
|
200
|
+
preview:
|
201
|
+
enable: true
|
202
|
+
```
|
203
|
+
|
204
|
+
### 3.3.5. 文章缩略
|
205
|
+
|
206
|
+
一般来说,缩略展示文档只需要在文档中添加 `<!-- more -->` 即可,缩略内容在显示全文中也会出现
|
207
|
+
|
208
|
+
但考虑到不想把缩略内容放在正文里,就添加了此参数,在 [Front-Matter](https://hexo.io/zh-cn/docs/front-matter) 里设置
|
209
|
+
|
210
|
+
支持 Markdown 格式
|
211
|
+
|
212
|
+
```yaml
|
213
|
+
description: |
|
214
|
+
Normal _Italic_ **Strong**
|
215
|
+
```
|
216
|
+
|
217
|
+
### 3.3.6. 文章置顶
|
218
|
+
|
219
|
+
在 [Front-Matter](https://hexo.io/zh-cn/docs/front-matter) 里设置 `pinned` 作为置顶参数,越大越靠前,默认为 0
|
220
|
+
|
221
|
+
### 3.3.7. 文章加密
|
222
|
+
|
223
|
+
使用 AES 加密算法,在 [Front-Matter](https://hexo.io/zh-cn/docs/front-matter) 里设置 `secret` 作为密码,**使用请安装插件 [Hexo-Helper-Crypto](https://github.com/argvchs/hexo-helper-crypto)**
|
224
|
+
|
225
|
+
```yaml
|
226
|
+
# Article encryption
|
227
|
+
crypto:
|
228
|
+
enable: false
|
229
|
+
```
|
230
|
+
|
231
|
+
### 3.3.8. 搜索
|
232
|
+
|
233
|
+
嵌入到 Archives 中的搜索
|
234
|
+
|
235
|
+
目前只支持搜索文档标题
|
236
|
+
|
237
|
+
```yaml
|
238
|
+
# Search
|
239
|
+
search:
|
240
|
+
enable: false
|
241
|
+
```
|
242
|
+
|
243
|
+
## 3.4. 评论配置
|
244
|
+
|
245
|
+
### 3.4.1. Giscus
|
246
|
+
|
247
|
+
Giscus 是一个由 GitHub Discussions 支持的评论系统
|
248
|
+
|
249
|
+
在 [Giscus.app](https://giscus.app) 设置好各项后,会在下面生成一个 `<script>` 标签,在主题内填入即可
|
250
|
+
|
251
|
+
```yaml
|
252
|
+
# Giscus
|
253
|
+
# https://github.com/giscus/giscus
|
254
|
+
giscus:
|
255
|
+
enable: false
|
256
|
+
src: https://giscus.app/client.js
|
257
|
+
repo:
|
258
|
+
repoID:
|
259
|
+
category:
|
260
|
+
categoryID:
|
261
|
+
mapping: pathname
|
262
|
+
strict: 0
|
263
|
+
reactionsEnabled: 1
|
264
|
+
emitMetadata: 0
|
265
|
+
inputPosition: bottom
|
266
|
+
theme: preferred_color_scheme
|
267
|
+
lang: zh-CN
|
268
|
+
```
|
269
|
+
|
270
|
+
### 3.4.2. Gitalk
|
271
|
+
|
272
|
+
Gitalk 是一个基于 GitHub Issue 和 Preact 的评论系统
|
273
|
+
|
274
|
+
考虑到博客可能部署到多个网站同步评论,但 OAuth APP 只能有一个回调 URL,所以添加了 `sites` 参数用于多个网站的评论
|
275
|
+
|
276
|
+
**同样如果没有其他网站,请在 `sites:` 后添加一个 `{}`**
|
277
|
+
|
278
|
+
由于 Gitalk 官方 CORS 代理用的是 Cloudflare,速度过慢,添加了 `proxy` 参数,搭建 CORS 代理可以看[这篇文章](https://argvchs.netlify.app/2022/07/04/build-cors-anywhere)
|
279
|
+
|
280
|
+
```yaml
|
281
|
+
# Gitalk
|
282
|
+
# https://github.com/gitalk/gitalk
|
283
|
+
gitalk:
|
284
|
+
enable: false
|
285
|
+
clientID: # Default ClientID
|
286
|
+
clientSecret: # Default ClientSecret
|
287
|
+
repo: # The name of repository of store comments
|
288
|
+
owner: # GitHub repo owner
|
289
|
+
admin: # GitHub repo owner and collaborators, only these guys can initialize github issues
|
290
|
+
language: zh-CN # en, zh-CN, zh-TW, es-ES, fr, ru, de, pl and ko are currently available
|
291
|
+
proxy: # CORS proxy
|
292
|
+
sites: # Sites
|
293
|
+
{}
|
294
|
+
# www.example.com:
|
295
|
+
# clientID:
|
296
|
+
# clientSecret:
|
297
|
+
```
|
298
|
+
|
299
|
+
### 3.4.3. Waline
|
300
|
+
|
301
|
+
Waline 是一个简单、安全的评论系统
|
302
|
+
|
303
|
+
详见:[在 ParticleX 上使用 Waline | Yuzi's Blog](https://blog.yuzi.dev/posts/bcb4ff00.html)
|
304
|
+
|
305
|
+
**注意如果不需要 `locale` 参数,请在 `locale:` 后添加一个 `{}`**
|
306
|
+
|
307
|
+
```yaml
|
308
|
+
# Waline
|
309
|
+
# https://github.com/walinejs/waline
|
310
|
+
waline:
|
311
|
+
enable: false
|
312
|
+
serverURL: # Waline server address url, you should set this to your own link
|
313
|
+
locale: # Locale: https://waline.js.org/guide/client/i18n.html#locale-option
|
314
|
+
{}
|
315
|
+
commentCount: true # If false, comment count will only be displayed in post page, not in home page
|
316
|
+
pageview: false # Pageviews count, Note: You should not enable both `waline.pageview` and `leancloud_visitors`
|
317
|
+
emoji: # Custom emoji
|
318
|
+
- https://unpkg.com/@waline/emojis@1.2.0/weibo
|
319
|
+
- https://unpkg.com/@waline/emojis@1.2.0/alus
|
320
|
+
- https://unpkg.com/@waline/emojis@1.2.0/bilibili
|
321
|
+
- https://unpkg.com/@waline/emojis@1.2.0/qq
|
322
|
+
- https://unpkg.com/@waline/emojis@1.2.0/tieba
|
323
|
+
- https://unpkg.com/@waline/emojis@1.2.0/tw-emoji
|
324
|
+
meta: # Comment information, valid meta are nick, mail and link
|
325
|
+
- nick
|
326
|
+
- mail
|
327
|
+
- link
|
328
|
+
requiredMeta: # Set required meta field, e.g.: [nick] | [nick, mail]
|
329
|
+
- nick
|
330
|
+
lang: zh-CN # Language, available values: en-US, zh-CN, zh-TW, pt-BR, ru-RU, jp-JP
|
331
|
+
wordLimit: 0 # Word limit, no limit when setting to 0
|
332
|
+
login: enable # Whether enable login, can choose from 'enable', 'disable' and 'force'
|
333
|
+
pageSize: 10 # Comment per page
|
334
|
+
```
|
335
|
+
|
336
|
+
### 3.4.4. Twikoo
|
337
|
+
|
338
|
+
Twikoo 是一个一个简洁、安全、免费的静态网站评论系统
|
339
|
+
|
340
|
+
```yaml
|
341
|
+
# Twikoo
|
342
|
+
# https://github.com/imaegoo/twikoo
|
343
|
+
twikoo:
|
344
|
+
enable: false
|
345
|
+
envID:
|
346
|
+
region:
|
347
|
+
path: location.pathname
|
348
|
+
lang: zh-CN
|
349
|
+
```
|
344
350
|
|
345
|
-
|
351
|
+
# 4. 写在最后
|
346
352
|
|
347
353
|
本项目采用 MIT 开源许可证,欢迎大家贡献,你可以随意打开一个 Issue 来进行提问,有任何改进想法都可以进行 Fork,期待您的 Pull Request!
|
package/_config.yml
CHANGED
@@ -4,11 +4,9 @@
|
|
4
4
|
# Avatar image
|
5
5
|
avatar: /images/avatar.jpg
|
6
6
|
|
7
|
-
# Home page info block
|
8
|
-
headBlockEnable: true
|
9
|
-
|
10
7
|
# Home page background image
|
11
|
-
background:
|
8
|
+
background:
|
9
|
+
- /images/background.jpg
|
12
10
|
|
13
11
|
# ParticleX theme icon is adopts the Font Awesome 6
|
14
12
|
# https://fontawesome.com
|
@@ -69,11 +67,11 @@ highlight:
|
|
69
67
|
enable: true
|
70
68
|
style: github
|
71
69
|
|
72
|
-
#
|
70
|
+
# KaTeX math rendering
|
73
71
|
math:
|
74
72
|
enable: false
|
75
73
|
|
76
|
-
# Image
|
74
|
+
# Image preview
|
77
75
|
preview:
|
78
76
|
enable: true
|
79
77
|
|
package/layout/card.ejs
CHANGED
package/layout/comment.ejs
CHANGED
package/layout/index.ejs
CHANGED
@@ -1,6 +1,9 @@
|
|
1
1
|
<div id="home-head">
|
2
|
-
<div
|
3
|
-
|
2
|
+
<div
|
3
|
+
id="home-background"
|
4
|
+
ref="homeBackground"
|
5
|
+
data-images="<%- theme.background.map(i => url_for(i)) %>"
|
6
|
+
></div>
|
4
7
|
<div id="home-info" @click="homeClick">
|
5
8
|
<span class="loop"></span>
|
6
9
|
<span class="loop"></span>
|
@@ -14,14 +17,11 @@
|
|
14
17
|
</div>
|
15
18
|
</span>
|
16
19
|
</div>
|
17
|
-
<% } %>
|
18
20
|
</div>
|
19
21
|
<div id="home-posts-wrap" <%- theme.card.enable ? "" : 'class="home-posts-wrap-no-card"' %> ref="homePostsWrap">
|
20
22
|
<div id="home-posts">
|
21
|
-
|
22
|
-
|
23
|
-
<%- partial("current") %>
|
24
|
-
</div>
|
23
|
+
<%- partial("posts") %>
|
24
|
+
<%- partial("current") %>
|
25
25
|
</div>
|
26
26
|
<% if (theme.card.enable) { %>
|
27
27
|
<div id="home-card">
|
package/layout/layout.ejs
CHANGED
@@ -1,25 +1,16 @@
|
|
1
1
|
<%
|
2
|
-
let type
|
3
|
-
if (is_home())
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
if (page.title)
|
15
|
-
title = page.title + " | ";
|
16
|
-
else if (is_category())
|
17
|
-
title = "Categories: " + page.category + " | ";
|
18
|
-
else if (is_tag())
|
19
|
-
title = "Tags: " + page.tag + " | ";
|
20
|
-
else if (is_archive())
|
21
|
-
title = "Archives | ";
|
22
|
-
title += config.title;
|
2
|
+
let type;
|
3
|
+
if (is_home()) type = "index";
|
4
|
+
if (is_post() || is_page()) type = "post";
|
5
|
+
if (is_category() || page.type === "categories") type = "categories";
|
6
|
+
if (is_tag() || page.type === "tags") type = "tags";
|
7
|
+
if (is_archive()) type = "archives";
|
8
|
+
let title;
|
9
|
+
if (is_home()) title = config.title;
|
10
|
+
if (is_post() || is_page()) title = page.title + " | " + config.title;
|
11
|
+
if (is_category()) title = "Categories: " + page.category + " | " + config.title;
|
12
|
+
if (is_tag()) title = "Tags: " + page.tag + " | " + config.title;
|
13
|
+
if (is_archive()) title = "Archives | " + config.title;
|
23
14
|
%>
|
24
15
|
<!DOCTYPE html>
|
25
16
|
<html lang="<%- config.language %>">
|
@@ -39,14 +30,14 @@
|
|
39
30
|
<div id="loading" v-show="loading">
|
40
31
|
<div id="loading-circle">
|
41
32
|
<h2>LOADING</h2>
|
42
|
-
<p
|
33
|
+
<p>加载过慢请开启缓存 浏览器默认开启</p>
|
43
34
|
<img src="<%- url_for("/images/loading.gif") %>" />
|
44
35
|
</div>
|
45
36
|
</div>
|
46
37
|
</transition>
|
38
|
+
<%- partial("menu") %>
|
47
39
|
<transition name="into">
|
48
40
|
<div id="main" v-show="!loading">
|
49
|
-
<%- partial("menu") %>
|
50
41
|
<%- partial(type) %>
|
51
42
|
<%- partial("footer") %>
|
52
43
|
</div>
|
package/layout/menu.ejs
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
<nav id="menu"
|
1
|
+
<nav id="menu" :class="{ hidden: hiddenMenu, 'menu-color': menuColor}">
|
2
2
|
<div class="desktop-menu">
|
3
3
|
<a class="title" href="<%- config.root %>">
|
4
4
|
<span><%= config.title.toUpperCase() %></span>
|
@@ -11,13 +11,13 @@
|
|
11
11
|
<% }); %>
|
12
12
|
</div>
|
13
13
|
<div id="mobile-menu">
|
14
|
-
<div class="curtain"
|
15
|
-
<div class="title" @click="
|
14
|
+
<div class="curtain" @click="shouMenuItems = !shouMenuItems" v-show="shouMenuItems"></div>
|
15
|
+
<div class="title" @click="shouMenuItems = !shouMenuItems">
|
16
16
|
<i class="fa-solid fa-bars fa-fw"></i>
|
17
17
|
<span> <%= config.title.toUpperCase() %></span>
|
18
18
|
</div>
|
19
19
|
<transition name="slide">
|
20
|
-
<div class="items" v-show="
|
20
|
+
<div class="items" v-show="shouMenuItems">
|
21
21
|
<% Object.keys(theme.menu).forEach(key => { %>
|
22
22
|
<a href="<%- url_for(theme.menu[key].link) %>">
|
23
23
|
<div class="item">
|
package/layout/post.ejs
CHANGED
@@ -43,26 +43,19 @@
|
|
43
43
|
<% } %>
|
44
44
|
</div>
|
45
45
|
<% if (theme.crypto.enable && typeof page.secret !== "undefined") { %>
|
46
|
-
<%
|
47
|
-
const CryptoJS = crypto();
|
48
|
-
function SHA(word) {
|
49
|
-
return CryptoJS.SHA256(word).toString();
|
50
|
-
}
|
51
|
-
function encrypt(word, secret) {
|
52
|
-
return CryptoJS.AES.encrypt(word, secret).toString();
|
53
|
-
}
|
54
|
-
%>
|
46
|
+
<% const CryptoJS = crypto(); %>
|
55
47
|
<input
|
56
48
|
id="crypto"
|
57
|
-
class="input"
|
49
|
+
:class="['input', cryptoClass]"
|
50
|
+
:disabled="check"
|
58
51
|
ref="crypto"
|
59
52
|
placeholder="文章被加密,请输入密码"
|
60
|
-
data-encrypted="<%- encrypt(page.content, page.secret) %>"
|
61
|
-
data-shasum="<%-
|
53
|
+
data-encrypted="<%- CryptoJS.AES.encrypt(page.content, page.secret).toString() %>"
|
54
|
+
data-shasum="<%- CryptoJS.SHA256(page.content).toString() %>"
|
62
55
|
v-model="crypto"
|
63
56
|
/>
|
64
57
|
<transition name="fade">
|
65
|
-
<div class="content" ref="content" v-show="check"></div>
|
58
|
+
<div class="content" ref="content" v-html="decrypted" v-show="check"></div>
|
66
59
|
</transition>
|
67
60
|
<% } else { %>
|
68
61
|
<div class="content" v-pre>
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "hexo-theme-particlex",
|
3
|
-
"version": "2.5.
|
3
|
+
"version": "2.5.9",
|
4
4
|
"description": "A concise Hexo theme, based on Particle.",
|
5
5
|
"repository": {
|
6
6
|
"type": "git",
|
@@ -21,7 +21,7 @@
|
|
21
21
|
},
|
22
22
|
"homepage": "https://github.com/argvchs/hexo-theme-particlex#readme",
|
23
23
|
"dependencies": {
|
24
|
-
"hexo-helper-crypto": "^1.1.
|
24
|
+
"hexo-helper-crypto": "^1.1.2",
|
25
25
|
"hexo-renderer-ejs": "^2.0.0"
|
26
26
|
},
|
27
27
|
"scripts": {
|
package/source/css/main.css
CHANGED
@@ -92,6 +92,7 @@
|
|
92
92
|
box-shadow: 0 0 20px #d9d9d980;
|
93
93
|
padding: 25px 0;
|
94
94
|
text-align: center;
|
95
|
+
width: 300px;
|
95
96
|
}
|
96
97
|
#home-card .card-style .avatar {
|
97
98
|
border: #f1f1f1 solid 3px;
|
@@ -360,11 +361,11 @@
|
|
360
361
|
height: 50vmin;
|
361
362
|
justify-content: center;
|
362
363
|
padding: 50px;
|
364
|
+
text-align: center;
|
363
365
|
width: 50vmin;
|
364
366
|
}
|
365
367
|
#main {
|
366
368
|
margin-right: calc(100% - 100vw);
|
367
|
-
overflow: auto;
|
368
369
|
}
|
369
370
|
#menu {
|
370
371
|
background: #92cafa;
|
@@ -488,6 +489,7 @@
|
|
488
489
|
line-height: 2;
|
489
490
|
overflow: auto;
|
490
491
|
padding: 50px 30px 20px;
|
492
|
+
white-space: pre;
|
491
493
|
}
|
492
494
|
.comment iframe,
|
493
495
|
body::-webkit-scrollbar-track {
|
@@ -504,24 +506,24 @@ body::-webkit-scrollbar-track {
|
|
504
506
|
margin: 15px auto;
|
505
507
|
max-width: 75%;
|
506
508
|
}
|
507
|
-
.
|
509
|
+
.copycode {
|
508
510
|
color: #5c6b72;
|
509
511
|
position: absolute;
|
510
512
|
right: 0;
|
511
513
|
top: 0;
|
512
514
|
}
|
513
|
-
.
|
515
|
+
.copycode i {
|
514
516
|
padding: 15px;
|
515
517
|
position: absolute;
|
516
518
|
right: 0;
|
517
519
|
top: 0;
|
518
520
|
transition: transform 0.25s;
|
519
521
|
}
|
520
|
-
.
|
522
|
+
.copycode.copied i {
|
521
523
|
transform: scale(1.25);
|
522
524
|
}
|
523
|
-
.
|
524
|
-
.
|
525
|
+
.copycode.copied i:first-child,
|
526
|
+
.copycode:not(.copied) i:last-child {
|
525
527
|
opacity: 0;
|
526
528
|
}
|
527
529
|
.fade-enter-active,
|
@@ -658,7 +660,7 @@ a {
|
|
658
660
|
text-decoration: none;
|
659
661
|
}
|
660
662
|
a:hover,
|
661
|
-
.content .
|
663
|
+
.content .copycode:hover {
|
662
664
|
opacity: 0.8;
|
663
665
|
}
|
664
666
|
b,
|
@@ -694,13 +696,12 @@ iframe,
|
|
694
696
|
.friend-link a,
|
695
697
|
.icon-link a,
|
696
698
|
.language,
|
697
|
-
.
|
699
|
+
.copycode {
|
698
700
|
user-select: none;
|
699
701
|
}
|
700
702
|
code {
|
701
703
|
background: #bddcf76b;
|
702
704
|
border-radius: 4px;
|
703
|
-
font-size: 14px;
|
704
705
|
line-height: 2.5;
|
705
706
|
padding: 4px 8px;
|
706
707
|
}
|
@@ -764,6 +765,7 @@ pre {
|
|
764
765
|
box-shadow: 0 2px 12px 0 #0000001a;
|
765
766
|
margin: 25px 0;
|
766
767
|
margin: 25px 0;
|
768
|
+
white-space: normal;
|
767
769
|
}
|
768
770
|
pre,
|
769
771
|
code,
|
@@ -824,9 +826,6 @@ ol li {
|
|
824
826
|
}
|
825
827
|
}
|
826
828
|
@media (min-width: 900px) {
|
827
|
-
#home-card {
|
828
|
-
margin-right: auto;
|
829
|
-
}
|
830
829
|
#home-head #home-info .info .wrap {
|
831
830
|
padding: 25px;
|
832
831
|
}
|
@@ -855,9 +854,8 @@ ol li {
|
|
855
854
|
width: 500px;
|
856
855
|
}
|
857
856
|
#home-posts {
|
858
|
-
margin-left: auto;
|
859
857
|
margin-right: 50px;
|
860
|
-
width:
|
858
|
+
width: 850px;
|
861
859
|
}
|
862
860
|
#home-posts .post {
|
863
861
|
margin-bottom: 25px;
|
@@ -867,8 +865,7 @@ ol li {
|
|
867
865
|
padding: 20px 0;
|
868
866
|
}
|
869
867
|
#home-posts-wrap {
|
870
|
-
max-width:
|
871
|
-
padding: 30px 0;
|
868
|
+
max-width: 1200px;
|
872
869
|
}
|
873
870
|
#menu .desktop-menu {
|
874
871
|
display: block;
|
@@ -894,7 +891,6 @@ ol li {
|
|
894
891
|
display: none;
|
895
892
|
}
|
896
893
|
#home-posts {
|
897
|
-
margin: auto;
|
898
894
|
width: 100%;
|
899
895
|
}
|
900
896
|
#home-posts-wrap,
|
package/source/js/lib/crypto.js
CHANGED
@@ -2,40 +2,31 @@ mixins.crypto = {
|
|
2
2
|
data() {
|
3
3
|
return {
|
4
4
|
crypto: "",
|
5
|
-
check:
|
5
|
+
check: null,
|
6
6
|
};
|
7
7
|
},
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
8
|
+
watch: {
|
9
|
+
crypto(value) {
|
10
|
+
let input = this.$refs.crypto,
|
11
|
+
content = this.$refs.content;
|
12
|
+
let { encrypted, shasum } = input.dataset;
|
13
13
|
try {
|
14
|
-
let
|
15
|
-
|
14
|
+
let decrypted = CryptoJS.AES.decrypt(encrypted, value).toString(CryptoJS.enc.Utf8);
|
15
|
+
if (CryptoJS.SHA256(decrypted).toString() === shasum) {
|
16
|
+
this.check = true;
|
17
|
+
content.innerHTML = decrypted;
|
18
|
+
this.render();
|
19
|
+
} else this.check = false;
|
16
20
|
} catch {
|
17
|
-
|
21
|
+
this.check = false;
|
18
22
|
}
|
19
23
|
},
|
20
24
|
},
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
input.dataset.encrypted,
|
27
|
-
value,
|
28
|
-
input.dataset.shasum
|
29
|
-
);
|
30
|
-
this.check = check;
|
31
|
-
if (check) {
|
32
|
-
input.classList.remove("fail");
|
33
|
-
input.classList.add("success");
|
34
|
-
input.disabled = true;
|
35
|
-
content.innerHTML = decrypted;
|
36
|
-
this.render();
|
37
|
-
} else input.classList.add("fail");
|
25
|
+
computed: {
|
26
|
+
cryptoClass() {
|
27
|
+
if (this.check === null) return "";
|
28
|
+
if (this.check === true) return "success";
|
29
|
+
if (this.check === false) return "fail";
|
38
30
|
},
|
39
31
|
},
|
40
32
|
};
|
41
|
-
mixins.push(cryptoMixin);
|
@@ -10,24 +10,29 @@ mixins.highlight = {
|
|
10
10
|
},
|
11
11
|
methods: {
|
12
12
|
highlight() {
|
13
|
-
let that = this;
|
14
13
|
let codes = document.querySelectorAll("pre");
|
15
14
|
for (let i of codes) {
|
16
|
-
let lang = [...i.classList, ...i.firstChild.classList][0] || "plaintext";
|
17
15
|
let code = i.innerText;
|
18
|
-
|
19
|
-
let
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
16
|
+
let language = [...i.classList, ...i.firstChild.classList][0] || "plaintext";
|
17
|
+
let highlighted = hljs.highlight(code, { language }).value;
|
18
|
+
i.innerHTML = `
|
19
|
+
<div class="code-content">${highlighted}</div>
|
20
|
+
<div class="language">${language}</div>
|
21
|
+
<div class="copycode">
|
22
|
+
<i class="fa-solid fa-copy fa-fw"></i>
|
23
|
+
<i class="fa-solid fa-clone fa-fw"></i>
|
24
|
+
</div>
|
25
|
+
`;
|
26
|
+
let copycode = i.querySelector(".copycode");
|
27
|
+
copycode.addEventListener("click", async () => {
|
28
|
+
if (this.copying) return;
|
29
|
+
this.copying = true;
|
30
|
+
copycode.classList.add("copied");
|
24
31
|
await navigator.clipboard.writeText(code);
|
25
32
|
await new Promise(resolve => setTimeout(resolve, 1000));
|
26
|
-
|
27
|
-
|
33
|
+
copycode.classList.remove("copied");
|
34
|
+
this.copying = false;
|
28
35
|
});
|
29
|
-
let content = i.querySelector(".code-content");
|
30
|
-
hljs.highlightElement(content);
|
31
36
|
}
|
32
37
|
},
|
33
38
|
},
|
package/source/js/lib/home.js
CHANGED
@@ -1,11 +1,10 @@
|
|
1
1
|
mixins.home = {
|
2
2
|
mounted() {
|
3
|
-
let
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
background.style.backgroundImage = `url('${image[id]}')`;
|
3
|
+
let background = this.$refs.homeBackground;
|
4
|
+
let images = background.dataset.images.split(",");
|
5
|
+
let id = Math.floor(Math.random() * images.length);
|
6
|
+
background.style.backgroundImage = `url('${images[id]}')`;
|
7
|
+
this.menuColor = true;
|
9
8
|
},
|
10
9
|
methods: {
|
11
10
|
homeClick() {
|
package/source/js/lib/preview.js
CHANGED
@@ -9,15 +9,14 @@ mixins.preview = {
|
|
9
9
|
},
|
10
10
|
methods: {
|
11
11
|
preview() {
|
12
|
-
let that = this;
|
13
12
|
let preview = this.$refs.preview,
|
14
13
|
content = this.$refs.previewContent;
|
15
14
|
let images = document.querySelectorAll("img");
|
16
15
|
for (let i of images)
|
17
|
-
i.addEventListener("click",
|
18
|
-
content.alt =
|
19
|
-
content.src =
|
20
|
-
|
16
|
+
i.addEventListener("click", () => {
|
17
|
+
content.alt = i.alt;
|
18
|
+
content.src = i.src;
|
19
|
+
this.previewShow = true;
|
21
20
|
});
|
22
21
|
preview.addEventListener("click", () => {
|
23
22
|
this.previewShow = false;
|
package/source/js/main.js
CHANGED
@@ -3,8 +3,10 @@ const app = Vue.createApp({
|
|
3
3
|
data() {
|
4
4
|
return {
|
5
5
|
loading: true,
|
6
|
-
|
7
|
-
|
6
|
+
hiddenMenu: false,
|
7
|
+
showMenuItems: false,
|
8
|
+
menuColor: false,
|
9
|
+
scrollTop: 0,
|
8
10
|
renderers: [],
|
9
11
|
};
|
10
12
|
},
|
@@ -23,20 +25,19 @@ const app = Vue.createApp({
|
|
23
25
|
for (let i of this.renderers) i();
|
24
26
|
},
|
25
27
|
handleScroll() {
|
26
|
-
let
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
this.
|
31
|
-
|
32
|
-
} else menu.classList.remove("hidden");
|
28
|
+
let wrap = this.$refs.homePostsWrap;
|
29
|
+
let newScrollTop = document.documentElement.scrollTop;
|
30
|
+
if (this.scrollTop < newScrollTop) {
|
31
|
+
this.hiddenMenu = true;
|
32
|
+
this.showMenuItems = false;
|
33
|
+
} else this.hiddenMenu = false;
|
33
34
|
if (wrap) {
|
34
|
-
if (
|
35
|
-
else
|
36
|
-
if (
|
35
|
+
if (newScrollTop <= window.innerHeight - 100) this.menuColor = true;
|
36
|
+
else this.menuColor = false;
|
37
|
+
if (newScrollTop <= 400) wrap.style.marginTop = -newScrollTop / 5 + "px";
|
37
38
|
else wrap.style.marginTop = "-80px";
|
38
39
|
}
|
39
|
-
this.
|
40
|
+
this.scrollTop = newScrollTop;
|
40
41
|
},
|
41
42
|
},
|
42
43
|
});
|