From c3f0d640ef366fe4d94ff995ee8fe5ef282b9c1e Mon Sep 17 00:00:00 2001 From: Maze Winther Date: Mon, 2 Feb 2026 18:11:12 +0100 Subject: feat: exponential zoom --- .../editor/timeline/timeline-toolbar.tsx | 31 ++++++++++------------ 1 file changed, 14 insertions(+), 17 deletions(-) (limited to 'apps/web/src/components/editor/timeline/timeline-toolbar.tsx') diff --git a/apps/web/src/components/editor/timeline/timeline-toolbar.tsx b/apps/web/src/components/editor/timeline/timeline-toolbar.tsx index 822bb438..33cf83ae 100644 --- a/apps/web/src/components/editor/timeline/timeline-toolbar.tsx +++ b/apps/web/src/components/editor/timeline/timeline-toolbar.tsx @@ -16,6 +16,7 @@ import { import { Slider } from "@/components/ui/slider"; import { formatTimeCode } from "@/lib/time"; import { TIMELINE_CONSTANTS } from "@/constants/timeline-constants"; +import { sliderToZoom, zoomToSlider } from "@/lib/timeline/zoom-utils"; import { EditableTimecode } from "@/components/editable-timecode"; import { ScenesView } from "../scenes-view"; import { type TAction, invokeAction } from "@/lib/actions"; @@ -50,13 +51,11 @@ export function TimelineToolbar({ setZoomLevel: ({ zoom }: { zoom: number }) => void; }) { const handleZoom = ({ direction }: { direction: "in" | "out" }) => { + const zoomFactor = 1.25; const newZoomLevel = direction === "in" - ? Math.min( - TIMELINE_CONSTANTS.ZOOM_MAX, - zoomLevel + TIMELINE_CONSTANTS.ZOOM_STEP, - ) - : Math.max(minZoom, zoomLevel - TIMELINE_CONSTANTS.ZOOM_STEP); + ? Math.min(TIMELINE_CONSTANTS.ZOOM_MAX, zoomLevel * zoomFactor) + : Math.max(minZoom, zoomLevel / zoomFactor); setZoomLevel({ zoom: newZoomLevel }); }; @@ -127,17 +126,13 @@ function ToolbarLeftSection() { } tooltip="Split element" - onClick={({ event }) => - handleAction({ action: "split", event }) - } + onClick={({ event }) => handleAction({ action: "split", event })} /> } tooltip="Split left" - onClick={({ event }) => - handleAction({ action: "split-left", event }) - } + onClick={({ event }) => handleAction({ action: "split-left", event })} /> onZoomChange(values[0])} - min={minZoom} - max={TIMELINE_CONSTANTS.ZOOM_MAX} - step={TIMELINE_CONSTANTS.ZOOM_STEP} + className="w-28" + value={[zoomToSlider({ zoomLevel, minZoom })]} + onValueChange={(values) => + onZoomChange(sliderToZoom({ sliderPosition: values[0], minZoom })) + } + min={0} + max={1} + step={0.005} /> onZoom({ direction: "in" })} > - + diff --git a/apps/web/src/constants/timeline-constants.tsx b/apps/web/src/constants/timeline-constants.tsx index 692ccd65..e467de41 100644 --- a/apps/web/src/constants/timeline-constants.tsx +++ b/apps/web/src/constants/timeline-constants.tsx @@ -35,12 +35,10 @@ export const TRACK_GAP = 4; export const TIMELINE_CONSTANTS = { PIXELS_PER_SECOND: 50, DEFAULT_ELEMENT_DURATION: 5, - PLAYHEAD_LOOKAHEAD_SECONDS: 30, // padding ahead PADDING_TOP_PX: 0, - ZOOM_LEVELS: [0.1, 0.25, 0.5, 1, 1.5, 2, 3, 4, 6, 8, 10, 15, 20, 30, 50], ZOOM_MIN: 0.1, ZOOM_MAX: 100, - ZOOM_STEP: 0.1, + ZOOM_BUTTON_FACTOR: 1.7, } as const; export const DEFAULT_TIMELINE_VIEW_STATE: TTimelineViewState = { diff --git a/apps/web/src/lib/timeline/zoom-utils.ts b/apps/web/src/lib/timeline/zoom-utils.ts index c4a64ed1..a299edb3 100644 --- a/apps/web/src/lib/timeline/zoom-utils.ts +++ b/apps/web/src/lib/timeline/zoom-utils.ts @@ -53,8 +53,8 @@ export function getZoomPercent({ } /** - * Convert linear slider position (0-1) to exponential zoom level. - * At low slider values, zoom changes are small. At high values, changes are large. + * convert linear slider position (0-1) to exponential zoom level. + * at low slider values, zoom changes are small. at high values, changes are large. */ export function sliderToZoom({ sliderPosition, -- cgit v1.3.1