hexo-theme-solitude 1.10.5 → 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 (60) hide show
  1. package/README.md +1 -1
  2. package/_config.yml +16 -0
  3. package/languages/default.yml +3 -0
  4. package/languages/en.yml +3 -0
  5. package/languages/zh-CN.yml +3 -0
  6. package/languages/zh-TW.yml +3 -0
  7. package/layout/includes/console.pug +5 -1
  8. package/layout/includes/inject/head.pug +1 -1
  9. package/layout/includes/page/recentcomment.pug +16 -0
  10. package/layout/includes/widgets/home/hometop.pug +0 -1
  11. package/layout/includes/widgets/home/topGroup.pug +9 -8
  12. package/layout/includes/widgets/page/banner.pug +2 -2
  13. package/layout/includes/widgets/page/message/artalk.pug +45 -0
  14. package/layout/includes/widgets/page/message/js.pug +5 -1
  15. package/layout/includes/widgets/page/message/twikoo.pug +19 -16
  16. package/layout/includes/widgets/page/message/valine.pug +12 -3
  17. package/layout/includes/widgets/page/message/waline.pug +42 -0
  18. package/layout/includes/widgets/page/recentcomment/artalk.pug +78 -0
  19. package/layout/includes/widgets/page/recentcomment/twikoo.pug +83 -0
  20. package/layout/includes/widgets/page/recentcomment/valine.pug +79 -0
  21. package/layout/includes/widgets/page/recentcomment/waline.pug +72 -0
  22. package/layout/includes/widgets/third-party/comments/artalk.pug +1 -1
  23. package/layout/includes/widgets/third-party/news-comment/artalk.pug +1 -1
  24. package/layout/includes/widgets/third-party/news-comment/twikoo.pug +1 -1
  25. package/layout/includes/widgets/third-party/news-comment/valine.pug +19 -17
  26. package/layout/includes/widgets/third-party/news-comment/waline.pug +2 -2
  27. package/layout/page.pug +2 -0
  28. package/package.json +1 -1
  29. package/plugins.yml +3 -3
  30. package/scripts/event/merge_config.js +7 -0
  31. package/source/css/_comments/comment.styl +1 -1
  32. package/source/css/_comments/valine.styl +1 -0
  33. package/source/css/_global/index.styl +27 -23
  34. package/source/css/_layout/article-container.styl +1 -1
  35. package/source/css/_layout/aside.styl +1 -0
  36. package/source/css/_layout/console.styl +13 -0
  37. package/source/css/_layout/footer.styl +1 -1
  38. package/source/css/_layout/header.styl +0 -27
  39. package/source/css/_layout/rightmenu.styl +1 -1
  40. package/source/css/_page/_about/about.styl +2 -1
  41. package/source/css/_page/_about/buff.styl +1 -1
  42. package/source/css/_page/_about/contentinfo.styl +2 -2
  43. package/source/css/_page/_about/maxim.styl +1 -1
  44. package/source/css/_page/_about/myphoto.styl +1 -1
  45. package/source/css/_page/_about/oneself.styl +2 -2
  46. package/source/css/_page/_about/personalities.styl +1 -1
  47. package/source/css/_page/_about/skills.styl +1 -1
  48. package/source/css/_page/_about/statistic.styl +1 -1
  49. package/source/css/_page/_home/home-top.styl +17 -96
  50. package/source/css/_page/_home/home.styl +1 -1
  51. package/source/css/_page/index.styl +3 -0
  52. package/source/css/_page/links.styl +0 -3
  53. package/source/css/_page/other.styl +127 -115
  54. package/source/css/_page/recentcomment.styl +85 -0
  55. package/source/css/_page/says.styl +5 -14
  56. package/source/css/_tags/gallery.styl +5 -3
  57. package/source/js/main.js +2 -22
  58. package/source/js/search/algolia.js +11 -0
  59. package/source/js/search/local.js +11 -0
  60. package/layout/includes/widgets/home/categoryGroup.pug +0 -12
package/README.md CHANGED
@@ -62,7 +62,7 @@
62
62
  - [x] 弹幕留言页
63
63
  - [ ] 首页顶部新样式
64
64
 
65
- > 如有問題請提 [issue](https://github.com/valor-x/hexo-theme-solitude/issues)
65
+ > 如有问题请提 [issue](https://github.com/valor-x/hexo-theme-solitude/issues)
66
66
 
67
67
  ## 应用
68
68
 
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.5",
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
@@ -3,6 +3,5 @@
3
3
  #bannerGroup
4
4
  #banners
5
5
  include ./banner.pug
6
- include ./categoryGroup.pug
7
6
  .topGroup
8
7
  include ./topGroup.pug
@@ -1,12 +1,13 @@
1
1
  - var filteredPosts = site.posts.data.filter(item => item.recommend === true).slice(0,6)
2
- each post in filteredPosts
3
- .recent-post-item
4
- .post_cover
5
- a(href=url_for(post.path), title=post.title)
6
- span.recent-post-top-text= _p('home.recommend')
7
- img.post_bg(alt=post.title, src=post.cover)
8
- .recent-post-info
9
- a.article-title(href=url_for(post.path), title=post.title)= post.title
2
+ .recent-post-group
3
+ each post in filteredPosts
4
+ .recent-post-item
5
+ .post_cover
6
+ a(href=url_for(post.path), title=post.title)
7
+ span.recent-post-top-text= _p('home.recommend')
8
+ img.post_bg(alt=post.title, src=post.cover)
9
+ .recent-post-info
10
+ a.article-title(href=url_for(post.path), title=post.title)= post.title
10
11
 
11
12
  mixin todayCardContent
12
13
  .todayCard-info
@@ -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
+ })()