feat(M9): FR-K1/K3/K4/K6/K7 快捷键体系——多作用域(global/app/editor)+Scope.resolveActive 裁决(K1); 编辑器类绑定 find/bold/italic/strike/inlineCode/clearFormat(K3); 冲突数量汇总 conflictCount+SettingsPanel 顶部警示(K4); CheatSheet 从 store 动态渲染+formatCombo Mac 适配(K6); Ctrl+F 捕获阶段 keydown 拦截宿主查找+FindReplace 切换(K7); keymap-enhanced E2E 2 项
This commit is contained in:
@@ -1,29 +1,31 @@
|
||||
import { IPC } from '@hunter/shared';
|
||||
import { useKeymap, formatCombo, type Scope } from './keymap-service';
|
||||
|
||||
const GROUPS: [string, [string, string][]][] = [
|
||||
['全局', [['Ctrl+N','新建文档'],['Ctrl+S','保存'],['Ctrl+Shift+F','全库搜索'],['Ctrl+Shift+L','大纲面板'],['?','快捷键帮助'],['Esc','关闭弹层']]],
|
||||
['查找替换', [['Ctrl+F','查找'],['Ctrl+H','替换']]],
|
||||
['标题段落', [['Ctrl+1~6','一至六级标题'],['Ctrl+0','段落'],['Ctrl+Shift+-','分割线']]],
|
||||
['行内格式', [['Ctrl+B','加粗'],['Ctrl+I','斜体'],['Alt+Shift+5','删除线'],['Ctrl+`','行内代码'],['Ctrl+Shift+Q','引用'],['Ctrl+\\','清除格式']]],
|
||||
['列表', [['Ctrl+L','无序列表'],['Ctrl+Shift+O','有序列表'],['Ctrl+]','增加缩进'],['Ctrl+[','减少缩进']]],
|
||||
['代码与公式', [['Ctrl+Shift+M','代码块'],['Ctrl+Shift+9','数学公式']]],
|
||||
['插入', [['Ctrl+K','链接'],['Ctrl+Shift+I','图片'],['Ctrl+Shift+T','表格']]],
|
||||
['编辑', [['Ctrl+Z','撤销'],['Ctrl+Y','重做']]],
|
||||
['块操作', [['Alt+↑/↓','上移/下移当前块'],['Alt+Backspace','删除当前块']]],
|
||||
];
|
||||
const SCOPE_LABELS: Record<Scope, string> = { global: '全局', app: '应用级', editor: '编辑器' };
|
||||
const SCOPE_ORDER: Scope[] = ['global', 'app', 'editor'];
|
||||
|
||||
export function CheatSheet({ onClose }: { onClose: () => void }) {
|
||||
const bindings = useKeymap(s => s.bindings);
|
||||
return (
|
||||
<div onClick={e => { if (e.target === e.currentTarget) onClose(); }} style={{ position: 'fixed', inset: 0, background: 'rgba(0,0,0,0.5)', display: 'flex', alignItems: 'center', justifyContent: 'center', zIndex: 1500 }}>
|
||||
<div style={{ width: 480, maxHeight: '80vh', overflow: 'auto', background: 'var(--bg-secondary)', border: '1px solid var(--control-border)', borderRadius: 10, padding: 20, boxShadow: '0 8px 32px rgba(0,0,0,0.5)' }}>
|
||||
<div style={{ display: 'flex', justifyContent: 'space-between', marginBottom: 16 }}><strong style={{ fontSize: 15 }}>快捷键速查</strong><button onClick={onClose} style={{ background: 'none', border: 'none', color: 'var(--text-tertiary)', cursor: 'pointer', fontSize: 16 }}>✕</button></div>
|
||||
{GROUPS.map(([title, items]) => (
|
||||
<div key={title} style={{ marginBottom: 14 }}>
|
||||
<div style={{ opacity: 0.5, fontSize: 12, marginBottom: 6 }}>{title}</div>
|
||||
{items.map(([k, v]) => (<div key={k} style={{ display: 'flex', justifyContent: 'space-between', padding: '3px 0', fontSize: 13 }}><span style={{ color: 'var(--text-primary)' }}>{v}</span><code style={{ background: 'var(--bg-secondary)', padding: '1px 6px', borderRadius: 3, color: 'var(--accent-text)' }}>{k}</code></div>))}
|
||||
</div>
|
||||
))}
|
||||
{SCOPE_ORDER.map(scope => {
|
||||
const items = bindings.filter(b => b.scope === scope);
|
||||
if (items.length === 0) return null;
|
||||
return (
|
||||
<div key={scope} style={{ marginBottom: 14 }}>
|
||||
<div style={{ opacity: 0.5, fontSize: 12, marginBottom: 6 }}>{SCOPE_LABELS[scope]}</div>
|
||||
{items.map(b => (
|
||||
<div key={b.id} style={{ display: 'flex', justifyContent: 'space-between', padding: '3px 0', fontSize: 13 }}>
|
||||
<span style={{ color: 'var(--text-primary)' }}>{b.label}</span>
|
||||
<code style={{ background: 'var(--bg-secondary)', padding: '1px 6px', borderRadius: 3, color: 'var(--accent-text)' }}>{formatCombo(b.combo)}</code>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
<div style={{ marginTop: 12, opacity: 0.4, fontSize: 11 }}>? 打开此面板 · Esc 关闭弹层</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user