From f3d7fe6ea5b52ca370063806f8cc4cc9a552ebbc Mon Sep 17 00:00:00 2001 From: FromTheLOLAshes Date: Mon, 25 Mar 2024 19:59:14 +0700 Subject: [PATCH] Fix a number of issues --- app/contexts/TrackContext.tsx | 20 --- app/contexts/TrackContext/TrackContext.tsx | 56 +++++++ app/contexts/TrackContext/TrackProvider.tsx | 62 ++++++++ .../TrackContext/utils/useUpdateAudio.ts | 66 +++++++++ .../TrackContext/utils/useUpdateCamera.ts | 55 +++++++ .../TrackContext/utils/useUpdateCharacters.ts | 138 ++++++++++++++++++ .../TrackContext/utils/useUpdateObject.ts | 53 +++++++ app/contexts/TrackProvider.tsx | 133 ----------------- app/models/track.ts | 28 +++- app/modules/LowerPanel/LowerPanel.tsx | 2 +- app/pages/PageEnigma/PageEnigma.tsx | 8 +- app/pages/PageEnigma/comps/Timeline/Audio.tsx | 45 ++++++ .../PageEnigma/comps/Timeline/Camera.tsx | 46 +++--- .../PageEnigma/comps/Timeline/Character.tsx | 110 +++++++++++--- .../PageEnigma/comps/Timeline/Objects.tsx | 50 +++++++ .../PageEnigma/comps/Timeline/Timeline.tsx | 126 ++++++++++------ .../PageEnigma/comps/Timeline/TrackClip.tsx | 91 +++++++----- .../comps/Timeline/utils/useMouseEvents.ts | 65 --------- .../Timeline/utils/useMouseEventsAnimation.ts | 52 +++++++ .../Timeline/utils/useMouseEventsClip.ts | 79 ++++++++++ tailwind.config.ts | 34 ++++- 21 files changed, 968 insertions(+), 351 deletions(-) delete mode 100644 app/contexts/TrackContext.tsx create mode 100644 app/contexts/TrackContext/TrackContext.tsx create mode 100644 app/contexts/TrackContext/TrackProvider.tsx create mode 100644 app/contexts/TrackContext/utils/useUpdateAudio.ts create mode 100644 app/contexts/TrackContext/utils/useUpdateCamera.ts create mode 100644 app/contexts/TrackContext/utils/useUpdateCharacters.ts create mode 100644 app/contexts/TrackContext/utils/useUpdateObject.ts delete mode 100644 app/contexts/TrackProvider.tsx create mode 100644 app/pages/PageEnigma/comps/Timeline/Audio.tsx create mode 100644 app/pages/PageEnigma/comps/Timeline/Objects.tsx delete mode 100644 app/pages/PageEnigma/comps/Timeline/utils/useMouseEvents.ts create mode 100644 app/pages/PageEnigma/comps/Timeline/utils/useMouseEventsAnimation.ts create mode 100644 app/pages/PageEnigma/comps/Timeline/utils/useMouseEventsClip.ts diff --git a/app/contexts/TrackContext.tsx b/app/contexts/TrackContext.tsx deleted file mode 100644 index d7172182bf..0000000000 --- a/app/contexts/TrackContext.tsx +++ /dev/null @@ -1,20 +0,0 @@ -import { createContext } from "react"; -import { CharacterTrack } from "~/models/track"; - -export const TrackContext = createContext<{ - characters: CharacterTrack[]; - updateCharacters: (options: { - type: "animations" | "positions" | "lipSync"; - id: string; - length: number; - offset: number; - }) => void; - selectClip: (options: { - type: "animations" | "positions" | "lipSync"; - id: string; - }) => void; -}>({ - characters: [], - updateCharacters: () => {}, - selectClip: () => {}, -}); diff --git a/app/contexts/TrackContext/TrackContext.tsx b/app/contexts/TrackContext/TrackContext.tsx new file mode 100644 index 0000000000..1ccddc1f0a --- /dev/null +++ b/app/contexts/TrackContext/TrackContext.tsx @@ -0,0 +1,56 @@ +import { createContext } from "react"; +import { + AudioGroup, + CameraGroup, + CharacterGroup, + ObjectGroup, +} from "~/models/track"; + +export const TrackContext = createContext<{ + characters: CharacterGroup[]; + camera: CameraGroup | null; + audio: AudioGroup | null; + objects: ObjectGroup; + selectedClip: string | null; + scale: number; + currentTime: number; + length: number; + updateCharacters: (options: { + type: "animations" | "positions" | "lipSync"; + id: string; + length: number; + offset: number; + }) => void; + updateCamera: (options: { + id: string; + length: number; + offset: number; + }) => void; + updateAudio: (options: { + id: string; + length: number; + offset: number; + }) => void; + updateObject: (options: { + id: string; + length: number; + offset: number; + }) => void; + selectClip: (clipId: string) => void; + updateCurrentTime: (time: number) => void; +}>({ + characters: [], + camera: null, + audio: null, + objects: { id: "", objects: [] }, + selectedClip: null, + scale: 1, + currentTime: 0, + length: 12, + updateCharacters: () => {}, + updateCamera: () => {}, + updateAudio: () => {}, + updateObject: () => {}, + selectClip: () => {}, + updateCurrentTime: () => {}, +}); diff --git a/app/contexts/TrackContext/TrackProvider.tsx b/app/contexts/TrackContext/TrackProvider.tsx new file mode 100644 index 0000000000..fc2eeb806c --- /dev/null +++ b/app/contexts/TrackContext/TrackProvider.tsx @@ -0,0 +1,62 @@ +import { TrackContext } from "~/contexts/TrackContext/TrackContext"; +import { ReactNode, useCallback, useMemo, useState } from "react"; +import useUpdateCharacters from "~/contexts/TrackContext/utils/useUpdateCharacters"; +import useUpdateCamera from "~/contexts/TrackContext/utils/useUpdateCamera"; +import useUpdateAudio from "~/contexts/TrackContext/utils/useUpdateAudio"; +import useUpdateObject from "~/contexts/TrackContext/utils/useUpdateObject"; + +interface Props { + children: ReactNode; +} + +export const TrackProvider = ({ children }: Props) => { + const { characters, updateCharacters } = useUpdateCharacters(); + const { camera, updateCamera } = useUpdateCamera(); + const { audio, updateAudio } = useUpdateAudio(); + const { objects, updateObject } = useUpdateObject(); + const [selectedClip, setSelectedClip] = useState(null); + const [time, setTime] = useState(0); + + const selectClip = useCallback((clipId: string | null) => { + setSelectedClip(clipId); + }, []); + + const updateCurrentTime = useCallback((newTime: number) => { + setTime(newTime); + }, []); + + const values = useMemo(() => { + return { + characters, + camera, + audio, + objects, + scale: 1, + currentTime: time, + length: 12, + updateCharacters, + updateCamera, + updateAudio, + updateObject, + selectClip, + selectedClip, + updateCurrentTime, + }; + }, [ + characters, + updateCharacters, + selectClip, + selectedClip, + camera, + updateCamera, + audio, + updateAudio, + objects, + updateObject, + time, + updateCurrentTime, + ]); + return ( + {children} + ); +}; diff --git a/app/contexts/TrackContext/utils/useUpdateAudio.ts b/app/contexts/TrackContext/utils/useUpdateAudio.ts new file mode 100644 index 0000000000..94363ec81b --- /dev/null +++ b/app/contexts/TrackContext/utils/useUpdateAudio.ts @@ -0,0 +1,66 @@ +import { useCallback, useState } from "react"; +import { AudioGroup } from "~/models/track"; + +export default function useUpdateAudio() { + const [audio, setAudio] = useState({ + id: "AU1", + muted: false, + clips: [ + { + id: "AU1-1", + length: 200, + offset: 0, + name: "audio 1", + }, + { + id: "AU1-2", + length: 180, + offset: 300, + name: "audio 2", + }, + ], + }); + + const updateAudio = useCallback( + ({ + id, + offset, + length, + }: { + id: string; + length: number; + offset: number; + }) => { + setAudio((oldAudio) => { + const newClips = [...oldAudio.clips]; + const clipIndex = newClips.findIndex((row) => row.id === id); + if (clipIndex === -1) { + return { ...oldAudio }; + } + const clip = newClips[clipIndex]; + clip.offset = offset; + clip.length = length; + return { + ...oldAudio, + clips: newClips, + }; + }); + }, + [], + ); + + const toggleAudioMute = useCallback(() => { + setAudio((oldAudio) => { + return { + ...oldAudio, + mute: !oldAudio, + }; + }); + }, []); + + return { + audio, + updateAudio, + toggleAudioMute, + }; +} diff --git a/app/contexts/TrackContext/utils/useUpdateCamera.ts b/app/contexts/TrackContext/utils/useUpdateCamera.ts new file mode 100644 index 0000000000..f0d3f59c9f --- /dev/null +++ b/app/contexts/TrackContext/utils/useUpdateCamera.ts @@ -0,0 +1,55 @@ +import { useCallback, useState } from "react"; +import { CameraGroup } from "~/models/track"; + +export default function useUpdateCamera() { + const [camera, setCamera] = useState({ + id: "CA1", + clips: [ + { + id: "CA1-1", + length: 200, + offset: 0, + name: "cam 1", + }, + { + id: "CA1-2", + length: 180, + offset: 300, + name: "cam 2", + }, + ], + }); + + const updateCamera = useCallback( + ({ + id, + offset, + length, + }: { + id: string; + length: number; + offset: number; + }) => { + setCamera((oldCamera) => { + const newClips = [...oldCamera.clips]; + const clipIndex = newClips.findIndex((row) => row.id === id); + if (clipIndex === -1) { + return { ...oldCamera }; + } + const clip = newClips[clipIndex]; + clip.offset = offset; + clip.length = length; + return { + ...oldCamera, + clips: newClips, + }; + }); + }, + [], + ); + + return { + camera, + updateCamera, + }; +} diff --git a/app/contexts/TrackContext/utils/useUpdateCharacters.ts b/app/contexts/TrackContext/utils/useUpdateCharacters.ts new file mode 100644 index 0000000000..8f72001303 --- /dev/null +++ b/app/contexts/TrackContext/utils/useUpdateCharacters.ts @@ -0,0 +1,138 @@ +import { useCallback, useState } from "react"; +import { CharacterGroup } from "~/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", + }, + ], + positionClips: [ + { + id: "CH1-P1", + length: 200, + offset: 100, + name: "pos 1", + }, + { + id: "CH1-P2", + length: 180, + offset: 500, + name: "pos 2", + }, + ], + lipSyncClips: [ + { + id: "CH1-L1", + length: 400, + offset: 150, + name: "sync 1", + }, + ], + }, + ]); + const updateCharacters = useCallback( + ({ + type, + id, + offset, + length, + }: { + type: "animations" | "positions" | "lipSync"; + id: string; + length: number; + offset: number; + }) => { + if (type === "animations") { + setCharacters((oldCharacters) => { + return oldCharacters.map((character) => { + const newAnimationClips = [...character.animationClips]; + const clipIndex = newAnimationClips.findIndex( + (row) => row.id === id, + ); + if (clipIndex === -1) { + return { ...character }; + } + const clip = newAnimationClips[clipIndex]; + clip.offset = offset; + clip.length = length; + return { + ...character, + animationClips: newAnimationClips, + }; + }); + }); + return; + } + if (type === "positions") { + setCharacters((oldCharacters) => { + return oldCharacters.map((character) => { + const newPositionClips = [...character.positionClips]; + const clipIndex = newPositionClips.findIndex( + (row) => row.id === id, + ); + if (clipIndex === -1) { + return { ...character }; + } + const clip = newPositionClips[clipIndex]; + clip.offset = offset; + clip.length = length; + return { + ...character, + positionClips: newPositionClips, + }; + }); + }); + return; + } + if (type === "lipSync") { + setCharacters((oldCharacters) => { + return oldCharacters.map((character) => { + const newLipSyncClips = [...character.lipSyncClips]; + const clipIndex = newLipSyncClips.findIndex((row) => row.id === id); + if (clipIndex === -1) { + return { ...character }; + } + const clip = newLipSyncClips[clipIndex]; + clip.offset = offset; + clip.length = length; + return { + ...character, + lipSyncClips: newLipSyncClips, + }; + }); + }); + } + }, + [], + ); + + const toggleAudioMute = useCallback((characterId: string) => { + setCharacters((oldCharacters) => { + return oldCharacters.map((character) => ({ + ...character, + muted: + character.id === characterId ? !character.muted : character.muted, + })); + }); + }, []); + + return { + characters, + updateCharacters, + toggleAudioMute, + }; +} diff --git a/app/contexts/TrackContext/utils/useUpdateObject.ts b/app/contexts/TrackContext/utils/useUpdateObject.ts new file mode 100644 index 0000000000..5fbad191e7 --- /dev/null +++ b/app/contexts/TrackContext/utils/useUpdateObject.ts @@ -0,0 +1,53 @@ +import { useCallback, useState } from "react"; +import { ObjectGroup } from "~/models/track"; + +export default function useUpdateObject() { + const [objects, setObjects] = useState({ + id: "OB1", + objects: [ + { + id: "OB1-O1", + clips: [ + { + id: "OB1-O1-1", + length: 200, + offset: 0, + name: "obj 1", + }, + ], + }, + ], + }); + + const updateObject = useCallback( + ({ + id, + offset, + length, + }: { + id: string; + length: number; + offset: number; + }) => { + setObjects((oldObject) => { + return { + id: oldObject.id, + objects: oldObject.objects.map((object) => ({ + id: object.id, + clips: object.clips.map((clip) => ({ + ...clip, + offset: clip.id === id ? offset : clip.offset, + length: clip.id === id ? length : clip.length, + })), + })), + }; + }); + }, + [], + ); + + return { + objects, + updateObject, + }; +} diff --git a/app/contexts/TrackProvider.tsx b/app/contexts/TrackProvider.tsx deleted file mode 100644 index b108fd3740..0000000000 --- a/app/contexts/TrackProvider.tsx +++ /dev/null @@ -1,133 +0,0 @@ -import { TrackContext } from "~/contexts/TrackContext"; -import { ReactNode, useCallback, useMemo, useState } from "react"; -import { CharacterTrack } from "~/models/track"; - -interface Props { - children: ReactNode; -} - -export const TrackProvider = ({ children }: Props) => { - const [characters, setCharacters] = useState([ - { - id: "t1", - animationClips: [ - { - id: "1", - length: 200, - offset: 0, - name: "track 1", - selected: false, - }, - { - id: "2", - length: 180, - offset: 300, - name: "track 2", - selected: false, - }, - ], - positionClips: [], - lipSyncClips: [], - }, - ]); - - const updateCharacters = useCallback( - ({ - type, - id, - offset, - length, - }: { - type: "animations" | "positions" | "lipSync"; - id: string; - length: number; - offset: number; - }) => { - if (type === "animations") { - setCharacters((oldCharacters) => { - return oldCharacters.map((character) => { - const newAnimationClips = [...character.animationClips]; - const clipIndex = newAnimationClips.findIndex( - (row) => row.id === id, - ); - if (clipIndex === -1) { - return { ...character }; - } - const clip = newAnimationClips[clipIndex]; - clip.offset = offset; - clip.length = length; - return { - ...character, - animationClips: newAnimationClips, - }; - }); - }); - return; - } - }, - [], - ); - - const selectClip = useCallback( - ({ - type, - id, - }: { - type: "animations" | "positions" | "lipSync"; - id: string; - }) => { - if (type === "animations") { - setCharacters((oldCharacters) => { - return oldCharacters.map((character) => { - const newAnimationClips = character.animationClips.map((clip) => ({ - ...clip, - selected: false, - })); - const newPositionClips = character.positionClips.map((clip) => ({ - ...clip, - selected: false, - })); - const newLipSyncClips = character.lipSyncClips.map((clip) => ({ - ...clip, - selected: false, - })); - const clipIndex = newAnimationClips.findIndex( - (row) => row.id === id, - ); - if (clipIndex === -1) { - return { - ...character, - animationClips: newAnimationClips, - positionClips: newPositionClips, - lipSyncClips: newLipSyncClips, - }; - } - const clip = newAnimationClips[clipIndex]; - clip.selected = true; - return { - ...character, - animationClips: newAnimationClips, - positionClips: newPositionClips, - lipSyncClips: newLipSyncClips, - }; - }); - }); - return; - } - }, - [], - ); - - console.log(characters); - - const values = useMemo(() => { - return { - characters, - updateCharacters, - selectClip, - }; - }, [characters, updateCharacters]); - return ( - {children} - ); -}; diff --git a/app/models/track.ts b/app/models/track.ts index a312aab70d..29d570891d 100644 --- a/app/models/track.ts +++ b/app/models/track.ts @@ -1,11 +1,8 @@ -import {Base} from "postcss-selector-parser"; - export interface BaseClip { id: string; name: string; offset: number; length: number; - selected: boolean; } export interface AnimationClip extends BaseClip {} @@ -14,16 +11,37 @@ export interface PositionClip extends BaseClip {} export interface LipSyncClip extends BaseClip {} -export interface CharacterTrack { +export interface CharacterGroup { id: string; + muted: boolean; animationClips: AnimationClip[]; positionClips: PositionClip[]; lipSyncClips: LipSyncClip[]; } -export interface CameraTrack { +export interface CameraGroup { id: string; clips: CameraClip[]; } export interface CameraClip extends BaseClip {} + +export interface AudioGroup { + id: string; + muted: boolean; + clips: AudioClip[]; +} + +export interface AudioClip extends BaseClip {} + +export interface ObjectGroup { + id: string; + objects: ObjectTrack[]; +} + +export interface ObjectTrack { + id: string; + clips: ObjectClip[]; +} + +export interface ObjectClip extends BaseClip {} diff --git a/app/modules/LowerPanel/LowerPanel.tsx b/app/modules/LowerPanel/LowerPanel.tsx index 0ac5d1dd7e..411a629518 100644 --- a/app/modules/LowerPanel/LowerPanel.tsx +++ b/app/modules/LowerPanel/LowerPanel.tsx @@ -14,7 +14,7 @@ export const LowerPanel = ({ children }: LowerPanelPropsI) => {
{ // const { setTopBarInner } = useContext(TopBarInnerContext) || {}; @@ -128,9 +128,9 @@ export const PageEnigma = () => {
{/* Timeline */} -
+
- +
diff --git a/app/pages/PageEnigma/comps/Timeline/Audio.tsx b/app/pages/PageEnigma/comps/Timeline/Audio.tsx new file mode 100644 index 0000000000..b02e5b5be2 --- /dev/null +++ b/app/pages/PageEnigma/comps/Timeline/Audio.tsx @@ -0,0 +1,45 @@ +import { TrackClip } from "./TrackClip"; +import { AudioGroup } from "~/models/track"; +import { useContext } from "react"; +import { TrackContext } from "~/contexts/TrackContext/TrackContext"; + +export const Audio = () => { + const { audio, updateAudio, length, scale } = useContext(TrackContext); + const fullWidth = length * 60 * 4 * scale; + const { clips } = audio!; + + return ( +
+
Global Audio
+
+
+
+ {clips.map((clip, index) => ( + 0 + ? clips[index - 1].offset + clips[index - 1].length + : 0 + } + max={index < clips.length - 1 ? clips[index + 1].offset : 1000} + style="audio" + updateClip={updateAudio} + clip={clip} + /> + ))} +
+ Global Audio Track +
+
+
+
+
+ ); +}; diff --git a/app/pages/PageEnigma/comps/Timeline/Camera.tsx b/app/pages/PageEnigma/comps/Timeline/Camera.tsx index 4ac7fbc41b..07074d3cfd 100644 --- a/app/pages/PageEnigma/comps/Timeline/Camera.tsx +++ b/app/pages/PageEnigma/comps/Timeline/Camera.tsx @@ -1,41 +1,41 @@ import { TrackClip } from "./TrackClip"; -import {CameraTrack, CharacterTrack} from "~/models/track"; +import { useContext } from "react"; +import { TrackContext } from "~/contexts/TrackContext/TrackContext"; -interface Props { - scale: number; - time: number; - camera: CameraTrack; - updateClip: (id: string, offset: number, length: number) => void; -} +export const Camera = () => { + const { camera, updateCamera, length, scale } = useContext(TrackContext); + const fullWidth = length * 60 * 4 * scale; + const { clips } = camera!; -export const Character = ({ - camera: { clips }, - updateClip, -}: Props) => { return ( -
-
Character
+
+
Camera
-
-
+
+
{clips.map((clip, index) => ( 0 - ? clips[index - 1].offset + - clips[index - 1].length + ? clips[index - 1].offset + clips[index - 1].length : 0 } - max={ - index < clips.length - 1 - ? clips[index + 1].offset - : 1000 - } - updateClip={updateClip} + max={index < clips.length - 1 ? clips[index + 1].offset : 1000} + style="camera" + updateClip={updateCamera} clip={clip} /> ))} +
+ Camera Position/Rotation +
diff --git a/app/pages/PageEnigma/comps/Timeline/Character.tsx b/app/pages/PageEnigma/comps/Timeline/Character.tsx index 9827a2743e..7fb717a189 100644 --- a/app/pages/PageEnigma/comps/Timeline/Character.tsx +++ b/app/pages/PageEnigma/comps/Timeline/Character.tsx @@ -1,23 +1,30 @@ import { TrackClip } from "./TrackClip"; -import { CharacterTrack } from "~/models/track"; +import { useContext } from "react"; +import { TrackContext } from "~/contexts/TrackContext/TrackContext"; interface Props { - scale: number; - time: number; - character: CharacterTrack; - updateClip: (id: string, offset: number, length: number) => void; + characterId: string; } -export const Character = ({ - character: { animationClips }, - updateClip, -}: Props) => { +export const Character = ({ characterId }: Props) => { + const { characters, updateCharacters, length, scale } = + useContext(TrackContext); + const fullWidth = length * 60 * 4 * scale; + const character = characters.find((row) => (row.id = characterId)); + if (!character) { + return false; + } + const { animationClips, positionClips, lipSyncClips } = character; + return ( -
-
Character
+
+
Character
-
-
+
+
{animationClips.map((clip, index) => ( + updateCharacters({ ...options, type: "animations" }) } - updateClip={updateClip} clip={clip} /> ))} +
+ Animation +
-
-
+
+
+ {positionClips.map((clip, index) => ( + 0 + ? animationClips[index - 1].offset + + animationClips[index - 1].length + : 0 + } + max={ + index < animationClips.length - 1 + ? animationClips[index + 1].offset + : length * 60 * 4 * scale + } + style="character" + updateClip={(options) => + updateCharacters({ ...options, type: "positions" }) + } + clip={clip} + /> + ))} +
+ Character Position/Rotation +
+
-
-
+
+
+ {lipSyncClips.map((clip, index) => ( + 0 + ? animationClips[index - 1].offset + + animationClips[index - 1].length + : 0 + } + max={ + index < animationClips.length - 1 + ? animationClips[index + 1].offset + : length * 60 * 4 * scale + } + style="character" + updateClip={(options) => + updateCharacters({ ...options, type: "lipSync" }) + } + clip={clip} + /> + ))} +
+ Lipsync Audio Track +
+
diff --git a/app/pages/PageEnigma/comps/Timeline/Objects.tsx b/app/pages/PageEnigma/comps/Timeline/Objects.tsx new file mode 100644 index 0000000000..31c52ec9fd --- /dev/null +++ b/app/pages/PageEnigma/comps/Timeline/Objects.tsx @@ -0,0 +1,50 @@ +import { TrackClip } from "./TrackClip"; +import { useContext } from "react"; +import { TrackContext } from "~/contexts/TrackContext/TrackContext"; + +export const Objects = () => { + const { objects, updateObject, length, scale } = useContext(TrackContext); + const fullWidth = length * 60 * 4 * scale; + + return ( +
+
Objects
+ {objects.objects.map((object) => ( +
+
+
+ {object.clips.map((clip, index) => ( + 0 + ? object.clips[index - 1].offset + + object.clips[index - 1].length + : 0 + } + max={ + index < object.clips.length - 1 + ? object.clips[index + 1].offset + : 0 + } + style="objects" + updateClip={updateObject} + clip={clip} + /> + ))} +
+ Mask Position/Rotation +
+
+
+
+ ))} +
+ ); +}; diff --git a/app/pages/PageEnigma/comps/Timeline/Timeline.tsx b/app/pages/PageEnigma/comps/Timeline/Timeline.tsx index 73ee72e905..c64bf43010 100644 --- a/app/pages/PageEnigma/comps/Timeline/Timeline.tsx +++ b/app/pages/PageEnigma/comps/Timeline/Timeline.tsx @@ -1,18 +1,21 @@ import { LowerPanel } from "~/modules/LowerPanel"; import Editor from "../../js/editor"; import { Character } from "./Character"; -import { useCallback, useContext } from "react"; -import { TrackContext } from "~/contexts/TrackContext"; +import { Fragment, useContext } from "react"; +import { TrackContext } from "~/contexts/TrackContext/TrackContext"; import { Button } from "~/components"; +import { Camera } from "./Camera"; +import { Audio } from "./Audio"; +import { Objects } from "./Objects"; +import { useMouseEventsAnimation } from "./utils/useMouseEventsAnimation"; export const Timeline = ({ editorCurrent, - time, }: { editorCurrent: Editor | null; - time: number; }) => { - const { characters, updateCharacters } = useContext(TrackContext); + const { characters, objects, scale, length } = useContext(TrackContext); + const { onPointerDown, time } = useMouseEventsAnimation(); const handleButtonLoad = () => { document.getElementById("load-upload")?.click(); @@ -22,59 +25,88 @@ export const Timeline = ({ }; const handleButtonPlay = () => {}; - const updateClip = useCallback( - (id: string, offset: number, length: number) => { - updateCharacters({ type: "animations", id, offset, length }); - }, - [], - ); + const sectionWidth = 60 * 4 * scale; + const fullHeight = + characters.length * 200 + objects.objects.length * 80 + 248 + 96; - // const width = (window.innerWidth - 40) / 10 - 2; - const width = 1500; return ( - + <>
-
- -
-
-
0
-
1
-
2
-
3
-
4
-
5
-
6
-
7
-
8
-
9
-
10
+ +
+ {Array(length) + .fill(0) + .map((_, index) => ( + +
+ 00:{index < 10 ? "0" + index.toString() : index.toString()} +
+
+ + ))} +
+ 00:{length < 10 ? "0" + length.toString() : length.toString()} +
+
-
+
{characters.map((character) => ( - + ))}
+
+ +
+
+
+
+ +
-
- + className="absolute" + style={{ top: 8, left: time * 4 * scale + 88 }} + onPointerDown={onPointerDown} + > + +
+
+ + ); }; diff --git a/app/pages/PageEnigma/comps/Timeline/TrackClip.tsx b/app/pages/PageEnigma/comps/Timeline/TrackClip.tsx index d8c632c6a2..ee4415aeda 100644 --- a/app/pages/PageEnigma/comps/Timeline/TrackClip.tsx +++ b/app/pages/PageEnigma/comps/Timeline/TrackClip.tsx @@ -1,61 +1,86 @@ -import { useMouseEvents } from "./utils/useMouseEvents"; +import { useMouseEventsClip } from "./utils/useMouseEventsClip"; import { BaseClip } from "~/models/track"; -import { TrackContext } from "~/contexts/TrackContext"; +import { TrackContext } from "~/contexts/TrackContext/TrackContext"; import { useContext } from "react"; interface Props { min: number; max: number; + style: "character" | "camera" | "audio" | "objects"; clip: BaseClip; - updateClip: (id: string, offset: number, length: number) => void; + updateClip: (options: { id: string; offset: number; length: number }) => void; selected?: boolean; } -export const TrackClip = ({ clip, min, max, updateClip }: Props) => { - const { selectClip } = useContext(TrackContext); - const { - onPointerDown, - onPointerUp, - onMouseLeave, - onMouseMove, - offset, - length, - } = useMouseEvents(clip, max, min, updateClip); +export const TrackClip = ({ clip, min, max, style, updateClip }: Props) => { + const { selectClip, selectedClip, scale } = useContext(TrackContext); + const { onPointerDown, offset, length } = useMouseEventsClip( + clip, + max, + min, + updateClip, + ); + + const classes = [ + "absolute", + clip.id === selectedClip ? `bg-${style}-selected` : `bg-${style}-clip`, + ]; return ( <>
{clip.name}