diff --git a/packages/ui/src/components/layout/Header.tsx b/packages/ui/src/components/layout/Header.tsx index e359fea8..0f6b91b5 100644 --- a/packages/ui/src/components/layout/Header.tsx +++ b/packages/ui/src/components/layout/Header.tsx @@ -5,7 +5,7 @@ import { TooltipTrigger, } from '@/components/ui/tooltip'; -import { RiChat4Line, RiCodeLine, RiGitBranchLine, RiLayoutLeftLine, RiPlayListAddLine, RiTerminalBoxLine, type RemixiconComponentType } from '@remixicon/react'; +import { RiChat4Line, RiCodeLine, RiGitBranchLine, RiLayoutLeftLine, RiPlayListAddLine, RiSettings3Line, RiTerminalBoxLine, type RemixiconComponentType } from '@remixicon/react'; import { useUIStore, type MainTab } from '@/stores/useUIStore'; import { useConfigStore } from '@/stores/useConfigStore'; import { useSessionStore } from '@/stores/useSessionStore'; @@ -82,6 +82,7 @@ export const FixedSessionsButton: React.FC = () => { export const Header: React.FC = () => { const setSessionSwitcherOpen = useUIStore((state) => state.setSessionSwitcherOpen); const toggleSidebar = useUIStore((state) => state.toggleSidebar); + const setSettingsDialogOpen = useUIStore((state) => state.setSettingsDialogOpen); const isSidebarOpen = useUIStore((state) => state.isSidebarOpen); const sidebarWidth = useUIStore((state) => state.sidebarWidth); const activeMainTab = useUIStore((state) => state.activeMainTab); @@ -134,6 +135,11 @@ export const Header: React.FC = () => { toggleSidebar(); }, [isMobile, isSessionSwitcherOpen, setSessionSwitcherOpen, toggleSidebar]); + const handleOpenSettings = React.useCallback(() => { + setSessionSwitcherOpen(false); + setSettingsDialogOpen(true); + }, [setSessionSwitcherOpen, setSettingsDialogOpen]); + const headerIconButtonClass = 'app-region-no-drag inline-flex h-9 w-9 items-center justify-center gap-2 p-2 typography-ui-label font-medium text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary disabled:pointer-events-none disabled:opacity-50 hover:text-foreground'; const desktopPaddingClass = React.useMemo(() => { @@ -415,6 +421,22 @@ export const Header: React.FC = () => { ); })} + + + + + + +

Settings

+
+
); diff --git a/packages/ui/src/components/layout/SettingsDialog.tsx b/packages/ui/src/components/layout/SettingsDialog.tsx index 68c1a9a0..223ec644 100644 --- a/packages/ui/src/components/layout/SettingsDialog.tsx +++ b/packages/ui/src/components/layout/SettingsDialog.tsx @@ -137,7 +137,10 @@ export const SettingsDialog: React.FC = ({ isOpen, onClose ); const mainContent = ( -
+
{SETTINGS_SECTIONS.map(({ id, label, icon: Icon }) => { const isActive = activeTab === id; @@ -204,6 +207,7 @@ export const SettingsDialog: React.FC = ({ isOpen, onClose onClose={onClose} title="Settings" className="max-w-full" + contentMaxHeightClassName="h-[min(80dvh,720px)]" renderHeader={(closeButton) => (
diff --git a/packages/ui/src/components/sections/settings/AppearanceSettings.tsx b/packages/ui/src/components/sections/settings/AppearanceSettings.tsx index 2fe30bc1..dcb11419 100644 --- a/packages/ui/src/components/sections/settings/AppearanceSettings.tsx +++ b/packages/ui/src/components/sections/settings/AppearanceSettings.tsx @@ -8,6 +8,7 @@ import { cn } from '@/lib/utils'; import { ButtonSmall } from '@/components/ui/button-small'; import { NumberInput } from '@/components/ui/number-input'; import { isVSCodeRuntime } from '@/lib/desktop'; +import { useDeviceInfo } from '@/lib/device'; interface Option { id: T; @@ -55,6 +56,7 @@ const DIFF_LAYOUT_OPTIONS: Option<'dynamic' | 'inline' | 'side-by-side'>[] = [ ]; export const AppearanceSettings: React.FC = () => { + const { isMobile } = useDeviceInfo(); const showReasoningTraces = useUIStore(state => state.showReasoningTraces); const setShowReasoningTraces = useUIStore(state => state.setShowReasoningTraces); const toolCallExpansion = useUIStore(state => state.toolCallExpansion); @@ -95,44 +97,46 @@ export const AppearanceSettings: React.FC = () => {
)} -
-
-

- Font Size -

+ {!isMobile && ( +
+
+

+ Font Size +

+
+
+ setFontSize(Number(e.target.value))} + className="flex-1 min-w-0 h-2 bg-muted rounded-lg appearance-none cursor-pointer [&::-webkit-slider-thumb]:appearance-none [&::-webkit-slider-thumb]:w-4 [&::-webkit-slider-thumb]:h-4 [&::-webkit-slider-thumb]:rounded-full [&::-webkit-slider-thumb]:bg-primary [&::-moz-range-thumb]:w-4 [&::-moz-range-thumb]:h-4 [&::-moz-range-thumb]:rounded-full [&::-moz-range-thumb]:bg-primary [&::-moz-range-thumb]:border-0" + /> + + setFontSize(100)} + disabled={fontSize === 100} + className="h-8 w-8 px-0 border border-border bg-background hover:bg-accent disabled:opacity-100 disabled:bg-background" + aria-label="Reset font size" + title="Reset" + > + + +
-
- setFontSize(Number(e.target.value))} - className="flex-1 min-w-0 h-2 bg-muted rounded-lg appearance-none cursor-pointer [&::-webkit-slider-thumb]:appearance-none [&::-webkit-slider-thumb]:w-4 [&::-webkit-slider-thumb]:h-4 [&::-webkit-slider-thumb]:rounded-full [&::-webkit-slider-thumb]:bg-primary [&::-moz-range-thumb]:w-4 [&::-moz-range-thumb]:h-4 [&::-moz-range-thumb]:rounded-full [&::-moz-range-thumb]:bg-primary [&::-moz-range-thumb]:border-0" - /> - - setFontSize(100)} - disabled={fontSize === 100} - className="h-8 w-8 px-0 border border-border bg-background hover:bg-accent disabled:opacity-100 disabled:bg-background" - aria-label="Reset font size" - title="Reset" - > - - -
-
+ )}
@@ -141,36 +145,68 @@ export const AppearanceSettings: React.FC = () => {
-
- setPadding(Number(e.target.value))} - className="flex-1 min-w-0 h-2 bg-muted rounded-lg appearance-none cursor-pointer [&::-webkit-slider-thumb]:appearance-none [&::-webkit-slider-thumb]:w-4 [&::-webkit-slider-thumb]:h-4 [&::-webkit-slider-thumb]:rounded-full [&::-webkit-slider-thumb]:bg-primary [&::-moz-range-thumb]:w-4 [&::-moz-range-thumb]:h-4 [&::-moz-range-thumb]:rounded-full [&::-moz-range-thumb]:bg-primary [&::-moz-range-thumb]:border-0" - /> - - setPadding(100)} - disabled={padding === 100} - className="h-8 w-8 px-0 border border-border bg-background hover:bg-accent disabled:opacity-100 disabled:bg-background" - aria-label="Reset spacing" - title="Reset" - > - - -
+ + {isMobile ? ( +
+ setPadding(Number(e.target.value))} + className="flex-1 min-w-0 h-3 bg-muted rounded-full appearance-none cursor-pointer [&::-webkit-slider-thumb]:appearance-none [&::-webkit-slider-thumb]:w-5 [&::-webkit-slider-thumb]:h-5 [&::-webkit-slider-thumb]:rounded-full [&::-webkit-slider-thumb]:bg-primary [&::-moz-range-thumb]:w-5 [&::-moz-range-thumb]:h-5 [&::-moz-range-thumb]:rounded-full [&::-moz-range-thumb]:bg-primary [&::-moz-range-thumb]:border-0" + aria-label="Spacing percentage" + /> + + + {padding} + + + setPadding(100)} + disabled={padding === 100} + className="h-8 w-8 px-0 border border-border bg-background hover:bg-accent disabled:opacity-100 disabled:bg-background" + aria-label="Reset spacing" + title="Reset" + > + + +
+ ) : ( +
+ setPadding(Number(e.target.value))} + className="flex-1 min-w-0 h-2 bg-muted rounded-lg appearance-none cursor-pointer [&::-webkit-slider-thumb]:appearance-none [&::-webkit-slider-thumb]:w-4 [&::-webkit-slider-thumb]:h-4 [&::-webkit-slider-thumb]:rounded-full [&::-webkit-slider-thumb]:bg-primary [&::-moz-range-thumb]:w-4 [&::-moz-range-thumb]:h-4 [&::-moz-range-thumb]:rounded-full [&::-moz-range-thumb]:bg-primary [&::-moz-range-thumb]:border-0" + /> + + setPadding(100)} + disabled={padding === 100} + className="h-8 w-8 px-0 border border-border bg-background hover:bg-accent disabled:opacity-100 disabled:bg-background" + aria-label="Reset spacing" + title="Reset" + > + + +
+ )}
@@ -197,34 +233,36 @@ export const AppearanceSettings: React.FC = () => {
{} -
-
-

- Diff layout (Diff tab) -

-

- Choose the default layout for file diffs. You can still override layout per file from the Diff tab. -

-
- -
-
- {DIFF_LAYOUT_OPTIONS.map((option) => ( - setDiffLayoutPreference(option.id)} - > - {option.label} - - ))} + {!isMobile && ( +
+
+

+ Diff layout (Diff tab) +

+

+ Choose the default layout for file diffs. You can still override layout per file from the Diff tab. +

+
+ +
+
+ {DIFF_LAYOUT_OPTIONS.map((option) => ( + setDiffLayoutPreference(option.id)} + > + {option.label} + + ))} +
+

+ {DIFF_LAYOUT_OPTIONS.find((option) => option.id === diffLayoutPreference)?.description} +

-

- {DIFF_LAYOUT_OPTIONS.find((option) => option.id === diffLayoutPreference)?.description} -

-
+ )} {}