hexo-theme-volantis 5.0.0-rc.3 → 5.0.0-rc.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -31,6 +31,8 @@ npm i hexo-theme-volantis
31
31
 
32
32
  See docs: https://volantis.js.org
33
33
 
34
+ or: https://vlts.cc
35
+
34
36
  or: https://volantis.vercel.app
35
37
 
36
38
  ## Examples
package/_config.yml CHANGED
@@ -18,11 +18,38 @@ default:
18
18
  ############################### Volantis ###############################
19
19
  info:
20
20
  theme_name: Volantis # This is theme's name.
21
- theme_version: '5.0.0-rc.3' # This is theme's version.
21
+ theme_version: '5.0.0-rc.4' # This is theme's version.
22
22
  theme_docs: https://volantis.js.org/ # This is theme's URL.
23
23
  theme_repo: https://github.com/volantis-x/hexo-theme-volantis
24
24
  # Debug 调试模式
25
25
  debug: false
26
+ ############################### CSP ###############################
27
+ # 内容安全策略( CSP )
28
+ # https://developer.mozilla.org/zh-CN/docs/Web/HTTP/CSP
29
+ # https://content-security-policy.com/
30
+ csp:
31
+ content: "
32
+ default-src 'self' https:;
33
+ block-all-mixed-content;
34
+ base-uri 'self' https:;
35
+ form-action 'self' https:;
36
+ worker-src 'self' https:;
37
+ connect-src 'self' https: *;
38
+ img-src 'self' data: https: *;
39
+ media-src 'self' https: *;
40
+ font-src 'self' data: https: *;
41
+ frame-src 'self' https: *;
42
+ manifest-src 'self' https: *;
43
+ child-src https:;
44
+ script-src 'self' https: 'unsafe-inline' *;
45
+ style-src 'self' https: 'unsafe-inline' *;
46
+ "
47
+ # 可以使用自动程序替换默认的 'unsafe-inline' 和 * 生成更严格的内容安全策略.
48
+ # hexo_fliter_sha256 用于 hexo g 时替换 'unsafe-inline' 生成 script-src 'sha256-' , 只适用于外层不含有压缩工具得场景.
49
+ # 如果外层含有压缩工具会改变 hash 导致无效,hexo_fliter_sha256 需设为false, 使用 gulp 方案.
50
+ hexo_fliter_sha256: false
51
+ # 另可以参考官网的 gulp 方案.
52
+ # gulpfile.js https://github.com/volantis-x/community/blob/main/gulpfile.js
26
53
  ############################### CDN ###############################
27
54
  # 本地静态文件使用jsdelivr的min版本加速 https://www.jsdelivr.com/features
28
55
  # 默认使用 https://cdn.jsdelivr.net/npm/hexo-theme-volantis@<%- theme.info.theme_version %>/source/js/*.min.js 的CDN压缩版本(min.js),注意版本号对应关系!!可以通过修改以下配置项覆盖
@@ -32,13 +59,15 @@ cdn:
32
59
  # CDN 前缀,为空使用默认值,链接最后不加 "/",
33
60
  # 例如: https://cdn.jsdelivr.net/gh/volantis-x/volantis-x.github.io@gh-page 填写最后编译生成的源码CDN地址前缀,此路径下应该含有/js与/css目录,
34
61
  # 该配置默认值是:"https://cdn.jsdelivr.net/npm/hexo-theme-volantis@"+ theme.info.theme_version +"/source"
35
- prefix: https://npm.elemecdn.com/hexo-theme-volantis@5.0.0-rc.3/source
62
+ prefix: https://npm.elemecdn.com/hexo-theme-volantis@5.0.0-rc.4/source
36
63
  # 以下配置可以覆盖 cdn.prefix,配置项的值可以为空,但是要使用CDN必须依据路径填写配置项的键
37
64
  set:
38
65
  js:
39
66
  app: /js/app.js
40
67
  css:
41
68
  style: /css/style.css # (异步加载样式)
69
+ # 请求静态资源添加时间戳 ?time=1648684470140
70
+ cdn_version: true
42
71
  ########################################################################
43
72
  # 全局页面字符串替换 A => B (可用于临时修改错字等)
44
73
  replace:
@@ -273,9 +302,6 @@ comments:
273
302
  # https://giscus.app
274
303
  # https://github.com/laymonage/giscus
275
304
  giscus:
276
- theme:
277
- light: "light" # https://cdn.jsdelivr.net/gh/volantis-x/cdn-volantis@master/css/giscus/light.css
278
- dark: "dark" # https://cdn.jsdelivr.net/gh/volantis-x/cdn-volantis@master/css/giscus/dark.css
279
305
  # 以下配置按照 yml 格式增删填写即可
280
306
  # repo: xxx/xxx
281
307
  # repo-id: xxx
@@ -285,6 +311,10 @@ comments:
285
311
  # reactions-enabled: "1"
286
312
  # emit-metadata: "0"
287
313
  # lang: "zh-CN"
314
+ # 以上配置按照 yml 格式增删填写即可
315
+ theme:
316
+ light: "light" # https://cdn.jsdelivr.net/gh/volantis-x/cdn-volantis@master/css/giscus/light.css
317
+ dark: "dark" # https://cdn.jsdelivr.net/gh/volantis-x/cdn-volantis@master/css/giscus/dark.css
288
318
 
289
319
  # beaudar
290
320
  # https://beaudar.lipk.org/
@@ -415,7 +445,7 @@ comments:
415
445
  # Waline
416
446
  # https://waline.js.org/
417
447
  waline:
418
- js: https://cdn.jsdelivr.net/npm/@waline/client/dist/Waline.min.js
448
+ js: https://npm.elemecdn.com/@waline/client@1.6.0/dist/Waline.min.js
419
449
  path: # 全局评论地址 目前设置全局评论地址后visitor失效,这是waline的问题
420
450
  placeholder: 快来评论吧~ # 评论占位提示
421
451
  # imageHosting: https://7bu.top/api/upload?token=7ffe9d626fe4315c953758efbdb6ee2e # 图床api(默认注释使用base64)
@@ -607,8 +637,8 @@ plugins:
607
637
  # jquery
608
638
  globalJquery: false # 全局引入 jquery
609
639
  jquery: /libs/jquery/dist/jquery.min.js # https://cdn.jsdelivr.net/npm/jquery@3.6.0/dist/jquery.min.js
610
- # fontawesome Pro 版本:https://cdn.jsdelivr.net/gh/inkss/fontawesome@5.15.3/css/all.min.css
611
- fontawesome: /libs/@fortawesome/fontawesome-free/css/all.min.css # https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free@5.14/css/all.min.css
640
+ # fontawesome Pro 版本:https://cdn.jsdelivr.net/gh/inkss/fontawesome@6.0.0/css/all.min.css
641
+ fontawesome: /libs/@fortawesome/fontawesome-free/css/all.min.css # https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free@6.1/css/all.min.css
612
642
  # katex@0.15.2
613
643
  katex:
614
644
  js: /libs/katex/katex.min.js # https://cdn.jsdelivr.net/npm/katex@0.15.2/dist/katex.min.js
@@ -851,17 +881,14 @@ plugins:
851
881
 
852
882
  # 友链朋友圈 hexo-circle-of-friends
853
883
  # https://github.com/Rock-Candy-Tea/hexo-circle-of-friends
854
- # https://zfe.space/post/friend-link-circle.html
884
+ # https://fcircle-doc.js.cool/
855
885
  fcircle:
856
886
  # Set `plugins: ["fcircle"]` to enable in front-matter
857
887
  # 支持 Pjax
858
888
  api: '' # api 地址
859
- max_number: 20 # 页面展示文章数量
860
- add_number: 10 # 每次加载增加的篇数
861
- opentype: '_blank' # '_blank'打开新标签,'_self'本窗口打开
862
- nofollow: true # 禁止搜索引擎抓取
863
- imgError: https://cdn.jsdelivr.net/gh/Zfour/Butterfly-friend-poor-html/friendcircle/404.png
864
- # loadingCutom: # 自定义loading图 例如: <i class="fa fa-spinner fa-spin"></i> | <img src="你的图片地址" alt="加载中...">
889
+ message: '与主机通讯中……' # 占位文字
890
+ css: 'https://cdn.jsdelivr.net/gh/lmm214/immmmm/themes/hello-friend/static/fcircle-beta.css'
891
+ js: 'https://cdn.jsdelivr.net/gh/lmm214/immmmm/themes/hello-friend/static/fcircle-beta.js'
865
892
 
866
893
  # 消息提示
867
894
  message:
@@ -936,7 +963,6 @@ rightmenu:
936
963
  print: # 只有文章页才允许自定义打印
937
964
  name: 打印页面
938
965
  icon: fa fa-print
939
- defaultStyles: true # 是否使用预制的打印样式
940
966
  darkmode: # 需开启 plugins.darkmodejs
941
967
  name: 暗黑模式
942
968
  icon: fa fa-moon
@@ -11,6 +11,7 @@
11
11
  <meta name="renderer" content="webkit">
12
12
  <meta name="force-rendering" content="webkit">
13
13
  <meta http-equiv="X-UA-Compatible" content="IE=Edge,chrome=1">
14
+ <meta http-equiv="Content-Security-Policy" content="<%- theme.csp.content %>">
14
15
  <meta name="HandheldFriendly" content="True" >
15
16
  <meta name="apple-mobile-web-app-capable" content="yes">
16
17
  <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=5">
@@ -4,6 +4,10 @@
4
4
  // theme.cdn.addCSS("first","first",theme.cdn.set.css.first) => theme.cdn.map.css.first
5
5
 
6
6
  theme.cdnCtrl={}
7
+ theme.cdnCtrl.cdn_version = "";
8
+ if (theme.cdn_version) {
9
+ theme.cdnCtrl.cdn_version = '?time=' + theme.getStartTime;
10
+ }
7
11
  if (theme.cdn.enable&&theme.cdn.prefix) {
8
12
  theme.cdnCtrl.prefix=theme.cdn.prefix.replace(/\/$/g, "")
9
13
  } else {
@@ -14,7 +18,7 @@
14
18
  theme.cdn.map.css={}
15
19
  theme.cdn.addJS=(name,source,force)=>{
16
20
  if(force){
17
- theme.cdn.map.js[name]=force + '?time=' + Date.now()
21
+ theme.cdn.map.js[name]=force + theme.cdnCtrl.cdn_version
18
22
  }else{
19
23
  if(!source){
20
24
  source=name
@@ -23,16 +27,16 @@
23
27
  if (theme.cdn.enable) {
24
28
  let suffix=theme.cdn.prefix&&theme.cdn.prefix.match(/jsdelivr/g)?'.min.js':'.js'
25
29
  source= (suffix==".min.js")?source.replace(/\.min/g, ""):source
26
- theme.cdn.map.js[name]=theme.cdnCtrl.prefix + '/js/' + source + suffix + '?time=' + Date.now()
30
+ theme.cdn.map.js[name]=theme.cdnCtrl.prefix + '/js/' + source + suffix + theme.cdnCtrl.cdn_version
27
31
  } else {
28
- theme.cdn.map.js[name]=url_for('/js/')+ source + '.js?time=' + Date.now()
32
+ theme.cdn.map.js[name]=url_for('/js/')+ source + '.js' + theme.cdnCtrl.cdn_version
29
33
  }
30
34
  }
31
35
  return theme.cdn.map.js[name]
32
36
  }
33
37
  theme.cdn.addCSS=(name,source,force)=>{
34
38
  if(force){
35
- theme.cdn.map.css[name]=force + '?time=' + Date.now()
39
+ theme.cdn.map.css[name]=force + theme.cdnCtrl.cdn_version
36
40
  }else{
37
41
  if(!source){
38
42
  source=name
@@ -41,9 +45,9 @@
41
45
  if (theme.cdn.enable&&theme.cdn.prefix) {
42
46
  let suffix=theme.cdn.prefix.match(/jsdelivr/g)?'.min.css':'.css'
43
47
  source= (suffix==".min.js")?source.replace(/\.min/g, ""):source
44
- theme.cdn.map.css[name]=theme.cdnCtrl.prefix + '/css/' + source + suffix + '?time=' + Date.now()
48
+ theme.cdn.map.css[name]=theme.cdnCtrl.prefix + '/css/' + source + suffix + theme.cdnCtrl.cdn_version
45
49
  } else {
46
- theme.cdn.map.css[name]=url_for('/css/')+ source + '.css?time=' + Date.now()
50
+ theme.cdn.map.css[name]=url_for('/css/')+ source + '.css' + theme.cdnCtrl.cdn_version
47
51
  }
48
52
  }
49
53
  return theme.cdn.map.css[name]
@@ -109,5 +113,7 @@
109
113
  // 在部署时加入了 ?time=' + Date.now()
110
114
  // 使用 js(theme.cdn.map.js.app) 引入的地址会形如: /js/app.js?time=1232123123.js
111
115
  // 但是无伤大雅
116
+ // 更新:
117
+ // ?time=' + Date.now() 替换为 theme.getStartTime 保证相同资源 hash 不变
112
118
  dfs(theme.cdn.set,[])
113
119
  _%>
@@ -7,7 +7,7 @@
7
7
  volantis.GLOBAL_CONFIG ={
8
8
  cdn: <%- JSON.stringify(theme.cdn.map) %>,
9
9
  default: <%- JSON.stringify(theme.default) %>,
10
- lastupdate: new Date('<%- new Date() %>'),
10
+ lastupdate: new Date('<%- theme.getStartTime %>'),
11
11
  sidebar: {
12
12
  for_page: <%- JSON.stringify(theme.sidebar.for_page) %>,
13
13
  for_post: <%- JSON.stringify(theme.sidebar.for_post) %>,
@@ -33,8 +33,7 @@
33
33
  faicon: <%- JSON.stringify(theme.rightmenu.faicon) %>,
34
34
  layout: <%- JSON.stringify(theme.rightmenu.layout) %>,
35
35
  music_alwaysShow: <%- JSON.stringify(theme.rightmenu.music.alwaysShow) %>,
36
- customPicUrl: <%- JSON.stringify(theme.rightmenu.customPicUrl) %>,
37
- print: <%- JSON.stringify(theme.rightmenu.print.defaultStyles) %>
36
+ customPicUrl: <%- JSON.stringify(theme.rightmenu.customPicUrl) %>
38
37
  }
39
38
  }
40
39
  }
@@ -385,4 +384,14 @@
385
384
  }
386
385
  /******************************************************************************/
387
386
  /******************************************************************************/
387
+ //图像加载出错时的处理
388
+ function errorImgAvatar(img) {
389
+ img.src = "<%- theme.default.avatar %>";
390
+ img.onerror = null;
391
+ }
392
+ function errorImgCover(img) {
393
+ img.src = "<%- theme.default.cover %>";
394
+ img.onerror = null;
395
+ }
396
+ /******************************************************************************/
388
397
  </script>
@@ -1,226 +1,12 @@
1
1
  <script>
2
- volantis.layoutHelper("page-plugins",`<div id="moments_container"></div>`,{pjax:false}) // 外层有 pjax 标签
2
+ volantis.layoutHelper("page-plugins",`<div class="post-content"><div id="cf-container"><%- theme.plugins.fcircle.message %></div></div>`,{pjax:false}) // 外层有 pjax 标签
3
3
  </script>
4
- <script>
5
- var requests_url = '<%- theme.plugins.fcircle.api %>';
6
- var orign_data = [];
7
- var maxnumber = <%- theme.plugins.fcircle.max_number %>;
8
- var addnumber = <%- theme.plugins.fcircle.add_number %>;
9
- var opentype = '<%- theme.plugins.fcircle.opentype %>';
10
- var nofollow = <%- theme.plugins.fcircle.nofollow %>;
11
- var loadingCutom = '<%- theme.plugins.fcircle.loadingCutom %>';
12
- var fcircleImgError = '<%- theme.plugins.fcircle.imgError %>';
13
-
14
- //处理数据
15
-
16
- if (document.getElementById('moments_container')) {
17
- //添加加载动画
18
- var loading_pic = document.getElementById('moments_container');
19
-
20
- // 判断loadingCutom值是否为空
21
- if (typeof loadingCutom == "undefined" || loadingCutom == null || loadingCutom === "") {
22
- loading_pic.innerHTML = '<style>.loader { color: #d9dad8; font-size: 90px; text-indent: -9999em; overflow: hidden; width: 1em; height: 1em; border-radius: 50%; margin: 72px auto; position: relative; -webkit-transform: translateZ(0); -ms-transform: translateZ(0); transform: translateZ(0); -webkit-animation: load6 1.7s infinite ease, round 1.7s infinite ease; animation: load6 1.7s infinite ease, round 1.7s infinite ease; } @-webkit-keyframes load6 { 0% { box-shadow: 0 -0.83em 0 -0.4em, 0 -0.83em 0 -0.42em, 0 -0.83em 0 -0.44em, 0 -0.83em 0 -0.46em, 0 -0.83em 0 -0.477em; } 5%, 95% { box-shadow: 0 -0.83em 0 -0.4em, 0 -0.83em 0 -0.42em, 0 -0.83em 0 -0.44em, 0 -0.83em 0 -0.46em, 0 -0.83em 0 -0.477em; } 10%, 59% { box-shadow: 0 -0.83em 0 -0.4em, -0.087em -0.825em 0 -0.42em, -0.173em -0.812em 0 -0.44em, -0.256em -0.789em 0 -0.46em, -0.297em -0.775em 0 -0.477em; } 20% { box-shadow: 0 -0.83em 0 -0.4em, -0.338em -0.758em 0 -0.42em, -0.555em -0.617em 0 -0.44em, -0.671em -0.488em 0 -0.46em, -0.749em -0.34em 0 -0.477em; } 38% { box-shadow: 0 -0.83em 0 -0.4em, -0.377em -0.74em 0 -0.42em, -0.645em -0.522em 0 -0.44em, -0.775em -0.297em 0 -0.46em, -0.82em -0.09em 0 -0.477em; } 100% { box-shadow: 0 -0.83em 0 -0.4em, 0 -0.83em 0 -0.42em, 0 -0.83em 0 -0.44em, 0 -0.83em 0 -0.46em, 0 -0.83em 0 -0.477em; } } @keyframes load6 { 0% { box-shadow: 0 -0.83em 0 -0.4em, 0 -0.83em 0 -0.42em, 0 -0.83em 0 -0.44em, 0 -0.83em 0 -0.46em, 0 -0.83em 0 -0.477em; } 5%, 95% { box-shadow: 0 -0.83em 0 -0.4em, 0 -0.83em 0 -0.42em, 0 -0.83em 0 -0.44em, 0 -0.83em 0 -0.46em, 0 -0.83em 0 -0.477em; } 10%, 59% { box-shadow: 0 -0.83em 0 -0.4em, -0.087em -0.825em 0 -0.42em, -0.173em -0.812em 0 -0.44em, -0.256em -0.789em 0 -0.46em, -0.297em -0.775em 0 -0.477em; } 20% { box-shadow: 0 -0.83em 0 -0.4em, -0.338em -0.758em 0 -0.42em, -0.555em -0.617em 0 -0.44em, -0.671em -0.488em 0 -0.46em, -0.749em -0.34em 0 -0.477em; } 38% { box-shadow: 0 -0.83em 0 -0.4em, -0.377em -0.74em 0 -0.42em, -0.645em -0.522em 0 -0.44em, -0.775em -0.297em 0 -0.46em, -0.82em -0.09em 0 -0.477em; } 100% { box-shadow: 0 -0.83em 0 -0.4em, 0 -0.83em 0 -0.42em, 0 -0.83em 0 -0.44em, 0 -0.83em 0 -0.46em, 0 -0.83em 0 -0.477em; } } @-webkit-keyframes round { 0% { -webkit-transform: rotate(0deg); transform: rotate(0deg); } 100% { -webkit-transform: rotate(360deg); transform: rotate(360deg); } } @keyframes round { 0% { -webkit-transform: rotate(0deg); transform: rotate(0deg); } 100% { -webkit-transform: rotate(360deg); transform: rotate(360deg); } }</style><center><span id="moments_loading"><div class="loader"></div></span></center>';
23
- } else {
24
- loading_pic.innerHTML = '<center><span id="moments_loading">' + loadingCutom + '</span></center>';
25
- }
26
-
27
- fetch(requests_url).then(
28
- data => data.json()
29
- ).then(
30
- data => {
31
- orign_data = data;
32
- data_handle(nofollow, orign_data, maxnumber)
33
- }
34
- )
35
- }
36
-
37
- var data_handle = (nofollow, data, maxnumber) => {
38
- var today = todaypost();
39
- var Datetody = new Date(today);
40
- for (var item = 0; item < data[1].length; item++) {
41
- var Datedate = new Date(data[1][item][1]);
42
- if (Datedate > Datetody) {
43
- data[1].splice(item--, 1);
44
- }
45
- }
46
- var today_post = 0;
47
- var error = 0;
48
- var unique_live_link;
49
- var datalist = data[1].slice(0, maxnumber);
50
- var listlenth = data[1].length;
51
- var user_lenth = data[0].length;
52
- var datalist_slice = slice_month(datalist);
53
- var last_update_time = timezoon(datalist_slice);
54
- var link_list = [];
55
- for (var item of data[1]) {
56
- if (item[1] === today) {
57
- today_post += 1;
58
- }
59
- link_list.push(item[3]);
60
- }
61
- var arr = unique(link_list);
62
- unique_live_link = arr.length;
63
- for (var item of data[0]) {
64
- if (item[3] === 'true') {
65
- error += 1;
66
- }
67
- }
68
- var html_item = '<h2>统计信息</h2>';
69
- html_item += '<div id="info_user_pool" class="moments-item info_user_pool" style="">';
70
- html_item += '<div class="moments_chart"><span class="moments_post_info_title">当前友链数:</span><span class="moments_post_info_number">' + user_lenth + ' 个</span><br><span class="moments_post_info_title">失败数:</span><span class="moments_post_info_number">' + error + ' 个</span><br></div>';
71
- html_item += '<div class="moments_chart"><span class="moments_post_info_title">活跃友链数:</span><span class="moments_post_info_number">' + unique_live_link + ' 个</span><br><span class="moments_post_info_title">当前库存:</span><span class="moments_post_info_number">' + listlenth + ' 篇</span><br></div>';
72
- html_item += '<div class="moments_chart"><span class="moments_post_info_title">今日更新:</span><span class="moments_post_info_number">' + today_post + ' 篇</span><br><span class="moments_post_info_title">最近更新:</span><span class="moments_post_info_number">' + last_update_time + '</span><br></div>';
73
- html_item += '</div>';
74
-
75
- for (var month_item of datalist_slice) {
76
- html_item += '<h2>' + month_item[0] + '</h2>';
77
- for (var post_item of month_item[1]) {
78
- var rel = '';
79
- if (nofollow && opentype == '_blank') {
80
- rel = 'noopener nofollow';
81
- } else if (nofollow) {
82
- rel = 'nofollow';
83
- } else if (opentype == '_blank') {
84
- rel = 'noopener';
85
- } else {
86
- rel = '';
87
- }
88
- html_item += ' <div class="moments-item">';
89
- html_item += ' <a target="' + opentype + '" class="moments-item-img" href="' + post_item[2] + '" title="' + post_item[0] + '"rel="' + rel + '">';
90
- html_item += '<img onerror="this.onerror=null,this.src=&quot;' + fcircleImgError + '&quot;"';
91
- html_item += ' src="' + post_item[4] + '"></a>';
92
- html_item += '<div class="moments-item-info"><div class="moments-item-time"><i class="far fa-user"></i>';
93
- html_item += '<span>' + post_item[3] + '</span>';
94
- html_item += ' <div class="moments_post_time"><i class="far fa-calendar-alt"></i>' +
95
- '<time datetime="' + post_item[1] + '" title="' + post_item[1] + '">' + post_item[1] + '</time></div>';
96
- html_item += `</div><a target="${opentype}" class="moments-item-title" href="${post_item[2]}" title="${post_item[0]}"rel="${rel}">${post_item[0]}</a></div>`;
97
- html_item += '</div>';
98
-
99
- }
100
- }
101
- if (data[1].length - maxnumber > 0) {
102
- html_item += '<div style="text-align: center"><button type="button" class="moments_load_button" ' +
103
- 'onclick="load_more_post()">加载更多...</button>' +
104
- '</div>'
105
- }
106
- html_item += '<style>.moments-item-info span{padding-left:.3rem;padding-right:.3rem}.moments_post_time time{padding-left:.3rem;cursor:default}.moments_post_info_title{font-weight:700}.moments_post_info_number{float:right}.moments_chart{align-items:flex-start;flex:1;width:100px;height:60px;margin:20px}@media screen and (max-width:500px){.info_user_pool{padding:10px;flex-direction:column;max-height:200px}.moments_chart{flex:0;width:100%;height:160px;margin:0}}.moments-item:before{border:0}@media screen and (min-width:500px){.moments_post_time{float:right}}.moments_load_button{-webkit-transition-duration:.4s;transition-duration:.4s;text-align:center;border:1px solid #ededed;border-radius:.3em;display:inline-block;background:transparent;color:#555;padding:.5em 1.25em}.moments_load_button:hover{color:#3090e4;border-color:#3090e4}.moments-item{position:relative;display:-webkit-box;display:-moz-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-align:center;-moz-box-align:center;-o-box-align:center;-ms-flex-align:center;-webkit-align-items:center;align-items:center;margin:0 0 1rem .5rem;-webkit-transition:all .2s ease-in-out;-moz-transition:all .2s ease-in-out;-o-transition:all .2s ease-in-out;-ms-transition:all .2s ease-in-out;transition:all .2s ease-in-out;box-shadow:rgba(0,0,0,0.07) 0 2px 2px 0,rgba(0,0,0,0.1) 0 1px 5px 0;border-radius:2px}.moments-item-img{overflow:hidden;width:80px;height:80px}.moments-item-img img{max-width:100%;width:100%;height:100%;object-fit:cover}.moments-item-info{-webkit-box-flex:1;-moz-box-flex:1;-o-box-flex:1;box-flex:1;-webkit-flex:1;-ms-flex:1;flex:1;padding:0 .8rem}.moments-item-title{display:-webkit-box;overflow:hidden;-webkit-box-orient:vertical;font-size:1.1em;-webkit-transition:all .3s;-moz-transition:all .3s;-o-transition:all .3s;-ms-transition:all .3s;transition:all .3s;-webkit-line-clamp:1}</style>'
107
-
108
-
109
-
110
- var moments_container = document.getElementById('moments_container');
111
- append_div(moments_container, html_item)
112
- };
113
-
114
- var load_more_post = () => {
115
- if (document.getElementById('moments_container')) {
116
- maxnumber = maxnumber + addnumber;
117
- document.getElementById('moments_container').innerHTML = "";
118
- data_handle(nofollow, orign_data, maxnumber)
119
- }
120
- };
121
-
122
-
123
-
124
- //加载更多文章
125
- //将html放入指定id的div容器
126
- var append_div = (parent, text) => {
127
- if (document.getElementById('moments_container')) {
128
- loading_pic.innerHTML = ``;
129
- };
130
- if (typeof text === 'string') {
131
- var temp = document.createElement('div');
132
- temp.innerHTML = text;
133
- // 防止元素太多 进行提速
134
- var frag = document.createDocumentFragment();
135
- while (temp.firstChild) {
136
- frag.appendChild(temp.firstChild);
137
- }
138
- parent.appendChild(frag);
139
- } else {
140
- parent.appendChild(text);
141
- }
142
- };
143
-
144
- //去重
145
- var unique = (arr) => {
146
- return Array.from(new Set(arr))
147
- };
148
-
149
- //时区优化
150
- var formatDate = (strDate) => {
151
- try {
152
- var date = new Date(Date.parse(strDate.replace(/-/g, "/")));
153
- var gettimeoffset;
154
- if (new Date().getTimezoneOffset()) {
155
- gettimeoffset = new Date().getTimezoneOffset();
156
- } else {
157
- gettimeoffset = 8;
158
- }
159
- var timeoffset = gettimeoffset * 60 * 1000;
160
- var len = date.getTime();
161
- var date2 = new Date(len - timeoffset);
162
- var sec = date2.getSeconds().toString();
163
- var min = date2.getMinutes().toString();
164
- if (sec.length === 1) {
165
- sec = "0" + sec;
166
- }
167
- if (min.length === 1) {
168
- min = "0" + min;
169
- }
170
- return date2.getFullYear().toString() + "/" + (date2.getMonth() + 1).toString() + "/" + date2.getDate().toString() + " " + date2.getHours().toString() + ":" + min + ":" + sec
171
- } catch (e) {
172
- return ""
173
- }
174
- };
175
-
176
- var timezoon = (datalist_slice) => {
177
- var time = datalist_slice[0][1][0][5];
178
- return formatDate(time)
179
- };
180
-
181
- //今日时间
182
- var todaypost = () => {
183
- var date = new Date();
184
- var year = date.getFullYear();
185
- var month = (date.getMonth() + 1).toString();
186
- var day = (date.getDate()).toString();
187
- if (month.length === 1) {
188
- month = "0" + month;
189
- }
190
- if (day.length === 1) {
191
- day = "0" + day;
192
- }
193
- return year + "-" + month + "-" + day
194
- };
195
-
196
- //月份切片
197
- var slice_month = (data) => {
198
- var monthlist = [];
199
- var datalist = [];
200
- var data_slice = data;
201
- for (var item in data_slice) {
202
- data_slice[item].push(item);
203
- if (data_slice[item][1].lenth !== 10) {
204
- var list = data_slice[item][1].split('-');
205
- if (list[1].length < 2) {
206
- list[1] = "0" + list[1]
207
- }
208
- if (list[2].length < 2) {
209
- list[2] = "0" + list[2]
210
- }
211
- data_slice[item][1] = list.join('-')
212
- }
213
- var month = data_slice[item][1].slice(0, 7);
214
- if (monthlist.indexOf(month) !== -1) {
215
- datalist[monthlist.length - 1][1].push(data_slice[item])
216
- } else {
217
- monthlist.push(month);
218
- datalist.push([month, [data_slice[item]]])
219
- }
220
- }
221
- for (var mounthgroup of datalist) {
222
- mounthgroup.push(mounthgroup[1][0][6]);
223
- }
224
- return datalist
225
- };
4
+ <script type="text/javascript">
5
+ var fdataUser = {
6
+ apiurl: '<%- theme.plugins.fcircle.api %>'
7
+ }
8
+ </script>
9
+ <link rel="stylesheet" href="<%- theme.plugins.fcircle.css %>">
10
+ <script type="text/javascript"
11
+ src="<%- theme.plugins.fcircle.js %>">
226
12
  </script>
@@ -1,7 +1,11 @@
1
1
  <%_
2
- var imgs = theme.plugins.parallax.images || page.images;
3
- if (theme.plugins.parallax.shuffle) {
4
- shuffle(imgs);
2
+ theme.plugins.parallax.images = theme.plugins.parallax.images || page.images;
3
+ if (theme.plugins.parallax.shuffle) {
4
+ // shuffle 只一次 防止 hash 变化
5
+ if (typeof theme.plugins.parallax.shuffle_end==='undefined') {
6
+ shuffle(theme.plugins.parallax.images);
7
+ theme.plugins.parallax.shuffle_end=1;
8
+ }
5
9
  }
6
10
  function shuffle(arr){
7
11
  var n = arr.length;
@@ -14,7 +18,7 @@ function shuffle(arr){
14
18
  }
15
19
  _%>
16
20
  <script>
17
- let imgs = <%- JSON.stringify(imgs) %>;
21
+ let imgs = <%- JSON.stringify(theme.plugins.parallax.images) %>;
18
22
  let index = 0;
19
23
  let IntervalParallax = null;
20
24
 
@@ -17,7 +17,7 @@
17
17
  var pjax;
18
18
  document.addEventListener('DOMContentLoaded', function () {
19
19
  pjax = new Pjax({
20
- elements: 'a[href]:not([href^="#"]):not([href="javascript:void(0)"]):not([pjax-fancybox]):not([onclick="return false;"]):not([target="_blank"]):not([target="view_window"]):not([href$=".xml"])',
20
+ elements: 'a[href]:not([href^="#"]):not([href="javascript:void(0)"]):not([pjax-fancybox]):not([onclick="return false;"]):not([onclick="return!1"]):not([target="_blank"]):not([target="view_window"]):not([href$=".xml"])',
21
21
  selectors: [
22
22
  "head title",
23
23
  "head meta[name='description']",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hexo-theme-volantis",
3
- "version": "5.0.0-rc.3",
3
+ "version": "5.0.0-rc.4",
4
4
  "description": "Elegant and powerful theme for Hexo.",
5
5
  "main": "package.json",
6
6
  "scripts": {
@@ -60,7 +60,7 @@ module.exports = hexo => {
60
60
  hexo.config.relative_link = false;
61
61
  }
62
62
  hexo.config.meta_generator = false;
63
-
63
+ hexo.theme.config.getStartTime = Date.now();
64
64
  // Custom languages support. Introduced in NexT v6.3.0.
65
65
  if (data.languages) {
66
66
  var { language } = hexo.config;
@@ -0,0 +1,71 @@
1
+ /* global hexo */
2
+
3
+ 'use strict';
4
+
5
+ const crypto = require('crypto');
6
+ const hash = (s) => crypto.createHash("sha256").update(s).digest('base64');
7
+
8
+ // script White list [scripts in event handlers (eg onclick)]. 包含压缩的 inline js
9
+ let unsafe_script_list = [
10
+ "this.media='all';this.onload=null",
11
+ 'this.media="all",this.onload=null',
12
+ "errorImgAvatar(this)",
13
+ "errorImgCover(this)",
14
+ "return false;",
15
+ "return!1",
16
+ ]
17
+ // script hash White list
18
+ let unsafe_script_hash = ["'sha256-MXV1jvkHrZruEyFEOrQRjKs9WlPZC1V/3RLoKrkoDFQ='"]
19
+
20
+ function getRandStr(len) {
21
+ var str = '';
22
+ for (var i = 0; i < len; i++) {
23
+ str += String.fromCharCode(Math.floor(Math.random() * 26) + 97);
24
+ }
25
+ return str;
26
+ }
27
+ let unsafe_script_list_get = 1
28
+ const nonce = getRandStr(15);
29
+
30
+ hexo.extend.filter.register('after_render:html', function(data) {
31
+ if (!hexo.theme.config.csp.hexo_fliter_sha256) return data;
32
+ let arg = process.argv[2];
33
+ if (arg != "g" && arg != "generate") {
34
+ return data;
35
+ }
36
+ data = data.replace(/<script.*?>/g, function (match) {
37
+ if (/src/g.test(match)) {
38
+ return match;
39
+ }
40
+ if (/type=\"application\/ld\+json\"/g.test(match)) {
41
+ return match;
42
+ }
43
+ return match.replace(/>/g, ` nonce='${nonce}'>`);
44
+ });
45
+ data.replace(/<script.*?>([\s\S]+?)<\/script>/gi, function (match, script) {
46
+ if (/type=\"application\/ld\+json\"/g.test(match)) {
47
+ return match;
48
+ }
49
+ unsafe_script_list.push(script)
50
+ return match;
51
+ });
52
+ return data;
53
+ },9999999999999);
54
+
55
+ hexo.extend.filter.register('after_render:html', function(data) {
56
+ if (!hexo.theme.config.csp.hexo_fliter_sha256) return data;
57
+ let arg = process.argv[2];
58
+ if (arg != "g" && arg != "generate") {
59
+ return data;
60
+ }else{
61
+ if (unsafe_script_list_get) {
62
+ unsafe_script_list=Array.from(new Set(unsafe_script_list))
63
+ unsafe_script_list.forEach(e => {
64
+ unsafe_script_hash.push("'sha256-" + hash(e) + "'")
65
+ });
66
+ unsafe_script_list_get = 0;
67
+ }
68
+ data = data.replace(/script-src 'self' https: 'unsafe-inline'/g, `script-src 'self' https: 'nonce-${nonce}' 'unsafe-hashes' ` + unsafe_script_hash.join(" "));
69
+ return data;
70
+ }
71
+ },99999999999999999);
@@ -52,7 +52,7 @@ hexo.extend.tag.register('contributors', function(args) {
52
52
  if (friend.url && friend.title) {
53
53
  var cell = '<div class="user-card">';
54
54
  cell += '<a class="card-link" target="_blank" rel="external noopener noreferrer" href="' + friend.url + '">';
55
- cell += '<img src="' + (friend.avatar || hexo.theme.config.default.avatar) + '" onerror="this.onerror=null;this.classList.add(&quot;loaded&quot;);this.srcset=this.src=&quot;' + hexo.theme.config.default.avatar + '&quot;;"/>';
55
+ cell += '<img src="' + (friend.avatar || hexo.theme.config.default.avatar) + '" onerror="errorImgAvatar(this)"/>';
56
56
  cell += '<div class="name"><span>' + friend.title + '</span></div>';
57
57
  cell += '</a></div>'
58
58
  return cell;
@@ -51,7 +51,7 @@ hexo.extend.tag.register('friends', function(args) {
51
51
  if (friend.url && friend.title) {
52
52
  var cell = '<div class="user-card">';
53
53
  cell += '<a class="card-link" target="_blank" rel="external noopener noreferrer" href="' + friend.url + '">';
54
- cell += '<img src="' + (friend.avatar || hexo.theme.config.default.avatar) + '" onerror="this.onerror=null;this.classList.add(&quot;loaded&quot;);this.srcset=this.src=&quot;' + hexo.theme.config.default.avatar + '&quot;;"/>';
54
+ cell += '<img src="' + (friend.avatar || hexo.theme.config.default.avatar) + '" onerror="errorImgAvatar(this)"/>';
55
55
  cell += '<div class="name"><span>' + friend.title + '</span></div>';
56
56
  cell += '</a></div>'
57
57
  return cell;
@@ -43,9 +43,9 @@ hexo.extend.tag.register('sites', function(args) {
43
43
  if (site.url && site.title) {
44
44
  var cell = '<div class="site-card">';
45
45
  cell += '<a class="card-link" target="_blank" rel="external noopener noreferrer" href="' + site.url + '">';
46
- cell += '<img src="' + (site.screenshot || ('https://image.thum.io/get/width/1024/crop/768/' + site.url)) + '" onerror="this.onerror=null;this.classList.add(&quot;loaded&quot;);this.srcset=this.src=&quot;' + hexo.theme.config.default.cover + '&quot;;"/>';
46
+ cell += '<img src="' + (site.screenshot || ('https://image.thum.io/get/width/1024/crop/768/' + site.url)) + '" onerror="errorImgCover(this)"/>';
47
47
  cell += '<div class="info">';
48
- cell += '<img src="' + (site.avatar || hexo.theme.config.default.link) + '" onerror="this.onerror=null;this.classList.add(&quot;loaded&quot;);this.srcset=this.src=&quot;' + hexo.theme.config.default.link + '&quot;;"/>';
48
+ cell += '<img src="' + (site.avatar || hexo.theme.config.default.link) + '" onerror="errorImgAvatar(this)"/>';
49
49
  cell += '<span class="title">' + site.title + '</span>';
50
50
  cell += '<span class="desc">' + (site.description || site.url) + '</span>';
51
51
  cell += '</div>';
@@ -50,6 +50,8 @@
50
50
  padding-right: $gap
51
51
  if hexo-config('sidebar.position') =='left'
52
52
  padding-left: $gap
53
+ @media screen and (max-width:$device-tablet)
54
+ padding-left: 0
53
55
  &.no_sidebar
54
56
  width: 100%
55
57
  padding-right: 0
@@ -7,7 +7,6 @@
7
7
  -ms-flex-order: 1;
8
8
  -webkit-order: 1;
9
9
  order: 1;
10
- padding-left: $gap
11
10
  position: relative
12
11
  display: flex
13
12
  flex-direction: column
@@ -52,7 +52,7 @@ const ContributorsJS = {
52
52
  var user = '<div class="user-card">';
53
53
  user += '<a class="card-link" target="_blank" rel="external noopener noreferrer"';
54
54
  user += ' href="' + item.html_url + '">';
55
- user += '<img alt="' + item.login + '" src="' + (item.avatar_url || cfg.avatar) + '" onerror="javascript:this.onerror=null;this.src=\'' + cfg.avatar + '\';">';
55
+ user += '<img alt="' + item.login + '" src="' + (item.avatar_url || cfg.avatar) + '" onerror="errorImgAvatar(this)">';
56
56
  user += '<div class="name"><span>' + item.login + '</span></div>';
57
57
  user += '</a>';
58
58
  user += '</div>';
@@ -53,7 +53,7 @@ const FriendsJS = {
53
53
  var user = '<div class="user-card">';
54
54
  user += '<a class="card-link" target="_blank" rel="external noopener noreferrer"';
55
55
  user += ' href="' + item.url + '">';
56
- user += '<img alt="' + item.title + '" src="' + (item.avatar || cfg.avatar) + '" onerror="javascript:this.onerror=null;this.src=\'' + cfg.avatar + '\';">';
56
+ user += '<img alt="' + item.title + '" src="' + (item.avatar || cfg.avatar) + '" onerror="errorImgAvatar(this)">';
57
57
  user += '<div class="name"><span>' + item.title + '</span></div>';
58
58
  user += '</a>';
59
59
  user += '</div>';
@@ -437,40 +437,38 @@ const RightMenu = (() => {
437
437
  // 执行打印页面
438
438
  fn.printHtml = () => {
439
439
  if (volantis.isReadModel) fn.readingModel();
440
- if (rightMenuConfig.print.defaultStyles) {
441
- DOMController.setAttribute('details', 'open', 'true');
442
- DOMController.remove('.cus-article-bkg');
443
- DOMController.remove('.iziToast-overlay');
444
- DOMController.remove('.iziToast-wrapper');
445
- DOMController.remove('.prev-next');
446
- DOMController.remove('footer');
447
- DOMController.remove('#l_header');
448
- DOMController.remove('#l_cover');
449
- DOMController.remove('#l_side');
450
- DOMController.remove('#comments');
451
- DOMController.remove('#s-top');
452
- DOMController.remove('#BKG');
453
- DOMController.remove('#rightmenu-wrapper');
454
- DOMController.remove('.nav-tabs');
455
- DOMController.remove('.parallax-mirror');
456
- DOMController.remove('.new-meta-item.share');
457
- DOMController.remove('div.footer');
458
- DOMController.setStyle('body', 'backgroundColor', 'unset');
459
- DOMController.setStyle('#l_main', 'width', '100%');
460
- DOMController.setStyle('#post', 'boxShadow', 'none');
461
- DOMController.setStyle('#post', 'background', 'none');
462
- DOMController.setStyle('#post', 'padding', '0');
463
- DOMController.setStyle('h1', 'textAlign', 'center');
464
- DOMController.setStyle('h1', 'fontWeight', '600');
465
- DOMController.setStyle('h1', 'fontSize', '2rem');
466
- DOMController.setStyle('h1', 'marginBottom', '20px');
467
- DOMController.setStyle('.tab-pane', 'display', 'block');
468
- DOMController.setStyle('.tab-content', 'borderTop', 'none');
469
- DOMController.setStyle('.highlight>table pre', 'whiteSpace', 'pre-wrap');
470
- DOMController.setStyle('.highlight>table pre', 'wordBreak', 'break-all');
471
- DOMController.setStyle('.fancybox img', 'height', 'auto');
472
- DOMController.setStyle('.fancybox img', 'weight', 'auto');
473
- }
440
+ DOMController.setAttribute('details', 'open', 'true');
441
+ DOMController.remove('.cus-article-bkg');
442
+ DOMController.remove('.iziToast-overlay');
443
+ DOMController.remove('.iziToast-wrapper');
444
+ DOMController.remove('.prev-next');
445
+ DOMController.remove('footer');
446
+ DOMController.remove('#l_header');
447
+ DOMController.remove('#l_cover');
448
+ DOMController.remove('#l_side');
449
+ DOMController.remove('#comments');
450
+ DOMController.remove('#s-top');
451
+ DOMController.remove('#BKG');
452
+ DOMController.remove('#rightmenu-wrapper');
453
+ DOMController.remove('.nav-tabs');
454
+ DOMController.remove('.parallax-mirror');
455
+ DOMController.remove('.new-meta-item.share');
456
+ DOMController.remove('div.footer');
457
+ DOMController.setStyle('body', 'backgroundColor', 'unset');
458
+ DOMController.setStyle('#l_main', 'width', '100%');
459
+ DOMController.setStyle('#post', 'boxShadow', 'none');
460
+ DOMController.setStyle('#post', 'background', 'none');
461
+ DOMController.setStyle('#post', 'padding', '0');
462
+ DOMController.setStyle('h1', 'textAlign', 'center');
463
+ DOMController.setStyle('h1', 'fontWeight', '600');
464
+ DOMController.setStyle('h1', 'fontSize', '2rem');
465
+ DOMController.setStyle('h1', 'marginBottom', '20px');
466
+ DOMController.setStyle('.tab-pane', 'display', 'block');
467
+ DOMController.setStyle('.tab-content', 'borderTop', 'none');
468
+ DOMController.setStyle('.highlight>table pre', 'whiteSpace', 'pre-wrap');
469
+ DOMController.setStyle('.highlight>table pre', 'wordBreak', 'break-all');
470
+ DOMController.setStyle('.fancybox img', 'height', 'auto');
471
+ DOMController.setStyle('.fancybox img', 'weight', 'auto');
474
472
 
475
473
  setTimeout(() => {
476
474
  window.print();
@@ -52,9 +52,9 @@ const SitesJS = {
52
52
  arr.forEach((item, i) => {
53
53
  var cell = '<div class="site-card">';
54
54
  cell += '<a class="card-link" target="_blank" rel="external noopener noreferrer" href="' + item.url + '">';
55
- cell += '<img alt="' + item.title + '" src="' + (item.screenshot || ('https://image.thum.io/get/width/1024/crop/768/' + item.url)) + '" onerror="javascript:this.onerror=null;this.src=\'' + cfg.screenshot + '\';"/>';
55
+ cell += '<img alt="' + item.title + '" src="' + (item.screenshot || ('https://image.thum.io/get/width/1024/crop/768/' + item.url)) + '" onerror="errorImgCover(this)"/>';
56
56
  cell += '<div class="info">';
57
- cell += '<img alt="' + item.title + '" src="' + (item.avatar || cfg.avatar) + '" onerror="javascript:this.onerror=null;this.src=\'' + cfg.avatar + '\';"/>';
57
+ cell += '<img alt="' + item.title + '" src="' + (item.avatar || cfg.avatar) + '" onerror="errorImgAvatar(this)"/>';
58
58
  cell += '<span class="title">' + item.title + '</span>';
59
59
  cell += '<span class="desc">' + (item.description || item.url) + '</span>';
60
60
  cell += '</div>';