hexo-theme-solitude 1.10.6 → 1.11.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 (32) hide show
  1. package/_config.yml +16 -0
  2. package/languages/default.yml +3 -0
  3. package/languages/en.yml +3 -0
  4. package/languages/zh-CN.yml +3 -0
  5. package/languages/zh-TW.yml +3 -0
  6. package/layout/includes/console.pug +5 -1
  7. package/layout/includes/inject/head.pug +1 -1
  8. package/layout/includes/page/recentcomment.pug +16 -0
  9. package/layout/includes/widgets/page/banner.pug +2 -2
  10. package/layout/includes/widgets/page/message/artalk.pug +45 -0
  11. package/layout/includes/widgets/page/message/js.pug +5 -1
  12. package/layout/includes/widgets/page/message/twikoo.pug +19 -16
  13. package/layout/includes/widgets/page/message/valine.pug +12 -3
  14. package/layout/includes/widgets/page/message/waline.pug +42 -0
  15. package/layout/includes/widgets/page/recentcomment/artalk.pug +78 -0
  16. package/layout/includes/widgets/page/recentcomment/twikoo.pug +83 -0
  17. package/layout/includes/widgets/page/recentcomment/valine.pug +79 -0
  18. package/layout/includes/widgets/page/recentcomment/waline.pug +72 -0
  19. package/layout/includes/widgets/third-party/comments/artalk.pug +1 -1
  20. package/layout/includes/widgets/third-party/news-comment/valine.pug +19 -17
  21. package/layout/includes/widgets/third-party/news-comment/waline.pug +3 -3
  22. package/layout/page.pug +2 -0
  23. package/package.json +1 -1
  24. package/plugins.yml +3 -3
  25. package/scripts/event/merge_config.js +7 -0
  26. package/source/css/_comments/comment.styl +1 -1
  27. package/source/css/_comments/valine.styl +1 -0
  28. package/source/css/_layout/console.styl +11 -0
  29. package/source/css/_layout/footer.styl +1 -1
  30. package/source/css/_page/index.styl +3 -0
  31. package/source/css/_page/recentcomment.styl +85 -0
  32. package/source/css/_page/says.styl +2 -11
package/_config.yml CHANGED
@@ -515,6 +515,21 @@ says:
515
515
  # Talk short text only shows the first n
516
516
  strip: 30
517
517
 
518
+ # 最近评论
519
+ # recent comments
520
+ # 前置要求:需配置最近评论页面和评论,否则显示为空
521
+ # Pre-requirements: recent comments page needs to be configured and commented, otherwise it will be displayed as empty
522
+ recent_comments:
523
+ enable: false
524
+ # 评论数
525
+ # Number of comments
526
+ limit: 50 # ⚠️waline 仅支持最大50条评论 / ⚠️waline only supports a maximum of 50 comments
527
+ # 缓存时间
528
+ # Cache time
529
+ cache: 0.2 # 1 = 1天 / 1 = 1 day
530
+ console: true # 控制台按钮 / console button
531
+ page: /recentcomments/ # 最近评论页面 / recent comments page
532
+
518
533
  # 留言板
519
534
  # message board
520
535
  # 前置要求:需配置留言板页面
@@ -525,6 +540,7 @@ envelope:
525
540
  speed: 20 # 播放速度
526
541
  hover: true # 鼠标悬停暂停
527
542
  loop: true # 循环播放
543
+ page: /message/ # 留言板页面 / message board page
528
544
 
529
545
  # -------------------------
530
546
  # meeting-api,用于界面中的音乐胶囊和音乐馆页,可自定义api,不会请勿动。
@@ -3,6 +3,7 @@ star: Behold, those who found delight in this piece also perused
3
3
  random: Random
4
4
  upload: 'datetime: '
5
5
  totalk: You don't need to delete blank lines, just type in your comments.
6
+ loading: Loading...
6
7
 
7
8
  theme:
8
9
  dark: Dark
@@ -109,10 +110,12 @@ console:
109
110
  switch_keyboard: Keyboard operation
110
111
  switch_music: Music switch
111
112
  archive_unit: Posts
113
+ recent_comment_more: Recent comments
112
114
  newest_comment:
113
115
  image: Image
114
116
  link: Link
115
117
  code: Code
118
+ emoji: Emoji
116
119
 
117
120
  sidebar:
118
121
  function: Function
package/languages/en.yml CHANGED
@@ -3,6 +3,7 @@ star: Behold, those who found delight in this piece also perused
3
3
  random: Random
4
4
  upload: 'datetime: '
5
5
  totalk: You don't need to delete blank lines, just type in your comments.
6
+ loading: Loading...
6
7
 
7
8
  theme:
8
9
  dark: Dark
@@ -109,10 +110,12 @@ console:
109
110
  switch_keyboard: Keyboard operation
110
111
  switch_music: Music switch
111
112
  archive_unit: Posts
113
+ recent_comment_more: Recent comments
112
114
  newest_comment:
113
115
  image: Image
114
116
  link: Link
115
117
  code: Code
118
+ emoji: Emoji
116
119
 
117
120
  sidebar:
118
121
  function: Function
@@ -3,6 +3,7 @@ star: 喜欢这篇的人也看了
3
3
  random: 随便逛逛
4
4
  upload: 发布时间:
5
5
  totalk: 无需删除空行,直接输入评论即可
6
+ loading: 加载中...
6
7
 
7
8
  # Language: 简体中文
8
9
  theme:
@@ -111,10 +112,12 @@ console:
111
112
  switch_keyboard: 键盘快捷键
112
113
  switch_music: 音乐开关
113
114
  archive_unit: 篇
115
+ recent_comment_more: 最近评论
114
116
  newest_comment:
115
117
  image: 图片
116
118
  link: 链接
117
119
  code: 代码
120
+ emoji: 表情
118
121
 
119
122
  sidebar:
120
123
  function: 功能
@@ -3,6 +3,7 @@ star: 喜歡這篇的人也看了
3
3
  random: 随便逛逛
4
4
  upload: 發佈時間:
5
5
  totalk: 無需刪除空行,直接輸入評論即可
6
+ loading: 加載中...
6
7
 
7
8
  # Language: 繁體中文 (台灣)
8
9
  theme:
@@ -111,10 +112,12 @@ console:
111
112
  switch_keyboard: 鍵盤快捷鍵
112
113
  switch_music: 音樂開關
113
114
  archive_unit: 篇
115
+ recent_comment_more: 最近評論
114
116
  newest_comment:
115
117
  image: 圖片
116
118
  link: 連結
117
119
  code: 代碼
120
+ emoji: 表情
118
121
 
119
122
  sidebar:
120
123
  function: 功能
@@ -8,7 +8,11 @@ div#console
8
8
  div.console-card#card-newest-comments(onclick="sco.hideConsole()")
9
9
  div.card-content
10
10
  div.author-content-item-tips= _p('console.comment_tip')
11
- div.author-content-item-title= _p('console.comment_title')
11
+ div.author-content-item-title
12
+ | #{_p('console.comment_title')}
13
+ if theme.recent_comments.enable && theme.recent_comments.console
14
+ a.recent-comment-more(href=url_for(theme.recent_comments.page) title=_p('console.recent_comment_more'))
15
+ i.solitude.st-right-btn-fill
12
16
  div.aside-list
13
17
 
14
18
  div.console-card-group-right
@@ -27,7 +27,7 @@ include ../head/pwa.pug
27
27
 
28
28
  script.
29
29
  console.log(
30
- "%c Program: Hexo %c Theme: Solitude %c Version: v1.10.6",
30
+ "%c Program: Hexo %c Theme: Solitude %c Version: v1.11.0",
31
31
  "border-radius:5px 0 0 5px;padding: 5px 10px;color:white;background:#ff3842;",
32
32
  "padding: 5px 10px;color:white;background:#3e9f50;",
33
33
  "padding: 5px 10px;color:white;background:#0084ff;border-radius:0 5px 5px 0",
@@ -0,0 +1,16 @@
1
+ - const { enable, limit, cache } = theme.recent_comments
2
+ - const {use, avatar} = theme.comment
3
+
4
+ include ../widgets/page/banner
5
+
6
+ if enable && use
7
+ #comments-page
8
+ case use[0]
9
+ when 'Twikoo'
10
+ include ../widgets/page/recentcomment/twikoo
11
+ when 'Valine'
12
+ include ../widgets/page/recentcomment/valine
13
+ when 'Waline'
14
+ include ../widgets/page/recentcomment/waline
15
+ when 'Artalk'
16
+ include ../widgets/page/recentcomment/artalk
@@ -1,7 +1,7 @@
1
1
  .author-content.author-content-item.single.sharePage(style=`background: url(${page.cover}) no-repeat center; background-size: cover;`)
2
2
  .card-content
3
- .author-content-item-tips= page.title
4
- span.author-content-item-title= page.desc
3
+ .author-content-item-tips= page.desc
4
+ span.author-content-item-title= page.title
5
5
  .content-bottom
6
6
  if page.leftend
7
7
  .tips= page.leftend
@@ -0,0 +1,45 @@
1
+ - const { server, site, option } = theme.artalk
2
+
3
+ script(pjax).
4
+ (async () => {
5
+ const emojiReg = /<img [^>]+ atk-emoticon="[^"]+">/g
6
+ if (typeof EasyDanmaku === "undefined") await utils.getScript('!{url_for(theme.cdn.envelope_js)}')
7
+ const envel = new EasyDanmaku({
8
+ page: '!{theme.envelope.page}',
9
+ el: '#barrage',
10
+ line: !{line},
11
+ speed: !{speed},
12
+ hover: !{hover},
13
+ loop: !{loop},
14
+ })
15
+ const data = utils.saveToLocal.get('enevlope')
16
+ if (data) {
17
+ envel.batchSend(data, true)
18
+ return
19
+ }
20
+
21
+ const searchParams = new URLSearchParams({'site_name': "!{site}", 'limit': '100'})
22
+ await fetch(`!{server}/api/v2/stats/latest_comments?${searchParams}`, {method: 'GET'}).then(async res => res.json())
23
+ .then(async data => {
24
+ let ls = []
25
+ for (const i of data.data) {
26
+ ls.push({
27
+ content: i.nick + ': ' + formatDanmaku(i.content),
28
+ avatar: '!{avatar}' + '/avatar/' + i.email_encrypted,
29
+ url: i.page_key + '#atk-comment-' + i.id,
30
+ })
31
+ }
32
+ envel.batchSend(ls, true)
33
+ utils.saveToLocal.set('enevlope', ls, .02)
34
+ }).catch(error => {
35
+ console.error("An error occurred while fetching comments: ", error)
36
+ })
37
+
38
+ function formatDanmaku(str) {
39
+ str = str.replace(emojiReg, '[!{__("console.newest_comment.emoji")}]')
40
+ str = str.replace(/!\[.*?\]\((.*?)\)/g, '[!{__("console.newest_comment.image")}]')
41
+ str = str.replace(/\[.*?\]\((.*?)\)/g, '[!{__("console.newest_comment.link")}]')
42
+ str = str.replace(/```.*?```/g, '[!{__("console.newest_comment.code")}]')
43
+ return str
44
+ }
45
+ })()
@@ -5,4 +5,8 @@ if use
5
5
  when "Valine"
6
6
  include ./valine
7
7
  when "Twikoo"
8
- include ./twikoo
8
+ include ./twikoo
9
+ when "Waline"
10
+ include ./waline
11
+ when "Artalk"
12
+ include ./artalk
@@ -2,38 +2,41 @@
2
2
 
3
3
  script(pjax).
4
4
  (async () => {
5
- if(typeof EasyDanmaku === "undefined") await utils.getScript('!{url_for(theme.cdn.envelope_js)}')
5
+ const emojiReg = /<img class="tk-owo-emotion" [^>]+>/g
6
+ if (typeof EasyDanmaku === "undefined") await utils.getScript('!{url_for(theme.cdn.envelope_js)}')
6
7
  const Danmaku = new EasyDanmaku({
7
- page: '/message/',
8
- el: '#barrage',
9
- line: !{line},
10
- speed: !{speed},
8
+ page: '!{theme.envelope.page}',
9
+ el: '#barrage',
10
+ line: !{line},
11
+ speed: !{speed},
11
12
  hover: !{hover},
12
13
  loop: !{loop},
13
14
  })
14
15
  const data = utils.saveToLocal.get('enevlope')
15
- if(data){
16
- Danmaku.batchSend(data,true)
16
+ if (data) {
17
+ Danmaku.batchSend(data, true)
17
18
  return
18
19
  }
19
20
  let ls = []
20
21
  fetch('!{envId}/', {
21
22
  method: "POST",
22
23
  body: JSON.stringify({
23
- "event": "GET_RECENT_COMMENTS",
24
- "includeReply": false,
25
- "pageSize": 100
24
+ "event": "GET_RECENT_COMMENTS",
25
+ "includeReply": false,
26
+ "pageSize": 100
26
27
  }),
27
- headers: { 'Content-Type': 'application/json' }
28
- }).then(res => res.json()).then(({ data }) => {
29
- data.forEach(i => {
30
- if (i.avatar == undefined) i.avatar = '!{avatar}/avatar/d615d5793929e8c7d70eab5f00f7f5f1?d=mp'
31
- ls.push({ avatar: i.avatar, content: i.nick + '' + formatDanmaku(i.comment), url: i.url + '#' + i.id })
32
- });
28
+ headers: {'Content-Type': 'application/json'}
29
+ }).then(res => res.json()).then(({data}) => {
30
+ for (const i of data) {
31
+ if (i.avatar === undefined) i.avatar = '!{avatar}/avatar/d615d5793929e8c7d70eab5f00f7f5f1?d=mp'
32
+ ls.push({avatar: i.avatar, content: i.nick + ': ' + formatDanmaku(i.comment), url: i.url + '#' + i.id})
33
+ }
33
34
  Danmaku.batchSend(ls, true);
34
35
  utils.saveToLocal.set('envelope', ls, 0.02)
35
36
  });
37
+
36
38
  function formatDanmaku(str) {
39
+ str = str.replace(emojiReg, '!{__("console.newest_comment.emoji")}')
37
40
  str = str.replace(/<\/*br>|[\s\uFEFF\xA0]+/g, '');
38
41
  str = str.replace(/<img.*?>/g, '[!{__("console.newest_comment.image")}]');
39
42
  str = str.replace(/<a.*?>.*?<\/a>/g, '[!{__("console.newest_comment.link")}]');
@@ -2,9 +2,10 @@
2
2
 
3
3
  script(pjax).
4
4
  (async () => {
5
+ const emojiReg = /:[a-z0-9_\u4e00-\u9fa5]+:/g
5
6
  if(typeof EasyDanmaku === "undefined") await utils.getScript('!{url_for(theme.cdn.envelope_js)}')
6
7
  const envel = new EasyDanmaku({
7
- page: '/message/',
8
+ page: '!{theme.envelope.page}',
8
9
  el: '#barrage',
9
10
  line: !{line},
10
11
  speed: !{speed},
@@ -35,9 +36,9 @@ script(pjax).
35
36
  const data = await res.json()
36
37
  const init = () =>
37
38
  data.results.map(item => ({
38
- content: item.comment,
39
+ content: item.nick + ': ' + formatDanmaku(item.comment),
39
40
  avatar: '!{avatar}/avatar/'+md5(item.mail),
40
- url: item.url,
41
+ url: item.url
41
42
  }))
42
43
  if (typeof md5 === "undefined") await utils.getScript('!{url_for(theme.cdn.blueimp_md5)}')
43
44
  envel.batchSend(init(),true)
@@ -45,4 +46,12 @@ script(pjax).
45
46
  } catch (error) {
46
47
  console.error("An error occurred while fetching comments: ", error)
47
48
  }
49
+
50
+ function formatDanmaku(str) {
51
+ str = str.replace(emojiReg, '[!{__("console.newest_comment.emoji")}]')
52
+ str = str.replace(/!\[.*?\]\((.*?)\)/g, '[!{__("console.newest_comment.image")}]')
53
+ str = str.replace(/\[.*?\]\((.*?)\)/g, '[!{__("console.newest_comment.link")}]')
54
+ str = str.replace(/```.*?```/g, '[!{__("console.newest_comment.code")}]')
55
+ return str
56
+ }
48
57
  })()
@@ -0,0 +1,42 @@
1
+ script(pjax).
2
+ (async () => {
3
+ const emojiReg = /<img [^>]+ class="wl-emoji">/g
4
+ if(typeof EasyDanmaku === "undefined") await utils.getScript('!{url_for(theme.cdn.envelope_js)}')
5
+ const envel = new EasyDanmaku({
6
+ page: '!{theme.envelope.page}',
7
+ el: '#barrage',
8
+ line: !{line},
9
+ speed: !{speed},
10
+ hover: !{hover},
11
+ loop: !{loop},
12
+ })
13
+ const data = utils.saveToLocal.get('enevlope')
14
+ if(data){
15
+ envel.batchSend(data,true)
16
+ return
17
+ }
18
+ await fetch('!{theme.waline.envId}/api/comment?type=recent&count=50', {method: 'GET'}).then(async res => res.json())
19
+ .then(async data => {
20
+ let ls = []
21
+ for (const i of data.data) {
22
+ ls.push({
23
+ content: i.nick + ': ' + formatContent(i.comment),
24
+ avatar: i.avatar,
25
+ url: i.url
26
+ })
27
+ }
28
+ envel.batchSend(ls,true)
29
+ utils.saveToLocal.set('enevlope',ls,.02)
30
+ }).catch(error => {
31
+ console.error("An error occurred while fetching comments: ", error)
32
+ })
33
+
34
+ function formatContent(content) {
35
+ content = content.replace(emojiReg, '[!{__("console.newest_comment.emoji")}]')
36
+ content = content.replace(/<img.*?>/g, '[!{__("console.newest_comment.image")}]');
37
+ content = content.replace(/<a.*?>.*?<\/a>/g, '[!{__("console.newest_comment.link")}]');
38
+ content = content.replace(/<pre.*?>.*?<\/pre>/g, '[!{__("console.newest_comment.code")}]');
39
+ content = content.replace(/<.*?>/g, '');
40
+ return content
41
+ }
42
+ })()
@@ -0,0 +1,78 @@
1
+ - const { server, site, option } = theme.artalk
2
+
3
+ script(pjax).
4
+ (async () => {
5
+ document.querySelector('#comments-page').textContent = `#{__("loading")}`
6
+ const emojiReg = /<img [^>]+ atk-emoticon="[^"]+">/g
7
+ let cache = utils.saveToLocal.get('artalk-recent-comments')
8
+ if (cache) {
9
+ setHtml(document.querySelector('#comments-page'), cache)
10
+ return
11
+ }
12
+ let ls = []
13
+ const searchParams = new URLSearchParams({'site_name': "!{site}", 'limit': '!{limit}'})
14
+ await fetch(`!{server}/api/v2/stats/latest_comments?${searchParams}`, {method: 'GET'}).then(async res => res.json())
15
+ .then(async data => {
16
+ for (const i of data.data) {
17
+ if (checkEmoji(i.content)) continue
18
+ let title = ''
19
+ if (i.page_key) {
20
+ await fetch(i.page_key).then(res => res.text()).then(html => {
21
+ const parser = new DOMParser()
22
+ const doc = parser.parseFromString(html, 'text/html')
23
+ title = doc.querySelector('title').innerText
24
+ }).catch(() => {
25
+ title = i.page_key
26
+ })
27
+ }
28
+ if (title.indexOf('|') > 0) {
29
+ title = title.split('|')[0]
30
+ }
31
+ ls.push({
32
+ title: title,
33
+ url: i.page_key + '#atk-comment-' + i.id,
34
+ nick: i.nick,
35
+ avatar: '!{avatar}' + '/avatar/' + i.email_encrypted,
36
+ time: i.date,
37
+ content: formatContent(i.content)
38
+ })
39
+ }
40
+ setHtml(document.querySelector('#comments-page'), ls)
41
+ utils.saveToLocal.set('artalk-recent-comments', ls, !{cache})
42
+ })
43
+
44
+ function setHtml(el, data) {
45
+ el.innerHTML = data.map(i => `
46
+ <div class="comment-card" title="${i.title}" onclick="pjax.loadUrl('${i.url}')">
47
+ <div class="comment-info">
48
+ <img src="${i.avatar}" class="nolazyload" alt="${i.nick}">
49
+ <div>
50
+ <span class="comment-user">${i.nick}</span>
51
+ </div>
52
+ <time class="comment-time" datetime="${i.time}"></time>
53
+ </div>
54
+ <div class="comment-content">${i.content}</div>
55
+ <div class="comment-title">
56
+ <i class="solitude st-chat-fill"></i>
57
+ ${i.title}</div>
58
+ </div>
59
+ `).join('')
60
+ if (typeof sco !== 'undefined') sco.changeTimeFormat(document.querySelectorAll('.comment-time'))
61
+ else {
62
+ document.addEventListener('pjax:complete', () => sco.changeTimeFormat(document.querySelectorAll('.comment-time')))
63
+ document.addEventListener('DOMContentLoaded', () => sco.changeTimeFormat(document.querySelectorAll('.comment-time')))
64
+ }
65
+ }
66
+
67
+ function checkEmoji(content) {
68
+ return emojiReg.test(content)
69
+ }
70
+
71
+ function formatContent(content) {
72
+ content = content.replace(emojiReg, '[!{__("console.newest_comment.emoji")}]')
73
+ content = content.replace(/!\[.*?\]\((.*?)\)/g, '[!{__("console.newest_comment.image")}]')
74
+ content = content.replace(/\[.*?\]\((.*?)\)/g, '[!{__("console.newest_comment.link")}]')
75
+ content = content.replace(/```.*?```/g, '[!{__("console.newest_comment.code")}]')
76
+ return content
77
+ }
78
+ })()
@@ -0,0 +1,83 @@
1
+ - const {envId} = theme.twikoo
2
+
3
+ script(pjax).
4
+ (async () => {
5
+ document.querySelector('#comments-page').textContent = `#{__("loading")}`
6
+ const emojiReg = /<img class="tk-owo-emotion" [^>]+>/g
7
+ let cache = utils.saveToLocal.get('twikoo-recent-comments')
8
+ if (cache) {
9
+ setHtml(document.querySelector('#comments-page'), cache)
10
+ return
11
+ }
12
+ let ls = []
13
+
14
+ await fetch('!{envId}', {
15
+ method: "POST",
16
+ body: JSON.stringify({
17
+ "event": "GET_RECENT_COMMENTS",
18
+ "includeReply": true,
19
+ "pageSize": !{limit}
20
+ }),
21
+ headers: {'Content-Type': 'application/json'}
22
+ }).then(res => res.json()).then(async ({data}) => {
23
+ for (const i of data) {
24
+ if (i.avatar === undefined) i.avatar = '!{avatar}/avatar/d615d5793929e8c7d70eab5f00f7f5f1?d=mp'
25
+ let title = ''
26
+ if (i.url) {
27
+ await fetch(i.url).then(res => res.text()).then(html => {
28
+ const parser = new DOMParser()
29
+ const doc = parser.parseFromString(html, 'text/html')
30
+ title = doc.querySelector('title').innerText
31
+ }).catch(() => {
32
+ title = i.url
33
+ })
34
+ }
35
+ if (title.indexOf('|') > 0) {
36
+ title = title.split('|')[0]
37
+ }
38
+ ls.push({
39
+ avatar: i.avatar,
40
+ nick: i.nick,
41
+ title: title,
42
+ content: i.comment,
43
+ url: i.url + '#' + i.id,
44
+ time: i.created
45
+ })
46
+ }
47
+ setHtml(document.querySelector('#comments-page'), ls)
48
+ utils.saveToLocal.set('twikoo-recent-comments', ls, !{cache})
49
+ });
50
+
51
+ function setHtml(el, data) {
52
+ el.innerHTML = data.map(i => `
53
+ <div class="comment-card" title="${i.title}" onclick="pjax.loadUrl('${i.url}')">
54
+ <div class="comment-info">
55
+ <img src="${i.avatar}" class="nolazyload" alt="${i.nick}">
56
+ <div>
57
+ <span class="comment-user">${i.nick}</span>
58
+ </div>
59
+ <time class="comment-time" datetime="${new Date(i.time)}"></time>
60
+ </div>
61
+ <div class="comment-content">${formatContent(i.content)}</div>
62
+ <div class="comment-title">
63
+ <i class="solitude st-chat-fill"></i>
64
+ ${i.title}</div>
65
+ </div>
66
+ `).join('')
67
+ if (typeof sco !== 'undefined') sco.changeTimeFormat(document.querySelectorAll('.comment-time'))
68
+ else {
69
+ document.addEventListener('pjax:complete', () => sco.changeTimeFormat(document.querySelectorAll('.comment-time')))
70
+ document.addEventListener('DOMContentLoaded', () => sco.changeTimeFormat(document.querySelectorAll('.comment-time')))
71
+ }
72
+ }
73
+
74
+ function formatContent(content) {
75
+ content = content.replace(emojiReg, '!{__("console.newest_comment.emoji")}')
76
+ content = content.replace(/<\/*br>|[\s\uFEFF\xA0]+/g, '');
77
+ content = content.replace(/<img.*?>/g, '[!{__("console.newest_comment.image")}]');
78
+ content = content.replace(/<a.*?>.*?<\/a>/g, '[!{__("console.newest_comment.link")}]');
79
+ content = content.replace(/<pre.*?>.*?<\/pre>/g, '[!{__("console.newest_comment.code")}]');
80
+ content = content.replace(/<.*?>/g, '');
81
+ return content
82
+ }
83
+ })()
@@ -0,0 +1,79 @@
1
+ - const { appId, appKey, serverURLs } = theme.valine
2
+
3
+ script(pjax).
4
+ (async () => {
5
+ document.querySelector('#comments-page').textContent = `#{__("loading")}`
6
+ const emojiReg = /:[a-z0-9_\u4e00-\u9fa5]+:/g
7
+ let cache = utils.saveToLocal.get('valine-recent-comments')
8
+ if (cache) {
9
+ setHtml(document.querySelector('#comments-page'), cache)
10
+ return
11
+ }
12
+ let ls = []
13
+ if (typeof md5 === "undefined") await utils.getScript('!{url_for(theme.cdn.blueimp_md5)}')
14
+ await fetch('!{serverURLs}/1.1/classes/Comment?limit=8&order=-createdAt', {
15
+ method: "GET",
16
+ headers: {
17
+ "X-LC-Id": '!{appId}',
18
+ "X-LC-Key": '!{appKey}',
19
+ "Content-Type": "application/json"
20
+ }
21
+ }).then(async res => res.json()).then(async results => {
22
+ for (const i of results.results) {
23
+ let title = ''
24
+ if (i.url) {
25
+ await fetch(i.url).then(res => res.text()).then(html => {
26
+ const parser = new DOMParser()
27
+ const doc = parser.parseFromString(html, 'text/html')
28
+ title = doc.querySelector('title').innerText
29
+ }).catch(() => {
30
+ title = i.url
31
+ })
32
+ }
33
+ if (title.indexOf('|') > 0) {
34
+ title = title.split('|')[0]
35
+ }
36
+ ls.push({
37
+ title: title,
38
+ url: i.url,
39
+ nick: i.nick,
40
+ avatar: '!{avatar}' + '/avatar/' + md5(i.mail.trim().toLowerCase()),
41
+ time: i.createdAt,
42
+ content: formatContent(i.comment)
43
+ })
44
+ }
45
+ setHtml(document.querySelector('#comments-page'), ls)
46
+ utils.saveToLocal.set('valine-recent-comments', ls, !{cache})
47
+ })
48
+
49
+ function setHtml(el, data) {
50
+ el.innerHTML = data.map(i => `
51
+ <div class="comment-card" title="${i.title}" onclick="pjax.loadUrl('${i.url}')">
52
+ <div class="comment-info">
53
+ <img src="${i.avatar}" class="nolazyload" alt="${i.nick}">
54
+ <div>
55
+ <span class="comment-user">${i.nick}</span>
56
+ </div>
57
+ <time class="comment-time" datetime="${i.time}"></time>
58
+ </div>
59
+ <div class="comment-content">${i.content}</div>
60
+ <div class="comment-title">
61
+ <i class="solitude st-chat-fill"></i>
62
+ ${i.title}</div>
63
+ </div>
64
+ `).join('')
65
+ if (typeof sco !== 'undefined') sco.changeTimeFormat(document.querySelectorAll('.comment-time'))
66
+ else {
67
+ document.addEventListener('pjax:complete', () => sco.changeTimeFormat(document.querySelectorAll('.comment-time')))
68
+ document.addEventListener('DOMContentLoaded', () => sco.changeTimeFormat(document.querySelectorAll('.comment-time')))
69
+ }
70
+ }
71
+
72
+ function formatContent(content) {
73
+ content = content.replace(emojiReg, '[!{__("console.newest_comment.emoji")}]')
74
+ content = content.replace(/!\[.*?\]\((.*?)\)/g, '[!{__("console.newest_comment.image")}]')
75
+ content = content.replace(/\[.*?\]\((.*?)\)/g, '[!{__("console.newest_comment.link")}]')
76
+ content = content.replace(/```.*?```/g, '[!{__("console.newest_comment.code")}]')
77
+ return content
78
+ }
79
+ })()
@@ -0,0 +1,72 @@
1
+ script(pjax).
2
+ (async () => {
3
+ document.querySelector('#comments-page').textContent = `#{__("loading")}`
4
+ const emojiReg = /<img [^>]+ class="wl-emoji">/g
5
+ let cache = utils.saveToLocal.get('waline-recent-comments')
6
+ if (cache) {
7
+ setHtml(document.querySelector('#comments-page'), cache)
8
+ return
9
+ }
10
+ let ls = []
11
+ await fetch('!{theme.waline.envId}/api/comment?type=recent&count=!{limit}', {method: 'GET'}).then(async res => res.json())
12
+ .then(async data => {
13
+ console.log(data)
14
+ for (const i of data.data) {
15
+ let title = ''
16
+ if (i.url) {
17
+ await fetch(i.url).then(res => res.text()).then(html => {
18
+ const parser = new DOMParser()
19
+ const doc = parser.parseFromString(html, 'text/html')
20
+ title = doc.querySelector('title').innerText
21
+ }).catch(() => {
22
+ title = i.url
23
+ })
24
+ }
25
+ if (title.indexOf('|') > 0) {
26
+ title = title.split('|')[0]
27
+ }
28
+ ls.push({
29
+ title: title,
30
+ url: i.url,
31
+ nick: i.nick,
32
+ avatar: i.avatar,
33
+ time: new Date(i.time),
34
+ content: formatContent(i.comment)
35
+ })
36
+ }
37
+ setHtml(document.querySelector('#comments-page'), ls)
38
+ utils.saveToLocal.set('waline-recent-comments', ls, !{cache})
39
+ })
40
+
41
+ function setHtml(el, data) {
42
+ el.innerHTML = data.map(i => `
43
+ <div class="comment-card" title="${i.title}" onclick="pjax.loadUrl('${i.url}')">
44
+ <div class="comment-info">
45
+ <img src="${i.avatar}" class="nolazyload" alt="${i.nick}">
46
+ <div>
47
+ <span class="comment-user">${i.nick}</span>
48
+ </div>
49
+ <time class="comment-time" datetime="${i.time}"></time>
50
+ </div>
51
+ <div class="comment-content">${i.content}</div>
52
+ <div class="comment-title">
53
+ <i class="solitude st-chat-fill"></i>
54
+ ${i.title}</div>
55
+ </div>
56
+ `).join('')
57
+ if (typeof sco !== 'undefined') sco.changeTimeFormat(document.querySelectorAll('.comment-time'))
58
+ else {
59
+ document.addEventListener('pjax:complete', () => sco.changeTimeFormat(document.querySelectorAll('.comment-time')))
60
+ document.addEventListener('DOMContentLoaded', () => sco.changeTimeFormat(document.querySelectorAll('.comment-time')))
61
+ }
62
+ }
63
+
64
+ function formatContent(content) {
65
+ content = content.replace(emojiReg, '[!{__("console.newest_comment.emoji")}]')
66
+ content = content.replace(/<img.*?>/g, '[!{__("console.newest_comment.image")}]');
67
+ content = content.replace(/<a.*?>.*?<\/a>/g, '[!{__("console.newest_comment.link")}]');
68
+ content = content.replace(/<pre.*?>.*?<\/pre>/g, '[!{__("console.newest_comment.code")}]');
69
+ content = content.replace(/<.*?>/g, '');
70
+ return content
71
+ }
72
+ })()
@@ -41,7 +41,7 @@ script.
41
41
  const artalkWrap = document.getElementById('artalk-wrap')
42
42
  if (!(artalkWrap && artalkWrap.children.length)) return
43
43
  const isDark = theme === 'dark'
44
- artalkItem.setDarkMode(!isDark)
44
+ artalkItem.setDarkMode(isDark)
45
45
  }
46
46
  utils.addGlobalFn('themeChange', artalkChangeMode, 'artalk')
47
47
  if ('!{use[0]}' === 'Artalk' || !{lazyload}) {
@@ -1,5 +1,6 @@
1
1
  script.
2
2
  window.addEventListener('load', () => {
3
+ const emojiReg = /:[a-z0-9_\u4e00-\u9fa5]+:/g
3
4
  const changeContent = (content) => {
4
5
  if (content === '') return content;
5
6
 
@@ -38,31 +39,32 @@ script.
38
39
  },
39
40
  }
40
41
  if (typeof md5 === "undefined") await utils.getScript('!{url_for(theme.cdn.blueimp_md5)}')
41
- await fetch('!{theme.valine.serverURLs}/1.1/classes/Comment?limit=8&order=-createdAt', settings).then(async res => {
42
- const result = await res.json()
43
- window.res = result
44
- const valineArray = result.results.map(e => {
45
- return {
46
- 'content': changeContent(e.comment),
47
- 'avatar': '!{theme.comment.avatar}' + '/avatar/' + md5(e.mail.toLowerCase()),
48
- 'nick': e.nick,
49
- 'url': e.url + '#' + e.objectId,
50
- 'date': e.updatedAt || e.createdAt
42
+ await fetch('!{theme.valine.serverURLs}/1.1/classes/Comment?limit=8&order=-createdAt', settings).then(res => res.json())
43
+ .then(async result => {
44
+ let ls = []
45
+ for (const i of result.results.slice(0, 6)) {
46
+ if (emojiReg.test(i.comment)) continue
47
+ ls.push({
48
+ content: changeContent(i.comment),
49
+ avatar: '!{theme.comment.avatar}' + '/avatar/' + md5(i.mail.toLowerCase()),
50
+ nick: i.nick,
51
+ url: i.url,
52
+ date: i.updatedAt || i.createdAt
53
+ })
51
54
  }
55
+ utils.saveToLocal.set('valine-newest-comment', ls, !{theme.comment.newest_comment.storage})
56
+ generateHtml(ls)
57
+ }).catch(error => {
58
+ console.error(error);
59
+ $asideList.textContent = "!{_p('newest_comment.error')}"
52
60
  })
53
- utils.saveToLocal.set('valine-newest-comment', valineArray, !{theme.comment.newest_comment.storage})
54
- generateHtml(valineArray)
55
- }).catch(error => {
56
- console.error(error);
57
- $asideList.textContent = "!{_p('newest_comment.error')}"
58
- })
59
61
  }
60
62
 
61
63
  const generateHtml = array => {
62
64
  const $dom = document.querySelector('#card-newest-comments .aside-list')
63
65
  $dom.innerHTML = array.length ? array.map(item => `
64
66
  <div class='aside-list-item'>
65
- <div onclick='pjax.loadUrl("${item.url}")' class='thumbnail'>
67
+ <div onclick='pjax.loadUrl(\"${item.url}\")' class='thumbnail'>
66
68
  <img src='${item.avatar}' alt='${item.nick}'>
67
69
  <div class='name'><span>${item.nick}</span></div>
68
70
  </div>
@@ -29,7 +29,7 @@ script.
29
29
  }
30
30
 
31
31
  const getComment = async () => {
32
- await fetch('!{theme.waline.envId}/api/comment?type=recent&count=8', {method: 'GET'}).then(async res => {
32
+ await fetch('!{theme.waline.envId}/api/comment?type=recent&count=6', {method: 'GET'}).then(async res => {
33
33
  const result = await res.json()
34
34
  const walineArray = result.data.map(e => {
35
35
  return {
@@ -37,9 +37,9 @@ script.
37
37
  'avatar': e.avatar,
38
38
  'nick': e.nick,
39
39
  'url': e.url + '#' + e.objectId,
40
- 'date': e.time || e.insertedAt
40
+ 'date': new Date(e.time || e.insertedAt)
41
41
  }
42
- }).slice(0, 6)
42
+ })
43
43
  utils.saveToLocal.set('waline-newest-comment', walineArray, !{theme.comment.newest_comment.storage})
44
44
  generateHtml(walineArray)
45
45
  }).catch(error => {
package/layout/page.pug CHANGED
@@ -22,6 +22,8 @@ block content
22
22
  include includes/page/music
23
23
  when 'message'
24
24
  !=partial('includes/page/message', {}, {cache: true})
25
+ when 'recentcomment'
26
+ !=partial('includes/page/recentcomment', {}, {cache: true})
25
27
  when 'banner'
26
28
  include includes/widgets/page/banner
27
29
  if page.container
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hexo-theme-solitude",
3
- "version": "1.10.6",
3
+ "version": "1.11.0",
4
4
  "description": "A beautiful, powerful, and efficient Hexo theme developed by EverFu.",
5
5
  "main": "package.json",
6
6
  "scripts": {
package/plugins.yml CHANGED
@@ -5,7 +5,7 @@ algolia_search:
5
5
  instantsearch:
6
6
  name: instantsearch.js
7
7
  file: dist/instantsearch.production.min.js
8
- version: 4.67.0
8
+ version: 4.68.1
9
9
  pjax:
10
10
  name: pjax
11
11
  file: pjax.min.js
@@ -31,11 +31,11 @@ valine:
31
31
  artalk_css:
32
32
  name: artalk
33
33
  file: dist/Artalk.css
34
- version: 2.8.5
34
+ version: 2.8.6
35
35
  artalk_js:
36
36
  name: artalk
37
37
  file: dist/Artalk.js
38
- version: 2.8.5
38
+ version: 2.8.6
39
39
  katex:
40
40
  name: katex
41
41
  file: dist/katex.min.css
@@ -200,12 +200,19 @@ hexo.extend.filter.register('before_generate', () => {
200
200
  style: 1,
201
201
  strip: 30
202
202
  },
203
+ recent_comments: {
204
+ enable: false,
205
+ limit: 50,
206
+ console: false,
207
+ page: '/recentcomments/'
208
+ },
203
209
  envelope: {
204
210
  enable: false,
205
211
  line: 10,
206
212
  speed: 20,
207
213
  hover: true,
208
214
  loop: true,
215
+ page: '/message/'
209
216
  },
210
217
  meting_api: "https://meting.qjqq.cn/?server=:server&type=:type&id=:id&auth=:auth&r=:r",
211
218
  music: {
@@ -154,7 +154,7 @@ div#post-comment
154
154
  border var(--style-border-always)
155
155
  border-radius 10px
156
156
  z-index 9999
157
- width 142px
157
+ max-width 142px
158
158
  display none
159
159
  transform translate(0, -105%)
160
160
  overflow hidden
@@ -46,6 +46,7 @@
46
46
  padding 0
47
47
  overflow: inherit;
48
48
  flex-direction column-reverse
49
+ margin-bottom 0
49
50
 
50
51
  .vheader
51
52
  display flex
@@ -17,6 +17,15 @@
17
17
  &.show .close-btn i
18
18
  transform rotate(0)
19
19
 
20
+ if hexo-config('recent_comments.enable') && hexo-config('recent_comments.console')
21
+ .recent-comment-more
22
+ margin-left auto
23
+ display flex
24
+ align-items center
25
+
26
+ &:hover
27
+ color var(--efu-main)
28
+
20
29
  .console-card-group
21
30
  display flex
22
31
  justify-content space-between
@@ -104,6 +113,8 @@
104
113
  font-size 36px
105
114
  font-weight 700
106
115
  line-height 1
116
+ display flex
117
+ align-items center
107
118
 
108
119
  .aside-list-item
109
120
  .thumbnail
@@ -135,7 +135,7 @@
135
135
  .footer-title-group
136
136
  display flex
137
137
  align-items center
138
- margin 1rem 0 .7rem 8px
138
+ margin .5rem 0 .7rem 8px
139
139
 
140
140
  a
141
141
  margin-left 8px
@@ -6,6 +6,9 @@
6
6
 
7
7
  @import "error.styl"
8
8
 
9
+ if hexo-config('recent_comments.enable')
10
+ @import "recentcomment.styl"
11
+
9
12
  if hexo-config('says.enable')
10
13
  @import "says.styl"
11
14
 
@@ -0,0 +1,85 @@
1
+ div#comments-page
2
+ display flex
3
+ flex-wrap wrap
4
+ gap 12px
5
+ min-height 100px
6
+ width 100%
7
+ margin-top .5rem
8
+
9
+ .comment-card
10
+ position relative
11
+ width calc(100% / 3 - 8px)
12
+ background var(--efu-card-bg)
13
+ border-radius 12px
14
+ border var(--style-border-always)
15
+ padding 14px
16
+ cursor pointer
17
+ transition .3s
18
+ overflow hidden
19
+ gap 8px
20
+ display flex
21
+ flex-direction column
22
+
23
+ +maxWidth900()
24
+ width calc(100% / 2 - 6px)
25
+
26
+ +maxWidth768()
27
+ width 100%
28
+
29
+ &:hover
30
+ border-color var(--style-border-hover-always)
31
+
32
+ .comment-info
33
+ display flex
34
+ align-items center
35
+ gap 8px
36
+ border-bottom var(--style-border-always)
37
+ padding-bottom 8px
38
+
39
+ div
40
+ display flex
41
+ flex-direction column
42
+ line-height 1.5
43
+
44
+ .comment-article, .comment-content
45
+ transition .3s
46
+ overflow hidden
47
+ text-overflow ellipsis
48
+ display -webkit-box
49
+ -webkit-box-orient vertical
50
+ -webkit-line-clamp 2
51
+ line-height 1.7
52
+ font-size 14px
53
+
54
+ .comment-title
55
+ font-size 12px
56
+ color var(--efu-secondtext)
57
+ margin-top auto
58
+ transition .3s
59
+ overflow hidden
60
+ text-overflow ellipsis
61
+ display -webkit-box
62
+ -webkit-box-orient vertical
63
+ -webkit-line-clamp 1
64
+ line-height 1
65
+ opacity .6
66
+ padding-top 8px
67
+
68
+ i
69
+ font-size 12px
70
+ line-height 12px
71
+
72
+ #comments-page .comment-info img
73
+ width 30px
74
+ height 30px
75
+ object-fit cover
76
+ border-radius 30px
77
+ margin 0
78
+
79
+ span.comment-user
80
+ font-weight 700
81
+
82
+ time.comment-time
83
+ font-size 12px
84
+ color var(--efu-secondtext)
85
+ margin-left auto
@@ -13,22 +13,13 @@ if hexo-config('says.home_mini')
13
13
  user-select none
14
14
  align-items center
15
15
  padding .5rem 1rem
16
+ animation slide-in .6s 0s backwards
17
+ margin-bottom .5rem
16
18
 
17
19
  &.more-page
18
20
  margin-bottom 0
19
21
 
20
- if hexo-config('hometop.enable')
21
- margin-bottom 1rem
22
-
23
- +maxWidth1300()
24
- if hexo-config('hometop.enable')
25
- margin-bottom 1rem
26
- animation slide-in .6s 0s backwards
27
-
28
22
  +minWidth1300()
29
- if hexo-config('hometop.enable')
30
- margin-bottom .5rem
31
- animation slide-in .6s 0s backwards
32
23
  &:hover
33
24
  border var(--style-border-hover)
34
25
  box-shadow var(--efu-shadow-main)