hexo-theme-stellar 1.29.0 → 1.30.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 (48) hide show
  1. package/_config.yml +29 -9
  2. package/_data/chat_users.yml +0 -0
  3. package/_data/widgets.yml +7 -0
  4. package/languages/zh-TW.yml +2 -2
  5. package/layout/_partial/head.ejs +2 -1
  6. package/layout/_partial/main/navbar/nav_tabs_blog.ejs +10 -10
  7. package/layout/_partial/scripts/defines.ejs +3 -0
  8. package/layout/_partial/scripts/services.ejs +91 -0
  9. package/layout/_partial/scripts/theme.ejs +5 -0
  10. package/layout/_partial/scripts/utils.ejs +67 -7
  11. package/layout/_partial/scripts.ejs +1 -1
  12. package/layout/_plugins/mermaid.ejs +1 -1
  13. package/layout/_plugins/scrollreveal.ejs +1 -0
  14. package/layout/_plugins/search/algolia_search.ejs +11 -12
  15. package/layout/layout.ejs +1 -1
  16. package/package.json +1 -1
  17. package/scripts/events/lib/config.js +3 -0
  18. package/scripts/events/lib/doc_tree.js +1 -6
  19. package/scripts/filters/index.js +26 -0
  20. package/scripts/generators/notebooks.js +1 -1
  21. package/scripts/generators/search.js +21 -2
  22. package/scripts/helpers/dynamic_color.js +138 -0
  23. package/scripts/tags/index.js +1 -0
  24. package/scripts/tags/lib/box.js +1 -1
  25. package/scripts/tags/lib/chat.js +515 -0
  26. package/scripts/tags/lib/folders.js +1 -1
  27. package/scripts/tags/lib/folding.js +2 -2
  28. package/scripts/tags/lib/sites.js +1 -1
  29. package/scripts/tags/lib/video.js +7 -2
  30. package/source/css/_components/tag-plugins/chat.styl +621 -0
  31. package/source/css/_components/tag-plugins/friends.styl +10 -0
  32. package/source/css/_components/tag-plugins/sites.styl +12 -0
  33. package/source/css/_components/tag-plugins/tabs.styl +5 -2
  34. package/source/css/_custom.styl +1 -0
  35. package/source/css/_defines/func.styl +7 -6
  36. package/source/css/_defines/theme.styl +38 -0
  37. package/source/css/_plugins/katex.styl +0 -1
  38. package/source/js/plugins/download-file.js +198 -0
  39. package/source/js/plugins/video.js +65 -0
  40. package/source/js/plugins/voice.js +438 -0
  41. package/source/js/search/algolia-search.js +63 -61
  42. package/source/js/services/artalk_latest_comment.js +33 -0
  43. package/source/js/services/friends.js +4 -0
  44. package/source/js/services/giscus_latest_comment.js +36 -0
  45. package/source/js/services/memos.js +91 -69
  46. package/source/js/services/sites.js +4 -0
  47. package/source/js/services/twikoo_latest_comment.js +47 -0
  48. package/source/js/services/waline_latest_comment.js +32 -0
@@ -9,6 +9,7 @@
9
9
  width: 100%
10
10
  display: flex
11
11
  flex-direction: column
12
+ position: relative
12
13
  >img
13
14
  object-fit: cover
14
15
  aspect-ratio: 1.5
@@ -18,6 +19,7 @@
18
19
  .info
19
20
  margin-top: 0.5rem
20
21
  line-height: 1.2
22
+ position: relative
21
23
  >img
22
24
  width: 28px
23
25
  height: @width
@@ -46,6 +48,16 @@
46
48
  overflow: hidden
47
49
  -webkit-line-clamp: 1
48
50
 
51
+ .label
52
+ position: absolute
53
+ color: initial
54
+ font-weight: 600
55
+ top: 1px
56
+ right: 0
57
+ font-size: 10px
58
+ padding: 2px 4px
59
+ border-radius: 16px
60
+
49
61
  // transform
50
62
  .sites-wrap .site-card .card-link
51
63
  >img
@@ -76,10 +76,13 @@
76
76
  text-align: justify
77
77
  margin-top: .5rem
78
78
  .tab-pane
79
+ display: block
79
80
  &:not(.active)
80
- display: none
81
+ visibility: hidden
82
+ height: 0
81
83
  &.active
82
- display: block
84
+ visibility: visible
85
+ height: auto
83
86
  .tab-content:has(.grid-box)
84
87
  width: 100%
85
88
 
@@ -2,6 +2,7 @@
2
2
 
3
3
  // 通用主题色
4
4
  $color-theme = convert(hexo-config('style.color.theme'))
5
+ $color-theme-opa = hsla(hue($color-theme), saturation($color-theme), lightness($color-theme), 0.3)
5
6
  $color-accent = convert(hexo-config('style.color.accent'))
6
7
  $color-link = convert(hexo-config('style.color.link'))
7
8
  $color-hover = convert(hexo-config('style.color.hover'))
@@ -14,11 +14,11 @@ trans1($op, $time = 0.2s)
14
14
  -o-transition: $op $time ease-out
15
15
 
16
16
  // 为2个属性设置动画
17
- trans2($op1, $op2)
18
- transition: $op1 0.2s ease-out, $op2 0.2s ease-out
19
- -moz-transition: $op1 0.2s ease-out, $op2 0.2s ease-out
20
- -webkit-transition: $op1 0.2s ease-out, $op2 0.2s ease-out
21
- -o-transition: $op1 0.2s ease-out, $op2 0.2s ease-out
17
+ trans2($op1, $op2, $time = 0.2s)
18
+ transition: $op1 $time ease-out, $op2 $time ease-out
19
+ -moz-transition: $op1 $time ease-out, $op2 $time ease-out
20
+ -webkit-transition: $op1 $time ease-out, $op2 $time ease-out
21
+ -o-transition: $op1 $time ease-out, $op2 $time ease-out
22
22
 
23
23
  trans2pro($op1, $t1, $op2, $t2)
24
24
  transition: $op1 $t1 ease-out, $op2 $t2 ease-out
@@ -78,7 +78,8 @@ scrollbar-codeblock($height = 4px)
78
78
  &::-webkit-scrollbar
79
79
  height: $height
80
80
  width: $height
81
- &::-webkit-scrollbar-track-piece
81
+ &::-webkit-scrollbar-track-piece,
82
+ &::-webkit-scrollbar-corner
82
83
  background: transparent
83
84
  &::-webkit-scrollbar-thumb
84
85
  background: transparent
@@ -23,6 +23,7 @@ _dark_text()
23
23
  --text-p1: hsl($color-text-h, $color-text-s, $color-text-l)
24
24
  --text-p2: hsl($color-text-h, $color-text-s, $color-text-l / 0.5 * 0.75)
25
25
  --text-p3: hsl($color-text-h, $color-text-s, $color-text-l / 0.5 * 1.25)
26
+ --text-p3-opa: hsla($color-text-h, $color-text-s, $color-text-l / 0.5 * 1.25, 0.3)
26
27
  --text-p4: hsl($color-text-h, $color-text-s, $color-text-l / 0.5 * 1.5)
27
28
  --text-meta: hsl($color-text-h, $color-text-s, $color-text-l / 0.5 * 2)
28
29
  --text-code: hsl($color-code-h, $color-code-s, $color-code-l)
@@ -32,6 +33,7 @@ _light_text()
32
33
  --text-p1: hsl($color-text-h, $color-text-s, 100 - $color-text-l / 0.5 * 0.5)
33
34
  --text-p2: hsl($color-text-h, $color-text-s, 100 - $color-text-l / 0.5 * 0.75)
34
35
  --text-p3: hsl($color-text-h, $color-text-s, 100 - $color-text-l / 0.5 * 1.2)
36
+ --text-p3-opa: hsla($color-text-h, $color-text-s, 100 - $color-text-l / 0.5 * 1.2, 0.3)
35
37
  --text-p4: hsl($color-text-h, $color-text-s, 100 - $color-text-l / 0.5 * 1.4)
36
38
  --text-meta: hsl($color-text-h, $color-text-s, 100 - $color-text-l / 0.5 * 1.75)
37
39
  --text-code: hsl($color-code-h, $color-code-s, (100 - $color-code-l) * 1.2)
@@ -39,6 +41,8 @@ _light_text()
39
41
  _common_root()
40
42
  :root
41
43
  --theme-link: $color-link
44
+ --theme-color: $color-theme
45
+ --theme-color-opa: $color-theme-opa
42
46
 
43
47
  _light_root()
44
48
  --site-bg: hsl($color-background-h, $color-background-s, $color-background-l)
@@ -53,6 +57,18 @@ _light_root()
53
57
  --alpha60: rgba(white, 0.6)
54
58
  --alpha75: rgba(white, 0.75)
55
59
  --alpha100: white
60
+ // chat 标签
61
+ --chat-bg: #f1f2f5
62
+ --chat-block: #ffffff
63
+ --chat-border: #f2f2f2
64
+ --chat-qq-right-bg: #0099FF
65
+ --chat-qq-right-text: #ffffff
66
+ --chat-wechat-news-num: #d8dadf
67
+ --chat-video-button: #ffffffE6
68
+ --chat-wechat-right-bg: #91ED61
69
+ --chat-quote-blink-color: #185c6d1a
70
+ --chat-wechat-quote-color: #808080
71
+ --chat-wechat-quote-bg: #8080801a
56
72
  _dark_text()
57
73
 
58
74
  _dark_root()
@@ -68,6 +84,18 @@ _dark_root()
68
84
  --alpha60: rgba(black, 0.6)
69
85
  --alpha75: rgba(black, 0.75)
70
86
  --alpha100: black
87
+ // chat 标签
88
+ --chat-bg: #1f2224 // #111111
89
+ --chat-block: #25282a // #191919
90
+ --chat-border: #303437 // #222222
91
+ --chat-qq-right-bg: #0099ff80
92
+ --chat-qq-right-text: #ffffff99
93
+ --chat-wechat-news-num: #25282a
94
+ --chat-video-button: #25282ad9 // #191919E6
95
+ --chat-wechat-right-bg: hsl(hue($c-green), 25, 25)
96
+ --chat-quote-blink-color: #185c6d26
97
+ --chat-wechat-quote-color: #858585
98
+ --chat-wechat-quote-bg: #8585851a
71
99
  _light_text()
72
100
  @media screen and (max-width: $device-mobile-max)
73
101
  --site-bg: black
@@ -82,3 +110,13 @@ _common_root()
82
110
  _light_root()
83
111
  @media (prefers-color-scheme: dark)
84
112
  _dark_root()
113
+
114
+ @media (prefers-color-scheme: dark)
115
+ :root:not([color-scheme])
116
+ img,
117
+ .md-text .tag-plugin.chat>.content .chatcell .user-main .talk.file>.content>.top>.right>svg.icon>path
118
+ filter: brightness(75%)!important
119
+ [color-scheme='dark']
120
+ img,
121
+ .md-text .tag-plugin.chat>.content .chatcell .user-main .talk.file>.content>.top>.right>svg.icon>path
122
+ filter: brightness(75%)!important
@@ -1,5 +1,4 @@
1
1
  .md-text
2
2
  p.katex-block
3
- .katex-display
4
3
  overflow: scroll
5
4
  scrollbar(0, 0)
@@ -0,0 +1,198 @@
1
+ // 传入一个字符串,返回对应的文件格式类型
2
+ function extToMimes(ext) {
3
+ let type = undefined;
4
+ switch (ext) {
5
+ // 对应图片格式jpg
6
+ case 'jpg':
7
+ type = 'image/jpeg'
8
+ break;
9
+ // 对应图片格式png
10
+ case 'png':
11
+ type = 'image/png'
12
+ break;
13
+ // 对应图片格式jpeg
14
+ case 'jpeg':
15
+ type = 'image/jpeg'
16
+ break;
17
+ // 对应图片格式gif
18
+ case 'gif':
19
+ type ='image/gif'
20
+ break;
21
+ // 对应图片格式bmp
22
+ case 'bmp':
23
+ type = 'image/bmp'
24
+ break;
25
+ // 对应文本格式txt
26
+ case 'txt':
27
+ type = 'text/plain'
28
+ break;
29
+ // 对应表格格式xls
30
+ case 'xls':
31
+ type = 'application/vnd.ms-excel'
32
+ break;
33
+ // 对应word文档doc格式
34
+ case 'doc':
35
+ type = 'application/msword'
36
+ break;
37
+ // 对应文档格式pdf
38
+ case 'pdf':
39
+ type = 'application/pdf'
40
+ break;
41
+ // 对应表格格式xlsx
42
+ case 'xlsx':
43
+ type = 'application/vnd.ms-excel'
44
+ break;
45
+ // 对应表格格式csv
46
+ case 'csv':
47
+ type = 'text/csv'
48
+ break;
49
+ // 对应的视频格式一般是MPEG-4或者H.264编码的MP4格式
50
+ case 'mp4':
51
+ type = 'video/mp4'
52
+ break;
53
+ // 对应的视频格式一般是AVI格式
54
+ case 'avi':
55
+ type = 'video/x-msvideo'
56
+ break;
57
+ // 对应的视频格式一般是Windows Media Video格式
58
+ case 'WindowsMediaVideo':
59
+ type = 'video/x-ms-wmv'
60
+ break;
61
+ // 对应的视频格式一般是MOV格式,由苹果公司开发的
62
+ case 'mov':
63
+ type = 'video/quicktime'
64
+ break;
65
+ // 对应的视频格式一般是Flash视频格式,由Adobe公司开发的
66
+ case 'flash':
67
+ type = 'video/x-flv'
68
+ break;
69
+ // 对应的视频格式一般是MKV格式,开源免费的多媒体容器格式
70
+ case 'mkv':
71
+ type = 'video/x-matroska'
72
+ break;
73
+ // 对应音频格式mp3
74
+ case 'mp3':
75
+ type = 'audio/mpeg'
76
+ break;
77
+ // 对应音频格式wav
78
+ case 'wav':
79
+ type = 'audio/wav'
80
+ break;
81
+ // 对应音频格式flac
82
+ case 'flac':
83
+ type = 'audio/flac'
84
+ break;
85
+ // 对应音频格式aac
86
+ case 'aac':
87
+ type = 'audio/aac'
88
+ break;
89
+ // 对应音频格式WMA
90
+ case 'wma':
91
+ type = 'audio/x-ms-wma'
92
+ break;
93
+ default:
94
+ type = 'text/plain'
95
+ break;
96
+ }
97
+ return type;
98
+ }
99
+
100
+ /**
101
+ * 根据字节数获取文件大小,并转换成 KB、MB、GB、TB 等形式
102
+ * @param {number} bytes - 文件的字节数
103
+ * @returns {string} - 文件大小的字符串表示形式
104
+ */
105
+ function formatFileSize(bytes) {
106
+ const units = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
107
+ let size = bytes;
108
+ let unitIndex = 0;
109
+
110
+ while (size >= 1024 && unitIndex < units.length - 1) {
111
+ size /= 1024;
112
+ unitIndex++;
113
+ }
114
+
115
+ // 保留两位小数,四舍五入
116
+ size = Math.round(size * 100) / 100;
117
+
118
+ return `${size}${units[unitIndex]}`;
119
+ }
120
+
121
+ var file_contents = {};
122
+
123
+ function cacheDatas(url, data) {
124
+ let content = data.file;
125
+ let fileName = url.split("/").at(-1);
126
+ let fileType = fileName.split(".")[1];
127
+ let fileMimeType = extToMimes(fileType);
128
+ // 拿到二进制字符串 content
129
+ // 再利用 Buffer 转为对象
130
+ const length = content ? content.data.length : 0;
131
+ let buf = new ArrayBuffer(length)
132
+ let view = new Uint8Array(buf)
133
+ for (let i = 0; i < length; ++i) {
134
+ view[i] = content.data[i]
135
+ }
136
+ // 再输入到 Blob 生成文件
137
+ let blob = new Blob([buf], {type: fileMimeType});
138
+ let fileSize = formatFileSize(blob.size);
139
+
140
+ let file_content = {};
141
+ file_content.name = fileName;
142
+ file_content.size = fileSize;
143
+ file_content.blob = blob;
144
+
145
+ file_contents[url] = file_content;
146
+ }
147
+
148
+ function renderFileDom(el, url) {
149
+ let fileSizeSpan = el.querySelector('.file-size');
150
+ let fileSize = file_contents[url].size;
151
+ if (fileSizeSpan && fileSize) {
152
+ fileSizeSpan.innerHTML = fileSize;
153
+ }
154
+ }
155
+
156
+ function downloadFile(url) {
157
+ let file = file_contents[url];
158
+ let a = document.createElement('a')
159
+ // 指定生成的文件名
160
+ a.download = file.name;
161
+ a.href = URL.createObjectURL(file.blob)
162
+ document.body.appendChild(a)
163
+ a.click()
164
+ document.body.removeChild(a)
165
+ }
166
+
167
+ function downloadFileEvent(fileDoms) {
168
+ for (let i = 0; i < fileDoms.length; ++i) {
169
+ let fileDom = fileDoms[i];
170
+ const api = ctx.tag_plugins.chat.api + '?type=file&url=' || 'https://api.vlts.cc/site_info/v1?type=file&url=';
171
+ const obverser = new IntersectionObserver((entries, observer) => {
172
+ utils.requestAnimationFrame(()=>{
173
+ entries.filter((entry)=>{return entry.isIntersecting}).sort((a,b)=>a.intersectionRect.y !== b.intersectionRect.y ? a.intersectionRect.y - b.intersectionRect.y : a.intersectionRect.x - b.intersectionRect.x).forEach((entry, index) => {
174
+ observer.unobserve(entry.target);
175
+ setTimeout(() => {
176
+ let url = entry.target.getAttribute('url');
177
+ fetch(api + url).then(function(response) {
178
+ if (response.ok) {
179
+ return response.json();
180
+ }
181
+ throw new Error('Network response was not ok.');
182
+ }).then(function(data) {
183
+ cacheDatas(url, data);
184
+ renderFileDom(fileDom, url);
185
+ }).catch(function(error) {
186
+ console.log(error);
187
+ });
188
+ fileDom.addEventListener('click', ()=>{
189
+ downloadFile(url);
190
+ });
191
+ }, Math.max(100, 16)*(index+1));
192
+ });
193
+ });
194
+ });
195
+ obverser.observe(fileDom);
196
+ }
197
+ }
198
+
@@ -0,0 +1,65 @@
1
+ function videoEvents(videos) {
2
+ for (let i = 0; i < videos.length; ++i) {
3
+ let video = videos[i];
4
+ video.loop = false;
5
+ let videoDom = video.parentElement;
6
+ let pauseBtn = videoDom.querySelector('.pause-btn');
7
+ let playBtn = videoDom.querySelector('.play-btn');
8
+ // videoDom.addEventListener('click', ()=>{
9
+ // if (pauseBtn.style.display === 'flex') {
10
+ // video.pause();
11
+ // pauseBtn.style.display = "none";
12
+ // playBtn.style.display = "flex";
13
+ // playFlag = false;
14
+ // } else {
15
+ // if (video.requestFullscreen) {
16
+ // video.requestFullscreen();
17
+ // } else if (video.mozRequestFullScreen) {
18
+ // video.mozRequestFullScreen();
19
+ // } else if (video.webkitRequestFullScreen) {
20
+ // video.webkitRequestFullScreen();
21
+ // } else if (video.msRequestFullscreen) {
22
+ // video.msRequestFullscreen();
23
+ // }
24
+ // video.play();
25
+ // pauseBtn.style.display = "flex";
26
+ // playBtn.style.display = "none";
27
+ // playFlag = true;
28
+ // }
29
+ // });
30
+
31
+ // video.addEventListener('ended', ()=>{
32
+ // pauseBtn.style.display = "none";
33
+ // playBtn.style.display = "flex";
34
+ // });
35
+
36
+ videoDom.addEventListener('click', ()=>{
37
+ if (video.requestFullscreen) {
38
+ video.requestFullscreen();
39
+ } else if (video.mozRequestFullScreen) {
40
+ video.mozRequestFullScreen();
41
+ } else if (video.webkitRequestFullScreen) {
42
+ video.webkitRequestFullScreen();
43
+ } else if (video.msRequestFullscreen) {
44
+ video.msRequestFullscreen();
45
+ }
46
+ });
47
+
48
+
49
+ document.addEventListener('fullscreenchange', () => {
50
+ if (checkIsFullScreen()) {
51
+ console.log("进入全屏");
52
+ video.play();
53
+ } else {
54
+ console.log("退出全屏");
55
+ video.currentTime = 0; // 更改当前播放的时间点
56
+ video.pause();
57
+ }
58
+ });
59
+ function checkIsFullScreen(){
60
+ var isFullScreen = document.fullscreen || document.mozFullScreen || document.webkitIsFullScreen;
61
+ return isFullScreen == undefined ? false : isFullScreen;
62
+ }
63
+ }
64
+ }
65
+