From 6138745813229750e8d2a6ed1bb82b8c4473fa8b Mon Sep 17 00:00:00 2001 From: 37863 <3786329580@qq.com> Date: Mon, 28 Sep 2026 23:30:40 +0800 Subject: [PATCH 1/5] fix(windows): align window and loading icons --- docs/development/platform-parity-matrix.csv | 1 + docs/development/platform-parity-matrix.md | 9 ++--- shared/platform-feature-matrix.json | 24 +++++++++++++ .../constants/window-actions.tsx | 8 +++-- .../status/git-status-file-item.tsx | 7 ++-- .../settings/components/settings-dialog.tsx | 4 +-- .../window/components/title-bar/title-bar.tsx | 10 ++++-- .../components/title-bar/window-controls.tsx | 36 +++++++++++++++++-- windows/tauri/src/ui/icons.tsx | 1 + windows/tauri/src/ui/spinner.tsx | 7 ++-- windows/tauri/src/ui/toast.tsx | 4 +-- 11 files changed, 89 insertions(+), 22 deletions(-) diff --git a/docs/development/platform-parity-matrix.csv b/docs/development/platform-parity-matrix.csv index 143fa6e01..18a00ad34 100644 --- a/docs/development/platform-parity-matrix.csv +++ b/docs/development/platform-parity-matrix.csv @@ -78,6 +78,7 @@ keymap-customization,设置,应用配置,快捷键查看与自定义,已实现, plugin-extension-management,扩展,插件与主题,插件、语言服务与主题管理,已实现,待验证,已实现,待验证,Extensions,启用、禁用和恢复插件/主题,确认启动加载、失败隔离和设置持久化。,,macos/Sources/Lithe/Views/App/PluginManagementView.swift; macos/Sources/Lithe/Platform/MacOS/Plugins,windows/tauri/src/extensions; windows/tauri/src/features/settings onboarding-welcome,启动与窗口,首次启动,欢迎页、项目入口与首次启动引导,已实现,待验证,已实现,待验证,Onboarding,清空首次启动状态,验证打开项目、克隆项目、最近项目和跳过引导;在 macOS 深色与浅色模式检查欢迎页布局、颜色和交互,确认默认及最小内容尺寸均为 800×650、可向屏幕可用区域放大,左下角齿轮菜单采用设置页下拉框配色并可进入设置与检查更新。,,macos/Sources/Lithe/Views/App/WelcomeView.swift; macos/Sources/Lithe/Views/Workspace,windows/tauri/src/features/onboarding; windows/tauri/src/features/bootstrap command-palette,工作台,命令与布局,命令面板与全局动作,已实现,待验证,已实现,待验证,Workbench,搜索并执行打开面板、运行、Git 和设置命令,确认快捷键和不可用命令状态。,,macos/Sources/Lithe/Models/Keymap/LitheCommandCatalog.swift; macos/Sources/Lithe/Views/Search/SearchEverywhereView.swift,windows/tauri/src/features/command-palette +window-controls,工作台,窗口管理,标题栏控制窗口最小化、最大化/还原与关闭;命令面板可最小化、最大化及切换全屏,已实现,待验证,已实现,待验证,Workbench,在 macOS 检查系统标题栏控制及全屏入口;在 Windows 验证标题栏最小化、最大化/还原和关闭,以及命令面板的窗口操作,确认图标语义、最大化/还原状态与按钮标签一致,并确认悬停关闭按钮背景贴合窗口右边缘。,,macos/Sources/Lithe/LitheApp.swift; macos/Sources/Lithe/Views/App/RootView.swift,windows/tauri/src/features/window/components/title-bar/window-controls.tsx; windows/tauri/src/features/command-palette/constants/window-actions.tsx workbench-panes,工作台,命令与布局,分栏、面板与工具窗布局,已实现,待验证,已实现,待验证,Workbench,打开、关闭、移动和调整面板,验证布局持久化及高频拖动稳定性;在 macOS 启用背景图后检查项目栏、编辑器、底部及右侧工具窗之间是否仍有清晰的分割区间;将 macOS 左侧工具窗缩至 30pt 并确认目录树始终贴左、不随宽度向右移动、内容不溢出、右上和右下圆角仍可见,关闭并重新打开项目后仍保持窄侧栏及其他布局尺寸,重新展开后布局正常;在 Maven 项目产生构建输出时确认左侧模块按钮可滚动、设置按钮始终完整显示;在亮色主题且有未读通知时确认未打开的铃铛图标清晰可见、打开通知面板后白色图标与蓝色背景成对出现;在深色 Lithe 主题下对照外框渐变、面板对比度、背景图片回退、左右工具窗的 40pt 按钮槽、30pt 选中块及 IDEA Community 图标对比度,悬停工具窗按钮时确认箭头光标,检查项目栏标题颜色和弹窗主按钮主题色;检查 macOS 40pt 顶栏 Logo 与系统窗口按钮垂直居中,项目切换器使用 20pt 项目字母头像和 30pt 悬停块,项目与分支切换块悬停保持箭头光标,红绿灯右侧留白与 IDEA 接近,项目头像、欢迎列表及切换菜单按标准化项目路径共享稳定颜色(超过 9 个项目、移除后重开仍一致),顶栏使用 IDEA Islands 主题项目色并按 85% 混色、600pt 水平和 300pt 垂直范围渐变,深色窗口分隔条四角与底栏缺口无浅色亮斑,缩放窗口及从欢迎页进入工作区再返回后仍对齐。,,macos/Sources/Lithe/Views/Workbench; macos/Sources/Lithe/Views/Workspace/ProjectSidebarView.swift; macos/Sources/Lithe/Views/Components/LitheSplitPaneView.swift; macos/Sources/Lithe/Services/Workbench/WorkbenchLayoutStore.swift; macos/Sources/Lithe/Views/App/RootView.swift; macos/Sources/Lithe/LitheApp.swift; macos/Sources/Lithe/Theme/LitheTheme.swift; macos/Resources/IDEAIcons/expui; macos/Resources/IDEAIcons/terminal,windows/tauri/src/features/panes; windows/tauri/src/features/layout workbench-activity-tooltips,工作台,工作台布局,活动栏图标的稳定悬停说明,已实现,待验证,已实现,待验证,Workbench,逐一悬停左上导航、左下工具入口及右侧通知/插件/Maven,快速切换图标并移出活动栏;确认始终只显示当前图标说明,面板更新和滚动后不残留旧提示,禁用入口可显示说明,短文字自适应且提示不超出窗口边缘。,,macos/Sources/Lithe/Views/Workbench/WorkbenchHoverTooltip.swift; macos/Sources/Lithe/Views/Workbench/WorkbenchView.swift; macos/Tests/LitheTests/WorkbenchHoverTooltipTests.swift,windows/tauri/src/features/layout/components/sidebar/sidebar-pane-selector.tsx; windows/tauri/src/features/layout/components/footer/footer-tab-control.tsx; windows/tauri/src/features/layout/components/plugin-activity-rail.tsx workbench-activity-rail-window-edge,工作台,工作台布局,活动栏贴合窗口外沿,已实现,待验证,已实现,待验证,Workbench,打开工作区,检查左右活动栏与窗口外沿齐平,外侧没有留白、圆角或边框;缩放窗口并切换活动面板后确认布局仍贴边。,,macos/Sources/Lithe/Views/Workbench/WorkbenchView.swift,windows/tauri/src/features/layout/components/main-layout.tsx; windows/tauri/src/features/layout/components/plugin-activity-rail.tsx; windows/tauri/src/features/layout/components/sidebar/main-sidebar.tsx diff --git a/docs/development/platform-parity-matrix.md b/docs/development/platform-parity-matrix.md index 2493813f2..ff7be8e96 100644 --- a/docs/development/platform-parity-matrix.md +++ b/docs/development/platform-parity-matrix.md @@ -4,9 +4,9 @@ - 最后复核:2026-09-27 - 盘点状态:initial-static-inventory(根据 macOS Views/Application/Services、Windows features/extensions 和共享契约的代码入口进行初版盘点;未替代真实运行验收。) -- 功能项:101 -- macOS:实现:✅ 88 已实现,🟡 3 部分实现,❌ 7 未实现,🧩 3 平台专属;验证:✔️ 0 已验证,🔍 91 待验证,— 10 不适用 -- Windows:实现:✅ 87 已实现,🟡 10 部分实现,❌ 4 未实现,🧩 0 平台专属;验证:✔️ 0 已验证,🔍 97 待验证,— 4 不适用 +- 功能项:102 +- macOS:实现:✅ 89 已实现,🟡 3 部分实现,❌ 7 未实现,🧩 3 平台专属;验证:✔️ 0 已验证,🔍 92 待验证,— 10 不适用 +- Windows:实现:✅ 88 已实现,🟡 10 部分实现,❌ 4 未实现,🧩 0 平台专属;验证:✔️ 0 已验证,🔍 98 待验证,— 4 不适用 ## 实现状态定义 @@ -165,7 +165,7 @@
-工作台 · 10 个能力点 +工作台 · 11 个能力点 | 功能组 | 能力点 | macOS | Windows | 负责人 | 验证方式 | 备注 | | --- | --- | --- | --- | --- | --- | --- | @@ -176,6 +176,7 @@ | 本地历史 | **快照列表与 Diff**
history-snapshots | ✅ 已实现
🔍 待验证
`macos/Sources/Lithe/Views/History`、`macos/Sources/Lithe/Services` | ✅ 已实现
🔍 待验证
`windows/tauri/src/features/local-history` | Local History | 编辑同一文件多次,比较快照时间、内容 Diff 和文件范围。 | | | 本地历史 | **恢复、删除与持久化**
history-restore | ✅ 已实现
🔍 待验证
`macos/Sources/Lithe/Views/History` | ✅ 已实现
🔍 待验证
`windows/tauri/src/features/local-history` | Local History | 验证恢复、删除、应用重启后持久化和失败回滚。 | | | 命令与布局 | **命令面板与全局动作**
command-palette | ✅ 已实现
🔍 待验证
`macos/Sources/Lithe/Models/Keymap/LitheCommandCatalog.swift`、`macos/Sources/Lithe/Views/Search/SearchEverywhereView.swift` | ✅ 已实现
🔍 待验证
`windows/tauri/src/features/command-palette` | Workbench | 搜索并执行打开面板、运行、Git 和设置命令,确认快捷键和不可用命令状态。 | | +| 窗口管理 | **标题栏控制窗口最小化、最大化/还原与关闭;命令面板可最小化、最大化及切换全屏**
window-controls | ✅ 已实现
🔍 待验证
`macos/Sources/Lithe/LitheApp.swift`、`macos/Sources/Lithe/Views/App/RootView.swift` | ✅ 已实现
🔍 待验证
`windows/tauri/src/features/window/components/title-bar/window-controls.tsx`、`windows/tauri/src/features/command-palette/constants/window-actions.tsx` | Workbench | 在 macOS 检查系统标题栏控制及全屏入口;在 Windows 验证标题栏最小化、最大化/还原和关闭,以及命令面板的窗口操作,确认图标语义、最大化/还原状态与按钮标签一致,并确认悬停关闭按钮背景贴合窗口右边缘。 | | | 命令与布局 | **分栏、面板与工具窗布局**
workbench-panes | ✅ 已实现
🔍 待验证
`macos/Sources/Lithe/Views/Workbench`、`macos/Sources/Lithe/Views/Workspace/ProjectSidebarView.swift`、`macos/Sources/Lithe/Views/Components/LitheSplitPaneView.swift`、`macos/Sources/Lithe/Services/Workbench/WorkbenchLayoutStore.swift`、`macos/Sources/Lithe/Views/App/RootView.swift`、`macos/Sources/Lithe/LitheApp.swift`、`macos/Sources/Lithe/Theme/LitheTheme.swift`、`macos/Resources/IDEAIcons/expui`、`macos/Resources/IDEAIcons/terminal` | ✅ 已实现
🔍 待验证
`windows/tauri/src/features/panes`、`windows/tauri/src/features/layout` | Workbench | 打开、关闭、移动和调整面板,验证布局持久化及高频拖动稳定性;在 macOS 启用背景图后检查项目栏、编辑器、底部及右侧工具窗之间是否仍有清晰的分割区间;将 macOS 左侧工具窗缩至 30pt 并确认目录树始终贴左、不随宽度向右移动、内容不溢出、右上和右下圆角仍可见,关闭并重新打开项目后仍保持窄侧栏及其他布局尺寸,重新展开后布局正常;在 Maven 项目产生构建输出时确认左侧模块按钮可滚动、设置按钮始终完整显示;在亮色主题且有未读通知时确认未打开的铃铛图标清晰可见、打开通知面板后白色图标与蓝色背景成对出现;在深色 Lithe 主题下对照外框渐变、面板对比度、背景图片回退、左右工具窗的 40pt 按钮槽、30pt 选中块及 IDEA Community 图标对比度,悬停工具窗按钮时确认箭头光标,检查项目栏标题颜色和弹窗主按钮主题色;检查 macOS 40pt 顶栏 Logo 与系统窗口按钮垂直居中,项目切换器使用 20pt 项目字母头像和 30pt 悬停块,项目与分支切换块悬停保持箭头光标,红绿灯右侧留白与 IDEA 接近,项目头像、欢迎列表及切换菜单按标准化项目路径共享稳定颜色(超过 9 个项目、移除后重开仍一致),顶栏使用 IDEA Islands 主题项目色并按 85% 混色、600pt 水平和 300pt 垂直范围渐变,深色窗口分隔条四角与底栏缺口无浅色亮斑,缩放窗口及从欢迎页进入工作区再返回后仍对齐。 | | | 工作台布局 | **活动栏图标的稳定悬停说明**
workbench-activity-tooltips | ✅ 已实现
🔍 待验证
`macos/Sources/Lithe/Views/Workbench/WorkbenchHoverTooltip.swift`、`macos/Sources/Lithe/Views/Workbench/WorkbenchView.swift`、`macos/Tests/LitheTests/WorkbenchHoverTooltipTests.swift` | ✅ 已实现
🔍 待验证
`windows/tauri/src/features/layout/components/sidebar/sidebar-pane-selector.tsx`、`windows/tauri/src/features/layout/components/footer/footer-tab-control.tsx`、`windows/tauri/src/features/layout/components/plugin-activity-rail.tsx` | Workbench | 逐一悬停左上导航、左下工具入口及右侧通知/插件/Maven,快速切换图标并移出活动栏;确认始终只显示当前图标说明,面板更新和滚动后不残留旧提示,禁用入口可显示说明,短文字自适应且提示不超出窗口边缘。 | | | 工作台布局 | **活动栏贴合窗口外沿**
workbench-activity-rail-window-edge | ✅ 已实现
🔍 待验证
`macos/Sources/Lithe/Views/Workbench/WorkbenchView.swift` | ✅ 已实现
🔍 待验证
`windows/tauri/src/features/layout/components/main-layout.tsx`、`windows/tauri/src/features/layout/components/plugin-activity-rail.tsx`、`windows/tauri/src/features/layout/components/sidebar/main-sidebar.tsx` | Workbench | 打开工作区,检查左右活动栏与窗口外沿齐平,外侧没有留白、圆角或边框;缩放窗口并切换活动面板后确认布局仍贴边。 | | diff --git a/shared/platform-feature-matrix.json b/shared/platform-feature-matrix.json index 5a28d9bcd..6a61036b1 100644 --- a/shared/platform-feature-matrix.json +++ b/shared/platform-feature-matrix.json @@ -1980,6 +1980,30 @@ "owner": "Workbench", "verification": "搜索并执行打开面板、运行、Git 和设置命令,确认快捷键和不可用命令状态。" }, + { + "id": "window-controls", + "area": "工作台", + "group": "窗口管理", + "capability": "标题栏控制窗口最小化、最大化/还原与关闭;命令面板可最小化、最大化及切换全屏", + "macos": { + "evidence": [ + "macos/Sources/Lithe/LitheApp.swift", + "macos/Sources/Lithe/Views/App/RootView.swift" + ], + "implementationStatus": "implemented", + "verificationStatus": "pending" + }, + "windows": { + "evidence": [ + "windows/tauri/src/features/window/components/title-bar/window-controls.tsx", + "windows/tauri/src/features/command-palette/constants/window-actions.tsx" + ], + "implementationStatus": "implemented", + "verificationStatus": "pending" + }, + "owner": "Workbench", + "verification": "在 macOS 检查系统标题栏控制及全屏入口;在 Windows 验证标题栏最小化、最大化/还原和关闭,以及命令面板的窗口操作,确认图标语义、最大化/还原状态与按钮标签一致,并确认悬停关闭按钮背景贴合窗口右边缘。" + }, { "id": "workbench-panes", "area": "工作台", diff --git a/windows/tauri/src/features/command-palette/constants/window-actions.tsx b/windows/tauri/src/features/command-palette/constants/window-actions.tsx index e755e5321..7954a859d 100644 --- a/windows/tauri/src/features/command-palette/constants/window-actions.tsx +++ b/windows/tauri/src/features/command-palette/constants/window-actions.tsx @@ -1,4 +1,8 @@ -import { ArrowsOutIcon as Maximize, ArrowsInIcon as Minimize } from "@/ui/icons"; +import { + ArrowsOutIcon as FullScreen, + MinusIcon as Minimize, + SquareIcon as Maximize, +} from "@/ui/icons"; import type { Action } from "../types/action.types"; interface WindowActionsParams { @@ -35,7 +39,7 @@ export const createWindowActions = (params: WindowActionsParams): Action[] => { id: "window-fullscreen", label: "Window: Toggle Fullscreen", description: "Enter or exit fullscreen mode", - icon: , + icon: , category: "Window", commandId: "window.toggleFullscreen", action: () => { diff --git a/windows/tauri/src/features/git/components/status/git-status-file-item.tsx b/windows/tauri/src/features/git/components/status/git-status-file-item.tsx index 18e5c3cce..2b0ad2a78 100644 --- a/windows/tauri/src/features/git/components/status/git-status-file-item.tsx +++ b/windows/tauri/src/features/git/components/status/git-status-file-item.tsx @@ -5,6 +5,7 @@ import { useTranslation } from "@/i18n/locale-provider"; import { Checkbox } from "@/ui/checkbox"; import { Button } from "@/ui/button"; import { MinusIcon as Minus, PlusIcon as Plus } from "@/ui/icons"; +import { Spinner } from "@/ui/spinner"; import { SidebarTreeRow } from "@/features/sidebar/components/sidebar-tree"; import { FILE_TREE_BASE_INDENT } from "@/features/file-explorer/lib/file-tree-row"; import { cn } from "@/utils/cn"; @@ -75,11 +76,7 @@ export function GitFileStageAction({ onContextMenu={(event) => event.stopPropagation()} > {pending ? ( - + ) : staged ? ( ) : ( diff --git a/windows/tauri/src/features/settings/components/settings-dialog.tsx b/windows/tauri/src/features/settings/components/settings-dialog.tsx index 26732beb4..7e5ac26eb 100644 --- a/windows/tauri/src/features/settings/components/settings-dialog.tsx +++ b/windows/tauri/src/features/settings/components/settings-dialog.tsx @@ -6,9 +6,9 @@ import { useTranslation } from "@/i18n/locale-provider"; import { Button } from "@/ui/button"; import Dialog from "@/ui/dialog"; import { - ArrowClockwiseIcon, CodeBlockIcon, DatabaseIcon, + DownloadIcon, GearIcon, GearSixIcon, KeyboardIcon, @@ -46,7 +46,7 @@ const categories: CategoryItem[] = [ { id: "ai-commit", labelKey: "settings.tabs.aiCommit", icon: MagicWandIcon }, { id: "git", labelKey: "settings.tabs.git", icon: CodeBlockIcon }, { id: "logs", labelKey: "settings.tabs.logs", icon: FileTextIcon }, - { id: "updates", labelKey: "settings.tabs.updates", icon: ArrowClockwiseIcon }, + { id: "updates", labelKey: "settings.tabs.updates", icon: DownloadIcon }, ]; function categoryFromRequestedTab(tab: SettingsTab | null): MacSettingsCategory { diff --git a/windows/tauri/src/features/window/components/title-bar/title-bar.tsx b/windows/tauri/src/features/window/components/title-bar/title-bar.tsx index c00bfff94..a45fa8cd7 100644 --- a/windows/tauri/src/features/window/components/title-bar/title-bar.tsx +++ b/windows/tauri/src/features/window/components/title-bar/title-bar.tsx @@ -289,7 +289,10 @@ export const TitleBar = ({ @@ -334,7 +337,10 @@ export const TitleBar = ({ diff --git a/windows/tauri/src/features/window/components/title-bar/window-controls.tsx b/windows/tauri/src/features/window/components/title-bar/window-controls.tsx index 0b6db86b4..39115e49e 100644 --- a/windows/tauri/src/features/window/components/title-bar/window-controls.tsx +++ b/windows/tauri/src/features/window/components/title-bar/window-controls.tsx @@ -18,6 +18,14 @@ interface WindowControlsProps { onMaximizedChange: (isMaximized: boolean) => void; } +// Use Windows' caption glyphs so the controls match the native title bar. +const WINDOW_CONTROL_GLYPHS = { + minimize: "\uE921", + maximize: "\uE922", + restore: "\uE923", + close: "\uE8BB", +} as const; + export function WindowControls({ currentWindow, isMaximized, @@ -63,7 +71,7 @@ export function WindowControls({ tooltipTriggerClassName={IS_WINDOWS ? "h-full" : undefined} aria-label={t("window.minimize")} > - + {IS_WINDOWS ? : } ); } + +function WindowControlGlyph({ + kind, +}: { + kind: "minimize" | "maximize" | "restore" | "close"; +}) { + return ( + + ); +} diff --git a/windows/tauri/src/ui/icons.tsx b/windows/tauri/src/ui/icons.tsx index 0ff85a8b1..9a49ec9af 100644 --- a/windows/tauri/src/ui/icons.tsx +++ b/windows/tauri/src/ui/icons.tsx @@ -222,6 +222,7 @@ function createIconComponent(IconComponent: ComponentType, displayName: str export const Icon = createIconComponent(Nucleo.IconCircleQuestionOutline18, "Icon"); export const AiLoadingIcon = createIconComponent(Nucleo.IconAiLoadingOutline18, "AiLoadingIcon"); +export const LoaderCircleIcon = createIconComponent(lucideIcons.LoaderCircle, "LoaderCircleIcon"); export const ArchiveIcon = createIconComponent(Nucleo.IconArchiveOutline18, "ArchiveIcon"); export const ArrowBendDownLeftIcon = createIconComponent( Nucleo.IconArrowCornerBottomLeftOutline18, diff --git a/windows/tauri/src/ui/spinner.tsx b/windows/tauri/src/ui/spinner.tsx index 37fb3ad7a..5908fb2ce 100644 --- a/windows/tauri/src/ui/spinner.tsx +++ b/windows/tauri/src/ui/spinner.tsx @@ -1,5 +1,6 @@ import type { ComponentProps } from "react"; import { useTranslation } from "@/i18n/locale-provider"; +import { LoaderCircleIcon } from "@/ui/icons"; import { cn } from "@/utils/cn"; type SpinnerProps = Omit, "children"> & { @@ -23,12 +24,14 @@ function Spinner({ aria-hidden={showLabel || undefined} aria-label={showLabel ? undefined : resolvedLabel} className={cn( - "inline-block shrink-0 animate-spin rounded-full border-2 border-current border-r-transparent", + "inline-flex shrink-0", compact ? "size-3" : "size-4", !showLabel && className, )} {...props} - /> + > + ); if (!showLabel) { diff --git a/windows/tauri/src/ui/toast.tsx b/windows/tauri/src/ui/toast.tsx index f3290c3f4..7afc1d63d 100644 --- a/windows/tauri/src/ui/toast.tsx +++ b/windows/tauri/src/ui/toast.tsx @@ -7,9 +7,9 @@ import { cn } from "@/utils/cn"; import { Button } from "@/ui/button"; import { useTranslation } from "@/i18n/locale-provider"; import { - AiLoadingIcon, CheckCircleIcon, InfoIcon, + LoaderCircleIcon, WarningIcon, XCircleIcon, XIcon, @@ -157,7 +157,7 @@ function ToastIcon({ type }: { type: string | undefined }) { } if (type === "loading") { - icon =