返回 slidev
notes-edit.vue
根目录 / packages / client / pages / notes-edit.vue
1 <script setup lang="ts">
2 import type { SlideRoute } from '@slidev/types'
3 import { useHead } from '@unhead/vue'
4 import { debouncedWatch } from '@vueuse/core'
5 import { ref } from 'vue'
6 import { useNav } from '../composables/useNav'
7 import { useDynamicSlideInfo } from '../composables/useSlideInfo'
8 import { slidesTitle } from '../env'
9 import IconButton from '../internals/IconButton.vue'
10 import Modal from '../internals/Modal.vue'
11
12 const RE_SLIDE_HEADER = /^---\s*#(\d+)\s*$/
13
14 useHead({ title: `Notes Edit - ${slidesTitle}` })
15
16 const { slides } = useNav()
17
18 const showHelp = ref(false)
19 const note = ref(serializeNotes(slides.value))
20
21 function serializeNotes(slides: SlideRoute[]) {
22 const lines: string[] = []
23
24 for (const slide of slides) {
25 if (!slide.meta.slide.note?.trim())
26 continue
27 lines.push(`--- #${slide.no}`)
28 lines.push('')
29 lines.push(slide.meta.slide.note)
30 lines.push('')
31 }
32
33 return lines.join('\n')
34 }
35
36 function deserializeNotes(notes: string, slides: SlideRoute[]) {
37 const lines = notes.split(/^(---\s*#\d+\s*)$/gm)
38
39 lines.forEach((line, index) => {
40 const match = line.match(RE_SLIDE_HEADER)
41 if (match) {
42 const no = Number.parseInt(match[1])
43 const note = lines[index + 1].trim()
44 const slide = slides.find(s => s.no === no)
45 if (slide) {
46 slide.meta.slide.note = note
47 useDynamicSlideInfo(no).update({ note })
48 }
49 }
50 })
51 }
52
53 debouncedWatch(note, (value) => {
54 deserializeNotes(value, slides.value)
55 }, { debounce: 300 })
56 </script>
57
58 <template>
59 <Modal v-model="showHelp" class="px-6 py-4 flex flex-col gap-2">
60 <div class="flex gap-2 text-xl">
61 <div class="i-carbon:information my-auto" /> Help
62 </div>
63 <div class="prose dark:prose-invert">
64 <p>This is the batch notes editor. You can edit the notes for all the slides at once here.</p>
65
66 <p>The note for each slide are separated by <code>--- #[no]</code> lines, you might want to keep them while editing.</p>
67 </div>
68 <div class="flex my-1">
69 <button class="slidev-form-button" @click="showHelp = false">
70 Close
71 </button>
72 </div>
73 </Modal>
74 <div class="h-full">
75 <div class="slidev-glass-effect fixed bottom-5 right-5 rounded-full border border-main">
76 <IconButton title="Help" class="rounded-full" @click="showHelp = true">
77 <div class="i-carbon:help text-2xl" />
78 </IconButton>
79 </div>
80 <textarea
81 v-model="note"
82 class="prose dark:prose-invert resize-none p5 outline-none bg-transparent block h-full w-full! max-w-full! max-h-full! min-h-full! min-w-full!"
83 />
84 </div>
85 </template>
86
86 lines Plain Text