fix(editor): allow scrolling all audio tracks

Allow timeline content to grow with additional audio rows so the existing scroll container can reach lower tracks.
This commit is contained in:
Wiii
2026-04-26 23:48:38 +07:00
committed by GitHub
parent 574cefc6bd
commit 5238dd79ce
4 changed files with 66 additions and 4 deletions
@@ -60,6 +60,10 @@ import Item from "./Item";
import KeyframeMarkers from "./KeyframeMarkers";
import Row from "./Row";
import TimelineWrapper from "./TimelineWrapper";
import {
getTimelineContentMinHeightPx,
getTimelineRowsMinHeightPx,
} from "./timelineLayout";
import { type AudioPeaksData, useAudioPeaks } from "./useAudioPeaks";
import { buildInteractionZoomSuggestions } from "./zoomSuggestionUtils";
@@ -702,12 +706,18 @@ function Timeline({
).sort((left, right) => getAnnotationTrackIndex(left) - getAnnotationTrackIndex(right)),
[annotationItems],
);
const timelineRowCount = 2 + annotationRowIds.length + audioRowIds.length;
const timelineRowsMinHeightPx = getTimelineRowsMinHeightPx(timelineRowCount);
const timelineContentMinHeightPx = getTimelineContentMinHeightPx(timelineRowCount);
return (
<div
ref={setRefs}
style={style}
className="select-none bg-editor-bg h-full min-h-0 relative cursor-pointer group flex flex-col"
style={{
...style,
minHeight: `max(100%, ${timelineContentMinHeightPx}px)`,
}}
className="select-none bg-editor-bg relative cursor-pointer group flex flex-col"
onClick={handleTimelineClick}
>
<div className="absolute inset-0 bg-[linear-gradient(to_right,hsl(var(--foreground)/0.03)_1px,transparent_1px)] bg-[length:20px_100%] pointer-events-none" />
@@ -720,7 +730,10 @@ function Timeline({
keyframes={keyframes}
/>
<div className="relative z-10 flex flex-1 min-h-0 flex-col">
<div
className="relative z-10 flex flex-1 min-h-0 flex-col"
style={{ minHeight: timelineRowsMinHeightPx }}
>
<Row id={CLIP_ROW_ID} isEmpty={clipItems.length === 0} hint="Press C to split clip">
{audioPeaks && <AudioWaveform peaks={audioPeaks} />}
<ClipMarkerOverlay videoDurationMs={videoDurationMs} />
@@ -375,7 +375,7 @@ export default function TimelineWrapper({
autoScroll={{ enabled: false }}
resizeHandleWidth={28}
>
<div className="relative h-full min-h-0">
<div className="relative min-h-full">
{children}
{/* Floating tooltip shown during drag/resize */}
<div
@@ -0,0 +1,31 @@
import { describe, expect, it } from "vitest";
import {
getTimelineContentMinHeightPx,
getTimelineRowsMinHeightPx,
TIMELINE_AXIS_HEIGHT_PX,
TIMELINE_ROW_MIN_HEIGHT_PX,
} from "./timelineLayout";
describe("timelineLayout", () => {
it("reserves vertical space for every rendered timeline row", () => {
expect(getTimelineRowsMinHeightPx(5)).toBe(5 * TIMELINE_ROW_MIN_HEIGHT_PX);
expect(getTimelineContentMinHeightPx(5)).toBe(
TIMELINE_AXIS_HEIGHT_PX + 5 * TIMELINE_ROW_MIN_HEIGHT_PX,
);
});
it("ignores invalid row counts", () => {
expect(getTimelineRowsMinHeightPx(-1)).toBe(0);
expect(getTimelineRowsMinHeightPx(Number.NaN)).toBe(0);
expect(getTimelineContentMinHeightPx(Number.POSITIVE_INFINITY)).toBe(
TIMELINE_AXIS_HEIGHT_PX,
);
});
it("floors fractional row counts", () => {
expect(getTimelineRowsMinHeightPx(2.9)).toBe(2 * TIMELINE_ROW_MIN_HEIGHT_PX);
expect(getTimelineContentMinHeightPx(2.9)).toBe(
TIMELINE_AXIS_HEIGHT_PX + 2 * TIMELINE_ROW_MIN_HEIGHT_PX,
);
});
});
@@ -0,0 +1,18 @@
export const TIMELINE_AXIS_HEIGHT_PX = 32;
export const TIMELINE_ROW_MIN_HEIGHT_PX = 28;
function normalizeRowCount(rowCount: number) {
if (!Number.isFinite(rowCount)) {
return 0;
}
return Math.max(0, Math.floor(rowCount));
}
export function getTimelineRowsMinHeightPx(rowCount: number) {
return normalizeRowCount(rowCount) * TIMELINE_ROW_MIN_HEIGHT_PX;
}
export function getTimelineContentMinHeightPx(rowCount: number) {
return TIMELINE_AXIS_HEIGHT_PX + getTimelineRowsMinHeightPx(rowCount);
}