feat(zoom): add mode switcher and smoothness slider to zoom UI

Add auto/manual pill-button mode switcher in zoom region detail.
Move Zoom Smoothness slider from cursor section to zoom section.
This commit is contained in:
webadderall
2026-04-08 22:00:16 +10:00
parent 8daa804ff5
commit 8f6f1d3d68
@@ -41,6 +41,7 @@ import type {
WebcamOverlaySettings,
WebcamPositionPreset,
ZoomDepth,
ZoomMode,
ZoomTransitionEasing,
} from "./types";
import {
@@ -149,6 +150,8 @@ interface SettingsPanelProps {
selectedZoomDepth?: ZoomDepth | null;
onZoomDepthChange?: (depth: ZoomDepth) => void;
selectedZoomId?: string | null;
selectedZoomMode?: ZoomMode | null;
onZoomModeChange?: (mode: ZoomMode) => void;
onZoomDelete?: (id: string) => void;
selectedTrimId?: string | null;
onTrimDelete?: (id: string) => void;
@@ -190,6 +193,8 @@ interface SettingsPanelProps {
onCursorSizeChange?: (size: number) => void;
cursorSmoothing?: number;
onCursorSmoothingChange?: (smoothing: number) => void;
zoomSmoothness?: number;
onZoomSmoothnessChange?: (smoothness: number) => void;
cursorMotionBlur?: number;
onCursorMotionBlurChange?: (amount: number) => void;
cursorClickBounce?: number;
@@ -508,6 +513,8 @@ export function SettingsPanel({
selectedZoomDepth,
onZoomDepthChange,
selectedZoomId,
selectedZoomMode,
onZoomModeChange,
onZoomDelete,
selectedTrimId,
onTrimDelete,
@@ -531,6 +538,8 @@ export function SettingsPanel({
onCursorSizeChange,
cursorSmoothing = 2,
onCursorSmoothingChange,
zoomSmoothness = 1.0,
onZoomSmoothnessChange,
cursorMotionBlur = DEFAULT_CURSOR_MOTION_BLUR,
onCursorMotionBlurChange,
cursorClickBounce = 1,
@@ -1808,6 +1817,17 @@ export function SettingsPanel({
formatValue={(v) => (v <= 0 ? tSettings("effects.off") : v.toFixed(2))}
parseInput={(text) => parseFloat(text)}
/>
<SliderControl
label={tSettings("effects.zoomSmoothness", "Zoom Smoothness")}
value={zoomSmoothness}
defaultValue={1.0}
min={0}
max={2}
step={0.01}
onChange={(v) => onZoomSmoothnessChange?.(v)}
formatValue={(v) => (v <= 0 ? tSettings("effects.off") : v.toFixed(2))}
parseInput={(text) => parseFloat(text)}
/>
<SliderControl
label={tSettings("effects.cursorMotionBlur")}
value={cursorMotionBlur}
@@ -2074,6 +2094,39 @@ export function SettingsPanel({
)}
</div>
</div>
<div className="mb-3">
<div className="flex rounded-lg border border-white/10 bg-white/5 p-0.5">
<button
type="button"
onClick={() => onZoomModeChange?.('auto')}
className={cn(
"flex-1 rounded-md px-3 py-1.5 text-xs font-medium transition-all",
selectedZoomMode === 'auto'
? "bg-[#2563EB] text-white shadow-sm"
: "text-slate-400 hover:text-slate-200",
)}
>
Auto
</button>
<button
type="button"
onClick={() => onZoomModeChange?.('manual')}
className={cn(
"flex-1 rounded-md px-3 py-1.5 text-xs font-medium transition-all",
selectedZoomMode === 'manual'
? "bg-[#2563EB] text-white shadow-sm"
: "text-slate-400 hover:text-slate-200",
)}
>
Manual
</button>
</div>
<p className="mt-1.5 text-[10px] text-slate-500">
{selectedZoomMode === 'manual'
? "Set a fixed focus point for this zoom"
: "Camera follows cursor automatically"}
</p>
</div>
<div className="grid grid-cols-6 gap-1.5">
{ZOOM_DEPTH_OPTIONS.map((option) => {
const isActive = selectedZoomDepth === option.depth;