feat(editor): add markdown presets, heading folding and external file refresh

This commit is contained in:
2026-09-06 12:57:09 +08:00
parent 415efc4444
commit 8ad1db33f7
43 changed files with 901 additions and 54 deletions
+8 -2
View File
@@ -19,6 +19,7 @@ export interface VaultInfo {
}
let cachedTree: FileNode[] | null = null
let treeRequestVersion = 0
const noteIdByPath = new Map<string, string>()
const typeByPath = new Map<string, FileNode['type']>()
@@ -88,6 +89,7 @@ export async function getRecentVaults(): Promise<VaultInfo[]> {
}
export async function openVault(path: string): Promise<VaultInfo> {
treeRequestVersion++
const snapshot = await apiClient.post<ApiWorkspaceSnapshot>('/api/workspace/open', { path }, { timeoutMs: 15000 })
cacheEntries(snapshot.items)
return {
@@ -104,7 +106,9 @@ export async function createVault(path: string, name: string): Promise<VaultInfo
}
export async function refreshTree(): Promise<FileNode[]> {
const entries = await apiClient.get<ApiWorkspaceEntry[]>('/api/workspace/tree')
const version = ++treeRequestVersion
const entries = await apiClient.get<ApiWorkspaceEntry[]>('/api/workspace/tree', { timeoutMs: 10000 })
if (version !== treeRequestVersion) return cachedTree ?? []
return cacheEntries(entries)
}
@@ -122,10 +126,12 @@ export async function getNoteId(filePath: string): Promise<string> {
return requireNoteId(filePath)
}
export async function saveFileContent(filePath: string, content: string): Promise<void> {
export async function saveFileContent(filePath: string, content: string, expectedContent?: string): Promise<void> {
const metadata = splitNoteMetadata(content)
const expectedHash = expectedContent === undefined ? undefined : Array.from(new Uint8Array(await crypto.subtle.digest('SHA-256', new TextEncoder().encode(expectedContent)))).map(byte => byte.toString(16).padStart(2, '0')).join('')
await noteService.updateNote(await requireNoteId(filePath), {
markdown: content,
...(expectedHash ? { expected_content_hash: expectedHash } : {}),
// Explicit [] clears the index; absent tags retain API-managed tags.
...(metadata?.hasTags ? { tags: metadata.tags } : {}),
})