feat(ui): integrate Electron mode detection for conditional UI rendering
- Added `isElectronMode` function to determine if the app is running in Electron or a browser. - Updated `SidebarHeader`, `TabBar`, and `TabbedLayout` components to conditionally render UI elements based on the Electron mode. - Adjusted styles and settings gear icon visibility to enhance user experience in browser mode. This commit improves the application's adaptability by ensuring that Electron-specific features are only available when appropriate.
This commit is contained in:
parent
7fa2f96ed4
commit
656c9b155f
4 changed files with 32 additions and 18 deletions
|
|
@ -39,6 +39,12 @@ function getImpl(): ElectronAPI {
|
||||||
* In browser: delegates to `HttpAPIClient` (created on first use).
|
* In browser: delegates to `HttpAPIClient` (created on first use).
|
||||||
* In tests: delegates to whatever mock is installed on `window.electronAPI`.
|
* In tests: delegates to whatever mock is installed on `window.electronAPI`.
|
||||||
*/
|
*/
|
||||||
|
/**
|
||||||
|
* Whether the app is running inside Electron (true) or in a browser via HTTP server (false).
|
||||||
|
* Use this to hide Electron-only UI (settings, traffic lights, etc.) in browser mode.
|
||||||
|
*/
|
||||||
|
export const isElectronMode = (): boolean => !!window.electronAPI;
|
||||||
|
|
||||||
export const api: ElectronAPI = new Proxy({} as ElectronAPI, {
|
export const api: ElectronAPI = new Proxy({} as ElectronAPI, {
|
||||||
get(_target, prop, receiver) {
|
get(_target, prop, receiver) {
|
||||||
const impl = getImpl();
|
const impl = getImpl();
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@
|
||||||
|
|
||||||
import { useEffect, useRef, useState } from 'react';
|
import { useEffect, useRef, useState } from 'react';
|
||||||
|
|
||||||
|
import { isElectronMode } from '@renderer/api';
|
||||||
import { HEADER_ROW1_HEIGHT, HEADER_ROW2_HEIGHT } from '@renderer/constants/layout';
|
import { HEADER_ROW1_HEIGHT, HEADER_ROW2_HEIGHT } from '@renderer/constants/layout';
|
||||||
import { useStore } from '@renderer/store';
|
import { useStore } from '@renderer/store';
|
||||||
import { truncateMiddle } from '@renderer/utils/stringUtils';
|
import { truncateMiddle } from '@renderer/utils/stringUtils';
|
||||||
|
|
@ -330,8 +331,10 @@ export const SidebarHeader = (): React.JSX.Element => {
|
||||||
style={
|
style={
|
||||||
{
|
{
|
||||||
height: `${HEADER_ROW1_HEIGHT}px`,
|
height: `${HEADER_ROW1_HEIGHT}px`,
|
||||||
paddingLeft: 'var(--macos-traffic-light-padding-left, 72px)',
|
paddingLeft: isElectronMode()
|
||||||
WebkitAppRegion: 'drag',
|
? 'var(--macos-traffic-light-padding-left, 72px)'
|
||||||
|
: '16px',
|
||||||
|
WebkitAppRegion: isElectronMode() ? 'drag' : undefined,
|
||||||
} as React.CSSProperties
|
} as React.CSSProperties
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
||||||
|
|
||||||
import { useDroppable } from '@dnd-kit/core';
|
import { useDroppable } from '@dnd-kit/core';
|
||||||
import { horizontalListSortingStrategy, SortableContext } from '@dnd-kit/sortable';
|
import { horizontalListSortingStrategy, SortableContext } from '@dnd-kit/sortable';
|
||||||
|
import { isElectronMode } from '@renderer/api';
|
||||||
import { HEADER_ROW1_HEIGHT } from '@renderer/constants/layout';
|
import { HEADER_ROW1_HEIGHT } from '@renderer/constants/layout';
|
||||||
import { useStore } from '@renderer/store';
|
import { useStore } from '@renderer/store';
|
||||||
import { Bell, PanelLeft, Plus, RefreshCw, Search, Settings } from 'lucide-react';
|
import { Bell, PanelLeft, Plus, RefreshCw, Search, Settings } from 'lucide-react';
|
||||||
|
|
@ -250,7 +251,8 @@ export const TabBar = ({ paneId }: TabBarProps): React.JSX.Element => {
|
||||||
sidebarCollapsed && isLeftmostPane
|
sidebarCollapsed && isLeftmostPane
|
||||||
? 'var(--macos-traffic-light-padding-left, 72px)'
|
? 'var(--macos-traffic-light-padding-left, 72px)'
|
||||||
: '8px',
|
: '8px',
|
||||||
WebkitAppRegion: sidebarCollapsed && isLeftmostPane ? 'drag' : undefined,
|
WebkitAppRegion:
|
||||||
|
isElectronMode() && sidebarCollapsed && isLeftmostPane ? 'drag' : undefined,
|
||||||
backgroundColor: 'var(--color-surface)',
|
backgroundColor: 'var(--color-surface)',
|
||||||
borderBottom: '1px solid var(--color-border)',
|
borderBottom: '1px solid var(--color-border)',
|
||||||
opacity: isFocused || paneCount === 1 ? 1 : 0.7,
|
opacity: isFocused || paneCount === 1 ? 1 : 0.7,
|
||||||
|
|
@ -382,20 +384,22 @@ export const TabBar = ({ paneId }: TabBarProps): React.JSX.Element => {
|
||||||
)}
|
)}
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
{/* Settings gear icon */}
|
{/* Settings gear icon (Electron only - browser can't access native settings) */}
|
||||||
<button
|
{isElectronMode() && (
|
||||||
onClick={openSettingsTab}
|
<button
|
||||||
onMouseEnter={() => setSettingsHover(true)}
|
onClick={openSettingsTab}
|
||||||
onMouseLeave={() => setSettingsHover(false)}
|
onMouseEnter={() => setSettingsHover(true)}
|
||||||
className="rounded-md p-2 transition-colors"
|
onMouseLeave={() => setSettingsHover(false)}
|
||||||
style={{
|
className="rounded-md p-2 transition-colors"
|
||||||
color: settingsHover ? 'var(--color-text)' : 'var(--color-text-muted)',
|
style={{
|
||||||
backgroundColor: settingsHover ? 'var(--color-surface-raised)' : 'transparent',
|
color: settingsHover ? 'var(--color-text)' : 'var(--color-text-muted)',
|
||||||
}}
|
backgroundColor: settingsHover ? 'var(--color-surface-raised)' : 'transparent',
|
||||||
title="Settings"
|
}}
|
||||||
>
|
title="Settings"
|
||||||
<Settings className="size-4" />
|
>
|
||||||
</button>
|
<Settings className="size-4" />
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Context menu */}
|
{/* Context menu */}
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@
|
||||||
* - Main content: PaneContainer with one or more panes, each with TabBar + content
|
* - Main content: PaneContainer with one or more panes, each with TabBar + content
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import { isElectronMode } from '@renderer/api';
|
||||||
import { getTrafficLightPaddingForZoom } from '@renderer/constants/layout';
|
import { getTrafficLightPaddingForZoom } from '@renderer/constants/layout';
|
||||||
import { useKeyboardShortcuts } from '@renderer/hooks/useKeyboardShortcuts';
|
import { useKeyboardShortcuts } from '@renderer/hooks/useKeyboardShortcuts';
|
||||||
import { useZoomFactor } from '@renderer/hooks/useZoomFactor';
|
import { useZoomFactor } from '@renderer/hooks/useZoomFactor';
|
||||||
|
|
@ -64,7 +65,7 @@ export const TabbedLayout = (): React.JSX.Element => {
|
||||||
// Enable keyboard shortcuts
|
// Enable keyboard shortcuts
|
||||||
useKeyboardShortcuts();
|
useKeyboardShortcuts();
|
||||||
const zoomFactor = useZoomFactor();
|
const zoomFactor = useZoomFactor();
|
||||||
const trafficLightPadding = getTrafficLightPaddingForZoom(zoomFactor);
|
const trafficLightPadding = isElectronMode() ? getTrafficLightPaddingForZoom(zoomFactor) : 0;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue