From 68c472cfd21eebb8f52722724147f09f7e736b99 Mon Sep 17 00:00:00 2001 From: Christopher Oliphant Date: Tue, 16 Apr 2024 09:29:00 -0400 Subject: [PATCH] upgrade timeline to V3 --- app/components/ConfirmationModal.tsx | 41 +++-- app/modules/LowerPanel/LowerPanel.tsx | 50 ++---- app/pages/PageEnigma/PageEditor.tsx | 3 +- app/pages/PageEnigma/PageEnigmaComponent.tsx | 7 +- app/pages/PageEnigma/PageStyling.tsx | 53 ++---- .../comps/Controls3D/Controls3D.tsx | 16 +- app/pages/PageEnigma/comps/Timeline/Audio.tsx | 53 +++++- .../PageEnigma/comps/Timeline/Camera.tsx | 53 +++++- .../PageEnigma/comps/Timeline/Character.tsx | 53 +++++- .../comps/Timeline/ObjectGroups.tsx | 66 ++++++- .../PageEnigma/comps/Timeline/ObjectTrack.tsx | 20 +-- .../PageEnigma/comps/Timeline/RowHeaders.tsx | 163 ++++++++++++------ .../PageEnigma/comps/Timeline/Scrubber.tsx | 16 +- .../PageEnigma/comps/Timeline/Timeline.tsx | 58 ++++--- .../PageEnigma/comps/Timeline/TimerGrid.tsx | 24 +-- .../PageEnigma/comps/Timeline/TrackClip.tsx | 62 +++---- .../PageEnigma/comps/Timeline/TrackClips.tsx | 21 +-- .../comps/Timeline/TrackKeyFrame.tsx | 13 +- .../comps/Timeline/TrackKeyFrames.tsx | 27 ++- .../Timeline/utils/useMouseEventsClip.ts | 31 ++-- .../Timeline/utils/useMouseEventsKeyframe.ts | 31 ++-- .../Timeline/utils/useMouseEventsScrubber.ts | 16 +- .../Timeline/utils/useMouseEventsTimeline.ts | 4 +- .../comps/Timeline/utils/useTimelineClick.ts | 35 ++++ app/pages/PageEnigma/constants/misc.ts | 1 + app/pages/PageEnigma/constants/page.ts | 4 + app/pages/PageEnigma/models/track.ts | 1 + .../store/characterGroups/addCharacter.ts | 1 + .../store/characterGroups/characterGroup.ts | 16 ++ .../characterGroups/loadCharacterData.ts | 1 + app/pages/PageEnigma/store/sizing.ts | 43 ++++- app/pages/PageEnigma/store/timing.ts | 1 + 32 files changed, 646 insertions(+), 338 deletions(-) create mode 100644 app/pages/PageEnigma/comps/Timeline/utils/useTimelineClick.ts create mode 100644 app/pages/PageEnigma/constants/misc.ts create mode 100644 app/pages/PageEnigma/constants/page.ts diff --git a/app/components/ConfirmationModal.tsx b/app/components/ConfirmationModal.tsx index abcdd1040a..596acbe2fe 100644 --- a/app/components/ConfirmationModal.tsx +++ b/app/components/ConfirmationModal.tsx @@ -1,6 +1,7 @@ import { Dialog, Transition } from "@headlessui/react"; import { Button } from "~/components/Button"; -import { Fragment } from "react"; +import { Fragment, useCallback } from "react"; +import { DoNotShow } from "~/pages/PageEnigma/constants/misc"; interface Props { text: string; @@ -12,6 +13,7 @@ interface Props { okColor?: string; onCancel?: () => void; cancelText?: string; + canHide?: boolean; } export const ConfirmationModal = ({ @@ -24,7 +26,19 @@ export const ConfirmationModal = ({ okColor = "bg-brand-success", onCancel, cancelText = "Cancel", + canHide, }: Props) => { + const handleOk = useCallback(() => { + const element = document.getElementById("can-delete"); + if (element) { + if ((element as HTMLInputElement).checked) { + localStorage.setItem(title.replace(" ", "-"), DoNotShow); + } + } + + onOk!(); + }, [onOk, title]); + return ( @@ -35,8 +49,7 @@ export const ConfirmationModal = ({ enterTo="opacity-100" leave="ease-in duration-200" leaveFrom="opacity-100" - leaveTo="opacity-0" - > + leaveTo="opacity-0">
@@ -47,17 +60,23 @@ export const ConfirmationModal = ({ enterTo="opacity-100 scale-100" leave="ease-in duration-200" leaveFrom="opacity-100 scale-100" - leaveTo="opacity-0 scale-95" - > + leaveTo="opacity-0 scale-95"> + className="mb-4 text-xl font-bold text-white"> {title}
{text}
+ {canHide && ( +
+ +
+ )}
{!!onCancel && ( @@ -65,17 +84,15 @@ export const ConfirmationModal = ({ type="button" onClick={onCancel} className="rounded-lg px-3 py-2" - variant="secondary" - > + variant="secondary"> {cancelText} )} {!!onOk && ( )} diff --git a/app/modules/LowerPanel/LowerPanel.tsx b/app/modules/LowerPanel/LowerPanel.tsx index e2d37203de..d885e974f5 100644 --- a/app/modules/LowerPanel/LowerPanel.tsx +++ b/app/modules/LowerPanel/LowerPanel.tsx @@ -1,23 +1,18 @@ -import React, { useCallback } from "react"; +import React from "react"; import { useMouseEventsTimeline } from "~/pages/PageEnigma/comps/Timeline/utils/useMouseEventsTimeline"; import { - timelineScrollX, - currentTime, dndTimelineHeight, overTimeline, - scale, timelineHeight, } from "~/pages/PageEnigma/store"; -import Queue from "~/pages/PageEnigma/Queue/Queue"; -import { QueueNames } from "~/pages/PageEnigma/Queue/QueueNames"; -import { toEngineActions } from "~/pages/PageEnigma/Queue/toEngineActions"; +import useTimelineClick from "~/pages/PageEnigma/comps/Timeline/utils/useTimelineClick"; +import { Pages } from "~/pages/PageEnigma/constants/page"; interface LowerPanelPropsI { children: React.ReactNode; - onStyle?: boolean; } -export const LowerPanel = ({ children, onStyle }: LowerPanelPropsI) => { +export const LowerPanel = ({ children }: LowerPanelPropsI) => { const { onPointerDown } = useMouseEventsTimeline(); const displayHeight = @@ -25,44 +20,23 @@ export const LowerPanel = ({ children, onStyle }: LowerPanelPropsI) => { ? dndTimelineHeight.value : timelineHeight.value; - const onTimelineClick = useCallback( - (event: React.PointerEvent) => { - if (event.button === 0) { - const newTime = Math.round( - (event.clientX + timelineScrollX.value - 92) / 4 / scale.value, - ); - if (newTime < 0) { - return; - } - currentTime.value = newTime; - Queue.publish({ - queueName: QueueNames.TO_ENGINE, - action: toEngineActions.UPDATE_TIME, - data: { currentTime: Math.round(newTime) }, - }); - } - }, - [], - ); + const onTimelineClick = useTimelineClick(Pages.EDIT); return ( <> - {!onStyle && ( -
- )} +
{ overTimeline.value = true; }} onPointerLeave={() => (overTimeline.value = false)} - onPointerDown={onTimelineClick} - > + onClick={onTimelineClick}> {children}
diff --git a/app/pages/PageEnigma/PageEditor.tsx b/app/pages/PageEnigma/PageEditor.tsx index 7649661d77..de45827031 100644 --- a/app/pages/PageEnigma/PageEditor.tsx +++ b/app/pages/PageEnigma/PageEditor.tsx @@ -24,9 +24,10 @@ import { AppUiContext } from "~/contexts/AppUiContext"; import { pageHeight, pageWidth } from "~/store"; import { TopBar } from "~/modules/TopBar"; import { DialogueTTS } from "./comps/DialogueTTS/DialogueTTS"; +import { Pages } from "~/pages/PageEnigma/constants/page"; interface Props { - setPage: (page: string) => void; + setPage: (page: Pages) => void; } export const PageEditor = ({ setPage }: Props) => { diff --git a/app/pages/PageEnigma/PageEnigmaComponent.tsx b/app/pages/PageEnigma/PageEnigmaComponent.tsx index 3390a2219f..a106f7bc20 100644 --- a/app/pages/PageEnigma/PageEnigmaComponent.tsx +++ b/app/pages/PageEnigma/PageEnigmaComponent.tsx @@ -5,11 +5,12 @@ import { EngineContext } from "~/contexts/EngineContext"; import { PageEditor } from "~/pages/PageEnigma/PageEditor"; import { PageStyling } from "~/pages/PageEnigma/PageStyling"; import { useParams } from "@remix-run/react"; +import { Pages } from "~/pages/PageEnigma/constants/page"; export const PageEnigmaComponent = () => { const [, dispatchAppUiState] = useContext(AppUiContext); const editor = useContext(EngineContext); - const [page, setPage] = useState("edit"); + const [page, setPage] = useState(Pages.EDIT); const params = useParams(); useEffect(() => { @@ -27,10 +28,10 @@ export const PageEnigmaComponent = () => { return ( <> -
+
-
+
diff --git a/app/pages/PageEnigma/PageStyling.tsx b/app/pages/PageEnigma/PageStyling.tsx index 98098fdf92..ec506c56ed 100644 --- a/app/pages/PageEnigma/PageStyling.tsx +++ b/app/pages/PageEnigma/PageStyling.tsx @@ -11,23 +11,15 @@ import { TimerGrid } from "~/pages/PageEnigma/comps/Timeline/TimerGrid"; import { Scrubber } from "~/pages/PageEnigma/comps/Timeline/Scrubber"; import { PreviewImages } from "~/pages/PageEnigma/comps/PreviewImages"; import { TopBar } from "~/modules/TopBar"; -import React, { UIEvent, useCallback, useContext } from "react"; +import { UIEvent, useCallback, useContext } from "react"; import { EngineContext } from "~/contexts/EngineContext"; -import { - currentTime, - filmLength, - scale, - timelineHeight, - timelineScrollX, -} from "~/pages/PageEnigma/store"; -import Queue from "~/pages/PageEnigma/Queue/Queue"; -import { QueueNames } from "~/pages/PageEnigma/Queue/QueueNames"; -import { toEngineActions } from "~/pages/PageEnigma/Queue/toEngineActions"; +import { filmLength, scale, stylizeScrollX } from "~/pages/PageEnigma/store"; import { pageWidth } from "~/store"; -import { RowHeaders } from "~/pages/PageEnigma/comps/Timeline/RowHeaders"; +import useTimelineClick from "~/pages/PageEnigma/comps/Timeline/utils/useTimelineClick"; +import { Pages } from "~/pages/PageEnigma/constants/page"; interface Props { - setPage: (page: string) => void; + setPage: (page: Pages) => void; } export const PageStyling = ({ setPage }: Props) => { @@ -44,33 +36,14 @@ export const PageStyling = ({ setPage }: Props) => { const switchEdit = () => { editorEngine?.switchEdit(); - setPage("edit"); + setPage(Pages.EDIT); }; const onScroll = useCallback((event: UIEvent) => { - timelineScrollX.value = event.currentTarget.scrollLeft; + stylizeScrollX.value = event.currentTarget.scrollLeft; }, []); - const onTimelineClick = useCallback( - (event: React.PointerEvent) => { - if (event.button === 0) { - console.log("click", event.clientX, event.pageX, timelineScrollX.value); - const newTime = Math.round( - (event.clientX + timelineScrollX.value - 92) / 4 / scale.value, - ); - if (newTime < 0) { - return; - } - currentTime.value = newTime; - Queue.publish({ - queueName: QueueNames.TO_ENGINE, - action: toEngineActions.UPDATE_TIME, - data: { currentTime: newTime }, - }); - } - }, - [], - ); + const onTimelineClick = useTimelineClick(Pages.STYLE); return (
@@ -103,21 +76,21 @@ export const PageStyling = ({ setPage }: Props) => {
- +
-
+
- +
diff --git a/app/pages/PageEnigma/comps/Controls3D/Controls3D.tsx b/app/pages/PageEnigma/comps/Controls3D/Controls3D.tsx index f50677606e..a81e8be050 100644 --- a/app/pages/PageEnigma/comps/Controls3D/Controls3D.tsx +++ b/app/pages/PageEnigma/comps/Controls3D/Controls3D.tsx @@ -2,22 +2,16 @@ import { faAngleRight, faArrowsRotate, faArrowsUpDownLeftRight, - faCube, - faPlus, faUpRightAndDownLeftFromCenter, } from "@fortawesome/pro-solid-svg-icons"; -import { - fa3dCylinder, - fa3dTorus, - fa3dSphere, -} from "@awesome.me/kit-fde2be5eb0/icons/kit/custom"; -import { Button, ButtonIcon, ButtonIconSelect, Link } from "~/components"; -import { EngineContext } from "../../../../contexts/EngineContext"; +import { Button, ButtonIconSelect } from "~/components"; +import { EngineContext } from "~/contexts/EngineContext"; import { useContext } from "react"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import { Pages } from "~/pages/PageEnigma/constants/page"; interface Props { - setPage: (page: string) => void; + setPage: (page: Pages) => void; } export const Controls3D = ({ setPage }: Props) => { @@ -60,7 +54,7 @@ export const Controls3D = ({ setPage }: Props) => { const changeStylize = () => { editorEngine?.switchPreview(); - setPage("style"); + setPage(Pages.STYLE); }; const modes = [ diff --git a/app/pages/PageEnigma/comps/Timeline/Audio.tsx b/app/pages/PageEnigma/comps/Timeline/Audio.tsx index 094aa4fbb5..2014659b89 100644 --- a/app/pages/PageEnigma/comps/Timeline/Audio.tsx +++ b/app/pages/PageEnigma/comps/Timeline/Audio.tsx @@ -1,20 +1,61 @@ import { TrackClips } from "~/pages/PageEnigma/comps/Timeline/TrackClips"; -import { audioGroup, fullWidth, updateAudio } from "~/pages/PageEnigma/store"; +import { + audioGroup, + audioMinimized, + fullWidth, + minimizeIconPosition, + updateAudio, +} from "~/pages/PageEnigma/store"; import { ClipGroup } from "~/pages/PageEnigma/models"; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import { faAngleDown, faAngleUp } from "@fortawesome/pro-solid-svg-icons"; +import { useSignals } from "@preact/signals-react/runtime"; export const Audio = () => { + useSignals(); const { clips } = audioGroup.value; + if (audioMinimized.value) { + return ( +
+ +
+ ); + } + return (
-
+ className="relative block rounded-r-lg bg-global_audio-groupBg pb-5 pr-4" + style={{ width: fullWidth.value + 16 }}> + +
diff --git a/app/pages/PageEnigma/comps/Timeline/Camera.tsx b/app/pages/PageEnigma/comps/Timeline/Camera.tsx index 06a55ad090..1d0e018adf 100644 --- a/app/pages/PageEnigma/comps/Timeline/Camera.tsx +++ b/app/pages/PageEnigma/comps/Timeline/Camera.tsx @@ -1,22 +1,63 @@ -import { cameraGroup, fullWidth, updateCamera } from "~/pages/PageEnigma/store"; +import { + cameraGroup, + cameraMinimized, + fullWidth, + minimizeIconPosition, + updateCamera, +} from "~/pages/PageEnigma/store"; import { TrackKeyFrames } from "~/pages/PageEnigma/comps/Timeline/TrackKeyFrames"; import { useSignals } from "@preact/signals-react/runtime"; import { ClipGroup } from "~/pages/PageEnigma/models"; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import { faAngleDown, faAngleUp } from "@fortawesome/pro-solid-svg-icons"; export const Camera = () => { useSignals(); const { keyframes } = cameraGroup.value!; + if (cameraMinimized.value) { + return ( +
+ +
+ ); + } + return (
-
+ className="relative block rounded-r-lg bg-camera-groupBg pb-5 pr-4" + style={{ width: fullWidth.value + 16 }}> +
+ +
+
diff --git a/app/pages/PageEnigma/comps/Timeline/Character.tsx b/app/pages/PageEnigma/comps/Timeline/Character.tsx index 10c896e825..f593104d00 100644 --- a/app/pages/PageEnigma/comps/Timeline/Character.tsx +++ b/app/pages/PageEnigma/comps/Timeline/Character.tsx @@ -2,11 +2,16 @@ import { useCallback, useMemo } from "react"; import { TrackClips } from "~/pages/PageEnigma/comps/Timeline/TrackClips"; import { fullWidth, + minimizeIconPosition, + toggleCharacterMinimized, toggleLipSyncMute, updateCharacters, } from "~/pages/PageEnigma/store"; import { TrackKeyFrames } from "~/pages/PageEnigma/comps/Timeline/TrackKeyFrames"; import { CharacterTrack, ClipGroup, ClipType } from "~/pages/PageEnigma/models"; +import { useSignals } from "@preact/signals-react/runtime"; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import { faAngleDown, faAngleUp } from "@fortawesome/pro-solid-svg-icons"; function buildUpdaters( updateCharacters: (options: { @@ -43,18 +48,52 @@ export const Character = ({ character }: Props) => { const { updateClipLipSync, updateClipPosition, updateClipAnimations } = useMemo(() => buildUpdaters(updateCharacters), []); - const { animationClips, positionKeyframes, lipSyncClips } = character; + const { animationClips, positionKeyframes, lipSyncClips, minimized } = + character; + + if (minimized) { + return ( +
+ +
+ ); + } return (
-
+ className="relative block rounded-r-lg bg-character-groupBg pb-5 pr-4" + style={{ width: fullWidth.value + 16 }}> +
+ +
+
{ { useSignals(); + if (!objectGroup.value.objects.length) { + return null; + } + + if (objectsMinimized.value) { + return ( +
+ +
+ ); + } + return ( - <> - {objectGroup.value.objects.map((object) => ( -
- -
- ))} - +
+ +
+ {objectGroup.value.objects.map((object) => ( +
+ +
+ ))} +
+
); }; diff --git a/app/pages/PageEnigma/comps/Timeline/ObjectTrack.tsx b/app/pages/PageEnigma/comps/Timeline/ObjectTrack.tsx index da2806c9a9..ab4340f18a 100644 --- a/app/pages/PageEnigma/comps/Timeline/ObjectTrack.tsx +++ b/app/pages/PageEnigma/comps/Timeline/ObjectTrack.tsx @@ -8,19 +8,11 @@ interface Props { export const ObjectTrackComponent = ({ object }: Props) => { return ( -
-
- -
-
+ ); }; diff --git a/app/pages/PageEnigma/comps/Timeline/RowHeaders.tsx b/app/pages/PageEnigma/comps/Timeline/RowHeaders.tsx index 0d519e7c50..e833f0a17e 100644 --- a/app/pages/PageEnigma/comps/Timeline/RowHeaders.tsx +++ b/app/pages/PageEnigma/comps/Timeline/RowHeaders.tsx @@ -1,7 +1,10 @@ import { audioGroup, + audioMinimized, + cameraMinimized, characterGroup, objectGroup, + objectsMinimized, timelineScrollY, toggleAudioMute, toggleLipSyncMute, @@ -16,22 +19,89 @@ export const RowHeaders = () => { return (
- {characterGroup.value.characters.map((character) => ( -
-
-
- Character + className="absolute mt-2 w-[146px]" + style={{ top: timelineScrollY.value * -1 - 8 }}> + {characterGroup.value.characters.map((character) => { + if (character.minimized) { + return ( +
+
+ {character.name} +
-
+ ); + } + return ( +
+
+ {character.name} +
+
+ Animation +
+
+ Transition +
+
+
+ Lip Sync + +
+
+
+ ); + })} + + {cameraMinimized.value ? ( +
+
+ Camera +
+
+ ) : ( +
+
+ Camera +
+
+ Movement +
+
+ )} + + {audioMinimized.value ? ( +
+
+ Global Audio +
+
+ ) : ( +
+
+ Global Audio +
+
+
+ Track 1
- ))} -
-
-
- Camera -
-
-
-
-
-
- Global Audio -
-
- -
-
-
- {objectGroup.value.objects.map((obj) => ( -
-
-
- Object + )} + {objectGroup.value.objects.length > 0 && ( + <> + {objectsMinimized.value ? ( +
+
+ Objects +
-
-
- ))} + ) : ( +
+
+ Objects +
+ {objectGroup.value.objects.map((obj) => ( +
+ {obj.name} +
+ ))} +
+ )} + + )}
); diff --git a/app/pages/PageEnigma/comps/Timeline/Scrubber.tsx b/app/pages/PageEnigma/comps/Timeline/Scrubber.tsx index 0974be1b85..022d3c922b 100644 --- a/app/pages/PageEnigma/comps/Timeline/Scrubber.tsx +++ b/app/pages/PageEnigma/comps/Timeline/Scrubber.tsx @@ -1,20 +1,28 @@ import { - timelineScrollX, currentTime, fullHeight, scale, + stylizeScrollX, + timelineScrollX, } from "~/pages/PageEnigma/store"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { faSortDown } from "@fortawesome/pro-solid-svg-icons"; import { useMouseEventsScrubber } from "~/pages/PageEnigma/comps/Timeline/utils/useMouseEventsScrubber"; import { useSignals } from "@preact/signals-react/runtime"; +import { Pages } from "~/pages/PageEnigma/constants/page"; -export const Scrubber = () => { +interface Props { + page: Pages; +} + +export const Scrubber = ({ page }: Props) => { useSignals(); const { onPointerDown, time } = useMouseEventsScrubber(); const displayTime = time === -1 ? currentTime.value : time; + const scrollX = + page === Pages.EDIT ? timelineScrollX.value : stylizeScrollX.value; - if (displayTime * 4 * scale.value - timelineScrollX.value < 0) { + if (displayTime * 4 * scale.value - scrollX < 0) { return null; } @@ -23,7 +31,7 @@ export const Scrubber = () => { className="absolute flex cursor-ew-resize flex-col items-center text-brand-primary" style={{ top: 8, - left: displayTime * 4 * scale.value + 84 - timelineScrollX.value, + left: displayTime * 4 * scale.value + 225 - scrollX, }} onPointerDown={onPointerDown}>
diff --git a/app/pages/PageEnigma/comps/Timeline/Timeline.tsx b/app/pages/PageEnigma/comps/Timeline/Timeline.tsx index e02d895928..598a32e074 100644 --- a/app/pages/PageEnigma/comps/Timeline/Timeline.tsx +++ b/app/pages/PageEnigma/comps/Timeline/Timeline.tsx @@ -5,15 +5,15 @@ import { Camera } from "./Camera"; import { Audio } from "./Audio"; import { ConfirmationModal } from "~/components/ConfirmationModal"; import { - timelineHeight, deleteAudioClip, deleteCharacterClip, - selectedItem, + filmLength, ignoreDelete, + scale, + selectedItem, + timelineHeight, timelineScrollX, timelineScrollY, - filmLength, - scale, } from "~/pages/PageEnigma/store"; import { useQueueHandler } from "~/pages/PageEnigma/comps/Timeline/utils/useQueueHandler"; import { useSignals } from "@preact/signals-react/runtime"; @@ -25,6 +25,8 @@ import useUpdateKeyframe from "~/pages/PageEnigma/contexts/TrackContext/utils/us import { Clip, Keyframe } from "~/pages/PageEnigma/models"; import { RowHeaders } from "~/pages/PageEnigma/comps/Timeline/RowHeaders"; import { pageWidth } from "~/store"; +import { Pages } from "~/pages/PageEnigma/constants/page"; +import { DoNotShow } from "~/pages/PageEnigma/constants/misc"; function getItemType(item: Clip | Keyframe | null) { if (!item) { @@ -50,20 +52,6 @@ export const Timeline = () => { timelineHeight.value = window.outerHeight * 0.25; }, []); - const onDeleteAsk = useCallback((event: KeyboardEvent) => { - if (ignoreDelete.value) { - return; - } - if ( - ["Backspace", "Delete"].indexOf(event.key) > -1 && - selectedItem.value !== null - ) { - event.stopPropagation(); - event.preventDefault(); - setDialogOpen(true); - } - }, []); - const onDelete = useCallback(() => { if ((selectedItem.value as Clip).clip_uuid) { deleteCharacterClip(selectedItem.value as Clip); @@ -74,6 +62,28 @@ export const Timeline = () => { selectedItem.value = null; }, [deleteKeyframe]); + const onDeleteAsk = useCallback( + (event: KeyboardEvent) => { + if (ignoreDelete.value) { + return; + } + if ( + ["Backspace", "Delete"].indexOf(event.key) > -1 && + selectedItem.value !== null + ) { + event.stopPropagation(); + event.preventDefault(); + const show = localStorage.getItem("Delete-Clip"); + if (show === DoNotShow) { + onDelete(); + return; + } + setDialogOpen(true); + } + }, + [onDelete], + ); + useEffect(() => { document.addEventListener("keydown", onDeleteAsk); @@ -85,21 +95,20 @@ export const Timeline = () => { return ( <> - +
{
- +
{ okText="Delete" okColor="bg-brand-primary" onCancel={() => setDialogOpen(false)} + canHide /> ); diff --git a/app/pages/PageEnigma/comps/Timeline/TimerGrid.tsx b/app/pages/PageEnigma/comps/Timeline/TimerGrid.tsx index 350cca3d2d..c960fca49b 100644 --- a/app/pages/PageEnigma/comps/Timeline/TimerGrid.tsx +++ b/app/pages/PageEnigma/comps/Timeline/TimerGrid.tsx @@ -1,34 +1,39 @@ import { - timelineScrollX, filmLength, fullHeight, scale, + stylizeScrollX, + timelineScrollX, } from "~/pages/PageEnigma/store"; import { Fragment } from "react"; import { useSignals } from "@preact/signals-react/runtime"; +import { Pages } from "~/pages/PageEnigma/constants/page"; -export const TimerGrid = () => { +interface Props { + page: Pages; +} +export const TimerGrid = ({ page }: Props) => { useSignals(); const sectionWidth = 60 * 4 * scale.value; + const scrollX = + page === Pages.EDIT ? timelineScrollX.value : stylizeScrollX.value; return (
-
+ ].join(" ")}> +
{Array(filmLength.value) .fill(0) .map((_, index) => (
+ style={{ left: index * sectionWidth + 4 }}> 00:{index < 10 ? "0" + index.toString() : index.toString()}
{ ))}
+ style={{ left: filmLength.value * sectionWidth + 4 }}> 00: {filmLength.value < 10 ? "0" + filmLength.value.toString() diff --git a/app/pages/PageEnigma/comps/Timeline/TrackClip.tsx b/app/pages/PageEnigma/comps/Timeline/TrackClip.tsx index 207bb67ccd..251c74b9c8 100644 --- a/app/pages/PageEnigma/comps/Timeline/TrackClip.tsx +++ b/app/pages/PageEnigma/comps/Timeline/TrackClip.tsx @@ -31,46 +31,40 @@ export const TrackClip = ({ clip, min, max, group, updateClip }: Props) => { const classes = [ "absolute", clip.clip_uuid === selectedClipId - ? `bg-${group}-selected` + ? `bg-${group}-selected border-white focus-visible:outline-0` : `bg-${group}-clip`, ]; return ( <> -
- {clip.name} -
); }; diff --git a/app/pages/PageEnigma/comps/Timeline/TrackClips.tsx b/app/pages/PageEnigma/comps/Timeline/TrackClips.tsx index 771b152b17..b5c82bfdfa 100644 --- a/app/pages/PageEnigma/comps/Timeline/TrackClips.tsx +++ b/app/pages/PageEnigma/comps/Timeline/TrackClips.tsx @@ -1,6 +1,4 @@ import { TrackClip } from "~/pages/PageEnigma/comps/Timeline/TrackClip"; -import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; -import { faVolume, faVolumeSlash } from "@fortawesome/pro-solid-svg-icons"; import { AssetType, Clip, @@ -20,7 +18,7 @@ import { interface Props { id: string; clips: Clip[]; - title: string; + title?: string; group: ClipGroup; type?: ClipType; updateClip: (options: { id: string; length: number; offset: number }) => void; @@ -79,7 +77,9 @@ export const TrackClips = ({ // Now check if the clip fits const position = track.getBoundingClientRect(); - const clipOffset = (event.clientX - position.x) / 4 / scale.value; + const clipOffset = Math.round( + (event.clientX - position.x) / 4 / scale.value, + ); if (clipOffset + (dragItem.value!.length ?? 0) > filmLength.value * 60) { canDrop.value = false; @@ -112,11 +112,10 @@ export const TrackClips = ({ return (
+ onPointerMove={onPointerMove}> {clips.map((clip, index) => ( ))} -
- {title} -
+ {!!title && ( +
+ {title} +
+ )}
); }; diff --git a/app/pages/PageEnigma/comps/Timeline/TrackKeyFrame.tsx b/app/pages/PageEnigma/comps/Timeline/TrackKeyFrame.tsx index 7820709d62..30f70ead33 100644 --- a/app/pages/PageEnigma/comps/Timeline/TrackKeyFrame.tsx +++ b/app/pages/PageEnigma/comps/Timeline/TrackKeyFrame.tsx @@ -33,20 +33,21 @@ export const TrackKeyFrame = ({ keyframe, updateKeyframe }: Props) => { return (