diff options
Diffstat (limited to 'apps/web/src')
| -rw-r--r-- | apps/web/src/components/editor/timeline/timeline-toolbar.tsx | 31 | ||||
| -rw-r--r-- | apps/web/src/lib/timeline/zoom-utils.ts | 33 |
2 files changed, 47 insertions, 17 deletions
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() { <ToolbarButton icon={<HugeiconsIcon icon={ScissorIcon} />} tooltip="Split element" - onClick={({ event }) => - handleAction({ action: "split", event }) - } + onClick={({ event }) => handleAction({ action: "split", event })} /> <ToolbarButton icon={<HugeiconsIcon icon={AlignLeftIcon} />} tooltip="Split left" - onClick={({ event }) => - handleAction({ action: "split-left", event }) - } + onClick={({ event }) => handleAction({ action: "split-left", event })} /> <ToolbarButton @@ -305,12 +300,14 @@ function ToolbarRightSection({ <HugeiconsIcon icon={SearchAddIcon} /> </Button> <Slider - className="w-24" - value={[zoomLevel]} - onValueChange={(values) => 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} /> <Button variant="text" diff --git a/apps/web/src/lib/timeline/zoom-utils.ts b/apps/web/src/lib/timeline/zoom-utils.ts index 49f7fcb6..c4a64ed1 100644 --- a/apps/web/src/lib/timeline/zoom-utils.ts +++ b/apps/web/src/lib/timeline/zoom-utils.ts @@ -51,3 +51,36 @@ export function getZoomPercent({ }): number { return (zoomLevel - minZoom) / (TIMELINE_CONSTANTS.ZOOM_MAX - minZoom); } + +/** + * 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, + minZoom, + maxZoom = TIMELINE_CONSTANTS.ZOOM_MAX, +}: { + sliderPosition: number; + minZoom: number; + maxZoom?: number; +}): number { + const clampedPosition = Math.max(0, Math.min(1, sliderPosition)); + return minZoom * (maxZoom / minZoom) ** clampedPosition; +} + +/** + * Convert exponential zoom level to linear slider position (0-1). + */ +export function zoomToSlider({ + zoomLevel, + minZoom, + maxZoom = TIMELINE_CONSTANTS.ZOOM_MAX, +}: { + zoomLevel: number; + minZoom: number; + maxZoom?: number; +}): number { + const clampedZoom = Math.max(minZoom, Math.min(maxZoom, zoomLevel)); + return Math.log(clampedZoom / minZoom) / Math.log(maxZoom / minZoom); +} |
