Skip to content

Commit fbd06fc

Browse files
Merge pull request #613 from auberginewly/feat/zoom-hold-preview
feat(zoom): hold-to-preview button for zoom focus editing (prototype for #612)
2 parents b6b37e3 + 85d0dea commit fbd06fc

14 files changed

Lines changed: 55 additions & 1 deletion

File tree

src/components/video-editor/SettingsPanel.tsx

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,8 @@ interface SettingsPanelProps {
238238
selectedZoomCustomScale?: number | null;
239239
onZoomCustomScaleChange?: (scale: number) => void;
240240
onZoomCustomScaleCommit?: () => void;
241+
onZoomPreviewStart?: () => void;
242+
onZoomPreviewEnd?: () => void;
241243
selectedZoomFocusMode?: ZoomFocusMode | null;
242244
onZoomFocusModeChange?: (mode: ZoomFocusMode) => void;
243245
selectedZoomFocus?: ZoomFocus | null;
@@ -367,6 +369,8 @@ export function SettingsPanel({
367369
selectedZoomCustomScale,
368370
onZoomCustomScaleChange,
369371
onZoomCustomScaleCommit,
372+
onZoomPreviewStart,
373+
onZoomPreviewEnd,
370374
selectedZoomFocusMode,
371375
onZoomFocusModeChange,
372376
selectedZoomFocus,
@@ -949,6 +953,31 @@ export function SettingsPanel({
949953
</div>
950954
</div>
951955
)}
956+
{zoomEnabled && onZoomPreviewStart && onZoomPreviewEnd && (
957+
<Button
958+
type="button"
959+
onPointerDown={() => onZoomPreviewStart()}
960+
onPointerUp={() => onZoomPreviewEnd()}
961+
onPointerLeave={() => onZoomPreviewEnd()}
962+
onPointerCancel={() => onZoomPreviewEnd()}
963+
onKeyDown={(e) => {
964+
if ((e.key === " " || e.key === "Enter") && !e.repeat) {
965+
e.preventDefault();
966+
onZoomPreviewStart();
967+
}
968+
}}
969+
onKeyUp={(e) => {
970+
if (e.key === " " || e.key === "Enter") {
971+
e.preventDefault();
972+
onZoomPreviewEnd();
973+
}
974+
}}
975+
onBlur={() => onZoomPreviewEnd()}
976+
className="h-7 w-full select-none rounded-md border border-white/[0.08] bg-white/[0.04] text-[10px] font-semibold text-slate-300 transition-all duration-150 ease-out hover:bg-white/[0.08] hover:text-slate-100 active:border-[#34B27B]/50 active:bg-[#34B27B] active:text-white cursor-pointer"
977+
>
978+
{t("zoom.previewHold")}
979+
</Button>
980+
)}
952981
{zoomEnabled &&
953982
selectedZoomFocusMode !== "auto" &&
954983
selectedZoomFocus &&

src/components/video-editor/VideoEditor.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,7 @@ export default function VideoEditor() {
195195
const durationRef = useRef(duration);
196196
durationRef.current = duration;
197197
const [selectedZoomId, setSelectedZoomId] = useState<string | null>(null);
198+
const [isPreviewingZoom, setIsPreviewingZoom] = useState(false);
198199
const [selectedTrimId, setSelectedTrimId] = useState<string | null>(null);
199200
const [selectedSpeedId, setSelectedSpeedId] = useState<string | null>(null);
200201
const [selectedAnnotationId, setSelectedAnnotationId] = useState<string | null>(null);
@@ -2120,6 +2121,7 @@ export default function VideoEditor() {
21202121
cursorMotionBlur={cursorMotionBlur}
21212122
cursorClickBounce={cursorClickBounce}
21222123
cursorClipToBounds={cursorClipToBounds}
2124+
isPreviewingZoom={isPreviewingZoom}
21232125
/>
21242126
</div>
21252127
</div>
@@ -2155,6 +2157,8 @@ export default function VideoEditor() {
21552157
}
21562158
onZoomCustomScaleChange={handleZoomCustomScaleChange}
21572159
onZoomCustomScaleCommit={handleZoomCustomScaleCommit}
2160+
onZoomPreviewStart={() => setIsPreviewingZoom(true)}
2161+
onZoomPreviewEnd={() => setIsPreviewingZoom(false)}
21582162
selectedZoomFocusMode={
21592163
selectedZoomId
21602164
? (zoomRegions.find((z) => z.id === selectedZoomId)?.focusMode ?? "manual")

src/components/video-editor/VideoPlayback.tsx

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,9 @@ interface VideoPlaybackProps {
150150
cursorMotionBlur?: number;
151151
cursorClickBounce?: number;
152152
cursorClipToBounds?: boolean;
153+
// When true, render the selected zoom at the playhead even while paused —
154+
// lets the editor preview the zoom effect without leaving the focus-edit view.
155+
isPreviewingZoom?: boolean;
153156
}
154157

155158
export interface VideoPlaybackRef {
@@ -271,6 +274,7 @@ const VideoPlayback = forwardRef<VideoPlaybackRef, VideoPlaybackProps>(
271274
cursorMotionBlur = DEFAULT_CURSOR_SETTINGS.motionBlur,
272275
cursorClickBounce = DEFAULT_CURSOR_SETTINGS.clickBounce,
273276
cursorClipToBounds = DEFAULT_CURSOR_SETTINGS.clipToBounds,
277+
isPreviewingZoom = false,
274278
},
275279
ref,
276280
) => {
@@ -342,6 +346,7 @@ const VideoPlayback = forwardRef<VideoPlaybackRef, VideoPlaybackProps>(
342346
const cursorMotionBlurRef = useRef(cursorMotionBlur);
343347
const cursorClickBounceRef = useRef(cursorClickBounce);
344348
const cursorClipToBoundsRef = useRef(cursorClipToBounds);
349+
const isPreviewingZoomRef = useRef(isPreviewingZoom);
345350
const motionBlurStateRef = useRef<MotionBlurState>(createMotionBlurState());
346351
const onTimeUpdateRef = useRef(onTimeUpdate);
347352
const onPlayStateChangeRef = useRef(onPlayStateChange);
@@ -833,6 +838,10 @@ const VideoPlayback = forwardRef<VideoPlaybackRef, VideoPlaybackProps>(
833838
cursorClipToBoundsRef.current = cursorClipToBounds;
834839
}, [cursorClipToBounds]);
835840

841+
useEffect(() => {
842+
isPreviewingZoomRef.current = isPreviewingZoom;
843+
}, [isPreviewingZoom]);
844+
836845
// Sync cursor overlay config when settings change
837846
useEffect(() => {
838847
const overlay = cursorOverlayRef.current;
@@ -1310,7 +1319,8 @@ const VideoPlayback = forwardRef<VideoPlaybackRef, VideoPlaybackProps>(
13101319
// If a zoom is selected but video is not playing, show default unzoomed view
13111320
const selectedId = selectedZoomIdRef.current;
13121321
const hasSelectedZoom = selectedId !== null;
1313-
const shouldShowUnzoomedView = hasSelectedZoom && !isPlayingRef.current;
1322+
const shouldShowUnzoomedView =
1323+
hasSelectedZoom && !isPlayingRef.current && !isPreviewingZoomRef.current;
13141324

13151325
if (region && strength > 0 && !shouldShowUnzoomedView) {
13161326
const zoomScale = blendedScale ?? ZOOM_DEPTH_SCALES[region.depth];

src/i18n/locales/ar/settings.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
{
22
"zoom": {
3+
"previewHold": "اضغط مع الاستمرار لمعاينة تأثير التكبير",
34
"level": "مستوى التكبير",
45
"selectRegion": "حدد منطقة التكبير للتعديل",
56
"deleteZoom": "حذف التكبير",

src/i18n/locales/en/settings.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
{
22
"zoom": {
3+
"previewHold": "Hold to preview zoom effect",
34
"level": "Zoom Level",
45
"customScale": "Custom Zoom",
56
"selectRegion": "Select a zoom region to adjust",

src/i18n/locales/es/settings.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
{
22
"zoom": {
3+
"previewHold": "Mantener para previsualizar el efecto de zoom",
34
"level": "Nivel de zoom",
45
"selectRegion": "Selecciona una región de zoom para ajustar",
56
"deleteZoom": "Eliminar zoom",

src/i18n/locales/fr/settings.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
{
22
"zoom": {
3+
"previewHold": "Maintenir pour prévisualiser l’effet de zoom",
34
"level": "Niveau de zoom",
45
"selectRegion": "Sélectionnez une région de zoom à ajuster",
56
"deleteZoom": "Supprimer le zoom",

src/i18n/locales/ja-JP/settings.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
{
22
"zoom": {
3+
"previewHold": "押している間ズーム効果をプレビュー",
34
"level": "ズーム倍率",
45
"selectRegion": "ズーム範囲を選択して調整",
56
"deleteZoom": "ズームを削除",

src/i18n/locales/ko-KR/settings.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
{
22
"zoom": {
3+
"previewHold": "누르고 있으면 줌 효과 미리보기",
34
"level": "줌 레벨",
45
"customScale": "커스텀 줌",
56
"selectRegion": "조정할 줌 구간을 선택하세요",

src/i18n/locales/ru/settings.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
{
22
"zoom": {
3+
"previewHold": "Удерживайте для предпросмотра эффекта зума",
34
"level": "Уровень масштабирования",
45
"selectRegion": "Выберите область масштабирования для настройки",
56
"deleteZoom": "Удалить масштабирование",

0 commit comments

Comments
 (0)