hexo-theme-stellar 1.29.1 → 1.30.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 (47) hide show
  1. package/_config.yml +21 -1
  2. package/_data/chat_users.yml +0 -0
  3. package/_data/widgets.yml +7 -0
  4. package/layout/_partial/head.ejs +2 -1
  5. package/layout/_partial/main/navbar/nav_tabs_blog.ejs +10 -10
  6. package/layout/_partial/scripts/defines.ejs +3 -0
  7. package/layout/_partial/scripts/services.ejs +91 -0
  8. package/layout/_partial/scripts/theme.ejs +5 -0
  9. package/layout/_partial/scripts/utils.ejs +67 -7
  10. package/layout/_partial/scripts.ejs +1 -1
  11. package/layout/_plugins/mermaid.ejs +1 -1
  12. package/layout/_plugins/scrollreveal.ejs +1 -0
  13. package/layout/_plugins/search/algolia_search.ejs +11 -12
  14. package/layout/layout.ejs +1 -1
  15. package/package.json +1 -1
  16. package/scripts/events/lib/config.js +3 -0
  17. package/scripts/events/lib/doc_tree.js +1 -6
  18. package/scripts/filters/index.js +26 -0
  19. package/scripts/generators/notebooks.js +1 -1
  20. package/scripts/generators/search.js +21 -2
  21. package/scripts/helpers/dynamic_color.js +138 -0
  22. package/scripts/tags/index.js +1 -0
  23. package/scripts/tags/lib/box.js +1 -1
  24. package/scripts/tags/lib/chat.js +515 -0
  25. package/scripts/tags/lib/folders.js +1 -1
  26. package/scripts/tags/lib/folding.js +2 -2
  27. package/scripts/tags/lib/sites.js +1 -1
  28. package/scripts/tags/lib/video.js +7 -2
  29. package/source/css/_components/tag-plugins/chat.styl +621 -0
  30. package/source/css/_components/tag-plugins/friends.styl +10 -0
  31. package/source/css/_components/tag-plugins/sites.styl +12 -0
  32. package/source/css/_components/tag-plugins/tabs.styl +5 -2
  33. package/source/css/_custom.styl +1 -0
  34. package/source/css/_defines/func.styl +7 -6
  35. package/source/css/_defines/theme.styl +38 -0
  36. package/source/css/_plugins/katex.styl +0 -1
  37. package/source/js/plugins/download-file.js +198 -0
  38. package/source/js/plugins/video.js +65 -0
  39. package/source/js/plugins/voice.js +438 -0
  40. package/source/js/search/algolia-search.js +63 -61
  41. package/source/js/services/artalk_latest_comment.js +33 -0
  42. package/source/js/services/friends.js +4 -0
  43. package/source/js/services/giscus_latest_comment.js +36 -0
  44. package/source/js/services/memos.js +91 -69
  45. package/source/js/services/sites.js +4 -0
  46. package/source/js/services/twikoo_latest_comment.js +47 -0
  47. package/source/js/services/waline_latest_comment.js +32 -0
package/_config.yml CHANGED
@@ -1,6 +1,6 @@
1
1
  ######## Stellar info ########
2
2
  stellar:
3
- version: '1.29.1'
3
+ version: '1.30.0'
4
4
  homepage: 'https://xaoxuu.com/wiki/stellar/'
5
5
  repo: 'https://github.com/xaoxuu/hexo-theme-stellar'
6
6
  main_css: /css/main.css
@@ -197,10 +197,12 @@ search:
197
197
  field: all # post, page, all
198
198
  path: /search.json # 搜索文件存放位置
199
199
  content: true # 是否搜索内容
200
+ skip_search: # 指定 path 中的内容不被搜索。
200
201
  algolia_search: # Docsearch https://docsearch.algolia.com/apply/ 申请
201
202
  appId:
202
203
  apiKey:
203
204
  indexName:
205
+ js: https://gcore.jsdelivr.net/algoliasearch/3/algoliasearch.min.js
204
206
 
205
207
 
206
208
  ######## Comments ########
@@ -416,6 +418,8 @@ tag_plugins:
416
418
  layout: grid # grid / flow
417
419
  size: mix # s / m / l / xl / mix
418
420
  ratio: square # origin / square
421
+ chat:
422
+ api: https://siteinfo.listentothewind.cn/api/v1
419
423
 
420
424
 
421
425
  # 基础依赖
@@ -451,6 +455,22 @@ data_services:
451
455
  js: /js/services/weibo.js
452
456
  memos:
453
457
  js: /js/services/memos.js
458
+ # chat
459
+ voice:
460
+ js: /js/plugins/voice.js
461
+ video:
462
+ js: /js/plugins/video.js
463
+ download-file:
464
+ js: /js/plugins/download-file.js
465
+ # 最新评论获取类
466
+ twikoo:
467
+ js: /js/services/twikoo_latest_comment.js
468
+ waline:
469
+ js: /js/services/waline_latest_comment.js
470
+ artalk:
471
+ js: /js/services/artalk_latest_comment.js
472
+ giscus:
473
+ js: /js/services/giscus_latest_comment.js
454
474
 
455
475
 
456
476
  # 扩展插件接入方法:(插件名下面用 #plugin# 代替)
File without changes
package/_data/widgets.yml CHANGED
@@ -71,6 +71,13 @@ timeline:
71
71
  type: # 默认不用写,如果是友链朋友圈数据请写 fcircle
72
72
  limit: # 默认通过 api 上增加 per_page 来设置,如果是友链朋友圈,可通过这个设置数量
73
73
 
74
+ latest_comment:
75
+ layout: timeline
76
+ title: 最新评论
77
+ api: # 参照文档获取服务对应的api
78
+ type: # 选择评论服务
79
+ limit: 16 # 限制获取数量
80
+
74
81
  tagtree:
75
82
  layout: tagtree
76
83
  expand_all: false # 是否展开所有节点
@@ -119,7 +119,8 @@ function custom_inject() {
119
119
  <%- feed_tag(config.feed.path, {title: config.title}) %>
120
120
  <% } %>
121
121
 
122
- <link rel="stylesheet" href="<%- `${theme.stellar.main_css}?v=${stellar_info('version')}` %>">
122
+ <link rel="stylesheet" href="<%- url_for(`${theme.stellar.main_css}?v=${stellar_info('version')}`) %>">
123
+
123
124
 
124
125
  <% if (config.favicon) { %>
125
126
  <%- favicon_tag(config.favicon) %>
@@ -11,37 +11,37 @@ function layoutDiv() {
11
11
 
12
12
  if (site.categories && site.categories.length > 0) {
13
13
  if (page.category) {
14
- el += '<a class="active" href="' + url_for(config.category_dir) + '">' + __("btn.category") + __("symbol.colon") + page.category + '</a>';
14
+ el += '<a class="active" href="' + url_for(config.category_dir) + '/">' + __("btn.category") + __("symbol.colon") + page.category + '</a>';
15
15
  } else if (page.layout == "categories") {
16
- el += '<a class="active" href="' + url_for(config.category_dir) + '">' + __("btn.categories") + '</a>';
16
+ el += '<a class="active" href="' + url_for(config.category_dir) + '/">' + __("btn.categories") + '</a>';
17
17
  } else {
18
- el += '<a href="' + url_for(config.category_dir) + '">' + __("btn.categories") + '</a>';
18
+ el += '<a href="' + url_for(config.category_dir) + '/">' + __("btn.categories") + '</a>';
19
19
  }
20
20
  }
21
21
 
22
22
  if (site.tags && site.tags.length > 0) {
23
23
  if (page.tag) {
24
- el += '<a class="active" href="' + url_for(config.tag_dir) + '">' + __("btn.tag") + __("symbol.colon") + page.tag + '</a>';
24
+ el += '<a class="active" href="' + url_for(config.tag_dir) + '/">' + __("btn.tag") + __("symbol.colon") + page.tag + '</a>';
25
25
  } else if (page.layout == "tags") {
26
- el += '<a class="active" href="' + url_for(config.tag_dir) + '">' + __("btn.tags") + '</a>';
26
+ el += '<a class="active" href="' + url_for(config.tag_dir) + '/">' + __("btn.tags") + '</a>';
27
27
  } else {
28
- el += '<a href="' + url_for(config.tag_dir) + '">' + __("btn.tags") + '</a>';
28
+ el += '<a href="' + url_for(config.tag_dir) + '/">' + __("btn.tags") + '</a>';
29
29
  }
30
30
  }
31
31
 
32
32
  if (theme.topic?.publish_list?.length > 0) {
33
33
  if (page.layout == 'index_topic') {
34
- el += '<a class="active" href="' + url_for(theme.site_tree.index_topic.base_dir) + '">' + __("btn.topic") + '</a>';
34
+ el += '<a class="active" href="' + url_for(theme.site_tree.index_topic.base_dir) + '/">' + __("btn.topic") + '</a>';
35
35
  } else {
36
- el += '<a href="' + url_for(theme.site_tree.index_topic.base_dir) + '">' + __("btn.topic") + '</a>';
36
+ el += '<a href="' + url_for(theme.site_tree.index_topic.base_dir) + '/">' + __("btn.topic") + '</a>';
37
37
  }
38
38
  }
39
39
 
40
40
  if (site.posts && site.posts.length > 0) {
41
41
  if (is_archive()) {
42
- el += '<a class="active" href="' + url_for(config.archive_dir) + '">' + __("btn.archives") + '</a>';
42
+ el += '<a class="active" href="' + url_for(config.archive_dir) + '/">' + __("btn.archives") + '</a>';
43
43
  } else {
44
- el += '<a href="' + url_for(config.archive_dir) + '">' + __("btn.archives") + '</a>';
44
+ el += '<a href="' + url_for(config.archive_dir) + '/">' + __("btn.archives") + '</a>';
45
45
  }
46
46
  }
47
47
 
@@ -7,6 +7,9 @@
7
7
  day: `<%- __('meta.date_suffix.day') %>`,
8
8
  },
9
9
  root : `<%- config.root %>`,
10
+ tag_plugins: {
11
+ chat: Object.assign(<%- JSON.stringify(theme.tag_plugins.chat) %>),
12
+ }
10
13
  };
11
14
 
12
15
  // required plugins (only load if needs)
@@ -10,6 +10,27 @@
10
10
  setCardLink(ctx.cardlinks);
11
11
  });
12
12
  }
13
+ } else if (id == 'voice') {
14
+ ctx.voiceAudios = document.querySelectorAll('.voice>audio');
15
+ if (ctx.voiceAudios?.length > 0) {
16
+ utils.js(js, { defer: true }).then(function () {
17
+ createVoiceDom(ctx.voiceAudios);
18
+ });
19
+ }
20
+ } else if (id == 'video') {
21
+ ctx.videos = document.querySelectorAll('.video>video');
22
+ if (ctx.videos?.length > 0) {
23
+ utils.js(js, { defer: true }).then(function () {
24
+ videoEvents(ctx.videos);
25
+ });
26
+ }
27
+ } else if (id == 'download-file') {
28
+ ctx.files = document.querySelectorAll('.file');
29
+ if (ctx.files?.length > 0) {
30
+ utils.js(js, { defer: true }).then(function () {
31
+ downloadFileEvent(ctx.files);
32
+ });
33
+ }
13
34
  } else {
14
35
  const els = document.getElementsByClassName(`ds-${id}`);
15
36
  if (els?.length > 0) {
@@ -25,5 +46,75 @@
25
46
  }
26
47
  }
27
48
  }
49
+
50
+ // chat iphone time
51
+ let phoneTimes = document.querySelectorAll('.chat .status-bar .time');
52
+
53
+ if (phoneTimes.length > 0) {
54
+ NowTime();
55
+ var date = new Date();
56
+ var sec = date.getSeconds();
57
+ var firstAdjustInterval = setInterval(firstAdjustTime, 1000 * (60 - sec));
58
+ }
59
+
60
+ function firstAdjustTime() {
61
+ NowTime();
62
+ clearInterval(firstAdjustInterval);
63
+ setInterval(NowTime, 1000 * 60);
64
+ }
65
+
66
+ function NowTime() {
67
+ for (let i = 0; i < phoneTimes.length; ++i) {
68
+ var timeSpan = phoneTimes[i];
69
+ var date = new Date();
70
+ var hour = date.getHours();
71
+ var min = date.getMinutes();
72
+ timeSpan.innerHTML = check(hour) + ":" + check(min);
73
+ }
74
+ };
75
+
76
+ function check(val) {
77
+ if (val < 10) {
78
+ return ("0" + val);
79
+ }
80
+ return (val);
81
+ }
82
+
83
+ // chat quote
84
+ const chat_quote_obverser = new IntersectionObserver((entries, observer) => {
85
+ 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) => {
86
+ observer.unobserve(entry.target);
87
+ setTimeout(() => {
88
+ entry.target.classList.add('quote-blink');
89
+ setTimeout(() => {
90
+ entry.target.classList.remove('quote-blink');
91
+ }, 1000);
92
+ }, Math.max(100, 16) * (index + 1));
93
+ });
94
+ });
95
+
96
+ var chatQuotes = document.querySelectorAll(".chat .talk .quote");
97
+ chatQuotes.forEach((quote) => {
98
+ quote.addEventListener('click', function () {
99
+ var chatCellDom = document.getElementById("quote-" + quote.getAttribute("quotedCellTag"));
100
+ if (chatCellDom) {
101
+ var chatDiv = chatCellDom.parentElement;
102
+ var mid = chatDiv.clientHeight / 2;
103
+ var offsetTop = chatCellDom.offsetTop;
104
+ if (offsetTop > mid - chatCellDom.clientHeight / 2) {
105
+ chatDiv.scrollTo({
106
+ top: chatCellDom.offsetTop - mid + chatCellDom.clientHeight / 2,
107
+ behavior: "smooth"
108
+ });
109
+ } else {
110
+ chatDiv.scrollTo({
111
+ top: 0,
112
+ behavior: "smooth"
113
+ });
114
+ }
115
+ chat_quote_obverser.observe(chatCellDom);
116
+ }
117
+ });
118
+ });
28
119
  });
29
120
  </script>
@@ -43,6 +43,8 @@
43
43
  }
44
44
  applyTheme(newTheme)
45
45
  window.localStorage.setItem('Stellar.theme', newTheme)
46
+ utils.dark.mode = newTheme === 'auto' ? (window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light") : newTheme;
47
+ utils.dark.method.toggle.start();
46
48
 
47
49
  const messages = {
48
50
  light: `<%- __('message.theme_switched.light') %>`,
@@ -57,6 +59,9 @@
57
59
  const theme = window.localStorage.getItem('Stellar.theme')
58
60
  if (theme !== null) {
59
61
  applyTheme(theme)
62
+ } else {
63
+ utils.dark.mode = window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
60
64
  }
65
+ utils.dark.method.toggle.start();
61
66
  })()
62
67
  </script>
@@ -1,4 +1,44 @@
1
1
  <script type="text/javascript">
2
+ function RunItem() {
3
+ this.list = []; // 存放回调函数
4
+ this.start = () => {
5
+ for (var i = 0; i < this.list.length; i++) {
6
+ this.list[i].run();
7
+ }
8
+ };
9
+ this.push = (fn, name, setRequestAnimationFrame = true) => {
10
+ let myfn = fn
11
+ if (setRequestAnimationFrame) {
12
+ myfn = () => {
13
+ utils.requestAnimationFrame(fn)
14
+ }
15
+ }
16
+ var f = new Item(myfn, name);
17
+ this.list.push(f);
18
+ };
19
+ this.remove = (name) => {
20
+ for (let index = 0; index < this.list.length; index++) {
21
+ const e = this.list[index];
22
+ if (e.name == name) {
23
+ this.list.splice(index, 1);
24
+ }
25
+ }
26
+ }
27
+ // 构造一个可以run的对象
28
+ function Item(fn, name) {
29
+ // 函数名称
30
+ this.name = name || fn.name;
31
+ // run方法
32
+ this.run = () => {
33
+ try {
34
+ fn()
35
+ } catch (error) {
36
+ console.log(error);
37
+ }
38
+ };
39
+ }
40
+ }
41
+
2
42
  const utils = {
3
43
  // 懒加载 css https://github.com/filamentgroup/loadCSS
4
44
  css: (href, before, media, attributes) => {
@@ -61,7 +101,7 @@
61
101
 
62
102
  js: (src, opt) => new Promise((resolve, reject) => {
63
103
  var script = document.createElement('script');
64
- if (src.startsWith('/')){
104
+ if (src.startsWith('/')) {
65
105
  src = ctx.root + src.substring(1);
66
106
  }
67
107
  script.src = src;
@@ -74,7 +114,7 @@
74
114
  script.async = true
75
115
  }
76
116
  script.onerror = reject
77
- script.onload = script.onreadystatechange = function() {
117
+ script.onload = script.onreadystatechange = function () {
78
118
  const loadState = this.readyState
79
119
  if (loadState && loadState !== 'loaded' && loadState !== 'complete') return
80
120
  script.onload = script.onreadystatechange = null
@@ -90,7 +130,7 @@
90
130
  fn()
91
131
  }
92
132
  },
93
-
133
+
94
134
  onLoading: (el) => {
95
135
  if (el) {
96
136
  $(el).append('<div class="loading-wrap"><svg xmlns="http://www.w3.org/2000/svg" width="2em" height="2em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 24 24"><g fill="none" stroke="currentColor" stroke-linecap="round" stroke-width="2"><path stroke-dasharray="60" stroke-dashoffset="60" stroke-opacity=".3" d="M12 3C16.9706 3 21 7.02944 21 12C21 16.9706 16.9706 21 12 21C7.02944 21 3 16.9706 3 12C3 7.02944 7.02944 3 12 3Z"><animate fill="freeze" attributeName="stroke-dashoffset" dur="1.3s" values="60;0"/></path><path stroke-dasharray="15" stroke-dashoffset="15" d="M12 3C16.9706 3 21 7.02944 21 12"><animate fill="freeze" attributeName="stroke-dashoffset" dur="0.3s" values="15;0"/><animateTransform attributeName="transform" dur="1.5s" repeatCount="indefinite" type="rotate" values="0 12 12;360 12 12"/></path></g></svg></div>');
@@ -124,7 +164,7 @@
124
164
  }
125
165
  }
126
166
  }, 5000);
127
- fetch(url).then(function(response) {
167
+ fetch(url).then(function (response) {
128
168
  if (status !== 2) {
129
169
  clearTimeout(timer);
130
170
  resolve(response);
@@ -135,11 +175,11 @@
135
175
  return response.json();
136
176
  }
137
177
  throw new Error('Network response was not ok.');
138
- }).then(function(data) {
178
+ }).then(function (data) {
139
179
  retryTimes = 0;
140
180
  utils.onLoadSuccess(el);
141
181
  callback(data);
142
- }).catch(function(error) {
182
+ }).catch(function (error) {
143
183
  if (retryTimes > 0) {
144
184
  retryTimes -= 1;
145
185
  setTimeout(() => {
@@ -154,5 +194,25 @@
154
194
  }
155
195
  req();
156
196
  },
197
+ /********************** requestAnimationFrame ********************************/
198
+ // 1、requestAnimationFrame 会把每一帧中的所有 DOM 操作集中起来,在一次重绘或回流中就完成,并且重绘或回流的时间间隔紧紧跟随浏览器的刷新频率,一般来说,这个频率为每秒60帧。
199
+ // 2、在隐藏或不可见的元素中,requestAnimationFrame 将不会进行重绘或回流,这当然就意味着更少的的 cpu,gpu 和内存使用量。
200
+ requestAnimationFrame: (fn) => {
201
+ if (!window.requestAnimationFrame) {
202
+ window.requestAnimationFrame = window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame;
203
+ }
204
+ window.requestAnimationFrame(fn)
205
+ },
206
+ dark: {},
207
+ };
208
+
209
+ // utils.dark.mode 当前模式 dark or light
210
+ // utils.dark.toggle() 暗黑模式触发器
211
+ // utils.dark.push(callBack[,"callBackName"]) 传入触发器回调函数
212
+ utils.dark.method = {
213
+ toggle: new RunItem(),
157
214
  };
158
- </script>
215
+ utils.dark = Object.assign(utils.dark, {
216
+ push: utils.dark.method.toggle.push,
217
+ });
218
+ </script>
@@ -21,7 +21,7 @@ function custom_inject() {
21
21
  <%- partial('scripts/tagtree') %>
22
22
 
23
23
  <!-- required -->
24
- <script src="<%- `${theme.stellar.main_js}?v=${stellar_info('version')}` %>" defer></script>
24
+ <script src="<%- url_for(`${theme.stellar.main_js}?v=${stellar_info('version')}`) %>" defer></script>
25
25
 
26
26
  <%- partial('scripts/theme') %>
27
27
 
@@ -4,7 +4,7 @@
4
4
  var mermaid_config = {
5
5
  startOnLoad: true,
6
6
  theme:
7
- "<%- theme.style.darkmode %>" == "auto" &&
7
+ "<%- theme.style.prefers_theme %>" == "auto" &&
8
8
  window.matchMedia("(prefers-color-scheme: dark)").matches
9
9
  ? "dark"
10
10
  : "<%- conf.theme %>",
@@ -11,5 +11,6 @@
11
11
  };
12
12
  ScrollReveal().reveal('.l_left .slide-up', slideUp);
13
13
  ScrollReveal().reveal('.l_main .slide-up', slideUp);
14
+ ScrollReveal().reveal('.l_right .slide-up', slideUp);
14
15
  });
15
16
  </script>
@@ -1,13 +1,12 @@
1
1
  <script>
2
- window.addEventListener('DOMContentLoaded', (event) => {
3
- window.searchConfig = {
4
- appId: '<%- conf.appId %>',
5
- apiKey: '<%- conf.apiKey %>',
6
- indexName: '<%- conf.indexName %>',
7
- hitsPerPage: 100,
8
- };
9
- utils.js('https://gcore.jsdelivr.net/algoliasearch/3/algoliasearch.min.js', { defer: true });
10
- utils.js('/js/search/algolia-search.js', { defer: true });
11
- });
12
- </script>
13
-
2
+ window.addEventListener('DOMContentLoaded', (event) => {
3
+ window.searchConfig = {
4
+ appId: '<%- conf.appId %>',
5
+ apiKey: '<%- conf.apiKey %>',
6
+ indexName: '<%- conf.indexName %>',
7
+ js: '<%- conf.js %>',
8
+ hitsPerPage: 100,
9
+ };
10
+ utils.js('/js/search/algolia-search.js', { defer: true });
11
+ });
12
+ </script>
package/layout/layout.ejs CHANGED
@@ -46,7 +46,7 @@ if (theme.style.prefers_theme === 'auto') {
46
46
  html += `<body>`
47
47
  html += site_background
48
48
  html += partial('_partial/cover/index')
49
- html += `<div class="l_body s:aa ${page_type} ${article_type}" id="start" layout="${page.layout}" ${indent ? 'text-indent' : ''}>`
49
+ html += `<div class="l_body ${page_type} ${article_type}" id="start" layout="${page.layout}" ${indent ? 'text-indent' : ''}>`
50
50
  html += `<aside class="l_left">`
51
51
  html += `<div class="leftbar-container${theme.style.leftbar?.blur ? ' leftbar-blur' : ''}">`
52
52
  html += partial('_partial/sidebar/index_leftbar')
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hexo-theme-stellar",
3
- "version": "1.29.1",
3
+ "version": "1.30.0",
4
4
  "description": "Elegant and powerful theme for Hexo.",
5
5
  "main": "package.json",
6
6
  "scripts": {
@@ -64,4 +64,7 @@ module.exports = ctx => {
64
64
  ctx.theme.config.menubar = {}
65
65
  }
66
66
 
67
+ // chat users
68
+ ctx.theme.config.chat_users = data.chat_users;
69
+
67
70
  }
@@ -63,7 +63,7 @@ module.exports = ctx => {
63
63
  const pages = ctx.locals.get('pages')
64
64
  // wiki 所有页面
65
65
  const wiki_pages = pages.filter(p => (p.wiki != null)).map(p => new WikiPage(p))
66
- const wiki_list = Object.keys(wiki.tree)
66
+ const wiki_list = Object.keys(wiki.tree).filter(id => wiki_pages.some(p => p.wiki === id))
67
67
  // 上架的项目列表
68
68
  wiki.shelf = ctx.locals.get('data').wiki || []
69
69
 
@@ -99,11 +99,6 @@ module.exports = ctx => {
99
99
  let id = wiki_list[i];
100
100
  let item = wiki.tree[id]
101
101
  let sub_pages = wiki_pages.filter(p => p.wiki === id)
102
- if (!sub_pages || sub_pages.length == 0) {
103
- wiki_list.splice(i, 1)
104
- delete wiki.tree[id]
105
- continue
106
- }
107
102
 
108
103
  // 首页
109
104
  // 未特别指定首页时,获取TOC第一页作为首页
@@ -2,3 +2,29 @@
2
2
 
3
3
  hexo.extend.filter.register('after_render:html', require('./lib/img_lazyload').processSite);
4
4
  hexo.extend.filter.register('after_render:html', require('./lib/img_onerror').processSite);
5
+
6
+ function change_image(data) {
7
+ if (this.theme.config.tag_plugins.image.parse_markdown) {
8
+ // data.content = data.content.replace(
9
+ // /!\[(.*?)\]\((.*?)\s*(?:"(.*?)")?\)/g,
10
+ // '{% image $2 $3 %}'
11
+ // );
12
+ let splited_content = data.content.split(/(```[\s\S]*?```|{%\s*gallery\s*%}[\s\S]*?{%\s*endgallery\s*%})/g);
13
+ splited_content = splited_content.map((s) => {
14
+ let matches_no = s.match(/(```[\s\S]*?```|{%\s*gallery\s*%}[\s\S]*?{%\s*endgallery\s*%})/i);
15
+ let matches_img = s.match(/!\[(.*?)\]\((.*?)\s*(?:"(.*?)")?\)/i);
16
+ if (!matches_no && matches_img) {
17
+ s = s.replace(
18
+ /!\[(.*?)\]\((.*?)\s*(?:"(.*?)")?\)/g,
19
+ `{% image $2 $3 %}`
20
+ );
21
+ }
22
+ return s;
23
+ });
24
+ data.content = splited_content.join('');
25
+ }
26
+ return data;
27
+ }
28
+
29
+ hexo.extend.filter.register('before_post_render', change_image, 9);
30
+
@@ -30,7 +30,7 @@ function paginationWithEmpty(base, posts, options={}) {
30
30
 
31
31
  hexo.extend.generator.register('notebooks', function (locals) {
32
32
  const { site_tree, notebooks } = hexo.theme.config
33
- if (notebooks.tree.length === 0) {
33
+ if (!notebooks?.tree || Object.keys(notebooks.tree).length === 0) {
34
34
  return []
35
35
  }
36
36
 
@@ -31,11 +31,13 @@ hexo.extend.generator.register('search_json_generator', function (locals) {
31
31
  temp_post.path = root + post.path
32
32
  }
33
33
  if (cfg.content != false && post.content) {
34
- var content = stripHTML(post.content).trim()
34
+ var content = stripHTML(post.content.replace(/<span class="line">\d+<\/span>/g, '')).trim()
35
35
  // 部分HTML标签
36
36
  content = content.replace(/<iframe[\s|\S]+iframe>/g, '')
37
37
  content = content.replace(/<hr>/g, '')
38
38
  content = content.replace(/<br>/g, '')
39
+ // 去除HTML实体
40
+ content = content.replace(/&[^\s;]+;/g, "")
39
41
  // 换行符换成空格
40
42
  content = content.replace(/\\n/g, ' ')
41
43
  content = content.replace(/\n/g, ' ')
@@ -60,8 +62,22 @@ hexo.extend.generator.register('search_json_generator', function (locals) {
60
62
  return temp_post
61
63
  }
62
64
 
65
+ function matchAndExit(path, patterns) {
66
+ for (let pattern of patterns) {
67
+ const regexPattern = new RegExp('^' + pattern.replace(/\*/g, '.*') + '$');
68
+ if (path.match(regexPattern)) {
69
+ // console.log("Matched pattern:", pattern);
70
+ return true;
71
+ }
72
+ }
73
+ return false;
74
+ }
75
+
63
76
  if (posts) {
64
77
  posts.each(function(post) {
78
+ var layout_list = ["post"]
79
+ if (!layout_list.includes(post.layout)) return
80
+ if (cfg.skip_search && matchAndExit(post.path, cfg.skip_search)) return
65
81
  if (post.indexing == false) return
66
82
  let temp_post = generateJson(post)
67
83
  res.push(temp_post)
@@ -69,6 +85,9 @@ hexo.extend.generator.register('search_json_generator', function (locals) {
69
85
  }
70
86
  if (pages) {
71
87
  pages.each(function(page) {
88
+ var layout_list = ["page", "wiki"]
89
+ if (!layout_list.includes(page.layout)) return
90
+ if (cfg.skip_search && matchAndExit(page.path, cfg.skip_search)) return
72
91
  if (page.indexing == false) return
73
92
  let temp_post = generateJson(page)
74
93
  res.push(temp_post)
@@ -78,4 +97,4 @@ hexo.extend.generator.register('search_json_generator', function (locals) {
78
97
  path: cfg.path,
79
98
  data: JSON.stringify(res)
80
99
  }
81
- })
100
+ })