feat: 快捷键录入重绑(FR-K3,keymap:load/save IPC+config.json,SettingsPanel 录入 UI+冲突检测,use-hotkeys 读 store 实时生效,重开恢复)
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
import { useState } from 'react';
|
||||
import { useState, useEffect } from 'react';
|
||||
import { useSettings } from './settings-store';
|
||||
import { useKeymap } from '../keymap/keymap-service';
|
||||
|
||||
const pageBtn: React.CSSProperties = { padding: '8px 14px', border: 'none', background: 'transparent', color: '#888', cursor: 'pointer', borderBottom: '2px solid transparent', fontSize: 13 };
|
||||
const row: React.CSSProperties = { display: 'flex', alignItems: 'center', justifyContent: 'space-between', padding: '10px 0', borderBottom: '1px solid #2a2a3a' };
|
||||
@@ -9,6 +10,30 @@ const toggle = (on: boolean): React.CSSProperties => ({ width: 36, height: 20, b
|
||||
export function SettingsPanel({ onClose }: { onClose: () => void }) {
|
||||
const s = useSettings();
|
||||
const [page, setPage] = useState<'keymap' | 'editor' | 'path' | 'other'>('editor');
|
||||
const { bindings, setCombo, resetAll, save: saveKeymap, conflicts } = useKeymap();
|
||||
const [recId, setRecId] = useState<string | null>(null);
|
||||
useEffect(() => {
|
||||
if (!recId) return;
|
||||
const onKey = (e: KeyboardEvent) => {
|
||||
e.preventDefault();
|
||||
if (e.key === 'Escape') { setRecId(null); return; }
|
||||
if (!e.ctrlKey && !e.metaKey && !e.altKey) return;
|
||||
const parts: string[] = [];
|
||||
if (e.ctrlKey) parts.push('ctrl');
|
||||
if (e.shiftKey) parts.push('shift');
|
||||
if (e.altKey) parts.push('alt');
|
||||
if (e.metaKey) parts.push('meta');
|
||||
const k = e.key.toLowerCase();
|
||||
if (k.length > 1) return;
|
||||
parts.push(k);
|
||||
const combo = parts.join('+');
|
||||
setCombo(recId, combo);
|
||||
void saveKeymap();
|
||||
setRecId(null);
|
||||
};
|
||||
window.addEventListener('keydown', onKey, true);
|
||||
return () => window.removeEventListener('keydown', onKey, true);
|
||||
}, [recId, setCombo, saveKeymap]);
|
||||
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: 520, maxHeight: '80vh', overflow: 'auto', background: '#1e1e2a', border: '1px solid #3a3a4a', borderRadius: 10, padding: 20, boxShadow: '0 8px 32px rgba(0,0,0,0.5)' }}>
|
||||
@@ -30,7 +55,24 @@ export function SettingsPanel({ onClose }: { onClose: () => void }) {
|
||||
</>}
|
||||
{page === 'other' && <div style={row}><span style={lbl}>删除前确认</span><button onClick={() => s.set('confirmDelete', !s.confirmDelete)} style={toggle(s.confirmDelete)}><span style={dot(s.confirmDelete)} /></button></div>}
|
||||
{page === 'path' && <div style={{ ...lbl, opacity: 0.6, padding: '12px 0' }}>文件路径设置将在 M9 完善(默认库路径配置)</div>}
|
||||
{page === 'keymap' && <div style={{ ...lbl, opacity: 0.6, padding: '12px 0' }}>快捷键自定义与冲突检测已就绪(见速查面板 ?)。键位录入 UI 在此页完善。</div>}
|
||||
{page === 'keymap' && <>
|
||||
<div style={{ ...lbl, opacity: 0.6, marginBottom: 8 }}>点击「录入」后按下新组合键(需含 Ctrl/Meta/Alt);Esc 取消</div>
|
||||
{bindings.map(b => {
|
||||
const cf = conflicts();
|
||||
const inConflict = Object.values(cf).some(ids => ids.includes(b.id));
|
||||
return (
|
||||
<div key={b.id} style={row}>
|
||||
<span style={lbl}>{b.label}</span>
|
||||
<span style={{ display: 'flex', gap: 8, alignItems: 'center' }}>
|
||||
{inConflict && <span style={{ color: '#e88', fontSize: 11 }}>冲突</span>}
|
||||
<code style={{ background: '#15151f', padding: '1px 6px', borderRadius: 3, color: recId === b.id ? '#fc4' : '#9cf', minWidth: 90, textAlign: 'center' }}>{recId === b.id ? '按下组合键…' : b.combo}</code>
|
||||
<button onClick={() => setRecId(b.id)} style={{ ...sel, cursor: 'pointer' }}>录入</button>
|
||||
</span>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
<button onClick={async () => { resetAll(); await saveKeymap(); }} style={{ marginTop: 12, ...sel, cursor: 'pointer' }}>重置默认</button>
|
||||
</>}
|
||||
<div style={{ marginTop: 16, fontSize: 12, opacity: 0.5 }}>设置已自动保存</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user