hexo-theme-stellar 1.30.4 → 1.32.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.
Files changed (78) hide show
  1. package/_config.yml +30 -16
  2. package/_data/icons.yml +3 -3
  3. package/_data/widgets.yml +0 -1
  4. package/layout/_partial/comments/artalk/script.ejs +1 -2
  5. package/layout/_partial/comments/layout.ejs +1 -1
  6. package/layout/_partial/head.ejs +20 -1
  7. package/layout/_partial/main/navbar/ghinfo.ejs +1 -1
  8. package/layout/_partial/scripts/defines.ejs +9 -0
  9. package/layout/_partial/scripts/theme.ejs +3 -3
  10. package/layout/_partial/sidebar/index_leftbar.ejs +9 -9
  11. package/layout/_partial/widgets/ghissues.ejs +1 -1
  12. package/layout/_partial/widgets/ghrepo.ejs +2 -2
  13. package/layout/_partial/widgets/ghuser.ejs +1 -1
  14. package/layout/index.ejs +3 -1
  15. package/layout/layout.ejs +3 -1
  16. package/package.json +4 -2
  17. package/scripts/events/index.js +46 -4
  18. package/scripts/events/lib/fix_image_tags.js +44 -0
  19. package/scripts/events/lib/get_image_ratios.js +88 -0
  20. package/scripts/events/lib/version-check.js +86 -0
  21. package/scripts/helpers/json_ld.js +118 -0
  22. package/scripts/tags/lib/albums.js +2 -1
  23. package/scripts/tags/lib/friends.js +2 -1
  24. package/scripts/tags/lib/ghcard.js +3 -2
  25. package/scripts/tags/lib/image.js +16 -6
  26. package/scripts/tags/lib/posters.js +2 -1
  27. package/scripts/tags/lib/sites.js +2 -1
  28. package/scripts/tags/lib/timeline.js +1 -1
  29. package/scripts/tags/lib/video.js +4 -4
  30. package/source/css/_common/base.styl +1 -2
  31. package/source/css/_common/canonical.styl +32 -0
  32. package/source/css/_common/device.styl +6 -4
  33. package/source/css/_common/highlight.styl +1 -1
  34. package/source/css/_components/layout.styl +11 -10
  35. package/source/css/_components/list.styl +3 -0
  36. package/source/css/_components/main.styl +1 -1
  37. package/source/css/_components/md.styl +4 -2
  38. package/source/css/_components/pages/archives.styl +2 -2
  39. package/source/css/_components/pages/article-story.styl +6 -0
  40. package/source/css/_components/pages/article-tech.styl +1 -1
  41. package/source/css/_components/pages/notebook.styl +1 -1
  42. package/source/css/_components/partial/article-banner.styl +4 -1
  43. package/source/css/_components/partial/footer.styl +1 -1
  44. package/source/css/_components/partial/navbar.styl +2 -1
  45. package/source/css/_components/sidebar/nav-area.styl +1 -1
  46. package/source/css/_components/sidebar/search.styl +44 -21
  47. package/source/css/_components/sidebar/sidebar.styl +22 -18
  48. package/source/css/_components/tag-plugins/banner.styl +1 -1
  49. package/source/css/_components/tag-plugins/button.styl +3 -4
  50. package/source/css/_components/tag-plugins/copy.styl +1 -1
  51. package/source/css/_components/tag-plugins/friends.styl +1 -1
  52. package/source/css/_components/tag-plugins/gallery.styl +6 -0
  53. package/source/css/_components/tag-plugins/image.styl +10 -0
  54. package/source/css/_components/tag-plugins/media.styl +1 -1
  55. package/source/css/_components/tag-plugins/note.styl +1 -1
  56. package/source/css/_components/tag-plugins/override.styl +1 -1
  57. package/source/css/_components/tag-plugins/quot.styl +2 -2
  58. package/source/css/_components/tag-plugins/tabs.styl +4 -3
  59. package/source/css/_components/tag-plugins/timeline.styl +2 -2
  60. package/source/css/_components/tag-plugins/toc.styl +1 -1
  61. package/source/css/_components/widgets/list.styl +1 -3
  62. package/source/css/_components/widgets/markdown.styl +0 -7
  63. package/source/css/_components/widgets/toc.styl +6 -4
  64. package/source/css/_components/widgets/widgets.styl +0 -5
  65. package/source/css/_custom.styl +5 -7
  66. package/source/css/_defines/const.styl +1 -1
  67. package/source/css/_defines/func.styl +9 -5
  68. package/source/css/_defines/theme.styl +4 -15
  69. package/source/css/_plugins/comments/artalk.styl +114 -2
  70. package/source/css/_plugins/comments/twikoo.styl +3 -3
  71. package/source/css/_plugins/index.styl +5 -5
  72. package/source/css/_plugins/lazyload.styl +49 -2
  73. package/source/js/main.js +50 -0
  74. package/source/js/plugins/download-file.js +1 -1
  75. package/source/js/search/local-search.js +163 -151
  76. package/source/js/services/artalk_latest_comment.js +1 -1
  77. package/source/js/services/mdrender.js +0 -1
  78. package/layout/_partial/widgets/search.ejs +0 -0
@@ -1,4 +1,116 @@
1
1
  .cmt-body.artalk .artalk
2
- --at-color-main: $color-theme
2
+ margin-top: 1rem
3
+ .atk-editor-plug-preview
4
+ scrollbar(0, 0)
3
5
  .atk-main-editor
4
- border-radius: $border-card
6
+ border-radius: $border-card
7
+ .atk-header,.atk-editor-user-wrap
8
+ border-bottom: 1px dashed var(--block-border)
9
+ padding: 0.5rem 1rem
10
+ .atk-editor-user-wrap:empty
11
+ visibility: hidden
12
+ padding: 0
13
+ >.atk-bottom
14
+ padding: 8px
15
+ .atk-plug-btn
16
+ border-radius: 32px
17
+ height: 2rem
18
+ width 2rem
19
+ .atk-send-btn
20
+ height: 2rem
21
+ border-radius: 100px
22
+ min-width: 5em
23
+ trans1 all
24
+ &:hover
25
+ --at-color-main: $color-hover
26
+ &:empty
27
+ display: none
28
+ .atk-list-comments-wrap>.atk-comment-wrap
29
+ border-radius: $border-card
30
+ background: var(--card)
31
+ box-shadow: 0 0 8px 0px rgba(0, 0, 0, 0.02)
32
+ >.atk-comment
33
+ padding: 1rem
34
+ &+.atk-comment-wrap
35
+ margin-top: .5rem
36
+ .atk-comment-children
37
+ border-top: 1px dashed var(--block-border)
38
+ margin-top: .5rem
39
+ .atk-avatar
40
+ padding: 0
41
+ .atk-avatar img
42
+ border-radius: 50%
43
+ width: 36px
44
+ height: 36px
45
+ .atk-comment-wrap>.atk-comment>.atk-main
46
+ margin-left: calc(36px + .5rem)
47
+ .atk-comment>.atk-main>.atk-header .atk-item.atk-nick
48
+ color: var(--text-p3)
49
+ font-weight: 500
50
+
51
+ .atk-badge-wrap span
52
+ border-radius: 100px
53
+ .atk-height-limit-btn
54
+ padding: 0.5rem 2rem
55
+ .atk-list-read-more
56
+ margin-top: 2.5rem
57
+ padding-bottom: 1.5rem
58
+ .atk-list-read-more-inner
59
+ padding: 1rem 2rem
60
+ border-radius: $border-button
61
+ height: 3rem
62
+ width: 12rem
63
+ margin: -1.5rem auto 0
64
+ .atk-error-layer
65
+ background: none
66
+
67
+ .cmt-body
68
+ .artalk, .atk-layer-wrap, .artalk.atk-dark-mode, .atk-layer-wrap.atk-dark-mode
69
+ --at-color-font: var(--text-p1)
70
+ --at-color-deep: var(--text-p2)
71
+ --at-color-sub: var(--text-p3)
72
+ --at-color-grey: var(--text-p4)
73
+ --at-color-meta: var(--text-p4)
74
+ --at-color-border: var(--block-border)
75
+ --at-color-light: var(--theme-link)
76
+ --at-color-bg: var(--card)
77
+ --at-color-bg-transl: var(--block-border)
78
+ --at-color-bg-grey: var(--block)
79
+ --at-color-bg-grey-transl: orange
80
+ --at-color-bg-light: rgba(29, 161, 242, 1)
81
+ --at-color-main: $color-theme
82
+ --at-color-red: $c-red
83
+ --at-color-green: $c-green
84
+ --at-color-gradient: linear-gradient(180deg, transparent, var(--card), 50%, var(--card))
85
+
86
+ .md-text .atk-comment>.atk-main>.atk-body
87
+ overflow: visible
88
+
89
+
90
+ // override
91
+ .md-text .cmt-body.artalk .artalk
92
+ --gap-p: 1rem
93
+ p
94
+ line-height: 1.5
95
+ font-size: $fs-15
96
+ >img
97
+ margin: var(--gap-p) auto
98
+ border-radius: $border-image-s
99
+ a>img
100
+ display: inline
101
+ p>img[atk-emoticon]
102
+ max-height: 1.5em
103
+ transform: scale(1.2)
104
+ margin: 0 4px
105
+ vertical-align: bottom
106
+ ul li, ol li
107
+ font-size: $fs-14
108
+ blockquote
109
+ position: relative
110
+ border-left: none
111
+ background: none
112
+ padding: 0.25rem 1rem
113
+ p
114
+ color: var(--text-p3)
115
+ .atk-content a
116
+ --at-color-main: var(--theme-link)
@@ -5,7 +5,7 @@
5
5
  .tk-content
6
6
  .vemoji, .tk-owo-emotion
7
7
  width: unset
8
- border-radius: $border-image
8
+ border-radius: $border-image-s
9
9
  max-height: 24px
10
10
  max-width: 100px
11
11
  display: inline
@@ -13,7 +13,7 @@
13
13
  img
14
14
  max-width: 400px
15
15
  max-height: 400px
16
- border-radius: $border-image
16
+ border-radius: $border-image-s
17
17
 
18
18
  .OwO
19
19
  .OwO-body
@@ -111,7 +111,7 @@
111
111
  border: none
112
112
  padding: 6px 2rem
113
113
  border-radius: $border-card
114
- background: var(--block-hover)
114
+ background: var(--block-border)
115
115
  color: var(--text-p1)
116
116
  line-height: 2
117
117
  font-size: 14px
@@ -20,13 +20,13 @@ if hexo-config('plugins.katex.enable')
20
20
  @import 'katex'
21
21
 
22
22
  // 评论
23
- if hexo-config('comments.service') == 'beaudar'
23
+ if hexo-config('comments.service') == 'beaudar' or index(hexo-config('comments.custom_css'), 'beaudar') >= 0
24
24
  @import 'comments/beaudar'
25
- if hexo-config('comments.service') == 'twikoo'
25
+ if hexo-config('comments.service') == 'twikoo' or index(hexo-config('comments.custom_css'), 'twikoo') >= 0
26
26
  @import 'comments/twikoo'
27
- if hexo-config('comments.service') == 'utterances'
27
+ if hexo-config('comments.service') == 'utterances' or index(hexo-config('comments.custom_css'), 'utterances') >= 0
28
28
  @import 'comments/utterances'
29
- if hexo-config('comments.service') == 'waline'
29
+ if hexo-config('comments.service') == 'waline' or index(hexo-config('comments.custom_css'), 'waline') >= 0
30
30
  @import 'comments/waline'
31
- if hexo-config('comments.service') == 'artalk'
31
+ if hexo-config('comments.service') == 'artalk' or index(hexo-config('comments.custom_css'), 'artalk') >= 0
32
32
  @import 'comments/artalk'
@@ -1,9 +1,13 @@
1
+ $lazyTransitionType = hexo-config('plugins.lazyload.transition')
2
+ $loadingImage = hexo-config('plugins.lazyload.loading_image.src')
3
+ $loadingImageSize = convert(hexo-config('plugins.lazyload.loading_image.size'))
4
+
1
5
  img.lazy
2
6
  &:not(.loaded)
3
7
  opacity: 0
4
8
  &.loaded,&.error
5
9
  opacity: 1
6
- if hexo-config('plugins.lazyload.transition') == 'blur'
10
+ if $lazyTransitionType == 'blur'
7
11
  trans1 all 0.75s
8
12
  &:not(.loaded)
9
13
  filter blur(50px)
@@ -13,4 +17,47 @@ img.lazy
13
17
  -webkit-filter none
14
18
  else
15
19
  trans1 all 0.38s
16
-
20
+
21
+
22
+ @keyframes fadeIn
23
+ from { opacity: 0; }
24
+ to { opacity: 1; }
25
+
26
+ @keyframes blurIn
27
+ from
28
+ opacity: 0
29
+ filter: blur(50px)
30
+ -webkit-filter: blur(50px)
31
+ to
32
+ opacity: 1
33
+ filter: blur(0px)
34
+ -webkit-filter: blur(0px)
35
+
36
+ article img.lazy
37
+ &:not(.loaded)
38
+ opacity: 1
39
+ border-radius: 4px
40
+ filter none
41
+ transition: none
42
+ if $loadingImage
43
+ &.loading
44
+ background: url($loadingImage) center center / $loadingImageSize no-repeat
45
+ else
46
+ &.loading
47
+ background: url($loadingIcon) center center / $loadingImageSize no-repeat
48
+ min-width: $loadingImageSize
49
+ min-height: $loadingImageSize
50
+
51
+ &.loaded
52
+ animation: fadeIn 0.38s ease-out
53
+ if $loadingImage
54
+ background: none
55
+ if $lazyTransitionType == 'blur'
56
+ &.loaded
57
+ animation: blurIn .75s ease-out
58
+
59
+ &.error
60
+ background: none
61
+ min-width: $loadingImageSize
62
+ min-height: $loadingImageSize
63
+
package/source/js/main.js CHANGED
@@ -200,6 +200,55 @@ const init = {
200
200
  window.dispatchEvent(new Event('tabs:register'));
201
201
  },
202
202
 
203
+ canonicalCheck: () => {
204
+ const canonical = window.canonical;
205
+ function showTip(isOfficial = false) {
206
+ const meta = document.createElement('meta');
207
+ meta.name = 'robots';
208
+ meta.content = 'noindex, nofollow';
209
+ document.head.appendChild(meta);
210
+ const notice = document.createElement('div');
211
+ const originalURL = `https://${canonical.originalHost}`;
212
+ if (isOfficial) {
213
+ notice.className = 'canonical-tip official';
214
+ notice.innerHTML = `
215
+ <a href="${originalURL}" target="_self" rel="noopener noreferrer">
216
+ 本站为官方备用站,仅供应急。主站:${originalURL}
217
+ </a>
218
+ `;
219
+ } else {
220
+ notice.className = 'canonical-tip unofficial';
221
+ notice.innerHTML = `
222
+ <a href="${originalURL}" target="_self" rel="noopener noreferrer">
223
+ <div class="headline icon">☠️</div>
224
+ 本站为非法克隆站,请前往官方源站访问。<br>
225
+ 源站:${originalURL}
226
+ </a>
227
+ `;
228
+ }
229
+ document.body.appendChild(notice);
230
+ }
231
+ if (!canonical.originalHost) return;
232
+ const canonicalTag = document.querySelector('link[rel="canonical"]');
233
+ if (!canonicalTag) {
234
+ showTip(false);
235
+ return;
236
+ }
237
+ const canonicalURL = new URL(canonicalTag.href);
238
+ const currentURL = new URL(window.location.href);
239
+ const canonicalHost = canonicalURL.hostname.replace(/^www\./, '');
240
+ const currentHost = currentURL.hostname.replace(/^www\./, '');
241
+ if (currentHost == 'localhost') return;
242
+ const encodedCanonicalHost = window.btoa(canonicalHost);
243
+ const encodedCurrentHost = window.btoa(currentHost);
244
+ const isCanonicalHostValid = canonical.encoded === encodedCanonicalHost;
245
+ const isCurrentHostValid = canonical.encoded === encodedCurrentHost;
246
+ if (isCanonicalHostValid && isCurrentHostValid) {
247
+ return;
248
+ }
249
+ showTip(canonical.officialHosts?.includes(currentHost));
250
+ }
251
+
203
252
  }
204
253
 
205
254
 
@@ -208,3 +257,4 @@ init.toc()
208
257
  init.sidebar()
209
258
  init.relativeDate(document.querySelectorAll('#post-meta time'))
210
259
  init.registerTabsTag()
260
+ init.canonicalCheck()
@@ -167,7 +167,7 @@ function extToMimes(ext) {
167
167
  function downloadFileEvent(fileDoms) {
168
168
  for (let i = 0; i < fileDoms.length; ++i) {
169
169
  let fileDom = fileDoms[i];
170
- const api = ctx.tag_plugins.chat.api + '?type=file&url=' || 'https://api.vlts.cc/site_info/v1?type=file&url=';
170
+ const api = ctx.tag_plugins.chat.api + '?type=file&url=';
171
171
  const obverser = new IntersectionObserver((entries, observer) => {
172
172
  utils.requestAnimationFrame(()=>{
173
173
  entries.filter((entry)=>{return entry.isIntersecting}).sort((a,b)=>a.intersectionRect.y !== b.intersectionRect.y ? a.intersectionRect.y - b.intersectionRect.y : a.intersectionRect.x - b.intersectionRect.x).forEach((entry, index) => {
@@ -1,170 +1,182 @@
1
- // A local search script with the help of
2
- // [hexo-generator-search](https://github.com/PaicHyperionDev/hexo-generator-search)
3
- // Copyright (C) 2015
4
- // Joseph Pan <http://github.com/wzpan>
5
- // Shuhao Mao <http://github.com/maoshuhao>
6
- // This library is free software; you can redistribute it and/or modify
7
- // it under the terms of the GNU Lesser General Public License as
8
- // published by the Free Software Foundation; either version 2.1 of the
9
- // License, or (at your option) any later version.
10
- //
11
- // This library is distributed in the hope that it will be useful, but
12
- // WITHOUT ANY WARRANTY; without even the implied warranty of
13
- // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14
- // Lesser General Public License for more details.
15
- //
16
- // You should have received a copy of the GNU Lesser General Public
17
- // License along with this library; if not, write to the Free Software
18
- // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19
- // 02110-1301 USA
20
- //
21
- // Modified by:
22
- // Pieter Robberechts <http://github.com/probberechts>
23
-
24
- /*exported searchFunc*/
1
+ var searchCache = null;
2
+ var searchCacheKey = 'search_cache_v1';
3
+
25
4
  var searchFunc = function(path, filter, wrapperId, searchId, contentId) {
26
5
 
27
6
  function getAllCombinations(keywords) {
28
- var i, j, result = [];
29
-
30
- for (i = 0; i < keywords.length; i++) {
31
- for (j = i + 1; j < keywords.length + 1; j++) {
32
- result.push(keywords.slice(i, j).join(" "));
33
- }
7
+ const result = [];
8
+ const maxLen = 3; // 组合最大长度
9
+ for (let i = 0; i < keywords.length; i++) {
10
+ for (let j = i + 1; j <= Math.min(i + maxLen, keywords.length); j++) {
11
+ result.push(keywords.slice(i, j).join(" "));
12
+ }
34
13
  }
35
14
  return result;
36
15
  }
37
16
 
38
- $.ajax({
39
- url: path,
40
- dataType: "json",
41
- success: function(jsonResponse) {
42
- var datas = jsonResponse;
43
- var $input = document.getElementById(searchId);
44
- if (!$input) { return; }
45
- var $resultContent = document.getElementById(contentId);
46
- var $wrapper = document.getElementById(wrapperId);
47
-
48
- $input.addEventListener("input", function(){
49
- var resultList = [];
50
- var keywords = getAllCombinations(this.value.trim().toLowerCase().split(" "))
51
- .sort(function(a,b) { return b.split(" ").length - a.split(" ").length; });
52
- $resultContent.innerHTML = "";
53
- if (this.value.trim().length <= 0) {
54
- $wrapper.setAttribute('searching', 'false');
55
- return;
56
- }
57
- $wrapper.setAttribute('searching', 'true');
58
- // perform local searching
59
- datas.forEach(function(data) {
60
- if (!data.content?.trim().length) { return }
61
- var matches = 0;
62
- if (filter && !data.path.includes(filter)) { return }
63
- var dataTitle = data.title?.trim() || 'Untitled';
64
- var dataTitleLowerCase = dataTitle.toLowerCase();
65
- var dataContent = data.content;
66
- var dataContentLowerCase = dataContent.toLowerCase();
67
- var dataUrl = data.path.startsWith('//') ? data.path.slice(1) : data.path; // 避免文章设置永久链接导致点击打开失败
68
- var indexTitle = -1;
69
- var indexContent = -1;
70
- var firstOccur = -1;
71
- // only match artiles with not empty contents
72
- if (dataContent !== "") {
73
- keywords.forEach(function(keyword) {
74
- indexTitle = dataTitleLowerCase.indexOf(keyword);
75
- indexContent = dataContentLowerCase.indexOf(keyword);
76
-
77
- if( indexTitle >= 0 || indexContent >= 0 ){
78
- matches += 1;
79
- if (indexContent < 0) {
80
- indexContent = 0;
81
- }
82
- if (firstOccur < 0) {
83
- firstOccur = indexContent;
84
- }
85
- }
86
- });
87
- }
88
- // show search results
89
- if (matches > 0) {
90
- var searchResult = {};
91
- searchResult.rank = matches;
92
- searchResult.str = "<li><a href='"+ dataUrl +"'><span class='search-result-title'>"+ dataTitle +"</span>";
93
- if (firstOccur >= 0) {
94
- // cut out 100 characters
95
- var start = firstOccur - 20;
96
- var end = firstOccur + 80;
97
-
98
- if(start < 0){
99
- start = 0;
100
- }
101
-
102
- if(start == 0){
103
- end = 100;
104
- }
105
-
106
- if(end > dataContent.length){
107
- end = dataContent.length;
108
- }
109
-
110
- var matchContent = dataContent.substring(start, end);
111
-
112
- // highlight all keywords
113
- var regS = new RegExp(keywords.join("|"), "gi");
114
- matchContent = matchContent.replace(regS, function(keyword) {
115
- return "<span class=\"search-keyword\">"+keyword+"</span>";
116
- });
117
-
118
- searchResult.str += "<p class=\"search-result-content\">" + matchContent +"...</p>";
119
- }
120
- searchResult.str += "</a></li>";
121
- resultList.push(searchResult);
17
+ function escapeRegExp(string) {
18
+ return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
19
+ }
20
+
21
+ function initSearch(datas) {
22
+ var $input = document.getElementById(searchId);
23
+ if (!$input) { return; }
24
+ if ($input._searchInitialized) return; // 防止重复绑定
25
+ $input._searchInitialized = true;
26
+
27
+ var $resultContent = document.getElementById(contentId);
28
+ var $wrapper = document.getElementById(wrapperId);
29
+
30
+ $input.addEventListener("input", function() {
31
+ var resultList = [];
32
+ var keywords = getAllCombinations(this.value.trim().toLowerCase().split(" "))
33
+ .sort(function(a,b) { return b.split(" ").length - a.split(" ").length; });
34
+ $resultContent.innerHTML = "";
35
+ if (this.value.trim().length <= 0) {
36
+ $wrapper.setAttribute('searching', 'false');
37
+ return;
38
+ }
39
+ $wrapper.setAttribute('searching', 'true');
40
+
41
+ datas.forEach(function(data) {
42
+ if (!data.content?.trim().length) return;
43
+ if (filter && !data.path.includes(filter)) return;
44
+
45
+ var matches = 0;
46
+ var dataTitle = data.title?.trim() || 'Untitled';
47
+ var dataTitleLowerCase = dataTitle.toLowerCase();
48
+ var dataContent = data.content;
49
+ var dataContentLowerCase = dataContent.toLowerCase();
50
+ var dataUrl = data.path.startsWith('//') ? data.path.slice(1) : data.path;
51
+
52
+ var indexTitle = -1;
53
+ var indexContent = -1;
54
+ var firstOccur = -1;
55
+
56
+ keywords.forEach(function(keyword) {
57
+ indexTitle = dataTitleLowerCase.indexOf(keyword);
58
+ indexContent = dataContentLowerCase.indexOf(keyword);
59
+ if (indexTitle >= 0 || indexContent >= 0) {
60
+ matches += 1;
61
+ if (indexContent < 0) indexContent = 0;
62
+ if (firstOccur < 0) firstOccur = indexContent;
122
63
  }
123
64
  });
124
- if (resultList.length) {
125
- resultList.sort(function(a, b) {
126
- return b.rank - a.rank;
127
- });
128
- var result ="<ul class=\"search-result-list\">";
129
- for (var i = 0; i < resultList.length; i++) {
130
- result += resultList[i].str;
65
+
66
+ if (matches > 0) {
67
+ const li = document.createElement('li');
68
+ const a = document.createElement('a');
69
+ a.href = dataUrl;
70
+
71
+ const titleSpan = document.createElement('span');
72
+ titleSpan.className = 'search-result-title';
73
+ titleSpan.textContent = dataTitle;
74
+ a.appendChild(titleSpan);
75
+
76
+ if (firstOccur >= 0) {
77
+ var start = Math.max(0, firstOccur - 20);
78
+ var end = Math.min(dataContent.length, firstOccur + 80);
79
+ if (start === 0) end = 100;
80
+ var matchContent = dataContent.substring(start, end);
81
+
82
+ var regS = new RegExp(keywords.map(escapeRegExp).join("|"), "gi");
83
+ matchContent = matchContent.replace(regS, function(keyword) {
84
+ return "<span class=\"search-keyword\">" + keyword + "</span>";
85
+ });
86
+
87
+ const para = document.createElement('p');
88
+ para.className = 'search-result-content';
89
+ para.innerHTML = matchContent + '...';
90
+ a.appendChild(para);
131
91
  }
132
- result += "</ul>";
133
- $resultContent.innerHTML = result;
92
+
93
+ li.appendChild(a);
94
+ resultList.push({ rank: matches, element: li });
134
95
  }
135
96
  });
136
- }
137
- });
97
+
98
+ if (resultList.length) {
99
+ resultList.sort(function(a, b) {
100
+ return b.rank - a.rank;
101
+ });
102
+
103
+ const ul = document.createElement('ul');
104
+ ul.className = 'search-result-list';
105
+ resultList.forEach(function(item) {
106
+ ul.appendChild(item.element);
107
+ });
108
+
109
+ $resultContent.innerHTML = '';
110
+ $resultContent.appendChild(ul);
111
+ }
112
+ });
113
+ }
114
+
115
+ if (!searchCache) {
116
+ // 数据还没准备好,延迟初始化
117
+ const timer = setInterval(() => {
118
+ if (searchCache) {
119
+ clearInterval(timer);
120
+ initSearch(searchCache);
121
+ }
122
+ }, 100);
123
+ } else {
124
+ initSearch(searchCache);
125
+ }
138
126
  };
139
127
 
140
128
  utils.jq(() => {
141
- var $inputArea = $("input#search-input");
142
- if ($inputArea.length == 0) {
143
- return;
129
+ (function preloadSearchData() {
130
+ var path = ctx.search.path;
131
+ if (path.startsWith('/')) {
132
+ path = path.substring(1);
144
133
  }
145
- var $resultArea = document.querySelector("div#search-result");
146
- $inputArea.focus(function() {
147
- var path = ctx.search.path;
148
- if (path.startsWith('/')) {
149
- path = path.substring(1);
150
- }
151
- path = ctx.root + path;
152
- const filter = $inputArea.attr('data-filter') || '';
153
- searchFunc(path, filter, 'search-wrapper', 'search-input', 'search-result');
154
- });
155
- $inputArea.keydown(function(e) {
156
- if (e.which == 13) {
157
- e.preventDefault();
134
+ path = ctx.root + path;
135
+
136
+ try {
137
+ var cached = localStorage.getItem(searchCacheKey);
138
+ if (cached) {
139
+ searchCache = JSON.parse(cached);
158
140
  }
159
- });
160
- var observer = new MutationObserver(function(mutationsList, observer) {
161
- if (mutationsList.length == 1) {
162
- if (mutationsList[0].addedNodes.length) {
163
- $('.search-wrapper').removeClass('noresult');
164
- } else if (mutationsList[0].removedNodes.length) {
165
- $('.search-wrapper').addClass('noresult');
141
+ } catch (e) {
142
+ console.warn('搜索缓存解析失败', e);
143
+ }
144
+
145
+ fetch(path)
146
+ .then(res => res.json())
147
+ .then(json => {
148
+ searchCache = json;
149
+ try {
150
+ localStorage.setItem(searchCacheKey, JSON.stringify(json));
151
+ } catch (e) {
152
+ console.warn('搜索缓存写入失败', e);
166
153
  }
167
- }
168
- });
169
- observer.observe($resultArea, { childList: true });
154
+ });
155
+ })();
156
+
157
+ var $inputArea = $("input#search-input");
158
+ if ($inputArea.length == 0) return;
159
+ var $resultArea = document.querySelector("div#search-result");
160
+
161
+ $inputArea.focus(function() {
162
+ var path = ctx.search.path;
163
+ if (path.startsWith('/')) {
164
+ path = path.substring(1);
165
+ }
166
+ path = ctx.root + path;
167
+ const filter = $inputArea.attr('data-filter') || '';
168
+ searchFunc(path, filter, 'search-wrapper', 'search-input', 'search-result');
169
+ });
170
+
171
+ $inputArea.keydown(function(e) {
172
+ if (e.which == 13) {
173
+ e.preventDefault();
174
+ }
175
+ });
176
+
177
+ const observer = new MutationObserver(function(mutationsList) {
178
+ const hasResults = $resultArea.querySelector(".search-result-list li");
179
+ $('.search-wrapper').toggleClass('noresult', !hasResults);
170
180
  });
181
+ observer.observe($resultArea, { childList: true, subtree: true });
182
+ });
@@ -10,7 +10,7 @@ utils.jq(() => {
10
10
  continue;
11
11
  }
12
12
  utils.request(el, api, async resp => {
13
- const data = await resp.json();
13
+ var data = await resp.json();
14
14
  data = data.data || [];
15
15
  data.forEach((item, i) => {
16
16
  var cell = '<div class="timenode" index="' + i + '">';
@@ -3,7 +3,6 @@ utils.jq(() => {
3
3
  for (var i = 0; i < els.length; i++) {
4
4
  const el = els[i];
5
5
  const src = `${el.getAttribute('src')}?t=${new Date().getTime()}`;
6
- console.log('src', src);
7
6
 
8
7
  utils.request(el, src, async resp => {
9
8
  const data = await resp.text();
File without changes