first commit
This commit is contained in:
156
src/views/NoteDetailView.vue
Normal file
156
src/views/NoteDetailView.vue
Normal file
@@ -0,0 +1,156 @@
|
||||
<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>
|
||||
Reference in New Issue
Block a user