hexo-theme-particlex 2.4.11 → 2.5.0

Sign up to get free protection for your applications and to get access to all the features.
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");