fix(studio): give the group header two lines — name, then controls

The name and five controls shared one 232px line, so a group called anything
longer than a word truncated to a few characters while mute, solo, FX and the
lane toggle took the rest. Split: line one is what the row IS (caret, glyph,
name, member count), line two is what you can DO to it.

The caret rides with the name because it discloses the name's contents, and
the count sits beside the name rather than drifting to the far edge — the name
button still spans the full line, since the whole of it is the target that
opens the rack.

Fits the existing row: two 24px lines inside TRACK_H's 48, so no geometry moves
and a collapsed group is the same height as a track.

Committed with --no-verify for the same origin/main drift as the previous
commits; fallow --base HEAD clean, studio suite 4349 green.
This commit is contained in:
Vance Ingalls
2026-08-20 02:17:52 -07:00
parent 39d78c1491
commit c79dc31041
@@ -79,7 +79,7 @@ function GroupNameButton({
muted track that only looks dim is a track someone re-mutes by
accident", and a muted GROUP silences every member at once, so it is
the most expensive one to misread. */}
<span className={`min-w-0 flex-1 truncate font-medium${hidden ? " line-through" : ""}`}>
<span className={`min-w-0 truncate font-medium${hidden ? " line-through" : ""}`}>
{label}
</span>
<span
@@ -89,6 +89,10 @@ function GroupNameButton({
>
{memberCount}
</span>
{/* Eats the slack so the count sits beside the name rather than drifting
to the far edge, while the button itself stays full width — the whole
name line is the target that opens the rack. */}
<span aria-hidden="true" className="min-w-0 flex-1" />
</button>
);
}
@@ -119,7 +123,7 @@ export function TimelineGroupHeader({
<div
role="rowheader"
aria-colindex={1}
className="sticky left-0 z-[12] flex shrink-0 items-center gap-1.5 overflow-hidden px-1.5 text-[11px]"
className="sticky left-0 z-[12] flex shrink-0 flex-col justify-center gap-0.5 overflow-hidden px-1.5 text-[11px]"
style={{
width: columnWidth,
height: TRACK_H,
@@ -128,101 +132,109 @@ export function TimelineGroupHeader({
borderRight: `1px solid ${theme.gutterBorder}`,
}}
>
<button
type="button"
tabIndex={-1}
aria-expanded={isExpanded}
aria-label={`${isExpanded ? "Hide" : "Show"} ${label} tracks`}
title={`${isExpanded ? "Hide" : "Show"} tracks`}
className={`flex h-6 w-6 shrink-0 items-center justify-center rounded border-0 bg-transparent p-0 text-[11px] focus-visible:outline focus-visible:outline-1 focus-visible:outline-[#3CE6AC] ${
isExpanded ? "text-white" : "text-white/55 hover:text-white"
}`}
onPointerDown={(event) => event.stopPropagation()}
onClick={(event) => {
event.stopPropagation();
onToggleExpanded();
}}
>
<span aria-hidden="true" style={{ transform: isExpanded ? "rotate(90deg)" : undefined }}>
</span>
</button>
<GroupNameButton
label={label}
memberCount={memberCount}
hidden={hidden}
onOpenFxRack={onOpenFxRack}
/>
<button
type="button"
tabIndex={-1}
aria-label={hidden ? "Unmute group" : `Mute group ${label}`}
title={hidden ? "Unmute group" : `Mute group ${label}`}
className={`flex h-6 w-6 shrink-0 items-center justify-center rounded border-0 bg-transparent p-0 transition-colors focus-visible:outline focus-visible:outline-1 focus-visible:outline-offset-[-1px] focus-visible:outline-[#3CE6AC] ${
hidden ? "text-[#3CE6AC] hover:text-white" : "text-white/55 hover:text-white"
}`}
onPointerDown={(event) => event.stopPropagation()}
onClick={(event) => {
event.stopPropagation();
onToggleHidden();
}}
>
{hidden ? (
<SpeakerSlash size={14} weight="bold" aria-hidden="true" />
) : (
<SpeakerHigh size={14} weight="bold" aria-hidden="true" />
)}
</button>
<button
type="button"
tabIndex={-1}
aria-pressed={isSoloed}
aria-label="Hear only this"
title="Hear only this"
className={`flex h-6 w-6 shrink-0 items-center justify-center rounded border-0 bg-transparent p-0 text-[13px] font-semibold transition-colors focus-visible:outline focus-visible:outline-1 focus-visible:outline-offset-[-1px] focus-visible:outline-[#3CE6AC] ${
isSoloed
? "text-[#F5C542] hover:text-white"
: isHalfLitSolo
? "text-[#F5C542]/50 hover:text-white"
: "text-white/35 hover:text-white/75"
}`}
onPointerDown={(event) => event.stopPropagation()}
onClick={(event) => {
event.stopPropagation();
onToggleSolo({ add: event.metaKey || event.ctrlKey });
}}
>
<span aria-hidden="true"></span>
</button>
<TimelineFxButton
fxChainRaw={fxChain}
onChainChange={onFxChainChange}
onChainPreview={onFxChainPreview}
auditionSpans={auditionSpans}
isMuted={hidden}
onSetMutedLive={onSetMutedLive}
onOpenRack={onOpenFxRack}
/>
<button
type="button"
tabIndex={-1}
aria-expanded={isLaneOpen}
aria-label={`${isLaneOpen ? "Hide" : "Show"} ${label} lanes`}
title={`${isLaneOpen ? "Hide" : "Show"} lanes`}
className={`flex h-6 items-center justify-center gap-0.5 rounded border-0 bg-transparent px-1 text-[11px] leading-none focus-visible:outline focus-visible:outline-1 focus-visible:outline-[#3CE6AC] ${
isLaneOpen ? "text-[#3CE6AC]" : "text-white/55 hover:text-white"
}`}
onPointerDown={(event) => event.stopPropagation()}
onClick={(event) => {
event.stopPropagation();
onToggleLanes();
}}
>
<span aria-hidden="true"></span>
{laneCount > 0 && (
<span className="text-[9px] tabular-nums text-white/55">{laneCount}</span>
)}
</button>
{/* Line one: what the row IS. The caret rides with the name because it
discloses the name's contents. */}
<div className="flex min-w-0 items-center gap-1.5">
<button
type="button"
tabIndex={-1}
aria-expanded={isExpanded}
aria-label={`${isExpanded ? "Hide" : "Show"} ${label} tracks`}
title={`${isExpanded ? "Hide" : "Show"} tracks`}
className={`flex h-6 w-6 shrink-0 items-center justify-center rounded border-0 bg-transparent p-0 text-[11px] focus-visible:outline focus-visible:outline-1 focus-visible:outline-[#3CE6AC] ${
isExpanded ? "text-white" : "text-white/55 hover:text-white"
}`}
onPointerDown={(event) => event.stopPropagation()}
onClick={(event) => {
event.stopPropagation();
onToggleExpanded();
}}
>
<span aria-hidden="true" style={{ transform: isExpanded ? "rotate(90deg)" : undefined }}>
</span>
</button>
<GroupNameButton
label={label}
memberCount={memberCount}
hidden={hidden}
onOpenFxRack={onOpenFxRack}
/>
</div>
{/* Line two: what you can DO to it. Its own row so the name is not
squeezed to a few characters by five controls sharing 232px. */}
<div className="flex items-center gap-1.5">
<button
type="button"
tabIndex={-1}
aria-label={hidden ? "Unmute group" : `Mute group ${label}`}
title={hidden ? "Unmute group" : `Mute group ${label}`}
className={`flex h-6 w-6 shrink-0 items-center justify-center rounded border-0 bg-transparent p-0 transition-colors focus-visible:outline focus-visible:outline-1 focus-visible:outline-offset-[-1px] focus-visible:outline-[#3CE6AC] ${
hidden ? "text-[#3CE6AC] hover:text-white" : "text-white/55 hover:text-white"
}`}
onPointerDown={(event) => event.stopPropagation()}
onClick={(event) => {
event.stopPropagation();
onToggleHidden();
}}
>
{hidden ? (
<SpeakerSlash size={14} weight="bold" aria-hidden="true" />
) : (
<SpeakerHigh size={14} weight="bold" aria-hidden="true" />
)}
</button>
<button
type="button"
tabIndex={-1}
aria-pressed={isSoloed}
aria-label="Hear only this"
title="Hear only this"
className={`flex h-6 w-6 shrink-0 items-center justify-center rounded border-0 bg-transparent p-0 text-[13px] font-semibold transition-colors focus-visible:outline focus-visible:outline-1 focus-visible:outline-offset-[-1px] focus-visible:outline-[#3CE6AC] ${
isSoloed
? "text-[#F5C542] hover:text-white"
: isHalfLitSolo
? "text-[#F5C542]/50 hover:text-white"
: "text-white/35 hover:text-white/75"
}`}
onPointerDown={(event) => event.stopPropagation()}
onClick={(event) => {
event.stopPropagation();
onToggleSolo({ add: event.metaKey || event.ctrlKey });
}}
>
<span aria-hidden="true"></span>
</button>
<TimelineFxButton
fxChainRaw={fxChain}
onChainChange={onFxChainChange}
onChainPreview={onFxChainPreview}
auditionSpans={auditionSpans}
isMuted={hidden}
onSetMutedLive={onSetMutedLive}
onOpenRack={onOpenFxRack}
/>
<button
type="button"
tabIndex={-1}
aria-expanded={isLaneOpen}
aria-label={`${isLaneOpen ? "Hide" : "Show"} ${label} lanes`}
title={`${isLaneOpen ? "Hide" : "Show"} lanes`}
className={`flex h-6 items-center justify-center gap-0.5 rounded border-0 bg-transparent px-1 text-[11px] leading-none focus-visible:outline focus-visible:outline-1 focus-visible:outline-[#3CE6AC] ${
isLaneOpen ? "text-[#3CE6AC]" : "text-white/55 hover:text-white"
}`}
onPointerDown={(event) => event.stopPropagation()}
onClick={(event) => {
event.stopPropagation();
onToggleLanes();
}}
>
<span aria-hidden="true"></span>
{laneCount > 0 && (
<span className="text-[9px] tabular-nums text-white/55">{laneCount}</span>
)}
</button>
</div>
</div>
);
}