From e36ec9317f32d8d180e6ec493ce58d1fbc17e540 Mon Sep 17 00:00:00 2001 From: FromTheLOLAshes Date: Wed, 27 Mar 2024 12:42:12 +0700 Subject: [PATCH 1/6] Refactor TrackContext, add drop of animation clip --- app/modules/LowerPanel/LowerPanel.tsx | 9 +- .../comps/SidePanelTabs/ClipElement.tsx | 39 ++++-- app/pages/PageEnigma/comps/Timeline/Audio.tsx | 3 +- .../PageEnigma/comps/Timeline/Camera.tsx | 1 + .../PageEnigma/comps/Timeline/Character.tsx | 3 + .../PageEnigma/comps/Timeline/Objects.tsx | 1 + app/pages/PageEnigma/comps/Timeline/Track.tsx | 24 +++- .../PageEnigma/comps/Timeline/TrackClip.tsx | 2 +- .../Timeline/utils/useMouseEventsAnimation.ts | 2 + .../Timeline/utils/useMouseEventsClip.ts | 2 +- .../contexts/TrackContext/TrackContext.tsx | 111 ++++++++++++++---- .../contexts/TrackContext/TrackProvider.tsx | 101 +++++++--------- .../TrackContext/utils/useUpdateAudio.ts | 37 +++++- .../TrackContext/utils/useUpdateCamera.ts | 19 ++- .../TrackContext/utils/useUpdateCharacters.ts | 106 ++++++++++++++--- .../TrackContext/utils/useUpdateDragDrop.ts | 38 ++++++ .../TrackContext/utils/useUpdateObject.ts | 18 ++- app/{ => pages/PageEnigma}/models/track.ts | 1 + 18 files changed, 401 insertions(+), 116 deletions(-) create mode 100644 app/pages/PageEnigma/contexts/TrackContext/utils/useUpdateDragDrop.ts rename app/{ => pages/PageEnigma}/models/track.ts (97%) diff --git a/app/modules/LowerPanel/LowerPanel.tsx b/app/modules/LowerPanel/LowerPanel.tsx index 680a097953..2fb21e12b1 100644 --- a/app/modules/LowerPanel/LowerPanel.tsx +++ b/app/modules/LowerPanel/LowerPanel.tsx @@ -1,4 +1,5 @@ -import { useState } from "react"; +import { useContext, useState } from "react"; +import { TrackContext } from "~/pages/PageEnigma/contexts/TrackContext/TrackContext"; interface LowerPanelPropsI { timelineHeight: number; @@ -7,6 +8,7 @@ interface LowerPanelPropsI { export const LowerPanel = ({ children, timelineHeight }: LowerPanelPropsI) => { const [open, setOpen] = useState(false); + const { setOverTimeline } = useContext(TrackContext); const handleOpen = () => { setOpen(true); }; @@ -20,6 +22,11 @@ export const LowerPanel = ({ children, timelineHeight }: LowerPanelPropsI) => { "bg-ui-panel", ].join(" ")} style={{ height: timelineHeight }} + onPointerOver={() => { + console.log("over"); + setOverTimeline(true); + }} + onPointerLeave={() => setOverTimeline(false)} > {children} diff --git a/app/pages/PageEnigma/comps/SidePanelTabs/ClipElement.tsx b/app/pages/PageEnigma/comps/SidePanelTabs/ClipElement.tsx index 747d64434d..c8f6e6fba5 100644 --- a/app/pages/PageEnigma/comps/SidePanelTabs/ClipElement.tsx +++ b/app/pages/PageEnigma/comps/SidePanelTabs/ClipElement.tsx @@ -1,5 +1,5 @@ import { useCallback, useContext, useEffect, useState } from "react"; -import { BaseClip } from "~/models/track"; +import { BaseClip } from "~/pages/PageEnigma/models/track"; import { TrackContext } from "~/pages/PageEnigma/contexts/TrackContext/TrackContext"; interface Props { @@ -8,8 +8,16 @@ interface Props { } export const ClipElement = ({ clip, type }: Props) => { - const { startDrag, dragId, endDrag, scale, canDrop, setCanDrop } = - useContext(TrackContext); + const { + startDrag, + dragId, + endDrag, + scale, + canDrop, + setCanDrop, + overTimeline, + dropId, + } = useContext(TrackContext); const [initPosition, setInitPosition] = useState<{ initX: number; initY: number; @@ -36,6 +44,8 @@ export const ClipElement = ({ clip, type }: Props) => { const onMouseMove = (event: MouseEvent) => { if (dragId) { + event.stopPropagation(); + event.preventDefault(); const deltaX = event.clientX - initX; const deltaY = event.clientY - initY; setCurrPosition({ x: deltaX, y: deltaY }); @@ -55,20 +65,24 @@ export const ClipElement = ({ clip, type }: Props) => { const onPointerDown = useCallback( (event: React.PointerEvent) => { if (event.button === 0) { + const box = document.getElementById(`ani-clip-${clip.id}`); + const position = box!.getBoundingClientRect(); + startDrag(type, clip.id); setCurrPosition({ - x: 0, - y: 0, + x: position.x, + y: position.y + position.height + 1, + }); + setInitPosition({ + initX: position.x, + initY: position.y + position.height + 1, }); - setInitPosition({ initY: event.clientY, initX: event.clientX }); setCanDrop(false); } }, [type, clip.id, startDrag, setCanDrop], ); - // console.log("clip", canDrop); - return (
{
diff --git a/app/pages/PageEnigma/comps/Timeline/Audio.tsx b/app/pages/PageEnigma/comps/Timeline/Audio.tsx index 2b7550edd6..e0ceaf066a 100644 --- a/app/pages/PageEnigma/comps/Timeline/Audio.tsx +++ b/app/pages/PageEnigma/comps/Timeline/Audio.tsx @@ -17,11 +17,12 @@ export const Audio = () => {
diff --git a/app/pages/PageEnigma/comps/Timeline/Camera.tsx b/app/pages/PageEnigma/comps/Timeline/Camera.tsx index 65f7fc59f9..ab0a4fb1bb 100644 --- a/app/pages/PageEnigma/comps/Timeline/Camera.tsx +++ b/app/pages/PageEnigma/comps/Timeline/Camera.tsx @@ -14,6 +14,7 @@ export const Camera = () => {
Camera
{
{ type="animations" /> { type="positions" /> { {objects.objects.map((object) => (
{ - const { length, setCanDrop, dragType } = useContext(TrackContext); + const { length, scale, setCanDrop, dragType, setDropId, setDropOffset } = + useContext(TrackContext); const trackType = type ?? style; function onPointerOver() { @@ -32,6 +35,19 @@ export const Track = ({ return; } setCanDrop(true); + setDropId(id); + } + + function onPointerMove(event: PointerEvent) { + if (dragType !== trackType) { + return; + } + const track = document.getElementById(`track-${trackType}-${id}`); + if (!track) { + return; + } + const position = track.getBoundingClientRect(); + setDropOffset((event.clientX - position.x) / 4 / scale); } function onPointerLeave() { if (dragType !== trackType) { @@ -43,9 +59,11 @@ export const Track = ({ return (
{clips.map((clip, index) => ( { const onMouseMove = (event: MouseEvent) => { const delta = (event.clientX - clientX) / 4 / scale + currentTime; if (isActive === "drag") { + event.stopPropagation(); + event.preventDefault(); if (delta < 0 || delta > max) { return; } diff --git a/app/pages/PageEnigma/comps/Timeline/utils/useMouseEventsClip.ts b/app/pages/PageEnigma/comps/Timeline/utils/useMouseEventsClip.ts index cad387f83b..b92f68bfb0 100644 --- a/app/pages/PageEnigma/comps/Timeline/utils/useMouseEventsClip.ts +++ b/app/pages/PageEnigma/comps/Timeline/utils/useMouseEventsClip.ts @@ -5,7 +5,7 @@ import React, { useEffect, useRef, } from "react"; -import { BaseClip } from "~/models/track"; +import { BaseClip } from "~/pages/PageEnigma/models/track"; import { TrackContext } from "~/pages/PageEnigma/contexts/TrackContext/TrackContext"; export const useMouseEventsClip = ( diff --git a/app/pages/PageEnigma/contexts/TrackContext/TrackContext.tsx b/app/pages/PageEnigma/contexts/TrackContext/TrackContext.tsx index aa744a0f7b..5ce6ff89c9 100644 --- a/app/pages/PageEnigma/contexts/TrackContext/TrackContext.tsx +++ b/app/pages/PageEnigma/contexts/TrackContext/TrackContext.tsx @@ -3,78 +3,143 @@ import { AnimationClip, AudioClip, AudioGroup, + BaseClip, CameraGroup, CharacterGroup, ObjectGroup, -} from "~/models/track"; +} from "~/pages/PageEnigma/models/track"; export const TrackContext = createContext<{ + // timeline characters and it's functions characters: CharacterGroup[]; - camera: CameraGroup | null; - audio: AudioGroup | null; - objects: ObjectGroup; - selectedClip: string | null; updateCharacters: (options: { type: "animations" | "positions" | "lipSync"; id: string; length: number; offset: number; }) => void; + toggleLipSyncMute: (characterId: string) => void; + addCharacterAnimation: (options: { + clipId: string; + characterId: string; + animationClips: BaseClip[]; + offset: number; + }) => void; + addCharacterAudio: (options: { + clipId: string; + characterId: string; + audioClips: BaseClip[]; + offset: number; + }) => void; + selectCharacterClip: (clipId: string) => void; + + // timeline camera group + camera: CameraGroup | null; updateCamera: (options: { id: string; length: number; offset: number; }) => void; + selectCameraClip: (clipId: string) => void; + + // timeline global audio group + audio: AudioGroup | null; updateAudio: (options: { id: string; length: number; offset: number; }) => void; + toggleAudioMute: () => void; + addGlobalAudio: (clipId: string, animationClips: BaseClip[]) => void; + selectAudioClip: (clipId: string) => void; + + // timeline objects group + objects: ObjectGroup; updateObject: (options: { id: string; length: number; offset: number; }) => void; + selectObjectClip: (clipId: string) => void; + + // current - only select one item - will be replaced + selectedClip: string | null; selectClip: (clipId: string) => void; - toggleLipSyncMute: (characterId: string) => void; - toggleAudioMute: () => void; + + // sidebar clips animationClips: AnimationClip[]; audioClips: AudioClip[]; + + // drag and drop dragType: "animations" | "lipSync" | null; dragId: string | null; startDrag: (type: "animations" | "lipSync", id: string) => void; endDrag: () => void; - scale: number; - currentTime: number; - length: number; - updateCurrentTime: (time: number) => void; canDrop: boolean; setCanDrop: (can: boolean) => void; + overTimeline: boolean; + setOverTimeline: (over: boolean) => void; + dropId: string; + setDropId: (id: string) => void; + dropOffset: number; + setDropOffset: (offset: number) => void; + + // scale of timeline displa + scale: number; + + // current time position + currentTime: number; + updateCurrentTime: (time: number) => void; + + // total length of the film clip + length: number; + + // computed width length * 60 * 4 * scale fullWidth: number; }>({ characters: [], - camera: null, - audio: null, - objects: { id: "", objects: [] }, - selectedClip: null, updateCharacters: () => {}, - updateCamera: () => {}, - updateAudio: () => {}, - updateObject: () => {}, - selectClip: () => {}, toggleLipSyncMute: () => {}, + addCharacterAnimation: () => {}, + addCharacterAudio: () => {}, + selectCharacterClip: () => {}, + + camera: null, + updateCamera: () => {}, + selectCameraClip: () => {}, + + audio: null, + updateAudio: () => {}, toggleAudioMute: () => {}, + selectAudioClip: () => {}, + addGlobalAudio: () => {}, + + objects: { id: "", objects: [] }, + updateObject: () => {}, + selectObjectClip: () => {}, + + selectedClip: null, + selectClip: () => {}, + animationClips: [], audioClips: [], + dragType: null, dragId: null, startDrag: () => {}, endDrag: () => {}, - scale: 1, - currentTime: 0, - length: 12, - updateCurrentTime: () => {}, + dropId: "", + setDropId: () => {}, canDrop: false, setCanDrop: () => {}, + overTimeline: false, + setOverTimeline: () => {}, + dropOffset: 0, + setDropOffset: () => {}, + + scale: 1, + currentTime: 0, + updateCurrentTime: () => {}, + length: 12, fullWidth: 0, }); diff --git a/app/pages/PageEnigma/contexts/TrackContext/TrackProvider.tsx b/app/pages/PageEnigma/contexts/TrackContext/TrackProvider.tsx index ecdcd15063..a6a9acadd7 100644 --- a/app/pages/PageEnigma/contexts/TrackContext/TrackProvider.tsx +++ b/app/pages/PageEnigma/contexts/TrackContext/TrackProvider.tsx @@ -4,50 +4,51 @@ import useUpdateCharacters from "~/pages/PageEnigma/contexts/TrackContext/utils/ import useUpdateCamera from "~/pages/PageEnigma/contexts/TrackContext/utils/useUpdateCamera"; import useUpdateAudio from "~/pages/PageEnigma/contexts/TrackContext/utils/useUpdateAudio"; import useUpdateObject from "~/pages/PageEnigma/contexts/TrackContext/utils/useUpdateObject"; -import { AnimationClip, AudioClip } from "~/models/track"; +import { AnimationClip, AudioClip } from "~/pages/PageEnigma/models/track"; +import useUpdateDragDrop from "~/pages/PageEnigma/contexts/TrackContext/utils/useUpdateDragDrop"; interface Props { children: ReactNode; } export const TrackProvider = ({ children }: Props) => { - const { characters, updateCharacters, toggleLipSyncMute } = - useUpdateCharacters(); - const { camera, updateCamera } = useUpdateCamera(); - const { audio, updateAudio, toggleAudioMute } = useUpdateAudio(); - const { objects, updateObject } = useUpdateObject(); - const [selectedClip, setSelectedClip] = useState(null); + const characters = useUpdateCharacters(); + const camera = useUpdateCamera(); + const audio = useUpdateAudio(); + const objects = useUpdateObject(); + const { endDrag, ...dragDrop } = useUpdateDragDrop(); + + const [selectedClip, setSelectedClip] = useState(null); const selectClip = useCallback((clipId: string | null) => { setSelectedClip(clipId); }, []); - const [state, setState] = useState<{ - dragType: "animations" | "lipSync" | null; - dragId: string | null; - }>({ dragType: null, dragId: null }); const [animationClips, setAnimationClips] = useState([]); const [audioClips, setAudioClips] = useState([]); - const startDrag = useCallback( - (type: "animations" | "lipSync", id: string) => { - setState({ dragId: id, dragType: type }); - }, - [], - ); - - const endDrag = useCallback(() => { - setState({ dragId: null, dragType: null }); - }, []); - + const [scale, setScale] = useState(1); + const [length, setLength] = useState(1); const [time, setTime] = useState(0); const updateCurrentTime = useCallback((newTime: number) => { setTime(newTime); }, []); - const [canDrop, setCanDrop] = useState(false); - const [scale, setScale] = useState(1); - const [length, setLength] = useState(1); + // cross group functions + const dropClip = useCallback(() => { + const { canDrop, dragType, dropId, dragId, dropOffset } = dragDrop; + if (canDrop) { + if (dragType === "animations") { + characters.addCharacterAnimation({ + clipId: dragId!, + characterId: dropId, + animationClips, + offset: dropOffset, + }); + } + } + endDrag(); + }, [dragDrop, animationClips, characters, endDrag]); const fullWidth = useMemo(() => { return length * 60 * 4 * scale; @@ -69,54 +70,42 @@ export const TrackProvider = ({ children }: Props) => { const values = useMemo(() => { return { - characters, - camera, - audio, - objects, - updateCharacters, - updateCamera, - updateAudio, - updateObject, + ...characters, + ...camera, + ...audio, + ...objects, + selectClip, selectedClip, - toggleLipSyncMute, - toggleAudioMute, - dragType: state.dragType, - dragId: state.dragId, + + ...dragDrop, + endDrag: dropClip, + animationClips, audioClips, - startDrag, - endDrag, + scale, currentTime: time, length, updateCurrentTime, - canDrop, - setCanDrop, fullWidth, }; }, [ characters, - updateCharacters, + camera, + audio, + objects, + selectClip, selectedClip, - camera, - updateCamera, - audio, - updateAudio, - objects, - updateObject, - toggleLipSyncMute, - toggleAudioMute, - state.dragId, - state.dragType, + + dragDrop, + dropClip, + animationClips, audioClips, - startDrag, - endDrag, - canDrop, + updateCurrentTime, - setCanDrop, time, fullWidth, length, diff --git a/app/pages/PageEnigma/contexts/TrackContext/utils/useUpdateAudio.ts b/app/pages/PageEnigma/contexts/TrackContext/utils/useUpdateAudio.ts index e366ba419a..8b7e95300b 100644 --- a/app/pages/PageEnigma/contexts/TrackContext/utils/useUpdateAudio.ts +++ b/app/pages/PageEnigma/contexts/TrackContext/utils/useUpdateAudio.ts @@ -1,5 +1,5 @@ import { useCallback, useState } from "react"; -import { AudioGroup } from "~/models/track"; +import { AudioGroup, BaseClip } from "~/pages/PageEnigma/models/track"; export default function useUpdateAudio() { const [audio, setAudio] = useState({ @@ -49,6 +49,23 @@ export default function useUpdateAudio() { [], ); + const addGlobalAudio = useCallback( + (dragId: string, audioClips: BaseClip[]) => { + const clip = audioClips.find((row) => row.id === dragId); + if (!clip) { + return; + } + + setAudio((oldAudio) => { + return { + ...oldAudio, + clips: [...oldAudio.clips, clip], + }; + }); + }, + [], + ); + const toggleAudioMute = useCallback(() => { setAudio((oldAudio) => { return { @@ -58,9 +75,27 @@ export default function useUpdateAudio() { }); }, []); + const selectAudioClip = useCallback((clipId: string) => { + setAudio((oldAudio) => { + return { + ...oldAudio, + clips: [ + ...oldAudio.clips.map((clip) => { + return { + ...clip, + selected: clip.id === clipId ? !clip.selected : clip.selected, + }; + }), + ], + }; + }); + }, []); + return { audio, updateAudio, toggleAudioMute, + selectAudioClip, + addGlobalAudio, }; } diff --git a/app/pages/PageEnigma/contexts/TrackContext/utils/useUpdateCamera.ts b/app/pages/PageEnigma/contexts/TrackContext/utils/useUpdateCamera.ts index f0d3f59c9f..b0a0912157 100644 --- a/app/pages/PageEnigma/contexts/TrackContext/utils/useUpdateCamera.ts +++ b/app/pages/PageEnigma/contexts/TrackContext/utils/useUpdateCamera.ts @@ -1,5 +1,5 @@ import { useCallback, useState } from "react"; -import { CameraGroup } from "~/models/track"; +import { CameraGroup } from "~/pages/PageEnigma/models/track"; export default function useUpdateCamera() { const [camera, setCamera] = useState({ @@ -48,8 +48,25 @@ export default function useUpdateCamera() { [], ); + const selectCameraClip = useCallback((clipId: string) => { + setCamera((oldCamera) => { + return { + ...oldCamera, + clips: [ + ...oldCamera.clips.map((clip) => { + return { + ...clip, + selected: clip.id === clipId ? !clip.selected : clip.selected, + }; + }), + ], + }; + }); + }, []); + return { camera, updateCamera, + selectCameraClip, }; } diff --git a/app/pages/PageEnigma/contexts/TrackContext/utils/useUpdateCharacters.ts b/app/pages/PageEnigma/contexts/TrackContext/utils/useUpdateCharacters.ts index 60f013df55..ddbbab21da 100644 --- a/app/pages/PageEnigma/contexts/TrackContext/utils/useUpdateCharacters.ts +++ b/app/pages/PageEnigma/contexts/TrackContext/utils/useUpdateCharacters.ts @@ -1,25 +1,12 @@ import { useCallback, useRef, useState } from "react"; -import { CharacterGroup } from "~/models/track"; +import { BaseClip, CharacterGroup } from "~/pages/PageEnigma/models/track"; export default function useUpdateCharacters() { const [characters, setCharacters] = useState([ { id: "CH1", muted: false, - animationClips: [ - { - id: "CH1-A1", - length: 200, - offset: 0, - name: "ani 1", - }, - { - id: "CH1-A2", - length: 180, - offset: 300, - name: "ani 2", - }, - ], + animationClips: [], positionClips: [ { id: "CH1-P1", @@ -120,6 +107,70 @@ export default function useUpdateCharacters() { [], ); + const addCharacterAnimation = useCallback( + ({ + clipId, + characterId, + animationClips, + offset, + }: { + clipId: string; + characterId: string; + animationClips: BaseClip[]; + offset: number; + }) => { + const clip = animationClips.find((row) => row.id === clipId); + if (!clip) { + return; + } + + setCharacters((oldCharacters) => { + return oldCharacters.map((character) => { + if (character.id !== characterId) { + return { ...character }; + } + return { + ...character, + animationClips: [...character.animationClips, { ...clip, offset }], + }; + }); + }); + }, + [], + ); + + const addCharacterAudio = useCallback( + ({ + clipId, + characterId, + audioClips, + offset, + }: { + clipId: string; + characterId: string; + audioClips: BaseClip[]; + offset: number; + }) => { + const clip = audioClips.find((row) => row.id === clipId); + if (!clip) { + return; + } + + setCharacters((oldCharacters) => { + return oldCharacters.map((character) => { + if (character.id !== characterId) { + return { ...character }; + } + return { + ...character, + lipSyncClips: [...character.lipSyncClips, { ...clip, offset }], + }; + }); + }); + }, + [], + ); + const toggleLipSyncMute = useCallback((characterId: string) => { setCharacters((oldCharacters) => { return oldCharacters.map((character) => ({ @@ -130,9 +181,34 @@ export default function useUpdateCharacters() { }); }, []); + const selectCharacterClip = useCallback((clipId: string) => { + setCharacters((oldCharacters) => { + return [ + ...oldCharacters.map((character) => ({ + ...character, + animationClips: character.animationClips.map((clip) => ({ + ...clip, + selected: clip.id === clipId ? !clip.selected : clip.selected, + })), + positionClips: character.positionClips.map((clip) => ({ + ...clip, + selected: clip.id === clipId ? !clip.selected : clip.selected, + })), + lipSyncClips: character.lipSyncClips.map((clip) => ({ + ...clip, + selected: clip.id === clipId ? !clip.selected : clip.selected, + })), + })), + ]; + }); + }, []); + return { characters, updateCharacters, toggleLipSyncMute, + addCharacterAnimation, + addCharacterAudio, + selectCharacterClip, }; } diff --git a/app/pages/PageEnigma/contexts/TrackContext/utils/useUpdateDragDrop.ts b/app/pages/PageEnigma/contexts/TrackContext/utils/useUpdateDragDrop.ts new file mode 100644 index 0000000000..35bf92ccb8 --- /dev/null +++ b/app/pages/PageEnigma/contexts/TrackContext/utils/useUpdateDragDrop.ts @@ -0,0 +1,38 @@ +import { useCallback, useState } from "react"; + +export default function useUpdateDragDrop() { + const [state, setState] = useState<{ + dragType: "animations" | "lipSync" | null; + dragId: string | null; + }>({ dragType: null, dragId: null }); + const startDrag = useCallback( + (type: "animations" | "lipSync", id: string) => { + setState({ dragId: id, dragType: type }); + }, + [], + ); + const [canDrop, setCanDrop] = useState(false); + const [overTimeline, setOverTimeline] = useState(false); + + const endDrag = useCallback(() => { + setState({ dragId: null, dragType: null }); + }, []); + + const [dropId, setDropId] = useState(""); + const [dropOffset, setDropOffset] = useState(0); + + return { + dragId: state.dragId, + dragType: state.dragType, + startDrag, + endDrag, + canDrop, + setCanDrop, + overTimeline, + setOverTimeline, + dropId, + setDropId, + dropOffset, + setDropOffset, + }; +} diff --git a/app/pages/PageEnigma/contexts/TrackContext/utils/useUpdateObject.ts b/app/pages/PageEnigma/contexts/TrackContext/utils/useUpdateObject.ts index 5fbad191e7..2866aa9faa 100644 --- a/app/pages/PageEnigma/contexts/TrackContext/utils/useUpdateObject.ts +++ b/app/pages/PageEnigma/contexts/TrackContext/utils/useUpdateObject.ts @@ -1,5 +1,5 @@ import { useCallback, useState } from "react"; -import { ObjectGroup } from "~/models/track"; +import { ObjectGroup } from "~/pages/PageEnigma/models/track"; export default function useUpdateObject() { const [objects, setObjects] = useState({ @@ -46,8 +46,24 @@ export default function useUpdateObject() { [], ); + const selectObjectClip = useCallback((clipId: string) => { + setObjects((oldObjectGroup) => { + return { + ...oldObjectGroup, + objects: oldObjectGroup.objects.map((object) => ({ + ...object, + clips: object.clips.map((clip) => ({ + ...clip, + selected: clip.id === clipId ? !clip.selected : clip.selected, + })), + })), + }; + }); + }, []); + return { objects, updateObject, + selectObjectClip, }; } diff --git a/app/models/track.ts b/app/pages/PageEnigma/models/track.ts similarity index 97% rename from app/models/track.ts rename to app/pages/PageEnigma/models/track.ts index 29d570891d..50c0723e17 100644 --- a/app/models/track.ts +++ b/app/pages/PageEnigma/models/track.ts @@ -3,6 +3,7 @@ export interface BaseClip { name: string; offset: number; length: number; + selected?: boolean; } export interface AnimationClip extends BaseClip {} From 985de175a515ec462ce14df197b8b902add2ade7 Mon Sep 17 00:00:00 2001 From: FromTheLOLAshes Date: Wed, 27 Mar 2024 14:17:42 +0700 Subject: [PATCH 2/6] Add delete clip with modal --- app/components/ConfirmationModal.tsx | 54 +++++++++++++++++ app/modules/LowerPanel/LowerPanel.tsx | 1 - .../PageEnigma/comps/Timeline/Timeline.tsx | 59 ++++++++++++++++++- .../contexts/TrackContext/TrackContext.tsx | 8 +++ .../TrackContext/utils/useUpdateAudio.ts | 10 ++++ .../TrackContext/utils/useUpdateCamera.ts | 10 ++++ .../TrackContext/utils/useUpdateCharacters.ts | 20 +++++++ .../TrackContext/utils/useUpdateObject.ts | 13 ++++ 8 files changed, 172 insertions(+), 3 deletions(-) create mode 100644 app/components/ConfirmationModal.tsx diff --git a/app/components/ConfirmationModal.tsx b/app/components/ConfirmationModal.tsx new file mode 100644 index 0000000000..0efd8fc2d8 --- /dev/null +++ b/app/components/ConfirmationModal.tsx @@ -0,0 +1,54 @@ +import { Dialog } from "@headlessui/react"; + +interface Props { + text: string; + title: string; + open: boolean; + onClose: () => void; + onOk?: () => void; + okText?: string; + okColor?: string; + onCancel?: () => void; + cancelText?: string; +} + +export const ConfirmationModal = ({ + text, + title, + open, + onClose, + onOk, + okText = "OK", + okColor = "bg-brand-success", + onCancel, + cancelText = "Cancel", +}: Props) => { + return ( + +
+
+ + {title} + +

{text}

+ +
+ {!!onCancel && ( + + )} + {!!onOk && ( + + )} +
+
+
+
+ ); +}; diff --git a/app/modules/LowerPanel/LowerPanel.tsx b/app/modules/LowerPanel/LowerPanel.tsx index 2fb21e12b1..ba6a4762d0 100644 --- a/app/modules/LowerPanel/LowerPanel.tsx +++ b/app/modules/LowerPanel/LowerPanel.tsx @@ -23,7 +23,6 @@ export const LowerPanel = ({ children, timelineHeight }: LowerPanelPropsI) => { ].join(" ")} style={{ height: timelineHeight }} onPointerOver={() => { - console.log("over"); setOverTimeline(true); }} onPointerLeave={() => setOverTimeline(false)} diff --git a/app/pages/PageEnigma/comps/Timeline/Timeline.tsx b/app/pages/PageEnigma/comps/Timeline/Timeline.tsx index c310970174..2ae8022803 100644 --- a/app/pages/PageEnigma/comps/Timeline/Timeline.tsx +++ b/app/pages/PageEnigma/comps/Timeline/Timeline.tsx @@ -1,4 +1,4 @@ -import { Fragment, useContext } from "react"; +import { Fragment, useCallback, useContext, useEffect, useState } from "react"; import { TrackContext } from "~/pages/PageEnigma/contexts/TrackContext/TrackContext"; import { LowerPanel } from "~/modules/LowerPanel"; import { Character } from "./Character"; @@ -9,19 +9,61 @@ import { Objects } from "./Objects"; import { useMouseEventsAnimation } from "./utils/useMouseEventsAnimation"; import { faSortDown } from "@fortawesome/pro-solid-svg-icons"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import { ConfirmationModal } from "~/components/ConfirmationModal"; interface Props { timelineHeight: number; } export const Timeline = ({ timelineHeight }: Props) => { - const { characters, objects, scale, length } = useContext(TrackContext); + const { + characters, + objects, + scale, + length, + selectedClip, + deleteCharacterClip, + deleteAudioClip, + deleteCameraClip, + deleteObjectClip, + } = useContext(TrackContext); const { onPointerDown, time } = useMouseEventsAnimation(); + const [dialogOpen, setDialogOpen] = useState(false); const sectionWidth = 60 * 4 * scale; const fullHeight = characters.length * 200 + objects.objects.length * 80 + 248 + 96; + const onDeleteAsk = useCallback( + (event: KeyboardEvent) => { + if (["Backspace", "Delete"].indexOf(event.key) > -1 && selectedClip) { + setDialogOpen(true); + } + }, + [selectedClip], + ); + + const onDelete = useCallback(() => { + deleteCharacterClip(selectedClip!); + deleteCameraClip(selectedClip!); + deleteAudioClip(selectedClip!); + deleteObjectClip(selectedClip!); + }, [ + selectedClip, + deleteAudioClip, + deleteCharacterClip, + deleteCameraClip, + deleteObjectClip, + ]); + + useEffect(() => { + document.addEventListener("keydown", onDeleteAsk); + + return () => { + document.addEventListener("keydown", onDeleteAsk); + }; + }, [onDeleteAsk]); + return ( <> @@ -102,6 +144,19 @@ export const Timeline = ({ timelineHeight }: Props) => { />
+ setDialogOpen(false)} + onOk={() => { + onDelete(); + setDialogOpen(false); + }} + okText="Delete" + okColor="bg-brand-primary" + onCancel={() => setDialogOpen(false)} + /> ); }; diff --git a/app/pages/PageEnigma/contexts/TrackContext/TrackContext.tsx b/app/pages/PageEnigma/contexts/TrackContext/TrackContext.tsx index 5ce6ff89c9..b9edb3d1e6 100644 --- a/app/pages/PageEnigma/contexts/TrackContext/TrackContext.tsx +++ b/app/pages/PageEnigma/contexts/TrackContext/TrackContext.tsx @@ -32,6 +32,7 @@ export const TrackContext = createContext<{ offset: number; }) => void; selectCharacterClip: (clipId: string) => void; + deleteCharacterClip: (clipId: string) => void; // timeline camera group camera: CameraGroup | null; @@ -41,6 +42,7 @@ export const TrackContext = createContext<{ offset: number; }) => void; selectCameraClip: (clipId: string) => void; + deleteCameraClip: (clipId: string) => void; // timeline global audio group audio: AudioGroup | null; @@ -52,6 +54,7 @@ export const TrackContext = createContext<{ toggleAudioMute: () => void; addGlobalAudio: (clipId: string, animationClips: BaseClip[]) => void; selectAudioClip: (clipId: string) => void; + deleteAudioClip: (clipId: string) => void; // timeline objects group objects: ObjectGroup; @@ -61,6 +64,7 @@ export const TrackContext = createContext<{ offset: number; }) => void; selectObjectClip: (clipId: string) => void; + deleteObjectClip: (clipId: string) => void; // current - only select one item - will be replaced selectedClip: string | null; @@ -103,20 +107,24 @@ export const TrackContext = createContext<{ addCharacterAnimation: () => {}, addCharacterAudio: () => {}, selectCharacterClip: () => {}, + deleteCharacterClip: () => {}, camera: null, updateCamera: () => {}, selectCameraClip: () => {}, + deleteCameraClip: () => {}, audio: null, updateAudio: () => {}, toggleAudioMute: () => {}, selectAudioClip: () => {}, addGlobalAudio: () => {}, + deleteAudioClip: () => {}, objects: { id: "", objects: [] }, updateObject: () => {}, selectObjectClip: () => {}, + deleteObjectClip: () => {}, selectedClip: null, selectClip: () => {}, diff --git a/app/pages/PageEnigma/contexts/TrackContext/utils/useUpdateAudio.ts b/app/pages/PageEnigma/contexts/TrackContext/utils/useUpdateAudio.ts index 8b7e95300b..8daab4f93c 100644 --- a/app/pages/PageEnigma/contexts/TrackContext/utils/useUpdateAudio.ts +++ b/app/pages/PageEnigma/contexts/TrackContext/utils/useUpdateAudio.ts @@ -91,11 +91,21 @@ export default function useUpdateAudio() { }); }, []); + const deleteAudioClip = useCallback((clipId: string) => { + setAudio((oldAudio) => { + return { + ...oldAudio, + clips: [...oldAudio.clips.filter((clip) => clip.id !== clipId)], + }; + }); + }, []); + return { audio, updateAudio, toggleAudioMute, selectAudioClip, addGlobalAudio, + deleteAudioClip, }; } diff --git a/app/pages/PageEnigma/contexts/TrackContext/utils/useUpdateCamera.ts b/app/pages/PageEnigma/contexts/TrackContext/utils/useUpdateCamera.ts index b0a0912157..b5b7d21da6 100644 --- a/app/pages/PageEnigma/contexts/TrackContext/utils/useUpdateCamera.ts +++ b/app/pages/PageEnigma/contexts/TrackContext/utils/useUpdateCamera.ts @@ -64,9 +64,19 @@ export default function useUpdateCamera() { }); }, []); + const deleteCameraClip = useCallback((clipId: string) => { + setCamera((oldCamera) => { + return { + ...oldCamera, + clips: [...oldCamera.clips.filter((clip) => clip.id !== clipId)], + }; + }); + }, []); + return { camera, updateCamera, selectCameraClip, + deleteCameraClip, }; } diff --git a/app/pages/PageEnigma/contexts/TrackContext/utils/useUpdateCharacters.ts b/app/pages/PageEnigma/contexts/TrackContext/utils/useUpdateCharacters.ts index ddbbab21da..88dc0ca4e5 100644 --- a/app/pages/PageEnigma/contexts/TrackContext/utils/useUpdateCharacters.ts +++ b/app/pages/PageEnigma/contexts/TrackContext/utils/useUpdateCharacters.ts @@ -203,6 +203,25 @@ export default function useUpdateCharacters() { }); }, []); + const deleteCharacterClip = useCallback((clipId: string) => { + setCharacters((oldCharacters) => { + return [ + ...oldCharacters.map((character) => ({ + ...character, + animationClips: character.animationClips.filter( + (clip) => clip.id !== clipId, + ), + positionClips: character.positionClips.filter( + (clip) => clip.id !== clipId, + ), + lipSyncClips: character.lipSyncClips.filter( + (clip) => clip.id !== clipId, + ), + })), + ]; + }); + }, []); + return { characters, updateCharacters, @@ -210,5 +229,6 @@ export default function useUpdateCharacters() { addCharacterAnimation, addCharacterAudio, selectCharacterClip, + deleteCharacterClip, }; } diff --git a/app/pages/PageEnigma/contexts/TrackContext/utils/useUpdateObject.ts b/app/pages/PageEnigma/contexts/TrackContext/utils/useUpdateObject.ts index 2866aa9faa..b23b738816 100644 --- a/app/pages/PageEnigma/contexts/TrackContext/utils/useUpdateObject.ts +++ b/app/pages/PageEnigma/contexts/TrackContext/utils/useUpdateObject.ts @@ -61,9 +61,22 @@ export default function useUpdateObject() { }); }, []); + const deleteObjectClip = useCallback((clipId: string) => { + setObjects((oldObjectGroup) => { + return { + ...oldObjectGroup, + objects: oldObjectGroup.objects.map((object) => ({ + ...object, + clips: object.clips.filter((clip) => clip.id !== clipId), + })), + }; + }); + }, []); + return { objects, updateObject, selectObjectClip, + deleteObjectClip, }; } From 16de02eb488630dd8fab71d881b0d58bada2ba67 Mon Sep 17 00:00:00 2001 From: FromTheLOLAshes Date: Wed, 27 Mar 2024 15:33:23 +0700 Subject: [PATCH 3/6] Remove button outline for clips --- app/pages/PageEnigma/comps/Timeline/TrackClip.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/pages/PageEnigma/comps/Timeline/TrackClip.tsx b/app/pages/PageEnigma/comps/Timeline/TrackClip.tsx index 92665f6af3..d99b8b5011 100644 --- a/app/pages/PageEnigma/comps/Timeline/TrackClip.tsx +++ b/app/pages/PageEnigma/comps/Timeline/TrackClip.tsx @@ -51,7 +51,7 @@ export const TrackClip = ({ clip, min, max, style, updateClip }: Props) => { "rounded-l-lg", "block h-full", clip.id === selectedClip - ? "border border-b-2 border-l-2 border-r-0 border-t-2 border-white" + ? "border border-b-2 border-l-2 border-r-0 border-t-2 border-white focus-visible:outline-0" : "", ].join(" ")} style={{ width: 15, left: offset * 4 * scale, cursor: "w-resize" }} @@ -63,7 +63,7 @@ export const TrackClip = ({ clip, min, max, style, updateClip }: Props) => { ...classes, "block h-full", clip.id === selectedClip - ? "border border-b-2 border-l-0 border-r-0 border-t-2 border-white" + ? "border border-b-2 border-l-0 border-r-0 border-t-2 border-white focus-visible:outline-0" : "", ].join(" ")} style={{ @@ -80,7 +80,7 @@ export const TrackClip = ({ clip, min, max, style, updateClip }: Props) => { "rounded-r-lg", "block h-full", clip.id === selectedClip - ? "border border-b-2 border-l-0 border-r-2 border-t-2 border-white" + ? "border border-b-2 border-l-0 border-r-2 border-t-2 border-white focus-visible:outline-0" : "", ].join(" ")} style={{ From 9b27408c670c98084258225d9479e3c0598664cf Mon Sep 17 00:00:00 2001 From: FromTheLOLAshes Date: Wed, 27 Mar 2024 21:04:21 +0700 Subject: [PATCH 4/6] Add click to move timer --- app/modules/LowerPanel/LowerPanel.tsx | 24 ++++++++++++++----- .../PageEnigma/comps/Timeline/Timeline.tsx | 7 ++++-- .../Timeline/utils/useMouseEventsAnimation.ts | 12 ++++++---- .../Timeline/utils/useMouseEventsClip.ts | 2 ++ 4 files changed, 32 insertions(+), 13 deletions(-) diff --git a/app/modules/LowerPanel/LowerPanel.tsx b/app/modules/LowerPanel/LowerPanel.tsx index ba6a4762d0..669cf4b086 100644 --- a/app/modules/LowerPanel/LowerPanel.tsx +++ b/app/modules/LowerPanel/LowerPanel.tsx @@ -1,4 +1,4 @@ -import { useContext, useState } from "react"; +import React, { useCallback, useContext } from "react"; import { TrackContext } from "~/pages/PageEnigma/contexts/TrackContext/TrackContext"; interface LowerPanelPropsI { @@ -7,11 +7,22 @@ interface LowerPanelPropsI { } export const LowerPanel = ({ children, timelineHeight }: LowerPanelPropsI) => { - const [open, setOpen] = useState(false); - const { setOverTimeline } = useContext(TrackContext); - const handleOpen = () => { - setOpen(true); - }; + // const [open, setOpen] = useState(false); + const { setOverTimeline, updateCurrentTime, scale } = + useContext(TrackContext); + + const onTimelineClick = useCallback( + (event: React.PointerEvent) => { + if (event.button === 0) { + updateCurrentTime((Math.round(event.clientX) - 92) / 4 / scale); + } + }, + [updateCurrentTime, scale], + ); + + // const handleOpen = () => { + // setOpen(true); + // }; return (
{ setOverTimeline(true); }} onPointerLeave={() => setOverTimeline(false)} + onPointerDown={onTimelineClick} > {children}
diff --git a/app/pages/PageEnigma/comps/Timeline/Timeline.tsx b/app/pages/PageEnigma/comps/Timeline/Timeline.tsx index 2ae8022803..2d9cef4408 100644 --- a/app/pages/PageEnigma/comps/Timeline/Timeline.tsx +++ b/app/pages/PageEnigma/comps/Timeline/Timeline.tsx @@ -22,6 +22,7 @@ export const Timeline = ({ timelineHeight }: Props) => { scale, length, selectedClip, + currentTime, deleteCharacterClip, deleteAudioClip, deleteCameraClip, @@ -32,7 +33,7 @@ export const Timeline = ({ timelineHeight }: Props) => { const sectionWidth = 60 * 4 * scale; const fullHeight = - characters.length * 200 + objects.objects.length * 80 + 248 + 96; + characters.length * 268 + objects.objects.length * 60 + 300 + 96; const onDeleteAsk = useCallback( (event: KeyboardEvent) => { @@ -43,6 +44,8 @@ export const Timeline = ({ timelineHeight }: Props) => { [selectedClip], ); + const displayTime = time === -1 ? currentTime : time; + const onDelete = useCallback(() => { deleteCharacterClip(selectedClip!); deleteCameraClip(selectedClip!); @@ -126,7 +129,7 @@ export const Timeline = ({ timelineHeight }: Props) => {
{ @@ -7,7 +7,7 @@ export const useMouseEventsAnimation = () => { const [isActive, setIsActive] = useState(""); const [clientX, setClientX] = useState(0); - const [time, setTime] = useState(currentTime); + const [time, setTime] = useState(-1); useEffect(() => { const max = length * 60 * 4 * scale; @@ -16,6 +16,7 @@ export const useMouseEventsAnimation = () => { if (isActive) { updateCurrentTime(Math.round(time)); setIsActive(""); + setTime(-1); } }; @@ -39,15 +40,16 @@ export const useMouseEventsAnimation = () => { window.removeEventListener("pointerup", onPointerUp); window.removeEventListener("pointermove", onMouseMove); }; - }, [clientX, isActive, length, updateCurrentTime, scale, time]); + }, [clientX, isActive, length, updateCurrentTime, scale, time, currentTime]); return { - onPointerDown: (event: React.PointerEvent) => { + onPointerDown: useCallback((event: React.PointerEvent) => { if (event.button === 0) { setClientX(event.clientX); setIsActive("drag"); + setTime(currentTime); } - }, + }, []), time, }; }; diff --git a/app/pages/PageEnigma/comps/Timeline/utils/useMouseEventsClip.ts b/app/pages/PageEnigma/comps/Timeline/utils/useMouseEventsClip.ts index b92f68bfb0..35c82d795d 100644 --- a/app/pages/PageEnigma/comps/Timeline/utils/useMouseEventsClip.ts +++ b/app/pages/PageEnigma/comps/Timeline/utils/useMouseEventsClip.ts @@ -89,6 +89,8 @@ export const useMouseEventsClip = ( type: string, ) => { if (event.button === 0) { + event.stopPropagation(); + event.preventDefault(); clientX.current = event.clientX; isActive.current = type; } From 63d623ba3b65268d564a838963b15113e9f84eec Mon Sep 17 00:00:00 2001 From: FromTheLOLAshes Date: Wed, 27 Mar 2024 21:25:22 +0700 Subject: [PATCH 5/6] Some updates --- app/components/ConfirmationModal.tsx | 15 +++++-- .../contexts/TrackContext/TrackContext.tsx | 6 ++- .../contexts/TrackContext/TrackProvider.tsx | 7 ++- .../TrackContext/utils/useUpdateAudio.ts | 22 +++++++++- .../TrackContext/utils/useUpdateCharacters.ts | 43 +++++++++++++------ 5 files changed, 71 insertions(+), 22 deletions(-) diff --git a/app/components/ConfirmationModal.tsx b/app/components/ConfirmationModal.tsx index 0efd8fc2d8..81b76722cd 100644 --- a/app/components/ConfirmationModal.tsx +++ b/app/components/ConfirmationModal.tsx @@ -1,4 +1,5 @@ import { Dialog } from "@headlessui/react"; +import { Button } from "~/components/Button"; interface Props { text: string; @@ -34,17 +35,23 @@ export const ConfirmationModal = ({
{!!onCancel && ( - + )} {!!onOk && ( - + )}
diff --git a/app/pages/PageEnigma/contexts/TrackContext/TrackContext.tsx b/app/pages/PageEnigma/contexts/TrackContext/TrackContext.tsx index b9edb3d1e6..9fddae7aa2 100644 --- a/app/pages/PageEnigma/contexts/TrackContext/TrackContext.tsx +++ b/app/pages/PageEnigma/contexts/TrackContext/TrackContext.tsx @@ -52,7 +52,11 @@ export const TrackContext = createContext<{ offset: number; }) => void; toggleAudioMute: () => void; - addGlobalAudio: (clipId: string, animationClips: BaseClip[]) => void; + addGlobalAudio: ( + clipId: string, + animationClips: BaseClip[], + offset: number, + ) => void; selectAudioClip: (clipId: string) => void; deleteAudioClip: (clipId: string) => void; diff --git a/app/pages/PageEnigma/contexts/TrackContext/TrackProvider.tsx b/app/pages/PageEnigma/contexts/TrackContext/TrackProvider.tsx index a6a9acadd7..4ef71835e5 100644 --- a/app/pages/PageEnigma/contexts/TrackContext/TrackProvider.tsx +++ b/app/pages/PageEnigma/contexts/TrackContext/TrackProvider.tsx @@ -32,6 +32,11 @@ export const TrackProvider = ({ children }: Props) => { const [time, setTime] = useState(0); const updateCurrentTime = useCallback((newTime: number) => { setTime(newTime); + console.log("message", { + action: "UpdateCurrentTime", + id: "", + data: { currentTime: newTime }, + }); }, []); // cross group functions @@ -86,8 +91,8 @@ export const TrackProvider = ({ children }: Props) => { scale, currentTime: time, - length, updateCurrentTime, + length, fullWidth, }; }, [ diff --git a/app/pages/PageEnigma/contexts/TrackContext/utils/useUpdateAudio.ts b/app/pages/PageEnigma/contexts/TrackContext/utils/useUpdateAudio.ts index 8daab4f93c..2052926c16 100644 --- a/app/pages/PageEnigma/contexts/TrackContext/utils/useUpdateAudio.ts +++ b/app/pages/PageEnigma/contexts/TrackContext/utils/useUpdateAudio.ts @@ -45,12 +45,17 @@ export default function useUpdateAudio() { clips: newClips, }; }); + console.log("message", { + action: "UpdateGlobalAudio", + id, + data: { offset, length }, + }); }, [], ); const addGlobalAudio = useCallback( - (dragId: string, audioClips: BaseClip[]) => { + (dragId: string, audioClips: BaseClip[], offset: number) => { const clip = audioClips.find((row) => row.id === dragId); if (!clip) { return; @@ -59,9 +64,14 @@ export default function useUpdateAudio() { setAudio((oldAudio) => { return { ...oldAudio, - clips: [...oldAudio.clips, clip], + clips: [...oldAudio.clips, { ...clip, offset }], }; }); + console.log("message", { + action: "UpdateGlobalAudio", + id: dragId, + data: { offset }, + }); }, [], ); @@ -73,6 +83,10 @@ export default function useUpdateAudio() { muted: !oldAudio.muted, }; }); + console.log("message", { + action: "ToggleGlobalAudioMute", + id: "", + }); }, []); const selectAudioClip = useCallback((clipId: string) => { @@ -98,6 +112,10 @@ export default function useUpdateAudio() { clips: [...oldAudio.clips.filter((clip) => clip.id !== clipId)], }; }); + console.log("message", { + action: "UpdateGlobalAudio", + id: clipId, + }); }, []); return { diff --git a/app/pages/PageEnigma/contexts/TrackContext/utils/useUpdateCharacters.ts b/app/pages/PageEnigma/contexts/TrackContext/utils/useUpdateCharacters.ts index 88dc0ca4e5..546e3664cc 100644 --- a/app/pages/PageEnigma/contexts/TrackContext/utils/useUpdateCharacters.ts +++ b/app/pages/PageEnigma/contexts/TrackContext/utils/useUpdateCharacters.ts @@ -7,20 +7,7 @@ export default function useUpdateCharacters() { id: "CH1", muted: false, animationClips: [], - positionClips: [ - { - id: "CH1-P1", - length: 200, - offset: 100, - name: "pos 1", - }, - { - id: "CH1-P2", - length: 180, - offset: 500, - name: "pos 2", - }, - ], + positionClips: [], lipSyncClips: [ { id: "CH1-L1", @@ -62,6 +49,11 @@ export default function useUpdateCharacters() { }; }); }); + console.log("message", { + action: "UpdateAnimation", + id, + data: { offset, length }, + }); return; } if (type === "positions") { @@ -102,6 +94,11 @@ export default function useUpdateCharacters() { }; }); }); + console.log("message", { + action: "UpdateLipSync", + id, + data: { offset, length }, + }); } }, [], @@ -135,6 +132,11 @@ export default function useUpdateCharacters() { }; }); }); + console.log("message", { + action: "AddAnimation", + id: clipId, + data: { offset }, + }); }, [], ); @@ -167,6 +169,11 @@ export default function useUpdateCharacters() { }; }); }); + console.log("message", { + action: "AddLipSync", + id: clipId, + data: { offset }, + }); }, [], ); @@ -179,6 +186,10 @@ export default function useUpdateCharacters() { character.id === characterId ? !character.muted : character.muted, })); }); + console.log("message", { + action: "ToggleLipSync", + id: characterId, + }); }, []); const selectCharacterClip = useCallback((clipId: string) => { @@ -220,6 +231,10 @@ export default function useUpdateCharacters() { })), ]; }); + console.log("message", { + action: "DeleteCharacterClip", + id: clipId, + }); }, []); return { From 3b59bafee444ab91329e32f6761cac8c169ff611 Mon Sep 17 00:00:00 2001 From: bflatastic Date: Wed, 27 Mar 2024 21:44:05 +0700 Subject: [PATCH 6/6] confirmation modal styling update --- app/components/ConfirmationModal.tsx | 92 ++++++++++++++++++---------- 1 file changed, 60 insertions(+), 32 deletions(-) diff --git a/app/components/ConfirmationModal.tsx b/app/components/ConfirmationModal.tsx index 81b76722cd..abcdd1040a 100644 --- a/app/components/ConfirmationModal.tsx +++ b/app/components/ConfirmationModal.tsx @@ -1,5 +1,6 @@ -import { Dialog } from "@headlessui/react"; +import { Dialog, Transition } from "@headlessui/react"; import { Button } from "~/components/Button"; +import { Fragment } from "react"; interface Props { text: string; @@ -25,37 +26,64 @@ export const ConfirmationModal = ({ cancelText = "Cancel", }: Props) => { return ( - -
-
- - {title} - -

{text}

- -
- {!!onCancel && ( - - )} - {!!onOk && ( - - )} -
-
-
-
+ {title} + + +
{text}
+ +
+ {!!onCancel && ( + + )} + {!!onOk && ( + + )} +
+ + +
+ + ); };