fix(import): shrink the conflict control and fold its help inside it

The conflict row's segmented control ran at the default size with the help
icon floating outside the group. Drop it to the smallest button size and
hand the help to the control, which shows it in its last option whenever
the label is hidden — the only case where the label has nowhere to put it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Gregory Schier
2026-09-02 11:13:19 -07:00
co-authored by Claude Opus 5
parent bd932ce85f
commit 72d3bda769
2 changed files with 13 additions and 4 deletions
@@ -571,11 +571,13 @@ function ImportTreeRow({
)} )}
<div className="truncate flex-1">{item.name}</div> <div className="truncate flex-1">{item.name}</div>
{item.action === "conflict" ? ( {item.action === "conflict" ? (
<div className="shrink-0 flex items-center gap-1.5"> <div className="shrink-0">
<SegmentedControl <SegmentedControl
name={`conflict-${item.modelId}`} name={`conflict-${item.modelId}`}
label={`Resolve conflict for ${item.name}`} label={`Resolve conflict for ${item.name}`}
hideLabel hideLabel
size="2xs"
help={actionHelp(item)}
value={item.resolution ?? "keep_mine"} value={item.resolution ?? "keep_mine"}
onChange={(v) => onResolveConflict(item.modelId, v)} onChange={(v) => onResolveConflict(item.modelId, v)}
options={[ options={[
@@ -583,7 +585,6 @@ function ImportTreeRow({
{ value: "take_source", label: "Take source" }, { value: "take_source", label: "Take source" },
]} ]}
/> />
<IconTooltip content={actionHelp(item)} iconSize="sm" />
</div> </div>
) : ( ) : (
actionLabel(item) && ( actionLabel(item) && (
@@ -6,6 +6,7 @@ import { useStateWithDeps } from "../../hooks/useStateWithDeps";
import { generateId } from "../../lib/generateId"; import { generateId } from "../../lib/generateId";
import { Button } from "./Button"; import { Button } from "./Button";
import { IconButton, type IconButtonProps } from "./IconButton"; import { IconButton, type IconButtonProps } from "./IconButton";
import { IconTooltip } from "./IconTooltip";
import { Label } from "./Label"; import { Label } from "./Label";
interface Props<T extends string> { interface Props<T extends string> {
@@ -36,11 +37,15 @@ export function SegmentedControl<T extends string>({
const containerRef = useRef<HTMLDivElement>(null); const containerRef = useRef<HTMLDivElement>(null);
const id = useRef(`input-${generateId()}`); const id = useRef(`input-${generateId()}`);
// A visually hidden label has nowhere to show the help, so the last option carries it
const inlineHelp =
hideLabel && help ? <IconTooltip tabIndex={-1} content={help} iconSize="xs" /> : null;
return ( return (
<div className="w-full grid"> <div className="w-full grid">
<Label <Label
htmlFor={id.current} htmlFor={id.current}
help={help} help={hideLabel ? undefined : help}
visuallyHidden={hideLabel} visuallyHidden={hideLabel}
className={classNames(labelClassName)} className={classNames(labelClassName)}
> >
@@ -78,9 +83,10 @@ export function SegmentedControl<T extends string>({
} }
}} }}
> >
{options.map((o) => { {options.map((o, i) => {
const isSelected = selectedValue === o.value; const isSelected = selectedValue === o.value;
const isActive = value === o.value; const isActive = value === o.value;
const rightSlot = i === options.length - 1 ? inlineHelp : null;
if (o.icon == null) { if (o.icon == null) {
return ( return (
<Button <Button
@@ -95,6 +101,7 @@ export function SegmentedControl<T extends string>({
isActive && "text-text!", isActive && "text-text!",
"focus:ring-1 focus:ring-border-focus", "focus:ring-1 focus:ring-border-focus",
)} )}
rightSlot={rightSlot}
onClick={() => onChange(o.value)} onClick={() => onChange(o.value)}
> >
{o.label} {o.label}
@@ -117,6 +124,7 @@ export function SegmentedControl<T extends string>({
)} )}
title={o.label} title={o.label}
icon={o.icon} icon={o.icon}
rightSlot={rightSlot}
onClick={() => onChange(o.value)} onClick={() => onChange(o.value)}
/> />
); );