feat(editor): 将 Milkdown/ProseMirror 替换为 @metona-team/metona-editor v0.1.3 - 三模式视图 (edit/split/preview) 由编辑器内置工具栏切换 - searchReplace + imagePaste 预设插件 - unified/rehype 渲染管线通过 render 钩子集成 - 主题双向同步 (应用暗色模式 ↔ 编辑器主题) feat(toast): metona-toast 迁移为 @metona-team/metona-toast v2.0.1 refactor: 删除冗余组件与代码 - 移除 SourceEditor、Preview、SearchReplace、EditorToolbar、useMilkdown - 移除 StatusBar 组件及状态栏扩展架构(编辑器内置底栏替代) - 移除 useSettings、useStatusBarItem、useStatusBarItems、statusBarStore - 移除 EditMode/PreviewMode/SourceMode 图标 refactor(ui): 简化布局 - 工具栏移除模式切换按钮,新增自动保存开关 - useKeyboard 移除 Ctrl+1/2/3/B/I 快捷键 - Editor 三模式统一由 MetonaEditor 容器渲染 chore: 版本号 v0.3.13 → v0.4.0 docs: 全面更新 README/DESIGN/CONTRIBUTING/DEVSETUP
52 lines
1.9 KiB
TypeScript
52 lines
1.9 KiB
TypeScript
import { useEffect, useCallback } from 'react'
|
|
import { useTabStore } from '../stores/tabStore'
|
|
|
|
/**
|
|
* 全局键盘快捷键 hook。
|
|
* MetonaEditor 内置工具栏处理格式化和模式切换(Ctrl+B/I/1/2/3),
|
|
* 本 hook 仅处理应用级快捷键。
|
|
*/
|
|
export function useKeyboard(handleOpenFile: () => void, handleSave: () => void, handleSaveAs: () => void) {
|
|
const handleKeydown = useCallback((e: KeyboardEvent) => {
|
|
const isCtrl = e.ctrlKey || e.metaKey
|
|
|
|
if (isCtrl && e.key === 'o') { e.preventDefault(); handleOpenFile(); return }
|
|
if (isCtrl && e.key === 's' && !e.shiftKey) { e.preventDefault(); handleSave(); return }
|
|
if (isCtrl && e.shiftKey && e.key === 'S') { e.preventDefault(); handleSaveAs(); return }
|
|
|
|
const tabState = useTabStore.getState()
|
|
if (isCtrl && e.key === 't') { e.preventDefault(); tabState.createTab(null, ''); return }
|
|
if (isCtrl && e.key === 'w') {
|
|
e.preventDefault()
|
|
if (tabState.activeTabId) tabState.closeTab(tabState.activeTabId)
|
|
return
|
|
}
|
|
|
|
// Ctrl+Tab / Ctrl+Shift+Tab — MRU 顺序切换
|
|
if (isCtrl && e.key === 'Tab') {
|
|
e.preventDefault()
|
|
const { tabs, activeTabId, mruStack } = tabState
|
|
if (tabs.length > 1) {
|
|
if (mruStack.length > 0) {
|
|
const targetId = mruStack[0]
|
|
if (tabs.find(t => t.id === targetId)) {
|
|
tabState.switchToTab(targetId)
|
|
return
|
|
}
|
|
}
|
|
const idx = tabs.findIndex(t => t.id === activeTabId)
|
|
const next = e.shiftKey
|
|
? (idx - 1 + tabs.length) % tabs.length
|
|
: (idx + 1) % tabs.length
|
|
tabState.switchToTab(tabs[next].id)
|
|
}
|
|
return
|
|
}
|
|
}, [handleOpenFile, handleSave, handleSaveAs])
|
|
|
|
useEffect(() => {
|
|
document.addEventListener('keydown', handleKeydown)
|
|
return () => document.removeEventListener('keydown', handleKeydown)
|
|
}, [handleKeydown])
|
|
}
|