hexo-theme-solitude 1.6.1 → 1.7.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 (47) 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 +20 -2
  7. package/languages/zh-CN.yml +25 -1
  8. package/languages/zh-TW.yml +25 -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/copyright.pug +5 -5
  15. package/layout/includes/widgets/post/postMeta.pug +8 -1
  16. package/layout/includes/widgets/third-party/comments/comment.pug +5 -7
  17. package/layout/includes/widgets/third-party/comments/valine.pug +44 -0
  18. package/layout/includes/widgets/third-party/comments/waline.pug +40 -12
  19. package/layout/includes/widgets/third-party/news-comment/newest-comment.pug +5 -3
  20. package/layout/includes/widgets/third-party/news-comment/twikoo.pug +12 -10
  21. package/layout/includes/widgets/third-party/news-comment/valine.pug +79 -0
  22. package/layout/includes/widgets/third-party/news-comment/waline.pug +25 -20
  23. package/layout/page.pug +3 -0
  24. package/layout/tag.pug +1 -1
  25. package/package.json +1 -1
  26. package/plugins.yml +15 -3
  27. package/scripts/event/cdn.js +7 -2
  28. package/scripts/event/init.js +4 -2
  29. package/scripts/event/merge_config.js +6 -5
  30. package/scripts/helper/related_post.js +2 -2
  31. package/scripts/tags/tabs.js +1 -1
  32. package/source/css/_comments/{index.styl → comment.styl} +4 -24
  33. package/source/css/_comments/valine.styl +245 -0
  34. package/source/css/_global/index.styl +3 -0
  35. package/source/css/_highlight/highlight/index.styl +1 -1
  36. package/source/css/_page/index.styl +1 -4
  37. package/source/css/_post/content.styl +13 -7
  38. package/source/css/_post/copyright.styl +4 -1
  39. package/source/css/index.styl +1 -3
  40. package/source/js/commentBarrage/twikoo.js +4 -4
  41. package/source/js/commentBarrage/valine.js +156 -0
  42. package/source/js/commentBarrage/waline.js +3 -3
  43. package/source/js/main.js +28 -33
  44. package/source/js/third_party/efu_ai.min.js +6 -0
  45. package/source/js/utils.js +14 -1
  46. package/source/css/_comments/waline.styl +0 -455
  47. package/source/js/third_party/sco-ai.min.js +0 -8
@@ -0,0 +1,245 @@
1
+ #comment
2
+ .vcount
3
+ display none !important
4
+
5
+ .vpreview-btn
6
+ display none
7
+
8
+ .vemoji-btn
9
+ position absolute
10
+ bottom 4.5px
11
+ left 50px
12
+
13
+ .vpanel
14
+ display flex
15
+ flex-direction column
16
+ position relative
17
+
18
+ .vemojis
19
+ display: none;
20
+ position: absolute;
21
+ left: 0;
22
+ right: 0;
23
+ max-width: 500px;
24
+ color: #4a4a4a;
25
+ border: 1px solid rgba(144, 147, 153, 0.31);
26
+ top: 6.7rem
27
+ z-index: 1000;
28
+ animation: .3s ease .1s 1 normal both running donate_effcet
29
+ width: 500px;
30
+ border: var(--style-border-always)
31
+ border-radius: 8px !important;
32
+ overflow: hidden;
33
+ background-color: var(--efu-maskbg)
34
+ backdrop-filter: saturate(180%) blur(10px);
35
+ transform: translateZ(0);
36
+ overflow-y: auto;
37
+ padding: 10px;
38
+
39
+ .vwrap
40
+ flex 1
41
+ display flex
42
+ border none !important
43
+ padding 0
44
+ overflow: inherit;
45
+ flex-direction column-reverse
46
+
47
+ .vheader
48
+ display flex
49
+ margin .5rem 0
50
+ position relative
51
+ width calc(100% - 5.5rem)
52
+ gap .5rem
53
+
54
+ +maxWidth768()
55
+ flex-direction column
56
+
57
+ input
58
+ border-radius 12px
59
+ width calc((100% - 1rem) / 3)
60
+ flex 1
61
+ position relative
62
+ font-size 13px
63
+ background var(--efu-secondbg)
64
+ border var(--style-border-always)
65
+ padding 6px 10px
66
+ line-height 1
67
+
68
+ +maxWidth768()
69
+ width 100%
70
+
71
+ .vquote
72
+
73
+ .vcard
74
+ background: var(--efu-card-bg);
75
+ border none
76
+ border-top: var(--style-border-dashed);
77
+ border-radius: 12px;
78
+ transition: .3s;
79
+ padding: 1rem 0 0;
80
+ margin-top: 0;
81
+ box-shadow: none;
82
+
83
+ .vreply-wrapper
84
+
85
+ .vrow .vcol:first-child
86
+ bottom 78px
87
+
88
+ +maxWidth768()
89
+ bottom 164px
90
+
91
+ .vrow .vcol.text-right:not(.vctrl)
92
+ bottom 31px
93
+
94
+ +maxWidth768()
95
+ bottom 117px
96
+
97
+ .cancel-reply
98
+ display flex !important
99
+ flex-direction row
100
+ justify-content center
101
+ margin 0
102
+
103
+ .cancel-reply-btn
104
+ position inherit
105
+
106
+ .vrow
107
+ padding 0
108
+
109
+ .vcol
110
+ position absolute
111
+
112
+ &:first-child
113
+ bottom 56px
114
+ left 20px
115
+ width auto
116
+
117
+ +maxWidth768()
118
+ bottom 141px
119
+
120
+ &.text-right:not(.vctrl)
121
+ bottom 9px
122
+ right 0
123
+ transition .3s
124
+ border 0 solid var(--efu-main)
125
+ width 5rem
126
+ margin-left .5rem
127
+ border-radius 12px
128
+ height 34px
129
+
130
+ +maxWidth768()
131
+ bottom 94px
132
+
133
+ button
134
+ background-color var(--efu-fontcolor)
135
+ width 100%
136
+ height 100%
137
+ color var(--efu-card-bg)
138
+ border-radius 12px
139
+ opacity .2
140
+
141
+ +maxWidth768()
142
+ height 119px
143
+
144
+ svg
145
+ width 18px
146
+ height 18px
147
+
148
+ #veditor
149
+ display block
150
+ padding 16px 16px 40px 16px
151
+ line-height 1.5
152
+ width 100%
153
+ font-size 14px
154
+ background var(--efu-secondbg)
155
+ color var(--efu-fontcolor)
156
+ border-radius 12px
157
+ min-height 121px
158
+ border var(--style-border-always)
159
+
160
+ &:focus
161
+ border var(--style-border-hover-always)
162
+ box-shadow var(--efu-shadow-main)
163
+
164
+ .vcard
165
+ margin-top: 0
166
+ margin-bottom: .5rem
167
+ background: var(--efu-card-bg);
168
+ transition: .3s;
169
+ border-radius: 12px;
170
+ padding: 0;
171
+ padding-top: .5rem;
172
+ border: none;
173
+ border-top: var(--style-border-dashed);
174
+ display: flex;
175
+ flex-direction: row;
176
+ word-break: break-all;
177
+
178
+ +maxWidth768()
179
+ padding: 1rem;
180
+ border: var(--style-border-always);
181
+ box-shadow: var(--efu-shadow-border)
182
+
183
+ .vimg
184
+ width 32px
185
+ height 32px
186
+ border-radius 32px
187
+ cursor pointer
188
+ margin-right 16px
189
+
190
+ &:hover
191
+ transform: rotate(360deg)
192
+
193
+ .vh
194
+ flex 1
195
+ padding 0
196
+ border 0
197
+
198
+ .vhead
199
+ display flex
200
+ align-items center
201
+ gap: 5px;
202
+
203
+ .vnick
204
+ font-size 1rem
205
+ line-height 32px
206
+ margin-right 0
207
+
208
+ .vsys
209
+ background: var(--efu-card-bg);
210
+ border: var(--style-border-always);
211
+ padding: 3px 5px
212
+ border-radius: 8px;
213
+ color: var(--efu-secondtext)
214
+ display: inline
215
+ font-size: .5rem;
216
+
217
+ .vat
218
+ display: flex;
219
+ align-items: center;
220
+ color: var(--efu-lighttext)
221
+ padding: 3px 12px
222
+ transition: all .3s;
223
+ border-radius: 8px;
224
+ background-color: var(--efu-secondbg);
225
+ border: var(--style-border-always);
226
+ position: absolute;
227
+ right: 0;
228
+ bottom: 18px
229
+
230
+ &:hover
231
+ background-color: var(--efu-lighttext)
232
+ color: var(--efu-card-bg)
233
+
234
+ .vquote
235
+ border-left none
236
+
237
+ .vicon.actived
238
+ fill var(--efu-main)
239
+
240
+ #page
241
+ .vcard
242
+ padding: 1rem 1rem 1.5rem;
243
+ border: var(--style-border);
244
+ border-top: var(--style-border);
245
+ box-shadow: var(--efu-shadow-border);
@@ -66,6 +66,9 @@ body
66
66
  line-height 2
67
67
  -webkit-tap-highlight-color transparent
68
68
  margin 0
69
+ if !hexo-config('copy.enable')
70
+ user-select none
71
+ -webkit-user-select none
69
72
 
70
73
  *
71
74
  box-sizing border-box
@@ -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
@@ -51,15 +51,18 @@
51
51
  .post-copyright__notice
52
52
  font-size 12px
53
53
  margin 0.5rem 0
54
+ display flex
55
+ justify-content center
54
56
 
55
57
  .post-copyright-info
56
58
  padding-left 0
57
59
  color var(--efu-secondtext)
58
60
  overflow hidden
59
61
  display -webkit-box
60
- -webkit-line-clamp 1
62
+ -webkit-line-clamp 3
61
63
  -webkit-box-orient vertical
62
64
  text-align center
65
+ max-width 500px
63
66
 
64
67
  +maxWidth768()
65
68
  -webkit-line-clamp 2
@@ -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
  }