frontend: FE-033 明暗主题三态切换并跟随系统,防闪白+全局过渡+Monaco同步
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -1,12 +1,20 @@
|
||||
import { FolderCog, PanelBottom, PanelLeft, PanelRight, Unplug } from "lucide-react"
|
||||
import { FolderCog, Monitor, Moon, PanelBottom, PanelLeft, PanelRight, Sun, Unplug } from "lucide-react"
|
||||
|
||||
import { Button } from "~/components/ui/button"
|
||||
import { Separator } from "~/components/ui/separator"
|
||||
import { Tooltip, TooltipContent, TooltipTrigger } from "~/components/ui/tooltip"
|
||||
import { useTheme, type ThemePreference } from "~/hooks/use-theme"
|
||||
import { isMacElectron } from "~/lib/platform"
|
||||
import type { WorkspaceSession } from "~/lib/tfs/session"
|
||||
import { cn } from "~/lib/utils"
|
||||
|
||||
// 主题三态对应的图标与说明文案。
|
||||
const THEME_VISUALS: Record<ThemePreference, { icon: typeof Monitor; label: string }> = {
|
||||
system: { icon: Monitor, label: "主题:跟随系统" },
|
||||
light: { icon: Sun, label: "主题:亮色" },
|
||||
dark: { icon: Moon, label: "主题:暗色" },
|
||||
}
|
||||
|
||||
// 三个可折叠面板的显隐状态,由 WorkspaceShell 持有。
|
||||
export interface PanelVisibility {
|
||||
tree: boolean
|
||||
@@ -33,6 +41,9 @@ export function TopBar({
|
||||
}) {
|
||||
// 隐藏式标题栏下顶栏整体作为拖拽区,并为左上角红绿灯预留空间。
|
||||
const macInset = isMacElectron()
|
||||
const theme = useTheme()
|
||||
const themeVisual = THEME_VISUALS[theme.preference]
|
||||
const ThemeIcon = themeVisual.icon
|
||||
return (
|
||||
<header
|
||||
className={cn(
|
||||
@@ -79,6 +90,14 @@ export function TopBar({
|
||||
<PanelBottom />
|
||||
</PanelToggle>
|
||||
<Separator orientation="vertical" className="mx-1 h-4!" />
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<Button size="icon-sm" variant="ghost" onClick={theme.cycle} aria-label={themeVisual.label}>
|
||||
<ThemeIcon />
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent side="bottom">{themeVisual.label}(点击切换)</TooltipContent>
|
||||
</Tooltip>
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<Button size="icon-sm" variant="ghost" onClick={onManageWorkspace} aria-label="工作区与映射管理">
|
||||
|
||||
@@ -126,6 +126,7 @@ export function DiffDialog({
|
||||
let diffEditor: MonacoEditor.IStandaloneDiffEditor | null = null
|
||||
let originalModel: MonacoEditor.ITextModel | null = null
|
||||
let modifiedModel: MonacoEditor.ITextModel | null = null
|
||||
let themeObserver: MutationObserver | null = null
|
||||
void (async () => {
|
||||
const { monaco, detectLanguage } = await import("~/lib/monaco")
|
||||
if (disposed || !containerRef.current) {
|
||||
@@ -167,10 +168,16 @@ export function DiffDialog({
|
||||
setBlockCount(diffEditor?.getLineChanges()?.length ?? 0)
|
||||
})
|
||||
editorRef.current = diffEditor
|
||||
// 弹窗打开期间应用切换明暗主题时,同步更新 Monaco 主题。
|
||||
themeObserver = new MutationObserver(() => {
|
||||
monaco.editor.setTheme(isDarkTheme() ? "mactfs-dark" : "mactfs-light")
|
||||
})
|
||||
themeObserver.observe(document.documentElement, { attributes: true, attributeFilter: ["class"] })
|
||||
})()
|
||||
return () => {
|
||||
disposed = true
|
||||
editorRef.current = null
|
||||
themeObserver?.disconnect()
|
||||
diffEditor?.dispose()
|
||||
originalModel?.dispose()
|
||||
modifiedModel?.dispose()
|
||||
|
||||
Reference in New Issue
Block a user