Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
127 changes: 68 additions & 59 deletions src/browser/components/ChatInput/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2118,67 +2118,71 @@ const ChatInputInner: React.FC<ChatInputProps> = (props) => {
</div>
)}

<div className="@container flex flex-wrap items-center gap-x-3 gap-y-1">
{/* Model Selector - always visible */}
<div
className="flex items-center"
data-component="ModelSelectorGroup"
data-tutorial="model-selector"
>
<ModelSelector
ref={modelSelectorRef}
value={baseModel}
onChange={setPreferredModel}
models={models}
onComplete={() => inputRef.current?.focus()}
defaultModel={defaultModel}
onSetDefaultModel={setDefaultModel}
onHideModel={hideModel}
hiddenModels={hiddenModels}
onUnhideModel={unhideModel}
onOpenSettings={() => open("models")}
/>
<Tooltip>
<TooltipTrigger asChild>
<HelpIndicator>?</HelpIndicator>
</TooltipTrigger>
<TooltipContent align="start" className="max-w-80 whitespace-normal">
<strong>Click to edit</strong>
<br />
<strong>{formatKeybind(KEYBINDS.CYCLE_MODEL)}</strong> to cycle models
<br />
<br />
<strong>Abbreviations:</strong>
{MODEL_ABBREVIATION_EXAMPLES.map((ex) => (
<React.Fragment key={ex.abbrev}>
<br />• <code>/model {ex.abbrev}</code> - {ex.displayName}
</React.Fragment>
))}
<br />
<br />
<strong>Full format:</strong>
<br />
<code>/model provider:model-name</code>
<br />
(e.g., <code>/model anthropic:claude-sonnet-4-5</code>)
</TooltipContent>
</Tooltip>
</div>

{/* Thinking Slider - slider hidden on narrow containers, label always clickable */}
<div
className="flex items-center [&_.thinking-slider]:[@container(max-width:550px)]:hidden"
data-component="ThinkingSliderGroup"
>
<ThinkingSliderComponent modelString={baseModel} />
</div>
<div className="@container flex flex-wrap items-center gap-x-3 gap-y-1 [@container(max-width:480px)]:flex-col [@container(max-width:480px)]:items-stretch [@container(max-width:480px)]:gap-1">
{/* Row 1 on mobile: Model Selector + Thinking Slider */}
<div className="flex items-center gap-x-3 [@container(max-width:480px)]:w-full">
<div
className="flex items-center"
data-component="ModelSelectorGroup"
data-tutorial="model-selector"
>
<ModelSelector
ref={modelSelectorRef}
value={baseModel}
onChange={setPreferredModel}
models={models}
onComplete={() => inputRef.current?.focus()}
defaultModel={defaultModel}
onSetDefaultModel={setDefaultModel}
onHideModel={hideModel}
hiddenModels={hiddenModels}
onUnhideModel={unhideModel}
onOpenSettings={() => open("models")}
/>
<div className="hidden [@media(hover:hover)_and_(pointer:fine)]:block">
<Tooltip>
<TooltipTrigger asChild>
<HelpIndicator>?</HelpIndicator>
</TooltipTrigger>
<TooltipContent align="start" className="max-w-80 whitespace-normal">
<strong>Click to edit</strong>
<br />
<strong>{formatKeybind(KEYBINDS.CYCLE_MODEL)}</strong> to cycle models
<br />
<br />
<strong>Abbreviations:</strong>
{MODEL_ABBREVIATION_EXAMPLES.map((ex) => (
<React.Fragment key={ex.abbrev}>
<br />• <code>/model {ex.abbrev}</code> - {ex.displayName}
</React.Fragment>
))}
<br />
<br />
<strong>Full format:</strong>
<br />
<code>/model provider:model-name</code>
<br />
(e.g., <code>/model anthropic:claude-sonnet-4-5</code>)
</TooltipContent>
</Tooltip>
</div>
</div>

<div className="ml-4 flex items-center" data-component="ModelSettingsGroup">
<ModelSettings model={baseModel || ""} />
{/* Thinking Slider - slider hidden on narrow containers, label always clickable */}
<div
className="flex items-center [&_.thinking-slider]:[@container(max-width:550px)]:hidden"
data-component="ThinkingSliderGroup"
>
<ThinkingSliderComponent modelString={baseModel} />
</div>
<div className="ml-4 flex items-center" data-component="ModelSettingsGroup">
<ModelSettings model={baseModel || ""} />
</div>
</div>

{/* Row 2 on mobile: Context Usage + Agent Mode + Send Button */}
<div
className="ml-auto flex items-center gap-2"
className="ml-auto flex items-center gap-2 [@container(max-width:480px)]:ml-0 [@container(max-width:480px)]:w-full [@container(max-width:480px)]:justify-end"
data-component="ModelControls"
data-tutorial="mode-selector"
>
Expand All @@ -2199,11 +2203,16 @@ const ChatInputInner: React.FC<ChatInputProps> = (props) => {
aria-label="Send message"
style={{ backgroundColor: focusBorderColor }}
className={cn(
"border-border-light inline-flex items-center gap-1 rounded-sm border px-1.5 py-0.5 text-[11px] font-medium transition-colors duration-200 hover:brightness-110 disabled:opacity-50 disabled:hover:brightness-100",
"border-border-light inline-flex items-center justify-center rounded-sm border px-1.5 py-0.5 text-[11px] font-medium transition-colors duration-200 hover:brightness-110 disabled:opacity-50 disabled:hover:brightness-100",
// Mobile: wider tap target + larger icon, keep icon centered.
"[@container(max-width:480px)]:h-9 [@container(max-width:480px)]:w-11 [@container(max-width:480px)]:px-0 [@container(max-width:480px)]:py-0 [@container(max-width:480px)]:text-sm",
currentAgent?.uiColor ? "text-white" : "text-text"
)}
>
<SendHorizontal className="h-3.5 w-3.5" strokeWidth={2.5} />
<SendHorizontal
className="h-3.5 w-3.5 [@container(max-width:480px)]:h-4 [@container(max-width:480px)]:w-4"
strokeWidth={2.5}
/>
</button>
</TooltipTrigger>
<TooltipContent align="center">
Expand Down
13 changes: 8 additions & 5 deletions src/browser/components/ContextUsageIndicatorButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -297,7 +297,10 @@ export const ContextUsageIndicatorButton: React.FC<ContextUsageIndicatorButtonPr
aria-label={ariaLabel}
aria-expanded={isOpen}
aria-haspopup="dialog"
className="hover:bg-sidebar-hover flex h-6 cursor-pointer items-center gap-1.5 rounded px-1"
className={cn(
"hover:bg-sidebar-hover flex h-6 cursor-pointer items-center gap-1.5 rounded px-1",
"[@container(max-width:480px)]:h-8 [@container(max-width:480px)]:gap-2 [@container(max-width:480px)]:px-2"
)}
type="button"
onClick={handleTriggerClick}
onPointerEnter={handleTriggerPointerEnter}
Expand All @@ -306,16 +309,16 @@ export const ContextUsageIndicatorButton: React.FC<ContextUsageIndicatorButtonPr
{/* Idle compaction badge - shows hourglass with hours when enabled */}
{isIdleCompactionEnabled && (
<div
className="text-muted flex items-center gap-0.5 text-[10px]"
className="text-muted flex items-center gap-0.5 text-[10px] [@container(max-width:480px)]:text-xs"
title={`Auto-compact after ${idleHours}h idle`}
>
<Hourglass className="h-3 w-3" />
<Hourglass className="h-3 w-3 [@container(max-width:480px)]:h-3.5 [@container(max-width:480px)]:w-3.5" />
<span>{idleHours}h</span>
</div>
)}
{/* Show meter when there's usage, or show empty placeholder for settings access */}
{data.totalTokens > 0 ? (
<div className="relative h-2 w-20">
<div className="relative h-2 w-20 [@container(max-width:480px)]:w-28">
<TokenMeter
segments={data.segments}
orientation="horizontal"
Expand All @@ -328,7 +331,7 @@ export const ContextUsageIndicatorButton: React.FC<ContextUsageIndicatorButtonPr
</div>
) : (
/* Empty meter placeholder - allows access to settings with no usage */
<div className="bg-dark relative h-2 w-20 rounded-full" />
<div className="bg-dark relative h-2 w-20 rounded-full [@container(max-width:480px)]:w-28" />
)}
</button>
</PopoverAnchor>
Expand Down
17 changes: 10 additions & 7 deletions src/browser/components/ModelSelector.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -306,7 +306,7 @@ export const ModelSelector = forwardRef<ModelSelectorRef, ModelSelectorProps>(
)}
</div>
{showDropdown && (
<div className="bg-separator border-border-light absolute bottom-full left-0 z-[1020] mb-1 max-h-[200px] min-w-80 overflow-y-auto rounded border shadow-[0_4px_12px_rgba(0,0,0,0.3)]">
<div className="bg-separator border-border-light absolute bottom-full left-0 z-[1020] mb-1 max-h-[200px] min-w-80 overflow-x-hidden overflow-y-auto rounded border shadow-[0_4px_12px_rgba(0,0,0,0.3)]">
{filteredModels.length === 0 ? (
<div className="text-muted-light font-monospace px-2.5 py-1.5 text-[11px]">
No matching models
Expand All @@ -327,7 +327,7 @@ export const ModelSelector = forwardRef<ModelSelectorRef, ModelSelectorProps>(
onClick={() => handleSelectModel(model)}
>
{/* Grid: model name | gateway | visibility | default */}
<div className="grid w-full grid-cols-[1fr_20px_20px_20px] items-center gap-1">
<div className="grid w-full min-w-0 grid-cols-[1fr_20px_30px_30px] items-center gap-1">
<span className="min-w-0 truncate">{model}</span>
{/* Gateway toggle */}
{gateway.canToggleModel(model) ? (
Expand Down Expand Up @@ -398,7 +398,7 @@ export const ModelSelector = forwardRef<ModelSelectorRef, ModelSelectorProps>(
>
<Eye
className={cn(
"h-3 w-3",
"h-4 w-4 md:h-3 md:w-3",
hiddenSet.has(model) ? "opacity-30" : "opacity-70"
)}
/>
Expand Down Expand Up @@ -428,10 +428,10 @@ export const ModelSelector = forwardRef<ModelSelectorRef, ModelSelectorProps>(
onMouseDown={(e) => e.preventDefault()}
onClick={(e) => handleSetDefault(e, model)}
className={cn(
"flex h-5 w-5 items-center justify-center rounded-sm border transition-colors duration-150",
"flex h-5 w-5 items-center justify-center rounded-sm transition-colors duration-150",
defaultModel === model
? "text-yellow-400 border-yellow-400/40 cursor-default"
: "text-muted-light border-border-light/40 hover:border-foreground/60 hover:text-foreground"
? "text-yellow-400 cursor-default"
: "text-muted-light hover:text-foreground"
)}
aria-label={
defaultModel === model
Expand All @@ -440,7 +440,10 @@ export const ModelSelector = forwardRef<ModelSelectorRef, ModelSelectorProps>(
}
disabled={defaultModel === model}
>
<Star className="h-3 w-3" />
<Star
className="h-4 w-4 md:h-3 md:w-3"
fill={defaultModel === model ? "currentColor" : "none"}
/>
</button>
</TooltipTrigger>
<TooltipContent align="center">
Expand Down
2 changes: 1 addition & 1 deletion src/browser/components/ThinkingSlider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ export const ThinkingSliderComponent: React.FC<ThinkingControlProps> = ({ modelS
<button
type="button"
onClick={cycleThinkingLevel}
className="cursor-pointer border-none bg-transparent p-0"
className="flex cursor-pointer items-center border-none bg-transparent p-0"
aria-label={`Thinking level: ${effectiveThinkingLevel}. Click to cycle.`}
>
<span
Expand Down
Loading