Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions src/components/video-editor/SettingsPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,8 @@ interface SettingsPanelProps {
selectedZoomCustomScale?: number | null;
onZoomCustomScaleChange?: (scale: number) => void;
onZoomCustomScaleCommit?: () => void;
onZoomPreviewStart?: () => void;
onZoomPreviewEnd?: () => void;
selectedZoomFocusMode?: ZoomFocusMode | null;
onZoomFocusModeChange?: (mode: ZoomFocusMode) => void;
selectedZoomFocus?: ZoomFocus | null;
Expand Down Expand Up @@ -367,6 +369,8 @@ export function SettingsPanel({
selectedZoomCustomScale,
onZoomCustomScaleChange,
onZoomCustomScaleCommit,
onZoomPreviewStart,
onZoomPreviewEnd,
selectedZoomFocusMode,
onZoomFocusModeChange,
selectedZoomFocus,
Expand Down Expand Up @@ -949,6 +953,31 @@ export function SettingsPanel({
</div>
</div>
)}
{zoomEnabled && onZoomPreviewStart && onZoomPreviewEnd && (
<Button
type="button"
onPointerDown={() => onZoomPreviewStart()}
onPointerUp={() => onZoomPreviewEnd()}
onPointerLeave={() => onZoomPreviewEnd()}
onPointerCancel={() => onZoomPreviewEnd()}
onKeyDown={(e) => {
if ((e.key === " " || e.key === "Enter") && !e.repeat) {
e.preventDefault();
onZoomPreviewStart();
}
}}
onKeyUp={(e) => {
if (e.key === " " || e.key === "Enter") {
e.preventDefault();
onZoomPreviewEnd();
}
}}
onBlur={() => onZoomPreviewEnd()}
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"
>
{t("zoom.previewHold")}
</Button>
)}
{zoomEnabled &&
selectedZoomFocusMode !== "auto" &&
selectedZoomFocus &&
Expand Down
4 changes: 4 additions & 0 deletions src/components/video-editor/VideoEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,7 @@ export default function VideoEditor() {
const durationRef = useRef(duration);
durationRef.current = duration;
const [selectedZoomId, setSelectedZoomId] = useState<string | null>(null);
const [isPreviewingZoom, setIsPreviewingZoom] = useState(false);
const [selectedTrimId, setSelectedTrimId] = useState<string | null>(null);
const [selectedSpeedId, setSelectedSpeedId] = useState<string | null>(null);
const [selectedAnnotationId, setSelectedAnnotationId] = useState<string | null>(null);
Expand Down Expand Up @@ -2120,6 +2121,7 @@ export default function VideoEditor() {
cursorMotionBlur={cursorMotionBlur}
cursorClickBounce={cursorClickBounce}
cursorClipToBounds={cursorClipToBounds}
isPreviewingZoom={isPreviewingZoom}
/>
</div>
</div>
Expand Down Expand Up @@ -2155,6 +2157,8 @@ export default function VideoEditor() {
}
onZoomCustomScaleChange={handleZoomCustomScaleChange}
onZoomCustomScaleCommit={handleZoomCustomScaleCommit}
onZoomPreviewStart={() => setIsPreviewingZoom(true)}
onZoomPreviewEnd={() => setIsPreviewingZoom(false)}
selectedZoomFocusMode={
selectedZoomId
? (zoomRegions.find((z) => z.id === selectedZoomId)?.focusMode ?? "manual")
Expand Down
12 changes: 11 additions & 1 deletion src/components/video-editor/VideoPlayback.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,9 @@ interface VideoPlaybackProps {
cursorMotionBlur?: number;
cursorClickBounce?: number;
cursorClipToBounds?: boolean;
// When true, render the selected zoom at the playhead even while paused —
// lets the editor preview the zoom effect without leaving the focus-edit view.
isPreviewingZoom?: boolean;
}

export interface VideoPlaybackRef {
Expand Down Expand Up @@ -271,6 +274,7 @@ const VideoPlayback = forwardRef<VideoPlaybackRef, VideoPlaybackProps>(
cursorMotionBlur = DEFAULT_CURSOR_SETTINGS.motionBlur,
cursorClickBounce = DEFAULT_CURSOR_SETTINGS.clickBounce,
cursorClipToBounds = DEFAULT_CURSOR_SETTINGS.clipToBounds,
isPreviewingZoom = false,
},
ref,
) => {
Expand Down Expand Up @@ -342,6 +346,7 @@ const VideoPlayback = forwardRef<VideoPlaybackRef, VideoPlaybackProps>(
const cursorMotionBlurRef = useRef(cursorMotionBlur);
const cursorClickBounceRef = useRef(cursorClickBounce);
const cursorClipToBoundsRef = useRef(cursorClipToBounds);
const isPreviewingZoomRef = useRef(isPreviewingZoom);
const motionBlurStateRef = useRef<MotionBlurState>(createMotionBlurState());
const onTimeUpdateRef = useRef(onTimeUpdate);
const onPlayStateChangeRef = useRef(onPlayStateChange);
Expand Down Expand Up @@ -833,6 +838,10 @@ const VideoPlayback = forwardRef<VideoPlaybackRef, VideoPlaybackProps>(
cursorClipToBoundsRef.current = cursorClipToBounds;
}, [cursorClipToBounds]);

useEffect(() => {
isPreviewingZoomRef.current = isPreviewingZoom;
}, [isPreviewingZoom]);

// Sync cursor overlay config when settings change
useEffect(() => {
const overlay = cursorOverlayRef.current;
Expand Down Expand Up @@ -1310,7 +1319,8 @@ const VideoPlayback = forwardRef<VideoPlaybackRef, VideoPlaybackProps>(
// If a zoom is selected but video is not playing, show default unzoomed view
const selectedId = selectedZoomIdRef.current;
const hasSelectedZoom = selectedId !== null;
const shouldShowUnzoomedView = hasSelectedZoom && !isPlayingRef.current;
const shouldShowUnzoomedView =
hasSelectedZoom && !isPlayingRef.current && !isPreviewingZoomRef.current;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preview the selected zoom, not the playhead region

When the playhead is not inside the selected zoom (for example, clicking a zoom item only selects it; TimelineEditor does not seek), holding Preview disables the unzoomed edit guard but still relies on findDominantRegion(... currentTime ...). In that scenario the button previews no zoom or a different zoom at the playhead, while the settings panel is editing the selected zoom's focus/depth, so users cannot verify the selected region unless they manually seek into it first.

Useful? React with 👍 / 👎.


if (region && strength > 0 && !shouldShowUnzoomedView) {
const zoomScale = blendedScale ?? ZOOM_DEPTH_SCALES[region.depth];
Expand Down
1 change: 1 addition & 0 deletions src/i18n/locales/ar/settings.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{
"zoom": {
"previewHold": "اضغط مع الاستمرار لمعاينة تأثير التكبير",
"level": "مستوى التكبير",
"selectRegion": "حدد منطقة التكبير للتعديل",
"deleteZoom": "حذف التكبير",
Expand Down
1 change: 1 addition & 0 deletions src/i18n/locales/en/settings.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{
"zoom": {
"previewHold": "Hold to preview zoom effect",
"level": "Zoom Level",
"customScale": "Custom Zoom",
"selectRegion": "Select a zoom region to adjust",
Expand Down
1 change: 1 addition & 0 deletions src/i18n/locales/es/settings.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{
"zoom": {
"previewHold": "Mantener para previsualizar el efecto de zoom",
"level": "Nivel de zoom",
"selectRegion": "Selecciona una región de zoom para ajustar",
"deleteZoom": "Eliminar zoom",
Expand Down
1 change: 1 addition & 0 deletions src/i18n/locales/fr/settings.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{
"zoom": {
"previewHold": "Maintenir pour prévisualiser l’effet de zoom",
"level": "Niveau de zoom",
"selectRegion": "Sélectionnez une région de zoom à ajuster",
"deleteZoom": "Supprimer le zoom",
Expand Down
1 change: 1 addition & 0 deletions src/i18n/locales/ja-JP/settings.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{
"zoom": {
"previewHold": "押している間ズーム効果をプレビュー",
"level": "ズーム倍率",
"selectRegion": "ズーム範囲を選択して調整",
"deleteZoom": "ズームを削除",
Expand Down
1 change: 1 addition & 0 deletions src/i18n/locales/ko-KR/settings.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{
"zoom": {
"previewHold": "누르고 있으면 줌 효과 미리보기",
"level": "줌 레벨",
"customScale": "커스텀 줌",
"selectRegion": "조정할 줌 구간을 선택하세요",
Expand Down
1 change: 1 addition & 0 deletions src/i18n/locales/ru/settings.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{
"zoom": {
"previewHold": "Удерживайте для предпросмотра эффекта зума",
"level": "Уровень масштабирования",
"selectRegion": "Выберите область масштабирования для настройки",
"deleteZoom": "Удалить масштабирование",
Expand Down
1 change: 1 addition & 0 deletions src/i18n/locales/tr/settings.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{
"zoom": {
"previewHold": "Yakınlaştırma efektini önizlemek için basılı tutun",
"level": "Yakınlaştırma Seviyesi",
"selectRegion": "Ayarlamak için bir yakınlaştırma bölgesi seçin",
"deleteZoom": "Yakınlaştırmayı Sil",
Expand Down
1 change: 1 addition & 0 deletions src/i18n/locales/vi/settings.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{
"zoom": {
"previewHold": "Giữ để xem trước hiệu ứng phóng to",
"level": "Mức độ thu phóng",
"selectRegion": "Chọn vùng thu phóng để điều chỉnh",
"deleteZoom": "Xóa thu phóng",
Expand Down
1 change: 1 addition & 0 deletions src/i18n/locales/zh-CN/settings.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{
"zoom": {
"previewHold": "按住预览放大效果",
"level": "缩放级别",
"selectRegion": "选择要调整的缩放区域",
"deleteZoom": "删除缩放",
Expand Down
1 change: 1 addition & 0 deletions src/i18n/locales/zh-TW/settings.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{
"zoom": {
"previewHold": "按住預覽放大效果",
"level": "縮放級別",
"selectRegion": "選擇要調整的縮放區域",
"deleteZoom": "刪除縮放",
Expand Down
Loading