hexo-theme-solitude 1.6.1 → 1.7.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 (45) hide show
  1. package/README.md +1 -1
  2. package/README_zh-cn.md +1 -1
  3. package/README_zh-tw.md +1 -1
  4. package/SECURITY.md +5 -5
  5. package/_config.yml +30 -15
  6. package/languages/en.yml +15 -1
  7. package/languages/zh-CN.yml +21 -1
  8. package/languages/zh-TW.yml +21 -1
  9. package/layout/category.pug +1 -1
  10. package/layout/includes/console.pug +8 -7
  11. package/layout/includes/head/config.pug +66 -40
  12. package/layout/includes/inject/body.pug +7 -3
  13. package/layout/includes/inject/head.pug +35 -1
  14. package/layout/includes/widgets/post/postMeta.pug +7 -0
  15. package/layout/includes/widgets/third-party/comments/comment.pug +5 -7
  16. package/layout/includes/widgets/third-party/comments/valine.pug +44 -0
  17. package/layout/includes/widgets/third-party/comments/waline.pug +40 -12
  18. package/layout/includes/widgets/third-party/news-comment/newest-comment.pug +5 -3
  19. package/layout/includes/widgets/third-party/news-comment/twikoo.pug +12 -10
  20. package/layout/includes/widgets/third-party/news-comment/valine.pug +79 -0
  21. package/layout/includes/widgets/third-party/news-comment/waline.pug +25 -20
  22. package/layout/page.pug +3 -0
  23. package/layout/tag.pug +1 -1
  24. package/package.json +1 -1
  25. package/plugins.yml +15 -3
  26. package/scripts/event/cdn.js +7 -2
  27. package/scripts/event/init.js +4 -2
  28. package/scripts/event/merge_config.js +6 -5
  29. package/scripts/helper/related_post.js +2 -2
  30. package/scripts/tags/tabs.js +1 -1
  31. package/source/css/_comments/{index.styl → comment.styl} +4 -24
  32. package/source/css/_comments/valine.styl +245 -0
  33. package/source/css/_global/index.styl +3 -0
  34. package/source/css/_highlight/highlight/index.styl +1 -1
  35. package/source/css/_page/index.styl +1 -4
  36. package/source/css/_post/content.styl +13 -7
  37. package/source/css/index.styl +1 -3
  38. package/source/js/commentBarrage/twikoo.js +4 -4
  39. package/source/js/commentBarrage/valine.js +156 -0
  40. package/source/js/commentBarrage/waline.js +3 -3
  41. package/source/js/main.js +28 -33
  42. package/source/js/third_party/efu_ai.min.js +6 -0
  43. package/source/js/utils.js +14 -1
  44. package/source/css/_comments/waline.styl +0 -455
  45. package/source/js/third_party/sco-ai.min.js +0 -8
@@ -28,7 +28,7 @@ figure
28
28
  color var(--efu-secondtext)
29
29
  background var(--efu-secondbg)
30
30
  border-right var(--style-border-always)
31
- text-align right
31
+ text-align center
32
32
 
33
33
  &.code
34
34
  width 100%
@@ -31,7 +31,4 @@ if hexo-config('music.enable')
31
31
  @import "share.styl"
32
32
 
33
33
  if hexo-config('google_adsense.enable')
34
- @import "google.styl"
35
-
36
- if hexo-config('message.enable')
37
- @import "message/index.styl"
34
+ @import "google.styl"
@@ -9,15 +9,20 @@
9
9
 
10
10
  a
11
11
  color var(--efu-fontcolor)
12
- padding 0 4px
13
12
  border-radius 4px 4px 0 0
14
13
 
15
- &:not(.fancybox):hover
16
- border 0
17
- text-decoration none
18
- color var(--efu-white)
19
- border-radius 4px
20
- background var(--efu-main)
14
+ border-bottom 2px dotted var(--efu-lighttext)
15
+ font-weight 700
16
+
17
+ &:not(.fancybox)
18
+ padding 0 4px
19
+
20
+ &:hover
21
+ border 0
22
+ text-decoration none
23
+ color var(--efu-white)
24
+ border-radius 4px
25
+ background var(--efu-main)
21
26
 
22
27
  .table-wrap
23
28
  margin 1rem 0
@@ -62,6 +67,7 @@
62
67
 
63
68
  img
64
69
  margin auto
70
+
65
71
  a
66
72
  &:not(.fancybox)
67
73
  text-decoration none
@@ -27,6 +27,4 @@ if hexo-config('search.enable')
27
27
 
28
28
  // comment
29
29
  if hexo-config('comment.enable')
30
- @import '_comments/index.styl'
31
- @import '_comments/twikoo.styl' when hexo-config('comment.type') == 'twikoo'
32
- @import '_comments/waline.styl' when hexo-config('comment.type') == 'waline'
30
+ @import '_comments/comment.styl'
@@ -3,9 +3,9 @@ function initializeCommentBarrage() {
3
3
  const e = {
4
4
  maxBarrage: 1,
5
5
  barrageTime: 8e3,
6
- twikooUrl: GLOBAL_CONFIG.comment.twikoo.url,
6
+ twikooUrl: GLOBAL_CONFIG.comment.url,
7
7
  pageUrl: window.location.pathname,
8
- accessToken: GLOBAL_CONFIG.comment.twikoo.accessToken,
8
+ accessToken: GLOBAL_CONFIG.comment.accessToken,
9
9
  };
10
10
 
11
11
  class CommentBarrage {
@@ -79,9 +79,9 @@ function initializeCommentBarrage() {
79
79
  commentBarrageItem.className = "comment-barrage-item";
80
80
  commentBarrageItem.innerHTML = `
81
81
  <div class="barrageHead">
82
- <a class="barrageTitle" href="javascript:sco.scrollTo('post-comment')">热评</a>
82
+ <a class="barrageTitle" href="javascript:sco.scrollTo('post-comment')">${GLOBAL_CONFIG.lang.barrage.title}</a>
83
83
  <div class="barrageNick">${comment.nick}</div>
84
- <img class="barrageAvatar" src="https://cravatar.cn/avatar/${comment.mailMd5}"/>
84
+ <img class="barrageAvatar" src="${GLOBAL_CONFIG.comment.avatar}/avatar/${comment.mailMd5}"/>
85
85
  <a class="comment-barrage-close" href="javascript:sco.switchCommentBarrage();"><i class="solitude st-close-fill"></i></a>
86
86
  </div>
87
87
  <a class="barrageContent" href="javascript:sco.scrollTo('${comment.id}');">${commentContent}</a>
@@ -0,0 +1,156 @@
1
+ function initializeCommentBarrage() {
2
+ window.commentBarrageInitialized = !0;
3
+ let config = {
4
+ maxBarrage: 1,
5
+ barrageTime: 8e3,
6
+ valineUrl: GLOBAL_CONFIG.comment.url,
7
+ pageUrl: window.location.pathname,
8
+ }
9
+ new class {
10
+ commentInterval = null
11
+
12
+ constructor(config) {
13
+ this.config = {
14
+ ...config,
15
+ barrageTimer: [],
16
+ barrageList: [],
17
+ barrageIndex: 0,
18
+ dom: document.querySelector(".comment-barrage")
19
+ };
20
+ this.commentInterval = null;
21
+ this.hoverOnCommentBarrage = false;
22
+ this.init();
23
+ }
24
+
25
+ async fetchComments() {
26
+ const url = new URL(`${this.config.valineUrl}/1.1/classes/Comment`);
27
+ const params = {
28
+ url: this.config.pageUrl,
29
+ order: '-createdAt'
30
+ };
31
+
32
+ for (const [key, value] of Object.entries(params)) {
33
+ url.searchParams.append(key, value);
34
+ }
35
+
36
+ try {
37
+ const response = await fetch(url, {
38
+ method: "GET",
39
+ headers: {
40
+ "X-LC-Id": GLOBAL_CONFIG.comment.appId,
41
+ "X-LC-Key": GLOBAL_CONFIG.comment.appKey,
42
+ "Content-Type": "application/json"
43
+ },
44
+ });
45
+
46
+ if (!response.ok) {
47
+ throw new Error(`HTTP error! status: ${response.status}`);
48
+ }
49
+
50
+ const data = await response.json();
51
+ return data.results.filter(item => item.url === this.config.pageUrl)
52
+ } catch (error) {
53
+ console.error("An error occurred while fetching comments: ", error);
54
+ }
55
+ }
56
+
57
+ commentLinkFilter(comments) {
58
+ return comments.flatMap(comment => this.getCommentReplies(comment));
59
+ }
60
+
61
+ getCommentReplies(comment) {
62
+ window.comment = comment
63
+ if (!comment.replies) {
64
+ return [comment];
65
+ }
66
+ return [comment, ...comment.replies.flatMap(reply => this.getCommentReplies(reply))];
67
+ }
68
+
69
+ processCommentContent(comment) {
70
+ const processed = comment.replace(/```[\s\S]*?```|<blockquote\b[^>]*>[\s\S]*?<\/blockquote>|<[^>]*>|\n|`([^`]{1,9})`:/g, "").trim();
71
+ return processed ? `<p>${processed}</p>` : "";
72
+ }
73
+
74
+ createCommentBarrage(comment) {
75
+ const content = this.processCommentContent(comment.comment).trim();
76
+ if (!content) {
77
+ return false;
78
+ }
79
+
80
+ const element = document.createElement("div");
81
+ element.classList.add("comment-barrage-item");
82
+ element.innerHTML = `
83
+ <div class="barrageHead">
84
+ <a class="barrageTitle" href="javascript:sco.scrollTo('post-comment')">${GLOBAL_CONFIG.lang.barrage.title}</a>
85
+ <div class="barrageNick">${comment.nick}</div>
86
+ <img class="barrageAvatar" src="${GLOBAL_CONFIG.comment.avatar}/avatar/${md5(comment.mail.toLowerCase())}"/>
87
+ <a class="comment-barrage-close" href="javascript:sco.switchCommentBarrage();">
88
+ <i class="solitude st-close-fill"></i>
89
+ </a>
90
+ </div>
91
+ <a class="barrageContent" href="javascript:sco.scrollTo('${comment.objectId}');">${comment.comment}</a>
92
+ `;
93
+
94
+ this.config.dom.appendChild(element);
95
+ this.config.barrageTimer.push(element);
96
+
97
+ return true;
98
+ }
99
+
100
+ removeCommentBarrage(element) {
101
+ element.className = "comment-barrage-item out";
102
+ setTimeout(() => {
103
+ this.config.dom.removeChild(element);
104
+ }, 1000);
105
+ }
106
+
107
+ async initCommentBarrage() {
108
+ const commentBarrage = document.querySelector(".comment-barrage");
109
+ const menuCommentBarrageText = document.querySelector(".menu-commentBarrage-text");
110
+ const consoleCommentBarrage = document.querySelector("#consoleCommentBarrage");
111
+
112
+ if (localStorage.getItem("commentBarrageSwitch") != null) {
113
+ commentBarrage.style.display = "flex";
114
+ consoleCommentBarrage.classList.add("on");
115
+ } else {
116
+ commentBarrage.style.display = "none";
117
+ consoleCommentBarrage.classList.remove("on");
118
+ }
119
+
120
+ const comments = await this.fetchComments();
121
+ this.config.barrageList = this.commentLinkFilter(comments);
122
+ this.config.dom.innerHTML = "";
123
+ clearInterval(this.commentInterval);
124
+ this.commentInterval = null;
125
+
126
+ const createOrRemoveBarrage = () => {
127
+ if (this.config.barrageList.length && !this.hoverOnCommentBarrage) {
128
+ if (!this.createCommentBarrage(this.config.barrageList[this.config.barrageIndex])) {
129
+ this.config.barrageIndex = (this.config.barrageIndex + 1) % this.config.barrageList.length;
130
+ return createOrRemoveBarrage();
131
+ }
132
+ this.config.barrageIndex = (this.config.barrageIndex + 1) % this.config.barrageList.length;
133
+ }
134
+ if (this.config.barrageTimer.length > (this.config.barrageList.length > this.config.maxBarrage ? this.config.maxBarrage : this.config.barrageList.length) && !this.hoverOnCommentBarrage) {
135
+ this.removeCommentBarrage(this.config.barrageTimer.shift());
136
+ }
137
+ };
138
+
139
+ setTimeout(() => {
140
+ createOrRemoveBarrage();
141
+ if (this.commentInterval) {
142
+ clearInterval(this.commentInterval);
143
+ }
144
+ this.commentInterval = setInterval(createOrRemoveBarrage, this.config.barrageTime);
145
+ }, 3000);
146
+ }
147
+
148
+ async init() {
149
+ await this.initCommentBarrage();
150
+ const commentBarrage = document.querySelector(".comment-barrage");
151
+ commentBarrage.addEventListener('mouseover', () => this.hoverOnCommentBarrage = true);
152
+ commentBarrage.addEventListener('mouseout', () => this.hoverOnCommentBarrage = false);
153
+ }
154
+ }
155
+ (config)
156
+ }
@@ -3,7 +3,7 @@ function initializeCommentBarrage() {
3
3
  let config = {
4
4
  maxBarrage: 1,
5
5
  barrageTime: 8e3,
6
- walineUrl: GLOBAL_CONFIG.comment.waline.url,
6
+ walineUrl: GLOBAL_CONFIG.comment.url,
7
7
  pageUrl: window.location.pathname,
8
8
  }
9
9
  new class {
@@ -78,9 +78,9 @@ function initializeCommentBarrage() {
78
78
  element.classList.add("comment-barrage-item");
79
79
  element.innerHTML = `
80
80
  <div class="barrageHead">
81
- <a class="barrageTitle" href="javascript:sco.scrollTo('post-comment')">热评</a>
81
+ <a class="barrageTitle" href="javascript:sco.scrollTo('post-comment')">${GLOBAL_CONFIG.lang.barrage.title}</a>
82
82
  <div class="barrageNick">${comment.nick}</div>
83
- <img class="barrageAvatar" src="https://cravatar.cn/avatar/${comment.avatar}"/>
83
+ <img class="barrageAvatar" src="${GLOBAL_CONFIG.comment.avatar}/avatar/${comment.avatar}"/>
84
84
  <a class="comment-barrage-close" href="javascript:sco.switchCommentBarrage();">
85
85
  <i class="solitude st-close-fill"></i>
86
86
  </a>
package/source/js/main.js CHANGED
@@ -74,7 +74,7 @@ const percent = () => {
74
74
 
75
75
  if ((document.getElementById("post-comment") || document.getElementById("footer")).offsetTop < viewportBottom || scrollPercent > 90) {
76
76
  document.querySelector("#nav-totop").classList.add("long")
77
- percentElement.innerHTML = "返回顶部"
77
+ percentElement.innerHTML = GLOBAL_CONFIG.lang.backtop
78
78
  } else {
79
79
  document.querySelector("#nav-totop").classList.remove("long")
80
80
  if (scrollPercent >= 0) {
@@ -346,10 +346,6 @@ let sco = {
346
346
  el.setSelectionRange(-1, -1)
347
347
  }
348
348
  }
349
- const commentTips = document.querySelector("#comment-tips");
350
- if (commentTips) {
351
- commentTips.classList.add("show");
352
- }
353
349
  },
354
350
  initbbtalk: function () {
355
351
  if (document.querySelector('#bber-talk')) {
@@ -586,31 +582,8 @@ let sco = {
586
582
  document.getElementById("toPageButton").href = targetPageUrl;
587
583
  }
588
584
  },
589
- addRandomCommentInfo: function () {
590
- const e = `${GLOBAL_CONFIG.comment.randomInfoStart[Math.floor(Math.random() * GLOBAL_CONFIG.comment.randomInfoStart.length)]}${GLOBAL_CONFIG.comment.randomInfoEnd[Math.floor(Math.random() * GLOBAL_CONFIG.comment.randomInfoEnd.length)]}`;
591
-
592
- const nameSelectors = ["#author", "input[name='comname']", "#inpName", "input[name='author']", "#ds-dialog-name", "#name", "input[name='nick']", "#comment_author"];
593
- const emailSelectors = ["#mail", "#email", "input[name='commail']", "#inpEmail", "input[name='email']", "#ds-dialog-email", "input[name='mail']", "#comment_email"];
594
-
595
- const nameElements = nameSelectors.map(selector => document.querySelector(selector)).filter(Boolean);
596
- const emailElements = emailSelectors.map(selector => document.querySelector(selector)).filter(Boolean);
597
-
598
- nameElements.forEach(element => {
599
- element.value = e;
600
- element.dispatchEvent(new Event("input"));
601
- });
602
-
603
- emailElements.forEach(element => {
604
- element.value = "donotreply@examp.com";
605
- element.dispatchEvent(new Event("input"));
606
- });
607
- },
608
585
  owoBig() {
609
- const type = GLOBAL_CONFIG.comment.type;
610
- const owoSelectors = {
611
- body: type === 'twikoo' ? '.OwO-body' : '.wl-emoji-popup',
612
- item: type === 'twikoo' ? '.OwO-items li' : '.wl-tab-wrapper button'
613
- };
586
+ const owoSelectors = GLOBAL_CONFIG.comment.owo
614
587
 
615
588
  let owoBig = document.getElementById('owo-big');
616
589
  if (!owoBig) {
@@ -762,6 +735,25 @@ const addHighlight = () => {
762
735
  }
763
736
  }
764
737
 
738
+ const addCopyright = () => {
739
+ if (!GLOBAL_CONFIG.copyright) return
740
+ const {limit, author, link, source, info} = GLOBAL_CONFIG.copyright
741
+ const handleCopy = (e) => {
742
+ e.preventDefault()
743
+ const copyText = window.getSelection(0).toString()
744
+ let text = copyText
745
+ if (copyText.length > limit) {
746
+ text = `${copyText}\n\n${author}\n${link}${window.location.href}\n${source}\n${info}`
747
+ }
748
+ if (e.clipboardData) {
749
+ return e.clipboardData.setData('text', text)
750
+ } else {
751
+ return window.clipboardData.setData('text', text)
752
+ }
753
+ }
754
+ document.body.addEventListener('copy', handleCopy)
755
+ }
756
+
765
757
  class tabs {
766
758
  static init() {
767
759
  this.clickFnOfTabs()
@@ -815,17 +807,18 @@ window.refreshFn = () => {
815
807
  utils.changeTimeFormat()
816
808
  GLOBAL_CONFIG.lazyload.enable && utils.lazyloadImg()
817
809
  GLOBAL_CONFIG.lightbox && utils.lightbox(document.querySelectorAll("#article-container img:not(.flink-avatar)"))
818
- GLOBAL_CONFIG.randomlinks && randomLinksList()
810
+ GLOBAL_CONFIG.randomlink && randomLinksList()
819
811
  PAGE_CONFIG.comment && initComment()
820
812
  PAGE_CONFIG.toc && toc.init();
821
813
  (PAGE_CONFIG.is_post || PAGE_CONFIG.is_page) && ((addHighlight()) || tabs.init())
814
+ addCopyright()
822
815
  PAGE_CONFIG.is_home && showTodayCard()
823
816
  GLOBAL_CONFIG.covercolor.enable && coverColor()
824
817
  sco.initConsoleState()
825
818
  GLOBAL_CONFIG.comment.commentBarrage && PAGE_CONFIG.comment && initializeCommentBarrage()
826
819
  document.body.setAttribute('data-type', PAGE_CONFIG.page)
827
820
  PAGE_CONFIG.page === "music" && scoMusic.init()
828
- GLOBAL_CONFIG.ai.enable && PAGE_CONFIG.page === "post" && ScoAI.init()
821
+ GLOBAL_CONFIG.post_ai && PAGE_CONFIG.page === "post" && efu_ai.init()
829
822
  }
830
823
 
831
824
  document.addEventListener('DOMContentLoaded', function () {
@@ -833,6 +826,8 @@ document.addEventListener('DOMContentLoaded', function () {
833
826
  })
834
827
 
835
828
  window.onkeydown = function (e) {
836
- (123 === e.keyCode || (17 === e.ctrlKey && 16 === e.shiftKey && 67 === e.keyCode)) && utils.snackbarShow("开发者模式已打开,请遵循GPL协议", !1, 3e3);
829
+ (123 === e.keyCode || (17 === e.ctrlKey && 16 === e.shiftKey && 67 === e.keyCode)) && utils.snackbarShow(GLOBAL_CONFIG.lang.f12, !1, 3e3);
837
830
  (27 === e.keyCode) && sco.hideConsole();
838
- }
831
+ }
832
+
833
+ document.addEventListener('copy', () => utils.snackbarShow(GLOBAL_CONFIG.lang.copy.success,false,3e3))
@@ -0,0 +1,6 @@
1
+ /**
2
+ * author: Efu AI
3
+ * email: o@efu.me
4
+ * website: https://efu.me
5
+ */
6
+ class efuAI{constructor(){this.root="https://summary.tianli0.top",this.aiTalkMode=!1,this.aiPostExplanation="",this.config=GLOBAL_CONFIG.post_ai,this.scoGPTIsRunning=!1}init(){this.generate(),this.AIEngine()}getTitleAndContent(){const e=document.getElementById("article-container"),t=document.title,n=e.getElementsByTagName("p"),i=e.querySelectorAll("h1, h2, h3, h4, h5");return(t+" "+Array.from(i).concat(Array.from(n)).map((e=>e.innerText.replace(/https?:\/\/[^\s]+/g,""))).join(" ")).slice(0,1e3)}async generate(){this.aiShowAnimation(this.fetch(document.title,this.getTitleAndContent(),this.config.key))}async fetch(e,t,n){const i=`${this.root}/?content=${encodeURIComponent(t)}&title=${e}&key=${encodeURIComponent(n)}&url=${encodeURIComponent(window.location.href)}`,s=await fetch(i),o=await s.json();return s.ok?(this.aiPostExplanation=o.summary,o.summary):(console.error("Request failed:",o.err_msg),o.err_msg)}aiShowAnimation(e,t=!1){const n=document.querySelector(".ai-explanation"),i=document.querySelector(".ai-tag");if(!n||this.scoGPTIsRunning)return;this.scoGPTIsRunning=!0,this.cleanSuggestions(),i.classList.add("loadingAI"),n.style.display="block",n.innerHTML='生成中...<span class="blinking-cursor"></span>';let s,o,a=!0,c=0,r=!0;const l=new IntersectionObserver((e=>{a=e[0].isIntersecting,a&&requestAnimationFrame(o)}),{threshold:0});e.then((e=>{s=performance.now(),o=()=>{if(c<e.length&&a){const r=performance.now(),g=r-s,h=e.slice(c,c+1),u=/[,。!、?,.!?]/.test(h),m=/[a-zA-Z0-9]/.test(h);g>=(u?100*Math.random()+100:m?10:25)&&(n.innerText=e.slice(0,c+1),s=r,c++,c<e.length?n.innerHTML=e.slice(0,c)+'<span class="blinking-cursor"></span>':(n.innerHTML=e,n.style.display="block",this.scoGPTIsRunning=!1,i.classList.remove("loadingAI"),l.disconnect(),t&&this.createSuggestions())),a&&requestAnimationFrame(o)}},a&&r&&setTimeout((()=>{requestAnimationFrame(o),r=!1}),3e3),l.observe(n)})).catch((e=>{console.error("检索信息失败:",e),n.innerHTML="检索信息失败",n.style.display="block",this.scoGPTIsRunning=!1,i.classList.remove("loadingAI"),l.disconnect()}))}AIEngine(){const e=document.querySelector(".ai-tag");e&&e.addEventListener("click",(()=>{this.scoGPTIsRunning||(this.aiTalkMode=!0,this.aiShowAnimation(Promise.resolve(this.config.talk),!0))}))}cleanSuggestions(){const e=document.querySelector(".ai-suggestions");e?e.innerHTML="":console.error("没有这个元素:'ai-suggestions'")}createSuggestions(){this.aiTalkMode&&(this.cleanSuggestions(),this.createSuggestionItemWithAction("这篇文章讲了什么?",(()=>{""===this.aiPostExplanation?this.generate():this.aiShowAnimation(Promise.resolve(this.aiPostExplanation),!0)})),this.config.randomPost&&this.createSuggestionItemWithAction("带我去看看其他文章",(()=>toRandomPost())),this.aiTalkMode=!0)}createSuggestionItemWithAction(e,t){const n=document.querySelector(".ai-suggestions");if(!n)return void console.error("无法找到具有class为ai-suggestions的元素");const i=document.createElement("div");i.classList.add("ai-suggestions-item"),i.textContent=e,i.addEventListener("click",t),n.appendChild(i)}}const efu_ai=new efuAI;
@@ -229,5 +229,18 @@ const utils = {
229
229
  target: 'time',
230
230
  lang: GLOBAL_CONFIG.lang.lately,
231
231
  })
232
- }
232
+ },
233
+ loadComment: (dom, callback) => {
234
+ if ('IntersectionObserver' in window) {
235
+ const observerItem = new IntersectionObserver((entries) => {
236
+ if (entries[0].isIntersecting) {
237
+ callback()
238
+ observerItem.disconnect()
239
+ }
240
+ }, { threshold: [0] })
241
+ observerItem.observe(dom)
242
+ } else {
243
+ callback()
244
+ }
245
+ },
233
246
  }