hexo-theme-solitude 3.0.20 → 4.0.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 (143) hide show
  1. package/.github/FUNDING.yml +3 -3
  2. package/README.md +11 -1
  3. package/README_en-US.md +11 -1
  4. package/_config.yml +16 -7
  5. package/languages/default.yml +56 -36
  6. package/languages/en.yml +90 -69
  7. package/languages/es.yml +94 -73
  8. package/languages/zh-CN.yml +56 -34
  9. package/languages/zh-TW.yml +80 -57
  10. package/layout/archive.pug +60 -14
  11. package/layout/category.pug +13 -11
  12. package/layout/includes/body/gadsense.pug +2 -2
  13. package/layout/includes/console.pug +71 -72
  14. package/layout/includes/footer.pug +38 -24
  15. package/layout/includes/head/config.pug +83 -39
  16. package/layout/includes/head/mode.pug +7 -7
  17. package/layout/includes/head/page_config.pug +20 -11
  18. package/layout/includes/inject/body.pug +18 -40
  19. package/layout/includes/keyboard.pug +3 -3
  20. package/layout/includes/loading.pug +1 -37
  21. package/layout/includes/mixins/articleSort.pug +3 -3
  22. package/layout/includes/mixins/common.pug +8 -4
  23. package/layout/includes/mixins/pace.pug +1 -1
  24. package/layout/includes/mixins/pagination.pug +3 -3
  25. package/layout/includes/nav.pug +5 -4
  26. package/layout/includes/page/about.pug +9 -8
  27. package/layout/includes/page/brevity.pug +2 -2
  28. package/layout/includes/page/links.pug +23 -11
  29. package/layout/includes/page/music.pug +0 -5
  30. package/layout/includes/rightmenu.pug +20 -20
  31. package/layout/includes/sidebar.pug +2 -2
  32. package/layout/includes/widgets/aside/asideInfoCard.pug +2 -2
  33. package/layout/includes/widgets/aside/asideTag.pug +2 -2
  34. package/layout/includes/widgets/home/bbTimeList.pug +3 -3
  35. package/layout/includes/widgets/home/categoryBar.pug +30 -15
  36. package/layout/includes/widgets/home/hometop.pug +113 -8
  37. package/layout/includes/widgets/home/postList.pug +1 -2
  38. package/layout/includes/widgets/home/topGroup.pug +3 -7
  39. package/layout/includes/widgets/nav/group.pug +4 -2
  40. package/layout/includes/widgets/nav/menu.pug +6 -4
  41. package/layout/includes/widgets/nav/right.pug +7 -6
  42. package/layout/includes/widgets/page/about/award.pug +67 -38
  43. package/layout/includes/widgets/page/about/hobbies.pug +12 -3
  44. package/layout/includes/widgets/page/banner.pug +1 -1
  45. package/layout/includes/widgets/page/kit/content.pug +2 -2
  46. package/layout/includes/widgets/page/links/banner.pug +30 -19
  47. package/layout/includes/widgets/page/message/artalk.pug +3 -3
  48. package/layout/includes/widgets/page/message/content.pug +3 -3
  49. package/layout/includes/widgets/page/message/twikoo.pug +3 -3
  50. package/layout/includes/widgets/page/message/valine.pug +4 -4
  51. package/layout/includes/widgets/page/message/waline.pug +3 -3
  52. package/layout/includes/widgets/page/recentcomment/artalk.pug +5 -9
  53. package/layout/includes/widgets/page/recentcomment/twikoo.pug +5 -9
  54. package/layout/includes/widgets/page/recentcomment/valine.pug +6 -10
  55. package/layout/includes/widgets/page/recentcomment/waline.pug +5 -9
  56. package/layout/includes/widgets/post/award.pug +1 -28
  57. package/layout/includes/widgets/post/copyright.pug +10 -10
  58. package/layout/includes/widgets/post/postInfo.pug +10 -11
  59. package/layout/includes/widgets/post/postMeta.pug +3 -2
  60. package/layout/includes/widgets/rightside/hide.pug +5 -5
  61. package/layout/includes/widgets/rightside/show.pug +7 -7
  62. package/layout/includes/widgets/third-party/comments/artalk.pug +9 -9
  63. package/layout/includes/widgets/third-party/comments/giscus.pug +2 -2
  64. package/layout/includes/widgets/third-party/comments/twikoo.pug +5 -5
  65. package/layout/includes/widgets/third-party/comments/valine.pug +6 -6
  66. package/layout/includes/widgets/third-party/comments/waline.pug +6 -6
  67. package/layout/includes/widgets/third-party/hot/index.pug +1 -1
  68. package/layout/includes/widgets/third-party/hot/twikoo.pug +1 -1
  69. package/layout/includes/widgets/third-party/music.pug +9 -5
  70. package/layout/includes/widgets/third-party/news-comment/artalk.pug +6 -6
  71. package/layout/includes/widgets/third-party/news-comment/twikoo.pug +7 -7
  72. package/layout/includes/widgets/third-party/news-comment/valine.pug +8 -8
  73. package/layout/includes/widgets/third-party/news-comment/waline.pug +7 -7
  74. package/layout/includes/widgets/third-party/pjax.pug +16 -10
  75. package/layout/includes/widgets/third-party/search/algolia-search.pug +2 -2
  76. package/layout/includes/widgets/third-party/search/docsearch.pug +3 -3
  77. package/layout/includes/widgets/third-party/search/index.pug +1 -3
  78. package/layout/includes/widgets/third-party/search/local-search.pug +9 -9
  79. package/layout/index.pug +10 -8
  80. package/package.json +8 -7
  81. package/plugins.yml +22 -21
  82. package/scripts/event/cdn.js +11 -6
  83. package/scripts/event/friend_links.js +30 -0
  84. package/scripts/event/merge_config.js +15 -7
  85. package/scripts/filter/comment.js +2 -2
  86. package/scripts/filter/default.js +1 -1
  87. package/scripts/helper/inject_head_js.js +79 -33
  88. package/scripts/helper/related_post.js +16 -21
  89. package/scripts/tags/chart.js +1 -1
  90. package/scripts/tags/typeit.js +1 -1
  91. package/source/css/_components/capsule.styl +259 -168
  92. package/source/css/_components/rightside.styl +98 -242
  93. package/source/css/_global/animation.styl +1 -10
  94. package/source/css/_global/index.styl +27 -1
  95. package/source/css/_layout/aside.styl +7 -1
  96. package/source/css/_layout/console.styl +144 -163
  97. package/source/css/_layout/header.styl +238 -47
  98. package/source/css/_layout/pagination.styl +176 -132
  99. package/source/css/_layout/rightmenu.styl +11 -2
  100. package/source/css/_layout/sidebar.styl +39 -17
  101. package/source/css/_mode/index.styl +7 -1
  102. package/source/css/_page/_about/about.styl +18 -2
  103. package/source/css/_page/_about/buff.styl +1 -1
  104. package/source/css/_page/_about/contentinfo.styl +2 -1
  105. package/source/css/_page/_about/game.styl +57 -1
  106. package/source/css/_page/_about/like.styl +7 -2
  107. package/source/css/_page/_about/maxim.styl +1 -1
  108. package/source/css/_page/_about/reward.styl +226 -108
  109. package/source/css/_page/_about/skills.styl +5 -3
  110. package/source/css/_page/_home/category-bar.styl +162 -88
  111. package/source/css/_page/_home/home-top.styl +309 -263
  112. package/source/css/_page/_home/home.styl +34 -7
  113. package/source/css/_page/archive.styl +412 -0
  114. package/source/css/_page/category.styl +27 -1
  115. package/source/css/_page/index.styl +2 -0
  116. package/source/css/_page/links.styl +190 -0
  117. package/source/css/_page/other.styl +37 -0
  118. package/source/css/_post/index.styl +2 -1
  119. package/source/css/_post/meta.styl +245 -217
  120. package/source/css/_search/local-search.styl +158 -82
  121. package/source/css/var.styl +2 -2
  122. package/source/js/archive-page.js +191 -0
  123. package/source/js/core/actions.js +48 -0
  124. package/source/js/core/api.js +32 -0
  125. package/source/js/core/config.js +13 -0
  126. package/source/js/core/lifecycle.js +52 -0
  127. package/source/js/core/preloader.js +34 -0
  128. package/source/js/core/resources.js +65 -0
  129. package/source/js/covercolor/api.js +13 -103
  130. package/source/js/covercolor/ave.js +14 -77
  131. package/source/js/covercolor/local.js +22 -116
  132. package/source/js/covercolor/shared.js +102 -0
  133. package/source/js/friend_links.js +502 -0
  134. package/source/js/main.js +793 -177
  135. package/source/js/music.js +24 -14
  136. package/source/js/post_ai.js +13 -2
  137. package/source/js/right_menu.js +44 -24
  138. package/source/js/search/algolia.js +29 -21
  139. package/source/js/search/local.js +231 -266
  140. package/source/js/tw_cn.js +37 -12
  141. package/source/js/utils.js +37 -25
  142. package/layout/includes/widgets/randomlink.pug +0 -43
  143. package/scripts/filter/randomPosts.js +0 -16
@@ -1,16 +1,16 @@
1
1
  #local-search
2
- div.search-dialog
2
+ div.search-dialog(role="dialog" aria-modal="true" aria-labelledby="local-search-title")
3
3
  nav.search-nav
4
- span.search-dialog-title=__('nav.search')
5
- button.search-close-button
4
+ span.search-dialog-title#local-search-title=__('nav.search')
5
+ button.search-close-button(type="button" aria-label=__('search.close'))
6
6
  i.solitude.fas.fa-xmark
7
7
  div.search-wrap
8
8
  div.search-box
9
- input.search-box-input#search-input(type="text", autocomplete="off", spellcheck="false", autocorrect="off", autocapitalize="off", placeholder=__('search.placeholder'))
10
- div#search-results
11
- #search-hits
12
- each tag in theme.search.tags || []
13
- a.tag-list(href='javascript:void(0);' onclick="pjax.loadUrl('" + url_for('/tags/' + tag) + "/')")=tag
9
+ input.search-box-input#search-input(type="search" autocomplete="off" spellcheck="false" autocorrect="off" autocapitalize="off" placeholder=__('search.placeholder') aria-label=__('search.placeholder'))
10
+ div#search-suggestions(aria-label=__('search.suggestions'))
11
+ each tag in theme.search.tags || []
12
+ button.tag-list(type="button" data-query=tag)=tag
13
+ ul#search-results(hidden)
14
14
  div#search-pagination
15
15
  div#search-tips
16
- div#search-mask
16
+ div#search-mask
package/layout/index.pug CHANGED
@@ -23,7 +23,7 @@ mixin categoryBar()
23
23
  //- 文章列表组件
24
24
  mixin postsList()
25
25
  .recent-posts#recent-posts
26
- +conditionalWrapper(theme.comment.hot_tip.enable)
26
+ if theme.comment.hot_tip.enable
27
27
  include ./includes/widgets/third-party/hot/index.pug
28
28
 
29
29
  each post, index in page.posts.sort("-sticky" || "-date").data
@@ -34,14 +34,16 @@ mixin postsList()
34
34
 
35
35
  //- 首页主内容组件
36
36
  mixin homeContent()
37
- main.layout#content-inner
38
- #home
37
+ main.layout.layout--home#content-inner
38
+ .home-category-bar.category-in-bar
39
39
  +categoryBar()
40
- +postsList()
41
-
42
- //- 侧边栏
43
- include ./includes/widgets/aside/aside
40
+ .home-layout-row
41
+ #home
42
+ +postsList()
43
+
44
+ //- 侧边栏
45
+ include ./includes/widgets/aside/aside
44
46
 
45
47
  block content
46
48
  +homeTop()
47
- +homeContent()
49
+ +homeContent()
package/package.json CHANGED
@@ -1,15 +1,19 @@
1
1
  {
2
2
  "name": "hexo-theme-solitude",
3
- "version": "3.0.20",
3
+ "version": "4.0.0",
4
4
  "description": "A beautiful, powerful, and efficient Hexo theme developed by everfu.",
5
5
  "main": "package.json",
6
+ "scripts": {
7
+ "test": "echo \"Error: no test specified\" && exit 1"
8
+ },
6
9
  "keywords": [
7
10
  "hexo",
8
11
  "theme",
9
12
  "solitude",
10
13
  "Card UI Design",
11
14
  "@everfu",
12
- "everly",
15
+ "everfu",
16
+ "伍拾柒",
13
17
  "hexo-theme-solitude"
14
18
  ],
15
19
  "repository": {
@@ -26,8 +30,5 @@
26
30
  },
27
31
  "homepage": "https://solitude.js.org",
28
32
  "author": "Hexo-Theme-Solitude<o@efu.me>",
29
- "license": "Apache-2.0",
30
- "scripts": {
31
- "test": "echo \"Error: no test specified\" && exit 1"
32
- }
33
- }
33
+ "license": "Apache-2.0"
34
+ }
package/plugins.yml CHANGED
@@ -1,21 +1,21 @@
1
1
  algolia_search:
2
2
  name: algoliasearch
3
3
  file: dist/algoliasearch.umd.js
4
- version: 5.19.0
4
+ version: 5.55.2
5
5
  instantsearch:
6
6
  name: instantsearch.js
7
7
  file: dist/instantsearch.production.min.js
8
- version: 4.75.7
8
+ version: 4.105.0
9
9
  docsearch_css:
10
10
  name: "@docsearch/css"
11
11
  other_name: docsearch-css
12
12
  file: dist/style.css
13
- version: 3.8.2
13
+ version: 3.9.0
14
14
  docsearch_js:
15
15
  name: "@docsearch/js"
16
16
  other_name: docsearch-js
17
17
  file: dist/umd/index.js
18
- version: 3.8.2
18
+ version: 3.9.0
19
19
  pjax:
20
20
  name: pjax
21
21
  file: pjax.min.js
@@ -23,16 +23,16 @@ pjax:
23
23
  twikoo:
24
24
  name: twikoo
25
25
  file: dist/twikoo.all.min.js
26
- version: 1.6.41
26
+ version: 1.7.14
27
27
  waline_js:
28
28
  name: "@waline/client"
29
29
  file: dist/waline.js
30
30
  other_name: waline
31
- version: 3.4.3
31
+ version: 3.15.2
32
32
  waline_css:
33
33
  name: "@waline/client"
34
34
  file: dist/waline.css
35
- version: 3.4.3
35
+ version: 3.15.2
36
36
  other_name: waline
37
37
  valine:
38
38
  name: valine
@@ -50,12 +50,12 @@ katex:
50
50
  name: katex
51
51
  file: dist/katex.min.css
52
52
  other_name: KaTeX
53
- version: 0.16.9
53
+ version: 0.16.47
54
54
  katex_copytex:
55
55
  name: katex
56
56
  file: dist/contrib/copy-tex.min.js
57
57
  other_name: KaTeX
58
- version: 0.16.9
58
+ version: 0.16.47
59
59
  lazyload:
60
60
  name: vanilla-lazyload
61
61
  file: dist/lazyload.iife.min.js
@@ -71,7 +71,7 @@ aplayer_js:
71
71
  meting_js:
72
72
  name: meting
73
73
  file: dist/Meting.min.js
74
- version: 2.0.1
74
+ version: 2.0.2
75
75
  pace_js:
76
76
  name: pace-js
77
77
  other_name: pace
@@ -80,12 +80,12 @@ pace_js:
80
80
  swiper_css:
81
81
  name: swiper
82
82
  file: swiper-bundle.min.css
83
- version: 11.0.5
83
+ version: 14.0.5
84
84
  other_name: Swiper
85
85
  swiper_js:
86
86
  name: swiper
87
87
  file: swiper-bundle.min.js
88
- version: 11.0.5
88
+ version: 14.0.5
89
89
  other_name: Swiper
90
90
  busuanzi_js:
91
91
  name: busuanzi
@@ -98,7 +98,7 @@ snackbar:
98
98
  fontawesome:
99
99
  name: "@fortawesome/fontawesome-free"
100
100
  file: css/all.min.css
101
- version: 6.7.2
101
+ version: 7.3.0
102
102
  other_name: font-awesome
103
103
  medium_zoom:
104
104
  name: medium-zoom
@@ -106,22 +106,22 @@ medium_zoom:
106
106
  version: 1.1.0
107
107
  fancyapps_ui:
108
108
  name: "@fancyapps/ui"
109
- file: dist/fancybox/fancybox.umd.min.js
110
- version: 5.0.36
109
+ file: dist/fancybox/fancybox.umd.js
110
+ version: 6.1.14
111
111
  other_name: fancyapps-ui
112
112
  fancyapps_css:
113
113
  name: "@fancyapps/ui"
114
- file: dist/fancybox/fancybox.min.css
115
- version: 5.0.36
114
+ file: dist/fancybox/fancybox.css
115
+ version: 6.1.14
116
116
  other_name: fancyapps-ui
117
117
  mermaid_js:
118
118
  name: mermaid
119
119
  file: dist/mermaid.js
120
- version: 11.4.1
120
+ version: 11.16.0
121
121
  chart_js:
122
122
  name: chart.js
123
123
  file: dist/chart.umd.js
124
- version: 4.4.1
124
+ version: 4.5.1
125
125
  other_name: Chart.js
126
126
  typeit_js:
127
127
  name: typeit
@@ -139,6 +139,7 @@ qrcode:
139
139
  other_name: qrcodejs
140
140
  color_thief:
141
141
  name: colorthief
142
- file: dist/color-thief.min.js
143
- version: 2.6.0
142
+ file: dist/umd/color-thief.global.js
143
+ version: 3.4.0
144
144
  other_name: color-thief
145
+ cdnjs_format: https://cdn.jsdelivr.net/npm/${name}@${version}/${min_file}
@@ -32,20 +32,24 @@ hexo.extend.filter.register("before_generate", () => {
32
32
  waterfall: { name, file: "js/third_party/waterfall.min.js", version },
33
33
  universe_js: { name, file: "js/third_party/universe.min.js", version },
34
34
  post_ai: { name, file: "js/post_ai.js", version },
35
+ friend_links: { name, file: "js/friend_links.js", version },
35
36
  envelope_js: { name, file: "js/third_party/envelope.min.js", version },
36
37
  };
37
38
 
38
39
  const minFile = (file) =>
39
40
  file.replace(/(?<!\.min)\.(js|css)$/g, (ext) => `.min${ext}`);
40
41
 
42
+ const formatCDN = (format, value) =>
43
+ (format || "").replace(/\$\{(.+?)}/g, (match, key) => value[key]);
44
+
41
45
  const createCDNLink = (data, type, cond = "") => {
42
46
  Object.keys(data).forEach((key) => {
43
- let { name, version, file, other_name } = data[key];
47
+ let { name, version, file, other_name, cdnjs_format } = data[key];
44
48
  const cdnjs_name = other_name || name;
45
49
  const cdnjs_file = file.replace(/^[lib|dist]*\/|browser\//g, "");
46
50
  const min_cdnjs_file = minFile(cdnjs_file);
47
51
  if (cond === "internal") file = `source/${file}`;
48
- const min_file = minFile(file);
52
+ const min_file = cond === "internal" ? file : minFile(file);
49
53
  const verType = CDN.version
50
54
  ? type === "local"
51
55
  ? `?v=${version}`
@@ -69,11 +73,12 @@ hexo.extend.filter.register("before_generate", () => {
69
73
  : `/pluginsSrc/${name}/${file + verType}`,
70
74
  jsdelivr: `https://cdn.jsdelivr.net/npm/${name}${verType}/${min_file}`,
71
75
  unpkg: `https://unpkg.com/${name}${verType}/${file}`,
72
- cdnjs: `https://cdnjs.cloudflare.com/ajax/libs/${cdnjs_name}/${version}/${min_cdnjs_file}`,
73
- custom: (CDN.custom_format || "").replace(
74
- /\$\{(.+?)}/g,
75
- (match, $1) => value[$1]
76
+ cdnjs: formatCDN(
77
+ cdnjs_format ||
78
+ "https://cdnjs.cloudflare.com/ajax/libs/${cdnjs_name}/${version}/${min_cdnjs_file}",
79
+ value
76
80
  ),
81
+ custom: formatCDN(CDN.custom_format, value),
77
82
  };
78
83
 
79
84
  data[key] = cdnSource[type];
@@ -0,0 +1,30 @@
1
+ "use strict";
2
+
3
+ const getFriendLinksMeta = (hexo) => {
4
+ const linksData = hexo.locals.get("data")?.links;
5
+ const groups = Array.isArray(linksData?.links) ? linksData.links : [];
6
+ const total = groups.reduce(
7
+ (count, group) =>
8
+ count + (Array.isArray(group?.link_list) ? group.link_list.length : 0),
9
+ 0
10
+ );
11
+ const configuredThreshold = Number(
12
+ hexo.theme.config.page?.links?.async_threshold
13
+ );
14
+ const threshold =
15
+ Number.isInteger(configuredThreshold) && configuredThreshold >= 0
16
+ ? configuredThreshold
17
+ : 200;
18
+
19
+ return { linksData, total, async: total > threshold };
20
+ };
21
+
22
+ hexo.extend.generator.register("friend-links-data", function () {
23
+ const meta = getFriendLinksMeta(this);
24
+ if (!meta.linksData || meta.total === 0) return;
25
+
26
+ return {
27
+ path: "links.json",
28
+ data: JSON.stringify({ ...meta.linksData, total: meta.total }),
29
+ };
30
+ });
@@ -26,13 +26,16 @@ hexo.extend.filter.register(
26
26
  icon: null,
27
27
  },
28
28
  group: null,
29
- recommendList: {
30
- sup: "Recommend",
31
- title: "Solitude Docs",
32
- url: "https://solitude.js.org/",
33
- img: "/img/default.avif",
34
- color: "none",
35
- },
29
+ recommendList: [
30
+ {
31
+ order: 1,
32
+ sup: "Recommend",
33
+ title: "Solitude Docs",
34
+ url: "https://solitude.js.org/",
35
+ img: "/img/default.avif",
36
+ color: "none",
37
+ },
38
+ ],
36
39
  },
37
40
  aside: {
38
41
  home: { noSticky: "about", Sticky: "allInfo" },
@@ -82,6 +85,7 @@ hexo.extend.filter.register(
82
85
  tags: true,
83
86
  categories: true,
84
87
  archives: 0,
88
+ links: { async_threshold: 200 },
85
89
  default: { cover: ["/img/default.avif"] },
86
90
  },
87
91
  post: {
@@ -136,6 +140,10 @@ hexo.extend.filter.register(
136
140
  theme_color: {
137
141
  dark: "#ffc848",
138
142
  light: "#425AEF",
143
+ nav_hover_text: {
144
+ dark: "#1b1c20",
145
+ light: "#ffffff",
146
+ },
139
147
  },
140
148
  display_mode: {
141
149
  type: "auto",
@@ -9,5 +9,5 @@ hexo.extend.filter.register('before_generate', () => {
9
9
  if (typeof use === 'string') {
10
10
  use = use.split(',').slice(0,2)
11
11
  }
12
- themeConfig.comment.use = use.map(item => item.toLowerCase().replace(/\b[a-z]/g, s => s.toUpperCase()))
13
- })
12
+ themeConfig.comment.use = use.map(item => item.trim().toLowerCase().replace(/\b[a-z]/g, s => s.toUpperCase()))
13
+ })
@@ -14,7 +14,7 @@ hexo.extend.filter.register("after_post_render", function (data) {
14
14
  data.excerpt =
15
15
  layout === "post" ? data.description || data.excerpt : data.title;
16
16
  data.toc = !!(config.aside.toc[layout] && data.toc !== false);
17
- data.aside = layout === "post" ? data.aside || true : data.aside || false;
17
+ data.aside = data.aside !== undefined ? data.aside : (layout === "post");
18
18
  };
19
19
 
20
20
  if (data.layout === "post" || data.layout === "page") {
@@ -7,6 +7,16 @@
7
7
 
8
8
  hexo.extend.helper.register("inject_head_js", function () {
9
9
  const createJS = () => `
10
+ const parseConfig = (id) => {
11
+ const element = document.getElementById(id)
12
+ if (!element) return {}
13
+ try {
14
+ return JSON.parse(element.content?.textContent || element.textContent || '{}')
15
+ } catch (error) {
16
+ console.error('Invalid Solitude config:', error)
17
+ return {}
18
+ }
19
+ }
10
20
  const saveToLocal = {
11
21
  set: function setWithExpiry(key, value, ttl) {
12
22
  if (ttl === 0)
@@ -25,7 +35,13 @@ hexo.extend.helper.register("inject_head_js", function () {
25
35
  if (!itemStr) {
26
36
  return undefined
27
37
  }
28
- const item = JSON.parse(itemStr)
38
+ let item
39
+ try {
40
+ item = JSON.parse(itemStr)
41
+ } catch (error) {
42
+ localStorage.removeItem(key)
43
+ return undefined
44
+ }
29
45
  const now = new Date()
30
46
 
31
47
  if (now.getTime() > item.expiry) {
@@ -35,40 +51,62 @@ hexo.extend.helper.register("inject_head_js", function () {
35
51
  return item.value
36
52
  }
37
53
  };
38
- window.utils = {
54
+ const resourceRequests = new Map()
55
+ const loadResource = (url, create) => {
56
+ const absoluteUrl = new URL(url, document.baseURI).href
57
+ if (resourceRequests.has(absoluteUrl)) return resourceRequests.get(absoluteUrl)
58
+ const request = new Promise((resolve, reject) => {
59
+ const element = create(absoluteUrl)
60
+ element.addEventListener('load', () => resolve(element), {once: true})
61
+ element.addEventListener('error', () => {
62
+ resourceRequests.delete(absoluteUrl)
63
+ reject(new Error('Unable to load ' + absoluteUrl))
64
+ }, {once: true})
65
+ document.head.appendChild(element)
66
+ })
67
+ resourceRequests.set(absoluteUrl, request)
68
+ return request
69
+ }
70
+ const api = window.Solitude || {}
71
+ window.Solitude = api
72
+ api.installLegacyAdapter = () => {
73
+ const aliases = {
74
+ utils: api,
75
+ sco: api,
76
+ GLOBAL_CONFIG: api.config
77
+ }
78
+ Object.entries(aliases).forEach(([name, value]) => {
79
+ if (name in window) return
80
+ Object.defineProperty(window, name, {
81
+ configurable: true,
82
+ enumerable: false,
83
+ value
84
+ })
85
+ })
86
+ }
87
+ Object.defineProperties(api, {
88
+ config: {configurable: true, get: () => parseConfig('site-config')},
89
+ page: {configurable: true, get: () => parseConfig('config-diff')}
90
+ })
91
+ Object.assign(api, {
39
92
  saveToLocal: saveToLocal,
40
- getCSS: (url, id = false) => new Promise((resolve, reject) => {
41
- const link = document.createElement('link')
42
- link.rel = 'stylesheet'
43
- link.href = url
44
- if (id) link.id = id
45
- link.onerror = reject
46
- link.onload = link.onreadystatechange = function() {
47
- const loadState = this.readyState
48
- if (loadState && loadState !== 'loaded' && loadState !== 'complete') return
49
- link.onload = link.onreadystatechange = null
50
- resolve()
51
- }
52
- document.head.appendChild(link)
93
+ loadStyle: (url, options = {}) => loadResource(url, href => {
94
+ const link = document.createElement('link')
95
+ link.rel = 'stylesheet'
96
+ link.href = href
97
+ if (options.id) link.id = options.id
98
+ return link
53
99
  }),
54
- getScript: (url, attr = {}) => new Promise((resolve, reject) => {
55
- const script = document.createElement('script')
56
- script.src = url
57
- script.async = true
58
- script.onerror = reject
59
- script.onload = script.onreadystatechange = function() {
60
- const loadState = this.readyState
61
- if (loadState && loadState !== 'loaded' && loadState !== 'complete') return
62
- script.onload = script.onreadystatechange = null
63
- resolve()
64
- }
65
-
66
- Object.keys(attr).forEach(key => {
67
- script.setAttribute(key, attr[key])
100
+ loadScript: (url, options = {}) => {
101
+ if (url.includes('barrage')) api.installLegacyAdapter()
102
+ return loadResource(url, src => {
103
+ const script = document.createElement('script')
104
+ script.src = src
105
+ script.async = options.async !== false
106
+ Object.entries(options.attributes || {}).forEach(([key, value]) => script.setAttribute(key, value))
107
+ return script
68
108
  })
69
-
70
- document.head.appendChild(script)
71
- }),
109
+ },
72
110
  addGlobalFn: (key, fn, name = false, parent = window) => {
73
111
  const globalFn = parent.globalFn || {}
74
112
  const keyObj = globalFn[key] || {}
@@ -82,7 +120,7 @@ hexo.extend.helper.register("inject_head_js", function () {
82
120
  },
83
121
  addEventListenerPjax: (ele, event, fn, option = false) => {
84
122
  ele.addEventListener(event, fn, option)
85
- utils.addGlobalFn('pjax', () => {
123
+ api.addGlobalFn('pjax', () => {
86
124
  ele.removeEventListener(event, fn, option)
87
125
  })
88
126
  },
@@ -92,7 +130,15 @@ hexo.extend.helper.register("inject_head_js", function () {
92
130
  item.textContent = (date.getMonth() + 1).toString()+'/'+date.getDate().toString();
93
131
  });
94
132
  },
133
+ })
134
+ api.getCSS = (url, id = false) => api.loadStyle(url, {id})
135
+ api.getScript = (url, attr = {}) => api.loadScript(url, {attributes: attr})
136
+ api.on = (name, handler) => {
137
+ const eventName = 'solitude:' + name
138
+ document.addEventListener(eventName, handler)
139
+ return () => document.removeEventListener(eventName, handler)
95
140
  }
141
+ api.navigate = url => api.pjax?.loadUrl ? api.pjax.loadUrl(url) : window.location.assign(url)
96
142
  `;
97
143
  return `<script>(()=>{${createJS()}})()</script>`;
98
144
  });
@@ -12,23 +12,22 @@ hexo.extend.helper.register('related_posts', function (currentPost, allPosts) {
12
12
  const headlineLang = this._p('star');
13
13
 
14
14
  const relatedPostsMap = new Map();
15
+ const currentTags = new Set((currentPost.tags || []).map(tag => tag.name));
15
16
 
16
- currentPost.tags.forEach(tag => {
17
- allPosts.forEach(post => {
18
- if (isTagRelated(tag.name, post.tags) && currentPost.path !== post.path) {
19
- if (!relatedPostsMap.has(post.path)) {
20
- relatedPostsMap.set(post.path, {
21
- title: post.title,
22
- path: post.path,
23
- cover: post.cover || 'var(--default-bg-color)',
24
- weight: 1,
25
- updated: post.updated,
26
- created: post.date
27
- });
28
- } else {
29
- relatedPostsMap.get(post.path).weight += 1;
30
- }
31
- }
17
+ allPosts.forEach(post => {
18
+ if (currentPost.path === post.path) return;
19
+ const weight = (post.tags || []).reduce(
20
+ (count, tag) => count + Number(currentTags.has(tag.name)),
21
+ 0
22
+ );
23
+ if (!weight) return;
24
+ relatedPostsMap.set(post.path, {
25
+ title: post.title,
26
+ path: post.path,
27
+ cover: post.cover || 'var(--default-bg-color)',
28
+ weight,
29
+ updated: post.updated,
30
+ created: post.date
32
31
  });
33
32
  });
34
33
 
@@ -45,7 +44,7 @@ hexo.extend.helper.register('related_posts', function (currentPost, allPosts) {
45
44
  <i class="solitude fas fa-star"></i>
46
45
  <span>${headlineLang}</span>
47
46
  <div class="relatedPosts-link">
48
- <a onclick="event.preventDefault(); toRandomPost();" href="javascript:void(0);" rel="external nofollow" data-pjax-state="">${this._p('random')}</a>
47
+ <a onclick="event.preventDefault(); Solitude.randomPost();" href="javascript:void(0);" rel="external nofollow" data-pjax-state="">${this._p('random')}</a>
49
48
  </div>
50
49
  </div>
51
50
  <div class="relatedPosts-list">`;
@@ -69,10 +68,6 @@ hexo.extend.helper.register('related_posts', function (currentPost, allPosts) {
69
68
  return result;
70
69
  });
71
70
 
72
- function isTagRelated(tagName, tags) {
73
- return tags.some(tag => tagName === tag.name);
74
- }
75
-
76
71
  function compare(attr, dateType) {
77
72
  return (a, b) => {
78
73
  const val1 = a[attr];
@@ -18,7 +18,7 @@ const chart = (args, content) => {
18
18
  new Chart(ctx, {${content}});
19
19
  };
20
20
  document.addEventListener("DOMContentLoaded", chart);
21
- utils.addEventListenerPjax(document, "pjax:complete", chart);
21
+ Solitude.addEventListenerPjax(document, "pjax:complete", chart);
22
22
  }()
23
23
  </script>
24
24
  </div>`;
@@ -19,7 +19,7 @@ const typeit = ([tag], content) => {
19
19
  .go();
20
20
  }
21
21
  document.addEventListener("DOMContentLoaded", typeit);
22
- utils.addEventListenerPjax(document, "pjax:complete", typeit);
22
+ Solitude.addEventListenerPjax(document, "pjax:complete", typeit);
23
23
  }()
24
24
  </script>
25
25
  </div>`