hexo-theme-solitude 1.1.3 → 1.2.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.
Files changed (254) hide show
  1. package/LICENSE +674 -19
  2. package/_config.yml +244 -193
  3. package/languages/en-US.yml +1 -0
  4. package/languages/zh-CN.yml +8 -8
  5. package/layout/404.pug +24 -0
  6. package/layout/archive.pug +11 -0
  7. package/layout/category.pug +16 -0
  8. package/layout/includes/console.pug +42 -0
  9. package/layout/includes/footer.pug +71 -0
  10. package/layout/includes/head/config.pug +79 -0
  11. package/layout/includes/head/pwa.pug +59 -0
  12. package/layout/includes/head.pug +29 -0
  13. package/layout/includes/header.pug +4 -0
  14. package/layout/includes/inject/body.pug +68 -0
  15. package/layout/{partial/compoment/inject/head.ejs → includes/inject/head.pug} +61 -35
  16. package/layout/includes/layout.pug +35 -0
  17. package/layout/{partial/loading.ejs → includes/loading.pug} +19 -17
  18. package/layout/includes/mixins/articleSort.pug +14 -0
  19. package/layout/includes/mixins/pagination.pug +8 -0
  20. package/layout/includes/nav.pug +22 -0
  21. package/layout/includes/page/about.pug +10 -0
  22. package/layout/includes/page/categories.pug +8 -0
  23. package/layout/includes/page/default.pug +2 -0
  24. package/layout/includes/page/echarts.pug +7 -0
  25. package/layout/includes/page/equipment.pug +3 -0
  26. package/layout/includes/page/links.pug +35 -0
  27. package/layout/includes/page/moments.pug +5 -0
  28. package/layout/includes/page/rss.pug +22 -0
  29. package/layout/includes/page/says.pug +20 -0
  30. package/layout/includes/page/tags.pug +8 -0
  31. package/layout/includes/page/tlink.pug +9 -0
  32. package/layout/includes/recent-posts.pug +9 -0
  33. package/layout/includes/sidebar.pug +17 -0
  34. package/layout/includes/widgets/aside/aside.pug +18 -0
  35. package/layout/includes/widgets/aside/asideAllInfo.pug +8 -0
  36. package/layout/includes/widgets/aside/asideArchive.pug +9 -0
  37. package/layout/includes/widgets/aside/asideFlipCard.pug +5 -0
  38. package/layout/includes/widgets/aside/asideHistory.pug +8 -0
  39. package/layout/includes/widgets/aside/asideInfoCard.pug +22 -0
  40. package/layout/includes/widgets/aside/asideNewestPost.pug +16 -0
  41. package/layout/includes/widgets/aside/asidePower.pug +19 -0
  42. package/layout/includes/widgets/aside/asideSwitch.pug +26 -0
  43. package/layout/includes/widgets/aside/asideTag.pug +11 -0
  44. package/layout/includes/widgets/aside/asideToc.pug +5 -0
  45. package/layout/includes/widgets/aside/asideWebInfo.pug +40 -0
  46. package/layout/includes/widgets/aside/asideWelcome.pug +12 -0
  47. package/layout/includes/widgets/home/banner.pug +16 -0
  48. package/layout/includes/widgets/home/bbTimeList.pug +8 -0
  49. package/layout/includes/widgets/home/categoryBar.pug +10 -0
  50. package/layout/includes/widgets/home/categoryGroup.pug +9 -0
  51. package/layout/includes/widgets/home/hometop.pug +9 -0
  52. package/layout/includes/widgets/home/postList.pug +26 -0
  53. package/layout/includes/widgets/home/rencentPost.pug +26 -0
  54. package/layout/includes/widgets/home/topGroup.pug +27 -0
  55. package/layout/includes/widgets/nav/left.pug +10 -0
  56. package/layout/includes/widgets/nav/menu.pug +16 -0
  57. package/layout/includes/widgets/nav/right.pug +23 -0
  58. package/layout/includes/widgets/page/about/authorinfo.pug +12 -0
  59. package/layout/includes/widgets/page/about/award.pug +34 -0
  60. package/layout/includes/widgets/page/about/contentinfo.pug +38 -0
  61. package/layout/includes/widgets/page/about/hobbies.pug +33 -0
  62. package/layout/includes/widgets/page/about/motto.pug +19 -0
  63. package/layout/includes/widgets/page/about/other.pug +61 -0
  64. package/layout/includes/widgets/page/about/personalities.pug +16 -0
  65. package/layout/includes/widgets/page/about/skillsinfo.pug +41 -0
  66. package/layout/includes/widgets/page/banner.pug +14 -0
  67. package/layout/includes/widgets/page/equipment/content.pug +23 -0
  68. package/layout/includes/widgets/page/links/banner.pug +30 -0
  69. package/layout/includes/widgets/page/links/linksCard.pug +18 -0
  70. package/layout/includes/widgets/page/links/linksItem.pug +14 -0
  71. package/layout/includes/widgets/page/moments/angle.pug +24 -0
  72. package/layout/includes/widgets/page/moments/index.pug +18 -0
  73. package/layout/includes/widgets/page/says/saysBottom.pug +11 -0
  74. package/layout/includes/widgets/page/says/saysContent.pug +6 -0
  75. package/layout/includes/widgets/page/says/saysFunction.pug +10 -0
  76. package/layout/includes/widgets/page/says/saysMeta.pug +7 -0
  77. package/layout/includes/widgets/post/award.pug +48 -0
  78. package/layout/includes/widgets/post/copyright.pug +27 -0
  79. package/layout/includes/widgets/post/postMeta.pug +55 -0
  80. package/layout/includes/widgets/post/postNav.pug +25 -0
  81. package/layout/includes/widgets/post/wave.pug +9 -0
  82. package/layout/includes/widgets/randomlink.pug +32 -0
  83. package/layout/includes/widgets/rightside/index.pug +74 -0
  84. package/layout/includes/widgets/third-party/comments/comment.pug +14 -0
  85. package/layout/includes/widgets/third-party/comments/gitalk.pug +0 -0
  86. package/layout/{partial/compoment/third-party/comments/twikoo.ejs → includes/widgets/third-party/comments/twikoo.pug} +8 -9
  87. package/layout/includes/widgets/third-party/comments/valine.pug +0 -0
  88. package/layout/includes/widgets/third-party/music.pug +3 -0
  89. package/layout/includes/widgets/third-party/pjax.pug +30 -0
  90. package/layout/includes/widgets/third-party/search/algolia-search.pug +14 -0
  91. package/layout/includes/widgets/third-party/search/index.pug +7 -0
  92. package/layout/includes/widgets/third-party/search/local-search.pug +13 -0
  93. package/layout/index.pug +20 -0
  94. package/layout/page.pug +32 -0
  95. package/layout/post.pug +43 -0
  96. package/layout/tag.pug +19 -0
  97. package/package.json +4 -4
  98. package/scripts/event/page.js +20 -2
  99. package/scripts/filter/checkThemeConfig.js +0 -1
  100. package/scripts/filter/randomPosts.js +0 -1
  101. package/scripts/helper/{charts.js → echarts.js} +27 -28
  102. package/scripts/helper/stylus.js +23 -0
  103. package/scripts/tags/bvideo.js +1 -36
  104. package/source/css/_comment/index.styl +121 -0
  105. package/source/css/_comment/twikoo.styl +515 -0
  106. package/source/css/_extra/console.styl +354 -0
  107. package/source/css/_extra/rightmenu.styl +83 -0
  108. package/source/css/_global/animation.css +756 -0
  109. package/source/css/_global/function.styl +83 -0
  110. package/source/css/_global/index.styl +120 -0
  111. package/source/css/_global/var.styl +1 -0
  112. package/source/css/_layout/articleSort.styl +199 -0
  113. package/source/css/_layout/base.styl +392 -0
  114. package/source/css/_layout/footer.styl +359 -0
  115. package/source/css/_layout/header.styl +1331 -0
  116. package/source/css/_layout/index.styl +293 -0
  117. package/source/css/_layout/sidebar.styl +226 -0
  118. package/source/css/_mode/index.styl +52 -0
  119. package/source/css/_page/about.styl +835 -0
  120. package/source/css/_page/category.styl +141 -0
  121. package/source/css/_page/equipment.styl +101 -0
  122. package/source/css/_page/error.styl +161 -0
  123. package/source/css/_page/home.styl +58 -0
  124. package/source/css/_page/homeTop.styl +1035 -0
  125. package/source/css/_page/index.styl +131 -0
  126. package/source/css/_page/link.styl +433 -0
  127. package/source/css/_page/moment.styl +179 -0
  128. package/source/css/_page/rss.styl +87 -0
  129. package/source/css/_page/says.styl +347 -0
  130. package/source/css/_page/tag.styl +56 -0
  131. package/source/css/_post/commentBarrage.styl +149 -0
  132. package/source/css/_post/externalTags.styl +694 -0
  133. package/source/css/_post/highlight.styl +96 -0
  134. package/source/css/_post/index.styl +935 -0
  135. package/source/css/_post/pagination.styl +467 -0
  136. package/source/css/_post/postContent.styl +957 -0
  137. package/source/css/_post/relatedPost.styl +160 -0
  138. package/source/css/_post/reward.styl +217 -0
  139. package/source/css/_search/algolia-search.styl +154 -0
  140. package/source/css/_search/local-search.styl +131 -0
  141. package/source/css/_widgets/aside/allinfo.styl +134 -0
  142. package/source/css/_widgets/aside/flip.styl +68 -0
  143. package/source/css/_widgets/aside/history.styl +35 -0
  144. package/source/css/_widgets/aside/index.styl +156 -0
  145. package/source/css/_widgets/aside/info.styl +263 -0
  146. package/source/css/_widgets/aside/newPost.styl +55 -0
  147. package/source/css/_widgets/aside/power.styl +90 -0
  148. package/source/css/_widgets/aside/toc.styl +85 -0
  149. package/source/css/_widgets/aside/welcome.styl +14 -0
  150. package/source/css/_widgets/index.styl +3 -0
  151. package/source/css/index.styl +40 -0
  152. package/source/js/commentBarrage.js +8 -5
  153. package/source/js/extend/console/comment.js +60 -63
  154. package/source/js/extend/covercolor/local.js +1 -1
  155. package/source/js/extend/search/algolia-search.js +151 -134
  156. package/source/js/extend/search/local-search.js +137 -162
  157. package/source/js/main.js +655 -505
  158. package/source/js/utils.js +168 -145
  159. package/layout/404.ejs +0 -34
  160. package/layout/archive.ejs +0 -10
  161. package/layout/category.ejs +0 -18
  162. package/layout/index.ejs +0 -20
  163. package/layout/layout.ejs +0 -30
  164. package/layout/page/about.ejs +0 -15
  165. package/layout/page/categories.ejs +0 -12
  166. package/layout/page/circle.ejs +0 -5
  167. package/layout/page/echarts.ejs +0 -1
  168. package/layout/page/equipment.ejs +0 -2
  169. package/layout/page/links.ejs +0 -46
  170. package/layout/page/page.ejs +0 -3
  171. package/layout/page/rss.ejs +0 -39
  172. package/layout/page/says.ejs +0 -17
  173. package/layout/page/tags.ejs +0 -12
  174. package/layout/page/tlink.ejs +0 -11
  175. package/layout/page.ejs +0 -45
  176. package/layout/partial/body.ejs +0 -7
  177. package/layout/partial/compoment/about/authorinfo.ejs +0 -18
  178. package/layout/partial/compoment/about/award.ejs +0 -59
  179. package/layout/partial/compoment/about/contentinfo.ejs +0 -33
  180. package/layout/partial/compoment/about/hobbies.ejs +0 -53
  181. package/layout/partial/compoment/about/motto.ejs +0 -17
  182. package/layout/partial/compoment/about/other.ejs +0 -76
  183. package/layout/partial/compoment/about/personalities.ejs +0 -11
  184. package/layout/partial/compoment/about/skillsinfo.ejs +0 -62
  185. package/layout/partial/compoment/aside/aside.ejs +0 -28
  186. package/layout/partial/compoment/aside/asideAllInfo.ejs +0 -6
  187. package/layout/partial/compoment/aside/asideArchive.ejs +0 -11
  188. package/layout/partial/compoment/aside/asideFlipCard.ejs +0 -72
  189. package/layout/partial/compoment/aside/asideHistory.ejs +0 -49
  190. package/layout/partial/compoment/aside/asideInfoCard.ejs +0 -39
  191. package/layout/partial/compoment/aside/asideNewestPost.ejs +0 -31
  192. package/layout/partial/compoment/aside/asidePower.ejs +0 -31
  193. package/layout/partial/compoment/aside/asideSwitch.ejs +0 -41
  194. package/layout/partial/compoment/aside/asideTag.ejs +0 -5
  195. package/layout/partial/compoment/aside/asideToc.ejs +0 -11
  196. package/layout/partial/compoment/aside/asideWebInfo.ejs +0 -60
  197. package/layout/partial/compoment/aside/asideWelcome.ejs +0 -33
  198. package/layout/partial/compoment/circle/angle.ejs +0 -26
  199. package/layout/partial/compoment/circle/banner.ejs +0 -11
  200. package/layout/partial/compoment/circle/content.ejs +0 -19
  201. package/layout/partial/compoment/dorakika/rightmenu.ejs +0 -100
  202. package/layout/partial/compoment/equipment/list.ejs +0 -37
  203. package/layout/partial/compoment/home/homeCategoryBar.ejs +0 -11
  204. package/layout/partial/compoment/home/postList.ejs +0 -37
  205. package/layout/partial/compoment/hometop/bbTimeList.ejs +0 -15
  206. package/layout/partial/compoment/hometop/categoryGroup.ejs +0 -19
  207. package/layout/partial/compoment/hometop/groupTag.ejs +0 -30
  208. package/layout/partial/compoment/hometop/topGroup.ejs +0 -41
  209. package/layout/partial/compoment/inject/body.ejs +0 -70
  210. package/layout/partial/compoment/links/angle.ejs +0 -26
  211. package/layout/partial/compoment/links/banner.ejs +0 -42
  212. package/layout/partial/compoment/links/linksCard.ejs +0 -27
  213. package/layout/partial/compoment/links/linksItem.ejs +0 -21
  214. package/layout/partial/compoment/mixins/articleSort.ejs +0 -26
  215. package/layout/partial/compoment/mixins/pagination.ejs +0 -11
  216. package/layout/partial/compoment/nav/left.ejs +0 -22
  217. package/layout/partial/compoment/nav/menu.ejs +0 -25
  218. package/layout/partial/compoment/nav/right.ejs +0 -42
  219. package/layout/partial/compoment/post/award.ejs +0 -60
  220. package/layout/partial/compoment/post/copyright.ejs +0 -39
  221. package/layout/partial/compoment/post/postMeta.ejs +0 -85
  222. package/layout/partial/compoment/post/postNav.ejs +0 -41
  223. package/layout/partial/compoment/post/wave.ejs +0 -14
  224. package/layout/partial/compoment/says/banner.ejs +0 -10
  225. package/layout/partial/compoment/says/saysBottom.ejs +0 -18
  226. package/layout/partial/compoment/says/saysContent.ejs +0 -10
  227. package/layout/partial/compoment/says/saysFunction.ejs +0 -15
  228. package/layout/partial/compoment/third-party/comments/comment.ejs +0 -12
  229. package/layout/partial/compoment/third-party/comments/twikoo_k.ejs +0 -29
  230. package/layout/partial/compoment/third-party/music.ejs +0 -5
  231. package/layout/partial/compoment/third-party/pjax.ejs +0 -31
  232. package/layout/partial/compoment/third-party/search/algolia-search.ejs +0 -20
  233. package/layout/partial/compoment/third-party/search/index.ejs +0 -10
  234. package/layout/partial/compoment/third-party/search/local-search.ejs +0 -22
  235. package/layout/partial/compoment/tlink/banner.ejs +0 -10
  236. package/layout/partial/console.ejs +0 -68
  237. package/layout/partial/footer.ejs +0 -109
  238. package/layout/partial/head.ejs +0 -37
  239. package/layout/partial/header.ejs +0 -6
  240. package/layout/partial/hometop.ejs +0 -15
  241. package/layout/partial/nav.ejs +0 -34
  242. package/layout/partial/pwa.ejs +0 -40
  243. package/layout/partial/sidebar.ejs +0 -31
  244. package/layout/post.ejs +0 -52
  245. package/layout/tag.ejs +0 -19
  246. package/scripts/helper/randomLinks.js +0 -16
  247. package/scripts/helper/themeJsExport.js +0 -79
  248. package/source/css/commentBarrage.css +0 -174
  249. package/source/css/custom.css +0 -901
  250. package/source/css/main.css +0 -16285
  251. package/source/css/search/algolia-search.css +0 -141
  252. package/source/css/search/local-search.css +0 -138
  253. package/source/css/var.css +0 -189
  254. /package/source/js/{rightmenu.js → rightside.js} +0 -0
@@ -1,147 +1,164 @@
1
- const $searchMask = document.getElementById('search-mask'),
2
- $searchDialog = document.querySelector('#algolia-search .search-dialog')
3
-
4
- class search {
5
- static openSearch() {
6
- utils.fadeIn($searchMask, '0.5')
7
- utils.fadeIn($searchDialog, '0.5')
8
- document.addEventListener('keydown', function f(event) {
9
- if (event.code === 'Escape') {
10
- closeSearch()
11
- document.removeEventListener('keydown', f)
1
+ window.addEventListener("load", () => {
2
+ const $searchMask = document.getElementById("search-mask");
3
+ const $searchDialog = document.querySelector("#algolia-search .search-dialog");
4
+
5
+ const openSearch = () => {
6
+ utils.animateIn($searchMask, "to_show 0.5s");
7
+ $searchDialog.style.display = "block";
8
+ setTimeout(() => {
9
+ document.querySelector("#algolia-search .ais-SearchBox-input").focus();
10
+ }, 100);
11
+ document.addEventListener("keydown", function f(event) {
12
+ if (event.code === "Escape") {
13
+ closeSearch();
14
+ document.removeEventListener("keydown", f);
12
15
  }
13
- })
14
- }
16
+ });
17
+ fixSafariHeight();
18
+ window.addEventListener("resize", fixSafariHeight);
19
+ };
20
+
21
+ const closeSearch = () => {
22
+ utils.animateOut($searchDialog, "search_close .5s");
23
+ utils.animateOut($searchMask, "to_hide 0.5s");
24
+ window.removeEventListener("resize", fixSafariHeight);
25
+ };
26
+
27
+ const fixSafariHeight = () => {
28
+ if (window.innerWidth < 768) {
29
+ $searchDialog.style.setProperty("--search-height", window.innerHeight + "px");
30
+ }
31
+ };
32
+
33
+ const searchClickFn = () => {
34
+ utils.addEventListenerPjax(document.querySelector("#search-button > .search"), "click", openSearch);
35
+ };
15
36
 
16
- static closeSearch() {
17
- utils.fadeOut($searchDialog, '0.5')
18
- utils.fadeOut($searchMask, '0.5')
37
+ const searchFnOnce = () => {
38
+ $searchMask.addEventListener("click", closeSearch);
39
+ document.querySelector("#algolia-search .search-close-button").addEventListener("click", closeSearch);
40
+ };
41
+
42
+ const algolia = GLOBAL_CONFIG.algolia;
43
+ const isAlgoliaValid = algolia.appId && algolia.apiKey && algolia.indexName;
44
+ if (!isAlgoliaValid) {
45
+ return console.error("Algolia setting is invalid!");
19
46
  }
20
47
 
21
- static cutContent(content) {
22
- if (content === '') return ''
48
+ const search = instantsearch({
49
+ indexName: algolia.indexName,
50
+ searchClient: algoliasearch(algolia.appId, algolia.apiKey),
51
+ searchFunction(helper) {
52
+ if (helper.state.query) {
53
+ let innerLoading = '<i class="scoicon sco-loading-line sco-spin"></i>';
54
+ document.getElementById("algolia-hits").innerHTML = innerLoading;
55
+ helper.search();
56
+ }
57
+ },
58
+ });
23
59
 
24
- const firstOccur = content.indexOf('<mark>')
60
+ const configure = instantsearch.widgets.configure({
61
+ hitsPerPage: algolia.hits.per_page ?? 5,
62
+ });
25
63
 
26
- let start = firstOccur - 30
27
- let end = firstOccur + 120
28
- let pre = ''
29
- let post = ''
64
+ const searchBox = instantsearch.widgets.searchBox({
65
+ container: "#algolia-search-input",
66
+ showReset: false,
67
+ showSubmit: false,
68
+ placeholder: GLOBAL_CONFIG.lang.search.placeholder,
69
+ showLoadingIndicator: true,
70
+ searchOnEnterKeyPressOnly: true,
71
+ searchAsYouType: false,
72
+ });
30
73
 
31
- if (start <= 0) {
32
- start = 0
33
- end = 140
34
- } else {
35
- pre = '...'
36
- }
74
+ const hits = instantsearch.widgets.hits({
75
+ container: "#algolia-hits",
76
+ templates: {
77
+ item(data) {
78
+ const link = data.permalink ? data.permalink : GLOBAL_CONFIG.root + data.path;
79
+ const result = data._highlightResult;
80
+ const loadingLogo = document.querySelector("#algolia-hits .sco-spin");
81
+ if (loadingLogo) {
82
+ loadingLogo.style.display = "none";
83
+ }
84
+ setTimeout(() => {
85
+ document.querySelector("#algolia-search .ais-SearchBox-input").focus();
86
+ }, 200);
87
+ return `
88
+ <a href="${link}" class="algolia-hit-item-link">
89
+ <span class="algolia-hits-item-title">${result.title.value || "no-title"}</span>
90
+ </a>`;
91
+ },
92
+ empty: function (data) {
93
+ const loadingLogo = document.querySelector("#algolia-hits .sco-spin");
94
+ if (loadingLogo) {
95
+ loadingLogo.style.display = "none";
96
+ }
97
+ setTimeout(() => {
98
+ document.querySelector("#algolia-search .ais-SearchBox-input").focus();
99
+ }, 200);
100
+ return (
101
+ '<div id="algolia-hits-empty">' +
102
+ GLOBAL_CONFIG.lang.search.empty.replace(/\$\{query}/, data.query) +
103
+ "</div>"
104
+ );
105
+ },
106
+ },
107
+ cssClasses: {
108
+ item: "algolia-hit-item",
109
+ },
110
+ });
37
111
 
38
- if (end > content.length) {
39
- end = content.length
40
- } else {
41
- post = '...'
42
- }
112
+ const pagination = instantsearch.widgets.pagination({
113
+ container: "#algolia-pagination",
114
+ totalPages: algolia.hits.per_page ?? 5,
115
+ scrollTo: false,
116
+ showFirstLast: false,
117
+ templates: {
118
+ first: '<i class="scoicon sco-show-left-line"></i>',
119
+ last: '<i class="scoicon sco-show-right-line"></i>',
120
+ previous: '<i class="scoicon sco-arrow-left-bold"></i>',
121
+ next: '<i class="scoicon sco-arrow-right-bold"></i>',
122
+ },
123
+ cssClasses: {
124
+ root: "pagination",
125
+ item: "pagination-item",
126
+ link: "page-number",
127
+ active: "current",
128
+ disabled: "disabled-item",
129
+ },
130
+ });
43
131
 
44
- const matchContent = pre + content.substring(start, end) + post
45
- return matchContent
46
- }
132
+ const stats = instantsearch.widgets.stats({
133
+ container: "#algolia-tips > #algolia-stats",
134
+ templates: {
135
+ text: function (data) {
136
+ const stats = GLOBAL_CONFIG.lang.search.hit
137
+ .replace(/\$\{hits}/, data.nbHits)
138
+ .replace(/\$\{time}/, data.processingTimeMS);
139
+ return `<hr>${stats}`;
140
+ },
141
+ },
142
+ });
47
143
 
48
- static search() {
49
- const algolia = GLOBALCONFIG.algolia, that = this
50
- const isAlgoliaValid = algolia.appId && algolia.apiKey && algolia.indexName
51
- if (!isAlgoliaValid) {
52
- return console.error('Algolia setting is invalid!')
53
- }
144
+ const powerBy = instantsearch.widgets.poweredBy({
145
+ container: "#algolia-tips > #algolia-poweredBy",
146
+ });
54
147
 
55
- const init = instantsearch({
56
- indexName: algolia.indexName,
57
- searchClient: algoliasearch(algolia.appId, algolia.apiKey),
58
- searchFunction(helper) {
59
- helper.state.query && helper.search()
60
- }
61
- })
62
-
63
- const searchBox = instantsearch.widgets.searchBox({
64
- container: '#search-input',
65
- showReset: false,
66
- showSubmit: false,
67
- autofocus: true,
68
- placeholder: GLOBALCONFIG.lang.search.placeholder,
69
- showLoadingIndicator: false
70
- })
71
-
72
- const hits = instantsearch.widgets.hits({
73
- container: '#algolia-hits',
74
- templates: {
75
- item(data) {
76
- const link = '/posts/' + data.permalink.split('/')[4]
77
- const result = data._highlightResult
78
- const content = result.contentStripTruncate
79
- ? that.cutContent(result.contentStripTruncate.value)
80
- : result.contentStrip
81
- ? that.cutContent(result.contentStrip.value)
82
- : result.content
83
- ? that.cutContent(result.content.value)
84
- : ''
85
- return `
86
- <a href="${link}" class="algolia-hit-item-link">
87
- ${result.title.value}
88
- </a>
89
- <p class="algolia-hit-item-content">${content}</p>`
90
- },
91
- empty: function (data) {
92
- return (
93
- `<div id="algolia-hits-empty">${GLOBALCONFIG.lang.search.empty}</div>`
94
- )
95
- }
96
- }
97
- })
98
-
99
- const stats = instantsearch.widgets.stats({
100
- container: '.algolia-stats',
101
- templates: {
102
- text: function (data) {
103
- const stats = GLOBALCONFIG.lang.search.hit.replace('${query}', `<mark>${data.nbHits}</mark>`)
104
- return (
105
- stats
106
- )
107
- }
108
- }
109
- })
148
+ search.addWidgets([configure, searchBox,stats, hits,powerBy, pagination]); // add the widgets to the instantsearch instance
110
149
 
111
- init.addWidgets([searchBox, hits, stats]) // add the widgets to the instantsearch instance
112
- init.start()
113
- init.on('render', () => {
114
- pjax.refresh(document.getElementById('algolia-hits'))
115
- })
116
- }
117
- }
118
-
119
- const searchClickFn = () => {
120
- document.querySelector('#search-button > .search').addEventListener('click', search.openSearch)
121
- document.getElementById('menu-search').addEventListener('click', function() {
122
- rm.hideRightMenu();
123
- search.openSearch();
124
- let t = document.getElementsByClassName('ais-search-box--input')[0];
125
- let evt = new Event('input', {
126
- bubbles: true,
127
- cancelable: true
128
- });
129
- t.value = selectTextNow;
130
- t.dispatchEvent(evt);
150
+ search.start();
151
+
152
+ searchClickFn();
153
+ searchFnOnce();
154
+
155
+ window.addEventListener("pjax:complete", () => {
156
+ !utils.isHidden($searchMask) && closeSearch();
157
+ searchClickFn();
158
+ });
159
+
160
+ window.pjax &&
161
+ search.on("render", () => {
162
+ window.pjax.refresh(document.getElementById("algolia-hits"));
131
163
  });
132
- }
133
-
134
- const searchClickFnOnce = () => {
135
- document.querySelector('#algolia-search .search-close-button').addEventListener('click', search.closeSearch)
136
- $searchMask.addEventListener('click', search.closeSearch)
137
- }
138
-
139
- window.addEventListener('load', () => {
140
- searchClickFn()
141
- searchClickFnOnce()
142
- search.search()
143
- })
144
-
145
- window.addEventListener('pjax:complete', () => {
146
- searchClickFn()
147
- })
164
+ });
@@ -1,171 +1,146 @@
1
- const $searchMask = document.getElementById('search-mask'),
2
- $searchDialog = document.querySelector('#local-search .search-dialog'),
3
- $input = document.querySelector('#search-input'),
4
- $resultContent = document.getElementById('search-results'),
5
- $loadingStatus = document.getElementById('loading-status')
6
- let dataObj = null
7
-
8
- class search{
9
- static openSearch(){
10
- utils.fadeIn($searchMask, '0.5')
11
- utils.fadeIn($searchDialog, '0.5')
12
- setTimeout(() => { document.querySelector('#search-input').focus() }, 100)
13
- search.search()
14
- document.addEventListener('keydown', function f (event) {
15
- if (event.code === 'Escape') {
16
- closeSearch()
17
- document.removeEventListener('keydown', f)
18
- }
19
- })
20
- }
1
+ window.onload = () => {
2
+ let idx, store = [];
3
+ const $searchMask = document.getElementById("search-mask");
4
+ const $searchDialog = document.querySelector("#local-search .search-dialog");
5
+ const openSearch = () => {
6
+ utils.animateIn($searchMask, "to_show 0.5s");
7
+ $searchDialog.style.display = "block";
8
+ setTimeout(() => {
9
+ document.querySelector("#local-search .search-box-input").focus();
10
+ }, 100);
11
+ document.addEventListener("keydown", function f(event) {
12
+ if (event.code === "Escape") {
13
+ closeSearch();
14
+ document.removeEventListener("keydown", f);
15
+ }
16
+ });
17
+ fixSafariHeight();
18
+ window.addEventListener("resize", fixSafariHeight);
19
+ };
20
+ const fixSafariHeight = () => {
21
+ if (window.innerWidth < 768) {
22
+ $searchDialog.style.setProperty("--search-height", window.innerHeight + "px");
23
+ }
24
+ };
25
+ const closeSearch = () => {
26
+ utils.animateOut($searchDialog, "search_close .5s");
27
+ utils.animateOut($searchMask, "to_hide 0.5s");
28
+ window.removeEventListener("resize", fixSafariHeight);
29
+ };
30
+ utils.addEventListenerPjax(document.querySelector("#search-button > .search"), "click", openSearch);
31
+ utils.addEventListenerPjax(document.querySelector("#local-search .search-close-button"), "click", closeSearch);
32
+ function initLunr() {
33
+ fetch("/search.xml")
34
+ .then(response => response.text())
35
+ .then(data => {
36
+ let parser = new DOMParser();
37
+ let xmlDoc = parser.parseFromString(data, "text/xml");
38
+ let entries = xmlDoc.getElementsByTagName("entry");
39
+ for (let i = 0; i < entries.length; i++) {
40
+ let entry = entries[i];
41
+ let title = entry.getElementsByTagName("title")[0].textContent;
42
+ let link = entry.getElementsByTagName("url")[0].textContent;
43
+ let content = entry.getElementsByTagName("content")[0].textContent;
44
+ store.push({
45
+ 'title': title,
46
+ 'link': link,
47
+ 'content': content
48
+ });
49
+ }
21
50
 
22
- static closeSearch(){
23
- utils.fadeOut($searchDialog, '0.5')
24
- utils.fadeOut($searchMask, '0.5')
25
- }
51
+ idx = lunr(function () {
52
+ this.ref('link');
53
+ this.field('title', {boost: 10});
54
+ this.field('content');
26
55
 
27
- static async fetchData(path){
28
- let data = []
29
- const response = await fetch(path)
30
- const res = await new window.DOMParser().parseFromString(await response.text(), 'text/xml')
31
- data = [...res.querySelectorAll('entry')].map(item => {
32
- return {
33
- title: item.querySelector('title').textContent,
34
- content: item.querySelector('content') && item.querySelector('content').textContent,
35
- url: item.querySelector('url').textContent
36
- }
37
- })
38
- if (response.ok) {
39
- const $loadDataItem = document.getElementById('loading-database')
40
- $loadDataItem.nextElementSibling.style.display = 'block'
41
- $loadDataItem.remove()
56
+ store.forEach(function (doc) {
57
+ this.add(doc);
58
+ }, this);
59
+ });
60
+ })
61
+ .catch(err => console.error("Error loading search data:", err));
42
62
  }
43
- return data
44
- }
45
-
46
- static search(){
47
- if (!GLOBALCONFIG.localsearch.preload && dataObj === null) dataObj = this.fetchData(GLOBALCONFIG.localsearch.path)
48
- $input.addEventListener('input', function type() {
49
- const keywords = this.value.trim().toLowerCase().split(/[\s]+/)
50
- if (keywords[0] !== '') $loadingStatus.innerHTML = '<i class="scoicon sco-loading-line"></i><span>加载中</span>'
51
- else {
52
- $resultContent.innerHTML = ''
53
- return
54
- }
63
+ let query = ''
64
+ let currentPage = 0;
65
+ const resultsPerPage = 10;
66
+ let results = [];
55
67
 
56
- if (keywords.length <= 0) return
57
- let count = 0, str = '<div class="search-result-list">'
58
- // perform local searching
59
- dataObj.then(data => {
60
- data.forEach(data => {
61
- let isMatch = true
62
- let dataTitle = data.title ? data.title.trim().toLowerCase() : ''
63
- const dataContent = data.content ? data.content.trim().replace(/<[^>]+>/g, '').toLowerCase() : ''
64
- const dataUrl = data.url.startsWith('/') ? data.url : GLOBALCONFIG.root + data.url
65
- let indexTitle = -1
66
- let indexContent = -1
67
- let firstOccur = -1
68
- // only match articles with not empty titles and contents
69
- if (dataTitle !== '' || dataContent !== '') {
70
- keywords.forEach((keyword, i) => {
71
- indexTitle = dataTitle.indexOf(keyword)
72
- indexContent = dataContent.indexOf(keyword)
73
- if (indexTitle < 0 && indexContent < 0) {
74
- isMatch = false
75
- } else {
76
- if (indexContent < 0) {
77
- indexContent = 0
68
+ function initUI() {
69
+ const $results = document.getElementById("search-results");
70
+ const $search = document.getElementById("search-input");
71
+ $search.addEventListener('keydown', function (e) {
72
+ if (e.keyCode === 13) {
73
+ $results.innerHTML = '';
74
+ query = this.value;
75
+ results = search(query);
76
+ renderResults(results, currentPage);
77
+ renderPagination(results.length);
78
78
  }
79
- if (i === 0) {
80
- firstOccur = indexContent
81
- }
82
- }
83
- })
84
- } else {
85
- isMatch = false
86
- }
87
-
88
- // show search results
89
- if (isMatch) {
90
- if (firstOccur >= 0) {
91
- // cut out 130 characters
92
- let start = firstOccur - 30
93
- let end = firstOccur + 100
94
- let pre = ''
95
- let post = ''
96
-
97
- if (start < 0) {
98
- start = 0
99
- }
100
-
101
- if (start === 0) {
102
- end = 100
103
- } else {
104
- pre = '...'
105
- }
106
-
107
- if (end > dataContent.length) {
108
- end = dataContent.length
109
- } else {
110
- post = '...'
111
- }
112
-
113
- let matchContent = dataContent.substring(start, end)
114
- // highlight all keywords
115
- keywords.forEach(keyword => {
116
- const regex = new RegExp(`(?!<[^>]*?)(${keyword})(?![^<]*?>)`, 'gi')
117
- matchContent = matchContent.replaceAll(regex, '<span class="search-keyword">$1</span>')
118
- dataTitle = dataTitle.replaceAll(regex, '<span class="search-keyword">$1</span>')
119
- })
120
-
121
- str += '<div class="search__hit-item"><a href="' + dataUrl + '"><span class="search-result-title">' + dataTitle + '</span>'
122
- count += 1
123
- if (dataContent !== '') {
124
- str += '<div class="search-result">' + pre + matchContent + post + '</div>'
125
- }
126
79
  }
127
- str += '</a></div>'
128
- }
129
- })
130
- if (count === 0) {
131
- str += `<div id="search__hits-empty">${GLOBALCONFIG.lang.search.empty}</div>`
132
- }else{
133
- str += `<div class="search__hits-count">${GLOBALCONFIG.lang.search.hit.replace('${query}', '<span class="search-keyword">' + count + '</span>')}</div>`
80
+ )
81
+ ;
82
+ }
83
+ function search(query) {
84
+ return idx.search(query).map(result => {
85
+ return store.filter(page => {
86
+ return page.link === result.ref;
87
+ })[0];
88
+ });
89
+ }
90
+ function renderResults(results, page) {
91
+ const $search_results = document.getElementById("search-results");
92
+ $search_results.innerHTML = '';
93
+ const $tips = document.getElementById("search-tips")
94
+ $tips.innerHTML = '';
95
+ const start = page * resultsPerPage;
96
+ const end = start + resultsPerPage;
97
+ if (!results.length) {
98
+ const $empty = document.createElement("span");
99
+ $empty.className = "search-result-empty";
100
+ $empty.textContent = GLOBAL_CONFIG.lang.search.empty.replace(/\$\{query}/, query);
101
+ $search_results.appendChild($empty);
102
+ return;
134
103
  }
135
- str += '</div>'
136
- $resultContent.innerHTML = str
137
- if (keywords[0] !== '') $loadingStatus.innerHTML = ''
138
- })
139
- })
140
- }
141
- }
104
+ results.slice(start, end).forEach(function (result) {
105
+ const $result = document.createElement("li");
106
+ $result.className = "search-result-item";
107
+ const $link = document.createElement("a");
108
+ $link.className = "search-result-title";
109
+ $link.href = result.link;
110
+ $link.textContent = result.title;
111
+ $result.appendChild($link);
112
+ $search_results.appendChild($result);
113
+ });
114
+ const count = document.createElement("span");
115
+ count.className = "search-result-count";
116
+ count.innerHTML = `共 <b>${results.length}</b> 条结果`;
117
+ $tips.appendChild(count);
118
+ }
119
+ function renderPagination(totalResults) {
120
+ const totalPages = Math.ceil(totalResults / resultsPerPage);
121
+ const paginationContainer = document.getElementById("search-pagination");
122
+ paginationContainer.innerHTML = '';
123
+ const paginationList = document.createElement("ul");
124
+ paginationList.className = "pagination-list";
142
125
 
143
- const searchClickFn = () => {
144
- document.querySelector('#search-button > .search').addEventListener('click', search.openSearch)
145
- document.getElementById('menu-search').addEventListener('click', function() {
146
- rm.hideRightMenu();
147
- search.openSearch();
148
- let t = document.getElementsByClassName('search-box-input')[0];
149
- let evt = new Event('input', {
150
- bubbles: true,
151
- cancelable: true
126
+ for (let i = 0; i < totalPages; i++) {
127
+ const button = document.createElement("li");
128
+ button.className = "pagination-item";
129
+ button.textContent = i + 1;
130
+ if (i === currentPage) {
131
+ button.classList.add('select');
132
+ }
133
+ button.addEventListener('click', function () {
134
+ currentPage = i;
135
+ renderResults(results, i);
136
+ });
137
+ paginationList.appendChild(button);
138
+ }
139
+ paginationContainer.appendChild(paginationList);
140
+ }
141
+ initLunr();
142
+ initUI();
143
+ window.addEventListener('DOMContentLoaded', (event) => {
144
+ initUI();
152
145
  });
153
- t.value = selectTextNow;
154
- t.dispatchEvent(evt);
155
- })
156
- }
157
-
158
- const searchClickFnOnce = () => {
159
- document.querySelector('#local-search .search-close-button').addEventListener('click', search.closeSearch)
160
- $searchMask.addEventListener('click', search.closeSearch)
161
- if (GLOBALCONFIG.localsearch.preload) dataObj = search.fetchData(GLOBALCONFIG.localsearch.path)
162
- }
163
-
164
- window.addEventListener('load', () => {
165
- searchClickFn()
166
- searchClickFnOnce()
167
- })
168
-
169
- window.addEventListener('pjax:complete', () => {
170
- searchClickFn()
171
- })
146
+ }