Files
tunji2/src/views/NoteDetailView.vue
2026-06-01 17:28:00 +08:00

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>