mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-07-20 15:33:54 +00:00
Builds on the clarify/needs-input work with a cross-cutting pass to make the desktop surfaces feel like one app. - Global Cmd+K command palette (cmdk): nav, settings deep-links, async API-key / MCP-server / archived-session groups, reusable theme sub-page (light/dark groups, stays open on pick), loop nav, fuzzy match. Replaces per-page settings search. - Shared SearchField: borderless, underline-on-focus, `field-sizing` auto-width. Unifies sessions sidebar, pages, overlays, command center, cron; drops bespoke OverlaySearchInput. - Cron & Profiles converted to OverlayView; flat token-driven panels (no card-in-card / divider borders) matching command center. - `r` refresh hotkey via useRefreshHotkey; drop the visible refresh buttons. - Button text/textStrong link variants applied across settings & views; shared PAGE_INSET_X content gutters. - Math/ascii loaders replace "Loading…" text placeholders; x-icon close over text "Close"; cursor-pointer at the dropdown/select primitive level.
51 lines
1.5 KiB
TypeScript
51 lines
1.5 KiB
TypeScript
import type { IconComponent } from '@/lib/icons'
|
|
import { cn } from '@/lib/utils'
|
|
|
|
export interface SegmentedControlOption<T extends string> {
|
|
id: T
|
|
label: string
|
|
icon?: IconComponent
|
|
}
|
|
|
|
interface SegmentedControlProps<T extends string> {
|
|
options: readonly SegmentedControlOption<T>[]
|
|
value: T
|
|
onChange: (id: T) => void
|
|
className?: string
|
|
}
|
|
|
|
/**
|
|
* Grouped one-row toggle used for small mutually-exclusive choices
|
|
* (color mode, tool-call display, usage period, etc.). Flat by design —
|
|
* no per-option borders, just a tinted track with a raised active pill.
|
|
*/
|
|
export function SegmentedControl<T extends string>({ options, value, onChange, className }: SegmentedControlProps<T>) {
|
|
return (
|
|
<div
|
|
className={cn(
|
|
'inline-grid w-fit auto-cols-fr grid-flow-col gap-0.5 rounded-[5px] bg-(--ui-bg-tertiary) p-0.5',
|
|
className
|
|
)}
|
|
>
|
|
{options.map(({ id, label, icon: Icon }) => {
|
|
const active = value === id
|
|
|
|
return (
|
|
<button
|
|
aria-pressed={active}
|
|
className={cn(
|
|
'flex items-center justify-center gap-1 rounded-[3px] px-2.5 py-0.5 text-[0.6875rem] font-medium transition-colors',
|
|
active ? 'bg-background text-foreground shadow-sm' : 'text-muted-foreground hover:text-foreground'
|
|
)}
|
|
key={id}
|
|
onClick={() => onChange(id)}
|
|
type="button"
|
|
>
|
|
{Icon && <Icon className="size-3" />}
|
|
{label}
|
|
</button>
|
|
)
|
|
})}
|
|
</div>
|
|
)
|
|
}
|