mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-05-07 02:51:50 +00:00
refactor(tui): tighten overlay helpers
- rename overlay help text component to match its role - share picker window math across model, session, and skills overlays
This commit is contained in:
parent
c6fdf48b79
commit
6e83d90eb4
5 changed files with 63 additions and 69 deletions
|
|
@ -7,20 +7,12 @@ import type { ModelOptionProvider, ModelOptionsResponse } from '../gatewayTypes.
|
|||
import { asRpcResult, rpcErrorMessage } from '../lib/rpc.js'
|
||||
import type { Theme } from '../theme.js'
|
||||
|
||||
import { OverlayControls, useOverlayKeys } from './overlayControls.js'
|
||||
import { OverlayHint, useOverlayKeys, windowItems, windowOffset } from './overlayControls.js'
|
||||
|
||||
const VISIBLE = 12
|
||||
const MIN_WIDTH = 40
|
||||
const MAX_WIDTH = 90
|
||||
|
||||
const pageOffset = (count: number, sel: number) => Math.max(0, Math.min(sel - Math.floor(VISIBLE / 2), count - VISIBLE))
|
||||
|
||||
const visibleItems = (items: string[], sel: number) => {
|
||||
const off = pageOffset(items.length, sel)
|
||||
|
||||
return { items: items.slice(off, off + VISIBLE), off }
|
||||
}
|
||||
|
||||
export function ModelPicker({ gw, onCancel, onSelect, sessionId, t }: ModelPickerProps) {
|
||||
const [providers, setProviders] = useState<ModelOptionProvider[]>([])
|
||||
const [currentModel, setCurrentModel] = useState('')
|
||||
|
|
@ -135,16 +127,16 @@ export function ModelPicker({ gw, onCancel, onSelect, sessionId, t }: ModelPicke
|
|||
const n = ch === '0' ? 10 : parseInt(ch, 10)
|
||||
|
||||
if (!Number.isNaN(n) && n >= 1 && n <= Math.min(10, count)) {
|
||||
const off = pageOffset(count, sel)
|
||||
const offset = windowOffset(count, sel, VISIBLE)
|
||||
|
||||
if (stage === 'provider') {
|
||||
const next = off + n - 1
|
||||
const next = offset + n - 1
|
||||
|
||||
if (providers[next]) {
|
||||
setProviderIdx(next)
|
||||
}
|
||||
} else if (provider && models[off + n - 1]) {
|
||||
onSelect(`${models[off + n - 1]} --provider ${provider.slug}${persistGlobal ? ' --global' : ''}`)
|
||||
} else if (provider && models[offset + n - 1]) {
|
||||
onSelect(`${models[offset + n - 1]} --provider ${provider.slug}${persistGlobal ? ' --global' : ''}`)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
|
@ -157,7 +149,7 @@ export function ModelPicker({ gw, onCancel, onSelect, sessionId, t }: ModelPicke
|
|||
return (
|
||||
<Box flexDirection="column">
|
||||
<Text color={t.color.label}>error: {err}</Text>
|
||||
<OverlayControls t={t}>Esc/q cancel</OverlayControls>
|
||||
<OverlayHint t={t}>Esc/q cancel</OverlayHint>
|
||||
</Box>
|
||||
)
|
||||
}
|
||||
|
|
@ -166,7 +158,7 @@ export function ModelPicker({ gw, onCancel, onSelect, sessionId, t }: ModelPicke
|
|||
return (
|
||||
<Box flexDirection="column">
|
||||
<Text color={t.color.dim}>no authenticated providers</Text>
|
||||
<OverlayControls t={t}>Esc/q cancel</OverlayControls>
|
||||
<OverlayHint t={t}>Esc/q cancel</OverlayHint>
|
||||
</Box>
|
||||
)
|
||||
}
|
||||
|
|
@ -176,7 +168,7 @@ export function ModelPicker({ gw, onCancel, onSelect, sessionId, t }: ModelPicke
|
|||
(p, i) => `${p.is_current ? '*' : ' '} ${names[i]} · ${p.total_models ?? p.models?.length ?? 0} models`
|
||||
)
|
||||
|
||||
const { items, off } = visibleItems(rows, providerIdx)
|
||||
const { items, offset } = windowItems(rows, providerIdx, VISIBLE)
|
||||
|
||||
return (
|
||||
<Box flexDirection="column" width={width}>
|
||||
|
|
@ -191,12 +183,12 @@ export function ModelPicker({ gw, onCancel, onSelect, sessionId, t }: ModelPicke
|
|||
{provider?.warning ? `warning: ${provider.warning}` : ' '}
|
||||
</Text>
|
||||
<Text color={t.color.dim} wrap="truncate-end">
|
||||
{off > 0 ? ` ↑ ${off} more` : ' '}
|
||||
{offset > 0 ? ` ↑ ${offset} more` : ' '}
|
||||
</Text>
|
||||
|
||||
{Array.from({ length: VISIBLE }, (_, i) => {
|
||||
const row = items[i]
|
||||
const idx = off + i
|
||||
const idx = offset + i
|
||||
|
||||
return row ? (
|
||||
<Text
|
||||
|
|
@ -217,18 +209,18 @@ export function ModelPicker({ gw, onCancel, onSelect, sessionId, t }: ModelPicke
|
|||
})}
|
||||
|
||||
<Text color={t.color.dim} wrap="truncate-end">
|
||||
{off + VISIBLE < rows.length ? ` ↓ ${rows.length - off - VISIBLE} more` : ' '}
|
||||
{offset + VISIBLE < rows.length ? ` ↓ ${rows.length - offset - VISIBLE} more` : ' '}
|
||||
</Text>
|
||||
|
||||
<Text color={t.color.dim} wrap="truncate-end">
|
||||
persist: {persistGlobal ? 'global' : 'session'} · g toggle
|
||||
</Text>
|
||||
<OverlayControls t={t}>↑/↓ select · Enter choose · 1-9,0 quick · Esc/q cancel</OverlayControls>
|
||||
<OverlayHint t={t}>↑/↓ select · Enter choose · 1-9,0 quick · Esc/q cancel</OverlayHint>
|
||||
</Box>
|
||||
)
|
||||
}
|
||||
|
||||
const { items, off } = visibleItems(models, modelIdx)
|
||||
const { items, offset } = windowItems(models, modelIdx, VISIBLE)
|
||||
|
||||
return (
|
||||
<Box flexDirection="column" width={width}>
|
||||
|
|
@ -243,12 +235,12 @@ export function ModelPicker({ gw, onCancel, onSelect, sessionId, t }: ModelPicke
|
|||
{provider?.warning ? `warning: ${provider.warning}` : ' '}
|
||||
</Text>
|
||||
<Text color={t.color.dim} wrap="truncate-end">
|
||||
{off > 0 ? ` ↑ ${off} more` : ' '}
|
||||
{offset > 0 ? ` ↑ ${offset} more` : ' '}
|
||||
</Text>
|
||||
|
||||
{Array.from({ length: VISIBLE }, (_, i) => {
|
||||
const row = items[i]
|
||||
const idx = off + i
|
||||
const idx = offset + i
|
||||
|
||||
if (!row) {
|
||||
return !models.length && i === 0 ? (
|
||||
|
|
@ -277,15 +269,15 @@ export function ModelPicker({ gw, onCancel, onSelect, sessionId, t }: ModelPicke
|
|||
})}
|
||||
|
||||
<Text color={t.color.dim} wrap="truncate-end">
|
||||
{off + VISIBLE < models.length ? ` ↓ ${models.length - off - VISIBLE} more` : ' '}
|
||||
{offset + VISIBLE < models.length ? ` ↓ ${models.length - offset - VISIBLE} more` : ' '}
|
||||
</Text>
|
||||
|
||||
<Text color={t.color.dim} wrap="truncate-end">
|
||||
persist: {persistGlobal ? 'global' : 'session'} · g toggle
|
||||
</Text>
|
||||
<OverlayControls t={t}>
|
||||
<OverlayHint t={t}>
|
||||
{models.length ? '↑/↓ select · Enter switch · 1-9,0 quick · Esc back · q close' : 'Enter/Esc back · q close'}
|
||||
</OverlayControls>
|
||||
</OverlayHint>
|
||||
</Box>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue