From 2b62b0b73c6dc8b5ba3ce11679aa5e83754665d4 Mon Sep 17 00:00:00 2001 From: Iuliia Ivashko Date: Fri, 30 Jan 2026 01:07:39 +0200 Subject: [PATCH 1/6] fix: macOS traffic lights and header padding --- packages/desktop/src-tauri/src/main.rs | 53 +++++++++++++++++-- packages/ui/src/components/layout/Header.tsx | 2 +- .../components/multirun/MultiRunLauncher.tsx | 2 +- 3 files changed, 52 insertions(+), 5 deletions(-) diff --git a/packages/desktop/src-tauri/src/main.rs b/packages/desktop/src-tauri/src/main.rs index 341c6600..d1dc59b8 100644 --- a/packages/desktop/src-tauri/src/main.rs +++ b/packages/desktop/src-tauri/src/main.rs @@ -324,6 +324,15 @@ fn get_macos_major_version() -> isize { version.majorVersion } +#[cfg(target_os = "macos")] +fn get_traffic_light_y(macos_version: isize) -> f64 { + if macos_version <= 15 { + 4.0 + } else { + 16.0 + } +} + #[cfg(target_os = "macos")] fn adjust_traffic_lights_position( window: &tauri::WebviewWindow, @@ -351,6 +360,41 @@ fn adjust_traffic_lights_position( } } +#[cfg(target_os = "macos")] +fn adjust_traffic_lights_centered( + window: &tauri::WebviewWindow, + fallback_x: f64, + y: f64, +) { + use objc2::msg_send; + use objc2::runtime::AnyObject; + use objc2_foundation::{NSPoint, NSRect}; + + if let Ok(ns_window) = window.ns_window() { + unsafe { + let ns_window: *mut AnyObject = ns_window.cast(); + let close_button: *mut AnyObject = msg_send![ns_window, standardWindowButton: 0usize]; + + if !close_button.is_null() { + let superview: *mut AnyObject = msg_send![close_button, superview]; + if !superview.is_null() { + let frame: NSRect = msg_send![superview, frame]; + let parent: *mut AnyObject = msg_send![superview, superview]; + if !parent.is_null() { + let parent_frame: NSRect = msg_send![parent, frame]; + let new_x = (parent_frame.size.width - frame.size.width) / 2.0; + let new_frame = NSRect::new(NSPoint::new(new_x, y), frame.size); + let _: () = msg_send![superview, setFrame: new_frame]; + return; + } + } + } + } + } + + adjust_traffic_lights_position(window, fallback_x, y); +} + #[cfg(target_os = "macos")] fn optimize_webview_layer(window: &tauri::WebviewWindow) { use objc2::msg_send; @@ -715,9 +759,10 @@ fn main() { let macos_version = get_macos_major_version(); info!("[macos] Detected macOS version: {}", macos_version); - if macos_version < 26 { + if macos_version <= 15 { NEEDS_TRAFFIC_LIGHT_FIX.store(true, Ordering::SeqCst); - adjust_traffic_lights_position(&window, 17.0, 16.0); + let traffic_light_y = get_traffic_light_y(macos_version); + adjust_traffic_lights_centered(&window, 17.0, traffic_light_y); } // Apply layer optimizations for smoother scrolling @@ -1087,7 +1132,9 @@ fn main() { #[cfg(target_os = "macos")] if NEEDS_TRAFFIC_LIGHT_FIX.load(Ordering::SeqCst) { if let Some(webview) = window.app_handle().get_webview_window("main") { - adjust_traffic_lights_position(&webview, 17.0, 16.0); + let macos_version = get_macos_major_version(); + let traffic_light_y = get_traffic_light_y(macos_version); + adjust_traffic_lights_centered(&webview, 17.0, traffic_light_y); } } } diff --git a/packages/ui/src/components/layout/Header.tsx b/packages/ui/src/components/layout/Header.tsx index 86191364..0b9ece79 100644 --- a/packages/ui/src/components/layout/Header.tsx +++ b/packages/ui/src/components/layout/Header.tsx @@ -284,7 +284,7 @@ export const Header: React.FC = () => { const desktopPaddingClass = React.useMemo(() => { if (isDesktopApp && isMacPlatform) { // Always reserve space for Mac traffic lights since header is always on top - return 'pl-[5.75rem]'; + return 'pl-[5.125rem]'; } return 'pl-3'; }, [isDesktopApp, isMacPlatform]); diff --git a/packages/ui/src/components/multirun/MultiRunLauncher.tsx b/packages/ui/src/components/multirun/MultiRunLauncher.tsx index 78ed41f6..699f3809 100644 --- a/packages/ui/src/components/multirun/MultiRunLauncher.tsx +++ b/packages/ui/src/components/multirun/MultiRunLauncher.tsx @@ -116,7 +116,7 @@ export const MultiRunLauncher: React.FC = ({ const desktopHeaderPaddingClass = React.useMemo(() => { if (isDesktopApp && isMacPlatform) { // Match main app header: reserve space for Mac traffic lights. - return 'pl-[5.75rem]'; + return 'pl-[5.125rem]'; } return 'pl-3'; }, [isDesktopApp, isMacPlatform]); From 63324f14d848e10c04495b75c6b631f3fc0134ac Mon Sep 17 00:00:00 2001 From: Iuliia Ivashko Date: Fri, 30 Jan 2026 01:11:48 +0200 Subject: [PATCH 2/6] build: switch release job to macos-15 runner for forward compatibility --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 6b7f3b8e..a2296a47 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -80,7 +80,7 @@ jobs: build-desktop-macos: needs: create-release - runs-on: macos-26 + runs-on: macos-15 strategy: fail-fast: false matrix: From 4af5b5dc75e0e61c07364fa3db7ceab18369815d Mon Sep 17 00:00:00 2001 From: Iuliia Ivashko Date: Fri, 30 Jan 2026 01:18:38 +0200 Subject: [PATCH 3/6] fix(SessionSidebar): prevent overflow in session name --- packages/ui/src/components/session/SessionSidebar.tsx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/ui/src/components/session/SessionSidebar.tsx b/packages/ui/src/components/session/SessionSidebar.tsx index caf82c54..92f90fdb 100644 --- a/packages/ui/src/components/session/SessionSidebar.tsx +++ b/packages/ui/src/components/session/SessionSidebar.tsx @@ -1234,17 +1234,17 @@ export const SessionSidebar: React.FC = ({ disabled={isMissingDirectory} onClick={() => handleSessionSelect(session.id, sessionDirectory, isMissingDirectory, projectId)} className={cn( - 'flex min-w-0 flex-1 flex-col gap-0 rounded-sm text-left focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/50 text-foreground select-none', + 'flex min-w-0 flex-1 flex-col gap-0 overflow-hidden rounded-sm text-left focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/50 text-foreground select-none', )} > {} -
+
{isStreaming ? ( ) : null} - +
{sessionTitle} - +
{pendingPermissionCount > 0 ? ( Date: Fri, 30 Jan 2026 01:44:33 +0200 Subject: [PATCH 4/6] feat(ui): adapt macOS header/vav bar height for legacy versions & fix traffic lights wobble --- packages/desktop/src-tauri/src/main.rs | 102 ------------------- packages/ui/src/components/layout/Header.tsx | 25 ++++- 2 files changed, 24 insertions(+), 103 deletions(-) diff --git a/packages/desktop/src-tauri/src/main.rs b/packages/desktop/src-tauri/src/main.rs index d1dc59b8..bd2c27f4 100644 --- a/packages/desktop/src-tauri/src/main.rs +++ b/packages/desktop/src-tauri/src/main.rs @@ -85,13 +85,6 @@ use tokio::{ use tower_http::cors::CorsLayer; use window_state::{load_window_state, persist_window_state, WindowStateManager}; -#[cfg(target_os = "macos")] -use std::sync::atomic::{AtomicBool, Ordering}; - - - -#[cfg(target_os = "macos")] -static NEEDS_TRAFFIC_LIGHT_FIX: AtomicBool = AtomicBool::new(false); const PROXY_BODY_LIMIT: usize = 50 * 1024 * 1024; // 50MB const CLIENT_RELOAD_DELAY_MS: u64 = 800; @@ -316,84 +309,6 @@ async fn desktop_open_devtools(window: WebviewWindow) -> Result<(), String> { Ok(()) } -#[cfg(target_os = "macos")] -fn get_macos_major_version() -> isize { - use objc2_foundation::NSProcessInfo; - let process_info = NSProcessInfo::processInfo(); - let version = process_info.operatingSystemVersion(); - version.majorVersion -} - -#[cfg(target_os = "macos")] -fn get_traffic_light_y(macos_version: isize) -> f64 { - if macos_version <= 15 { - 4.0 - } else { - 16.0 - } -} - -#[cfg(target_os = "macos")] -fn adjust_traffic_lights_position( - window: &tauri::WebviewWindow, - x: f64, - y: f64, -) { - use objc2::msg_send; - use objc2::runtime::AnyObject; - use objc2_foundation::{NSPoint, NSRect}; - - if let Ok(ns_window) = window.ns_window() { - unsafe { - let ns_window: *mut AnyObject = ns_window.cast(); - let close_button: *mut AnyObject = msg_send![ns_window, standardWindowButton: 0usize]; - - if !close_button.is_null() { - let superview: *mut AnyObject = msg_send![close_button, superview]; - if !superview.is_null() { - let frame: NSRect = msg_send![superview, frame]; - let new_frame = NSRect::new(NSPoint::new(x, y), frame.size); - let _: () = msg_send![superview, setFrame: new_frame]; - } - } - } - } -} - -#[cfg(target_os = "macos")] -fn adjust_traffic_lights_centered( - window: &tauri::WebviewWindow, - fallback_x: f64, - y: f64, -) { - use objc2::msg_send; - use objc2::runtime::AnyObject; - use objc2_foundation::{NSPoint, NSRect}; - - if let Ok(ns_window) = window.ns_window() { - unsafe { - let ns_window: *mut AnyObject = ns_window.cast(); - let close_button: *mut AnyObject = msg_send![ns_window, standardWindowButton: 0usize]; - - if !close_button.is_null() { - let superview: *mut AnyObject = msg_send![close_button, superview]; - if !superview.is_null() { - let frame: NSRect = msg_send![superview, frame]; - let parent: *mut AnyObject = msg_send![superview, superview]; - if !parent.is_null() { - let parent_frame: NSRect = msg_send![parent, frame]; - let new_x = (parent_frame.size.width - frame.size.width) / 2.0; - let new_frame = NSRect::new(NSPoint::new(new_x, y), frame.size); - let _: () = msg_send![superview, setFrame: new_frame]; - return; - } - } - } - } - } - - adjust_traffic_lights_position(window, fallback_x, y); -} #[cfg(target_os = "macos")] fn optimize_webview_layer(window: &tauri::WebviewWindow) { @@ -756,15 +671,6 @@ fn main() { if let Some(window) = app.get_webview_window("main") { #[cfg(target_os = "macos")] { - let macos_version = get_macos_major_version(); - info!("[macos] Detected macOS version: {}", macos_version); - - if macos_version <= 15 { - NEEDS_TRAFFIC_LIGHT_FIX.store(true, Ordering::SeqCst); - let traffic_light_y = get_traffic_light_y(macos_version); - adjust_traffic_lights_centered(&window, 17.0, traffic_light_y); - } - // Apply layer optimizations for smoother scrolling optimize_webview_layer(&window); } @@ -1129,14 +1035,6 @@ fn main() { size.height as f64, is_maximized, ); - #[cfg(target_os = "macos")] - if NEEDS_TRAFFIC_LIGHT_FIX.load(Ordering::SeqCst) { - if let Some(webview) = window.app_handle().get_webview_window("main") { - let macos_version = get_macos_major_version(); - let traffic_light_y = get_traffic_light_y(macos_version); - adjust_traffic_lights_centered(&webview, 17.0, traffic_light_y); - } - } } tauri::WindowEvent::CloseRequested { api, .. } => { api.prevent_close(); diff --git a/packages/ui/src/components/layout/Header.tsx b/packages/ui/src/components/layout/Header.tsx index 0b9ece79..0a583172 100644 --- a/packages/ui/src/components/layout/Header.tsx +++ b/packages/ui/src/components/layout/Header.tsx @@ -107,6 +107,18 @@ export const Header: React.FC = () => { return /Macintosh|Mac OS X/.test(navigator.userAgent || ''); }, []); + const macosMajorVersion = React.useMemo(() => { + if (typeof navigator === 'undefined') { + return null; + } + const match = (navigator.userAgent || '').match(/Mac OS X (\d+)[._]/); + if (!match) { + return null; + } + const parsed = Number.parseInt(match[1], 10); + return Number.isNaN(parsed) ? null : parsed; + }, []); + useEffect(() => { if (typeof window === 'undefined') { return; @@ -289,6 +301,16 @@ export const Header: React.FC = () => { return 'pl-3'; }, [isDesktopApp, isMacPlatform]); + const macosHeaderSizeClass = React.useMemo(() => { + if (!isDesktopApp || !isMacPlatform) { + return ''; + } + if (macosMajorVersion === null || macosMajorVersion > 15) { + return ''; + } + return 'h-14'; + }, [isDesktopApp, isMacPlatform, macosMajorVersion]); + const updateHeaderHeight = React.useCallback(() => { if (typeof document === 'undefined') { return; @@ -463,7 +485,8 @@ export const Header: React.FC = () => { onMouseDown={handleDragStart} className={cn( 'app-region-drag relative flex h-12 select-none items-center', - desktopPaddingClass + desktopPaddingClass, + macosHeaderSizeClass )} role="tablist" aria-label="Main navigation" From 2d305d18c6652a323bf8b8fdd7a3c3805afb6a6b Mon Sep 17 00:00:00 2001 From: Bohdan Triapitsyn Date: Fri, 30 Jan 2026 02:46:43 +0200 Subject: [PATCH 5/6] feat(desktop): enable macOS version awareness for UI adjustments - Fetch macOS major version from Rust to determine layout - Adjust header padding and height for macOS versions --- packages/desktop/src-tauri/src/main.rs | 18 ++++++++++ packages/desktop/src/main.tsx | 11 ++++++ .../ui/src/components/chat/ChatMessage.tsx | 8 +++-- packages/ui/src/components/layout/Header.tsx | 34 ++++++++++++++----- .../components/multirun/MultiRunLauncher.tsx | 30 ++++++++++------ packages/ui/src/hooks/useKeyboardShortcuts.ts | 4 ++- packages/ui/src/lib/desktop.ts | 1 + packages/ui/src/stores/useUIStore.ts | 7 ++++ 8 files changed, 91 insertions(+), 22 deletions(-) diff --git a/packages/desktop/src-tauri/src/main.rs b/packages/desktop/src-tauri/src/main.rs index bd2c27f4..8b670920 100644 --- a/packages/desktop/src-tauri/src/main.rs +++ b/packages/desktop/src-tauri/src/main.rs @@ -309,6 +309,23 @@ async fn desktop_open_devtools(window: WebviewWindow) -> Result<(), String> { Ok(()) } +#[cfg(target_os = "macos")] +fn get_macos_major_version() -> isize { + use objc2_foundation::NSProcessInfo; + let process_info = NSProcessInfo::processInfo(); + let version = process_info.operatingSystemVersion(); + version.majorVersion +} + +#[cfg(not(target_os = "macos"))] +fn get_macos_major_version() -> isize { + 0 +} + +#[tauri::command] +fn desktop_get_macos_version() -> isize { + get_macos_major_version() +} #[cfg(target_os = "macos")] fn optimize_webview_layer(window: &tauri::WebviewWindow) { @@ -807,6 +824,7 @@ fn main() { .invoke_handler(tauri::generate_handler![ desktop_server_info, desktop_restart_opencode, + desktop_get_macos_version, #[cfg(feature = "devtools")] desktop_open_devtools, load_settings, diff --git a/packages/desktop/src/main.tsx b/packages/desktop/src/main.tsx index c69396c3..82e67106 100644 --- a/packages/desktop/src/main.tsx +++ b/packages/desktop/src/main.tsx @@ -122,6 +122,7 @@ if (homeDirectory) { window.opencodeDesktop = { homeDirectory, + macosMajorVersion: null as number | null, async getServerInfo() { try { const info = await invoke('desktop_server_info'); @@ -262,6 +263,16 @@ window.opencodeDesktop = { } }; +// Fetch macOS version from Rust +try { + const macosVersion = await invoke('desktop_get_macos_version'); + window.opencodeDesktop.macosMajorVersion = macosVersion > 0 ? macosVersion : null; + console.info('[main] macOS version:', macosVersion); +} catch (err) { + console.warn('[main] Failed to get macOS version:', err); + window.opencodeDesktop.macosMajorVersion = null; +} + console.info('[main] window.opencodeDesktop assigned'); if (typeof window !== 'undefined') { diff --git a/packages/ui/src/components/chat/ChatMessage.tsx b/packages/ui/src/components/chat/ChatMessage.tsx index 8e552e88..fbec6ad4 100644 --- a/packages/ui/src/components/chat/ChatMessage.tsx +++ b/packages/ui/src/components/chat/ChatMessage.tsx @@ -755,16 +755,20 @@ const ChatMessage: React.FC = ({ onContentChange?.('structural'); }, [isUser, onContentChange]); + const setImagePreviewOpen = useUIStore((state) => state.setImagePreviewOpen); + const handleShowPopup = React.useCallback((content: ToolPopupContent) => { if (content.image) { setPopupContent(content); + setImagePreviewOpen(true); } - }, []); + }, [setImagePreviewOpen]); const handlePopupChange = React.useCallback((open: boolean) => { setPopupContent((prev) => ({ ...prev, open })); - }, []); + setImagePreviewOpen(open); + }, [setImagePreviewOpen]); const isAnimationSettled = Boolean(getMessageInfoProp(message.info, 'animationSettled')); const isStreamingPhase = streamPhase === 'streaming'; diff --git a/packages/ui/src/components/layout/Header.tsx b/packages/ui/src/components/layout/Header.tsx index 0a583172..093812d2 100644 --- a/packages/ui/src/components/layout/Header.tsx +++ b/packages/ui/src/components/layout/Header.tsx @@ -108,15 +108,28 @@ export const Header: React.FC = () => { }, []); const macosMajorVersion = React.useMemo(() => { + if (typeof window === 'undefined') { + return null; + } + // Use Tauri-provided version if available (accurate), otherwise fall back to UA parsing + const desktopApi = (window as typeof window & { opencodeDesktop?: { macosMajorVersion?: number | null } }).opencodeDesktop; + if (desktopApi?.macosMajorVersion != null) { + return desktopApi.macosMajorVersion; + } + // Fallback: WebKit reports "Mac OS X 10_15_7" format where 10 is legacy prefix if (typeof navigator === 'undefined') { return null; } - const match = (navigator.userAgent || '').match(/Mac OS X (\d+)[._]/); + const match = (navigator.userAgent || '').match(/Mac OS X (\d+)[._](\d+)/); if (!match) { return null; } - const parsed = Number.parseInt(match[1], 10); - return Number.isNaN(parsed) ? null : parsed; + const first = Number.parseInt(match[1], 10); + const second = Number.parseInt(match[2], 10); + if (Number.isNaN(first)) { + return null; + } + return first === 10 ? second : first; }, []); useEffect(() => { @@ -296,19 +309,22 @@ export const Header: React.FC = () => { const desktopPaddingClass = React.useMemo(() => { if (isDesktopApp && isMacPlatform) { // Always reserve space for Mac traffic lights since header is always on top - return 'pl-[5.125rem]'; + return 'pl-[5.5rem]'; } return 'pl-3'; }, [isDesktopApp, isMacPlatform]); const macosHeaderSizeClass = React.useMemo(() => { - if (!isDesktopApp || !isMacPlatform) { + if (!isDesktopApp || !isMacPlatform || macosMajorVersion === null) { return ''; } - if (macosMajorVersion === null || macosMajorVersion > 15) { - return ''; + if (macosMajorVersion >= 26) { + return 'h-12'; } - return 'h-14'; + if (macosMajorVersion <= 15) { + return 'h-14'; + } + return ''; }, [isDesktopApp, isMacPlatform, macosMajorVersion]); const updateHeaderHeight = React.useCallback(() => { @@ -351,7 +367,7 @@ export const Header: React.FC = () => { useEffect(() => { updateHeaderHeight(); - }, [updateHeaderHeight, isMobile]); + }, [updateHeaderHeight, isMobile, macosHeaderSizeClass]); const handleDragStart = React.useCallback(async (e: React.MouseEvent) => { if ((e.target as HTMLElement).closest('button, a, input, select, textarea')) { diff --git a/packages/ui/src/components/multirun/MultiRunLauncher.tsx b/packages/ui/src/components/multirun/MultiRunLauncher.tsx index 699f3809..e571cf8b 100644 --- a/packages/ui/src/components/multirun/MultiRunLauncher.tsx +++ b/packages/ui/src/components/multirun/MultiRunLauncher.tsx @@ -116,7 +116,7 @@ export const MultiRunLauncher: React.FC = ({ const desktopHeaderPaddingClass = React.useMemo(() => { if (isDesktopApp && isMacPlatform) { // Match main app header: reserve space for Mac traffic lights. - return 'pl-[5.125rem]'; + return 'pl-[5.5rem]'; } return 'pl-3'; }, [isDesktopApp, isMacPlatform]); @@ -139,6 +139,20 @@ export const MultiRunLauncher: React.FC = ({ } }, [isDesktopApp]); + // Handle ESC key to dismiss + React.useEffect(() => { + if (!onCancel) return; + const handleKeyDown = (e: KeyboardEvent) => { + if (e.key === 'Escape') { + e.preventDefault(); + e.stopPropagation(); + onCancel(); + } + }; + window.addEventListener('keydown', handleKeyDown, true); + return () => window.removeEventListener('keydown', handleKeyDown, true); + }, [onCancel]); + // Use the BranchSelector hook for branch state management const [worktreeBaseBranch, setWorktreeBaseBranch] = React.useState('HEAD'); const { isLoading: isLoadingWorktreeBaseBranches, isGitRepository } = useBranchOptions(currentDirectory); @@ -306,31 +320,27 @@ export const MultiRunLauncher: React.FC = ({
-
-

New Multi-Run

-
+

New Multi-Run

{onCancel && ( -
+
-

Close

+

Close (Esc)

diff --git a/packages/ui/src/hooks/useKeyboardShortcuts.ts b/packages/ui/src/hooks/useKeyboardShortcuts.ts index 74287442..d5a899e8 100644 --- a/packages/ui/src/hooks/useKeyboardShortcuts.ts +++ b/packages/ui/src/hooks/useKeyboardShortcuts.ts @@ -226,6 +226,8 @@ export const useKeyboardShortcuts = () => { isHelpDialogOpen, isSessionSwitcherOpen, isAboutDialogOpen, + isMultiRunLauncherOpen, + isImagePreviewOpen, activeMainTab, } = useUIStore.getState(); @@ -238,7 +240,7 @@ export const useKeyboardShortcuts = () => { } // Check if any overlay is open or not on chat tab - don't process abort - const hasOverlay = isCommandPaletteOpen || isHelpDialogOpen || isSessionSwitcherOpen || isAboutDialogOpen; + const hasOverlay = isCommandPaletteOpen || isHelpDialogOpen || isSessionSwitcherOpen || isAboutDialogOpen || isMultiRunLauncherOpen || isImagePreviewOpen; const isChatActive = activeMainTab === 'chat'; if (hasOverlay || !isChatActive) { diff --git a/packages/ui/src/lib/desktop.ts b/packages/ui/src/lib/desktop.ts index 2450a1e2..8e19cd27 100644 --- a/packages/ui/src/lib/desktop.ts +++ b/packages/ui/src/lib/desktop.ts @@ -89,6 +89,7 @@ export type DesktopSettingsApi = { export type DesktopApi = { homeDirectory?: string; + macosMajorVersion?: number | null; getServerInfo: () => Promise; restartOpenCode: () => Promise<{ success: boolean }>; shutdown: () => Promise<{ success: boolean }>; diff --git a/packages/ui/src/stores/useUIStore.ts b/packages/ui/src/stores/useUIStore.ts index 26da7228..4fb1459c 100644 --- a/packages/ui/src/stores/useUIStore.ts +++ b/packages/ui/src/stores/useUIStore.ts @@ -62,6 +62,7 @@ interface UIStore { diffWrapLines: boolean; diffViewMode: 'single' | 'stacked'; isTimelineDialogOpen: boolean; + isImagePreviewOpen: boolean; nativeNotificationsEnabled: boolean; notificationMode: 'always' | 'hidden-only'; @@ -113,6 +114,7 @@ interface UIStore { setDiffViewMode: (mode: 'single' | 'stacked') => void; setMultiRunLauncherOpen: (open: boolean) => void; setTimelineDialogOpen: (open: boolean) => void; + setImagePreviewOpen: (open: boolean) => void; setNativeNotificationsEnabled: (value: boolean) => void; setNotificationMode: (mode: 'always' | 'hidden-only') => void; openMultiRunLauncher: () => void; @@ -165,6 +167,7 @@ export const useUIStore = create()( diffWrapLines: false, diffViewMode: 'stacked', isTimelineDialogOpen: false, + isImagePreviewOpen: false, nativeNotificationsEnabled: false, notificationMode: 'hidden-only', @@ -534,6 +537,10 @@ export const useUIStore = create()( set({ isTimelineDialogOpen: open }); }, + setImagePreviewOpen: (open) => { + set({ isImagePreviewOpen: open }); + }, + setNativeNotificationsEnabled: (value) => { set({ nativeNotificationsEnabled: value }); }, From 9b706119e6053e64835cbc587068065044ab56c0 Mon Sep 17 00:00:00 2001 From: Iuliia Ivashko Date: Fri, 30 Jan 2026 02:56:16 +0200 Subject: [PATCH 6/6] style: fix session sidebar title truncation to show elipsis for UX consistency --- packages/ui/src/components/session/SessionSidebar.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/ui/src/components/session/SessionSidebar.tsx b/packages/ui/src/components/session/SessionSidebar.tsx index 92f90fdb..d8647a06 100644 --- a/packages/ui/src/components/session/SessionSidebar.tsx +++ b/packages/ui/src/components/session/SessionSidebar.tsx @@ -1238,11 +1238,11 @@ export const SessionSidebar: React.FC = ({ )} > {} -
+
{isStreaming ? ( ) : null} -
+
{sessionTitle}