fixes and timeline re-styling

This commit is contained in:
Christopher Oliphant committed 2024-04-12 13:20:13 -04:00
1 parent 0a0a2f1cab
commit ef12e7375b
21 files changed
+363 -208

No files matched your search

+4 -14
View File
@@ -1,7 +1,7 @@
import React, { useCallback, UIEvent } from "react";
import React, { useCallback } from "react";
import { useMouseEventsTimeline } from "~/pages/PageEnigma/comps/Timeline/utils/useMouseEventsTimeline";
import {
currentScroll,
timelineScrollX,
currentTime,
dndTimelineHeight,
overTimeline,
@@ -29,7 +29,7 @@ export const LowerPanel = ({ children, onStyle }: LowerPanelPropsI) => {
(event: React.PointerEvent<HTMLDivElement>) => {
if (event.button === 0) {
const newTime = Math.round(
(event.clientX + currentScroll.value - 92) / 4 / scale.value,
(event.clientX + timelineScrollX.value - 92) / 4 / scale.value,
);
if (newTime < 0) {
return;
@@ -45,10 +45,6 @@ export const LowerPanel = ({ children, onStyle }: LowerPanelPropsI) => {
[],
);
const onScroll = useCallback((event: UIEvent<HTMLDivElement>) => {
currentScroll.value = event.currentTarget.scrollLeft;
}, []);
return (
<>
{!onStyle && (
@@ -59,19 +55,13 @@ export const LowerPanel = ({ children, onStyle }: LowerPanelPropsI) => {
/>
)}
<div
className={[
"absolute bottom-0",
"w-screen",
onStyle ? "overflow-x-auto overflow-y-hidden" : "overflow-auto",
"bg-ui-panel",
].join(" ")}
className={["absolute bottom-0", "w-screen", "bg-ui-panel"].join(" ")}
style={{ height: onStyle ? 80 : displayHeight }}
onPointerOver={() => {
overTimeline.value = true;
}}
onPointerLeave={() => (overTimeline.value = false)}
onPointerDown={onTimelineClick}
onScroll={onScroll}
>
{children}
</div>
+7 -1
View File
@@ -1,4 +1,4 @@
import React, { useContext } from "react";
import React, { useContext, useRef } from "react";
import { LoadingBar, LoadingDots } from "~/components";
import { SidePanel } from "~/modules/SidePanel";
@@ -33,6 +33,11 @@ export const PageEditor = ({ setPage }: Props) => {
useSignals();
const [appUiState] = useContext(AppUiContext);
const r1 = useRef(appUiState);
if (r1.current !== appUiState) {
console.log("app");
r1.current = appUiState;
}
//To prevent the click event from propagating to the canvas: TODO: HANDLE THIS BETTER?
const handleOverlayClick = (event: React.MouseEvent<HTMLDivElement>) => {
@@ -51,6 +56,7 @@ export const PageEditor = ({ setPage }: Props) => {
? pageHeight.value - dndTimelineHeight.value - 68
: pageHeight.value - timelineHeight.value - 68;
console.log("page");
return (
<div className="w-screen">
<TopBar pageName="Edit Scene" />
+1 -1
View File
@@ -20,7 +20,7 @@ export const PageEnigmaComponent = () => {
dispatchAppUiState,
});
}
}, [editor, dispatchAppUiState]);
}, []);
return (
<>
+57 -11
View File
@@ -1,15 +1,23 @@
import { useSignals } from "@preact/signals-react/runtime";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faAngleLeft } from "@fortawesome/pro-solid-svg-icons";
import { Button, Link } from "~/components";
import { Button } from "~/components";
import { StyleSelection } from "~/pages/PageEnigma/comps/StyleSelection";
import { LowerPanel } from "~/modules/LowerPanel";
import { TimerGrid } from "~/pages/PageEnigma/comps/TimerGrid/TimerGrid";
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 { useContext } from "react";
import React, { UIEvent, useCallback, useContext } from "react";
import { EngineContext } from "~/contexts/EngineContext";
import {
currentTime,
filmLength,
scale,
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";
interface Props {
setPage: (page: string) => void;
@@ -19,6 +27,8 @@ export const PageStyling = ({ setPage }: Props) => {
useSignals();
const editorEngine = useContext(EngineContext);
console.log(timelineScrollX.value);
const generateFrame = async () => {
await editorEngine?.generateFrame();
};
@@ -30,7 +40,31 @@ export const PageStyling = ({ setPage }: Props) => {
const switchEdit = () => {
editorEngine?.switchEdit();
setPage("edit");
}
};
const onScroll = useCallback((event: UIEvent<HTMLDivElement>) => {
timelineScrollX.value = event.currentTarget.scrollLeft;
}, []);
const onTimelineClick = useCallback(
(event: React.PointerEvent<HTMLDivElement>) => {
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) },
});
}
},
[],
);
return (
<div className="w-screen">
@@ -50,17 +84,29 @@ export const PageStyling = ({ setPage }: Props) => {
<div className="fixed bottom-0 left-0 w-full">
<div className="flex h-[62px] w-full items-center justify-center gap-5 bg-ui-panel">
<div>
<Button variant="action" onClick={generateFrame}>Update Preview</Button>
<Button variant="action" onClick={generateFrame}>
Update Preview
</Button>
</div>
<div>
<Button variant="primary" onClick={generateMovie}>Generate Movie</Button>
<Button variant="primary" onClick={generateMovie}>
Generate Movie
</Button>
</div>
</div>
<div className="relative flex h-[80px] w-full gap-5 border-t border-t-action-600 bg-ui-panel">
<LowerPanel onStyle>
<TimerGrid />
<Scrubber />
</LowerPanel>
<div className="w-screen overflow-x-auto" onScroll={onScroll}>
<div
style={{
width: filmLength.value * 60 * 4 * scale.value,
height: 60,
}}
onClick={onTimelineClick}
>
<TimerGrid />
<Scrubber />
</div>
</div>
</div>
</div>
</div>
+4 -14
View File
@@ -1,10 +1,5 @@
import { TrackClips } from "~/pages/PageEnigma/comps/Timeline/TrackClips";
import {
audioGroup,
fullWidth,
toggleAudioMute,
updateAudio,
} from "~/pages/PageEnigma/store";
import { audioGroup, fullWidth, updateAudio } from "~/pages/PageEnigma/store";
import { ClipGroup } from "~/pages/PageEnigma/models";
export const Audio = () => {
@@ -12,21 +7,16 @@ export const Audio = () => {
return (
<div
className="bg-global_audio-groupBg block rounded-lg pb-5 pl-2 pr-4"
style={{ width: fullWidth.value + 90 }}
className="block rounded-r-lg bg-global_audio-groupBg pb-5 pr-4"
style={{ width: fullWidth.value + 16 }}
>
<div className="prevent-select mb-5 pt-2 text-xs font-medium text-white">
Global Audio
</div>
<div className="flex flex-col gap-4">
<div className="flex flex-col gap-4 pt-4">
<TrackClips
id={audioGroup.value.id}
clips={clips}
title="Global Audio TrackClips"
updateClip={updateAudio}
group={ClipGroup.GLOBAL_AUDIO}
muted={audioGroup.value.muted}
toggleMute={toggleAudioMute}
/>
</div>
</div>
@@ -9,11 +9,10 @@ export const Camera = () => {
return (
<div
className="block rounded-lg bg-camera-groupBg pb-5 pl-2 pr-4"
style={{ width: fullWidth.value + 90 }}
className="block rounded-r-lg bg-camera-groupBg pb-5 pr-4"
style={{ width: fullWidth.value + 16 }}
>
<div className="mb-5 pt-2 text-xs font-medium text-white">Camera</div>
<div className="flex flex-col gap-4">
<div className="pt-4">
<TrackKeyFrames
id={cameraGroup.value.id}
keyframes={keyframes}
@@ -43,24 +43,14 @@ export const Character = ({ character }: Props) => {
const { updateClipLipSync, updateClipPosition, updateClipAnimations } =
useMemo(() => buildUpdaters(updateCharacters), []);
const toggleCharacterLipSyncMute = useCallback(() => {
toggleLipSyncMute(character?.object_uuid ?? "");
}, [character?.object_uuid]);
if (!character) {
return false;
}
const { animationClips, positionKeyframes, lipSyncClips } = character;
return (
<div
className="block rounded-lg bg-character-groupBg pb-5 pl-2 pr-4"
style={{ width: fullWidth.value + 90 }}
className="block rounded-r-lg bg-character-groupBg pb-5 pr-4"
style={{ width: fullWidth.value + 16 }}
>
<div className="prevent-select mb-5 pt-2 text-xs font-medium text-white">
Character
</div>
<div className="flex flex-col gap-4">
<div className="flex flex-col gap-4 pt-4">
<TrackClips
id={character.object_uuid}
clips={animationClips}
@@ -81,8 +71,6 @@ export const Character = ({ character }: Props) => {
clips={lipSyncClips}
title="Lipsync Audio TrackClips"
updateClip={updateClipLipSync}
muted={character.muted}
toggleMute={toggleCharacterLipSyncMute}
group={ClipGroup.CHARACTER}
type={ClipType.AUDIO}
/>
@@ -7,7 +7,9 @@ export const Characters = () => {
return (
<>
{characterGroup.value.characters.map((character) => (
<Character key={character.object_uuid} character={character} />
<div key={character.object_uuid} className="pb-4 pr-4">
<Character character={character} />
</div>
))}
</>
);
@@ -1,17 +1,17 @@
import { objectGroup } from "~/pages/PageEnigma/store";
import { useSignals } from "@preact/signals-react/runtime";
import { ObjectTrack } from "~/pages/PageEnigma/comps/Timeline/ObjectTrack";
import { ObjectTrackComponent } from "~/pages/PageEnigma/comps/Timeline/ObjectTrack";
export const ObjectGroups = () => {
useSignals();
return (
<>
{objectGroup.value.objects.length > 0 && (
<div className="p-4">
<ObjectTrack />
{objectGroup.value.objects.map((object) => (
<div key={object.object_uuid} className="pb-4 pr-4">
<ObjectTrackComponent object={object} />
</div>
)}
))}
</>
);
};
@@ -1,27 +1,26 @@
import { fullWidth, objectGroup, updateObject } from "~/pages/PageEnigma/store";
import { fullWidth, updateObject } from "~/pages/PageEnigma/store";
import { TrackKeyFrames } from "~/pages/PageEnigma/comps/Timeline/TrackKeyFrames";
import { ClipGroup } from "~/pages/PageEnigma/models";
import { ClipGroup, ObjectTrack } from "~/pages/PageEnigma/models";
export const ObjectTrack = () => {
interface Props {
object: ObjectTrack;
}
export const ObjectTrackComponent = ({ object }: Props) => {
return (
<div
className="bg-object-groupBg block rounded-lg pb-5 pl-2 pr-4"
style={{ width: fullWidth.value + 90 }}
className="mr-4 block rounded-r-lg bg-object-groupBg pb-5 pr-4"
style={{ width: fullWidth.value + 32 }}
>
<div className="prevent-select mb-5 pt-2 text-xs font-medium text-white">
Objects
<div key={object.object_uuid} className="pt-4">
<TrackKeyFrames
id={object.object_uuid}
keyframes={object.keyframes}
title={`${object.name} Position/Rotation`}
updateKeyframe={updateObject}
group={ClipGroup.OBJECT}
/>
</div>
{objectGroup.value.objects.map((object) => (
<div key={object.object_uuid} className="flex flex-col gap-4">
<TrackKeyFrames
id={object.object_uuid}
keyframes={object.keyframes}
title={`${object.name} Position/Rotation`}
updateKeyframe={updateObject}
group={ClipGroup.OBJECT}
/>
</div>
))}
</div>
);
};
@@ -0,0 +1,89 @@
import {
audioGroup,
characterGroup,
objectGroup,
timelineScrollY,
toggleAudioMute,
toggleLipSyncMute,
} from "~/pages/PageEnigma/store";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faVolume, faVolumeSlash } from "@fortawesome/pro-solid-svg-icons";
import { useSignals } from "@preact/signals-react/runtime";
export const RowHeaders = () => {
useSignals();
return (
<div className="relative">
<div
className="absolute mt-2"
style={{ top: timelineScrollY.value * -1 - 8 }}
>
{characterGroup.value.characters.map((character) => (
<div className="mb-4 ml-6" key={character.object_uuid}>
<div className="relative block h-[224px] w-[64px] overflow-x-hidden rounded-l-lg bg-character-groupBg">
<div className="absolute left-2 top-2 text-xs font-medium text-white">
Character
</div>
<div className="absolute">
<button
className="text-md absolute text-white transition-colors duration-100 hover:text-white/80"
style={{ top: 174, left: 34 }}
onClick={() => toggleLipSyncMute(character.object_uuid)}
>
{character.muted ? (
<FontAwesomeIcon
icon={faVolumeSlash}
className="text-brand-primary transition-colors duration-100 hover:text-brand-primary/80"
/>
) : (
<FontAwesomeIcon icon={faVolume} />
)}
</button>
</div>
</div>
</div>
))}
<div className="mb-4 ml-6">
<div className="relative block h-[88px] w-[64px] rounded-l-lg bg-camera-groupBg">
<div className="absolute left-2 top-2 text-xs font-medium text-white">
Camera
</div>
</div>
</div>
<div className="mb-4 ml-6">
<div className="relative block h-[88px] w-[64px] rounded-l-lg bg-global_audio-groupBg">
<div className="absolute left-2 top-2 text-xs font-medium text-white">
Global Audio
</div>
<div className="absolute">
<button
className="text-md absolute text-white transition-colors duration-100 hover:text-white/80"
style={{ top: 40, left: 34 }}
onClick={() => toggleAudioMute()}
>
{audioGroup.value.muted ? (
<FontAwesomeIcon
icon={faVolumeSlash}
className="text-brand-primary transition-colors duration-100 hover:text-brand-primary/80"
/>
) : (
<FontAwesomeIcon icon={faVolume} />
)}
</button>
</div>
</div>
</div>
{objectGroup.value.objects.map((obj) => (
<div key={obj.object_uuid} className="mb-4 ml-6">
<div className="relative block h-[88px] w-[64px] rounded-l-lg bg-object-groupBg">
<div className="absolute left-2 top-2 text-xs font-medium text-white">
Object
</div>
</div>
</div>
))}
</div>
</div>
);
};
@@ -1,4 +1,9 @@
import { currentTime, fullHeight, scale } from "~/pages/PageEnigma/store";
import {
timelineScrollX,
currentTime,
fullHeight,
scale,
} 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";
@@ -9,10 +14,16 @@ export const Scrubber = () => {
const { onPointerDown, time } = useMouseEventsScrubber();
const displayTime = time === -1 ? currentTime.value : time;
if (displayTime * 4 * scale.value + 84 - timelineScrollX.value < 84) {
return null;
}
return (
<div
className="absolute flex cursor-ew-resize flex-col items-center text-brand-primary"
style={{ top: 8, left: displayTime * 4 * scale.value + 84 }}
style={{
top: 8,
left: displayTime * 4 * scale.value + 84 - timelineScrollX.value,
}}
onPointerDown={onPointerDown}
>
<div>
@@ -1,4 +1,4 @@
import { useCallback, useEffect, useState } from "react";
import { UIEvent, useCallback, useEffect, useState } from "react";
import { LowerPanel } from "~/modules/LowerPanel";
import { Camera } from "./Camera";
@@ -10,15 +10,21 @@ import {
deleteCharacterClip,
selectedItem,
ignoreDelete,
timelineScrollX,
timelineScrollY,
filmLength,
scale,
} from "~/pages/PageEnigma/store";
import { useQueueHandler } from "~/pages/PageEnigma/comps/Timeline/utils/useQueueHandler";
import { useSignals } from "@preact/signals-react/runtime";
import { TimerGrid } from "~/pages/PageEnigma/comps/TimerGrid/TimerGrid";
import { TimerGrid } from "~/pages/PageEnigma/comps/Timeline/TimerGrid";
import { Scrubber } from "~/pages/PageEnigma/comps/Timeline/Scrubber";
import { Characters } from "~/pages/PageEnigma/comps/Timeline/Characters";
import { ObjectGroups } from "~/pages/PageEnigma/comps/Timeline/ObjectGroups";
import useUpdateKeyframe from "~/pages/PageEnigma/contexts/TrackContext/utils/useUpdateKeyframe";
import { Clip, Keyframe } from "~/pages/PageEnigma/models";
import { RowHeaders } from "~/pages/PageEnigma/comps/Timeline/RowHeaders";
import { pageWidth } from "~/store";
function getItemType(item: Clip | Keyframe | null) {
if (!item) {
@@ -32,6 +38,11 @@ export const Timeline = () => {
const [dialogOpen, setDialogOpen] = useState(false);
const { deleteKeyframe } = useUpdateKeyframe();
const onScroll = useCallback((event: UIEvent<HTMLDivElement>) => {
timelineScrollX.value = event.currentTarget.scrollLeft;
timelineScrollY.value = event.currentTarget.scrollTop;
}, []);
// implement the code to handle incoming messages from the Engine
useQueueHandler();
@@ -75,17 +86,39 @@ export const Timeline = () => {
<>
<LowerPanel>
<TimerGrid />
<div className="p-4">
<Characters />
<div className="flex">
<div
className="mt-2 overflow-hidden"
style={{
width: 88,
height: timelineHeight.value - 54,
}}
>
<RowHeaders />
</div>
<div
className="mt-2 overflow-auto"
onScroll={onScroll}
style={{
width: pageWidth.value - 90,
height: timelineHeight.value - 54,
}}
>
<div
style={{ width: filmLength.value * 60 * 4 * scale.value + 32 }}
>
<Characters />
<div className="pb-4 pr-8">
<Camera />
</div>
<div className="pb-4 pr-8">
<Audio />
</div>
<ObjectGroups />
</div>
</div>
<Scrubber />
</div>
<div className="p-4">
<Camera />
</div>
<div className="p-4">
<Audio />
</div>
<ObjectGroups />
<Scrubber />
</LowerPanel>
<ConfirmationModal
title="Delete Clip"
@@ -0,0 +1,78 @@
import {
timelineScrollX,
filmLength,
fullHeight,
scale,
} from "~/pages/PageEnigma/store";
import { Fragment } from "react";
import { useSignals } from "@preact/signals-react/runtime";
export const TimerGrid = () => {
useSignals();
const sectionWidth = 60 * 4 * scale.value;
return (
<div
className={[
"prevent-select ml-[88px] mt-4",
"relative flex h-7 overflow-hidden",
"border-t border-t-ui-panel-border",
"text-xs text-white opacity-75",
].join(" ")}
>
<div className="absolute" style={{ left: timelineScrollX.value * -1 }}>
{Array(filmLength.value)
.fill(0)
.map((_, index) => (
<Fragment key={index}>
<div
className="absolute ps-1 pt-2"
style={{ left: index * sectionWidth + 4 }}
>
00:{index < 10 ? "0" + index.toString() : index.toString()}
</div>
<div
className="absolute block bg-ui-divider"
style={{
width: 1,
left: index * sectionWidth,
height: fullHeight.value,
}}
/>
{Array(9)
.fill(0)
.map((_, ind) => (
<div
key={ind}
className="absolute block h-2 bg-ui-divider"
style={{
width: 1,
top: 0,
left:
index * sectionWidth + (sectionWidth / 10) * (ind + 1),
}}
/>
))}
</Fragment>
))}
<div
className="absolute pt-2"
style={{ left: filmLength.value * sectionWidth + 4 }}
>
00:
{filmLength.value < 10
? "0" + filmLength.value.toString()
: filmLength.value.toString()}
</div>
<div
className="absolute block h-full bg-ui-divider"
style={{
width: 1,
left: filmLength.value * sectionWidth,
height: fullHeight.value,
}}
/>
</div>
</div>
);
};
@@ -23,8 +23,6 @@ interface Props {
title: string;
group: ClipGroup;
type?: ClipType;
toggleMute?: () => void;
muted?: boolean;
updateClip: (options: { id: string; length: number; offset: number }) => void;
}
@@ -56,9 +54,7 @@ function getCanBuild({
export const TrackClips = ({
id,
clips,
toggleMute,
updateClip,
muted,
title,
group,
type,
@@ -81,7 +77,7 @@ export const TrackClips = ({
return;
}
// Now check the the clip fits
// Now check if the clip fits
const position = track.getBoundingClientRect();
const clipOffset = (event.clientX - position.x) / 4 / scale.value;
@@ -114,49 +110,31 @@ export const TrackClips = ({
}
return (
<div className="pl-16">
<div
id={`track-${trackType}-${id}`}
className={`relative mt-4 block h-9 w-full rounded-lg bg-${group}-unselected`}
onPointerOver={onPointerOver}
onPointerLeave={onPointerLeave}
onPointerMove={onPointerMove}
>
{clips.map((clip, index) => (
<TrackClip
key={clip.clip_uuid}
min={
index > 0 ? clips[index - 1].offset + clips[index - 1].length : 0
}
max={
index < clips.length - 1
? clips[index + 1].offset
: filmLength.value * 60
}
group={group}
updateClip={updateClip}
clip={clip}
/>
))}
<div className="prevent-select absolute ps-2 pt-1 text-xs font-medium text-white">
{title}
</div>
{!!toggleMute && (
<button
className="text-md absolute text-white transition-colors duration-100 hover:text-white/80"
style={{ top: 6, left: -28 }}
onClick={toggleMute}
>
{muted ? (
<FontAwesomeIcon
icon={faVolumeSlash}
className="text-brand-primary transition-colors duration-100 hover:text-brand-primary/80"
/>
) : (
<FontAwesomeIcon icon={faVolume} />
)}
</button>
)}
<div
id={`track-${trackType}-${id}`}
className={`relative mt-4 block h-9 w-full rounded-lg bg-${group}-unselected`}
onPointerOver={onPointerOver}
onPointerLeave={onPointerLeave}
onPointerMove={onPointerMove}
>
{clips.map((clip, index) => (
<TrackClip
key={clip.clip_uuid}
min={
index > 0 ? clips[index - 1].offset + clips[index - 1].length : 0
}
max={
index < clips.length - 1
? clips[index + 1].offset
: filmLength.value * 60
}
group={group}
updateClip={updateClip}
clip={clip}
/>
))}
<div className="prevent-select absolute ps-2 pt-1 text-xs font-medium text-white">
{title}
</div>
</div>
);
@@ -24,7 +24,7 @@ export const TrackKeyFrames = ({
group,
}: Props) => {
return (
<div className="pl-16">
<div>
<div
id={`track-${group}-${id}`}
className={`relative mt-4 block h-9 w-full rounded-lg bg-${group}-unselected`}
@@ -1,6 +1,6 @@
import React, { useCallback, useEffect, useState } from "react";
import {
currentScroll,
timelineScrollX,
currentTime,
filmLength,
scale,
@@ -26,7 +26,7 @@ export const useMouseEventsScrubber = () => {
Queue.publish({
queueName: QueueNames.TO_ENGINE,
action: toEngineActions.UPDATE_TIME,
data: { currentTime: Math.round(time) + currentScroll.value },
data: { currentTime: Math.round(time) + timelineScrollX.value },
});
}
};
@@ -46,7 +46,7 @@ export const useMouseEventsScrubber = () => {
Queue.publish({
queueName: QueueNames.TO_ENGINE,
action: toEngineActions.UPDATE_TIME,
data: { currentTime: delta + currentScroll.value },
data: { currentTime: delta + timelineScrollX.value },
});
}
return delta;
@@ -1,55 +0,0 @@
import { filmLength, fullHeight, scale } from "~/pages/PageEnigma/store";
import { Fragment } from "react";
export const TimerGrid = () => {
const sectionWidth = 60 * 4 * scale.value;
return (
<div
className={[
"prevent-select mt-4",
"flex h-3",
"border-t border-t-ui-panel-border",
"text-xs text-white opacity-75",
].join(" ")}
>
{Array(filmLength.value)
.fill(0)
.map((_, index) => (
<Fragment key={index}>
<div
className="absolute ps-1 pt-1"
style={{ left: index * sectionWidth + 92 }}
>
00:{index < 10 ? "0" + index.toString() : index.toString()}
</div>
<div
className="absolute block h-full bg-ui-divider"
style={{
width: 1,
left: index * sectionWidth + 88,
height: fullHeight.value,
}}
/>
</Fragment>
))}
<div
className="absolute"
style={{ left: filmLength.value * sectionWidth + 92 }}
>
00:
{filmLength.value < 10
? "0" + filmLength.value.toString()
: filmLength.value.toString()}
</div>
<div
className="absolute block h-full bg-ui-divider"
style={{
width: 1,
left: filmLength.value * sectionWidth + 88,
height: fullHeight.value,
}}
/>
</div>
);
};
@@ -73,7 +73,7 @@ export function deleteObjectKeyframe(keyframe: Keyframe) {
const obj = oldObjectGroup.objects.find(
(row) => row.object_uuid === keyframe.object_uuid,
);
console.log("delete", obj, keyframe.keyframe_uuid);
if (!obj) {
return oldObjectGroup;
}
+1 -1
View File
@@ -9,7 +9,7 @@ export const timelineHeight = signal(0);
export const fullHeight = computed(() => {
return (
characterGroup.value.length * 268 +
characterGroup.value.characters.length * 268 +
objectGroup.value.objects.length * 60 +
300 +
96
+2 -1
View File
@@ -2,4 +2,5 @@ import { signal } from "@preact/signals-core";
export const currentTime = signal(0);
export const currentScroll = signal(0);
export const timelineScrollX = signal(0);
export const timelineScrollY = signal(0);