Fix Pr reviews
This commit is contained in:
@@ -166,7 +166,6 @@ const ZOOM_DEPTH_OPTIONS: Array<{ depth: ZoomDepth; label: string }> = [
|
||||
{ depth: 6, label: "5×" },
|
||||
];
|
||||
|
||||
// TODO: make this configurable
|
||||
const ZOOM_SPEED_OPTIONS = [
|
||||
{ label: "Instant", zoomIn: 0, zoomOut: 0 },
|
||||
{ label: "Fast", zoomIn: 500, zoomOut: 350 },
|
||||
@@ -570,8 +569,10 @@ export function SettingsPanel({
|
||||
<div className="grid grid-cols-4 gap-1.5">
|
||||
{ZOOM_SPEED_OPTIONS.map((opt) => {
|
||||
const isActive =
|
||||
selectedZoomInDuration === opt.zoomIn &&
|
||||
selectedZoomOutDuration === opt.zoomOut;
|
||||
selectedZoomInDuration !== undefined &&
|
||||
selectedZoomOutDuration !== undefined &&
|
||||
Math.round(selectedZoomInDuration) === Math.round(opt.zoomIn) &&
|
||||
Math.round(selectedZoomOutDuration) === Math.round(opt.zoomOut);
|
||||
return (
|
||||
<Button
|
||||
key={opt.label}
|
||||
@@ -924,7 +925,7 @@ export function SettingsPanel({
|
||||
</AccordionTrigger>
|
||||
<AccordionContent className="pb-3">
|
||||
<Tabs defaultValue="image" className="w-full">
|
||||
<TabsList className="mb-2 bg-white/5 border border-white/5 p-0.5 w-full grid grid-cols-3 rounded-lg">
|
||||
<TabsList className="mb-2 bg-white/5 border border-white/5 p-0.5 w-full grid grid-cols-3 rounded-lg">
|
||||
<TabsTrigger
|
||||
value="image"
|
||||
className="data-[state=active]:bg-[#34B27B] data-[state=active]:text-white text-slate-400 text-[10px] py-1 rounded-md transition-all"
|
||||
|
||||
@@ -1773,13 +1773,13 @@ export default function VideoEditor() {
|
||||
selectedZoomInDuration={
|
||||
selectedZoomId
|
||||
? (zoomRegions.find((z) => z.id === selectedZoomId)?.zoomInDurationMs ??
|
||||
ZOOM_IN_TRANSITION_WINDOW_MS)
|
||||
Math.round(ZOOM_IN_TRANSITION_WINDOW_MS))
|
||||
: undefined
|
||||
}
|
||||
selectedZoomOutDuration={
|
||||
selectedZoomId
|
||||
? (zoomRegions.find((z) => z.id === selectedZoomId)?.zoomOutDurationMs ??
|
||||
TRANSITION_WINDOW_MS)
|
||||
Math.round(TRANSITION_WINDOW_MS))
|
||||
: undefined
|
||||
}
|
||||
onZoomDurationChange={(zoomIn, zoomOut) =>
|
||||
|
||||
@@ -3,6 +3,11 @@ import { useItem, useTimelineContext } from "dnd-timeline";
|
||||
import { Gauge, MessageSquare, Scissors, ZoomIn } from "lucide-react";
|
||||
import { useMemo } from "react";
|
||||
import { cn } from "@/lib/utils";
|
||||
import {
|
||||
DEFAULT_ZOOM_IN_MS,
|
||||
DEFAULT_ZOOM_OUT_MS,
|
||||
getDurations,
|
||||
} from "../videoPlayback/zoomRegionUtils";
|
||||
import glassStyles from "./ItemGlass.module.css";
|
||||
|
||||
interface ItemProps {
|
||||
@@ -86,6 +91,16 @@ export default function Item({
|
||||
const MIN_ITEM_PX = 6;
|
||||
const safeItemStyle = { ...itemStyle, minWidth: MIN_ITEM_PX };
|
||||
|
||||
const { zoomIn, zoomOut } = useMemo(() => {
|
||||
if (!isZoom) return { zoomIn: 0, zoomOut: 0 };
|
||||
return getDurations({
|
||||
startMs: span.start,
|
||||
endMs: span.end,
|
||||
zoomInDurationMs,
|
||||
zoomOutDurationMs,
|
||||
});
|
||||
}, [isZoom, span.start, span.end, zoomInDurationMs, zoomOutDurationMs]);
|
||||
|
||||
return (
|
||||
<div
|
||||
ref={setNodeRef}
|
||||
@@ -114,14 +129,14 @@ export default function Item({
|
||||
<div
|
||||
className="absolute top-0 bottom-0 left-0 bg-white/10 border-r border-white/20 pointer-events-none"
|
||||
style={{
|
||||
width: `${((zoomInDurationMs ?? 1522.575) / (span.end - span.start)) * 100}%`,
|
||||
width: `${(zoomIn / (span.end - span.start)) * 100}%`,
|
||||
}}
|
||||
/>
|
||||
{/* Draggable handle for Transition In */}
|
||||
<div
|
||||
className="absolute top-0 bottom-0 w-2 cursor-col-resize z-20 group-hover:bg-white/5 transition-colors"
|
||||
style={{
|
||||
left: `${((zoomInDurationMs ?? 1522.575) / (span.end - span.start)) * 100}%`,
|
||||
left: `${(zoomIn / (span.end - span.start)) * 100}%`,
|
||||
transform: "translateX(-50%)",
|
||||
}}
|
||||
onPointerDown={(e) => {
|
||||
@@ -130,17 +145,18 @@ export default function Item({
|
||||
const target = e.currentTarget;
|
||||
target.setPointerCapture(e.pointerId);
|
||||
|
||||
const startX = e.clientX;
|
||||
const initialZoomIn = zoomInDurationMs ?? DEFAULT_ZOOM_IN_MS;
|
||||
const initialZoomOut = zoomOutDurationMs ?? DEFAULT_ZOOM_OUT_MS;
|
||||
|
||||
const onPointerMove = (moveEvent: PointerEvent) => {
|
||||
const deltaPx = moveEvent.clientX - e.clientX;
|
||||
const deltaPx = moveEvent.clientX - startX;
|
||||
const deltaMs = pixelsToValue(deltaPx);
|
||||
const newDuration = Math.max(
|
||||
0,
|
||||
Math.min(
|
||||
(zoomInDurationMs ?? 1522.575) + deltaMs,
|
||||
span.end - span.start - (zoomOutDurationMs ?? 1015.05),
|
||||
),
|
||||
Math.min(initialZoomIn + deltaMs, span.end - span.start - initialZoomOut),
|
||||
);
|
||||
onZoomDurationChange?.(id, newDuration, zoomOutDurationMs ?? 1015.05);
|
||||
onZoomDurationChange?.(id, newDuration, initialZoomOut);
|
||||
};
|
||||
|
||||
const onPointerUp = () => {
|
||||
@@ -157,14 +173,14 @@ export default function Item({
|
||||
<div
|
||||
className="absolute top-0 bottom-0 right-0 bg-white/10 border-l border-white/20 pointer-events-none"
|
||||
style={{
|
||||
width: `${((zoomOutDurationMs ?? 1015.05) / (span.end - span.start)) * 100}%`,
|
||||
width: `${(zoomOut / (span.end - span.start)) * 100}%`,
|
||||
}}
|
||||
/>
|
||||
{/* Draggable handle for Transition Out */}
|
||||
<div
|
||||
className="absolute top-0 bottom-0 w-2 cursor-col-resize z-20 group-hover:bg-white/5 transition-colors"
|
||||
style={{
|
||||
right: `${((zoomOutDurationMs ?? 1015.05) / (span.end - span.start)) * 100}%`,
|
||||
right: `${(zoomOut / (span.end - span.start)) * 100}%`,
|
||||
transform: "translateX(50%)",
|
||||
}}
|
||||
onPointerDown={(e) => {
|
||||
@@ -173,17 +189,18 @@ export default function Item({
|
||||
const target = e.currentTarget;
|
||||
target.setPointerCapture(e.pointerId);
|
||||
|
||||
const startX = e.clientX;
|
||||
const initialZoomIn = zoomInDurationMs ?? DEFAULT_ZOOM_IN_MS;
|
||||
const initialZoomOut = zoomOutDurationMs ?? DEFAULT_ZOOM_OUT_MS;
|
||||
|
||||
const onPointerMove = (moveEvent: PointerEvent) => {
|
||||
const deltaPx = e.clientX - moveEvent.clientX; // Inverted because right-anchored
|
||||
const deltaPx = startX - moveEvent.clientX; // Inverted because right-anchored
|
||||
const deltaMs = pixelsToValue(deltaPx);
|
||||
const newDuration = Math.max(
|
||||
0,
|
||||
Math.min(
|
||||
(zoomOutDurationMs ?? 1015.05) + deltaMs,
|
||||
span.end - span.start - (zoomInDurationMs ?? 1522.575),
|
||||
),
|
||||
Math.min(initialZoomOut + deltaMs, span.end - span.start - initialZoomIn),
|
||||
);
|
||||
onZoomDurationChange?.(id, zoomInDurationMs ?? 1522.575, newDuration);
|
||||
onZoomDurationChange?.(id, initialZoomIn, newDuration);
|
||||
};
|
||||
|
||||
const onPointerUp = () => {
|
||||
|
||||
@@ -37,10 +37,15 @@ function easeConnectedPan(value: number) {
|
||||
return cubicBezier(0.1, 0.0, 0.2, 1.0, value);
|
||||
}
|
||||
|
||||
const DEFAULT_ZOOM_OUT_MS = TRANSITION_WINDOW_MS;
|
||||
const DEFAULT_ZOOM_IN_MS = ZOOM_IN_TRANSITION_WINDOW_MS;
|
||||
export const DEFAULT_ZOOM_OUT_MS = TRANSITION_WINDOW_MS;
|
||||
export const DEFAULT_ZOOM_IN_MS = ZOOM_IN_TRANSITION_WINDOW_MS;
|
||||
|
||||
function getDurations(region: ZoomRegion) {
|
||||
export function getDurations(region: {
|
||||
startMs: number;
|
||||
endMs: number;
|
||||
zoomInDurationMs?: number;
|
||||
zoomOutDurationMs?: number;
|
||||
}) {
|
||||
let zoomIn = region.zoomInDurationMs ?? DEFAULT_ZOOM_IN_MS;
|
||||
let zoomOut = region.zoomOutDurationMs ?? DEFAULT_ZOOM_OUT_MS;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user