mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-07-23 16:36:23 +00:00
refactor(ui-tui): every selectable list rides the shared selection chip — zero inverse left
/agents, /journey, model picker, skills hub, plugins hub, pet picker, and
the approval/confirm prompts all used SGR inverse for the active row —
terminal-interpreted against unknowable defaults (black slab on transparent
profiles) and visually divergent from completions/session-switcher. New
spreadable chipRowProps(t, active) in overlayPrimitives (chip bg + lifted
ink + bold; spread after `color` so chip ink wins) converts each site to
the one selection treatment. rg confirms zero inverse={} remaining in
components/.
This commit is contained in:
parent
ce8c2c97aa
commit
5bfffcd445
8 changed files with 39 additions and 32 deletions
|
|
@ -32,6 +32,7 @@ import { compactPreview } from '../lib/text.js'
|
|||
import type { Theme } from '../theme.js'
|
||||
import type { SubagentNode, SubagentProgress } from '../types.js'
|
||||
|
||||
import { listRowStyle } from './overlayPrimitives.js'
|
||||
import { OverlayScrollbar } from './overlayScrollbar.js'
|
||||
|
||||
// ── Types + lookup tables ────────────────────────────────────────────
|
||||
|
|
@ -464,14 +465,17 @@ function ListRow({
|
|||
const paren = line ? line.indexOf('(') : -1
|
||||
const toolShort = line ? (paren > 0 ? line.slice(0, paren) : line).trim() : ''
|
||||
const trailing = toolShort ? ` · ${compactPreview(toolShort, 14)}` : ''
|
||||
const fg = active ? t.color.accent : t.color.text
|
||||
// Selection chip, not `inverse` — inverse swaps against the terminal's
|
||||
// unknowable defaults (black slab on transparent profiles).
|
||||
const row = listRowStyle(t, active)
|
||||
const fg = active ? (row.color ?? t.color.accent) : t.color.text
|
||||
|
||||
return (
|
||||
<Text bold={active} color={fg} inverse={active} wrap="truncate-end">
|
||||
<Text backgroundColor={row.backgroundColor} bold={active} color={fg} wrap="truncate-end">
|
||||
{' '}
|
||||
<Text color={active ? fg : t.color.muted}>{formatRowId(index)} </Text>
|
||||
{indentFor(node.item.depth)}
|
||||
{heatMarker ? <Text color={heatMarker}>▍</Text> : null}
|
||||
{heatMarker ? <Text color={active ? fg : heatMarker}>▍</Text> : null}
|
||||
<Text color={active ? fg : color}>{glyph}</Text> {goal}
|
||||
<Text color={active ? fg : t.color.muted}>
|
||||
{toolsCount}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import { rpcErrorMessage } from '../lib/rpc.js'
|
|||
import { deriveStarmapPalette, fadeHex, fadeInk, type StarmapPalette } from '../lib/starmapPalette.js'
|
||||
import type { Theme } from '../theme.js'
|
||||
|
||||
import { listRowStyle } from './overlayPrimitives.js'
|
||||
import { OverlayScrollbar } from './overlayScrollbar.js'
|
||||
|
||||
interface MutationResult {
|
||||
|
|
@ -115,12 +116,14 @@ function ChartRow({ palette, row }: { palette: StarmapPalette; row: Run[] }) {
|
|||
}
|
||||
|
||||
// Full-width selectable row, matching the /agents list treatment: the active
|
||||
// row inverts and collapses every segment onto the accent foreground.
|
||||
// row carries the shared selection chip (never `inverse`, which swaps against
|
||||
// the terminal's unknowable defaults) and collapses onto the chip ink.
|
||||
function ListRow({ active, cells, t }: { active: boolean; cells: Cell[]; t: Theme }) {
|
||||
const fg = active ? t.color.accent : t.color.text
|
||||
const row = listRowStyle(t, active)
|
||||
const fg = active ? (row.color ?? t.color.accent) : t.color.text
|
||||
|
||||
return (
|
||||
<Text bold={active} color={fg} inverse={active} wrap="truncate-end">
|
||||
<Text backgroundColor={row.backgroundColor} bold={active} color={fg} wrap="truncate-end">
|
||||
{cells.map((c, i) => (
|
||||
<Text color={active ? fg : (c.color ?? t.color.text)} key={i}>
|
||||
{c.text}
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import { asRpcResult, rpcErrorMessage } from '../lib/rpc.js'
|
|||
import type { Theme } from '../theme.js'
|
||||
|
||||
import { OverlayHint, useOverlayKeys, windowItems } from './overlayControls.js'
|
||||
import { chipRowProps } from './overlayPrimitives.js'
|
||||
|
||||
const VISIBLE = 12
|
||||
const MIN_WIDTH = 40
|
||||
|
|
@ -596,9 +597,8 @@ export function ModelPicker({
|
|||
|
||||
return row ? (
|
||||
<Text
|
||||
bold={providerIdx === idx}
|
||||
color={providerIdx === idx ? t.color.accent : dimmed ? t.color.label : t.color.muted}
|
||||
inverse={providerIdx === idx}
|
||||
color={dimmed ? t.color.label : t.color.muted}
|
||||
{...chipRowProps(t, providerIdx === idx)}
|
||||
key={p?.slug ?? `row-${idx}`}
|
||||
wrap="truncate-end"
|
||||
>
|
||||
|
|
@ -669,9 +669,8 @@ export function ModelPicker({
|
|||
|
||||
return (
|
||||
<Text
|
||||
bold={modelIdx === idx}
|
||||
color={modelIdx === idx ? t.color.accent : t.color.muted}
|
||||
inverse={modelIdx === idx}
|
||||
color={t.color.muted}
|
||||
{...chipRowProps(t, modelIdx === idx)}
|
||||
key={`${provider?.slug ?? 'prov'}:${idx}:${row}`}
|
||||
wrap="truncate-end"
|
||||
>
|
||||
|
|
|
|||
|
|
@ -86,6 +86,16 @@ export function listRowStyle(t: Theme, active: boolean): { backgroundColor?: str
|
|||
return { backgroundColor, color: liftForContrast(t.color.text, backgroundColor, 4.5) }
|
||||
}
|
||||
|
||||
/** Spreadable props for a selectable row: chip bg + ink + bold when active.
|
||||
* Spread AFTER `color` so the chip ink wins on the active row. Replaces
|
||||
* `inverse`, which swaps against the terminal's unknowable default colors
|
||||
* (a black slab on transparent profiles). */
|
||||
export function chipRowProps(t: Theme, active: boolean): { backgroundColor?: string; bold: boolean; color?: string } {
|
||||
const row = listRowStyle(t, active)
|
||||
|
||||
return { backgroundColor: row.backgroundColor, bold: active, ...(row.color ? { color: row.color } : {}) }
|
||||
}
|
||||
|
||||
/** A numbered menu row with the ▸ cursor (mirrors ClarifyPrompt). Active rows
|
||||
* carry the shared list-row selection chip — same treatment as completions
|
||||
* and the session switcher — instead of `inverse`, whose contrast depends on
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import { rpcErrorMessage } from '../lib/rpc.js'
|
|||
import type { Theme } from '../theme.js'
|
||||
|
||||
import { OverlayHint, windowItems } from './overlayControls.js'
|
||||
import { chipRowProps } from './overlayPrimitives.js'
|
||||
|
||||
const VISIBLE = 10
|
||||
const MIN_WIDTH = 40
|
||||
|
|
@ -155,7 +156,7 @@ export function PetPicker({ gw, maxWidth, onClose, t }: PetPickerProps) {
|
|||
const tag = pet.installed ? '' : pet.curated ? ' · official' : ''
|
||||
|
||||
return (
|
||||
<Text bold={at} color={at ? t.color.accent : t.color.muted} inverse={at} key={pet.slug} wrap="truncate-end">
|
||||
<Text color={t.color.muted} {...chipRowProps(t, at)} key={pet.slug} wrap="truncate-end">
|
||||
{at ? '▸ ' : ' '}
|
||||
{mark} {pet.displayName}
|
||||
<Text color={at ? t.color.accent : t.color.muted}>
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import { rpcErrorMessage } from '../lib/rpc.js'
|
|||
import type { Theme } from '../theme.js'
|
||||
|
||||
import { OverlayHint, useOverlayKeys, windowItems, windowOffset } from './overlayControls.js'
|
||||
import { chipRowProps } from './overlayPrimitives.js'
|
||||
|
||||
const VISIBLE = 12
|
||||
const MIN_WIDTH = 44
|
||||
|
|
@ -209,9 +210,8 @@ export function PluginsHub({ gw, maxWidth, onClose, t }: PluginsHubProps) {
|
|||
|
||||
return (
|
||||
<Text
|
||||
bold={active}
|
||||
color={active ? t.color.accent : t.color.muted}
|
||||
inverse={active}
|
||||
color={t.color.muted}
|
||||
{...chipRowProps(t, active)}
|
||||
key={effectiveRows[lineIdx]?.name ?? row}
|
||||
wrap="truncate-end"
|
||||
>
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import { isMac } from '../lib/platform.js'
|
|||
import type { Theme } from '../theme.js'
|
||||
import type { ApprovalReq, ClarifyReq, ConfirmReq } from '../types.js'
|
||||
|
||||
import { chipRowProps } from './overlayPrimitives.js'
|
||||
import { TextInput } from './textInput.js'
|
||||
|
||||
const APPROVAL_OPTS = ['once', 'session', 'always', 'deny'] as const
|
||||
|
|
@ -129,7 +130,7 @@ export function ApprovalPrompt({ cols = 80, onChoice, req, t }: ApprovalPromptPr
|
|||
|
||||
{opts.map((o, i) => (
|
||||
<Text key={o}>
|
||||
<Text bold={sel === i} color={sel === i ? t.color.warn : t.color.muted} inverse={sel === i}>
|
||||
<Text color={t.color.muted} {...chipRowProps(t, sel === i)}>
|
||||
{sel === i ? '▸ ' : ' '}
|
||||
{i + 1}. {LABELS[o]}
|
||||
</Text>
|
||||
|
|
@ -208,7 +209,7 @@ export function ClarifyPrompt({ cols = 80, onAnswer, onCancel, req, t }: Clarify
|
|||
|
||||
{[...choices, 'Other (type your answer)'].map((c, i) => (
|
||||
<Text key={i}>
|
||||
<Text bold={sel === i} color={sel === i ? t.color.label : t.color.muted} inverse={sel === i}>
|
||||
<Text color={t.color.muted} {...chipRowProps(t, sel === i)}>
|
||||
{sel === i ? '▸ ' : ' '}
|
||||
{i + 1}. {c}
|
||||
</Text>
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import { rpcErrorMessage } from '../lib/rpc.js'
|
|||
import type { Theme } from '../theme.js'
|
||||
|
||||
import { OverlayHint, useOverlayKeys, windowItems, windowOffset } from './overlayControls.js'
|
||||
import { chipRowProps } from './overlayPrimitives.js'
|
||||
|
||||
const VISIBLE = 12
|
||||
const MIN_WIDTH = 40
|
||||
|
|
@ -220,13 +221,7 @@ export function SkillsHub({ gw, maxWidth, onClose, t }: SkillsHubProps) {
|
|||
const idx = offset + i
|
||||
|
||||
return (
|
||||
<Text
|
||||
bold={catIdx === idx}
|
||||
color={catIdx === idx ? t.color.accent : t.color.muted}
|
||||
inverse={catIdx === idx}
|
||||
key={row}
|
||||
wrap="truncate-end"
|
||||
>
|
||||
<Text color={t.color.muted} {...chipRowProps(t, catIdx === idx)} key={row} wrap="truncate-end">
|
||||
{catIdx === idx ? '▸ ' : ' '}
|
||||
{i + 1}. {row}
|
||||
</Text>
|
||||
|
|
@ -256,13 +251,7 @@ export function SkillsHub({ gw, maxWidth, onClose, t }: SkillsHubProps) {
|
|||
const idx = offset + i
|
||||
|
||||
return (
|
||||
<Text
|
||||
bold={skillIdx === idx}
|
||||
color={skillIdx === idx ? t.color.accent : t.color.muted}
|
||||
inverse={skillIdx === idx}
|
||||
key={row}
|
||||
wrap="truncate-end"
|
||||
>
|
||||
<Text color={t.color.muted} {...chipRowProps(t, skillIdx === idx)} key={row} wrap="truncate-end">
|
||||
{skillIdx === idx ? '▸ ' : ' '}
|
||||
{i + 1}. {row}
|
||||
</Text>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue