hexo-theme-particlex 2.1.0 → 2.1.2

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
@@ -139,7 +139,7 @@ highlightStyle: github # Highlight style
139
139
 
140
140
  一般来说,缩略展示文档只需要在文档中添加 `<!-- more -->` 即可,缩略内容在显示全文中也会出现
141
141
 
142
- 但考虑到不想把缩略内容放在正文里,就添加了此参数,在 Front-Matter 里设置
142
+ 但考虑到不想把缩略内容放在正文里,就添加了此参数,在 [Front-Matter](https://hexo.io/zh-cn/docs/front-matter) 里设置
143
143
 
144
144
  支持 Markdown 格式
145
145
 
@@ -184,9 +184,13 @@ highlightStyle: github # Highlight style
184
184
  enable: false
185
185
  ```
186
186
 
187
+ - 文章置顶
188
+
189
+ 在 [Front-Matter](https://hexo.io/zh-cn/docs/front-matter) 里设置 `top` 作为置顶参数,越大越靠前,默认为 0
190
+
187
191
  - 文章加密
188
192
 
189
- 使用 AES 加密算法,在 Front-Matter 里设置 `password` 作为密码,**使用请安装插件 [Hexo-Helper-Crypto](https://github.com/argvchs/hexo-helper-crypto)**
193
+ 使用 AES 加密算法,在 [Front-Matter](https://hexo.io/zh-cn/docs/front-matter) 里设置 `password` 作为密码,**使用请安装插件 [Hexo-Helper-Crypto](https://github.com/argvchs/hexo-helper-crypto)**
190
194
 
191
195
  ```yaml
192
196
  crypto:
@@ -195,24 +199,13 @@ highlightStyle: github # Highlight style
195
199
 
196
200
  - 搜索
197
201
 
198
- 嵌入到 Archives 中的搜索,搜索数据是用 [Hexo-Generator-Search-Lite](https://github.com/argvchs/hexo-generator-search-lite) 生成,默认关闭,使用需要安装上述插件并**设置 `optimize: true`**
202
+ 嵌入到 Archives 中的搜索,默认关闭
199
203
 
200
- 目前只支持搜索文档的 Title Categories Tags(我太弱了)
201
-
202
- 要同时在主题和根目录的两个 `_config.yml` 添加配置
204
+ 目前只支持搜索文档标题(我太弱了)
203
205
 
204
206
  ```yaml
205
- # Theme config
206
207
  search:
207
208
  enable: false
208
- path: /search.json
209
- ```
210
-
211
- ```yaml
212
- # Site config
213
- search:
214
- path: /search.json
215
- optimize: true
216
209
  ```
217
210
 
218
211
  - Gitalk
package/_config.yml CHANGED
@@ -87,7 +87,6 @@ crypto:
87
87
  # Search
88
88
  search:
89
89
  enable: false
90
- path: /search.json
91
90
 
92
91
  # Gitalk
93
92
  # https://github.com/gitalk/gitalk
@@ -1,12 +1,10 @@
1
1
  <div id="archives">
2
2
  <% if (theme.search.enable) { %>
3
- <div class="search-mask" style="z-index: <%= site.posts.length + 1 %>"></div>
4
- <input class="ipt search-bar" placeholder="搜索..." style="z-index: <%= site.posts.length + 2 %>">
5
- <script src="<%- url_for("/js/searcher.js") %>"></script>
6
- <script>searcher.init("<%- url_for(theme.search.path) %>");</script>
3
+ <div id="search-mask" style="z-index: <%= site.posts.length + 1 %>"></div>
4
+ <input id="search-bar" class="ipt" placeholder="搜索" style="z-index: <%= site.posts.length + 2 %>">
7
5
  <% } %>
8
6
  <% site.posts.forEach((post, id) => { %>
9
- <div class="timeline" path="<%- url_for(post.path) %>" style="z-index: <%= site.posts.length - id %>">
7
+ <div class="timeline" style="z-index: <%= site.posts.length - id %>" data-title="<%- post.title.toLowerCase().replace(/\s+/gm, "") %>">
10
8
  <div class="timeline-tail"></div>
11
9
  <div class="timeline-content">
12
10
  <div class="item-time"><%- date(post.date, "YYYY/M/D") %></div>
@@ -16,7 +16,17 @@
16
16
  <%= category.name %>
17
17
  </a>
18
18
  </span>
19
- <% if (is_category(category.name)) { posts = category.posts; } %><% }); %>
19
+ <% if (is_category(category.name)) { %>
20
+ <%
21
+ posts = category.posts;
22
+ posts.data.sort((a, b) => {
23
+ if (typeof a.top === "undefined") a.top = 0;
24
+ if (typeof b.top === "undefined") b.top = 0;
25
+ return a.top == b.top ? b.date - a.date : b.top - a.top
26
+ });
27
+ %>
28
+ <% } %>
29
+ <% }); %>
20
30
  </div>
21
31
  <% posts.forEach(post => { %>
22
32
  <div class="timeline">
package/layout/layout.ejs CHANGED
@@ -20,7 +20,11 @@
20
20
  else if (is_archive() || is_year() || is_month())
21
21
  title = "Archives | ";
22
22
  title += config.title;
23
- site.posts.data.sort((a, b) => b.date - a.date);
23
+ site.posts.data.sort((a, b) => {
24
+ if (typeof a.top === "undefined") a.top = 0;
25
+ if (typeof b.top === "undefined") b.top = 0;
26
+ return a.top == b.top ? b.date - a.date : b.top - a.top;
27
+ });
24
28
  %>
25
29
  <!DOCTYPE html>
26
30
  <html lang="<%- config.language %>">
package/layout/post.ejs CHANGED
@@ -41,21 +41,19 @@
41
41
  <% if (typeof page.password !== "undefined" && theme.crypto.enable) { %>
42
42
  <%
43
43
  const CryptoJS = crypto();
44
- function SHA(str) {
44
+ function sha(str) {
45
45
  return CryptoJS.SHA256(str).toString(CryptoJS.enc.Base64);
46
46
  }
47
47
  function encrypt(str, key) {
48
- return CryptoJS.AES.encrypt(str, SHA(key), {
48
+ return CryptoJS.AES.encrypt(str, sha(key), {
49
49
  mode: CryptoJS.mode.ECB,
50
50
  padding: CryptoJS.pad.Pkcs7,
51
51
  }).toString();
52
52
  }
53
53
  %>
54
- <input class="ipt crypto" placeholder="文章被加密,请输入密码">
55
- <div class="content" v-pre></div>
56
54
  <script src="https://cdn.staticfile.org/crypto-js/4.1.1/crypto-js.min.js"></script>
57
- <script src="<%- url_for("/js/cryptor.js") %>"></script>
58
- <script>cryptor.init("<%- encrypt(page.content, page.password.toString()) %>", "<%- SHA(page.content) %>")</script>
55
+ <input id="crypto" class="ipt" placeholder="文章被加密,请输入密码" data-encrypt="<%- encrypt(page.content, page.password.toString()) %>" data-check="<%- sha(page.content) %>">
56
+ <div class="content" style="opacity: 0" v-pre></div>
59
57
  <% } else { %>
60
58
  <div class="content" v-pre>
61
59
  <%- page.content %>
package/layout/tags.ejs CHANGED
@@ -16,7 +16,17 @@
16
16
  <%= tag.name %>
17
17
  </a>
18
18
  </span>
19
- <% if (is_tag(tag.name)) { posts = tag.posts; } %><% }); %>
19
+ <% if (is_tag(tag.name)) { %>
20
+ <%
21
+ posts = tag.posts;
22
+ posts.data.sort((a, b) => {
23
+ if (typeof a.top === "undefined") a.top = 0;
24
+ if (typeof b.top === "undefined") b.top = 0;
25
+ return a.top == b.top ? b.date - a.date : b.top - a.top;
26
+ });
27
+ %>
28
+ <% } %>
29
+ <% }); %>
20
30
  </div>
21
31
  <% posts.forEach(post => { %>
22
32
  <div class="timeline">
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hexo-theme-particlex",
3
- "version": "2.1.0",
3
+ "version": "2.1.2",
4
4
  "description": "A concise Hexo theme, based on Particle.",
5
5
  "scripts": {
6
6
  "test": "echo \"Error: no test specified\" && exit 1"
@@ -24,7 +24,6 @@
24
24
  },
25
25
  "homepage": "https://github.com/argvchs/hexo-theme-particlex#readme",
26
26
  "dependencies": {
27
- "hexo-generator-search-lite": "^1.0.8",
28
27
  "hexo-helper-crypto": "^1.0.4",
29
28
  "hexo-renderer-babeljs": "^1.0.7",
30
29
  "hexo-renderer-ejs": "^2.0.0"
@@ -61,6 +61,7 @@ body {
61
61
  margin: 0;
62
62
  padding: 0;
63
63
  word-wrap: break-word;
64
+ word-break: keep-all;
64
65
  scrollbar-width: thin;
65
66
  scrollbar-color: #8ab5ff #e6efff;
66
67
  }
@@ -200,9 +201,6 @@ footer .footer-wrap {
200
201
  color: #333;
201
202
  border-radius: 50%;
202
203
  }
203
- #home-head .home-info .info h1 {
204
- word-break: keep-all;
205
- }
206
204
  #home-head .home-info .loop:nth-child(1) {
207
205
  border-radius: 38% 62% 63% 37%/41% 44% 56% 59%;
208
206
  background: #fff;
@@ -292,8 +290,10 @@ footer .footer-wrap {
292
290
  #home-posts .post .excerpt {
293
291
  color: #1e3e3f;
294
292
  }
293
+ #home-posts .post .post-tags {
294
+ line-height: 1.5;
295
+ }
295
296
  #home-posts .post .post-tags a {
296
- color: #ffbbf4;
297
297
  font-size: 14px;
298
298
  }
299
299
  #home-posts .post .post-tags .tag {
@@ -477,7 +477,6 @@ footer .footer-wrap {
477
477
  #menu .desktop-menu .title {
478
478
  display: inline-block;
479
479
  margin-left: 30px;
480
- margin-right: 20px;
481
480
  font-family: "Lexend", "Noto Sans SC", sans-serif;
482
481
  text-transform: uppercase;
483
482
  color: #555;
@@ -718,16 +717,24 @@ footer .footer-icon {
718
717
  color: #5c6b72;
719
718
  text-decoration: none;
720
719
  }
721
- #archives .tag-icon {
722
- color: #5c6b72;
723
- text-decoration: none;
720
+ #archives .info {
721
+ line-height: 1.5;
724
722
  }
725
723
  #archives .category {
726
- margin-right: 20px;
724
+ display: inline-block;
725
+ margin-right: 10px;
726
+ }
727
+ #archives .tags {
728
+ display: inline-block;
727
729
  }
728
730
  #archives .tags .tag {
731
+ display: inline-block;
729
732
  margin-right: 10px;
730
733
  }
734
+ #archives .tag-icon {
735
+ color: #5c6b72;
736
+ text-decoration: none;
737
+ }
731
738
  #archives h3 {
732
739
  margin: 10px 0;
733
740
  }
@@ -778,6 +785,9 @@ footer .footer-icon {
778
785
  font-weight: bold;
779
786
  margin: 20px 0;
780
787
  }
788
+ .article .info {
789
+ line-height: 1.5;
790
+ }
781
791
  .article .info a {
782
792
  color: #5c6b72;
783
793
  text-decoration: none;
@@ -785,25 +795,18 @@ footer .footer-icon {
785
795
  .article .info .date {
786
796
  color: #5c6b72;
787
797
  display: inline-block;
788
- margin-right: 20px;
789
- }
790
- .article .info .date .tag {
791
798
  margin-right: 10px;
792
799
  }
793
800
  .article .info .category {
794
- color: #5c6b72;
795
801
  display: inline-block;
796
- margin-right: 20px;
797
- }
798
- .article .info .category .tag {
799
802
  margin-right: 10px;
800
803
  }
801
804
  .article .info .tags {
802
- color: #5c6b72;
803
805
  display: inline-block;
804
- margin-right: 20px;
806
+ margin-right: 10px;
805
807
  }
806
808
  .article .info .tags .tag {
809
+ display: inline-block;
807
810
  margin-right: 10px;
808
811
  }
809
812
  .article .content {
@@ -862,24 +865,24 @@ input.ipt:focus {
862
865
  border-color: #0969da;
863
866
  box-shadow: 0 0 0 3px #0969da4d;
864
867
  }
865
- input.crypto {
868
+ #crypto {
866
869
  margin: 50px auto 0;
867
870
  }
868
- input.crypto.fail {
871
+ #crypto.fail {
869
872
  color: #ea4a5a;
870
873
  border-color: #ea4a5a;
871
874
  }
872
- input.crypto.fail:focus {
875
+ #crypto.fail:focus {
873
876
  box-shadow: 0 0 0 3px #ea4a5a4d;
874
877
  }
875
- input.crypto.success {
878
+ #crypto.success {
876
879
  color: #34d058;
877
880
  border-color: #34d058;
878
881
  }
879
- input.search-bar {
882
+ #search-bar {
880
883
  margin: 0 auto 50px;
881
884
  }
882
- .search-mask {
885
+ #search-mask {
883
886
  position: relative;
884
887
  margin: auto;
885
888
  margin-top: -125px;
@@ -888,58 +891,6 @@ input.search-bar {
888
891
  height: 150px;
889
892
  background: #f6f8fa;
890
893
  }
891
- .gt-container *:not(.gt-header-textarea) {
892
- font-family: unset !important;
893
- }
894
- .gt-header-textarea {
895
- font-family: "Fira Code", "Noto Sans SC", monospace;
896
- }
897
- .gt-container .gt-comment-content {
898
- border: 1px solid #0000001a;
899
- border-radius: 5px;
900
- }
901
- .gt-container .gt-comment-content:hover,
902
- .gt-container .gt-header-textarea:hover,
903
- .gt-container .gt-header-textarea:focus {
904
- box-shadow: 0 2px 8px #00000017 !important;
905
- background-color: #fbfbfb;
906
- }
907
- .gt-container .gt-header-textarea:focus {
908
- background-color: #fbfbfb;
909
- }
910
- .gt-container .gt-avatar img {
911
- border-radius: 50% !important;
912
- }
913
- .gt-container .gt-popup {
914
- border-radius: 10px;
915
- }
916
- .gt-container .markdown-body {
917
- color: unset !important;
918
- }
919
- .gt-container .markdown-body p {
920
- margin: 10px 0 !important;
921
- }
922
- .gt-container .markdown-body blockquote {
923
- border-left: unset !important;
924
- padding: 1px 20px !important;
925
- border-left: 3px solid #1e3e3f !important;
926
- color: unset !important;
927
- }
928
- .gt-container .markdown-body code {
929
- font-family: "Fira Code" !important;
930
- background: #bddcf76b;
931
- border-radius: 4px;
932
- font-size: 14px;
933
- color: #4b616b;
934
- }
935
- .gt-container .markdown-body pre {
936
- font-family: "Fira Code" !important;
937
- font-weight: 500;
938
- border: 1px solid #ebeef5;
939
- padding: 20px;
940
- margin: 25px 0;
941
- border-radius: 15px !important;
942
- }
943
894
  #showimg {
944
895
  position: fixed !important;
945
896
  display: flex;
@@ -962,6 +913,9 @@ input.search-bar {
962
913
  max-height: 95%;
963
914
  box-shadow: 0 0 50px 10px #d9d9d980;
964
915
  }
916
+ .math.display .katex {
917
+ overflow: auto;
918
+ }
965
919
  ::-webkit-scrollbar {
966
920
  width: 12px;
967
921
  height: 12px;
@@ -1,12 +1,14 @@
1
- const sleep = ms => new Promise(res => setTimeout(res, ms));
1
+ function sleep(ms) {
2
+ return new Promise(resolve => setTimeout(resolve, ms));
3
+ }
2
4
  let copying = false;
3
5
  function highlight() {
4
6
  hljs.configure({ ignoreUnescapedHTML: true });
5
7
  let codes = document.getElementsByTagName("pre");
6
- for (let code of codes) {
7
- let lang = [...code.classList, ...code.firstChild.classList][0] || "text";
8
- code.innerHTML = `<div class="code-content">${code.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>`;
9
- let copycode = code.getElementsByClassName("copycode")[0];
8
+ for (let i of codes) {
9
+ let lang = [...i.classList, ...i.firstChild.classList][0] || "text";
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];
10
12
  copycode.addEventListener("click", async function () {
11
13
  if (copying) return;
12
14
  copying = true;
@@ -16,13 +18,13 @@ function highlight() {
16
18
  this.classList.remove("copied");
17
19
  copying = false;
18
20
  });
19
- hljs.highlightElement(code.getElementsByClassName("code-content")[0]);
21
+ hljs.highlightElement(i.getElementsByClassName("code-content")[0]);
20
22
  }
21
23
  }
22
24
  function showimg() {
23
25
  let wrap = document.getElementById("showimg"),
24
26
  content = document.getElementById("showimg-content"),
25
- imgs = document.querySelectorAll(".article .content img");
27
+ images = document.querySelectorAll(".article .content img");
26
28
  function show(src) {
27
29
  content.setAttribute("src", src);
28
30
  wrap.style.opacity = 1;
@@ -32,12 +34,13 @@ function showimg() {
32
34
  wrap.style.opacity = 0;
33
35
  wrap.style.visibility = "hidden";
34
36
  }
35
- for (let img of imgs)
36
- img.addEventListener("click", function () {
37
+ for (let i of images)
38
+ i.addEventListener("click", function () {
37
39
  show(this.getAttribute("src"));
38
40
  });
39
- wrap.addEventListener("click", () => hide());
40
- window.addEventListener("resize", () => hide());
41
+ wrap.addEventListener("click", hide);
42
+ window.addEventListener("resize", hide);
43
+ window.addEventListener("scroll", hide);
41
44
  }
42
45
  function rendermath() {
43
46
  if (typeof renderMathInElement !== "undefined")
@@ -50,3 +53,17 @@ function rendermath() {
50
53
  ],
51
54
  });
52
55
  }
56
+ function sha(str) {
57
+ return CryptoJS.SHA256(str).toString(CryptoJS.enc.Base64);
58
+ }
59
+ function decrypt(encrypt, key, check) {
60
+ try {
61
+ let res = CryptoJS.AES.decrypt(encrypt, sha(key), {
62
+ mode: CryptoJS.mode.ECB,
63
+ padding: CryptoJS.pad.Pkcs7,
64
+ }).toString(CryptoJS.enc.Utf8);
65
+ return { decrypt: res, check: sha(res) == check };
66
+ } catch {
67
+ return { check: false };
68
+ }
69
+ }
@@ -5,19 +5,41 @@ const app = Vue.createApp({
5
5
  menushow: false,
6
6
  cardtop: 100,
7
7
  barlocal: 0,
8
+ composition: false,
8
9
  };
9
10
  },
10
- created() {
11
- let that = this;
12
- window.addEventListener("load", () => {
13
- that.showpage = true;
14
- document.getElementById("loading").style.opacity = 0;
15
- document.getElementById("loading").style.visibility = "hidden";
16
- });
17
- },
18
11
  mounted() {
12
+ this.showpage = true;
13
+ document.getElementById("loading").style.opacity = 0;
14
+ document.getElementById("loading").style.visibility = "hidden";
19
15
  if (document.getElementById("home-head"))
20
16
  document.getElementById("menu").className += " menu-color";
17
+ if (document.getElementById("crypto")) {
18
+ let input = document.getElementById("crypto");
19
+ input.addEventListener("input", () => {
20
+ if (!this.composition) this.handlecrypto();
21
+ });
22
+ input.addEventListener("compositionstart", () => {
23
+ this.composition = true;
24
+ });
25
+ input.addEventListener("compositionend", () => {
26
+ this.handlecrypto();
27
+ this.composition = false;
28
+ });
29
+ }
30
+ if (document.getElementById("search-bar")) {
31
+ let input = document.getElementById("search-bar");
32
+ input.addEventListener("input", () => {
33
+ if (!this.composition) this.handlesearch();
34
+ });
35
+ input.addEventListener("compositionstart", () => {
36
+ this.composition = true;
37
+ });
38
+ input.addEventListener("compositionend", () => {
39
+ this.handlesearch();
40
+ this.composition = false;
41
+ });
42
+ }
21
43
  window.addEventListener("scroll", this.handlescroll, true);
22
44
  highlight();
23
45
  showimg();
@@ -25,20 +47,16 @@ const app = Vue.createApp({
25
47
  },
26
48
  methods: {
27
49
  homeclick() {
28
- window.scrollTo({
29
- top: window.innerHeight,
30
- behavior: "smooth",
31
- });
50
+ window.scrollTo({ top: window.innerHeight, behavior: "smooth" });
32
51
  },
33
52
  handlescroll() {
34
53
  let newlocal = document.documentElement.scrollTop;
35
54
  let menu = document.getElementById("menu");
36
55
  let wrap = document.getElementById("home-posts-wrap");
37
56
  let footer = document.getElementById("footer");
38
- let that = this;
39
57
  if (this.barlocal < newlocal) {
40
58
  menu.className = "hidden-menu";
41
- that.menushow = false;
59
+ this.menushow = false;
42
60
  } else menu.className = "show-menu";
43
61
  if (wrap) {
44
62
  if (newlocal <= window.innerHeight - 100) menu.className += " menu-color";
@@ -52,6 +70,36 @@ const app = Vue.createApp({
52
70
  }
53
71
  this.barlocal = newlocal;
54
72
  },
73
+ handlecrypto() {
74
+ let input = document.getElementById("crypto"),
75
+ content = document.getElementsByClassName("content")[0];
76
+ let res = decrypt(input.dataset.encrypt, input.value, input.dataset.check);
77
+ if (res.check) {
78
+ input.disabled = true;
79
+ input.classList.remove("fail");
80
+ input.classList.add("success");
81
+ content.innerHTML = res.decrypt;
82
+ content.style.opacity = 1;
83
+ highlight();
84
+ showimg();
85
+ rendermath();
86
+ } else input.classList.add("fail");
87
+ },
88
+ handlesearch() {
89
+ let input = document.getElementById("search-bar"),
90
+ timeline = document.getElementsByClassName("timeline"),
91
+ key = input.value.toLowerCase().replace(/s+/gm, "");
92
+ for (let i of timeline)
93
+ if (!key || i.dataset.title.includes(key)) {
94
+ i.style.opacity = 1;
95
+ i.style.pointerEvents = "";
96
+ i.style.marginTop = "";
97
+ } else {
98
+ i.style.opacity = 0;
99
+ i.style.pointerEvents = "none";
100
+ i.style.marginTop = -i.offsetHeight - 30 + "px";
101
+ }
102
+ },
55
103
  },
56
104
  });
57
105
  app.mount("#layout");
@@ -1,44 +0,0 @@
1
- const cryptor = {
2
- init(enc, sha) {
3
- this.enc = enc;
4
- this.sha = sha;
5
- this.composition = false;
6
- window.addEventListener("load", () => {
7
- this.input = document.getElementsByClassName("crypto")[0];
8
- this.content = document.getElementsByClassName("content")[0];
9
- this.content.style.opacity = 0;
10
- this.input.addEventListener("input", () => this.composition || this.update());
11
- this.input.addEventListener("compositionstart", () => (this.composition = true));
12
- this.input.addEventListener("compositionend", () => {
13
- this.update(), (this.composition = false);
14
- });
15
- });
16
- },
17
- SHA(str) {
18
- return CryptoJS.SHA256(str).toString(CryptoJS.enc.Base64);
19
- },
20
- decrypt(enc, key, sha) {
21
- try {
22
- let res = CryptoJS.AES.decrypt(enc, this.SHA(key), {
23
- mode: CryptoJS.mode.ECB,
24
- padding: CryptoJS.pad.Pkcs7,
25
- }).toString(CryptoJS.enc.Utf8);
26
- return { dec: res, check: this.SHA(res) == sha };
27
- } catch {
28
- return { check: false };
29
- }
30
- },
31
- update() {
32
- let res = this.decrypt(this.enc, this.input.value, this.sha);
33
- if (res.check) {
34
- this.input.disabled = true;
35
- this.input.classList.remove("fail");
36
- this.input.classList.add("success");
37
- this.content.innerHTML = res.dec;
38
- this.content.style.opacity = 1;
39
- highlight();
40
- showimg();
41
- rendermath();
42
- } else this.input.classList.add("fail");
43
- },
44
- };
@@ -1,43 +0,0 @@
1
- const searcher = {
2
- init(path) {
3
- this.composition = false;
4
- window.addEventListener("load", () => {
5
- this.input = document.getElementsByClassName("search-bar")[0];
6
- this.timeline = document.getElementsByClassName("timeline");
7
- this.input.addEventListener("input", () => this.composition || this.update());
8
- this.input.addEventListener("compositionstart", () => (this.composition = true));
9
- this.input.addEventListener("compositionend", () => {
10
- this.update();
11
- this.composition = false;
12
- });
13
- fetch(path)
14
- .then(res => res.json())
15
- .then(data => {
16
- this.data = data;
17
- });
18
- });
19
- },
20
- rstr(s) {
21
- if (!s) return "";
22
- return s.toLowerCase().replace(/\s+/gm, "");
23
- },
24
- match(s, rs) {
25
- return s.indexOf(rs) != -1;
26
- },
27
- update() {
28
- let res = [],
29
- rs = this.rstr(this.input.value);
30
- if (rs) res = this.data.filter(i => this.match(i.odata, rs)).map(i => i.path);
31
- else res = this.data.map(i => i.path);
32
- for (let line of this.timeline)
33
- if (res.indexOf(line.getAttribute("path")) == -1) {
34
- line.style.opacity = 0;
35
- line.style.pointerEvents = "none";
36
- line.style.marginTop = -line.offsetHeight - 30 + "px";
37
- } else {
38
- line.style.opacity = 1;
39
- line.style.pointerEvents = "";
40
- line.style.marginTop = "";
41
- }
42
- },
43
- };