Skip to content

feat(chat): let users choose the inline composer chips and show More only on real overflow (#71) - #76

Merged
vlinx-io merged 1 commit into
vlinx-io:devfrom
mguttmann:feat/composer-toolbar-customization
Sep 20, 2026
Merged

vlinx-io merged 1 commit into
vlinx-io:devfrom
mguttmann:feat/composer-toolbar-customization

Conversation

@mguttmann

@mguttmann mguttmann commented Sep 13, 2026 •

Copy link
Copy Markdown

Closes #71

What changes

  • A setting decides which chips stay inline. Settings > Conversation view > Composer toolbar lists every composer chip with an On/Off switch and, for chips that are on, up/down arrows for their order. The default is exactly the previous inline set (model, thinking effort, collaboration mode, permission mode), so nothing changes for anyone who does not touch it.
  • More only on real overflow. ComposerToolbar now receives the chips that exist for the session plus the user's ordered list. It lays the enabled chips out in that order and measures them in a layout effect before paint, then follows a ResizeObserver. The More toggle is rendered only while the enabled chips do not fit the row; it then holds the chips that overflowed, followed by the chips that are off. When everything fits there is no More button at all.
  • Pure layout logic with its own tests. composerLayout.ts holds the split by preference (arrangeComposerChips) and the width partition (partitionComposerChips) without React or DOM; the toolbar injects measured widths, the tests inject made-up ones.
  • One chip list instead of a fixed split. The hardcoded primary/secondary split in ChatPane.tsx becomes a single list of chips with ids. Availability per agent kind and engine state stays where it was (MCP and tasks only while the engine runs, fast mode only when offered, account chip yields to the inline sign-in panel, and so on). A chip that is on is always drawn when it exists for the agent kind; momentary unavailability shows as an empty or disabled chip, never as absence (see the rule below).
  • Mobile unchanged in shape. The mobile layout keeps its two rows (enabled chips first, the rest below) without measuring.
  • Persistence. composerInlineChips joins the settings payload and syncs like the other conversation view preferences. It is sanitized on load: unknown ids are dropped, a malformed value falls back to the default, an explicit empty list is allowed.
  • 15 new i18n keys in all 11 locale files.
  • The user manual (docs/manuals) gains the new Conversation view section and the account chip description follows the new behaviour.

Keyboard and screen reader behaviour of the More row (Escape closes, outside click closes, aria-expanded and aria-controls) is unchanged when the button does appear.

Assumptions worth a look

  • The setting is global, not per agent kind or per session.
  • The Codex reset credits control is treated as a chip like the others (off by default, as before).
  • Chips do not shrink: a chip that no longer fits moves into More instead of being squeezed.
  • Turning every chip off is allowed; the toolbar then shows only More with everything inside.

The visibility rule, after a first round of use

Manuel switched the Tasks chip on and saw nothing: the chip hid itself while the task list was empty, and MCP and Tasks were offered only while the Claude process was alive, so they came and went between turns. A chip nobody can find defeats the setting. The branch applies one rule: a chip the user turned on is always visible when it exists for the agent kind. Tasks with an empty list shows its label and "No background tasks"; MCP and Tasks are disabled while no agent process runs (dimmed, not openable, a tooltip names the cause, no status request is sent, no badge); the account chip stays in the row disabled during an unresolved sign-in instead of disappearing. ChipPopover gained a disabled prop with the existing disabled chip look. Only chips that do not exist for the agent kind stay absent (for example Codex reset credits in a Claude session). The settings hint and the manual describe the rule.

Verification

On this branch: pnpm lint clean, pnpm build green, pnpm test 120 files / 1053 tests passing on the rebase onto v0.2.2. New tests cover the layout arithmetic, the toolbar's fold behaviour, the settings section, and the sanitizer.

Note on linking: GitHub does not show the Development sidebar link for fork PRs from accounts without write access, so the Closes #71 keyword in the commit and here does the closing on merge.

🤖 Generated with Claude Code

@mguttmann

Copy link
Copy Markdown
Author

Follow-up pushed (f43ef74): switched-on chips are now always visible. The first version hid the Tasks chip while the task list was empty and offered MCP and Tasks only while the agent process was alive, so a chip someone had just switched on was nowhere to be found. Now Tasks shows its label and an empty state, MCP and Tasks are disabled (dimmed, not openable, no request sent, no badge) while no agent process runs, and the account chip stays disabled during a sign-in instead of vanishing. Only chips that do not exist for the agent kind stay absent. Settings hint and manual updated; 1022 tests, lint and build green.

@mguttmann

Copy link
Copy Markdown
Author

Rebased onto v0.2.1 (68a4bc2). The only conflict was the toolbar block in ChatPane.tsx, where v0.2.1 gave the permission chip its pending mark, the picked-mode label and the four-way tooltip; those are now carried inside the chip list's permission entry, so the chip renders exactly as in v0.2.1. Lint, type check and 1035 tests green on the rebased branch.

@mguttmann
mguttmann force-pushed the feat/composer-toolbar-customization branch from f43ef74 to 3053fe6 Compare September 14, 2026 16:03
…only on real overflow

The composer toolbar rendered a fixed set of chips inline and hid the
rest behind a "More" button that appeared on desktop whether or not the
row had room. A new setting, composerInlineChips, holds the ordered list
of chips a user wants inline; its default is exactly the previous inline
set, so nothing changes for people who do not touch it. ComposerToolbar
receives the chips that exist for the session and measures them: chips
are laid out in the chosen order, the More button appears only when they
do not fit, and it then holds the displaced chips followed by the ones
that are off. A pure partition function carries the layout decision and
its tests; the measurement runs in a layout effect before paint and
follows a ResizeObserver. Settings gained a Conversation view list with
an on/off switch and up/down ordering per chip. Mobile keeps its two-row
layout.

A chip the user turned on is always drawn when it exists for the agent
kind: Tasks with an empty list shows its label and an empty menu, MCP
and Tasks are disabled while no agent process runs (dimmed, not
openable, a tooltip names the cause, no status request, no badge), and
the account chip stays in the row disabled during an unresolved sign-in.
A chip that comes and goes with the process cannot be found by someone
who just switched it on. Only chips that do not exist for the agent kind
stay absent.

Closes vlinx-io#71

Co-Authored-By: Claude Fable 5.1 <[email protected]>
@mguttmann
mguttmann force-pushed the feat/composer-toolbar-customization branch from 3053fe6 to b38cbae Compare September 15, 2026 14:49
@mguttmann

Copy link
Copy Markdown
Author

Rebased onto v0.2.2 (7874081) and squashed into one commit, because the toolbar block moved under v0.2.2's conversation view work and a two-step replay of the same region produced no reviewable history. Conflicts resolved: the chip list replaces the fixed primary/secondary split as before, the model chip follows your footer to advancedFooter rename, and termStore keeps both new imports. pnpm test 120 files / 1053 tests, build and lint green.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Conversation view: let users choose which composer chips stay inline, and show "More" only when they really do not fit

2 participants