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.
- package/_config.yml +30 -16
- package/_data/icons.yml +3 -3
- package/_data/widgets.yml +0 -1
- package/layout/_partial/comments/artalk/script.ejs +1 -2
- package/layout/_partial/comments/layout.ejs +1 -1
- package/layout/_partial/head.ejs +20 -1
- package/layout/_partial/main/navbar/ghinfo.ejs +1 -1
- package/layout/_partial/scripts/defines.ejs +9 -0
- package/layout/_partial/scripts/theme.ejs +3 -3
- package/layout/_partial/sidebar/index_leftbar.ejs +9 -9
- package/layout/_partial/widgets/ghissues.ejs +1 -1
- package/layout/_partial/widgets/ghrepo.ejs +2 -2
- package/layout/_partial/widgets/ghuser.ejs +1 -1
- package/layout/index.ejs +3 -1
- package/layout/layout.ejs +3 -1
- package/package.json +4 -2
- package/scripts/events/index.js +46 -4
- package/scripts/events/lib/fix_image_tags.js +44 -0
- package/scripts/events/lib/get_image_ratios.js +88 -0
- package/scripts/events/lib/version-check.js +86 -0
- package/scripts/helpers/json_ld.js +118 -0
- package/scripts/tags/lib/albums.js +2 -1
- package/scripts/tags/lib/friends.js +2 -1
- package/scripts/tags/lib/ghcard.js +3 -2
- package/scripts/tags/lib/image.js +16 -6
- package/scripts/tags/lib/posters.js +2 -1
- package/scripts/tags/lib/sites.js +2 -1
- package/scripts/tags/lib/timeline.js +1 -1
- package/scripts/tags/lib/video.js +4 -4
- package/source/css/_common/base.styl +1 -2
- package/source/css/_common/canonical.styl +32 -0
- package/source/css/_common/device.styl +6 -4
- package/source/css/_common/highlight.styl +1 -1
- package/source/css/_components/layout.styl +11 -10
- package/source/css/_components/list.styl +3 -0
- package/source/css/_components/main.styl +1 -1
- package/source/css/_components/md.styl +4 -2
- package/source/css/_components/pages/archives.styl +2 -2
- package/source/css/_components/pages/article-story.styl +6 -0
- package/source/css/_components/pages/article-tech.styl +1 -1
- package/source/css/_components/pages/notebook.styl +1 -1
- package/source/css/_components/partial/article-banner.styl +4 -1
- package/source/css/_components/partial/footer.styl +1 -1
- package/source/css/_components/partial/navbar.styl +2 -1
- package/source/css/_components/sidebar/nav-area.styl +1 -1
- package/source/css/_components/sidebar/search.styl +44 -21
- package/source/css/_components/sidebar/sidebar.styl +22 -18
- package/source/css/_components/tag-plugins/banner.styl +1 -1
- package/source/css/_components/tag-plugins/button.styl +3 -4
- package/source/css/_components/tag-plugins/copy.styl +1 -1
- package/source/css/_components/tag-plugins/friends.styl +1 -1
- package/source/css/_components/tag-plugins/gallery.styl +6 -0
- package/source/css/_components/tag-plugins/image.styl +10 -0
- package/source/css/_components/tag-plugins/media.styl +1 -1
- package/source/css/_components/tag-plugins/note.styl +1 -1
- package/source/css/_components/tag-plugins/override.styl +1 -1
- package/source/css/_components/tag-plugins/quot.styl +2 -2
- package/source/css/_components/tag-plugins/tabs.styl +4 -3
- package/source/css/_components/tag-plugins/timeline.styl +2 -2
- package/source/css/_components/tag-plugins/toc.styl +1 -1
- package/source/css/_components/widgets/list.styl +1 -3
- package/source/css/_components/widgets/markdown.styl +0 -7
- package/source/css/_components/widgets/toc.styl +6 -4
- package/source/css/_components/widgets/widgets.styl +0 -5
- package/source/css/_custom.styl +5 -7
- package/source/css/_defines/const.styl +1 -1
- package/source/css/_defines/func.styl +9 -5
- package/source/css/_defines/theme.styl +4 -15
- package/source/css/_plugins/comments/artalk.styl +114 -2
- package/source/css/_plugins/comments/twikoo.styl +3 -3
- package/source/css/_plugins/index.styl +5 -5
- package/source/css/_plugins/lazyload.styl +49 -2
- package/source/js/main.js +50 -0
- package/source/js/plugins/download-file.js +1 -1
- package/source/js/search/local-search.js +163 -151
- package/source/js/services/artalk_latest_comment.js +1 -1
- package/source/js/services/mdrender.js +0 -1
- package/layout/_partial/widgets/search.ejs +0 -0
|
@@ -1,4 +1,116 @@
|
|
|
1
1
|
.cmt-body.artalk .artalk
|
|
2
|
-
|
|
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-
|
|
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
|
|
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='
|
|
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
|
-
|
|
2
|
-
|
|
3
|
-
|
|
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
|
-
|
|
29
|
-
|
|
30
|
-
for (i = 0; i < keywords.length; i++) {
|
|
31
|
-
|
|
32
|
-
|
|
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
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
$wrapper.setAttribute('searching', '
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
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
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
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
|
-
|
|
133
|
-
|
|
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
|
-
|
|
142
|
-
|
|
143
|
-
|
|
129
|
+
(function preloadSearchData() {
|
|
130
|
+
var path = ctx.search.path;
|
|
131
|
+
if (path.startsWith('/')) {
|
|
132
|
+
path = path.substring(1);
|
|
144
133
|
}
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
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
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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 + '">';
|
|
File without changes
|