Skip to content

Commit f459881

Browse files
committed
feat: support title navigation
1 parent b0ab984 commit f459881

File tree

3 files changed

+54
-15
lines changed

3 files changed

+54
-15
lines changed

src/stores/index.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,13 @@ export const useStore = defineStore(`store`, () => {
184184

185185
const readingTime = ref<ReadTimeResults | null>(null)
186186

187+
// 文章标题
188+
const titleList = ref<{
189+
url: string
190+
title: string
191+
level: number
192+
}[]>([])
193+
187194
// 更新编辑器
188195
const editorRefresh = () => {
189196
codeThemeChange()
@@ -192,6 +199,26 @@ export const useStore = defineStore(`store`, () => {
192199
const { markdownContent, readingTime: readingTimeResult } = renderer.parseFrontMatterAndContent(editor.value!.getValue())
193200
readingTime.value = readingTimeResult
194201
let outputTemp = marked.parse(markdownContent) as string
202+
203+
// 提取标题
204+
const div = document.createElement('div')
205+
div.innerHTML = outputTemp
206+
const list = div.querySelectorAll<HTMLElement>(`[data-heading]`)
207+
208+
titleList.value = []
209+
let i = 0
210+
for (const item of list) {
211+
item.setAttribute(`id`, `${i}`)
212+
titleList.value.push({
213+
url: `#${i}`,
214+
title: `${item.innerText}`,
215+
level: Number(item.tagName.slice(1))
216+
})
217+
i++
218+
}
219+
220+
outputTemp = div.innerHTML
221+
195222
outputTemp = DOMPurify.sanitize(outputTemp)
196223

197224
// 阅读时间及字数统计
@@ -501,6 +528,8 @@ export const useStore = defineStore(`store`, () => {
501528
delPost,
502529
isOpenPostSlider,
503530
isOpenRightSlider,
531+
532+
titleList,
504533
}
505534
})
506535

src/utils/renderer.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,8 @@ export function initRenderer(opts: IOpts) {
157157

158158
function styledContent(styleLabel: string, content: string, tagName?: string): string {
159159
const tag = tagName ?? styleLabel
160-
return `<${tag} ${styles(styleLabel)}>${content}</${tag}>`
160+
161+
return `<${tag} ${/^h\d$/.test(tag) ? `data-heading="true"` : ``} ${styles(styleLabel)}>${content}</${tag}>`
161162
}
162163

163164
function addFootnote(title: string, link: string): number {

src/views/CodemirrorEditor.vue

Lines changed: 23 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -418,24 +418,33 @@ onMounted(() => {
418418
</ContextMenuContent>
419419
</ContextMenu>
420420
</div>
421-
<div
422-
id="preview"
423-
ref="preview"
424-
class="preview-wrapper flex-1 p-5"
425-
>
426-
<div id="output-wrapper" :class="{ output_night: !backLight }">
427-
<div class="preview border-x-1 shadow-xl">
428-
<section id="output" v-html="output" />
429-
<div v-if="isCoping" class="loading-mask">
430-
<div class="loading-mask-box">
431-
<div class="loading__img" />
432-
<span>正在生成</span>
421+
<div class="relative flex-1">
422+
<div
423+
id="preview"
424+
ref="preview"
425+
class="preview-wrapper p-5"
426+
>
427+
<div id="output-wrapper" :class="{ output_night: !backLight }">
428+
<div class="preview border-x-1 shadow-xl">
429+
<section id="output" v-html="output" />
430+
<div v-if="isCoping" class="loading-mask">
431+
<div class="loading-mask-box">
432+
<div class="loading__img" />
433+
<span>正在生成</span>
434+
</div>
433435
</div>
434436
</div>
435437
</div>
436-
</div>
437438

438-
<BackTop target="preview" :right="40" :bottom="40" />
439+
<BackTop target="preview" :right="40" :bottom="40" />
440+
</div>
441+
<ul class="bg-background absolute left-0 top-0 max-h-100 w-60 overflow-auto border rounded-2 p-2 text-sm shadow">
442+
<li v-for="(item, index) in store.titleList" :key="index" class="line-clamp-1 py-1 leading-6 hover:bg-gray-300 dark:hover:bg-gray-600" :style="{paddingLeft: item.level - 0.5 + 'em'}">
443+
<a :href="item.url">
444+
{{ item.title }}
445+
</a>
446+
</li>
447+
</ul>
439448
</div>
440449
<CssEditor class="order-2 flex-1" />
441450
<RightSlider class="order-2" />

0 commit comments

Comments
 (0)