feat(M5/M1): FR-A12/V4 过渡动效+最近库下拉——styles.css 全局 transition+panel-slide-in keyframe+按钮悬停(A12); SettingsPanel/CheatSheet 加 panel-slide-in; Toolbar 最近库下拉快速切换(最多5)+高亮当前库(V4); recents-transition E2E 1 项
This commit is contained in:
@@ -14,7 +14,7 @@ export function CheatSheet({ onClose }: { onClose: () => void }) {
|
||||
}, [onClose]);
|
||||
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 className="panel-slide-in" 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>
|
||||
{SCOPE_ORDER.map(scope => {
|
||||
const items = bindings.filter(b => b.scope === scope);
|
||||
|
||||
@@ -47,7 +47,7 @@ export function SettingsPanel({ onClose }: { onClose: () => void }) {
|
||||
}, [recId, onClose]);
|
||||
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: 'var(--bg-secondary)', border: '1px solid var(--control-border)', borderRadius: 10, padding: 20, boxShadow: '0 8px 32px rgba(0,0,0,0.5)' }}>
|
||||
<div className="panel-slide-in" style={{ width: 520, 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>
|
||||
|
||||
@@ -3,6 +3,7 @@ import { invoke } from '../../ipc-client';
|
||||
import { IPC } from '@hunter/shared';
|
||||
import { useDialog } from '../dialog/dialog-store';
|
||||
import { useTabs } from '../tabs/tab-store';
|
||||
import { useState } from 'react';
|
||||
|
||||
// 极简浮层通知(FR-B1,后续抽组件)
|
||||
function notify(msg: string) {
|
||||
@@ -15,8 +16,9 @@ function notify(msg: string) {
|
||||
const alert2 = notify;
|
||||
|
||||
export function Toolbar() {
|
||||
const { loadTree, loadVault, openDoc } = useStore();
|
||||
const { loadTree, loadVault, openDoc, vault } = useStore();
|
||||
const { showInput } = useDialog();
|
||||
const [recentsOpen, setRecentsOpen] = useState(false);
|
||||
const newDoc = async () => {
|
||||
const name = await showInput('新建文档', '输入文档标题…');
|
||||
if (!name) return;
|
||||
@@ -51,6 +53,24 @@ export function Toolbar() {
|
||||
<button onClick={newFolder} style={btn}>📁 新建文件夹</button>
|
||||
<button onClick={importFiles} style={btn}>📥 导入</button>
|
||||
<button onClick={switchVault} style={btn}>⇄ 切换库</button>
|
||||
{/* FR-V4:最近库下拉快速切换 */}
|
||||
{vault?.recents && vault.recents.length > 1 && (
|
||||
<div style={{ position: 'relative' }}>
|
||||
<button onClick={() => setRecentsOpen(o => !o)} style={btn} data-testid="recents-toggle">最近库 ▾</button>
|
||||
{recentsOpen && (
|
||||
<div style={{ position: 'absolute', left: 0, top: 30, background: 'var(--bg-secondary)', border: '1px solid var(--control-border)', borderRadius: 6, padding: 4, zIndex: 500, minWidth: 200, boxShadow: '0 4px 12px rgba(0,0,0,0.3)' }} onMouseLeave={() => setRecentsOpen(false)}>
|
||||
{vault.recents.map(r => (
|
||||
<div key={r} onClick={async () => { setRecentsOpen(false); await useStore.getState().saveNow(); await invoke(IPC.vaultSwitch, { root: r }); useTabs.getState().closeAll(); useStore.getState().resetEditor(); await loadVault(); await loadTree(); }}
|
||||
style={{ padding: '6px 10px', cursor: 'pointer', borderRadius: 4, fontSize: 12, color: r === vault.currentRoot ? 'var(--accent)' : 'var(--text-primary)', whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}
|
||||
onMouseEnter={e => (e.currentTarget.style.background = 'var(--control-border)')}
|
||||
onMouseLeave={e => (e.currentTarget.style.background = 'transparent')}>
|
||||
{r === vault.currentRoot ? '★ ' : ''}{r.split(/[\\/]/).pop()}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user