release: v0.6.0 — 内置解析器迁移 / Toast 全面接入 / Sqlark 深度集成

- 渲染管线迁移至 MetonaEditor 内置解析器,移除 unified/rehype 全家桶(9 个依赖)
- 修复相对路径图片修复的目录前缀碰撞与路径解析 bug
- ConfirmDialog/useConfirm/LoadingSpinner/useDocStats 移除,改用 MeToast.confirm/loading/promise
- 新增状态栏(字数/行数/阅读时间/光标位置)、Zen 模式、数据备份导出导入
- Sqlark: 版本化迁移(addMigration/migrateTo)、subscribe 表变更、备份 exportAll/importTable
- 数据库损坏自愈:异常退出残留残缺 SSTable 导致打开失败时自动重建
- 大纲导航改用 scrollToLine 官方 API
- 修复 rollup 平台包互删(postinstall 自动补齐)+ 集成测试(fake-indexeddb)
This commit is contained in:
thzxx
2026-08-09 16:50:06 +08:00
parent 20eb39efc5
commit ee5f35177e
71 changed files with 4837 additions and 4345 deletions
+86 -56
View File
@@ -1,56 +1,86 @@
import { create } from 'zustand'
import type { ViewMode, ThemeMode } from '../types/settings'
import type { MarkdownEditor } from '@metona-team/metona-editor'
// Module-level getter for the MetonaEditor instance
// Used by OutlinePanel for heading navigation
let _getEditor: (() => MarkdownEditor | null) | null = null
export function setMetonaEditorGetter(fn: () => MarkdownEditor | null) {
_getEditor = fn
}
export function getMetonaEditor(): MarkdownEditor | null {
return _getEditor ? _getEditor() : null
}
const THEME_CYCLE: ThemeMode[] = ['light', 'dark', 'warm']
interface EditorState {
viewMode: ViewMode
themeMode: ThemeMode
// AR-03: 外部修改检测状态,替代 DOM CustomEvent
externallyModified: { filePath: string } | null
// UX-02: 全局加载状态
loadingStates: Record<string, boolean>
setViewMode: (mode: ViewMode) => void
setThemeMode: (mode: ThemeMode) => void
cycleTheme: () => ThemeMode
setExternallyModified: (info: { filePath: string } | null) => void
// UX-02: 加载状态管理
setLoading: (key: string, loading: boolean) => void
isLoading: (key: string) => boolean
}
export const useEditorStore = create<EditorState>((set, get) => ({
viewMode: 'editor',
themeMode: 'light',
externallyModified: null,
loadingStates: {},
setViewMode: (mode: ViewMode) => set({ viewMode: mode }),
setThemeMode: (mode: ThemeMode) => set({ themeMode: mode }),
cycleTheme: () => {
const current = get().themeMode
const idx = THEME_CYCLE.indexOf(current)
const next = THEME_CYCLE[(idx + 1) % THEME_CYCLE.length]
set({ themeMode: next })
return next
},
setExternallyModified: (info: { filePath: string } | null) => set({ externallyModified: info }),
setLoading: (key: string, loading: boolean) => set(state => ({
loadingStates: { ...state.loadingStates, [key]: loading }
})),
isLoading: (key: string) => get().loadingStates[key] ?? false
}))
import { create } from 'zustand'
import type { ViewMode, ThemeMode } from '../types/settings'
import type { MarkdownEditor } from '@metona-team/metona-editor'
// Module-level getter for the MetonaEditor instance
// Used by OutlinePanel for heading navigation
let _getEditor: (() => MarkdownEditor | null) | null = null
export function setMetonaEditorGetter(fn: () => MarkdownEditor | null) {
_getEditor = fn
}
export function getMetonaEditor(): MarkdownEditor | null {
return _getEditor ? _getEditor() : null
}
const THEME_CYCLE: ThemeMode[] = ['light', 'dark', 'warm']
/** v0.6.0: 编辑器实时状态(由 Editor 组件绑定事件写入,状态栏消费) */
export interface EditorLiveStats {
characters: number
words: number
chineseChars: number
englishWords: number
lines: number
readingTime: number
}
export interface EditorCursor {
line: number
column: number
}
interface EditorState {
viewMode: ViewMode
themeMode: ThemeMode
// AR-03: 外部修改检测状态,替代 DOM CustomEvent
externallyModified: { filePath: string } | null
// UX-02: 全局加载状态
loadingStates: Record<string, boolean>
// v0.6.0: 编辑器实时状态
stats: EditorLiveStats | null
cursor: EditorCursor | null
zenMode: boolean
setViewMode: (mode: ViewMode) => void
setThemeMode: (mode: ThemeMode) => void
cycleTheme: () => ThemeMode
setExternallyModified: (info: { filePath: string } | null) => void
// UX-02: 加载状态管理
setLoading: (key: string, loading: boolean) => void
isLoading: (key: string) => boolean
// v0.6.0: 编辑器状态同步
setStats: (stats: EditorLiveStats | null) => void
setCursor: (cursor: EditorCursor | null) => void
setZenMode: (zen: boolean) => void
}
export const useEditorStore = create<EditorState>((set, get) => ({
viewMode: 'editor',
themeMode: 'light',
externallyModified: null,
loadingStates: {},
stats: null,
cursor: null,
zenMode: false,
setViewMode: (mode: ViewMode) => set({ viewMode: mode }),
setThemeMode: (mode: ThemeMode) => set({ themeMode: mode }),
cycleTheme: () => {
const current = get().themeMode
const idx = THEME_CYCLE.indexOf(current)
const next = THEME_CYCLE[(idx + 1) % THEME_CYCLE.length]
set({ themeMode: next })
return next
},
setExternallyModified: (info: { filePath: string } | null) => set({ externallyModified: info }),
setLoading: (key: string, loading: boolean) =>
set(state => ({
loadingStates: { ...state.loadingStates, [key]: loading },
})),
isLoading: (key: string) => get().loadingStates[key] ?? false,
setStats: (stats: EditorLiveStats | null) => set({ stats }),
setCursor: (cursor: EditorCursor | null) => set({ cursor }),
setZenMode: (zenMode: boolean) => set({ zenMode }),
}))