hexo-theme-solitude 2.1.6 → 2.1.8

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 (73) hide show
  1. package/CONTRIBUTING.md +1 -1
  2. package/LICENSE +1 -1
  3. package/README.md +1 -1
  4. package/README_en-US.md +1 -1
  5. package/README_zh-Hant.md +1 -1
  6. package/SECURITY.md +1 -1
  7. package/_config.yml +16 -20
  8. package/languages/default.yml +173 -173
  9. package/layout/archive.pug +3 -1
  10. package/layout/category.pug +3 -1
  11. package/layout/includes/inject/body.pug +1 -1
  12. package/layout/includes/page/default.pug +1 -1
  13. package/layout/includes/page/links.pug +1 -1
  14. package/layout/includes/page/tlink.pug +1 -1
  15. package/layout/includes/rightmenu.pug +6 -5
  16. package/layout/includes/widgets/page/about/hobbies.pug +18 -17
  17. package/layout/includes/widgets/page/about/tenyear.pug +24 -25
  18. package/layout/includes/widgets/page/links/linksCard.pug +5 -2
  19. package/layout/includes/widgets/page/message/content.pug +1 -1
  20. package/layout/includes/widgets/third-party/hot/artalk.pug +56 -0
  21. package/layout/includes/widgets/third-party/hot/twikoo.pug +57 -0
  22. package/layout/includes/widgets/third-party/pjax.pug +2 -1
  23. package/layout/index.pug +1 -1
  24. package/layout/post.pug +1 -1
  25. package/layout/tag.pug +2 -0
  26. package/package.json +1 -1
  27. package/plugins.yml +10 -10
  28. package/scripts/event/init.js +0 -1
  29. package/scripts/event/merge_config.js +14 -39
  30. package/scripts/event/welcome.js +11 -7
  31. package/scripts/filter/default.js +20 -21
  32. package/scripts/filter/lazyload.js +2 -4
  33. package/scripts/filter/randomPosts.js +14 -3
  34. package/scripts/helper/getArchiveLength.js +9 -11
  35. package/scripts/helper/related_post.js +56 -56
  36. package/scripts/tags/article.js +53 -15
  37. package/scripts/tags/tabs.js +37 -46
  38. package/source/css/_comments/comment.styl +4 -3
  39. package/source/css/_comments/twikoo.styl +6 -7
  40. package/source/css/_global/animation.styl +0 -15
  41. package/source/css/_global/index.styl +19 -19
  42. package/source/css/_highlight/highlight/diff.styl +13 -1
  43. package/source/css/_highlight/index.styl +2 -2
  44. package/source/css/_highlight/prismjs/diff.styl +13 -1
  45. package/source/css/_highlight/prismjs/index.styl +1 -1
  46. package/source/css/_highlight/prismjs/line-number.styl +1 -1
  47. package/source/css/_layout/article-container.styl +1 -1
  48. package/source/css/_layout/console.styl +1 -0
  49. package/source/css/_layout/recent-post.styl +2 -2
  50. package/source/css/_page/_about/about.styl +1 -1
  51. package/source/css/_page/_about/game.styl +2 -17
  52. package/source/css/_page/error.styl +2 -3
  53. package/source/css/_page/links.styl +2 -2
  54. package/source/css/_page/other.styl +1 -0
  55. package/source/css/_page/says.styl +4 -3
  56. package/source/css/_tags/gallery.styl +1 -1
  57. package/source/css/_tags/tabs.styl +2 -2
  58. package/source/img/error_load.avif +0 -0
  59. package/source/js/covercolor/api.js +29 -14
  60. package/source/js/covercolor/ave.js +38 -24
  61. package/source/js/covercolor/local.js +60 -52
  62. package/source/js/main.js +253 -248
  63. package/source/js/music.js +21 -39
  64. package/source/js/right_menu.js +64 -127
  65. package/source/js/third_party/barrage.min.js +93 -1
  66. package/source/js/third_party/envelope.min.js +1 -1
  67. package/source/js/third_party/post_ai.min.js +184 -1
  68. package/source/js/tw_cn.js +17 -16
  69. package/source/js/utils.js +50 -57
  70. package/layout/includes/widgets/home/hot/artalk.pug +0 -45
  71. package/layout/includes/widgets/home/hot/twikoo.pug +0 -46
  72. package/source/img/loading.avif +0 -0
  73. /package/layout/includes/widgets/{home → third-party}/hot/index.pug +0 -0
@@ -1 +1,184 @@
1
- class POST_AI{constructor(){this.root="https://summary.tianli0.top";this.aiTalkMode=false;this.aiPostExplanation='';this.config=GLOBAL_CONFIG.post_ai;this.scoGPTIsRunning=false;console.log(' %c TianliGPT %c 文章摘要 %c https://postchat.zhheo.com','background:#35495e ; padding: 1px; border-radius: 3px 0 0 3px; color: #fff','background:#ff9a9a ; padding: 1px; border-radius: 0 3px 3px 0; color: #fff','background:unset ; padding: 1px; border-radius: 0 3px 3px 0; color: #fff')}init(){if(!document.querySelector(".ai-explanation"))return;this.scoGPTIsRunning=false;this.aiPostExplanation=PAGE_CONFIG.ai_text?PAGE_CONFIG.ai_text+"":false;if(!this.aiPostExplanation){this.generate()}else{this.aiShowAnimation(Promise.resolve(this.aiPostExplanation))}this.AIEngine()}getTitleAndContent(){const e=document.getElementById("article-container");const t=document.title;const n=e.getElementsByTagName("p");const 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,1000)}async generate(){this.aiShowAnimation(this.fetch(document.title,this.getTitleAndContent(),this.config.key))}async fetch(title,content,key){const url=`${this.root}/?content=${encodeURIComponent(content)}&title=${title}&key=${encodeURIComponent(key)}&url=${encodeURIComponent(window.location.href)}`;const response=await fetch(url);const data=await response.json();if(response.ok){this.aiPostExplanation=data.summary;return data.summary}else{console.error("Request failed:",data.err_msg);return data.err_msg}}aiShowAnimation(promise,onComplete=false){const explanationElement=document.querySelector(".ai-explanation");const tagElement=document.querySelector(".ai-tag");if(!explanationElement||this.scoGPTIsRunning)return;this.scoGPTIsRunning=true;this.cleanSuggestions();tagElement.classList.add("loadingAI");explanationElement.style.display="block";explanationElement.innerHTML='生成中...<span class="blinking-cursor"></span>';setTimeout(()=>{let startTime,update,currentIndex=0,isIntersecting=true,isInitial=true;const observer=new IntersectionObserver(entries=>{isIntersecting=entries[0].isIntersecting;if(isIntersecting)requestAnimationFrame(update)},{threshold:0});promise.then(result=>{startTime=performance.now();update=()=>{if(currentIndex<result.length&&isIntersecting){const now=performance.now();const timeElapsed=now-startTime;const char=result.slice(currentIndex,currentIndex+1);const isPunctuation=/[,。!、?,.!?]/.test(char);const isAlphaNumeric=/[a-zA-Z0-9]/.test(char);const delay=isPunctuation?100*Math.random()+100:(isAlphaNumeric?10:25);if(timeElapsed>=delay){explanationElement.innerText=result.slice(0,currentIndex+1);startTime=now;currentIndex++;if(currentIndex<result.length){explanationElement.innerHTML=result.slice(0,currentIndex)+'<span class="blinking-cursor"></span>'}else{explanationElement.innerHTML=result;explanationElement.style.display="block";this.scoGPTIsRunning=false;tagElement.classList.remove("loadingAI");observer.disconnect();if(onComplete)this.createSuggestions()}}if(isIntersecting)requestAnimationFrame(update)}};if(isIntersecting&&isInitial){requestAnimationFrame(update);isInitial=false}observer.observe(explanationElement)}).catch(error=>{console.error("检索信息失败:",error);explanationElement.innerHTML="检索信息失败";explanationElement.style.display="block";this.scoGPTIsRunning=false;tagElement.classList.remove("loadingAI");observer.disconnect()})},2000)}AIEngine(){const e=document.querySelector(".ai-tag");if(e){e.addEventListener("click",()=>{if(!this.scoGPTIsRunning){this.aiTalkMode=true;this.aiShowAnimation(Promise.resolve(this.config.talk),true)}})}}cleanSuggestions(){const e=document.querySelector(".ai-suggestions");if(e){e.innerHTML=""}else{console.error("没有这个元素:'ai-suggestions'")}}createSuggestions(){if(this.aiTalkMode){this.cleanSuggestions();this.createSuggestionItemWithAction("这篇文章讲了什么?",()=>{if(this.aiPostExplanation===""){this.generate()}else{this.aiShowAnimation(Promise.resolve(this.aiPostExplanation),true)}});if(this.config.randomPost){this.createSuggestionItemWithAction("带我去看看其他文章",()=>toRandomPost())}this.aiTalkMode=true}}createSuggestionItemWithAction(text,action){const suggestions=document.querySelector(".ai-suggestions");if(!suggestions){console.error("无法找到具有class为ai-suggestions的元素");return}const item=document.createElement("div");item.classList.add("ai-suggestions-item");item.textContent=text;item.addEventListener("click",action);suggestions.appendChild(item)}}const ai=new POST_AI();
1
+ class POST_AI {
2
+ constructor() {
3
+ this.root = "https://summary.tianli0.top";
4
+ this.aiTalkMode = false;
5
+ this.aiPostExplanation = '';
6
+ this.config = GLOBAL_CONFIG.post_ai;
7
+ this.scoGPTIsRunning = false;
8
+ console.log('%c TianliGPT %c 文章摘要 %c https://postchat.zhheo.com',
9
+ 'background:#35495e ; padding: 1px; border-radius: 3px 0 0 3px; color: #fff',
10
+ 'background:#ff9a9a ; padding: 1px; border-radius: 0 3px 3px 0; color: #fff',
11
+ 'background:unset ; padding: 1px; border-radius: 0 3px 3px 0; color: #fff');
12
+ }
13
+
14
+ init() {
15
+ const explanationElement = document.querySelector(".ai-explanation");
16
+ if (!explanationElement) return;
17
+
18
+ this.scoGPTIsRunning = false;
19
+ this.aiPostExplanation = PAGE_CONFIG.ai_text || '';
20
+
21
+ if (!this.aiPostExplanation) {
22
+ this.generate();
23
+ } else {
24
+ this.aiShowAnimation(Promise.resolve(this.aiPostExplanation));
25
+ }
26
+ this.AIEngine();
27
+ }
28
+
29
+ getTitleAndContent() {
30
+ const articleContainer = document.querySelector(".article-container");
31
+ const title = document.title;
32
+ const paragraphs = articleContainer.getElementsByTagName("p");
33
+ const headers = articleContainer.querySelectorAll("h1, h2, h3, h4, h5");
34
+
35
+ return (title + " " + [...headers, ...paragraphs]
36
+ .map(element => element.innerText.replace(/https?:\/\/[^\s]+/g, ""))
37
+ .join(" ")).slice(0, 1000);
38
+ }
39
+
40
+ async generate() {
41
+ const title = document.title;
42
+ const content = this.getTitleAndContent();
43
+ const key = this.config.key;
44
+ this.aiShowAnimation(this.fetch(title, content, key));
45
+ }
46
+
47
+ async fetch(title, content, key) {
48
+ const url = `${this.root}/?content=${encodeURIComponent(content)}&title=${title}&key=${encodeURIComponent(key)}&url=${encodeURIComponent(window.location.href)}`;
49
+ try {
50
+ const response = await fetch(url);
51
+ const data = await response.json();
52
+ if (response.ok) {
53
+ this.aiPostExplanation = data.summary;
54
+ return data.summary;
55
+ } else {
56
+ console.error("Request failed:", data.err_msg);
57
+ return data.err_msg;
58
+ }
59
+ } catch (error) {
60
+ console.error("Fetch error:", error);
61
+ return "Error fetching data";
62
+ }
63
+ }
64
+
65
+ aiShowAnimation(promise, onComplete = false, delay = 0) {
66
+ const explanationElement = document.querySelector(".ai-explanation");
67
+ const tagElement = document.querySelector(".ai-tag");
68
+ if (!explanationElement || this.scoGPTIsRunning) return;
69
+
70
+ this.scoGPTIsRunning = true;
71
+ this.cleanSuggestions();
72
+ tagElement.classList.add("loadingAI");
73
+ explanationElement.style.display = "block";
74
+ explanationElement.innerHTML = '生成中...<span class="blinking-cursor"></span>';
75
+
76
+ setTimeout(() => {
77
+ let startTime, update, currentIndex = 0, isIntersecting = true, isInitial = true;
78
+ const observer = new IntersectionObserver(entries => {
79
+ isIntersecting = entries[0].isIntersecting;
80
+ if (isIntersecting) requestAnimationFrame(update);
81
+ }, { threshold: 0 });
82
+
83
+ promise.then(result => {
84
+ startTime = performance.now();
85
+ update = () => {
86
+ if (currentIndex < result.length && isIntersecting) {
87
+ const now = performance.now();
88
+ const timeElapsed = now - startTime;
89
+ const char = result.slice(currentIndex, currentIndex + 1);
90
+ const isPunctuation = /[,。!、?,.!?]/.test(char);
91
+ const isAlphaNumeric = /[a-zA-Z0-9]/.test(char);
92
+ const delay = isPunctuation ? 100 * Math.random() + 100 : (isAlphaNumeric ? 10 : 25);
93
+
94
+ if (timeElapsed >= delay) {
95
+ explanationElement.innerText = result.slice(0, currentIndex + 1);
96
+ startTime = now;
97
+ currentIndex++;
98
+ if (currentIndex < result.length) {
99
+ explanationElement.innerHTML = result.slice(0, currentIndex) + '<span class="blinking-cursor"></span>';
100
+ } else {
101
+ explanationElement.innerHTML = result;
102
+ explanationElement.style.display = "block";
103
+ this.scoGPTIsRunning = false;
104
+ tagElement.classList.remove("loadingAI");
105
+ observer.disconnect();
106
+ if (onComplete) this.createSuggestions();
107
+ }
108
+ }
109
+ if (isIntersecting) requestAnimationFrame(update);
110
+ }
111
+ };
112
+ if (isIntersecting && isInitial) {
113
+ requestAnimationFrame(update);
114
+ isInitial = false;
115
+ }
116
+ observer.observe(explanationElement);
117
+ }).catch(error => {
118
+ console.error("检索信息失败:", error);
119
+ explanationElement.innerHTML = "检索信息失败";
120
+ explanationElement.style.display = "block";
121
+ this.scoGPTIsRunning = false;
122
+ tagElement.classList.remove("loadingAI");
123
+ observer.disconnect();
124
+ });
125
+ }, delay);
126
+ }
127
+
128
+ AIEngine() {
129
+ const tagElement = document.querySelector(".ai-tag");
130
+ if (tagElement) {
131
+ tagElement.addEventListener("click", () => {
132
+ if (!this.scoGPTIsRunning) {
133
+ this.aiTalkMode = true;
134
+ this.aiShowAnimation(Promise.resolve(this.config.talk), true);
135
+ }
136
+ });
137
+ }
138
+ }
139
+
140
+ cleanSuggestions() {
141
+ const suggestionsElement = document.querySelector(".ai-suggestions");
142
+ if (suggestionsElement) {
143
+ suggestionsElement.innerHTML = "";
144
+ } else {
145
+ console.error("没有这个元素:'ai-suggestions'");
146
+ }
147
+ }
148
+
149
+ createSuggestions() {
150
+ if (this.aiTalkMode) {
151
+ this.cleanSuggestions();
152
+ this.createSuggestionItemWithAction("这篇文章讲了什么?", () => {
153
+ if (this.aiPostExplanation === "") {
154
+ setTimeout(() => {
155
+ this.generate();
156
+ }, 3000);
157
+ } else {
158
+ setTimeout(() => {
159
+ this.aiShowAnimation(Promise.resolve(this.aiPostExplanation), true);
160
+ }, 3000);
161
+ }
162
+ });
163
+ if (this.config.randomPost) {
164
+ this.createSuggestionItemWithAction("带我去看看其他文章", () => toRandomPost());
165
+ }
166
+ this.aiTalkMode = true;
167
+ }
168
+ }
169
+
170
+ createSuggestionItemWithAction(text, action) {
171
+ const suggestions = document.querySelector(".ai-suggestions");
172
+ if (!suggestions) {
173
+ console.error("无法找到具有class为ai-suggestions的元素");
174
+ return;
175
+ }
176
+ const item = document.createElement("div");
177
+ item.classList.add("ai-suggestions-item");
178
+ item.textContent = text;
179
+ item.addEventListener("click", action);
180
+ suggestions.appendChild(item);
181
+ }
182
+ }
183
+
184
+ const ai = new POST_AI();
@@ -11,33 +11,34 @@ document.addEventListener('DOMContentLoaded', function () {
11
11
 
12
12
  function translateText(txt) {
13
13
  if (!txt) return '';
14
- if (currentEncoding === 1 && targetEncoding === 2) return Simplized(txt);
15
- if (currentEncoding === 2 && targetEncoding === 1) return Traditionalized(txt);
16
- return txt;
14
+ return currentEncoding === targetEncoding ? txt : (currentEncoding === 1 ? Simplized(txt) : Traditionalized(txt));
17
15
  }
18
16
 
19
17
  function translateBody(fobj) {
20
- const objs = fobj && typeof fobj === 'object' ? fobj.childNodes : document.body.childNodes;
18
+ const objs = fobj?.childNodes || document.body.childNodes;
21
19
 
22
20
  objs.forEach(obj => {
23
21
  if (['BR', 'HR'].includes(obj.tagName)) return;
24
-
22
+
25
23
  if (obj.title) obj.title = translateText(obj.title);
26
24
  if (obj.alt) obj.alt = translateText(obj.alt);
27
25
  if (obj.placeholder) obj.placeholder = translateText(obj.placeholder);
28
26
  if (obj.tagName === 'INPUT' && obj.value && !['text', 'hidden'].includes(obj.type)) {
29
27
  obj.value = translateText(obj.value);
30
28
  }
31
- if (obj.nodeType === 3) obj.data = translateText(obj.data);
32
- else translateBody(obj);
29
+ if (obj.nodeType === 3) {
30
+ obj.data = translateText(obj.data);
31
+ } else {
32
+ translateBody(obj);
33
+ }
33
34
  });
34
35
  }
35
36
 
36
- function translatePage(simeple, traditional ,button) {
37
+ function translatePage(simplified, traditional, button) {
37
38
  currentEncoding = targetEncoding;
38
39
  targetEncoding = targetEncoding === 1 ? 2 : 1;
39
- button.lastChild.textContent = targetEncoding === 1 ? simeple : traditional;
40
-
40
+ button.lastChild.textContent = targetEncoding === 1 ? simplified : traditional;
41
+
41
42
  utils.snackbarShow(targetEncoding === 1 ? '你已切換為繁體' : '你已切换为简体');
42
43
  utils.saveToLocal.set(targetEncodingCookie, targetEncoding, 2);
43
44
  setLang();
@@ -58,7 +59,7 @@ document.addEventListener('DOMContentLoaded', function () {
58
59
  const tt = FTPYStr();
59
60
  return Array.from(cc).map(char => {
60
61
  const index = ss.indexOf(char);
61
- return index > -1 ? tt.charAt(index) : char;
62
+ return index !== -1 ? tt.charAt(index) : char;
62
63
  }).join('');
63
64
  }
64
65
 
@@ -67,29 +68,29 @@ document.addEventListener('DOMContentLoaded', function () {
67
68
  const tt = FTPYStr();
68
69
  return Array.from(cc).map(char => {
69
70
  const index = tt.indexOf(char);
70
- return index > -1 ? ss.charAt(index) : char;
71
+ return index !== -1 ? ss.charAt(index) : char;
71
72
  }).join('');
72
73
  }
73
74
 
74
75
  function translateInitialization() {
75
- let btn_1 = document.getElementById('menu-translate');
76
+ const btn_1 = document.getElementById('menu-translate');
76
77
  if (btn_1) {
77
78
  btn_1.lastChild.textContent = targetEncoding === 1 ? '转为简体' : '转为繁体';
78
79
  if (currentEncoding !== targetEncoding) {
79
80
  setLang();
80
81
  setTimeout(translateBody, translateDelay);
81
82
  }
82
- btn_1.addEventListener('click', () => {translatePage( '转为简体','转为繁体',btn_1)}, false);
83
+ btn_1.addEventListener('click', () => translatePage('转为简体', '转为繁体', btn_1), false);
83
84
  }
84
85
 
85
- let btn_2 = document.querySelector('.rs_hide .translate');
86
+ const btn_2 = document.querySelector('.rs_hide .translate');
86
87
  if (btn_2) {
87
88
  btn_2.lastChild.textContent = targetEncoding === 1 ? '简' : '繁';
88
89
  if (currentEncoding !== targetEncoding) {
89
90
  setLang();
90
91
  setTimeout(translateBody, translateDelay);
91
92
  }
92
- btn_2.addEventListener('click', () => {translatePage('简','繁',btn_2)}, false);
93
+ btn_2.addEventListener('click', () => translatePage('简', '繁', btn_2), false);
93
94
  }
94
95
  }
95
96
 
@@ -11,20 +11,21 @@
11
11
  if (!previous && leading === false) previous = now;
12
12
  const remaining = wait - (now - previous);
13
13
  if (remaining <= 0 || remaining > wait) {
14
- if (timeout) {
15
- clearTimeout(timeout);
16
- timeout = null;
17
- }
14
+ if (timeout) clearTimeout(timeout);
18
15
  later(this, arguments);
19
16
  } else if (!timeout && trailing !== false) {
20
17
  timeout = setTimeout(() => later(this, arguments), remaining);
21
18
  }
22
19
  };
23
20
  },
24
- fadeIn: (ele, time) => ele.style.cssText = `display:block;animation: to_show ${time}s`,
21
+ fadeIn: (ele, time) => {
22
+ ele.style.display = 'block';
23
+ ele.style.animation = `to_show ${time}s`;
24
+ },
25
25
  fadeOut: (ele, time) => {
26
26
  const resetStyles = () => {
27
- ele.style.cssText = "display: none; animation: '' ";
27
+ ele.style.display = 'none';
28
+ ele.style.animation = '';
28
29
  ele.removeEventListener('animationend', resetStyles);
29
30
  };
30
31
  ele.addEventListener('animationend', resetStyles);
@@ -37,12 +38,7 @@
37
38
  }
38
39
  },
39
40
  snackbarShow: (text, showAction = false, duration = 5000) => {
40
- Snackbar.show({
41
- text,
42
- showAction,
43
- duration,
44
- pos: 'top-center'
45
- });
41
+ Snackbar.show({ text, showAction, duration, pos: 'top-center' });
46
42
  },
47
43
  copy: async (text) => {
48
44
  const message = await navigator.clipboard.writeText(text)
@@ -59,37 +55,27 @@
59
55
  return actualTop;
60
56
  },
61
57
  siblings: (ele, selector) => {
62
- return [...ele.parentNode.children].filter((child) => {
63
- if (selector) {
64
- return child !== ele && child.matches(selector)
65
- }
66
- return child !== ele
67
- })
68
- },
69
- randomNum: (length) => {
70
- return Math.floor(Math.random() * length)
71
- },
72
- timeDiff: (timeObj, today) => {
73
- const timeDiff = today.getTime() - timeObj.getTime();
74
- return Math.floor(timeDiff / (1000 * 3600 * 24));
58
+ return [...ele.parentNode.children].filter(child =>
59
+ child !== ele && (!selector || child.matches(selector))
60
+ );
75
61
  },
62
+ randomNum: length => Math.floor(Math.random() * length),
63
+ timeDiff: (timeObj, today) => Math.floor((today.getTime() - timeObj.getTime()) / (1000 * 3600 * 24)),
76
64
  scrollToDest: (pos, time = 500) => {
77
65
  const currentPos = window.pageYOffset;
78
66
  const isNavFixed = document.getElementById('page-header').classList.contains('nav-fixed');
79
67
  pos = currentPos > pos || isNavFixed ? pos - 70 : pos;
80
68
 
81
69
  if ('scrollBehavior' in document.documentElement.style) {
82
- window.scrollTo({top: pos, behavior: 'smooth'});
70
+ window.scrollTo({ top: pos, behavior: 'smooth' });
83
71
  return;
84
72
  }
85
73
 
86
74
  const distance = pos - currentPos;
87
75
  const step = currentTime => {
88
- const start = start || currentTime;
89
- const progress = currentTime - start;
90
-
76
+ const progress = currentTime - (start || currentTime);
91
77
  if (progress < time) {
92
- window.scrollTo(0, currentPos + distance * progress / time);
78
+ window.scrollTo(0, currentPos + (distance * progress) / time);
93
79
  window.requestAnimationFrame(step);
94
80
  } else {
95
81
  window.scrollTo(0, pos);
@@ -99,9 +85,9 @@
99
85
  window.requestAnimationFrame(step);
100
86
  },
101
87
  isMobile: () => /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent),
102
- isHidden: e => 0 === e.offsetHeight && 0 === e.offsetWidth,
88
+ isHidden: e => e.offsetHeight === 0 && e.offsetWidth === 0,
103
89
  animateIn: (ele, text) => {
104
- Object.assign(ele.style, {display: 'block', animation: text});
90
+ Object.assign(ele.style, { display: 'block', animation: text });
105
91
  },
106
92
  animateOut: (ele, text) => {
107
93
  const resetAnimation = () => {
@@ -113,12 +99,10 @@
113
99
  ele.style.animation = text;
114
100
  },
115
101
  wrap: (selector, eleType, options) => {
116
- const createEle = document.createElement(eleType)
117
- for (const [key, value] of Object.entries(options)) {
118
- createEle.setAttribute(key, value)
119
- }
120
- selector.parentNode.insertBefore(createEle, selector)
121
- createEle.appendChild(selector)
102
+ const createEle = document.createElement(eleType);
103
+ Object.entries(options).forEach(([key, value]) => createEle.setAttribute(key, value));
104
+ selector.parentNode.insertBefore(createEle, selector);
105
+ createEle.appendChild(selector);
122
106
  },
123
107
  lazyloadImg: () => {
124
108
  window.lazyLoadInstance = new LazyLoad({
@@ -136,7 +120,7 @@
136
120
  };
137
121
 
138
122
  if (lightboxType === 'mediumZoom') {
139
- mediumZoom && mediumZoom(selector, {background: "var(--efu-card-bg)"});
123
+ mediumZoom && mediumZoom(selector, { background: "var(--efu-card-bg)" });
140
124
  } else if (lightboxType === 'fancybox') {
141
125
  selector.forEach(i => {
142
126
  if (i.parentNode.tagName !== 'A') {
@@ -150,9 +134,9 @@
150
134
  Fancybox.bind('[data-fancybox]', {
151
135
  Hash: false,
152
136
  animated: true,
153
- Thumbs: {showOnStart: false},
154
- Images: {Panzoom: {maxScale: 4}},
155
- Carousel: {transition: 'slide'},
137
+ Thumbs: { showOnStart: false },
138
+ Images: { Panzoom: { maxScale: 4 } },
139
+ Carousel: { transition: 'slide' },
156
140
  Toolbar: {
157
141
  display: {
158
142
  left: ['infobar'],
@@ -173,18 +157,21 @@
173
157
  const hour = 3600000;
174
158
  const day = 86400000;
175
159
  const month = 2592000000;
176
- const {time} = GLOBAL_CONFIG.lang;
177
- const dayCount = Math.floor(dateDiff / day)
178
- if (!more) return dayCount
179
- const minuteCount = Math.floor(dateDiff / minute)
180
- const hourCount = Math.floor(dateDiff / hour)
181
- const monthCount = Math.floor(dateDiff / month)
182
- if (monthCount > 12) return datePost.toISOString().slice(0, 10)
183
- if (monthCount >= 1) return `${monthCount} ${time.month}`
184
- if (dayCount >= 1) return `${dayCount} ${time.day}`
185
- if (hourCount >= 1) return `${hourCount} ${time.hour}`
186
- if (minuteCount >= 1) return `${minuteCount} ${time.min}`
187
- return time.just
160
+ const { time } = GLOBAL_CONFIG.lang;
161
+
162
+ const dayCount = Math.floor(dateDiff / day);
163
+ if (!more) return dayCount;
164
+
165
+ const minuteCount = Math.floor(dateDiff / minute);
166
+ const hourCount = Math.floor(dateDiff / hour);
167
+ const monthCount = Math.floor(dateDiff / month);
168
+
169
+ if (monthCount > 12) return datePost.toISOString().slice(0, 10);
170
+ if (monthCount >= 1) return `${monthCount} ${time.month}`;
171
+ if (dayCount >= 1) return `${dayCount} ${time.day}`;
172
+ if (hourCount >= 1) return `${hourCount} ${time.hour}`;
173
+ if (minuteCount >= 1) return `${minuteCount} ${time.min}`;
174
+ return time.just;
188
175
  },
189
176
  loadComment: (dom, callback) => {
190
177
  const observerItem = 'IntersectionObserver' in window ? new IntersectionObserver((entries) => {
@@ -192,10 +179,16 @@
192
179
  callback();
193
180
  observerItem.disconnect();
194
181
  }
195
- }, {threshold: [0]}) : null;
182
+ }, { threshold: [0] }) : null;
196
183
 
197
184
  observerItem ? observerItem.observe(dom) : callback();
198
185
  },
199
- }
200
- window.utils = {...window.utils, ...utilsFn};
186
+ escapeHtml: unsafe => unsafe.replace(/[&<"']/g, m => ({
187
+ '&': '&amp;',
188
+ '<': '&lt;',
189
+ '"': '&quot;',
190
+ "'": '&#039;'
191
+ }[m])),
192
+ };
193
+ window.utils = { ...window.utils, ...utilsFn };
201
194
  })()
@@ -1,45 +0,0 @@
1
- - const { server, site } = theme.artalk
2
-
3
- script.
4
- function updatePostsBasedOnComments() {
5
- const location = window.location
6
- const posts = Array.from(document.querySelectorAll('.recent-post-item[onclick] .post_cover a')).map(item => item.href.replace(location, GLOBAL_CONFIG.root))
7
-
8
- function get() {
9
- fetch(`!{server}/api/v2/stats/page_comment?page_keys=${posts.join(',')}&site_name=!{site}`).then(res => res.json())
10
- .then(item => {
11
- item = item.data
12
- posts.forEach(post => {
13
- const comment = item[post]
14
- if (comment > !{count}) {
15
- const postElement = document.querySelector(`.recent-post-item[onclick*="${post}"]`);
16
- if (postElement) {
17
- const infoTopTips = postElement.querySelector(".recent-post-info-top-tips"),
18
- originalSpan = infoTopTips ? infoTopTips.querySelector(".original") : null;
19
- if (originalSpan) {
20
- const hotTip = createHotTipElement();
21
- infoTopTips.insertBefore(hotTip, originalSpan);
22
- }
23
- }
24
- }
25
- })
26
- })
27
- .catch(error => console.error("Error fetching comments:", error));
28
- }
29
-
30
- function createHotTipElement() {
31
- const hotTip = document.createElement("span");
32
- hotTip.classList.add("hot-tip");
33
-
34
- const icon = document.createElement("i");
35
- icon.classList.add("solitude", "fas", "fa-fire-flame-curved");
36
- hotTip.appendChild(icon);
37
-
38
- const commentCount = document.createTextNode("!{_p('hot-tip')}");
39
- hotTip.appendChild(commentCount);
40
-
41
- return hotTip;
42
- }
43
-
44
- get()
45
- }
@@ -1,46 +0,0 @@
1
- script.
2
- function updatePostsBasedOnComments() {
3
- const location = window.location
4
- const posts = Array.from(document.querySelectorAll('.recent-post-item[onclick] .post_cover a')).map(item => item.href.replace(location, '/'))
5
-
6
- function get() {
7
- twikoo.getCommentsCount({
8
- envId: "!{theme.twikoo.envId}",
9
- urls: posts,
10
- includeReply: true
11
- }).then(function (response) {
12
- response.forEach(function (comment) {
13
- if (comment.count > !{count}) {
14
- const postElement = document.querySelector(`.recent-post-item[onclick*="${comment.url}"]`);
15
- if (postElement) {
16
- const infoTopTips = postElement.querySelector(".recent-post-info-top-tips"),
17
- originalSpan = infoTopTips ? infoTopTips.querySelector(".original") : null;
18
- if (originalSpan) {
19
- const hotTip = createHotTipElement();
20
- infoTopTips.insertBefore(hotTip, originalSpan);
21
- }
22
- }
23
- }
24
- });
25
- }).catch(function (error) {
26
- console.error("Error fetching comments:", error);
27
- });
28
- }
29
-
30
- function createHotTipElement() {
31
- const hotTip = document.createElement("span");
32
- hotTip.classList.add("hot-tip");
33
-
34
- const icon = document.createElement("i");
35
- icon.classList.add("solitude", "fas", "fa-fire-flame-curved");
36
- hotTip.appendChild(icon);
37
-
38
- const commentCount = document.createTextNode("!{_p('hot-tip')}");
39
- hotTip.appendChild(commentCount);
40
-
41
- return hotTip;
42
- }
43
-
44
- if (typeof twikoo === 'object') get()
45
- else utils.getScript('!{url_for(theme.cdn.twikoo)}').then(get)
46
- }
Binary file