157 lines
4.7 KiB
Vue
157 lines
4.7 KiB
Vue
<script setup>
|
|
import { ref, watch, onMounted } from 'vue'
|
|
import { useRoute, useRouter } from 'vue-router'
|
|
import { useNotesStore } from '@/stores/notes'
|
|
import { ArrowLeft, Edit3, Eye, Columns } from 'lucide-vue-next'
|
|
|
|
const route = useRoute()
|
|
const router = useRouter()
|
|
const notesStore = useNotesStore()
|
|
|
|
const note = ref(null)
|
|
const content = ref('')
|
|
const editMode = ref('edit') // 'edit' | 'preview' | 'split'
|
|
const isSaving = ref(false)
|
|
|
|
onMounted(async () => {
|
|
await loadNote()
|
|
})
|
|
|
|
watch(() => route.params.id, loadNote)
|
|
|
|
async function loadNote() {
|
|
const id = route.params.id
|
|
if (!id) return
|
|
await notesStore.openNote(id)
|
|
if (notesStore.currentNote) {
|
|
note.value = notesStore.currentNote
|
|
content.value = notesStore.currentNote.content || ''
|
|
}
|
|
}
|
|
|
|
async function handleSave() {
|
|
if (!note.value) return
|
|
isSaving.value = true
|
|
await notesStore.saveNote(note.value.id, content.value)
|
|
isSaving.value = false
|
|
}
|
|
|
|
// Auto-save on content change
|
|
let saveTimer = null
|
|
watch(content, () => {
|
|
clearTimeout(saveTimer)
|
|
saveTimer = setTimeout(handleSave, 2000)
|
|
})
|
|
</script>
|
|
|
|
<template>
|
|
<div class="h-full flex flex-col">
|
|
<!-- 头部工具栏 -->
|
|
<div
|
|
class="flex items-center justify-between px-6 py-3 border-b"
|
|
:style="{ borderColor: 'var(--p-surface-200)' }"
|
|
>
|
|
<div class="flex items-center gap-3">
|
|
<button
|
|
class="p-1.5 rounded-md transition-colors"
|
|
:style="{ color: 'var(--p-surface-500)' }"
|
|
@click="router.back()"
|
|
>
|
|
<ArrowLeft :size="18" />
|
|
</button>
|
|
<h1
|
|
v-if="note"
|
|
class="text-lg font-semibold truncate"
|
|
:style="{ color: 'var(--p-surface-800)' }"
|
|
>
|
|
{{ note.title }}
|
|
</h1>
|
|
</div>
|
|
|
|
<!-- 视图模式切换 -->
|
|
<div class="flex items-center gap-1 rounded-lg p-0.5" :style="{ backgroundColor: 'var(--p-surface-100)' }">
|
|
<button
|
|
class="p-1.5 rounded-md transition-colors"
|
|
:style="{
|
|
backgroundColor: editMode === 'edit' ? 'var(--p-surface-0)' : 'transparent',
|
|
color: editMode === 'edit' ? 'var(--p-primary-600)' : 'var(--p-surface-500)',
|
|
}"
|
|
@click="editMode = 'edit'"
|
|
title="编辑模式"
|
|
>
|
|
<Edit3 :size="16" />
|
|
</button>
|
|
<button
|
|
class="p-1.5 rounded-md transition-colors"
|
|
:style="{
|
|
backgroundColor: editMode === 'preview' ? 'var(--p-surface-0)' : 'transparent',
|
|
color: editMode === 'preview' ? 'var(--p-primary-600)' : 'var(--p-surface-500)',
|
|
}"
|
|
@click="editMode = 'preview'"
|
|
title="预览模式"
|
|
>
|
|
<Eye :size="16" />
|
|
</button>
|
|
<button
|
|
class="p-1.5 rounded-md transition-colors"
|
|
:style="{
|
|
backgroundColor: editMode === 'split' ? 'var(--p-surface-0)' : 'transparent',
|
|
color: editMode === 'split' ? 'var(--p-primary-600)' : 'var(--p-surface-500)',
|
|
}"
|
|
@click="editMode = 'split'"
|
|
title="双栏模式"
|
|
>
|
|
<Columns :size="16" />
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 内容区 -->
|
|
<div class="flex-1 overflow-hidden">
|
|
<div v-if="!note" class="flex items-center justify-center h-full">
|
|
<p :style="{ color: 'var(--p-surface-400)' }">加载中...</p>
|
|
</div>
|
|
|
|
<div v-else class="h-full flex">
|
|
<!-- 编辑区 -->
|
|
<div
|
|
v-if="editMode === 'edit' || editMode === 'split'"
|
|
class="h-full overflow-y-auto"
|
|
:class="editMode === 'split' ? 'w-1/2 border-r' : 'w-full'"
|
|
:style="{ borderColor: 'var(--p-surface-200)' }"
|
|
>
|
|
<textarea
|
|
v-model="content"
|
|
class="w-full h-full p-6 text-sm font-mono resize-none outline-none"
|
|
:style="{
|
|
backgroundColor: 'var(--p-surface-0)',
|
|
color: 'var(--p-surface-700)',
|
|
}"
|
|
placeholder="开始编写 Markdown..."
|
|
/>
|
|
</div>
|
|
|
|
<!-- 预览区 -->
|
|
<div
|
|
v-if="editMode === 'preview' || editMode === 'split'"
|
|
class="h-full overflow-y-auto p-6"
|
|
:class="editMode === 'split' ? 'w-1/2' : 'w-full'"
|
|
>
|
|
<div class="prose prose-sm max-w-none">
|
|
<pre class="whitespace-pre-wrap text-sm" :style="{ color: 'var(--p-surface-700)' }">{{ content }}</pre>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 状态栏 -->
|
|
<div
|
|
class="flex items-center justify-between px-6 py-1.5 border-t text-xs"
|
|
:style="{ borderColor: 'var(--p-surface-200)', color: 'var(--p-surface-400)' }"
|
|
>
|
|
<span>{{ isSaving ? '保存中...' : '已保存' }}</span>
|
|
<span>{{ content.length }} 字符</span>
|
|
</div>
|
|
</div>
|
|
</template>
|