Repository navigation
UI Consistency: 2 issues found
Reviewed the keybinding settings redesign against the shared component system and layout/interaction preservation rules. Previously flagged items (compact Input sizing, collapsed WhenClauseControl variants, labelled browser-notice tooltip trigger, shortcut text in the pill's accessible name, plain-text add-row heading, reserved menu slot) are all addressed in the head commit. Two findings remain:
apps/web/src/components/settings/KeybindingsSettings.tsx(KeybindingKeyControl, lines 845-853): Save mounts between the shortcut control and the row menu inside the right-alignedSettingsRowcontrol cluster, so the just-focused captureInputshifts ~50px left as soon as the draft becomes dirty. The old fixed grid column pinned it. Suggested reserving the Save slot the way the menu slot is reserved.apps/web/src/components/settings/KeybindingsSettings.tsx(WhenClauseControl, lines 876-885): the When trigger is a hand-rolled ghost button now that the field styling is gone — nocursor-pointer, nopointer-coarsehit-target expansion (24px inline target on touch, previously a full-widthh-7field), and anInput-style focus ring. Suggested rendering it viaButton variant="ghost".
Both were posted as inline review comments with suggested diffs.
Details
Note
Your check run agent prompt is: .macroscope/check-run-agents/ui-consistency.md
More information about how Check Run Agents work can be found in our Help Center.
Methodology:
- Compared merge base
afc8342with head6ee6c83forapps/web/src/components/settings/KeybindingsSettings.tsx(only in-scope changed file). - Read the primitives the new code composes:
settingsLayout.tsx(SettingsRowgrid/control cluster),ui/button.tsx(size/variant contract,cursor-pointer,pointer-coarsehit targets, focus ring),ui/input.tsx(wrapper vs inner control,size="compact"),ui/badge.tsx(size="sm",variant="outline"). - Traced layout ownership:
SettingsRowcontrol track isminmax(10rem,auto)withsm:justify-end, so any control appended to the right of the shortcut control widens the track leftwards; the reserved menu placeholder only stabilises the trailing edge. - Surveyed repository
PopoverTriggercall sites to confirm the prevailing convention isrender={<Button …/>}(with deliberate raw-element exceptions for swatches and row-nested triggers, which do not apply here).
Not flagged (intentional or out of scope): removal of the ScrollArea/min-w-[680px] table (rows are now responsive), rounded-none + divide-y list composition, KeybindingSourceBadge returning null for defaults, the pre-existing pill button and WhenExpressionBuilder input class overrides (unchanged by this PR), and the unused autoFocus pass-through on NewKeybindingKeyInput (dead prop only, no behavioral effect).
🔍 Agent activity — 14 tool calls
💭 I'm checking the current head commit against what prior runs already flagged - the input size compact, WhenClauseControl variant, tooltip aria-label, sr-only shortcut, combobox heading, and menu slot null issues - to see what's still unresolved.
1. git_tools — afc8342..6ee6c83
2. browse_code — apps/web/src/components/settings/KeybindingsSettings.tsx
💭 The prior issues seem resolved now, so I'm double-checking the remaining areas like SettingsRow's control layout, Badge and Input sizing consistency, Button compact sizing, and the MenuPopup's minimum width class.
3. browse_code — apps/web/src/components/settings/settingsLayout.tsx
4. browse_code — apps/web/src/components/ui/badge.tsx
💭 I'm checking whether the description content in SettingsRow is valid HTML — a button-based Popover trigger nested inside a paragraph is fine since buttons are phrasing content. Now I'm looking at whether KeybindingSettingsRow's description has similar nesting that could cause issues. For the KeybindingKeyControl's pill-style button, that's pre-existing UI intentional to the design, so I'll skip flagging it since it wasn't changed by this diff. I'm also examining WhenClauseControl's inline ghost-style Popover trigger, comparing its focus ring styling against conventions used elsewhere in the codebase to see if it's missing something like a border ring on focus. I want to check whether other Popover triggers in the repo consistently use a Button render prop rather than raw styled elements, which would make this a legitimate pattern-consistency finding. I'm also looking at the unused autoFocus prop on NewKeybindingKeyInput — it seems to be dead code that was already flagged in a prior review comment, so re-flagging it now would likely be redundant. I also notice the list rows use rounded-none to override the primitive's radius, but that seems like intentional composition for a list rather than a real violation. Then I move on to the BrowserKeybindingNotice component, where a focusable span carries the full guidance in a tooltip, which could be a concern for touch/coarse-pointer users who can't access hover-based tooltips. Font sizes and widths for the description text, span, and mobile input all look consistent enough. I should still check the parts of the file I haven't reviewed yet — lines 1-700 and 1300 onward — to compare against existing components and confirm the section header/column labels weren't accidentally removed. I also notice each keybinding row now renders its title as an h3, meaning hundreds of headings per page, but that matches how other settings rows are structured, so it's fine. I want to double check the KeybindingPill button next, then look at the 1-700 range for warnings and how the panel ends.
5. browse_code — apps/web/src/components/settings/KeybindingsSettings.tsx
6. browse_code — apps/web/src/components/settings/KeybindingsSettings.tsx
💭 I'm checking the KeybindingRowMenu placeholder sizing against the icon button dimensions to make sure the reserved space and gap spacing line up correctly for the control cluster layout. Then I'm considering whether the conflict warning rendering conditionally could cause the pill or input to shift position when conflicts appear, since previously it sat in a fixed grid column but now lives inline in the flex cluster — this could introduce minor alignment jitter for rows with conflicts, and similarly the Save button appearing on dirty state could shift things further given the justify-end behavior at larger breakpoints. Since the container's right edge is fixed by the grid column but content is right-aligned within it, adding the Save button really does push the input leftward when it appears—something the old fixed-width keybinding column with left-aligned input didn't do. So this does look like a genuine, if moderate, regression introduced by the new layout, distinct from but related to the ragged-edge issue already flagged. That WhenClauseControl trigger is hand-rolled rather than using the repo's Button render-prop pattern for popover triggers, and I'm checking whether it's missing things like proper hit-target sizing for coarse pointers and a cursor-pointer style that Button's primitives would normally provide.
7. browse_code — apps/web/src/components/ui/button.tsx
8. git_tools — PopoverTrigger — rejected: repo.url: required parameter is missing or empty;repo: required parameter is missing or empty
9. git_tools — PopoverTrigger
💭 I'm noticing the repo has mixed patterns with hand-rolled trigger classNames, like the theme color pickers and the WhenClauseControl's inline quiet button. I'm weighing whether this counts as a reportable finding — the rule flags local triggers that recreate Select, Toggle, or Menu components, and I recall the old version actually did recreate a Select-like trigger. The PR changed that bordered trigger into a ghost inline button, which effectively reconstructs
Button variant="ghost" size="xs"but without cursor-pointer, coarse-pointer hit targets, focus ring, or disabled handling. Since the class string shifted but the same local-ownership pattern persists, and using the actual Button component would give all those accessibility affordances for free, I'm concluding this is a legitimate finding worth flagging. On touch, the "Always/When" text with chevron shrinks to roughly 50x24px, well under the recommended 44px target, and switching to a Button ghost variant with its coarse-pointer padding would fix that. I'm also weighing the row layout jitter when the Save button appears as a moderate issue, while the disabled state and description truncation both look fine. Now I'm checking whether the Input primitive's width class on its wrapper causes any conflicts. That dead prop already got flagged, so I'll not repeat it. I'm checking other details: all rows still get disabled together when any command is saving, badges render fine with null for defaults, and the switch from a min-width scroll area to responsive stacked rows is a real improvement for narrow viewports. Column headers are gone but the "When" label now appears inline, which seems fine, and I'm double-checking accessibility around the keybinding input next. I want to checkKeybindingConflictWarning's implementation around lines 600-700 to verify it null-renders correctly and confirm the icon in the control cluster isn't duplicated, then also reviewUnknownWhenVariableWarningfor the same concerns.
10. browse_code — apps/web/src/components/settings/KeybindingsSettings.tsx
11. browse_code — apps/web/src/components/ui/input.tsx
💭 I notice the WhenExpressionBuilder Input still uses the old-style class overrides, but that line wasn't touched in this diff, so it's a pre-existing pattern outside the scope of this review, not something to flag. Checking font-mono usage on the Input wrappers for keybinding controls — it's inherited by the inner input, so that's fine. The KeybindingPill's aria-label already includes the shortcut, so that's fine too. Now I want to figure out which findings are actually worth posting — prior review rounds already covered several issues that got addressed, so I should check what's changed since the last review to make sure I'm only flagging genuinely new code.
12. git_tools
💭 I'm noticing the log looks like it's from the base branch, so I'll focus on the current head's issues instead. One clear regression stands out: the hand-rolled trigger lacks a pointer cursor and proper focus styling for a button-role control, and its text size is inconsistent with the surrounding description text—a step down from the previous field-styled trigger that was clearly discoverable as an interactive element. It also duplicates ghost-button styling by hand rather than using the existing Button component, which already provides proper pointer cursor, touch target sizing, and disabled/focus behavior. Since other triggers in the file use
render={<Button .../>}, I think it's worth suggesting the same pattern here with a ghost variant sized to match the h-6 height—framed as a suggestion rather than a hard requirement, since nesting a Button inside a paragraph and using it with PopoverTrigger via mergeProps is a pattern already proven elsewhere in the codebase. Separately, I'm now looking at a layout jitter issue where the Save button's placement in a right-aligned cluster shifts other elements during editing. Mirroring the existing reserved-slot pattern used for the menu is a good, concrete fix here. Turning to BrowserKeybindingNotice, the change from a bordered warning banner to a plain row with tooltip-hidden text raises the question of touch accessibility, but since the author already added an aria-label and visible inline text, plus the trigger pattern matches other warning components in the file, it seems like a reasonable tradeoff rather than a new issue to flag. I check thatsize-4.5is valid in Tailwind v4's fractional spacing scale, so no problem there. I also note the unusedautoFocusprop onNewKeybindingKeyInputand the single-callsite optional className onNewKeybindingCommandSelect, but these feel too minor to raise. Circling back to the SettingsRow layout question, I want to check whether the grid template actually causes the control column to shift when content changes. I confirm that with the grid templateminmax(0,1fr)_minmax(10rem,auto), the second column grows to fit its content while the first column flexes, so widening content in the control column does shift things leftward as suspected. I also note each row is its own independent grid, so control column widths vary row to row, though right edges stay aligned thanks to the reserved menu slot—this cross-row inconsistency in title column width doesn't matter. The more important finding is that when the Save button appears between the pill and the menu, it pushes the pill's right edge leftward, confirming the earlier issue. I want to verify next whether KeybindingConflictWarning renders null when there's nothing to show.
13. git_tools — function KeybindingConflictWarning
💭 I confirm the conflict warning being right-aligned doesn't shift the pill's position since it's left of the pill, so that finding only applies to the Save button issue. Now I need to decide whether to file two comments — one about the trigger hit-target and one about Save-slot jitter — and gauge how confident I am in each before committing. Digging into the trigger button variant, I'm checking whether swapping in
Button variant="ghost"would properly preserve the font-mono styling, rounded corners, chevron sizing, and muted-foreground color logic depending on whether there's an expression present, tracing through how the className merge order would resolve the text color in each case. The stronger, more objective finding is the missingcursor-pointerclass — a real interaction inconsistency with the rest of the codebase's button conventions given Tailwind v4's default cursor behavior, though this issue predates the current patch since the old trigger lacked it too; still, since the patch rewrote the whole trigger element, it's fair to flag as something the patch touches and could fix. The other concrete issue is the shrunk hit target on coarse pointers — going from a full-width h-7 field to an inline h-6 px-1 target without thepointer-coarse:after:min-h-11expansion that the repo's Button/Badge components use, which is a genuine touch-target regression. I'll combine both points into one comment recommending a Button ghost variant, then move on to the Save slot jitter comment, and do a final check on the pill button to confirm it's just relocated content with no new issues. I'm weighing whether the inline trigger's geometry genuinely differs from Button enough to exempt it from flagging — its sizing looks close to a ghost xs button, which cuts against that exemption. Given the check defaults to failure and past rounds surfaced real issues, posting both comments seems justified despite the false-positive risk, though I want to sanity-check the touch-target concern against whether this settings UI is actually used on touch devices. I'm reconsidering whether to post both flags or just the more concrete Save-slot layout jitter, tracing through the interaction: clicking the pill sets recording state, swaps in an autofocused input before any dirty state exists, and the width change from a narrow pill to a fixed 176px input causes a real, noticeable layout shift in the control column. est. I'm thinking the fix could reserve a fixed-width span always rendered for the Save button slot, so the layout doesn't shift when it appears. An alternative is rendering the button always but hidden withinvisiblewhen not dirty, which keeps the width consistent and removes it from the tab order without a jump. Still writing diff... Given the guidance defaults to failure when findings exist, I'll set the state to failure with both findings, but frame the trigger-behavior one as a softer suggestion about cursor/pointer/primitive reuse rather than a hard defect. Now I need to figure out the right line numbers for each comment. I'm mapping the Save-jitter comment to lines 845-853 and the When-trigger comment to lines 876-885, both on the new file side, and confirming these fall within the diff hunks before drafting the actual comment text about how the menu slot reservation interacts with the right-aligned settings row layout. For the Save comment, I'm noting the fix suggestion — reserving the Save slot the same way the menu slot is reserved to stop the ~50px jump when the draft becomes dirty. For the When trigger comment, I'm flagging that dropping the field styling leaves the hover background as the only affordance, and the trigger is hand-rolled instead of using a Button, missing cursor-pointer, the touch hit-target sizing, and having an inconsistent focus ring. I'm now sketching the fix as rendering the trigger through the ghost Button variant so those behaviors live in the primitive, then working out how to express that as a diff since usingrendermeans PopoverTrigger's className shouldn't also be set separately. I confirm this preserves the ghost variant's hover states and focus ring styling correctly, and the render prop pattern with PopoverTrigger is already used elsewhere in the file. I'll skip mentioning the pill detail and move on to finalizing the review with a summarizing body.
14. modify_pr — Two follow-ups on the new SettingsRow-based layout: one layout shift introduced by putting Save inside the right-aligned control cluster, and one hand-rolled trigger that now carries the affordance for the When clause.
Agent Credits: 142 credits