hexo-theme-volantis 5.8.1 → 6.0.1

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 (113) hide show
  1. package/CHANGELOG.md +5 -39
  2. package/_cdn.yml +449 -0
  3. package/_config.yml +155 -157
  4. package/languages/en.yml +9 -10
  5. package/languages/zh-CN.yml +11 -15
  6. package/languages/zh-TW.yml +10 -11
  7. package/layout/_meta/category.ejs +10 -5
  8. package/layout/_meta/counter.ejs +14 -17
  9. package/layout/_meta/tags.ejs +3 -0
  10. package/layout/_meta/walinecount.ejs +1 -1
  11. package/layout/_partial/article.ejs +14 -9
  12. package/layout/_partial/cover.ejs +4 -4
  13. package/layout/_partial/footer.ejs +1 -1
  14. package/layout/_partial/head.ejs +7 -18
  15. package/layout/_partial/header.ejs +6 -6
  16. package/layout/_partial/post.ejs +4 -4
  17. package/layout/_partial/scripts/_ctrl.ejs +43 -2
  18. package/layout/_partial/scripts/config.ejs +69 -0
  19. package/layout/_partial/scripts/global.ejs +136 -60
  20. package/layout/_partial/scripts/index.ejs +16 -23
  21. package/layout/_plugins/_page_plugins/artitalk/index.ejs +1 -1
  22. package/layout/_plugins/_page_plugins/bbtalk/index.ejs +1 -1
  23. package/layout/_plugins/_page_plugins/fcircle/index.ejs +9 -8
  24. package/layout/_plugins/_page_plugins/katex/index.ejs +3 -3
  25. package/layout/_plugins/_page_plugins/mathjax/index.ejs +1 -1
  26. package/layout/_plugins/aplayer/layout.ejs +31 -23
  27. package/layout/_plugins/aplayer/script.ejs +93 -65
  28. package/layout/_plugins/comments/artalk/script.ejs +31 -40
  29. package/layout/_plugins/comments/discuss/script.ejs +1 -1
  30. package/layout/_plugins/comments/disqusjs/script.ejs +2 -2
  31. package/layout/_plugins/comments/gitalk/script.ejs +1 -1
  32. package/layout/_plugins/comments/twikoo/script.ejs +1 -1
  33. package/layout/_plugins/comments/vssue/script.ejs +3 -3
  34. package/layout/_plugins/comments/waline/script.ejs +2 -2
  35. package/layout/_plugins/github-api/script.ejs +3 -3
  36. package/layout/_plugins/lazyload/script.ejs +1 -1
  37. package/layout/_plugins/nodewaves/script.ejs +1 -1
  38. package/layout/_plugins/pace/script.ejs +15 -0
  39. package/layout/_plugins/parallax/script.ejs +1 -1
  40. package/layout/_plugins/pjax/index.ejs +66 -11
  41. package/layout/_plugins/pjax/pdata.ejs +5 -5
  42. package/layout/_plugins/preload/script.ejs +2 -2
  43. package/layout/_plugins/rightmenus/layout.ejs +4 -4
  44. package/layout/_plugins/scrollreveal/script.ejs +2 -2
  45. package/layout/_plugins/search/script.ejs +11 -8
  46. package/layout/_plugins/swiper/script.ejs +2 -2
  47. package/layout/{_partial/scripts/toc.ejs → _plugins/toc/script.ejs} +40 -36
  48. package/layout/_widget/blogger.ejs +4 -4
  49. package/layout/_widget/webinfo.ejs +13 -14
  50. package/layout/friends.ejs +2 -2
  51. package/layout/layout.ejs +1 -15
  52. package/package.json +4 -4
  53. package/scripts/events/lib/cdn.js +206 -0
  54. package/scripts/events/lib/check-configuration.js +7 -7
  55. package/scripts/events/lib/check-environment.js +17 -17
  56. package/scripts/events/lib/config.js +0 -24
  57. package/scripts/events/lib/render-stylus.js +5 -5
  58. package/scripts/events/lib/stellar-tag-utils.js +2 -2
  59. package/scripts/filters/hexo-blog-encrypt-callback.js +44 -0
  60. package/scripts/filters/img.js +1 -1
  61. package/scripts/filters/replace.js +3 -3
  62. package/scripts/filters/z-lazyload.js +3 -5
  63. package/scripts/helpers/first-style.js +2 -2
  64. package/scripts/helpers/head/generate_seo.js +24 -10
  65. package/scripts/helpers/head/generate_title__keywords__description.js +28 -9
  66. package/scripts/helpers/related-posts.js +3 -3
  67. package/scripts/helpers/structured-data/lib/blogposting.js +1 -1
  68. package/scripts/helpers/structured-data/lib/breadcrumblist.js +1 -1
  69. package/scripts/helpers/structured-data/lib/config.js +1 -1
  70. package/scripts/helpers/structured-data/lib/website.js +1 -1
  71. package/scripts/helpers//346/226/207/347/253/240/346/216/250/350/215/220.js +184 -0
  72. package/scripts/tags/btn.js +2 -2
  73. package/scripts/tags/btns.js +3 -3
  74. package/scripts/tags/checkbox.js +6 -6
  75. package/scripts/tags/contributors.js +7 -7
  76. package/scripts/tags/dropmenu.js +8 -8
  77. package/scripts/tags/fancybox.js +6 -6
  78. package/scripts/tags/folding.js +5 -5
  79. package/scripts/tags/frame.js +3 -3
  80. package/scripts/tags/friends.js +8 -8
  81. package/scripts/tags/ghcard.js +7 -7
  82. package/scripts/tags/image.js +6 -6
  83. package/scripts/tags/inline-labels.js +6 -6
  84. package/scripts/tags/link.js +5 -5
  85. package/scripts/tags/md.js +4 -4
  86. package/scripts/tags/media.js +5 -5
  87. package/scripts/tags/note.js +12 -12
  88. package/scripts/tags/pandown.js +29 -29
  89. package/scripts/tags/site.js +4 -4
  90. package/scripts/tags/span.js +4 -4
  91. package/scripts/tags/table.js +2 -2
  92. package/scripts/tags/tabs.js +23 -23
  93. package/scripts/tags/timeline.js +5 -5
  94. package/source/css/_first/base_first.styl +1 -1
  95. package/source/css/_style/_layout/article.styl +43 -0
  96. package/source/css/_style/_layout/main.styl +1 -1
  97. package/source/css/_style/_layout/search.styl +206 -14
  98. package/source/css/_style/_plugins/index.styl +1 -3
  99. package/source/js/app.js +133 -160
  100. package/source/js/plugins/parallax.js +1 -1
  101. package/source/js/plugins/rightMenus.js +24 -20
  102. package/source/js/search/algolia.js +239 -0
  103. package/source/js/search/hexo.js +8 -2
  104. package/source/js/search/meilisearch.js +220 -0
  105. package/layout/_partial/scripts/_ctrl/cdnCtrl.ejs +0 -127
  106. package/layout/_partial/scripts/_ctrl/coverCtrl.ejs +0 -43
  107. package/layout/_plugins/analytics/LCCounter.ejs +0 -207
  108. package/layout/_plugins/pjax/animate.ejs +0 -31
  109. package/layout/_plugins/rightmenu/layout.ejs +0 -119
  110. package/scripts/helpers/revisioned.js +0 -167
  111. package/source/css/_style/_plugins/pjaxanimate.styl +0 -160
  112. package/source/js/plugins/rightMenu.js +0 -577
  113. /package/layout/{_partial/scripts/content-visibility-scroll-fix.ejs → _plugins/content-visibility/script.ejs} +0 -0
@@ -1,207 +0,0 @@
1
- <script defer>
2
-
3
- const LCCounter = {
4
- app_id: '<%= theme.analytics.leancloud.app_id %>',
5
- app_key: '<%= theme.analytics.leancloud.app_key %>',
6
- custom_api_server: '<%= theme.analytics.leancloud.custom_api_server %>',
7
-
8
- // 查询存储的记录
9
- getRecord(Counter, url, title) {
10
- return new Promise(function (resolve, reject) {
11
- Counter('get', '/classes/Counter?where=' + encodeURIComponent(JSON.stringify({url})))
12
- .then(resp => resp.json())
13
- .then(({results, code, error}) => {
14
- if (code === 401) {
15
- throw error;
16
- }
17
- if (results && results.length > 0) {
18
- var record = results[0];
19
- resolve(record);
20
- } else {
21
- Counter('post', '/classes/Counter', {url, title: title, times: 0})
22
- .then(resp => resp.json())
23
- .then((record, error) => {
24
- if (error) {
25
- throw error;
26
- }
27
- resolve(record);
28
- }).catch(error => {
29
- console.error('Failed to create', error);
30
- reject(error);
31
- });
32
- }
33
- }).catch((error) => {
34
- console.error('LeanCloud Counter Error:', error);
35
- reject(error);
36
- });
37
- })
38
- },
39
-
40
- // 发起自增请求
41
- increment(Counter, incrArr) {
42
- return new Promise(function (resolve, reject) {
43
- Counter('post', '/batch', {
44
- "requests": incrArr
45
- }).then((res) => {
46
- res = res.json();
47
- if (res.error) {
48
- throw res.error;
49
- }
50
- resolve(res);
51
- }).catch((error) => {
52
- console.error('Failed to save visitor count', error);
53
- reject(error);
54
- });
55
- });
56
- },
57
-
58
- // 构建自增请求体
59
- buildIncrement(objectId) {
60
- return {
61
- "method": "PUT",
62
- "path": `/1.1/classes/Counter/${ objectId }`,
63
- "body": {
64
- "times": {
65
- '__op': 'Increment',
66
- 'amount': 1
67
- }
68
- }
69
- }
70
- },
71
-
72
- // 校验是否为有效的 UV
73
- validUV() {
74
- var key = 'LeanCloudUVTimestamp';
75
- var flag = localStorage.getItem(key);
76
- if (flag) {
77
- // 距离标记小于 24 小时则不计为 UV
78
- if (new Date().getTime() - parseInt(flag) <= 86400000) {
79
- return false;
80
- }
81
- }
82
- localStorage.setItem(key, new Date().getTime().toString());
83
- return true;
84
- },
85
-
86
- addCount(Counter) {
87
- var enableIncr = '<%= theme.analytics.enable %>' === 'true' && window.location.hostname !== 'localhost';
88
- enableIncr = true;
89
- var getterArr = [];
90
- var incrArr = [];
91
- // 请求 PV 并自增
92
- var pvCtn = document.querySelector('#lc-sv');
93
- if (pvCtn || enableIncr) {
94
- var pvGetter = this.getRecord(Counter, '<%- config.url %>' + '/#lc-sv', 'Visits').then((record) => {
95
- incrArr.push(this.buildIncrement(record.objectId))
96
- var eles = document.querySelectorAll('#lc-sv #number');
97
- if (eles.length > 0) {
98
- eles.forEach((el,index,array)=>{
99
- el.innerText = record.times + 1;
100
- if (pvCtn) {
101
- pvCtn.style.display = 'inline';
102
- }
103
- })
104
- }
105
- });
106
- getterArr.push(pvGetter);
107
- }
108
-
109
- // 请求 UV 并自增
110
- var uvCtn = document.querySelector('#lc-uv');
111
- if (uvCtn || enableIncr) {
112
- var uvGetter = this.getRecord(Counter, '<%- config.url %>' + '/#lc-uv', 'Visitors').then((record) => {
113
- var vuv = this.validUV();
114
- vuv && incrArr.push(this.buildIncrement(record.objectId))
115
- var eles = document.querySelectorAll('#lc-uv #number');
116
- if (eles.length > 0) {
117
- eles.forEach((el,index,array)=>{
118
- el.innerText = record.times + (vuv ? 1 : 0);
119
- if (uvCtn) {
120
- uvCtn.style.display = 'inline';
121
- }
122
- })
123
- }
124
- });
125
- getterArr.push(uvGetter);
126
- }
127
-
128
- // 请求文章的浏览数,如果是当前页面就自增
129
- var allPV = document.querySelectorAll('#lc-pv');
130
- if (allPV.length > 0 || enableIncr) {
131
- for (i = 0; i < allPV.length; i++) {
132
- let pv = allPV[i];
133
- let title = pv.getAttribute('data-title');
134
- var url = '<%- config.url %>' + pv.getAttribute('data-path');
135
- if (url) {
136
- var viewGetter = this.getRecord(Counter, url, title).then((record) => {
137
- // 是当前页面就自增
138
- let curPath = window.location.pathname;
139
- if (curPath.includes('index.html')) {
140
- curPath = curPath.substring(0, curPath.lastIndexOf('index.html'));
141
- }
142
- if (pv.getAttribute('data-path') == curPath) {
143
- incrArr.push(this.buildIncrement(record.objectId));
144
- }
145
- if (pv) {
146
- var ele = pv.querySelector('#lc-pv #number');
147
- if (ele) {
148
- if (pv.getAttribute('data-path') == curPath) {
149
- ele.innerText = (record.times || 0) + 1;
150
- } else {
151
- ele.innerText = record.times || 0;
152
- }
153
- pv.style.display = 'inline';
154
- }
155
- }
156
- });
157
- getterArr.push(viewGetter);
158
- }
159
- }
160
- }
161
-
162
- // 如果启动计数自增,批量发起自增请求
163
- if (enableIncr) {
164
- Promise.all(getterArr).then(() => {
165
- incrArr.length > 0 && this.increment(Counter, incrArr);
166
- })
167
- }
168
-
169
- },
170
-
171
-
172
- fetchData(api_server) {
173
- var Counter = (method, url, data) => {
174
- return fetch(`${ api_server }/1.1${ url }`, {
175
- method,
176
- headers: {
177
- 'X-LC-Id': this.app_id,
178
- 'X-LC-Key': this.app_key,
179
- 'Content-Type': 'application/json',
180
- },
181
- body: JSON.stringify(data)
182
- });
183
- };
184
- this.addCount(Counter);
185
- },
186
-
187
- refreshCounter() {
188
- var api_server = this.custom_api_server || `https://${ this.app_id.slice(0, 8).toLowerCase() }.api.lncldglobal.com`;
189
- if (api_server) {
190
- this.fetchData(api_server);
191
- } else {
192
- fetch('https://app-router.leancloud.cn/2/route?appId=' + this.app_id)
193
- .then(resp => resp.json())
194
- .then(({api_server}) => {
195
- this.fetchData('https://' + api_server);
196
- });
197
- }
198
- }
199
-
200
- };
201
-
202
- LCCounter.refreshCounter();
203
-
204
- document.addEventListener('pjax:complete', function () {
205
- LCCounter.refreshCounter();
206
- });
207
- </script>
@@ -1,31 +0,0 @@
1
- <!-- 样式位于:source/css/_plugins/pjaxanimate.styl -->
2
-
3
- <div class="pjax-animate">
4
- <% if (theme.plugins.pjax.animation == 'nprogress') { %>
5
- <script src="<%- theme.plugins.pjax.nprogress %>"></script>
6
- <div id="loading-bar-wrapper"><script>NProgress.configure({parent:"#loading-bar-wrapper",trickleSpeed: 100})</script></div>
7
- <script>
8
- window.ShowLoading = function() {
9
- NProgress.start();
10
- };
11
- window.HideLoading = function() {
12
- NProgress.done();
13
- }
14
- </script>
15
- <%} else if (theme.plugins.pjax.animation == 'circle') { %>
16
- <div class="loading-circle"><div id="loader-circle"></div></div>
17
- <script>
18
- window.ShowLoading = function() {
19
- document.querySelector(".loading-circle").style.display="block"
20
- };
21
- window.HideLoading = function() {
22
- document.querySelector(".loading-circle").style.display="none"
23
- }
24
- </script>
25
- <% } %>
26
- <script>
27
- volantis.pjax.push(window.HideLoading,'HideLoading');
28
- volantis.pjax.send(window.ShowLoading,'ShowLoading');
29
- volantis.pjax.error(window.HideLoading,'HideLoading');
30
- </script>
31
- </div>
@@ -1,119 +0,0 @@
1
- <% if (theme.rightmenu.enable == true && theme.rightmenu.layout.length > 0) { %>
2
- <% let faIcon = theme.rightmenu.faicon %>
3
- <% function loadmenu(obj) { %>
4
- <li class="menuLoad-Content">
5
- <a class='vlts-menu fix-cursor-default' <%= obj.url ? 'href='+ url_for(obj.url)+'' : ''%>
6
- <% if (obj.rel) { %>
7
- rel="<%- obj.rel %>"
8
- <% } %>
9
- <% if (obj.target) { %>
10
- target="<%- obj.target %>"
11
- <% } %>
12
- <% if (obj.onclick) { %>
13
- onclick="<%- obj.onclick %>"
14
- <% } %>
15
- <% if (obj.id) { %>
16
- id="<%- obj.id %>"
17
- <% } else if (obj.url) { %>
18
- id="<%= url_for(obj.url).replace(/\/|%|\./g, "")?url_for(obj.url).replace(/\/|%|\./g, ""):"home" %>"
19
- <% } %>
20
- >
21
- <% if (obj.icon) { %><i class='<%= obj.icon %> fa-fw'></i><% } %> <%- obj.name %>
22
- </a>
23
- </li>
24
- <% } %>
25
- <div id="rightmenu-wrapper">
26
- <ul class="list-v rightmenu" id="rightmenu-content">
27
- <li class='navigation menuNavigation-Content'>
28
- <a class='nav icon-only fix-cursor-default' onclick='history.back()'><i class='<%= faIcon %> fa-arrow-left fa-fw'></i></a>
29
- <a class='nav icon-only fix-cursor-default' onclick='history.forward()'><i class='<%= faIcon %> fa-arrow-right fa-fw'></i></a>
30
- <a class='nav icon-only fix-cursor-default' onclick='window.location.reload()'><i class='<%= faIcon %> fa-redo fa-fw'></i></a>
31
- <a class='nav icon-only fix-cursor-default' href='/'><i class='<%= faIcon %> fa-home fa-fw'></i></a>
32
- </li>
33
- <li class='option menuOption-Content'>
34
- <span class='vlts-menu opt fix-cursor-default menu-Option' data-fn-type='copyText'>
35
- <% let copy_text = __('rightmenu.copy_text') %>
36
- <i class='<%= faIcon %> fa-copy fa-fw'></i> <%- trim(copy_text) %>
37
- </span>
38
- <span class='vlts-menu opt fix-cursor-default menu-Option' data-fn-type='copyPaste'>
39
- <% let copy_paste = __('rightmenu.copy_paste') %>
40
- <i class='<%= faIcon %> fa-paste fa-fw mR12'></i> <%- trim(copy_paste) %>
41
- </span>
42
- <span class='vlts-menu opt fix-cursor-default menu-Option' data-fn-type='copySelect'>
43
- <% let copy_select = __('rightmenu.copy_select') %>
44
- <i class='<%= faIcon %> fa-object-ungroup fa-fw mR12'></i> <%- trim(copy_select) %>
45
- </span>
46
- <span class='vlts-menu opt fix-cursor-default menu-Option' data-fn-type='copyCut'>
47
- <% let copy_cut = __('rightmenu.copy_cut') %>
48
- <i class='<%= faIcon %> fa-cut fa-fw mR12'></i> <%- trim(copy_cut) %>
49
- </span>
50
- <% if (theme.search.enable) { %>
51
- <span class='vlts-menu opt fix-cursor-default menu-Option' data-fn-type='searchWord'>
52
- <% let search_word = __('rightmenu.search_word') %>
53
- <i class='<%= faIcon %> fa-search fa-fw'></i> <%- trim(search_word) %>
54
- </span>
55
- <% } %>
56
- <span class='vlts-menu opt fix-cursor-default menu-Option' data-fn-type='openTab'>
57
- <% let open_in_new_tab = __('rightmenu.open_in_new_tab') %>
58
- <i class='<%= faIcon %> fa-external-link-square-alt fa-fw mR12'></i> <%- trim(open_in_new_tab) %>
59
- </span>
60
- <span class='vlts-menu opt fix-cursor-default menu-Option' data-fn-type='copySrc'>
61
- <% let copy_image_src = __('rightmenu.copy_image_src') %>
62
- <i class='<%= faIcon %> fa-image fa-fw mR12'></i> <%- trim(copy_image_src) %>
63
- </span>
64
- <span class='vlts-menu opt fix-cursor-default menu-Option' data-fn-type='copyImg'>
65
- <% let copy_image_file = __('rightmenu.copy_image_file') %>
66
- <i class='<%= faIcon %> fa-images fa-fw mR12'></i> <%- trim(copy_image_file) %>
67
- </span>
68
- </li>
69
- <% theme.rightmenu.layout.forEach(function(item){ %>
70
- <% if (item == 'hr') { %>
71
- <hr class="menuLoad-Content">
72
- <% } else if (item == 'darkmode') { %>
73
- <li class='option menuOption-Content'>
74
- <span class='vlts-menu opt fix-cursor-default toggle-mode-btn' id='menuDarkBtn'>
75
- <i class='<%= theme.rightmenu.darkmode.icon %> fa-fw '></i> <%- trim(theme.rightmenu.darkmode.name) %>
76
- </span>
77
- </li>
78
- <% } else if (item == 'print') { %>
79
- <li class='option menuOption-Content'>
80
- <span class='vlts-menu opt fix-cursor-default' id='printHtml'>
81
- <i class='<%= theme.rightmenu.print.icon %> fa-fw '></i> <%- trim(theme.rightmenu.print.name) %>
82
- </span>
83
- </li>
84
- <% } else if (item == 'reading') { %>
85
- <li class='option menuOption-Content'>
86
- <span class='vlts-menu opt fix-cursor-default' id='readingModel'>
87
- <i class='<%= theme.rightmenu.reading.icon %> fa-fw '></i> <%- trim(theme.rightmenu.reading.name) %>
88
- </span>
89
- </li>
90
- <% } else if (item == 'music' && theme.plugins.aplayer.enable == true) { %>
91
- <div id="menuMusic">
92
- <li class='music name menuOption-Content'>
93
- <p class='nav music-title fix-cursor-default'></p>
94
- </li>
95
- <li class='music ctrl'>
96
- <a class='nav icon-only backward fix-cursor-default' href="/" onclick="return false;" title="backward"><i class='<%= faIcon %> fa-step-backward fa-fw'></i></a>
97
- <a class='nav icon-only toggle fix-cursor-default' href="/" onclick="return false;" title="toggle"><i class='<%= faIcon %> fa-play fa-fw'></i></a>
98
- <a class='nav icon-only forward fix-cursor-default' href="/" onclick="return false;" title="forward"><i class='<%= faIcon %> fa-step-forward fa-fw'></i></a>
99
- </li>
100
- <li class='music volume'>
101
- <div class='nav volume'>
102
- <div class="aplayer-volume-bar-wrap">
103
- <div class="aplayer-volume-bar fix-cursor-pointer">
104
- <div class="aplayer-volume"></div>
105
- <i class='left <%= faIcon %> fa-volume-off fa-fw'></i>
106
- <i class='right <%= faIcon %> fa-volume-up fa-fw'></i>
107
- </div>
108
- </div>
109
- </div>
110
- </li>
111
- </div>
112
- <% } else if (item in theme.rightmenu) { %>
113
- <% loadmenu(theme.rightmenu[item]) %>
114
- <% } %>
115
- <% }) %>
116
- </ul>
117
- </div>
118
- <script>volantis.js('<%- theme.cdn.map.js.rightMenu %>')</script>
119
- <% } %>
@@ -1,167 +0,0 @@
1
- // hexo g 执行 hexo s 跳出
2
-
3
- // https://blog.imkero.com/posts/hexo-page-performance.html#静态资源版本控制
4
-
5
-
6
- const minimatch = require("minimatch");
7
- const crypto = require('crypto');
8
-
9
- const stream2buffer = (stream) => {
10
- if(!stream) return;
11
- return new Promise((resolve, reject) => {
12
- const _buf = [];
13
- stream.on("data", (chunk) => _buf.push(chunk));
14
- stream.on("end", () => resolve(Buffer.concat(_buf)));
15
- stream.on("error", (err) => reject(err));
16
- });
17
- };
18
-
19
- const readFileAsBuffer = (filePath) => {
20
- return stream2buffer(hexo.route.get(filePath));
21
- };
22
-
23
- const readFileAsString = async (filePath) => {
24
- const buffer = await readFileAsBuffer(filePath);
25
- return buffer.toString();
26
- };
27
-
28
- const parseFilePath = (filePath) => {
29
- const parts = filePath.split("/");
30
- const originalFileName = parts[parts.length - 1];
31
-
32
- const dotPosition = originalFileName.lastIndexOf(".");
33
-
34
- const dirname = parts.slice(0, parts.length - 1).join("/");
35
- const basename =
36
- dotPosition === -1
37
- ? originalFileName
38
- : originalFileName.substring(0, dotPosition);
39
- const extension =
40
- dotPosition === -1 ? "" : originalFileName.substring(dotPosition);
41
-
42
- return [dirname, basename, extension];
43
- };
44
-
45
- const genFilePath = (dirname, basename, extension) => {
46
- let dirPrefix = "";
47
- if (dirname) {
48
- dirPrefix += dirname + "/";
49
- }
50
-
51
- if (extension && !extension.startsWith(".")) {
52
- extension = "." + extension;
53
- }
54
-
55
- return dirPrefix + basename + extension;
56
- };
57
-
58
- const getRevisionedFilePath = (filePath, revision) => {
59
- const [dirname, basename, extension] = parseFilePath(filePath);
60
- return genFilePath(dirname, `${basename}.${revision}`, extension);
61
- };
62
-
63
- const revisioned = (filePath) => {
64
- if (!hexo.theme.config.cdn_version) {
65
- return filePath;
66
- }
67
- let arg = process.argv[2];
68
- if (arg == "s" || arg == "server") {
69
- return filePath
70
- }
71
- return getRevisionedFilePath(filePath, `!!revision:${filePath}!!`);
72
- };
73
-
74
- hexo.extend.helper.register("revisioned", revisioned);
75
-
76
- const calcFileHash = async (filePath) => {
77
- if (hexo.route.get(filePath)) {
78
- const buffer = await stream2buffer(hexo.route.get(filePath));
79
- const fileHash = crypto.createHash("md5").update(buffer).digest('hex').substring(0, 8);
80
- return fileHash;
81
- } else {
82
- // 随机生成 hash
83
- return crypto.randomBytes(16).toString('hex').substring(0, 8);
84
- }
85
-
86
- };
87
-
88
- const replaceRevisionPlaceholder = async () => {
89
-
90
- if (!hexo.theme.config.cdn_version) {
91
- return;
92
- }
93
- try {
94
- const options = hexo.config.new_revision || {};
95
- const include = options.include || [];
96
-
97
- const hashPromiseMap = {};
98
- const hashMap = {};
99
- const doHash = (filePath) =>
100
- calcFileHash(filePath).then((hash) => {
101
- hashMap[filePath] = hash;
102
- });
103
-
104
- await Promise.all(
105
- hexo.route.list().map(async (path) => {
106
- const [, , extension] = parseFilePath(path);
107
- if (![".css", ".js", ".html"].includes(extension)) {
108
- return;
109
- }
110
-
111
- let fileContent = await readFileAsString(path);
112
-
113
- const regexp = /\.!!revision:([^\)]+?)!!/g;
114
- const matchResult = [...fileContent.matchAll(regexp)];
115
- if (matchResult.length) {
116
- const hashTaskList = [];
117
-
118
- // 异步获取文件 hash
119
- matchResult.forEach((group) => {
120
- const filePath = group[1];
121
- if (!(filePath in hashPromiseMap)) {
122
- hashPromiseMap[filePath] = doHash(filePath);
123
- }
124
- hashTaskList.push(hashPromiseMap[filePath]);
125
- });
126
-
127
- // 等待全部 hash 完成
128
- await Promise.all(hashTaskList);
129
-
130
- // 替换 placeholder
131
- fileContent = fileContent.replace(regexp, function (match, filePath) {
132
- if (!(filePath in hashMap)) {
133
- throw new Error("file hash not computed");
134
- }
135
- return "." + hashMap[filePath];
136
- });
137
-
138
- hexo.route.set(path, fileContent);
139
- }
140
- })
141
- );
142
-
143
- await Promise.all(
144
- hexo.route.list().map(async (path) => {
145
- for (let i = 0, len = include.length; i < len; i++) {
146
- if (minimatch(path, include[i])) {
147
- return doHash(path);
148
- }
149
- }
150
- })
151
- );
152
-
153
- await Promise.all(
154
- Object.keys(hashMap).map(async (filePath) => {
155
- hexo.route.set(
156
- getRevisionedFilePath(filePath, hashMap[filePath]),
157
- await readFileAsBuffer(filePath)
158
- );
159
- hexo.route.remove(filePath);
160
- })
161
- );
162
- } catch (error) {
163
- hexo.log.error("cdn_version ERROR: " + error);
164
- }
165
- };
166
-
167
- hexo.extend.filter.register("after_generate", replaceRevisionPlaceholder,9999);
@@ -1,160 +0,0 @@
1
- // nprogress
2
- /* Make clicks pass-through */
3
- #nprogress
4
- pointer-events: none
5
-
6
- #nprogress .bar
7
- background: $color-theme
8
- position: fixed
9
- z-index: 3000
10
- top: 0
11
- left: 0
12
- width: 100%
13
- height: 100%
14
-
15
- /* Fancy blur effect */
16
- #nprogress .peg
17
- display: block
18
- position: absolute
19
- right: 0px
20
- width: 100px
21
- height: 100%
22
- opacity: 1.0
23
- -webkit-transform: rotate(3deg) translate(0px, -4px)
24
- -ms-transform: rotate(3deg) translate(0px, -4px)
25
- transform: rotate(3deg) translate(0px, -4px)
26
-
27
- /* Remove these to get rid of the spinner */
28
- #nprogress .spinner
29
- display: block
30
- position: fixed
31
- z-index: 3000
32
- top: 15px
33
- right: 15px
34
-
35
-
36
- #nprogress .spinner-icon
37
- width: 18px
38
- height: 18px
39
- box-sizing: border-box
40
- border: solid 2px transparent
41
- border-top-color: #29d
42
- border-left-color: #29d
43
- border-radius: 50%
44
-
45
- -webkit-animation: nprogress-spinner 400ms linear infinite
46
- animation: nprogress-spinner 400ms linear infinite
47
-
48
-
49
- .nprogress-custom-parent
50
- overflow: hidden
51
- position: relative
52
-
53
- .nprogress-custom-parent #nprogress .spinner,
54
- .nprogress-custom-parent #nprogress .bar
55
- position: absolute
56
-
57
-
58
- @-webkit-keyframes nprogress-spinner
59
- 0%
60
- -webkit-transform: rotate(0deg)
61
- 100%
62
- -webkit-transform: rotate(360deg)
63
-
64
- @keyframes nprogress-spinner
65
- 0%
66
- transform: rotate(0deg)
67
- 100%
68
- transform: rotate(360deg)
69
-
70
-
71
-
72
- #loading-bar-wrapper
73
- position: fixed
74
- width: 100px
75
- top: 8px
76
- left: 50%
77
- transform: translateX(-50%)
78
- height: 8px
79
- border-radius: 8px
80
- z-index: 2000
81
- background: transparent
82
- &.nprogress-custom-parent
83
- background: var(--color-card)
84
- box-shadow: $boxshadow-card
85
-
86
- // circle
87
- .loading-circle
88
- display none
89
- height 100%
90
- width 100%
91
- position fixed
92
- top 0
93
- left 0
94
- z-index 999999
95
- background-color rgba(250,250,250,.9)
96
- img
97
- width 280px
98
- height 210px
99
- position relative
100
- top 45%
101
- left 50%
102
- margin-left -140px
103
- margin-top -105px
104
-
105
- #loader-circle
106
- display block
107
- position relative
108
- left 50%
109
- top 50%
110
- width 150px
111
- height 150px
112
- margin -75px 0 0 -75px
113
- border-radius 50%
114
- border 3px solid transparent
115
- border-top-color #ff5a5a
116
- -webkit-animation spin 1s linear infinite
117
- animation spin 1s linear infinite
118
- &:before
119
- content ""
120
- position absolute
121
- top 5px
122
- left 5px
123
- right 5px
124
- bottom 5px
125
- border-radius 50%
126
- border 3px solid transparent
127
- border-top-color #5af33f
128
- -webkit-animation spin 3s linear infinite
129
- animation spin 3s linear infinite
130
- &:after
131
- content ""
132
- position absolute
133
- top 15px
134
- left 15px
135
- right 15px
136
- bottom 15px
137
- border-radius 50%
138
- border 3px solid transparent
139
- border-top-color #6dc9ff
140
- -webkit-animation spin 2s linear infinite
141
- animation spin 2s linear infinite
142
-
143
- @-webkit-keyframes spin
144
- 0%
145
- -webkit-transform: rotate(0deg)
146
- -ms-transform: rotate(0deg)
147
- transform: rotate(0deg)
148
- 100%
149
- -webkit-transform: rotate(360deg)
150
- -ms-transform: rotate(360deg)
151
- transform: rotate(360deg)
152
- @keyframes spin
153
- 0%
154
- -webkit-transform: rotate(0deg)
155
- -ms-transform: rotate(0deg)
156
- transform: rotate(0deg)
157
- 100%
158
- -webkit-transform: rotate(360deg)
159
- -ms-transform: rotate(360deg)
160
- transform: rotate(360deg)