hexo-theme-stellar 1.32.0 → 1.32.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.
package/_config.yml CHANGED
@@ -1,6 +1,6 @@
1
1
  ######## Stellar info ########
2
2
  stellar:
3
- version: '1.32.0'
3
+ version: '1.32.1'
4
4
  homepage: 'https://xaoxuu.com/wiki/stellar/'
5
5
  repo: 'https://github.com/xaoxuu/hexo-theme-stellar'
6
6
  main_css: /css/main.css
@@ -608,7 +608,7 @@ plugins:
608
608
 
609
609
  style:
610
610
  prefers_theme: auto # auto / light / dark
611
- smooth_scroll: false # true / false 开启时如果目录过长可能无法准确定位
611
+ smooth_scroll: true # true / false 开启时如果目录过长可能无法准确定位
612
612
  font-size:
613
613
  root: 16px # 改这个会影响全局所有文字的字号
614
614
  body: 17px # 影响正文区域的字号,如果改成 px 则不受 root 影响
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hexo-theme-stellar",
3
- "version": "1.32.0",
3
+ "version": "1.32.1",
4
4
  "description": "Elegant and powerful theme for Hexo.",
5
5
  "main": "package.json",
6
6
  "scripts": {
@@ -10,25 +10,44 @@ let cache = fs.existsSync(outputPath)
10
10
  ? JSON.parse(fs.readFileSync(outputPath))
11
11
  : {};
12
12
 
13
- // 提取 Markdown 中的图片链接
14
- function extractImageUrls(content) {
15
- const urls = [];
13
+ // 提取 Markdown 中的图片链接并处理已有 ratio
14
+ function extractImageUrlsAndCacheRatio(content, relative, ctx) {
15
+ const urlsToProbe = [];
16
16
  const tagImgRegex = /{%\s+image\s+[^%]*?\b(https?:\/\/[^\s%]+)[^%]*?%}/g;
17
17
 
18
+ if (!cache[relative]) cache[relative] = {};
19
+
18
20
  let match;
19
21
  while ((match = tagImgRegex.exec(content)) !== null) {
20
- urls.push(match[1]);
22
+ const fullTag = match[0];
23
+ const url = match[1];
24
+
25
+ // ratio:xxx 或 ratio:xxx/yyy
26
+ const ratioMatch = fullTag.match(/ratio:([0-9./]+)/);
27
+ const ratioStr = ratioMatch ? ratioMatch[1] : null;
28
+
29
+ if (cache[relative][url]) {
30
+ // 已有缓存,跳过
31
+ continue;
32
+ }
33
+
34
+ if (ratioStr) {
35
+ cache[relative][url] = ratioStr;
36
+ // 🧠 实时写入
37
+ fs.mkdirSync(path.dirname(outputPath), { recursive: true });
38
+ fs.writeFileSync(outputPath, JSON.stringify(cache, null, 2));
39
+ } else {
40
+ urlsToProbe.push(url);
41
+ }
21
42
  }
22
43
 
23
- return urls;
44
+ return urlsToProbe;
24
45
  }
25
46
 
26
-
27
- // 远程图片尺寸探测
47
+ // 探测远程图片尺寸
28
48
  async function getImageRatio(ctx, url) {
29
- if (!url.startsWith('http')) {
30
- return null;
31
- }
49
+ if (!url.startsWith('http')) return null;
50
+
32
51
  try {
33
52
  const result = await probe(url);
34
53
  return `${result.width}/${result.height}`;
@@ -38,46 +57,49 @@ async function getImageRatio(ctx, url) {
38
57
  }
39
58
  }
40
59
 
41
-
42
60
  // 主逻辑
43
61
  module.exports = async (ctx, options) => {
44
62
  const cacheExists = fs.existsSync(outputPath);
45
- if (cacheExists) {
46
- ctx.log.info('正在获取图片长宽比。缓存已存在,开始增量更新...');
47
- } else {
48
- ctx.log.info('正在获取图片长宽比。首次可能耗时较久,请耐心等待...');
49
- }
63
+ ctx.log.info(
64
+ cacheExists
65
+ ? '正在获取图片长宽比。缓存已存在,开始增量更新...'
66
+ : '正在获取图片长宽比。首次可能耗时较久,请耐心等待...'
67
+ );
50
68
 
51
69
  const mdFiles = glob.sync('source/**/*.md');
52
70
 
53
71
  for (const file of mdFiles) {
54
72
  const relative = path.relative(process.cwd(), file);
55
73
  const content = fs.readFileSync(file, 'utf8');
56
- const imageUrls = extractImageUrls(content);
57
- const currentUrls = new Set(imageUrls);
58
74
 
59
- // 初始化或清理旧数据
75
+ // 初始化文件级缓存(提取前先建好结构)
60
76
  if (!cache[relative]) {
61
77
  cache[relative] = {};
62
- } else {
63
- for (const oldUrl of Object.keys(cache[relative])) {
64
- if (!currentUrls.has(oldUrl)) {
65
- delete cache[relative][oldUrl];
66
- }
78
+ }
79
+
80
+ const imageUrls = extractImageUrlsAndCacheRatio(content, relative, ctx);
81
+ const currentUrls = new Set([
82
+ ...imageUrls,
83
+ ...Object.keys(cache[relative])
84
+ ]);
85
+
86
+ // 清理已被 Markdown 中移除的旧记录
87
+ for (const oldUrl of Object.keys(cache[relative])) {
88
+ if (!currentUrls.has(oldUrl)) {
89
+ delete cache[relative][oldUrl];
67
90
  }
68
91
  }
69
92
 
70
- // 探测新图片
93
+ // 探测未缓存图片
71
94
  for (const url of imageUrls) {
72
- if (cache[relative][url]) {
73
- continue;
74
- }
95
+ if (cache[relative][url]) continue;
96
+
75
97
  const ratio = await getImageRatio(ctx, url);
76
98
  if (ratio) {
77
99
  cache[relative][url] = ratio;
78
- ctx.log.info(`已添加: ${url} → ${ratio}`);
100
+ ctx.log.info(`✅ 探测添加: ${url} → ${ratio}`);
79
101
 
80
- // 🧠 实时写入(增量更新,支持中断恢复)
102
+ // 实时落盘
81
103
  fs.mkdirSync(path.dirname(outputPath), { recursive: true });
82
104
  fs.writeFileSync(outputPath, JSON.stringify(cache, null, 2));
83
105
  }
@@ -85,4 +107,4 @@ module.exports = async (ctx, options) => {
85
107
  }
86
108
 
87
109
  ctx.log.info('[image-ratios.json] 生成完成');
88
- };
110
+ };
@@ -40,7 +40,7 @@ hexo.extend.tag.register('navbar', require('./lib/navbar')(hexo))
40
40
  hexo.extend.tag.register('note', require('./lib/note')(hexo))
41
41
  hexo.extend.tag.register('poetry', require('./lib/poetry')(hexo), true)
42
42
  hexo.extend.tag.register('quot', require('./lib/quot')(hexo))
43
- hexo.extend.tag.register('quote', require('./lib/quote')(hexo), true)
43
+ hexo.extend.tag.register('blockquote', require('./lib/blockquote')(hexo), true)
44
44
  hexo.extend.tag.register('hashtag', require('./lib/hashtag')(hexo))
45
45
  hexo.extend.tag.register('okr', require('./lib/okr')(hexo), {ends: true})
46
46
  hexo.extend.tag.register('audio', require('./lib/audio')(hexo))
@@ -1,11 +1,11 @@
1
1
  /**
2
- * quote.js v1.1 | https://github.com/xaoxuu/hexo-theme-stellar/
2
+ * blockquote.js v1.1 | https://github.com/xaoxuu/hexo-theme-stellar/
3
3
  * 格式与官方标签插件一致使用空格分隔,中括号内的是可选参数(中括号不需要写出来)
4
4
  *
5
- * quote:
6
- * {% quote [indent:true/false] %}
5
+ * blockquote:
6
+ * {% blockquote [indent:true/false] %}
7
7
  * body
8
- * {% endquote %}
8
+ * {% endblockquote %}
9
9
  *
10
10
  */
11
11
 
@@ -15,7 +15,7 @@ module.exports = ctx => function(args, content) {
15
15
  var el = ''
16
16
  args = ctx.args.map(args, ['indent'], [])
17
17
 
18
- el += `<div class="tag-plugin quote" indent="${args.indent}">`
18
+ el += `<div class="tag-plugin blockquote" indent="${args.indent}">`
19
19
  el += ctx.render.renderSync({text: content, engine: 'markdown'}).split('\n').join('')
20
20
  el += `</div>`
21
21
  return el
@@ -18,7 +18,7 @@ module.exports = ctx => function(args) {
18
18
  if (args.links) {
19
19
  args.links = args.links.split(' ')
20
20
  }
21
- var el = `<div class="tag-plugin navbar"><nav>`
21
+ var el = `<div class="tag-plugin navbar">`
22
22
  for (let link of args.links) {
23
23
  const matches = link.match(/\[(.*?)\]\((.*?)\)/i)
24
24
  if (matches?.length > 2) {
@@ -33,6 +33,6 @@ module.exports = ctx => function(args) {
33
33
  el += `<a class="link" href="#${link}">${link}</a>`
34
34
  }
35
35
  }
36
- el += `</nav></div>`
36
+ el += `</div>`
37
37
  return el
38
38
  }
@@ -35,24 +35,35 @@ ul,ol
35
35
  table:not([class])
36
36
  border-collapse: collapse
37
37
  overflow: auto
38
- display: block
39
38
  margin: 1rem 0
40
39
  max-width: 100%
41
40
  vertical-align: text-top
42
41
  --fsp: $fsp2
43
42
  font-size: var(--fsp)
43
+ scrollbar(0,0)
44
+ display: table
44
45
  th
45
46
  background: var(--block)
47
+ border-top: 1px solid var(--block-border)
48
+ border-bottom: 1px solid var(--block-border)
46
49
  td,th
47
- padding: 0.5em 1em
48
- border: 1px solid var(--block-border)
50
+ padding: 4px 1em
49
51
  line-height: 1.5
50
52
  tr
51
- word-break: keep-all
52
- white-space:nowrap
53
+ border-bottom: 1px dashed var(--block-border)
53
54
  trans()
54
55
  &:hover
55
56
  background: var(--block)
56
57
 
58
+ @media screen and (min-width: $device-mobile-max)
59
+ width 100%
60
+
61
+ @media screen and (max-width: $device-mobile-max)
62
+ display: block
63
+ tr
64
+ word-break: keep-all
65
+ white-space:nowrap
66
+
67
+
57
68
  *[ff=title]
58
69
  font-family: $ff-logo
@@ -5,7 +5,7 @@
5
5
  left: 50%
6
6
  transform: translateX(-50%)
7
7
  max-width: 90%
8
- background-color: var(--block-border)
8
+ background-color: var(--card)
9
9
  color: var(--text-p1)
10
10
  font-size: 1rem
11
11
  font-family: #fff8e1
@@ -36,7 +36,7 @@ p>code:not([class]),li>code:not([class])
36
36
  display: block
37
37
  border-bottom-left-radius: $border-button
38
38
  border-bottom-right-radius: $border-button
39
- background: var(--block-border)
39
+ background: var(--block)
40
40
  >table
41
41
  overflow: auto
42
42
  display: block
@@ -50,6 +50,7 @@ p>code:not([class]),li>code:not([class])
50
50
  scrollbar-codeblock(convert(hexo-config('style.codeblock.scrollbar')))
51
51
  tr
52
52
  background: transparent
53
+ border: none
53
54
  &:hover
54
55
  background: transparent
55
56
 
@@ -88,11 +89,13 @@ p>code:not([class]),li>code:not([class])
88
89
  background: var(--block)
89
90
  margin: 0
90
91
  padding: 1em 0
92
+ pre
93
+ background: none
91
94
  .blob-code-inner
92
95
  color: var(--text-p1)
93
96
  font-family: $ff-codeblock
94
97
  .gist-meta
95
- background: var(--block-border)
98
+ background: var(--block)
96
99
 
97
100
 
98
101
  table:not([class])
@@ -82,38 +82,7 @@
82
82
  margin: 2em 0 1.5em
83
83
  >a:first-child
84
84
  display: none
85
- // 修正缩进效果
86
- >blockquote,.tag-plugin.quote
87
- text-align: center
88
- --inset: calc(var(--fsp) * 2)
89
- margin-left: var(--inset)
90
- margin-right: var(--inset)
91
- background: var(--block)
92
- padding: 1rem 2rem
93
- border-radius: $border-card
94
- &:before,&:after
95
- position: absolute
96
- font-size: 2rem
97
- background-color: hsla($color-theme, 0.25)
98
- top: -0.3em
99
- width: 1em
100
- height: 1em
101
- content: ''
102
- opacity 1
103
- trans1 all
104
- &:before
105
- left: -0.3em
106
- svg-mask-icon($iQuoteLeft)
107
- &:after
108
- right: -0.3em
109
- svg-mask-icon($iQuoteRight)
110
- p:not([class])
111
- color: var(--text-p2)
112
- font-size: $fs-body
113
- text-indent: 2em
114
- &:hover
115
- &:before,&:after
116
- background-color: hsla($color-theme, 0.5)
85
+
117
86
  // 取消缩进效果
118
87
  .poetry, .okr, .timeline, li, .article-footer
119
88
  p:not([class])
@@ -124,6 +93,39 @@
124
93
  border-radius: $border-image-l
125
94
 
126
95
 
96
+ .l_body[type=story] .md-text.content>blockquote, .md-text.content .tag-plugin.blockquote
97
+ text-align: center
98
+ --inset: calc(var(--fsp) * 2)
99
+ margin-left: var(--inset)
100
+ margin-right: var(--inset)
101
+ background: var(--block)
102
+ padding: 1rem 2rem
103
+ border-radius: $border-card
104
+ &:before,&:after
105
+ position: absolute
106
+ font-size: 2rem
107
+ background-color: hsla($color-theme, 0.25)
108
+ top: -0.3em
109
+ width: 1em
110
+ height: 1em
111
+ content: ''
112
+ opacity 1
113
+ trans1 all
114
+ &:before
115
+ left: -0.3em
116
+ svg-mask-icon($iQuoteLeft)
117
+ &:after
118
+ right: -0.3em
119
+ svg-mask-icon($iQuoteRight)
120
+ p:not([class])
121
+ color: var(--text-p2)
122
+ font-size: $fs-body
123
+ text-indent: 2em
124
+ &:hover
125
+ &:before,&:after
126
+ background-color: hsla($color-theme, 0.5)
127
+
128
+
127
129
  .l_body[type=story] .article.banner .content .bottom.only-title
128
130
  justify-content: center
129
131
 
@@ -9,11 +9,12 @@
9
9
  width: 100%
10
10
  min-width: 200px
11
11
  span
12
- line-height: 3
13
- padding: 0 1rem
14
- background: var(--block)
15
- border-right: 1px solid var(--block-border)
16
- color: var(--text-p3)
12
+ padding: .25rem .5rem
13
+ margin: auto .5rem
14
+ line-height: 1
15
+ border-radius: 4px
16
+ background: hsla($color-theme, 0.2)
17
+ color: $color-theme
17
18
  font-family: $ff-code
18
19
  font-size: $fs-13
19
20
  font-weight: 700
@@ -25,11 +26,14 @@
25
26
  color: var(--text-p2)
26
27
  line-height: 3
27
28
  text-indent: 1rem
29
+ span+input.copy-area
30
+ text-indent: 0
28
31
  button.copy-btn
29
- margin: 2px
32
+ margin: 2px 2px 2px 0
30
33
  border-radius: 'calc(%s - 2px)' % $border-bar
31
34
  display: inline-block
32
- background: none
35
+ background: var(--block)
36
+ trans1 all
33
37
  line-height: 0
34
38
  font-size: 1rem
35
39
  padding: 0 .75rem
@@ -1,9 +1,19 @@
1
1
  .tag-plugin.navbar
2
- padding: 0
3
- &:after
4
- left: 0
5
- right: 0
6
-
7
- @media screen and (min-width: $device-mobile-max)
8
- .tag-plugin.navbar nav a
9
- margin-top: 2px
2
+ display: inline-flex
3
+ background: var(--card)
4
+ border-radius: $border-button
5
+ z-index inherit
6
+ box-shadow: 0 0 8px hsla(black, 0.04)
7
+ a
8
+ box-sizing: border-box
9
+ padding: .25rem 1rem
10
+ margin: 2px
11
+ color: inherit
12
+ border-radius: 'calc(%s - 1px)' % $border-button
13
+ trans1 all
14
+ &+a
15
+ margin-left: 0
16
+ &.active
17
+ background: var(--block)
18
+ &:hover
19
+ background: var(--block)
@@ -28,9 +28,6 @@
28
28
  .md-text .tag-plugin.note[color]
29
29
  code
30
30
  background: none
31
- .md-text .tag-plugin.note:not([color])
32
- .highlight, pre
33
- background: var(--block-border)
34
31
  .md-text .tag-plugin.note[child=codeblock]
35
32
  padding: 0
36
33
  background: var(--theme-codeblock)
@@ -5,9 +5,4 @@
5
5
  background: none
6
6
  padding-top: 0
7
7
  padding-bottom: 0
8
- table:not([class])
9
- th
10
- background: var(--block-border)
11
- td,th
12
- border-color: var(--block-border)
13
8
 
@@ -1,4 +1,4 @@
1
- .tag-plugin.quote
1
+ .tag-plugin.blockquote
2
2
  position: relative
3
3
  p:not([class])
4
4
  text-indent: 0 !important
@@ -1,7 +1,7 @@
1
1
  .widget-wrapper.post-list .widget-body
2
2
  a
3
3
  font-size: $fs-14
4
- padding: 8px 16px
4
+ padding: 6px 16px
5
5
  display: block
6
6
  border-radius: $border-bar
7
7
  color: var(--text-p1)
@@ -26,7 +26,7 @@
26
26
  a
27
27
  --padding: calc(var(--gap-padding) / 2)
28
28
  --padding-offset: calc(0 - var(--padding))
29
- padding: 6px var(--padding)
29
+ padding: 4px var(--padding)
30
30
  margin: 0 var(--padding)
31
31
  color: var(--text-p3)
32
32
  display: block
@@ -111,7 +111,7 @@
111
111
  border: none
112
112
  padding: 6px 2rem
113
113
  border-radius: $border-card
114
- background: var(--block-border)
114
+ background: var(--block)
115
115
  color: var(--text-p1)
116
116
  line-height: 2
117
117
  font-size: 14px