mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-07-22 16:25:58 +00:00
fix(desktop): composer progressively collapses on narrow tiles
Drive the composer's layout off its OWN measured width (the existing ResizeObserver, so it reacts per-tile, not per-viewport) instead of only stacking or overflowing: - >=440px: full inline row, full model label. - 320-440px: still inline, but the model pill sheds its label for its chevron icon (~120px back) so the controls stop crowding the placeholder. - <320px: stacks to the two-row layout, pill stays iconized. Adds COMPOSER_COMPACT_PILL_PX above the stack breakpoint and a `compactPill` signal from useComposerMetrics, wired to the model pill's existing compact mode.
This commit is contained in:
parent
092a97ef75
commit
305e26558e
3 changed files with 24 additions and 7 deletions
|
|
@ -6,6 +6,12 @@ import { setSessionPickerOpen } from '@/store/session'
|
|||
|
||||
export const COMPOSER_STACK_BREAKPOINT_PX = 320
|
||||
|
||||
// Above the stack breakpoint but still cramped: the model pill sheds its label
|
||||
// for its chevron icon (freeing ~120px) so the controls stop crowding the input
|
||||
// before the whole row has to stack. Progressive collapse: full pill → icon
|
||||
// pill → stacked.
|
||||
export const COMPOSER_COMPACT_PILL_PX = 440
|
||||
|
||||
// A single editor line is ~28px (--composer-input-min-height 1.625rem + 0.5rem
|
||||
// vertical padding). Anything taller means the text wrapped to a second line,
|
||||
// which is when the composer should expand to the stacked layout.
|
||||
|
|
@ -79,7 +85,5 @@ export function isPendingDraftPersistCurrent(
|
|||
pending: PendingDraftPersist | null,
|
||||
expected: PendingDraftPersist | null
|
||||
): boolean {
|
||||
return (
|
||||
pending !== null && expected !== null && pending.scope === expected.scope && pending.text === expected.text
|
||||
)
|
||||
return pending !== null && expected !== null && pending.scope === expected.scope && pending.text === expected.text
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import { useResizeObserver } from '@/hooks/use-resize-observer'
|
|||
import { $composerPoppedOut } from '@/store/composer-popout'
|
||||
import { isSecondaryWindow } from '@/store/windows'
|
||||
|
||||
import { COMPOSER_SINGLE_LINE_MAX_PX, COMPOSER_STACK_BREAKPOINT_PX } from '../composer-utils'
|
||||
import { COMPOSER_COMPACT_PILL_PX, COMPOSER_SINGLE_LINE_MAX_PX, COMPOSER_STACK_BREAKPOINT_PX } from '../composer-utils'
|
||||
|
||||
interface UseComposerMetricsArgs {
|
||||
composerRef: RefObject<HTMLFormElement | null>
|
||||
|
|
@ -24,10 +24,13 @@ interface UseComposerMetricsArgs {
|
|||
* Returns `stacked` (the only value the render needs).
|
||||
*/
|
||||
export function useComposerMetrics({ composerRef, composerSurfaceRef, editorRef, poppedOut }: UseComposerMetricsArgs): {
|
||||
compactPill: boolean
|
||||
stacked: boolean
|
||||
} {
|
||||
const [expanded, setExpanded] = useState(false)
|
||||
const [tight, setTight] = useState(false)
|
||||
// Wider than `tight`: the pill goes icon-only before the row has to stack.
|
||||
const [compactPill, setCompactPill] = useState(false)
|
||||
const narrow = useMediaQuery('(max-width: 30rem)')
|
||||
|
||||
// Edge signals, not the live text: these only re-render when emptiness / the
|
||||
|
|
@ -72,6 +75,7 @@ export function useComposerMetrics({ composerRef, composerSurfaceRef, editorRef,
|
|||
const lastBucketedHeightRef = useRef(0)
|
||||
const lastBucketedSurfaceHeightRef = useRef(0)
|
||||
const lastTightRef = useRef<boolean | null>(null)
|
||||
const lastCompactPillRef = useRef<boolean | null>(null)
|
||||
|
||||
const syncComposerMetrics = useCallback(() => {
|
||||
const composer = composerRef.current
|
||||
|
|
@ -105,6 +109,13 @@ export function useComposerMetrics({ composerRef, composerSurfaceRef, editorRef,
|
|||
lastTightRef.current = nextTight
|
||||
setTight(nextTight)
|
||||
}
|
||||
|
||||
const nextCompactPill = width < COMPOSER_COMPACT_PILL_PX
|
||||
|
||||
if (nextCompactPill !== lastCompactPillRef.current) {
|
||||
lastCompactPillRef.current = nextCompactPill
|
||||
setCompactPill(nextCompactPill)
|
||||
}
|
||||
}
|
||||
|
||||
// Expand once the input has actually wrapped past a single line. The
|
||||
|
|
@ -156,5 +167,7 @@ export function useComposerMetrics({ composerRef, composerSurfaceRef, editorRef,
|
|||
}
|
||||
}, [])
|
||||
|
||||
return { stacked: expanded || narrow || tight }
|
||||
// Pill compacts on real width (tile/pane), OR when stacked for any reason
|
||||
// (viewport-narrow / wrapped) so the controls row never over-runs.
|
||||
return { compactPill: compactPill || narrow || tight, stacked: expanded || narrow || tight }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -208,7 +208,7 @@ export function ChatBar({
|
|||
|
||||
const statusStackVisible = queuedPrompts.length > 0 || statusPresent
|
||||
|
||||
const { stacked } = useComposerMetrics({ composerRef, composerSurfaceRef, editorRef, poppedOut })
|
||||
const { compactPill, stacked } = useComposerMetrics({ composerRef, composerSurfaceRef, editorRef, poppedOut })
|
||||
const hasComposerPayload = hasText || attachments.length > 0
|
||||
const canSubmit = busy || hasComposerPayload
|
||||
const busyAction = busy && hasComposerPayload ? 'queue' : 'stop'
|
||||
|
|
@ -704,7 +704,7 @@ export function ChatBar({
|
|||
busyAction={busyAction}
|
||||
canSteer={canSteer}
|
||||
canSubmit={canSubmit}
|
||||
compactModelPill={poppedOut}
|
||||
compactModelPill={poppedOut || compactPill}
|
||||
conversation={{
|
||||
active: voiceConversationActive,
|
||||
level: conversation.level,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue