diff --git a/apps/desktop/package.json b/apps/desktop/package.json index 7b100f9..f72fe86 100644 --- a/apps/desktop/package.json +++ b/apps/desktop/package.json @@ -18,7 +18,10 @@ ], "asar": true, "win": { - "target": ["nsis", "dir"] + "target": [ + "nsis", + "dir" + ] }, "nsis": { "oneClick": false, @@ -54,6 +57,7 @@ "hotkeys-js": "^4.0.5", "katex": "^0.16.47", "lowlight": "^3.3.0", + "lucide-react": "^1.37.0", "markmap-view": "^0.18.12", "remark-gfm": "^4.0.1", "remark-math": "^6.0.0", @@ -66,10 +70,10 @@ "devDependencies": { "@playwright/test": "^1.62.1", "@types/d3-drag": "^3.0.7", - "@types/katex": "^0.16.8", "@types/d3-force": "^3.0.10", "@types/d3-selection": "^3.0.11", "@types/d3-zoom": "^3.0.8", + "@types/katex": "^0.16.8", "@types/node": "^20.0.0", "@types/react": "^18.3.0", "@types/react-dom": "^18.3.0", diff --git a/apps/desktop/src/renderer/App.tsx b/apps/desktop/src/renderer/App.tsx index d6e58ed..aac4ad2 100644 --- a/apps/desktop/src/renderer/App.tsx +++ b/apps/desktop/src/renderer/App.tsx @@ -21,6 +21,7 @@ import { useGlobalHotkeys } from './features/keymap/use-hotkeys'; import { useKeymap } from './features/keymap/keymap-service'; import { useLayout } from './features/shell/layout-store'; import { Resizer } from './features/shell/Resizer'; +import { StatusBar } from './features/shell/StatusBar'; import { EffectLayer } from './features/effects/EffectLayer'; import { useSettings } from './features/settings/settings-store'; import { SearchBox } from './features/search/SearchBox'; @@ -38,10 +39,19 @@ export function App() { const [showSettings, setShowSettings] = useState(false); const [showCheat, setShowCheat] = useState(false); const [showAppearance, setShowAppearance] = useState(false); + const [focused, setFocused] = useState(true); // 窗口聚焦状态——用于最外层边框的明暗切换 const appearance = useAppearance(); const settings = useSettings(); const layout = useLayout(); const switchToEditor = useCallback(() => setView('editor'), []); + // 窗口聚焦/失焦 → 边框强化/淡化 + useEffect(() => { + const onF = () => setFocused(true); + const onB = () => setFocused(false); + window.addEventListener('focus', onF); + window.addEventListener('blur', onB); + return () => { window.removeEventListener('focus', onF); window.removeEventListener('blur', onB); }; + }, []); useEffect(() => { loadVault(); loadTree(); restore(); appearance.load(); useKeymap.getState().load(); useSettings.getState().loadGpu(); }, []); useEffect(() => { if (activeId && tabs.length > 0) { const t = tabs.find(x => x.id === activeId); if (t) openDoc(t.path).then(() => { @@ -78,7 +88,7 @@ export function App() { // 编辑器样式随设置生效(FR-编辑器设置真实生效) useEffect(() => { document.documentElement.style.setProperty('--editor-font-size', settings.fontSize + 'px'); document.documentElement.style.setProperty('--editor-font-family', settings.fontFamily); document.documentElement.style.setProperty('--editor-white-space', settings.wordWrap ? 'pre-wrap' : 'pre'); }, [settings.fontSize, settings.fontFamily, settings.wordWrap]); return ( -
+
{appearance.bgImage &&
}
setView(v => v === 'editor' ? 'graph' : 'editor')} onSettings={() => setShowSettings(true)} onAppearance={() => setShowAppearance(true)} onToggleSidebar={() => layout.toggleSidebar()} onToggleMinimal={() => layout.toggleMinimal()} onToggleTabbar={() => layout.toggleTabbar()} minimal={layout.minimal} tabbarVisible={layout.tabbarVisible} /> @@ -107,6 +117,7 @@ export function App() { )} )}
+ diff --git a/apps/desktop/src/renderer/features/appearance/themes.ts b/apps/desktop/src/renderer/features/appearance/themes.ts index 0e2d8fa..b9c7677 100644 --- a/apps/desktop/src/renderer/features/appearance/themes.ts +++ b/apps/desktop/src/renderer/features/appearance/themes.ts @@ -35,4 +35,12 @@ export function applyTheme(params: ThemeParams, group?: 'dark' | 'light') { root.style.setProperty('--blur-px', params.blurPx + 'px'); root.style.setProperty('--surface-opacity', String(params.surfaceOpacity)); root.style.setProperty('--radius', params.radius + 'px'); + // ---- 设计 token(A档-4):圆角阶梯 + 间距,组件统一引用 ---- + root.style.setProperty('--radius-sm', '4px'); // 输入框/小元素 + root.style.setProperty('--radius-md', '6px'); // 按钮/菜单项 + root.style.setProperty('--radius-lg', params.radius + 'px'); // 面板/卡片 + root.style.setProperty('--space-1', '4px'); + root.style.setProperty('--space-2', '8px'); + root.style.setProperty('--space-3', '12px'); + root.style.setProperty('--space-4', '16px'); } diff --git a/apps/desktop/src/renderer/features/editor/Editor.tsx b/apps/desktop/src/renderer/features/editor/Editor.tsx index ad9d01e..ef6ab1a 100644 --- a/apps/desktop/src/renderer/features/editor/Editor.tsx +++ b/apps/desktop/src/renderer/features/editor/Editor.tsx @@ -1,6 +1,7 @@ import { useStore } from '../../store'; import { TiptapEditor } from './TiptapEditor'; import { MoreActions } from './MoreActions'; +import { BookOpen } from 'lucide-react'; import type { SaveState } from '../../store'; function saveLabel(s: SaveState): string { @@ -14,9 +15,14 @@ export function Editor() { const title = useStore(s => s.title); const saveState = useStore(s => s.saveState); if (!currentPath) { + // B档-8:空状态引导 return ( -
-
从左侧选择一篇笔记,或新建文档开始
+
+
+
+
从左侧选择一篇笔记,或新建文档开始
+
支持 Markdown · 代码高亮 · 公式 · 知识图谱
+
); } diff --git a/apps/desktop/src/renderer/features/editor/EditorToolbar.tsx b/apps/desktop/src/renderer/features/editor/EditorToolbar.tsx index 5e8f420..e59f865 100644 --- a/apps/desktop/src/renderer/features/editor/EditorToolbar.tsx +++ b/apps/desktop/src/renderer/features/editor/EditorToolbar.tsx @@ -4,14 +4,15 @@ import { useEditorRef } from './editor-context'; import { useDialog } from '../dialog/dialog-store'; import { invoke } from '../../ipc-client'; import { IPC } from '@hunter/shared'; +import { Star, Undo2, Redo2, Bold, Italic, Strikethrough, Code, Eraser, Quote, Heading1, Heading2, Heading3, List, ListOrdered, SquareCode, Table, Link, ImagePlus, Globe } from 'lucide-react'; // FR-M4:编辑区星标入口 function StarButton() { const { meta, toggleStar } = useStore(); - return ; + return ; } -const btn: React.CSSProperties = { minWidth: 28, height: 26, border: 'none', background: 'transparent', color: 'var(--text-secondary)', cursor: 'pointer', borderRadius: 4, fontSize: 13 }; +const btn: React.CSSProperties = { minWidth: 28, height: 26, border: 'none', background: 'transparent', color: 'var(--text-secondary)', cursor: 'pointer', borderRadius: 'var(--radius-md)', fontSize: 13, display: 'inline-flex', alignItems: 'center', justifyContent: 'center' }; function T({ onClick, title, children, disabled }: { onClick: () => void; title: string; children: React.ReactNode; disabled?: boolean }) { return