diff options
| author | cashmere <cashmere@autistici.org> | 2026-08-09 02:37:37 +0200 |
|---|---|---|
| committer | cashmere <cashmere@autistici.org> | 2026-08-09 02:37:37 +0200 |
| commit | c555f1eaebff90749bdc543592cfa80a060b29e2 (patch) | |
| tree | e6a04adb212871063653b66c17eb1b8c17c7d22f /apps/web/src/app/editor | |
| parent | df82306a86d14bca0149e6d756ba82b75659af43 (diff) | |
| download | opencut-c555f1eaebff90749bdc543592cfa80a060b29e2.tar.gz | |
feat: lens effects tab, standalone motion effects, clip/asset rename, preview popout
- New Lens category in the assets panel: Blur, Motion Blur, Zoom In/Out,
Pan x4, Shake, Pulse, Spin, Custom Zoom. EffectDefinition gains a
category field; tabs with an empty category are hidden, and the
properties-panel 'Open effects' button opens the first non-empty one.
- Motion effects work standalone: dropping them on the timeline creates
an effect-track element that animates (scale/translate/rotate) every
track below it, computed purely in the TS frame descriptor - no wasm
changes, identical in preview and export. supportsStandalone removed.
- Motion Blur: directional gaussian smear (amount + angle) reusing the
existing WGSL shader with arbitrary u_direction.
- Custom Zoom: start/end scale params (keyframable clip-level).
- MotionOffset gains optional rotate, accumulated clip-level and applied
to standalone layer quads via rotationDegrees.
- Rename clips (timeline context menu) and media assets (media panel
context menu) via a shared RenameDialog; asset rename persists through
storageService with rollback on error.
- Preview pops out into a Document Picture-in-Picture window and docks
back; button hidden where the API is unsupported.
- Export keeps running when the export popover is closed; only the
explicit Cancel button aborts.
- Captions and Adjustment tabs removed from the assets panel.
Diffstat (limited to 'apps/web/src/app/editor')
| -rw-r--r-- | apps/web/src/app/editor/page.tsx | 43 |
1 files changed, 37 insertions, 6 deletions
diff --git a/apps/web/src/app/editor/page.tsx b/apps/web/src/app/editor/page.tsx index 8229774a..5719be94 100644 --- a/apps/web/src/app/editor/page.tsx +++ b/apps/web/src/app/editor/page.tsx @@ -17,7 +17,8 @@ import { MigrationDialog } from "@/project/components/migration-dialog"; import { usePanelStore } from "@/editor/panel-store"; import { usePasteMedia } from "@/media/use-paste-media"; import { MobileGate } from "@/components/editor/mobile-gate"; -import { Suspense, useMemo, useState } from "react"; +import { Suspense, useEffect, useMemo, useState } from "react"; +import { createPortal } from "react-dom"; import { useEditor } from "@/editor/use-editor"; import { Cancel01Icon } from "@hugeicons/core-free-icons"; import { HugeiconsIcon } from "@hugeicons/react"; @@ -29,6 +30,7 @@ import { mergePreviewOverlaySources, } from "@/preview/overlays"; import { usePreviewStore } from "@/preview/preview-store"; +import { usePreviewPopoutStore } from "@/preview/popout-store"; import { getGuidePreviewOverlaySource } from "@/guides"; import { bookmarkNotesPreviewOverlay, @@ -98,6 +100,14 @@ function EditorLayout() { const setOverlayVisibility = usePreviewStore( (state) => state.setOverlayVisibility, ); + const popoutContainer = usePreviewPopoutStore((state) => state.container); + const dockPopout = usePreviewPopoutStore((state) => state.dockPopout); + + useEffect(() => { + return () => { + usePreviewPopoutStore.getState().dockPopout(); + }; + }, []); const showBookmarkNotes = isPreviewOverlayVisible({ overlay: bookmarkNotesPreviewOverlay, overlays, @@ -182,11 +192,32 @@ function EditorLayout() { minSize={30} className="min-h-0 min-w-0 flex-1" > - <PreviewPanel - overlayControls={overlayControls} - overlayInstances={overlaySource.instances} - onOverlayVisibilityChange={setOverlayVisibility} - /> + {popoutContainer ? ( + <> + {createPortal( + <PreviewPanel + overlayControls={overlayControls} + overlayInstances={overlaySource.instances} + onOverlayVisibilityChange={setOverlayVisibility} + />, + popoutContainer, + )} + <div className="flex size-full flex-col items-center justify-center gap-3"> + <span className="text-muted-foreground text-sm"> + Preview is popped out + </span> + <Button variant="secondary" onClick={dockPopout}> + Dock preview + </Button> + </div> + </> + ) : ( + <PreviewPanel + overlayControls={overlayControls} + overlayInstances={overlaySource.instances} + onOverlayVisibilityChange={setOverlayVisibility} + /> + )} </ResizablePanel> <ResizableHandle withHandle /> |
