This commit is contained in:
cc
2026-03-12 23:52:49 +08:00
13 changed files with 888 additions and 158 deletions

View File

@@ -138,10 +138,6 @@ function App() {
const effectiveMode = mode === 'system' ? (systemDark ?? mq.matches ? 'dark' : 'light') : mode
document.documentElement.setAttribute('data-theme', currentTheme)
document.documentElement.setAttribute('data-mode', effectiveMode)
const symbolColor = effectiveMode === 'dark' ? '#ffffff' : '#1a1a1a'
if (!isOnboardingWindow && !isNotificationWindow) {
window.electronAPI.window.setTitleBarOverlay({ symbolColor })
}
}
applyMode(themeMode)

View File

@@ -3,6 +3,7 @@
background: var(--bg-secondary);
display: flex;
align-items: center;
justify-content: space-between;
padding-left: 16px;
padding-right: 16px;
border-bottom: 1px solid var(--border-color);
@@ -57,3 +58,35 @@
color: var(--text-primary);
}
}
.title-window-controls {
display: inline-flex;
align-items: center;
gap: 6px;
-webkit-app-region: no-drag;
}
.title-window-control-btn {
width: 28px;
height: 28px;
padding: 0;
border: none;
border-radius: 8px;
background: transparent;
color: var(--text-tertiary);
display: inline-flex;
align-items: center;
justify-content: center;
cursor: pointer;
transition: background 0.2s ease, color 0.2s ease;
&:hover {
background: var(--bg-tertiary);
color: var(--text-primary);
}
&.is-close:hover {
background: #e5484d;
color: #fff;
}
}

View File

@@ -1,13 +1,34 @@
import { PanelLeftClose, PanelLeftOpen } from 'lucide-react'
import { useEffect, useState } from 'react'
import { Copy, Minus, PanelLeftClose, PanelLeftOpen, Square, X } from 'lucide-react'
import './TitleBar.scss'
interface TitleBarProps {
title?: string
sidebarCollapsed?: boolean
onToggleSidebar?: () => void
showWindowControls?: boolean
}
function TitleBar({ title, sidebarCollapsed = false, onToggleSidebar }: TitleBarProps = {}) {
function TitleBar({
title,
sidebarCollapsed = false,
onToggleSidebar,
showWindowControls = true
}: TitleBarProps = {}) {
const [isMaximized, setIsMaximized] = useState(false)
useEffect(() => {
if (!showWindowControls) return
void window.electronAPI.window.isMaximized().then(setIsMaximized).catch(() => {
setIsMaximized(false)
})
return window.electronAPI.window.onMaximizeStateChanged((maximized) => {
setIsMaximized(maximized)
})
}, [showWindowControls])
return (
<div className="title-bar">
<div className="title-brand">
@@ -25,6 +46,37 @@ function TitleBar({ title, sidebarCollapsed = false, onToggleSidebar }: TitleBar
</button>
) : null}
</div>
{showWindowControls ? (
<div className="title-window-controls">
<button
type="button"
className="title-window-control-btn"
aria-label="最小化"
title="最小化"
onClick={() => window.electronAPI.window.minimize()}
>
<Minus size={14} />
</button>
<button
type="button"
className="title-window-control-btn"
aria-label={isMaximized ? '还原' : '最大化'}
title={isMaximized ? '还原' : '最大化'}
onClick={() => window.electronAPI.window.maximize()}
>
{isMaximized ? <Copy size={12} /> : <Square size={12} />}
</button>
<button
type="button"
className="title-window-control-btn is-close"
aria-label="关闭"
title="关闭"
onClick={() => window.electronAPI.window.close()}
>
<X size={14} />
</button>
</div>
) : null}
</div>
)
}

View File

@@ -11,6 +11,8 @@ export interface ElectronAPI {
window: {
minimize: () => void
maximize: () => void
isMaximized: () => Promise<boolean>
onMaximizeStateChanged: (callback: (isMaximized: boolean) => void) => () => void
close: () => void
openAgreementWindow: () => Promise<boolean>
completeOnboarding: () => Promise<boolean>