From a399429a62ad35dff3d121d1ae6a66a07136f4e9 Mon Sep 17 00:00:00 2001 From: su-fen <715041@qq.com> Date: Sun, 21 Jun 2026 22:26:05 +0800 Subject: [PATCH 1/2] style(hub): update Skills and MCP hub icons --- crates/agent-gateway/web/package.json | 1 + crates/agent-gateway/web/pnpm-lock.yaml | 10 +++ .../components/chat/ChatHistorySidebar.tsx | 10 +-- .../web/src/components/icons.tsx | 76 +++++++++++++++++++ .../web/src/pages/mcp-hub/McpHubPage.tsx | 4 +- .../src/pages/skills-hub/SkillsHubPage.tsx | 20 ++--- crates/agent-gui/package.json | 1 + crates/agent-gui/pnpm-lock.yaml | 10 +++ .../components/chat/ChatHistorySidebar.tsx | 10 +-- crates/agent-gui/src/components/icons.tsx | 76 +++++++++++++++++++ .../src/pages/mcp-hub/McpHubPage.tsx | 4 +- .../src/pages/skills-hub/SkillsHubPage.tsx | 20 ++--- 12 files changed, 210 insertions(+), 32 deletions(-) diff --git a/crates/agent-gateway/web/package.json b/crates/agent-gateway/web/package.json index 4f6f9411..f41da2f1 100644 --- a/crates/agent-gateway/web/package.json +++ b/crates/agent-gateway/web/package.json @@ -11,6 +11,7 @@ "dependencies": { "@git-diff-view/file": "^0.1.3", "@git-diff-view/react": "^0.1.3", + "@iconify-json/gravity-ui": "^1.2.12", "@radix-ui/react-dropdown-menu": "^2.1.16", "@radix-ui/react-scroll-area": "^1.2.10", "@radix-ui/react-select": "^2.2.6", diff --git a/crates/agent-gateway/web/pnpm-lock.yaml b/crates/agent-gateway/web/pnpm-lock.yaml index cdb71bed..c32f65b2 100644 --- a/crates/agent-gateway/web/pnpm-lock.yaml +++ b/crates/agent-gateway/web/pnpm-lock.yaml @@ -14,6 +14,9 @@ importers: '@git-diff-view/react': specifier: ^0.1.3 version: 0.1.3(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@iconify-json/gravity-ui': + specifier: ^1.2.12 + version: 1.2.12 '@radix-ui/react-dropdown-menu': specifier: ^2.1.16 version: 2.1.16(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) @@ -263,6 +266,9 @@ packages: react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + '@iconify-json/gravity-ui@1.2.12': + resolution: {integrity: sha512-/66CorNnUoFs66nb8FJ+ZPq6Zog9NwR13ml90qijI0Hj3bVqQIdiWZ9npSyNWRgJe452LFmWZrdWQONYBbJ7XA==} + '@iconify-json/logos@1.2.11': resolution: {integrity: sha512-fOo4pGEatuyuCFNL+cwquYMa2Im0oJHRHV7lt/Qqs5Ode/lPImHCQcfTtPzZj7qYMPb/h8YHN3TG54uEowrjNQ==} @@ -2591,6 +2597,10 @@ snapshots: reactivity-store: 0.4.0(react@19.2.5) use-sync-external-store: 1.6.0(react@19.2.5) + '@iconify-json/gravity-ui@1.2.12': + dependencies: + '@iconify/types': 2.0.0 + '@iconify-json/logos@1.2.11': dependencies: '@iconify/types': 2.0.0 diff --git a/crates/agent-gateway/web/src/components/chat/ChatHistorySidebar.tsx b/crates/agent-gateway/web/src/components/chat/ChatHistorySidebar.tsx index 7b9b83ff..be2788bc 100644 --- a/crates/agent-gateway/web/src/components/chat/ChatHistorySidebar.tsx +++ b/crates/agent-gateway/web/src/components/chat/ChatHistorySidebar.tsx @@ -17,15 +17,15 @@ import { Folder, FolderTree, Link2, + McpLogo, MessageSquareText, MoreHorizontal, PanelLeftClose, Pin, PinOff, - Plug, Plus, Share2, - Sparkles, + SkillIcon, SquarePen, Trash2, } from "../icons"; @@ -1586,9 +1586,9 @@ export const ChatHistorySidebar = memo(function ChatHistorySidebar(props: ChatHi )} title="Skills Hub" > - @@ -1606,7 +1606,7 @@ export const ChatHistorySidebar = memo(function ChatHistorySidebar(props: ChatHi )} title="MCP Hub" > - & { title?: string }) { + return ( + + {title ?? "Skill"} + + + + + + + ); +} + export const AlertCircle = createIcon(AlertCircleSource); export const AlertTriangle = createIcon(AlertTriangleSource); export const ClaudeIcon = createIcon(ClaudeSource); @@ -341,6 +415,7 @@ export const Lock = createIcon(LockSource); export const LogOut = createIcon(LogOutSource); export const MessageSquare = createIcon(MessageSquareSource); export const MessageSquareText = createIcon(MessageSquareTextSource); +export const McpLogo = createIcon(McpLogoSource); export const MonitorSmartphone = createIcon(MonitorSmartphoneSource); export const Moon = createIcon(MoonSource); export const MoreHorizontal = createIcon(MoreHorizontalSource); @@ -370,6 +445,7 @@ export const Settings = createIcon(SettingsSource); export const Settings2 = createIcon(Settings2Source); export const Share2 = createIcon(Share2Source); export const Shield = createIcon(ShieldSource); +export const SkillIcon = createIcon(SkillIconSource); export const Sparkles = createIcon(SparklesSource); export const Square = createIcon(SquareSource); export const SquarePen = createIcon(SquarePenSource); diff --git a/crates/agent-gateway/web/src/pages/mcp-hub/McpHubPage.tsx b/crates/agent-gateway/web/src/pages/mcp-hub/McpHubPage.tsx index 4a1809e4..ecf48e35 100644 --- a/crates/agent-gateway/web/src/pages/mcp-hub/McpHubPage.tsx +++ b/crates/agent-gateway/web/src/pages/mcp-hub/McpHubPage.tsx @@ -1,6 +1,6 @@ import { useState } from "react"; -import { Cloud, Plug, Plus, Server, Sparkles } from "../../components/icons"; +import { Cloud, McpLogo, Plug, Plus, Server, Sparkles } from "../../components/icons"; import { Button } from "../../components/ui/button"; import { useLocale } from "../../i18n"; import { McpRegistryBrowser } from "./McpRegistryBrowser"; @@ -65,7 +65,7 @@ export function McpHubPage(props: McpHubPageProps) {
} + icon={} title="MCP Hub" subtitle={t("mcpHub.subtitle")} sidebarOpen={sidebarOpen} diff --git a/crates/agent-gateway/web/src/pages/skills-hub/SkillsHubPage.tsx b/crates/agent-gateway/web/src/pages/skills-hub/SkillsHubPage.tsx index 99f89de2..d9dcb42c 100644 --- a/crates/agent-gateway/web/src/pages/skills-hub/SkillsHubPage.tsx +++ b/crates/agent-gateway/web/src/pages/skills-hub/SkillsHubPage.tsx @@ -12,9 +12,11 @@ import { Loader2, Lock, MessageSquare, + Plug, RefreshCw, Search, - Sparkles, + Server, + SkillIcon, Trash2, X, } from "../../components/icons"; @@ -740,7 +742,7 @@ export function SkillsHubPage(props: SkillsHubPageProps) {
} + icon={} title={t("settings.skillsHubTitle")} subtitle={rootDir ? rootDir : t("settings.skillsHubSubtitle")} sidebarOpen={sidebarOpen} @@ -768,7 +770,7 @@ export function SkillsHubPage(props: SkillsHubPageProps) { : "border-border/40 bg-muted/40 text-muted-foreground", )} > - + {skillsEnabled ? ( ) : null} @@ -872,7 +874,7 @@ export function SkillsHubPage(props: SkillsHubPageProps) { { value: "installed" as const, label: t("settings.skillsHubInstalledTab"), - icon: Sparkles, + icon: Server, count: selectableSkills.length, }, { @@ -1044,7 +1046,7 @@ export function SkillsHubPage(props: SkillsHubPageProps) { : "border-border/30 bg-muted/50 text-muted-foreground group-hover:border-border/50 group-hover:bg-background/70 group-hover:text-foreground/85", )} > - +
{alwaysEnabled ? ( @@ -1283,7 +1285,7 @@ function InstalledSkillPreviewDrawer(props: { >
- {alwaysEnabled ? : } + {alwaysEnabled ? : }
@@ -1324,7 +1326,7 @@ function InstalledSkillPreviewDrawer(props: {
- +
@@ -1697,7 +1699,7 @@ function SkillsStoreView(props: { : "border-border/30 bg-muted/50 text-muted-foreground group-hover:border-border/50 group-hover:bg-background/70 group-hover:text-foreground/85", )} > - +
@@ -1927,7 +1929,7 @@ function SkillsStorePreviewDrawer(props: { loading="lazy" /> ) : ( - + )}
diff --git a/crates/agent-gui/package.json b/crates/agent-gui/package.json index f9bbb375..56293d87 100644 --- a/crates/agent-gui/package.json +++ b/crates/agent-gui/package.json @@ -24,6 +24,7 @@ "@earendil-works/pi-ai": "^0.79.6", "@git-diff-view/file": "^0.1.3", "@git-diff-view/react": "^0.1.3", + "@iconify-json/gravity-ui": "^1.2.12", "@openai/codex-sdk": "^0.118.0", "@streamdown/cjk": "^1.0.3", "@streamdown/code": "^1.1.1", diff --git a/crates/agent-gui/pnpm-lock.yaml b/crates/agent-gui/pnpm-lock.yaml index 83a1c4d0..e6afaaab 100644 --- a/crates/agent-gui/pnpm-lock.yaml +++ b/crates/agent-gui/pnpm-lock.yaml @@ -26,6 +26,9 @@ importers: '@git-diff-view/react': specifier: ^0.1.3 version: 0.1.3(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@iconify-json/gravity-ui': + specifier: ^1.2.12 + version: 1.2.12 '@openai/codex-sdk': specifier: ^0.118.0 version: 0.118.0 @@ -516,6 +519,9 @@ packages: peerDependencies: hono: ^4 + '@iconify-json/gravity-ui@1.2.12': + resolution: {integrity: sha512-/66CorNnUoFs66nb8FJ+ZPq6Zog9NwR13ml90qijI0Hj3bVqQIdiWZ9npSyNWRgJe452LFmWZrdWQONYBbJ7XA==} + '@iconify-json/logos@1.2.11': resolution: {integrity: sha512-fOo4pGEatuyuCFNL+cwquYMa2Im0oJHRHV7lt/Qqs5Ode/lPImHCQcfTtPzZj7qYMPb/h8YHN3TG54uEowrjNQ==} @@ -3637,6 +3643,10 @@ snapshots: dependencies: hono: 4.12.12 + '@iconify-json/gravity-ui@1.2.12': + dependencies: + '@iconify/types': 2.0.0 + '@iconify-json/logos@1.2.11': dependencies: '@iconify/types': 2.0.0 diff --git a/crates/agent-gui/src/components/chat/ChatHistorySidebar.tsx b/crates/agent-gui/src/components/chat/ChatHistorySidebar.tsx index bedab9e5..6feb704a 100644 --- a/crates/agent-gui/src/components/chat/ChatHistorySidebar.tsx +++ b/crates/agent-gui/src/components/chat/ChatHistorySidebar.tsx @@ -17,15 +17,15 @@ import { FolderOpen, FolderTree, Link2, + McpLogo, MessageSquareText, MoreHorizontal, PanelLeftClose, Pin, PinOff, - Plug, Plus, Share2, - Sparkles, + SkillIcon, SquarePen, Trash2, } from "../icons"; @@ -1304,9 +1304,9 @@ export const ChatHistorySidebar = memo(function ChatHistorySidebar(props: ChatHi )} title="Skills Hub" > - @@ -1324,7 +1324,7 @@ export const ChatHistorySidebar = memo(function ChatHistorySidebar(props: ChatHi )} title="MCP Hub" > - & { title?: string }) { + return ( + + {title ?? "Skill"} + + + + + + + ); +} + export const AlertTriangle = createIcon(AlertTriangleSource); export const ClaudeIcon = createIcon(ClaudeSource); export const FileTypeGeminiIcon = createIcon(FileTypeGeminiSource); @@ -260,6 +334,7 @@ export const Lock = createIcon(LockSource); export const Maximize2 = createIcon(Maximize2Source); export const MessageSquare = createIcon(MessageSquareSource); export const MessageSquareText = createIcon(MessageSquareTextSource); +export const McpLogo = createIcon(McpLogoSource); export const Minimize2 = createIcon(Minimize2Source); export const Minus = createIcon(MinusSource); export const MonitorSmartphone = createIcon(MonitorSmartphoneSource); @@ -292,6 +367,7 @@ export const Settings = createIcon(SettingsSource); export const Settings2 = createIcon(Settings2Source); export const Share2 = createIcon(Share2Source); export const Shield = createIcon(ShieldSource); +export const SkillIcon = createIcon(SkillIconSource); export const Sparkles = createIcon(SparklesSource); export const Square = createIcon(SquareSource); export const SquarePen = createIcon(SquarePenSource); diff --git a/crates/agent-gui/src/pages/mcp-hub/McpHubPage.tsx b/crates/agent-gui/src/pages/mcp-hub/McpHubPage.tsx index 8eeb3610..47aa0464 100644 --- a/crates/agent-gui/src/pages/mcp-hub/McpHubPage.tsx +++ b/crates/agent-gui/src/pages/mcp-hub/McpHubPage.tsx @@ -1,6 +1,6 @@ import { useState } from "react"; import { HubBackdrop, HubHeader } from "../../components/hub/HubChrome"; -import { Cloud, Plug, Plus, Server, Sparkles } from "../../components/icons"; +import { Cloud, McpLogo, Plug, Plus, Server, Sparkles } from "../../components/icons"; import { Button } from "../../components/ui/button"; import { useLocale } from "../../i18n"; import { type AppSettings, type McpServerConfig, updateMcp } from "../../lib/settings"; @@ -60,7 +60,7 @@ export function McpHubPage(props: McpHubPageProps) {
} + icon={} title="MCP Hub" subtitle={t("mcpHub.subtitle")} sidebarOpen={sidebarOpen} diff --git a/crates/agent-gui/src/pages/skills-hub/SkillsHubPage.tsx b/crates/agent-gui/src/pages/skills-hub/SkillsHubPage.tsx index 2788d312..bb1bbeb5 100644 --- a/crates/agent-gui/src/pages/skills-hub/SkillsHubPage.tsx +++ b/crates/agent-gui/src/pages/skills-hub/SkillsHubPage.tsx @@ -11,9 +11,11 @@ import { Loader2, Lock, MessageSquare, + Plug, RefreshCw, Search, - Sparkles, + Server, + SkillIcon, Trash2, X, } from "../../components/icons"; @@ -743,7 +745,7 @@ export function SkillsHubPage(props: SkillsHubPageProps) {
} + icon={} title={t("settings.skillsHubTitle")} subtitle={rootDir ? rootDir : t("settings.skillsHubSubtitle")} sidebarOpen={sidebarOpen} @@ -771,7 +773,7 @@ export function SkillsHubPage(props: SkillsHubPageProps) { : "border-border/40 bg-muted/40 text-muted-foreground", )} > - + {skillsEnabled ? ( ) : null} @@ -875,7 +877,7 @@ export function SkillsHubPage(props: SkillsHubPageProps) { { value: "installed" as const, label: t("settings.skillsHubInstalledTab"), - icon: Sparkles, + icon: Server, count: selectableSkills.length, }, { @@ -1050,7 +1052,7 @@ export function SkillsHubPage(props: SkillsHubPageProps) { : "border-border/30 bg-muted/50 text-muted-foreground group-hover:border-border/50 group-hover:bg-background/70 group-hover:text-foreground/85", )} > - +
{alwaysEnabled ? ( @@ -1292,7 +1294,7 @@ function InstalledSkillPreviewDrawer(props: { >
- {alwaysEnabled ? : } + {alwaysEnabled ? : }
@@ -1333,7 +1335,7 @@ function InstalledSkillPreviewDrawer(props: {
- +
@@ -1707,7 +1709,7 @@ function SkillsStoreView(props: { : "border-border/30 bg-muted/50 text-muted-foreground group-hover:border-border/50 group-hover:bg-background/70 group-hover:text-foreground/85", )} > - +
@@ -1937,7 +1939,7 @@ function SkillsStorePreviewDrawer(props: { loading="lazy" /> ) : ( - + )}
From 6636380727b3743d523928e68f2435e2eb370a04 Mon Sep 17 00:00:00 2001 From: su-fen <715041@qq.com> Date: Sun, 21 Jun 2026 22:33:35 +0800 Subject: [PATCH 2/2] fix(gui): align macOS titlebar actions with traffic lights --- .../src-tauri/src/commands/app/app.rs | 71 +++++++++++++++---- .../src/components/MacOsTitleBarSpacer.tsx | 13 +++- 2 files changed, 69 insertions(+), 15 deletions(-) diff --git a/crates/agent-gui/src-tauri/src/commands/app/app.rs b/crates/agent-gui/src-tauri/src/commands/app/app.rs index 9afce0f1..e88d9081 100644 --- a/crates/agent-gui/src-tauri/src/commands/app/app.rs +++ b/crates/agent-gui/src-tauri/src/commands/app/app.rs @@ -66,7 +66,7 @@ async fn read_macos_traffic_light_metrics( fn read_macos_traffic_light_metrics_on_main_thread( window: &tauri::Window, ) -> Result, String> { - use objc2_app_kit::{NSView, NSWindow, NSWindowButton}; + use objc2_app_kit::{NSWindow, NSWindowButton}; let ns_window_ptr = window .ns_window() @@ -76,24 +76,48 @@ fn read_macos_traffic_light_metrics_on_main_thread( } let ns_window: &NSWindow = unsafe { &*ns_window_ptr.cast::() }; - let Some(close_button) = ns_window.standardWindowButton(NSWindowButton::CloseButton) else { + let window_frame = ns_window.frame(); + + let button_frames = [ + NSWindowButton::CloseButton, + NSWindowButton::MiniaturizeButton, + NSWindowButton::ZoomButton, + ] + .into_iter() + .filter_map(|button| ns_window.standardWindowButton(button)) + .map(|button| macos_window_button_screen_frame(ns_window, &button)) + .collect::>(); + + if button_frames.is_empty() { return Ok(None); - }; + } - let close_frame = NSView::frame(&close_button); - let close_screen_frame = ns_window.convertRectToScreen(close_frame); - let window_frame = ns_window.frame(); - let top_from_top_edge = close_screen_frame.origin.y - window_frame.origin.y; - let top_from_bottom_edge = window_frame.origin.y + window_frame.size.height - - (close_screen_frame.origin.y + close_screen_frame.size.height); + let min_x = button_frames + .iter() + .map(|frame| frame.0) + .fold(f64::INFINITY, f64::min); + let min_y = button_frames + .iter() + .map(|frame| frame.1) + .fold(f64::INFINITY, f64::min); + let max_x = button_frames + .iter() + .map(|frame| frame.0 + frame.2) + .fold(f64::NEG_INFINITY, f64::max); + let max_y = button_frames + .iter() + .map(|frame| frame.1 + frame.3) + .fold(f64::NEG_INFINITY, f64::max); + let width = max_x - min_x; + let height = max_y - min_y; + let top_from_top_edge = min_y - window_frame.origin.y; + let top_from_bottom_edge = window_frame.origin.y + window_frame.size.height - max_y; let top = [top_from_top_edge, top_from_bottom_edge] .into_iter() .filter(|value| value.is_finite() && *value >= 0.0) .min_by(|left, right| left.partial_cmp(right).unwrap()) .unwrap_or(top_from_bottom_edge); - let left = close_screen_frame.origin.x - window_frame.origin.x; - let width = close_screen_frame.size.width; - let height = close_screen_frame.size.height; + let left = min_x - window_frame.origin.x; if [top, left, width, height] .iter() @@ -111,3 +135,26 @@ fn read_macos_traffic_light_metrics_on_main_thread( height, })) } + +#[cfg(target_os = "macos")] +#[allow(dead_code)] +fn macos_window_button_screen_frame( + ns_window: &objc2_app_kit::NSWindow, + button: &objc2_app_kit::NSButton, +) -> (f64, f64, f64, f64) { + use objc2_app_kit::NSView; + + let frame = NSView::frame(button); + let window_frame = unsafe { + NSView::superview(button) + .map(|superview| superview.convertRect_toView(frame, None)) + .unwrap_or(frame) + }; + let screen_frame = ns_window.convertRectToScreen(window_frame); + ( + screen_frame.origin.x, + screen_frame.origin.y, + screen_frame.size.width, + screen_frame.size.height, + ) +} diff --git a/crates/agent-gui/src/components/MacOsTitleBarSpacer.tsx b/crates/agent-gui/src/components/MacOsTitleBarSpacer.tsx index 2561c6fc..89393b56 100644 --- a/crates/agent-gui/src/components/MacOsTitleBarSpacer.tsx +++ b/crates/agent-gui/src/components/MacOsTitleBarSpacer.tsx @@ -16,8 +16,11 @@ type MacOsTrafficLightMetrics = { // Fallback values match tauri.conf.json; runtime AppKit metrics replace them on macOS. const MAC_OS_TRAFFIC_LIGHT_TOP = 18; -const MAC_OS_TRAFFIC_LIGHT_DIAMETER = 12; +const MAC_OS_TRAFFIC_LIGHT_LEFT = 18; +const MAC_OS_TRAFFIC_LIGHT_GROUP_WIDTH = 52; +const MAC_OS_TRAFFIC_LIGHT_GROUP_HEIGHT = 12; const MAC_OS_TITLEBAR_TOGGLE_BUTTON_SIZE = 28; +const MAC_OS_TITLEBAR_TOGGLE_GAP = 22; function isValidMetrics( metrics: MacOsTrafficLightMetrics | null, @@ -104,13 +107,17 @@ export function MacOsTitleBarToggle({ const trafficLightMetrics = useMacOsTrafficLightMetrics(show); if (!show) return null; const trafficLightTop = trafficLightMetrics?.top ?? MAC_OS_TRAFFIC_LIGHT_TOP; - const trafficLightHeight = trafficLightMetrics?.height ?? MAC_OS_TRAFFIC_LIGHT_DIAMETER; + const trafficLightLeft = trafficLightMetrics?.left ?? MAC_OS_TRAFFIC_LIGHT_LEFT; + const trafficLightWidth = trafficLightMetrics?.width ?? MAC_OS_TRAFFIC_LIGHT_GROUP_WIDTH; + const trafficLightHeight = trafficLightMetrics?.height ?? MAC_OS_TRAFFIC_LIGHT_GROUP_HEIGHT; const toggleTop = trafficLightTop - (MAC_OS_TITLEBAR_TOGGLE_BUTTON_SIZE - trafficLightHeight) / 2; + const toggleLeft = trafficLightLeft + trafficLightWidth + MAC_OS_TITLEBAR_TOGGLE_GAP; return (