hexo-theme-particlex 2.4.11 → 2.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -69,7 +69,6 @@ theme: particlex
69
69
  avatar: # Avatar image
70
70
  headBlockEnable: true # Home page info block
71
71
  background: # Home page background image
72
- highlightStyle: github # Highlight style
73
72
  ```
74
73
 
75
74
  - 导航栏
@@ -170,9 +169,21 @@ highlightStyle: github # Highlight style
170
169
  - default
171
170
  ```
172
171
 
173
- - 渲染数学公式
172
+ - 代码高亮
174
173
 
175
- 使用 KaTeX 渲染数学公式,默认关闭
174
+ 使用 Highlight.js 代码高亮
175
+
176
+ 样式可以在[这里](https://highlightjs.org/static/demo)选择,默认为 GitHub
177
+
178
+ ```yaml
179
+ highlight:
180
+ enable: false
181
+ style: github
182
+ ```
183
+
184
+ - 数学渲染
185
+
186
+ 使用 KaTeX 渲染数学公式
176
187
 
177
188
  ```yaml
178
189
  math:
@@ -194,7 +205,7 @@ highlightStyle: github # Highlight style
194
205
 
195
206
  - 搜索
196
207
 
197
- 嵌入到 Archives 中的搜索,默认关闭
208
+ 嵌入到 Archives 中的搜索
198
209
 
199
210
  目前只支持搜索文档标题(我太弱了)
200
211
 
package/_config.yml CHANGED
@@ -10,10 +10,6 @@ headBlockEnable: true
10
10
  # Home page background image
11
11
  background:
12
12
 
13
- # Highlight style
14
- # https://highlightjs.org
15
- highlightStyle: github
16
-
17
13
  # ParticleX theme icon is adopts the Font Awesome 6
18
14
  # https://fontawesome.com/search
19
15
 
@@ -76,6 +72,12 @@ polyfill:
76
72
  features:
77
73
  - default
78
74
 
75
+ # Highlight.js
76
+ # https://highlightjs.org
77
+ highlight:
78
+ enable: true
79
+ style: github
80
+
79
81
  # Rendering math with KaTeX
80
82
  math:
81
83
  enable: false
@@ -4,46 +4,53 @@
4
4
  %>
5
5
  <div id="archives">
6
6
  <% if (theme.search.enable) { %>
7
- <div id="search-mask" style="z-index: <%- posts.length + 1 %>"></div>
8
- <input id="search-bar" class="input" placeholder="搜索" style="z-index: <%- posts.length + 2 %>">
7
+ <input id="search-bar" class="input" placeholder="搜索" v-model="rawSearch" />
9
8
  <% } %>
10
- <% posts.forEach((post, id) => { %>
11
- <div class="timeline" style="z-index: <%- posts.length - id %>" data-title="<%- post.title.toLowerCase().replace(/\s+/gm, "") %>">
12
- <div class="timeline-tail"></div>
13
- <div class="timeline-content">
14
- <div class="item-time"><%= date(post.date, "YYYY/M/D") %></div>
15
- <a href="<%- url_for(post.path) %>">
16
- <h3><%= post.title %></h3>
17
- </a>
18
- <div class="info">
19
- <% if (post.categories && post.categories.data.length !== 0) { %>
20
- <span class="category">
21
- <a href="<%- url_for(post.categories.data[0].path) %>">
9
+ <div id="timeline-wrap" ref="timeline">
10
+ <% posts.reverse().forEach((post, id) => { %>
11
+ <div class="timeline" data-title="<%- post.title.toLowerCase().replace(/\s+/gm, "") %>">
12
+ <div class="timeline-tail"></div>
13
+ <div class="timeline-content">
14
+ <div class="item-time"><%= date(post.date, "YYYY/M/D") %></div>
15
+ <a href="<%- url_for(post.path) %>">
16
+ <h3><%= post.title %></h3>
17
+ </a>
18
+ <div class="info">
19
+ <% if (post.categories && post.categories.data.length !== 0) { %>
20
+ <span class="category">
21
+ <a href="<%- url_for(post.categories.data[0].path) %>">
22
+ <span class="icon">
23
+ <i class="fa-solid fa-bookmark fa-fw"></i>
24
+ </span>
25
+ <%= post.categories.data[0].name %>
26
+ </a>
27
+ </span>
28
+ <% } %>
29
+ <% if (post.tags && post.tags.data.length !== 0) { %>
30
+ <span class="tags">
22
31
  <span class="icon">
23
- <i class="fa-solid fa-bookmark fa-fw"></i>
32
+ <i class="fa-solid fa-tags fa-fw"></i>
24
33
  </span>
25
- <%= post.categories.data[0].name %>
26
- </a>
27
- </span>
28
- <% } %>
29
- <% if (post.tags && post.tags.data.length !== 0) { %>
30
- <span class="tags">
31
- <span class="icon">
32
- <i class="fa-solid fa-tags fa-fw"></i>
33
- </span>
34
- <% post.tags.data.forEach(data => { %>
35
- <span class="tag">
36
- <%
37
- const color = ["color: #ffa2c4", "color: #00bcd4", "color: #03a9f4", "color: #00a596", "color: #ff7d73"];
38
- let num = Math.floor(Math.random() * color.length);
39
- %>
40
- <a href="<%- url_for(data.path) %>" style="<%- color[num] %>"><%= data.name %></a>
34
+ <% post.tags.data.forEach(data => { %>
35
+ <span class="tag">
36
+ <%
37
+ const color = [
38
+ "color: #ffa2c4",
39
+ "color: #00bcd4",
40
+ "color: #03a9f4",
41
+ "color: #00a596",
42
+ "color: #ff7d73",
43
+ ];
44
+ let num = Math.floor(Math.random() * color.length);
45
+ %>
46
+ <a href="<%- url_for(data.path) %>" style="<%- color[num] %>"><%= data.name %></a>
47
+ </span>
48
+ <% }); %>
41
49
  </span>
42
- <% }); %>
43
- </span>
44
- <% } %>
50
+ <% } %>
51
+ </div>
45
52
  </div>
46
53
  </div>
54
+ <% }); %>
47
55
  </div>
48
- <% }); %>
49
56
  </div>
package/layout/card.ejs CHANGED
@@ -1,7 +1,7 @@
1
1
  <div id="card-div">
2
2
  <div class="card-style" style="width: 300px">
3
3
  <div class="avatar">
4
- <img src="<%- url_for(theme.avatar) %>" alt="avatar">
4
+ <img src="<%- url_for(theme.avatar) %>" alt="avatar" />
5
5
  </div>
6
6
  <div class="name"><%= config.author %></div>
7
7
  <div class="description">
@@ -12,7 +12,9 @@
12
12
  <% Object.keys(theme.card.iconLinks).forEach(key => { %>
13
13
  <span class="icon-link">
14
14
  <a href="<%- url_for(theme.card.iconLinks[key].link) %>">
15
- <i class="fa-<%- theme.card.iconLinks[key].theme %> fa-<%- theme.card.iconLinks[key].name %> fa-fw"></i>
15
+ <i
16
+ class="fa-<%- theme.card.iconLinks[key].theme %> fa-<%- theme.card.iconLinks[key].name %> fa-fw"
17
+ ></i>
16
18
  </a>
17
19
  </span>
18
20
  <% }); %>
@@ -51,7 +51,13 @@
51
51
  <% post.tags.data.forEach(data => { %>
52
52
  <span class="tag">
53
53
  <%
54
- const color = ["color: #ffa2c4", "color: #00bcd4", "color: #03a9f4", "color: #00a596", "color: #ff7d73"];
54
+ const color = [
55
+ "color: #ffa2c4",
56
+ "color: #00bcd4",
57
+ "color: #03a9f4",
58
+ "color: #00a596",
59
+ "color: #ff7d73",
60
+ ];
55
61
  let num = Math.floor(Math.random() * color.length);
56
62
  %>
57
63
  <a href="<%- url_for(data.path) %>" style="<%- color[num] %>"><%= data.name %></a>
@@ -1,9 +1,4 @@
1
- <script src="<%- url_for("/js/functions.js") %>"></script>
2
- <script src="<%- url_for("/js/particlex.js") %>"></script>
3
- <% if (type === "post" && page.comments) { %>
4
1
  <% if (theme.gitalk.enable) { %>
5
- <script src="https://cdn.staticfile.org/gitalk/1.8.0/gitalk.min.js"></script>
6
- <link rel="stylesheet" href="https://cdn.staticfile.org/gitalk/1.8.0/gitalk.min.css">
7
2
  <script>
8
3
  let clientID = "<%- theme.gitalk.clientID %>",
9
4
  clientSecret = "<%- theme.gitalk.clientSecret %>";
@@ -48,9 +43,6 @@
48
43
  ></script>
49
44
  <% } %>
50
45
  <% if (theme.waline.enable) { %>
51
- <script src="https://cdn.staticfile.org/waline/2.14.7/waline.min.js"></script>
52
- <link rel="stylesheet" href="https://cdn.staticfile.org/waline/2.14.7/waline.min.css">
53
- <link rel="stylesheet" href="https://cdn.staticfile.org/waline/2.14.7/waline-meta.min.css">
54
46
  <script>
55
47
  Waline.init({
56
48
  el: "#waline-container",
@@ -69,7 +61,6 @@
69
61
  </script>
70
62
  <% } %>
71
63
  <% if (theme.twikoo.enable) { %>
72
- <script src="https://cdn.staticfile.org/twikoo/1.6.8/twikoo.all.min.js"></script>
73
64
  <script>
74
65
  twikoo.init({
75
66
  el: "#twikoo-container",
@@ -80,4 +71,3 @@
80
71
  })
81
72
  </script>
82
73
  <% } %>
83
- <% } %>
package/layout/footer.ejs CHANGED
@@ -1,14 +1,17 @@
1
1
  <footer id="footer">
2
- <div class="footer-wrap">
2
+ <div id="footer-wrap">
3
3
  <div>
4
4
  &copy;
5
5
  <%= theme.footer.since %> - <%= date(Date.now(), "YYYY") %> <%= config.title %>
6
- <span class="footer-icon">
6
+ <span id="footer-icon">
7
7
  <i class="fa-solid fa-font-awesome fa-fw"></i>
8
8
  </span>
9
9
  &commat;<%= config.author %>
10
10
  </div>
11
- <div>Based on the <a href="https://hexo.io">Hexo Engine</a> &amp; <a href="https://github.com/argvchs/hexo-theme-particlex">ParticleX Theme</a></div>
11
+ <div>
12
+ Based on the <a href="https://hexo.io">Hexo Engine</a> &amp;
13
+ <a href="https://github.com/argvchs/hexo-theme-particlex">ParticleX Theme</a>
14
+ </div>
12
15
  <% if (theme.footer.ICP.enable) { %>
13
16
  <div>
14
17
  备案号:
@@ -0,0 +1,44 @@
1
+ <script src="https://cdn.staticfile.org/vue/3.2.45/vue.global.prod.min.js"></script>
2
+ <link rel="stylesheet" href="https://cdn.staticfile.org/font-awesome/6.2.1/css/all.min.css" />
3
+ <link rel="stylesheet" href="<%- url_for("/css/fonts.min.css") %>" />
4
+ <script>const mixins = [];</script>
5
+ <% if (theme.highlight.enable) { %>
6
+ <script src="https://cdn.staticfile.org/highlight.js/11.7.0/highlight.min.js"></script>
7
+ <link
8
+ rel="stylesheet"
9
+ href="https://cdn.staticfile.org/highlight.js/11.7.0/styles/<%- theme.highlight.style %>.min.css"
10
+ />
11
+ <script src="<%- url_for("/js/lib/highlight.js") %>"></script>
12
+ <% } %>
13
+ <% if (theme.polyfill.enable) { %>
14
+ <script src="https://polyfill.io/v3/polyfill.min.js?features=<%- theme.polyfill.features.join(",") %>"></script>
15
+ <% } %>
16
+ <% if (theme.math.enable) { %>
17
+ <script src="https://cdn.staticfile.org/KaTeX/0.16.4/katex.min.js"></script>
18
+ <script src="https://cdn.staticfile.org/KaTeX/0.16.4/contrib/auto-render.min.js"></script>
19
+ <link rel="stylesheet" href="https://cdn.staticfile.org/KaTeX/0.16.4/katex.min.css" />
20
+ <script src="<%- url_for("/js/lib/math.js") %>"></script>
21
+ <% } %>
22
+ <% if (theme.crypto.enable && typeof page.secret !== "undefined") { %>
23
+ <script src="https://cdn.staticfile.org/crypto-js/4.1.1/crypto-js.min.js"></script>
24
+ <script src="<%- url_for("/js/lib/crypto.js") %>"></script>
25
+ <% } %>
26
+ <% if (theme.search.enable && type === "archives") { %>
27
+ <script src="<%- url_for("/js/lib/search.js") %>"></script>
28
+ <% } %>
29
+ <% if (page.comments && type === "post") { %>
30
+ <% if (theme.gitalk.enable) { %>
31
+ <script src="https://cdn.staticfile.org/gitalk/1.8.0/gitalk.min.js"></script>
32
+ <link rel="stylesheet" href="https://cdn.staticfile.org/gitalk/1.8.0/gitalk.min.css" />
33
+ <% } %>
34
+ <% if (theme.waline.enable) { %>
35
+ <script src="https://cdn.staticfile.org/waline/2.14.7/waline.min.js"></script>
36
+ <link rel="stylesheet" href="https://cdn.staticfile.org/waline/2.14.7/waline.min.css" />
37
+ <link rel="stylesheet" href="https://cdn.staticfile.org/waline/2.14.7/waline-meta.min.css" />
38
+ <% } %>
39
+ <% if (theme.twikoo.enable) { %>
40
+ <script src="https://cdn.staticfile.org/twikoo/1.6.8/twikoo.all.min.js"></script>
41
+ <% } %>
42
+ <% } %>
43
+ <script src="<%- url_for("/js/lib/preview.js") %>"></script>
44
+ <link rel="stylesheet" href="<%- url_for("/css/main.css") %>" />
package/layout/index.ejs CHANGED
@@ -1,7 +1,7 @@
1
- <div id="home-head">
1
+ <div id="home-head" ref="head">
2
2
  <div id="home-background" style="background-image: url(<%- theme.background %>)"></div>
3
3
  <% if (theme.headBlockEnable) { %>
4
- <div id="home-info" @click="homeclick">
4
+ <div id="home-info" @click="homeClick">
5
5
  <span class="loop"></span>
6
6
  <span class="loop"></span>
7
7
  <span class="loop"></span>
@@ -16,7 +16,7 @@
16
16
  </div>
17
17
  <% } %>
18
18
  </div>
19
- <div id="home-posts-wrap" class="<%- theme.card.enable ? "" : "home-posts-wrap-no-card" %>">
19
+ <div id="home-posts-wrap" <%- theme.card.enable ? "" : 'class="home-posts-wrap-no-card"' %> ref="wrap">
20
20
  <div id="home-posts">
21
21
  <div id="posts">
22
22
  <%- partial("posts") %>
package/layout/layout.ejs CHANGED
@@ -24,45 +24,42 @@
24
24
  <!DOCTYPE html>
25
25
  <html lang="<%- config.language %>">
26
26
  <head>
27
- <meta charset="UTF-8">
27
+ <meta charset="UTF-8" />
28
28
  <title><%= title %></title>
29
- <meta name="author" content="<%- config.author %>">
30
- <meta name="description" content="<%- config.description %>">
31
- <meta name="keywords" content="<%- config.keywords %>">
32
- <meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=0">
33
- <link rel="icon" href="<%- url_for(theme.avatar) %>">
34
- <script src="https://cdn.staticfile.org/vue/3.2.45/vue.global.prod.min.js"></script>
35
- <script src="https://cdn.staticfile.org/highlight.js/11.7.0/highlight.min.js"></script>
36
- <link rel="stylesheet" href="https://cdn.staticfile.org/highlight.js/11.7.0/styles/<%- theme.highlightStyle %>.min.css">
37
- <link rel="stylesheet" href="https://cdn.staticfile.org/font-awesome/6.2.1/css/all.min.css">
38
- <% if (theme.polyfill.enable) { %>
39
- <script src="https://polyfill.io/v3/polyfill.min.js?features=<%- theme.polyfill.features.join(",") %>"></script>
40
- <% } %>
41
- <% if (theme.math.enable) { %>
42
- <script src="https://cdn.staticfile.org/KaTeX/0.16.4/katex.min.js"></script>
43
- <script src="https://cdn.staticfile.org/KaTeX/0.16.4/contrib/auto-render.min.js"></script>
44
- <link rel="stylesheet" href="https://cdn.staticfile.org/KaTeX/0.16.4/katex.min.css">
45
- <% } %>
46
- <% if (theme.crypto.enable && typeof page.secret !== "undefined") { %>
47
- <script src="https://cdn.staticfile.org/crypto-js/4.1.1/crypto-js.min.js"></script>
48
- <% } %>
49
- <link rel="stylesheet" href="<%- url_for("/css/fonts.min.css") %>">
50
- <link rel="stylesheet" href="<%- url_for("/css/particlex.css") %>">
29
+ <meta name="author" content="<%- config.author %>" />
30
+ <meta name="description" content="<%- config.description %>" />
31
+ <meta name="keywords" content="<%- config.keywords %>" />
32
+ <meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=0" />
33
+ <link rel="icon" href="<%- url_for(theme.avatar) %>" />
34
+ <%- partial("import", { type }) %>
51
35
  </head>
52
36
  <body>
53
- <%- partial("loading") %>
54
37
  <div id="layout">
38
+ <transition name="fade">
39
+ <div id="loading" v-show="loading">
40
+ <div id="loading-circle">
41
+ <h2>LOADING</h2>
42
+ <p>加载过慢请开启缓存&ensp;浏览器默认开启</p>
43
+ <img src="<%- url_for("/images/loading.gif") %>" />
44
+ </div>
45
+ </div>
46
+ </transition>
55
47
  <transition name="into">
56
- <div id="main" v-show="showpage" style="display: -not-none">
48
+ <div id="main" v-show="!loading">
57
49
  <%- partial("menu") %>
58
50
  <%- partial(type) %>
59
51
  <%- partial("footer") %>
60
52
  </div>
61
53
  </transition>
62
- <div id="showimg">
63
- <img id="showimg-content">
54
+ <transition name="fade">
55
+ <div id="preview" ref="preview" v-show="previewShow">
56
+ <img id="preview-content" ref="previewContent" />
64
57
  </div>
58
+ </transition>
65
59
  </div>
66
- <%- partial("script", { type }) %>
60
+ <script src="<%- url_for("/js/main.js") %>"></script>
61
+ <% if (type === "post" && page.comments) { %>
62
+ <%- partial("comment") %>
63
+ <% } %>
67
64
  </body>
68
65
  </html>
package/layout/menu.ejs CHANGED
@@ -1,4 +1,4 @@
1
- <nav id="menu">
1
+ <nav id="menu" ref="menu">
2
2
  <div class="desktop-menu">
3
3
  <a class="title" href="<%- config.root %>">
4
4
  <span><%= config.title.toUpperCase() %></span>
@@ -10,14 +10,14 @@
10
10
  </a>
11
11
  <% }); %>
12
12
  </div>
13
- <div :class="&quot;phone-menu &quot; + menushow" id="phone-menu">
14
- <div class="curtain" @click="menushow = !menushow" v-show="menushow"></div>
15
- <div class="title" @click="menushow = !menushow">
13
+ <div id="mobile-menu">
14
+ <div class="curtain" v-show="showMenu" @click="showMenu = !showMenu"></div>
15
+ <div class="title" @click="showMenu = !showMenu">
16
16
  <i class="fa-solid fa-bars fa-fw"></i>
17
17
  <span>&emsp;<%= config.title.toUpperCase() %></span>
18
18
  </div>
19
19
  <transition name="slide">
20
- <div class="items" v-show="menushow">
20
+ <div class="items" v-show="showMenu">
21
21
  <% Object.keys(theme.menu).forEach(key => { %>
22
22
  <a href="<%- url_for(theme.menu[key].src) %>">
23
23
  <div class="item">
package/layout/post.ejs CHANGED
@@ -27,7 +27,13 @@
27
27
  <% page.tags.data.forEach(data => { %>
28
28
  <span class="tag">
29
29
  <%
30
- const color = ["color: #ffa2c4", "color: #00bcd4", "color: #03a9f4", "color: #00a596", "color: #ff7d73"];
30
+ const color = [
31
+ "color: #ffa2c4",
32
+ "color: #00bcd4",
33
+ "color: #03a9f4",
34
+ "color: #00a596",
35
+ "color: #ff7d73",
36
+ ];
31
37
  let num = Math.floor(Math.random() * color.length);
32
38
  %>
33
39
  <a href="<%- url_for(data.path) %>" style="<%- color[num] %>"><%= data.name %></a>
@@ -39,15 +45,25 @@
39
45
  <% if (theme.crypto.enable && typeof page.secret !== "undefined") { %>
40
46
  <%
41
47
  const CryptoJS = crypto();
42
- function sha(str) {
43
- return CryptoJS.SHA256(str).toString();
48
+ function SHA(word) {
49
+ return CryptoJS.SHA256(word).toString();
44
50
  }
45
- function encrypt(str, key) {
46
- return CryptoJS.AES.encrypt(str, key).toString();
51
+ function encrypt(word, secret) {
52
+ return CryptoJS.AES.encrypt(word, secret).toString();
47
53
  }
48
54
  %>
49
- <input id="crypto" class="input" placeholder="文章被加密,请输入密码" data-encrypt="<%- encrypt(page.content, page.secret) %>" data-shasum="<%- sha(page.content) %>">
50
- <div class="content" v-pre style="opacity: 0"></div>
55
+ <input
56
+ id="crypto"
57
+ class="input"
58
+ ref="crypto"
59
+ placeholder="文章被加密,请输入密码"
60
+ data-encrypted="<%- encrypt(page.content, page.secret) %>"
61
+ data-shasum="<%- SHA(page.content) %>"
62
+ v-model="crypto"
63
+ />
64
+ <transition name="fade">
65
+ <div class="content" ref="content" v-show="check"></div>
66
+ </transition>
51
67
  <% } else { %>
52
68
  <div class="content" v-pre>
53
69
  <%- page.content %>
package/layout/posts.ejs CHANGED
@@ -61,7 +61,13 @@
61
61
  <% post.tags.data.forEach(data => { %>
62
62
  <span class="tag">
63
63
  <%
64
- const color = ["color: #ffa2c4", "color: #00bcd4", "color: #03a9f4", "color: #00a596", "color: #ff7d73"];
64
+ const color = [
65
+ "color: #ffa2c4",
66
+ "color: #00bcd4",
67
+ "color: #03a9f4",
68
+ "color: #00a596",
69
+ "color: #ff7d73",
70
+ ];
65
71
  let num = Math.floor(Math.random() * color.length);
66
72
  %>
67
73
  <a href="<%- url_for(data.path) %>" style="<%- color[num] %>">
package/layout/tags.ejs CHANGED
@@ -51,7 +51,13 @@
51
51
  <% post.tags.data.forEach(data => { %>
52
52
  <span class="tag">
53
53
  <%
54
- const color = ["color: #ffa2c4", "color: #00bcd4", "color: #03a9f4", "color: #00a596", "color: #ff7d73"];
54
+ const color = [
55
+ "color: #ffa2c4",
56
+ "color: #00bcd4",
57
+ "color: #03a9f4",
58
+ "color: #00a596",
59
+ "color: #ff7d73",
60
+ ];
55
61
  let num = Math.floor(Math.random() * color.length);
56
62
  %>
57
63
  <a href="<%- url_for(data.path) %>" style="<%- color[num] %>"><%= data.name %></a>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hexo-theme-particlex",
3
- "version": "2.4.11",
3
+ "version": "2.5.0",
4
4
  "description": "A concise Hexo theme, based on Particle.",
5
5
  "repository": {
6
6
  "type": "git",
@@ -1,53 +1,3 @@
1
- @keyframes into {
2
- from {
3
- opacity: 0;
4
- transform: scale(1.1);
5
- }
6
- to {
7
- opacity: 1;
8
- transform: scale(1);
9
- }
10
- }
11
- @keyframes loading {
12
- from {
13
- opacity: 0;
14
- }
15
- to {
16
- opacity: 1;
17
- }
18
- }
19
- @keyframes loop1 {
20
- from {
21
- transform: rotate(30deg);
22
- }
23
- to {
24
- transform: rotate(390deg);
25
- }
26
- }
27
- @keyframes loop2 {
28
- from {
29
- transform: rotate(60deg);
30
- }
31
- to {
32
- transform: rotate(420deg);
33
- }
34
- }
35
- @keyframes loop3 {
36
- from {
37
- transform: rotate(90deg);
38
- }
39
- to {
40
- transform: rotate(450deg);
41
- }
42
- }
43
- @keyframes loop4 {
44
- from {
45
- transform: rotate(120deg);
46
- }
47
- to {
48
- transform: rotate(480deg);
49
- }
50
- }
51
1
  #archives {
52
2
  margin: auto;
53
3
  margin-top: 100px;
@@ -117,19 +67,19 @@
117
67
  text-align: center;
118
68
  width: 100%;
119
69
  }
120
- #footer .footer-icon {
70
+ #footer #footer-icon {
121
71
  color: #66afef;
122
72
  display: inline-block;
123
73
  font-size: 18px;
124
74
  margin: 0 10px;
125
75
  }
126
- #footer .footer-wrap {
76
+ #footer #footer-wrap {
127
77
  border-top: 1px solid #aaa;
128
78
  color: #5c6b72;
129
79
  margin: auto;
130
80
  width: 900px;
131
81
  }
132
- #footer .footer-wrap div {
82
+ #footer #footer-wrap div {
133
83
  margin: 15px;
134
84
  }
135
85
  #home-card {
@@ -376,9 +326,42 @@
376
326
  #home-posts-wrap,
377
327
  #archives,
378
328
  .article,
379
- #footer .footer-wrap {
329
+ #footer #footer-wrap {
380
330
  box-sizing: border-box;
381
331
  }
332
+ #loading {
333
+ align-items: center;
334
+ background: #fff;
335
+ display: flex;
336
+ flex-direction: column;
337
+ height: 100vh;
338
+ justify-content: center;
339
+ left: 0;
340
+ position: fixed;
341
+ top: 0;
342
+ width: 100vw;
343
+ z-index: 2147483647;
344
+ }
345
+ #loading h2,
346
+ #loading p,
347
+ #loading img {
348
+ margin: 10px;
349
+ }
350
+ #loading img {
351
+ border-radius: 0;
352
+ height: 50px;
353
+ }
354
+ #loading-circle {
355
+ align-items: center;
356
+ border: 10px solid #a3ddfb;
357
+ border-radius: 50%;
358
+ display: flex;
359
+ flex-direction: column;
360
+ height: 50vmin;
361
+ justify-content: center;
362
+ padding: 50px;
363
+ width: 50vmin;
364
+ }
382
365
  #main {
383
366
  margin-right: calc(100% - 100vw);
384
367
  overflow: auto;
@@ -391,8 +374,8 @@
391
374
  position: fixed;
392
375
  top: 0;
393
376
  transition: background 0.25s ease-out, top 0.25s ease-out;
394
- width: 100%;
395
- z-index: 10005;
377
+ width: 100vw;
378
+ z-index: 10004;
396
379
  }
397
380
  #menu .desktop-menu {
398
381
  height: 50px;
@@ -408,11 +391,11 @@
408
391
  display: inline-block;
409
392
  margin-left: 30px;
410
393
  }
411
- #menu .phone-menu {
394
+ #menu #mobile-menu {
412
395
  min-height: 50px;
413
396
  text-align: center;
414
397
  }
415
- #menu .phone-menu .curtain {
398
+ #menu #mobile-menu .curtain {
416
399
  height: 100%;
417
400
  left: 0;
418
401
  position: fixed;
@@ -420,26 +403,26 @@
420
403
  width: 100%;
421
404
  z-index: -1;
422
405
  }
423
- #menu .phone-menu .items {
406
+ #menu #mobile-menu .items {
424
407
  padding: 10px 0 20px;
425
- z-index: 10003;
408
+ z-index: 10002;
426
409
  }
427
- #menu .phone-menu .items .item {
410
+ #menu #mobile-menu .items .item {
428
411
  display: flex;
429
412
  justify-content: center;
430
413
  margin: auto;
431
414
  min-width: 200px;
432
415
  width: 80%;
433
416
  }
434
- #menu .phone-menu .items a {
417
+ #menu #mobile-menu .items a {
435
418
  color: #555;
436
419
  }
437
- #menu .phone-menu .title {
420
+ #menu #mobile-menu .title {
438
421
  color: #555;
439
422
  cursor: pointer;
440
- z-index: 10004;
423
+ z-index: 10003;
441
424
  }
442
- #menu.hidden-menu {
425
+ #menu.hidden {
443
426
  top: -70px !important;
444
427
  }
445
428
  #menu.menu-color {
@@ -450,38 +433,32 @@
450
433
  #menu.menu-color a {
451
434
  color: #fff !important;
452
435
  }
453
- #search-bar {
454
- margin: 0 auto 50px;
455
- }
456
- #search-mask {
457
- background: #f6f8fa;
458
- height: 150px;
459
- margin: auto;
460
- margin-bottom: -25px;
461
- margin-top: -125px;
462
- width: 100%;
463
- }
464
- #showimg {
436
+ #preview {
465
437
  align-items: center;
466
438
  background-color: #fffc;
467
439
  display: flex;
468
440
  height: 100vh;
469
441
  justify-content: center;
470
442
  left: 0;
471
- opacity: 0;
472
443
  position: fixed;
473
444
  top: 0;
474
- transition: opacity 0.25s, visibility 0.25s;
475
- visibility: hidden;
476
445
  width: 100vw;
477
- z-index: 10006;
446
+ z-index: 10005;
478
447
  }
479
- #showimg-content {
448
+ #preview-content {
480
449
  box-shadow: 0 0 50px 10px #d9d9d980;
481
450
  margin: auto;
482
451
  max-height: 95%;
483
452
  max-width: 95%;
484
453
  }
454
+ #search-bar {
455
+ margin: 0 auto 50px;
456
+ z-index: 10001;
457
+ }
458
+ #timeline-wrap {
459
+ display: flex;
460
+ flex-direction: column-reverse;
461
+ }
485
462
  * {
486
463
  margin: 0;
487
464
  padding: 0;
@@ -547,6 +524,14 @@ body::-webkit-scrollbar-track {
547
524
  .copycode:not(.copied) i:last-child {
548
525
  opacity: 0;
549
526
  }
527
+ .fade-enter-active,
528
+ .fade-leave-active {
529
+ transition: opacity 0.3s;
530
+ }
531
+ .fade-enter-from,
532
+ .fade-leave-to {
533
+ opacity: 0;
534
+ }
550
535
  .icon {
551
536
  color: #5c6b72;
552
537
  margin-right: 5px;
@@ -575,7 +560,15 @@ body::-webkit-scrollbar-track {
575
560
  }
576
561
  .into-enter-active,
577
562
  .into-leave-active {
578
- animation: into 0.6s;
563
+ transition: opacity 0.5s, transform 0.5s;
564
+ }
565
+ .into-enter-from,
566
+ .into-leave-to {
567
+ opacity: 0;
568
+ transform: scale(1.1);
569
+ }
570
+ .katex {
571
+ overflow: auto;
579
572
  }
580
573
  .language {
581
574
  background: linear-gradient(to right, #ed6ea0 0%, #ec8c69 100%);
@@ -589,14 +582,18 @@ body::-webkit-scrollbar-track {
589
582
  position: absolute;
590
583
  top: 0;
591
584
  }
592
- .katex {
593
- overflow: auto;
594
- }
595
585
  .page-num,
596
586
  .icon-link a,
597
587
  .friend-link a {
598
588
  transition: background 0.25s, color 0.25s;
599
589
  }
590
+ .page-num:hover,
591
+ .icon-link a:hover,
592
+ .friend-link a:hover,
593
+ .categories-tags a:hover,
594
+ .go-post:hover {
595
+ opacity: 1;
596
+ }
600
597
  .slide-enter-active,
601
598
  .slide-leave-active {
602
599
  transition: margin-top 0.3s, opacity 0.3s;
@@ -608,7 +605,7 @@ body::-webkit-scrollbar-track {
608
605
  }
609
606
  .timeline {
610
607
  margin-bottom: 30px;
611
- transition: margin-top 0.5s, opacity 0.25s;
608
+ transition: margin-top 0.5s, opacity 0.3s, visibility 0.3s;
612
609
  }
613
610
  .timeline-content {
614
611
  background: #fff;
@@ -690,6 +687,7 @@ audio,
690
687
  iframe,
691
688
  #home-head,
692
689
  #menu,
690
+ #loading,
693
691
  .katex,
694
692
  .go-post,
695
693
  .page-current,
@@ -720,13 +718,6 @@ h6 {
720
718
  font-weight: bold;
721
719
  margin: 15px 0;
722
720
  }
723
- .page-num:hover,
724
- .icon-link a:hover,
725
- .friend-link a:hover,
726
- .categories-tags a:hover,
727
- .go-post:hover {
728
- opacity: 1;
729
- }
730
721
  h2 {
731
722
  font-size: 27px;
732
723
  }
@@ -801,6 +792,38 @@ ul li,
801
792
  ol li {
802
793
  margin: 8px 0;
803
794
  }
795
+ @keyframes loop1 {
796
+ from {
797
+ transform: rotate(30deg);
798
+ }
799
+ to {
800
+ transform: rotate(390deg);
801
+ }
802
+ }
803
+ @keyframes loop2 {
804
+ from {
805
+ transform: rotate(60deg);
806
+ }
807
+ to {
808
+ transform: rotate(420deg);
809
+ }
810
+ }
811
+ @keyframes loop3 {
812
+ from {
813
+ transform: rotate(90deg);
814
+ }
815
+ to {
816
+ transform: rotate(450deg);
817
+ }
818
+ }
819
+ @keyframes loop4 {
820
+ from {
821
+ transform: rotate(120deg);
822
+ }
823
+ to {
824
+ transform: rotate(480deg);
825
+ }
826
+ }
804
827
  @media (min-width: 900px) {
805
828
  #home-card {
806
829
  margin-right: auto;
@@ -851,12 +874,12 @@ ol li {
851
874
  #menu .desktop-menu {
852
875
  display: block;
853
876
  }
854
- #menu .phone-menu {
877
+ #menu #mobile-menu {
855
878
  display: none;
856
879
  }
857
880
  .article,
858
881
  #archives,
859
- #footer .footer-wrap {
882
+ #footer #footer-wrap {
860
883
  width: 900px;
861
884
  }
862
885
  .home-posts-wrap-no-card #home-posts {
@@ -932,14 +955,14 @@ ol li {
932
955
  #home-posts-wrap,
933
956
  .article,
934
957
  #archives,
935
- #footer .footer-wrap {
958
+ #footer #footer-wrap {
936
959
  width: 100%;
937
960
  }
938
961
  #menu .desktop-menu,
939
962
  #home-card {
940
963
  display: none;
941
964
  }
942
- #menu .phone-menu {
965
+ #menu #mobile-menu {
943
966
  display: block;
944
967
  }
945
968
  ul,
@@ -0,0 +1,41 @@
1
+ const cryptoMixin = {
2
+ data() {
3
+ return {
4
+ crypto: "",
5
+ check: false,
6
+ };
7
+ },
8
+ methods: {
9
+ SHA(word) {
10
+ return CryptoJS.SHA256(word).toString();
11
+ },
12
+ decrypt(word, secret, shasum) {
13
+ try {
14
+ let res = CryptoJS.AES.decrypt(word, secret).toString(CryptoJS.enc.Utf8);
15
+ return { check: this.SHA(res) === shasum, decrypted: res };
16
+ } catch {
17
+ return { check: false };
18
+ }
19
+ },
20
+ },
21
+ watch: {
22
+ crypto(value) {
23
+ let input = this.$refs.crypto,
24
+ content = this.$refs.content;
25
+ let { decrypted, check } = this.decrypt(
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");
38
+ },
39
+ },
40
+ };
41
+ mixins.push(cryptoMixin);
@@ -0,0 +1,32 @@
1
+ const highlightMixin = {
2
+ data() {
3
+ return { copying: false };
4
+ },
5
+ mounted() {
6
+ hljs.configure({ ignoreUnescapedHTML: true });
7
+ },
8
+ methods: {
9
+ highlight() {
10
+ let that = this;
11
+ let codes = document.getElementsByTagName("pre");
12
+ for (let i of codes) {
13
+ let lang = [...i.classList, ...i.firstChild.classList][0] || "plaintext";
14
+ let code = i.innerText;
15
+ i.innerHTML = `<div class="code-content">${code}</div><div class="language">${lang}</div><div class="copycode"><i class="fa-solid fa-copy fa-fw"></i><i class="fa-solid fa-clone fa-fw"></i></div>`;
16
+ let copycode = i.getElementsByClassName("copycode")[0];
17
+ copycode.addEventListener("click", async function () {
18
+ if (that.copying) return;
19
+ that.copying = true;
20
+ this.classList.add("copied");
21
+ await navigator.clipboard.writeText(code);
22
+ await new Promise(resolve => setTimeout(resolve, 1000));
23
+ this.classList.remove("copied");
24
+ that.copying = false;
25
+ });
26
+ let content = i.getElementsByClassName("code-content")[0];
27
+ hljs.highlightElement(content);
28
+ }
29
+ },
30
+ },
31
+ };
32
+ mixins.push(highlightMixin);
@@ -0,0 +1,15 @@
1
+ const mathMixin = {
2
+ methods: {
3
+ math() {
4
+ renderMathInElement(document.body, {
5
+ delimiters: [
6
+ { left: "$$", right: "$$", display: true },
7
+ { left: "$", right: "$", display: false },
8
+ { left: "\\(", right: "\\)", display: false },
9
+ { left: "\\[", right: "\\]", display: true },
10
+ ],
11
+ });
12
+ },
13
+ },
14
+ };
15
+ mixins.push(mathMixin);
@@ -0,0 +1,26 @@
1
+ const previewMixin = {
2
+ data() {
3
+ return { previewShow: false };
4
+ },
5
+ methods: {
6
+ preview() {
7
+ let that = this;
8
+ let preview = this.$refs.preview,
9
+ content = this.$refs.previewContent,
10
+ images = document.getElementsByTagName("img");
11
+ for (let i of images)
12
+ i.addEventListener("click", function () {
13
+ content.alt = this.alt;
14
+ content.src = this.src;
15
+ that.previewShow = true;
16
+ });
17
+ preview.addEventListener("click", () => {
18
+ this.previewShow = false;
19
+ });
20
+ window.addEventListener("resize", () => {
21
+ this.previewShow = false;
22
+ });
23
+ },
24
+ },
25
+ };
26
+ mixins.push(previewMixin);
@@ -0,0 +1,28 @@
1
+ const searchMixin = {
2
+ data() {
3
+ return {
4
+ rawSearch: "",
5
+ };
6
+ },
7
+ watch: {
8
+ search(value) {
9
+ let timeline = this.$refs.timeline.childNodes;
10
+ for (let i of timeline)
11
+ if (!value || i.dataset.title.includes(value)) {
12
+ i.style.opacity = 1;
13
+ i.style.visibility = "visible";
14
+ i.style.marginTop = 0;
15
+ } else {
16
+ i.style.opacity = 0;
17
+ i.style.visibility = "hidden";
18
+ i.style.marginTop = -i.offsetHeight - 30 + "px";
19
+ }
20
+ },
21
+ },
22
+ computed: {
23
+ search() {
24
+ return this.rawSearch.toLowerCase().replace(/s+/gm, "");
25
+ },
26
+ },
27
+ };
28
+ mixins.push(searchMixin);
@@ -0,0 +1,47 @@
1
+ const app = Vue.createApp({
2
+ mixins,
3
+ data() {
4
+ return {
5
+ loading: true,
6
+ showMenu: false,
7
+ barLocal: 0,
8
+ };
9
+ },
10
+ created() {
11
+ window.addEventListener("load", () => {
12
+ this.loading = false;
13
+ });
14
+ },
15
+ mounted() {
16
+ if (this.$refs.head) this.$refs.menu.classList.add("menu-color");
17
+ window.addEventListener("scroll", this.handleScroll, true);
18
+ this.render();
19
+ },
20
+ methods: {
21
+ homeClick() {
22
+ window.scrollTo({ top: window.innerHeight, behavior: "smooth" });
23
+ },
24
+ handleScroll() {
25
+ let menu = this.$refs.menu,
26
+ wrap = this.$refs.wrap;
27
+ let newlocal = document.documentElement.scrollTop;
28
+ if (this.barLocal < newlocal) {
29
+ this.showMenu = false;
30
+ menu.classList.add("hidden");
31
+ } else menu.classList.remove("hidden");
32
+ if (wrap) {
33
+ if (newlocal <= window.innerHeight - 100) menu.classList.add("menu-color");
34
+ else menu.classList.remove("menu-color");
35
+ if (newlocal <= 400) wrap.style.marginTop = -newlocal / 5 + "px";
36
+ else wrap.style.marginTop = "-80px";
37
+ }
38
+ this.barLocal = newlocal;
39
+ },
40
+ render() {
41
+ if (typeof this.highlight !== "undefined") this.highlight();
42
+ if (typeof this.math !== "undefined") this.math();
43
+ this.preview();
44
+ },
45
+ },
46
+ });
47
+ app.mount("#layout");
@@ -1,9 +0,0 @@
1
- <div id="loading" style="height: 100vh; width: 100vw; left: 0; top: 0; position: fixed; display: flex; z-index: 2147483647; background: #fff; transition: opacity 0.3s ease-out; -webkit-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; pointer-events: none">
2
- <div style="width: 50vmin; height: 50vmin; margin: auto; padding: 50px; border-radius: 50%; display: flex; border: solid 10px #a3ddfb">
3
- <div style="margin: auto; text-align: center">
4
- <h2>LOADING</h2>
5
- <p>加载过慢请开启缓存,浏览器默认开启</p>
6
- <img src="<%- url_for("/images/loading.gif") %>" style="height: 50px; border-radius: 0">
7
- </div>
8
- </div>
9
- </div>
@@ -1,71 +0,0 @@
1
- function sleep(ms) {
2
- return new Promise(resolve => setTimeout(resolve, ms));
3
- }
4
- let copying = false;
5
- function highlight() {
6
- hljs.configure({ ignoreUnescapedHTML: true });
7
- let codes = document.getElementsByTagName("pre");
8
- for (let i of codes) {
9
- let lang = [...i.classList, ...i.firstChild.classList][0] || "plaintext";
10
- i.innerHTML = `<div class="code-content">${i.innerHTML}</div><div class="language">${lang}</div><div class="copycode"><i class="fa-solid fa-copy fa-fw"></i><i class="fa-solid fa-clone fa-fw"></i></div>`;
11
- let copycode = i.getElementsByClassName("copycode")[0];
12
- copycode.addEventListener("click", async function () {
13
- if (copying) return;
14
- copying = true;
15
- this.classList.add("copied");
16
- await navigator.clipboard.writeText(this.parentElement.firstChild.innerText);
17
- await sleep(1000);
18
- this.classList.remove("copied");
19
- copying = false;
20
- });
21
- hljs.highlightElement(i.getElementsByClassName("code-content")[0]);
22
- }
23
- }
24
- function showimg() {
25
- let wrap = document.getElementById("showimg"),
26
- content = document.getElementById("showimg-content"),
27
- images = document.querySelectorAll(".article .content img");
28
- function show(image) {
29
- content.alt = image.alt;
30
- content.src = image.src;
31
- wrap.style.opacity = 1;
32
- wrap.style.visibility = "visible";
33
- }
34
- function hide() {
35
- wrap.style.opacity = 0;
36
- wrap.style.visibility = "hidden";
37
- }
38
- for (let i of images)
39
- i.addEventListener("click", function () {
40
- show(this);
41
- });
42
- wrap.addEventListener("click", hide);
43
- window.addEventListener("resize", hide);
44
- }
45
- function rendermath() {
46
- if (typeof renderMathInElement !== "undefined")
47
- renderMathInElement(document.body, {
48
- delimiters: [
49
- { left: "$$", right: "$$", display: true },
50
- { left: "$", right: "$", display: false },
51
- { left: "\\(", right: "\\)", display: false },
52
- { left: "\\[", right: "\\]", display: true },
53
- ],
54
- });
55
- }
56
- function renderall() {
57
- highlight();
58
- showimg();
59
- rendermath();
60
- }
61
- function sha(str) {
62
- return CryptoJS.SHA256(str).toString();
63
- }
64
- function decrypt(str, key, shasum) {
65
- try {
66
- let res = CryptoJS.AES.decrypt(str, key).toString(CryptoJS.enc.Utf8);
67
- return { decrypt: res, check: sha(res) === shasum };
68
- } catch {
69
- return { check: false };
70
- }
71
- }
@@ -1,98 +0,0 @@
1
- const app = Vue.createApp({
2
- data() {
3
- return {
4
- showpage: false,
5
- menushow: false,
6
- cardtop: 100,
7
- barlocal: 0,
8
- composition: false,
9
- };
10
- },
11
- created() {
12
- window.addEventListener("load", () => {
13
- this.showpage = true;
14
- document.getElementById("loading").style.opacity = 0;
15
- });
16
- },
17
- mounted() {
18
- if (document.getElementById("home-head"))
19
- document.getElementById("menu").className += " menu-color";
20
- if (document.getElementById("crypto")) {
21
- let input = document.getElementById("crypto");
22
- input.addEventListener("input", () => {
23
- if (!this.composition) this.handlecrypto();
24
- });
25
- input.addEventListener("compositionstart", () => {
26
- this.composition = true;
27
- });
28
- input.addEventListener("compositionend", () => {
29
- this.handlecrypto();
30
- this.composition = false;
31
- });
32
- }
33
- if (document.getElementById("search-bar")) {
34
- let input = document.getElementById("search-bar");
35
- input.addEventListener("input", () => {
36
- if (!this.composition) this.handlesearch();
37
- });
38
- input.addEventListener("compositionstart", () => {
39
- this.composition = true;
40
- });
41
- input.addEventListener("compositionend", () => {
42
- this.handlesearch();
43
- this.composition = false;
44
- });
45
- }
46
- window.addEventListener("scroll", this.handlescroll, true);
47
- renderall();
48
- },
49
- methods: {
50
- homeclick() {
51
- window.scrollTo({ top: window.innerHeight, behavior: "smooth" });
52
- },
53
- handlescroll() {
54
- let newlocal = document.documentElement.scrollTop;
55
- let menu = document.getElementById("menu");
56
- let wrap = document.getElementById("home-posts-wrap");
57
- if (this.barlocal < newlocal) {
58
- menu.className = "hidden-menu";
59
- this.menushow = false;
60
- } else menu.className = "show-menu";
61
- if (wrap) {
62
- if (newlocal <= window.innerHeight - 100) menu.className += " menu-color";
63
- if (newlocal <= 400) wrap.style.marginTop = newlocal / -5 + "px";
64
- else wrap.style.marginTop = "-80px";
65
- }
66
- this.barlocal = newlocal;
67
- },
68
- handlecrypto() {
69
- let input = document.getElementById("crypto"),
70
- content = document.getElementsByClassName("content")[0];
71
- let res = decrypt(input.dataset.encrypt, input.value, input.dataset.shasum);
72
- if (res.check) {
73
- input.disabled = true;
74
- input.classList.remove("fail");
75
- input.classList.add("success");
76
- content.innerHTML = res.decrypt;
77
- content.style.opacity = 1;
78
- renderall();
79
- } else input.classList.add("fail");
80
- },
81
- handlesearch() {
82
- let input = document.getElementById("search-bar"),
83
- timeline = document.getElementsByClassName("timeline"),
84
- key = input.value.toLowerCase().replace(/s+/gm, "");
85
- for (let i of timeline)
86
- if (!key || i.dataset.title.includes(key)) {
87
- i.style.opacity = 1;
88
- i.style.pointerEvents = "";
89
- i.style.marginTop = "";
90
- } else {
91
- i.style.opacity = 0;
92
- i.style.pointerEvents = "none";
93
- i.style.marginTop = -i.offsetHeight - 30 + "px";
94
- }
95
- },
96
- },
97
- });
98
- app.mount("#layout");