构建 Obsidian 的 Hexo 写作工作流 这篇文章中,我们已经把一些写作习惯迁移到 Obsidian 上,但我们还剩下最后一块难啃的骨头——Obsidian Markdown 语法的适配。这篇文章的解决方案将覆盖部分经常使用的 Obsidian Flavored Markdown(OFM) 语法。

为了写成这篇文章我手撸两个插件😭。直至目前,本文的解决方案比文章最初发表时进行了巨大优化,操作更加简单。

前置知识

OFM

Obsidian 除了支持大部分 CommonMark 语法、部分 GFM 功能以及 LaTeX 外,Obsidian 增加了一些新语法 [1]

语法 Syntax 描述 Description 本文解决的问题
[[ ]] Internal links
![[ ]] Embedding files
![ name | width x height ]() External images with dimensions
%% Comments
> [!note] Callouts
Obsidian 不支持在 HTML 块中使用 Markdown 语法或空行。但是 Hexo 支持。

为了使得这些 Obsidian 语法在 Hexo 中产生作用,我们可以安装插件改进这一点,从而得到更丰富的书写体验。

使用增强的 Markdown 语法会增加你对特定软件和插件的依赖性,但能提升你的写作体验。

介绍解决方案前先简要说明一下我对 Markdown 渲染相关的插件的理解。

Hexo 里的 Markdown 渲染引擎

有了 Markdown 渲染引擎,Hexo 才能将 Markdown 格式的内容渲染成 HTML 网页。不同的渲染器支持的语法不同。这里列出以下三种渲染引擎。

渲染引擎 功能
hexo-renderer-marked Hexo 预装渲染引擎。不支持复杂的数学公式
hexo-renderer-markdown-it 取代第一个的渲染器,渲染更快,更符合 CommonMark
hexo-renderer-markdown-it-plus 上一个渲染器的分支,可能更好用了吧

上面的渲染引擎中内置不同的插件。我使用的 hexo-renderer-markdown-it-plus 支持扩展,我们可以在 npm 插件市场选择一款插件用以扩展更多语法(一般名为 markdown-it-xxxx)。

比如我安装的支持任务列表语法(GFM[2])的插件 markdown-it-task-lists,以及后文讲到的 Callouts 语法(OFM)插件 mdit-plugin-callouts。然后配置上去即可(后面有教程):

image.png

Internal links 双向链接渲染解决方案

经过博主不懈努力,目前只需安装一个插件就可以解决问题:

1
npm install hexo-filter-titlebased-link --save

使用插件前请确保你博客文章的所有标题都是独一无二的。(不放心可以自己写个脚本检查,参考文章 Obsidian Internal links 双向链接渲染解决方案)。

Readme Card

GitHub 仓库地址:uuanqin/hexo-filter-titlebased-link: Transfer wiki links (based on the title) in Markdown files to permalink. 将基于标题的双向链接转换为 Hexo 设定的永久链接。 (github.com)

欢迎 star⭐~

旧方案仍然可以工作,不过操作繁琐。详见 这篇文章

渲染效果详见本站的双链测试页:双链渲染测试

Callouts 标注块解决方案

找了半天终于找到这个宝藏插件,这里默默感谢作者 @widcardw。现在 @widcardw 已经是本站友链用户啦~欢迎大家多多拜访!

此章节于 240802 改进(刚好文章发布一周年),相比原方案减少了操作步骤。

对于这种需要另外渲染的新语法,我使用一款 npm 插件:mdit-plugin-callouts - npm (npmjs.com),来增强渲染这一部分的内容。

这款插件本身是用于使 vite 博客网站支持 Obsidian 的 Callouts 用的,但稍微调整下也可以运用于 Hexo。

首先打开项目文件夹安装插件:

1
npm install mdit-plugin-callouts

Hexo 博客中我安装的渲染器是 hexo-renderer-markdown-it-plus,它可以通过配置文件拓展其他 Markdown 渲染插件。

_config.yml 中增加相应配置以添加插件:

1
2
3
4
5
6
7
8
9
# markdown_it_plus 语法渲染插件选项
markdown_it_plus:
plugins:
# Obsidian Callouts
- plugin:
name: mdit-plugin-callouts
enable: true
options:
# this is plugin option

新建外部 CSS 文件 callout_blocks.css,比如我放在博客 source/css 目录下,内容为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
:root {
--un-ring-offset-shadow: 0 0 transparent;
--un-ring-shadow: 0 0 transparent
}

.custom-callout {
border-left: 3px solid;
border-radius: var(--callout-radius);
box-shadow: var(--un-ring-offset-shadow), var(--un-ring-shadow), var(--un-shadow);
margin: 1rem 0;
padding: 0 !important;
}

:root {
--callout-note: 68, 138, 255;
--callout-abstract: 0, 176, 255;
--callout-info: 0, 184, 212;
--callout-tip: 0, 191, 165;
--callout-success: 8, 185, 78;
--callout-question: 224, 172, 0;
--callout-warning: 255, 145, 0;
--callout-failure: 255, 82, 82;
--callout-danger: 255, 23, 68;
--callout-bug: 245, 0, 87;
--callout-example: 124, 77, 255;
--callout-quote: 158, 158, 158;
--callout-radius: 0px;
--callout-border-opacity: 0.5;
--callout-title-bg-opacity: 0.08
}

.callout-fold:before {
align-self: center;
content: url('data:image/svg+xml;charset=utf-8,<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="gray" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="chevron-down"><path d="m6 9 6 6 6-6"/></svg>')
}

.callout-fold {
display: flex;
transform: rotate(-90deg);
transition: .5s cubic-bezier(.075, .82, .165, 1)
}

.custom-callout[open] > summary > .callout-fold {
transform: rotate(0deg)
}

.custom-callout > summary {
border-top-left-radius: var(--callout-radius);
border-top-right-radius: var(--callout-radius);
cursor: pointer;
margin: 0;
padding: 1rem
}

.custom-callout > summary::marker {
content: ""
}

.custom-callout > summary:before {
margin-right: .5rem
}

.custom-callout > summary::-webkit-details-marker {
display: none
}

.callout-title {
display: flex;
justify-content: space-between
}

.custom-callout > .callout-body {
background: transparent !important;
border-left: none;
margin: 0 !important;
padding: .5rem 1rem;
position: relative
}

.custom-callout > .callout-body > p {
margin: 8px 0
}

.custom-callout > .callout-body > pre {
margin: 1.25rem -1rem
}

.custom-callout > .callout-body > pre:first-child {
margin-top: -.75rem
}

.custom-callout > .callout-body > pre:last-child {
margin-bottom: -.75rem
}

.custom-callout.note, .custom-callout.seealso {
border-color: rgba(var(--callout-note), var(--callout-border-opacity))
}

.custom-callout.note > summary, .custom-callout.seealso > summary {
background-color: rgba(var(--callout-note), var(--callout-title-bg-opacity))
}

.custom-callout.abstract, .custom-callout.summary, .custom-callout.tldr {
border-color: rgba(var(--callout-abstract), var(--callout-border-opacity))
}

.custom-callout.abstract > summary, .custom-callout.summary > summary, .custom-callout.tldr > summary {
background-color: rgba(var(--callout-abstract), var(--callout-title-bg-opacity))
}

.custom-callout.info, .custom-callout.todo {
border-color: rgba(var(--callout-info), var(--callout-border-opacity))
}

.custom-callout.info > summary, .custom-callout.todo > summary {
background-color: rgba(var(--callout-info), var(--callout-title-bg-opacity))
}

.custom-callout.hint, .custom-callout.important, .custom-callout.tip {
border-color: rgba(var(--callout-tip), var(--callout-border-opacity))
}

.custom-callout.hint > summary, .custom-callout.important > summary, .custom-callout.tip > summary {
background-color: rgba(var(--callout-tip), var(--callout-title-bg-opacity))
}

.custom-callout.check, .custom-callout.done, .custom-callout.success {
border-color: rgba(var(--callout-success), var(--callout-border-opacity))
}

.custom-callout.check > summary, .custom-callout.done > summary, .custom-callout.success > summary {
background-color: rgba(var(--callout-success), var(--callout-title-bg-opacity))
}

.custom-callout.faq, .custom-callout.help, .custom-callout.question {
border-color: rgba(var(--callout-question), var(--callout-border-opacity))
}

.custom-callout.faq > summary, .custom-callout.help > summary, .custom-callout.question > summary {
background-color: rgba(var(--callout-question), var(--callout-title-bg-opacity))
}

.custom-callout.attention, .custom-callout.caution, .custom-callout.warning {
border-color: rgba(var(--callout-warning), var(--callout-border-opacity))
}

.custom-callout.attention > summary, .custom-callout.caution > summary, .custom-callout.warning > summary {
background-color: rgba(var(--callout-warning), var(--callout-title-bg-opacity))
}

.custom-callout.fail, .custom-callout.failure, .custom-callout.missing {
border-color: rgba(var(--callout-failure), var(--callout-border-opacity))
}

.custom-callout.fail > summary, .custom-callout.failure > summary, .custom-callout.missing > summary {
background-color: rgba(var(--callout-failure), var(--callout-title-bg-opacity))
}

.custom-callout.danger, .custom-callout.error {
border-color: rgba(var(--callout-danger), var(--callout-border-opacity))
}

.custom-callout.danger > summary, .custom-callout.error > summary {
background-color: rgba(var(--callout-danger), var(--callout-title-bg-opacity))
}

.custom-callout.bug {
border-color: rgba(var(--callout-bug), var(--callout-border-opacity))
}

.custom-callout.bug > summary {
background-color: rgba(var(--callout-bug), var(--callout-title-bg-opacity))
}

.custom-callout.example {
border-color: rgba(var(--callout-example), var(--callout-border-opacity))
}

.custom-callout.example > summary {
background-color: rgba(var(--callout-example), var(--callout-title-bg-opacity))
}

.custom-callout.cite, .custom-callout.quote {
border-color: rgba(var(--callout-quote), var(--callout-border-opacity))
}

.custom-callout.cite > summary, .custom-callout.quote > summary {
background-color: rgba(var(--callout-quote), var(--callout-title-bg-opacity))
}

.callout-title > .callout-icon + div {
-webkit-box-flex: 1;
-ms-flex: 1 1 0%;
-webkit-flex: 1 1 0%;
flex: 1 1 0%;
margin-left: .25rem
}

.callout-icon {
align-items: center;
color: #000;
display: flex
}

.callout-icon:before {
height: 20px;
width: 20px
}

.custom-callout.attention > .callout-title > .callout-icon:before, .custom-callout.caution > .callout-title > .callout-icon:before, .custom-callout.warning > .callout-title > .callout-icon:before {
content: url('data:image/svg+xml;charset=utf-8,<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="%23FF9100" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="svg-icon lucide-alert-triangle"><path d="m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3ZM12 9v4M12 17h.01"/></svg>')
}

.custom-callout.note > .callout-title > .callout-icon:before, .custom-callout.seealso > .callout-title > .callout-icon:before {
content: url('data:image/svg+xml;charset=utf-8,<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="%23448AFF" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="svg-icon lucide-pencil"><path d="m18 2 4 4M7.5 20.5 19 9l-4-4L3.5 16.5 2 22z"/></svg>')
}

.custom-callout.abstract > .callout-title > .callout-icon:before, .custom-callout.summary > .callout-title > .callout-icon:before, .custom-callout.tldr > .callout-title > .callout-icon:before {
content: url('data:image/svg+xml;charset=utf-8,<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="%2300B0FF" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="svg-icon lucide-clipboard-list"><rect x="8" y="2" width="8" height="4" rx="1" ry="1"/><path d="M16 4h2a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h2M12 11h4M12 16h4M8 11h.01M8 16h.01"/></svg>')
}

.custom-callout.info > .callout-title > .callout-icon:before, .custom-callout.todo > .callout-title > .callout-icon:before {
content: url('data:image/svg+xml;charset=utf-8,<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="%2300B8D4" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="svg-icon lucide-check-circle-2"><path d="M12 22c5.523 0 10-4.477 10-10S17.523 2 12 2 2 6.477 2 12s4.477 10 10 10z"/><path d="m9 12 2 2 4-4"/></svg>')
}

.custom-callout.hint > .callout-title > .callout-icon:before, .custom-callout.important > .callout-title > .callout-icon:before, .custom-callout.tip > .callout-title > .callout-icon:before {
content: url('data:image/svg+xml;charset=utf-8,<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="%2300BFA5" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="svg-icon lucide-flame"><path d="M8.5 14.5A2.5 2.5 0 0 0 11 12c0-1.38-.5-2-1-3-1.072-2.143-.224-4.054 2-6 .5 2.5 2 4.9 4 6.5 2 1.6 3 3.5 3 5.5a7 7 0 1 1-14 0c0-1.153.433-2.294 1-3a2.5 2.5 0 0 0 2.5 2.5z"/></svg>')
}

.custom-callout.check > .callout-title > .callout-icon:before, .custom-callout.done > .callout-title > .callout-icon:before, .custom-callout.success > .callout-title > .callout-icon:before {
content: url('data:image/svg+xml;charset=utf-8,<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="%2300C853" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="svg-icon lucide-check"><path d="M20 6 9 17l-5-5"/></svg>')
}

.custom-callout.faq > .callout-title > .callout-icon:before, .custom-callout.help > .callout-title > .callout-icon:before, .custom-callout.question > .callout-title > .callout-icon:before {
content: url('data:image/svg+xml;charset=utf-8,<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="%23E0AC00" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="svg-icon lucide-help-circle"><circle cx="12" cy="12" r="10"/><path d="M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3M12 17h.01"/></svg>')
}

.custom-callout.fail > .callout-title > .callout-icon:before, .custom-callout.failure > .callout-title > .callout-icon:before, .custom-callout.missing > .callout-title > .callout-icon:before {
content: url('data:image/svg+xml;charset=utf-8,<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="%23FF5252" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="svg-icon lucide-x"><path d="M18 6 6 18M6 6l12 12"/></svg>')
}

.custom-callout.danger > .callout-title > .callout-icon:before, .custom-callout.error > .callout-title > .callout-icon:before {
content: url('data:image/svg+xml;charset=utf-8,<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="%23FF1744" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="svg-icon lucide-zap"><path d="M13 2 3 14h9l-1 8 10-12h-9l1-8z"/></svg>')
}

.custom-callout.bug > .callout-title > .callout-icon:before {
content: url('data:image/svg+xml;charset=utf-8,<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="%23F50057" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="svg-icon lucide-bug"><rect x="8" y="6" width="8" height="14" rx="4"/><path d="m19 7-3 2M5 7l3 2M19 19l-3-2M5 19l3-2M20 13h-4M4 13h4M10 4l1 2M14 4l-1 2"/></svg>')
}

.custom-callout.example > .callout-title > .callout-icon:before {
content: url('data:image/svg+xml;charset=utf-8,<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="%237C4DFF" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="svg-icon lucide-list"><path d="M8 6h13M8 12h13M8 18h13M3 6h.01M3 12h.01M3 18h.01"/></svg>')
}

.custom-callout.cite > .callout-title > .callout-icon:before, .custom-callout.quote > .callout-title > .callout-icon:before {
content: url('data:image/svg+xml;charset=utf-8,<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="%239E9E9E" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="svg-icon lucide-quote"><path d="M3 21c3 0 7-1 7-8V5c0-1.25-.756-2.017-2-2H4c-1.25 0-2 .75-2 1.972V11c0 1.25.75 2 2 2 1 0 1 0 1 1v1c0 1-1 2-2 2s-1 .008-1 1.031V20c0 1 0 1 1 1zM15 21c3 0 7-1 7-8V5c0-1.25-.757-2.017-2-2h-4c-1.25 0-2 .75-2 1.972V11c0 1.25.75 2 2 2h.75c0 2.25.25 4-2.75 4v3c0 1 0 1 1 1z"/></svg>')
}

/* 找不到关键字则提供默认样式 note 样式 */

.custom-callout > .callout-title > .callout-icon:before, .custom-callout.seealso > .callout-title > .callout-icon:before {
content: url('data:image/svg+xml;charset=utf-8,<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="%23448AFF" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="svg-icon lucide-pencil"><path d="m18 2 4 4M7.5 20.5 19 9l-4-4L3.5 16.5 2 22z"/></svg>')
}

.custom-callout , .custom-callout.seealso {
border-color: rgba(var(--callout-note), var(--callout-border-opacity)); /* 不起作用 */
}

.custom-callout > summary, .custom-callout.seealso > summary {
background-color: rgba(var(--callout-note), var(--callout-title-bg-opacity))
}


/* 标题加粗并着色 */

.custom-callout .callout-title > .callout-icon + div{
font-weight: bold;
color: rgba(var(--callout-note)); /* 默认颜色 */
}

.custom-callout.abstract> .callout-title > .callout-icon + div ,
.custom-callout.summary> .callout-title > .callout-icon + div,
.custom-callout.tldr> .callout-title > .callout-icon + div{
color: rgba(var(--callout-abstract));
}

.custom-callout.info> .callout-title > .callout-icon + div ,
.custom-callout.todo> .callout-title > .callout-icon + div{
color: rgba(var(--callout-info));
}

.custom-callout.hint> .callout-title > .callout-icon + div ,
.custom-callout.important> .callout-title > .callout-icon + div,
.custom-callout.tip> .callout-title > .callout-icon + div{
color: rgba(var(--callout-tip));
}

.custom-callout.check> .callout-title > .callout-icon + div ,
.custom-callout.done> .callout-title > .callout-icon + div,
.custom-callout.success> .callout-title > .callout-icon + div{
color: rgba(var(--callout-success));
}

.custom-callout.question> .callout-title > .callout-icon + div ,
.custom-callout.faq> .callout-title > .callout-icon + div,
.custom-callout.help> .callout-title > .callout-icon + div{
color: rgba(var(--callout-question));
}

.custom-callout.attention> .callout-title > .callout-icon + div ,
.custom-callout.caution> .callout-title > .callout-icon + div,
.custom-callout.warning> .callout-title > .callout-icon + div{
color: rgba(var(--callout-warning));
}

.custom-callout.fail> .callout-title > .callout-icon + div,
.custom-callout.failure> .callout-title > .callout-icon + div,
.custom-callout.missing> .callout-title > .callout-icon + div{
color: rgba(var(--callout-failure));
}

.custom-callout.error> .callout-title > .callout-icon + div ,
.custom-callout.danger> .callout-title > .callout-icon + div
{
color: rgba(var(--callout-danger));
}

.custom-callout.bug> .callout-title > .callout-icon + div{
color: rgba(var(--callout-bug));
}

.custom-callout.example> .callout-title > .callout-icon + div{
color: rgba(var(--callout-example));
}

.custom-callout.cite> .callout-title > .callout-icon + div ,
.custom-callout.quote> .callout-title > .callout-icon + div
{
color: rgba(var(--callout-quote));
}

上面的 CSS 代码是本人对原插件自带的样式的改进:

  • 所有样式聚合于单文件
  • 提供不指定关键字时的默认样式
  • Callouts 块标题加粗并染色
  • 通过 !important; 关键字解决 Butterfly 样式冲突问题。

接下来根据你使用的主题的说明,引入外部 CSS 文件 callout_blocks.css。Butterfly 主题的做法为在主题配置文件 _config.butterfly.yml 中插入:

1
2
3
4
inject:
head:
# callout blocks
- <link rel="stylesheet" href="/css/callout_blocks.css">

现在你可以测试一下 Hexo 渲染后的页面正不正常了。

更多渲染情况详见本站渲染调试页:Markdown 渲染测试

External images 图片大小解决方案

Obsidian 对于图片大小尺寸调整有其自己的一套 语法

1
2
![img|100x145](path/to/img) // 宽100px,高145px
![img|100](path/to/img) // 宽100px

通过搜寻并没有很好的方案解决,于是我就自己手撸一个了…

博主自写插件:

Readme Card

Git 仓库地址:uuanqin/markdown-it-obsidian-imgsize: Obsidian图片大小处理插件 (github.com)

使用方法很简单,仿照上一小节 Callouts 的解决方法,安装这个 markdown-it 插件即可:

1
npm i markdown-it-obsidian-imgsize --save

这一层打通以后,你就可以放心使用 Obsidian 中方便调整图像大小的插件啦,比如我正在用的这个 Obsidian 中的插件:nicojeske/mousewheel-image-zoom (github.com) 可以通过鼠标滚轮调整图片大小。

后记

心路历程

解决 Callouts 问题的过程中,搜到 @widcardw 的博客并产生启发,于是我的第一款 NPM 插件 markdown-it-obsidian-imgsize 诞生了。开发杂记详见:【开发杂记】第一次开发 npm 插件

关于双链渲染,心路历程详见:【开发杂记】第一次写 Hexo 插件

每次写 CSS 都要吐槽各种选择器真的很恶心,不想学前端的理由 ++。好在有讯飞星火辅助了 CSS 样式代码的解释与生成,头发少掉几根。

后续改进

  • 写一个 markdown-it 插件 适配 Obsidian 图片大小的语法(我真的写了一个新插件)
  • 重写 Callouts 插件适配 Hexo
    • 240802 对原方案做了小改进解决了大部分的问题,新插件的需求似乎没那么强烈了。
  • 重写 Hexo-Obsidian 双向链接插件(我直接写了一个新插件)

本文参考


  1. Obsidian Flavored Markdown - Obsidian Help ↩︎

  2. Markdown 相关语法规范详见 Markdown 渲染测试 ↩︎