diff --git a/packages/studio/src/player/components/LayerDisclosureRow.tsx b/packages/studio/src/player/components/LayerDisclosureRow.tsx index 1dc27408d..718b8e127 100644 --- a/packages/studio/src/player/components/LayerDisclosureRow.tsx +++ b/packages/studio/src/player/components/LayerDisclosureRow.tsx @@ -1,7 +1,8 @@ import { TRACK_H } from "./timelineLayout"; import { TrackClipCount } from "./TrackClipCount"; -// Layer row (Figma order: disclosure ∿, diamond, name) — the disclosure lives +// Layer row (diamond, name, then the ∿ disclosure on the right edge) — the +// disclosure lives // here, not on the clip bar, and re-expands a collapsed layer. `∿` (not a // caret) because a group's own row keeps the caret for its structural // disclosure (member rows) — this button only ever means "show this row's @@ -45,27 +46,6 @@ export function LayerDisclosureRow({ background: gutterBackground, }} > - {/* Decorative: the disclosure button above already names the row's keyframe state, and aria-label on a plain span is not exposed reliably anyway. */} {children} + {/* Anchored right, on every header that has one: the lane toggle is the + row's last word about itself, and a left-hand ∿ put it where the eye + looks for identity instead. `ml-auto` rather than a spacer so it holds + the edge whatever else the row grows. */} + ); } diff --git a/packages/studio/src/player/components/TimelineGroupHeader.tsx b/packages/studio/src/player/components/TimelineGroupHeader.tsx index ebf68d91c..0f815eb6f 100644 --- a/packages/studio/src/player/components/TimelineGroupHeader.tsx +++ b/packages/studio/src/player/components/TimelineGroupHeader.tsx @@ -133,7 +133,7 @@ export function TimelineGroupHeader({ {/* 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. */} -
+
event.stopPropagation()} diff --git a/packages/studio/src/player/components/TimelineTrackHeader.test.tsx b/packages/studio/src/player/components/TimelineTrackHeader.test.tsx index 63474aadf..845f8a27d 100644 --- a/packages/studio/src/player/components/TimelineTrackHeader.test.tsx +++ b/packages/studio/src/player/components/TimelineTrackHeader.test.tsx @@ -771,6 +771,7 @@ describe("TimelineTrackHeader", () => { expect(header()?.style.paddingLeft).toBe(""); expect(header()?.style.borderLeft).toBe(""); + expect(header()?.style.background).not.toContain("linear-gradient"); view.rerender({ keyframeClip: VOICE, @@ -781,6 +782,10 @@ describe("TimelineTrackHeader", () => { }); expect(header()?.style.paddingLeft).toBe("14px"); expect(header()?.style.borderLeft).toContain("2px"); + // And a lighter gutter, so the row reads as sitting INSIDE its group + // rather than beside it. Overlaid on the theme's own fill rather than a + // hard-coded colour, so it follows whatever the gutter is. + expect(header()?.style.background).toContain("linear-gradient"); act(() => view.root.unmount()); }); diff --git a/packages/studio/src/player/components/TimelineTrackHeader.tsx b/packages/studio/src/player/components/TimelineTrackHeader.tsx index 67153ab52..99bf6571f 100644 --- a/packages/studio/src/player/components/TimelineTrackHeader.tsx +++ b/packages/studio/src/player/components/TimelineTrackHeader.tsx @@ -34,6 +34,17 @@ import { timelineLogicalRowCellId, timelinePropertyRowId } from "./timelineNavig * nesting its `aria-level` already reports. */ const GROUP_MEMBER_RAIL = "#3CE6AC59"; const GROUP_MEMBER_INDENT = 14; +/** A hair lighter than `gutterBackground`, so a member row reads as sitting + * INSIDE its group rather than beside it. Overlaid rather than hard-coded so + * it tracks whatever the theme's gutter is. */ +const GROUP_MEMBER_TINT = "rgba(255,255,255,0.035)"; + +/** The gutter fill for a row, tinted when it belongs to a group. */ +function gutterFill(base: string, isGroupMember: boolean): string { + return isGroupMember + ? `linear-gradient(${GROUP_MEMBER_TINT}, ${GROUP_MEMBER_TINT}), ${base}` + : base; +} interface TimelineTrackHeaderProps { /** The track's real key: a FRACTIONAL z-order sort value. Routes callbacks; @@ -489,7 +500,7 @@ export function TimelineTrackHeader({ }`} style={{ width: showTrackLabel ? LABEL_COL_W : contentOrigin, - background: theme.gutterBackground, + background: gutterFill(theme.gutterBackground, isGroupMember), borderRight: `1px solid ${theme.gutterBorder}`, // A group's member rows are `aria-level="2"`, and until this they read // as level 2 to a screen reader while looking identical to every @@ -578,7 +589,7 @@ export function TimelineTrackHeader({ } clipCount={clipCount} isExpanded={isExpanded} - gutterBackground={theme.gutterBackground} + gutterBackground={gutterFill(theme.gutterBackground, isGroupMember)} columnWidth={showTrackLabel ? LABEL_COL_W : contentOrigin} lanesId={lanesId} onToggleClipExpanded={onToggleClipExpanded} @@ -615,7 +626,7 @@ export function TimelineTrackHeader({ expandedElement={keyframeClip} currentTime={currentTime} clipPercentage={clipPercentage} - gutterBackground={theme.gutterBackground} + gutterBackground={gutterFill(theme.gutterBackground, isGroupMember)} columnWidth={showTrackLabel ? LABEL_COL_W : contentOrigin} onTogglePropertyGroupKeyframe={onTogglePropertyGroupKeyframe} onSeek={onSeek} @@ -638,7 +649,7 @@ export function TimelineTrackHeader({ } top={getTimelineLaneTop(lanes.length) + index * AUTOMATION_LANE_H} isLastLane={index === automationRows.length - 1} - gutterBackground={theme.gutterBackground} + gutterBackground={gutterFill(theme.gutterBackground, isGroupMember)} columnWidth={showTrackLabel ? LABEL_COL_W : contentOrigin} onRemove={onRemoveAutomationLane} />