mirror of
https://github.com/storytold/artcraft.git
synced 2026-11-05 09:48:44 +00:00
Adjust timeline sizing
This commit is contained in:
1 parent
521b61552c
commit
bcb3acbc7f
7 files changed
+117
-45
No files matched your search
@@ -1,15 +1,17 @@
|
||||
import React, { useCallback, useContext } from "react";
|
||||
import { TrackContext } from "~/pages/PageEnigma/contexts/TrackContext/TrackContext";
|
||||
import { useMouseEventsHeight } from "~/pages/PageEnigma/comps/Timeline/utils/useMouseEventsHeight";
|
||||
|
||||
interface LowerPanelPropsI {
|
||||
timelineHeight: number;
|
||||
children: React.ReactNode;
|
||||
}
|
||||
|
||||
export const LowerPanel = ({ children, timelineHeight }: LowerPanelPropsI) => {
|
||||
// const [open, setOpen] = useState(false);
|
||||
const { setOverTimeline, updateCurrentTime, scale } =
|
||||
export const LowerPanel = ({ children }: LowerPanelPropsI) => {
|
||||
const { setOverTimeline, updateCurrentTime, scale, timelineHeight } =
|
||||
useContext(TrackContext);
|
||||
const { onPointerDown, height } = useMouseEventsHeight();
|
||||
|
||||
const displayHeight = height > -1 ? height : timelineHeight;
|
||||
|
||||
const onTimelineClick = useCallback(
|
||||
(event: React.PointerEvent<HTMLDivElement>) => {
|
||||
@@ -20,25 +22,25 @@ export const LowerPanel = ({ children, timelineHeight }: LowerPanelPropsI) => {
|
||||
[updateCurrentTime, scale],
|
||||
);
|
||||
|
||||
// const handleOpen = () => {
|
||||
// setOpen(true);
|
||||
// };
|
||||
|
||||
return (
|
||||
<div
|
||||
className={[
|
||||
"absolute bottom-0",
|
||||
"w-screen overflow-auto",
|
||||
"border-t border-ui-panel-border",
|
||||
"bg-ui-panel",
|
||||
].join(" ")}
|
||||
style={{ height: timelineHeight }}
|
||||
style={{ height: displayHeight }}
|
||||
onPointerOver={() => {
|
||||
setOverTimeline(true);
|
||||
}}
|
||||
onPointerLeave={() => setOverTimeline(false)}
|
||||
onPointerDown={onTimelineClick}
|
||||
>
|
||||
<div
|
||||
className="w-full cursor-ns-resize bg-ui-panel-border"
|
||||
style={{ height: 3, zIndex: 1000 }}
|
||||
onPointerDown={onPointerDown}
|
||||
/>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { useState } from "react";
|
||||
import { Tabs } from "../Tabs";
|
||||
import { Transition } from "@headlessui/react";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import {
|
||||
@@ -11,14 +10,14 @@ interface Props {
|
||||
children: React.ReactNode;
|
||||
}
|
||||
|
||||
export const SidePanel = ({children}:Props) => {
|
||||
export const SidePanel = ({ children }: Props) => {
|
||||
const [isVisible, setIsVisible] = useState(true);
|
||||
|
||||
return (
|
||||
<div className="relative border-l border-l-ui-panel-border bg-ui-panel">
|
||||
<button
|
||||
onClick={() => setIsVisible(!isVisible)}
|
||||
className="hover:bg-ui-controls-button absolute left-[-25px] top-1/2 flex rounded-l-lg bg-ui-controls px-2 py-3 align-middle text-sm text-white transition duration-150 ease-in-out"
|
||||
className="absolute left-[-25px] top-1/2 flex rounded-l-lg bg-ui-controls px-2 py-3 align-middle text-sm text-white transition duration-150 ease-in-out hover:bg-ui-controls-button"
|
||||
>
|
||||
<FontAwesomeIcon icon={isVisible ? faChevronRight : faChevronLeft} />
|
||||
</button>
|
||||
@@ -31,11 +30,8 @@ export const SidePanel = ({children}:Props) => {
|
||||
leaveFrom="translate-x-0"
|
||||
leaveTo="translate-x-full"
|
||||
>
|
||||
|
||||
{children}
|
||||
|
||||
{children}
|
||||
</Transition>
|
||||
</div>
|
||||
|
||||
);
|
||||
};
|
||||
@@ -1,4 +1,4 @@
|
||||
import { useEffect, useReducer } from "react";
|
||||
import { useContext, useEffect, useReducer } from "react";
|
||||
|
||||
import { faSparkles } from "@fortawesome/pro-solid-svg-icons";
|
||||
|
||||
@@ -17,39 +17,47 @@ import { AppUIProvider } from "./contexts/AppUiContext";
|
||||
import { reducer, initialState, ACTION_TYPES } from "./reducer";
|
||||
import { VIEW_MODES } from "./reducer/types";
|
||||
import { ViewSideBySide } from "./comps/ViewSideBySide";
|
||||
import { TrackContext } from "~/pages/PageEnigma/contexts/TrackContext/TrackContext";
|
||||
|
||||
export const PageEnigmaComponent = () => {
|
||||
const [appUiState, dispatchAppUiState] = useReducer(reducer, initialState);
|
||||
|
||||
useEffect(()=>{
|
||||
setTimeout(()=>dispatchAppUiState({
|
||||
type: ACTION_TYPES.HIDE_EDITOR_LOADER
|
||||
}), 500);
|
||||
},[]);
|
||||
const { timelineHeight } = useContext(TrackContext);
|
||||
|
||||
useEffect(() => {
|
||||
setTimeout(
|
||||
() =>
|
||||
dispatchAppUiState({
|
||||
type: ACTION_TYPES.HIDE_EDITOR_LOADER,
|
||||
}),
|
||||
500,
|
||||
);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<TopBarHelmet>
|
||||
<Button icon={faSparkles}>Generate Movie</Button>
|
||||
</TopBarHelmet>
|
||||
|
||||
<AppUIProvider value={[appUiState, dispatchAppUiState]} >
|
||||
|
||||
<AppUIProvider value={[appUiState, dispatchAppUiState]}>
|
||||
<EngineProvider>
|
||||
<div style={{ height: "calc(100vh - 68px)" }}>
|
||||
{/* Engine section/side panel */}
|
||||
<div
|
||||
id="CanvasUiWrapper"
|
||||
className="flex"
|
||||
style={{ height: `calc(100% - ${appUiState.timelineHeight}px)` }}
|
||||
style={{ height: `calc(100% - ${timelineHeight}px)` }}
|
||||
// style={{ height: `calc(100% - 260px` }}
|
||||
>
|
||||
<div className="relative w-full overflow-hidden bg-transparent">
|
||||
<div className={(appUiState.viewMode === VIEW_MODES.SIDE_BY_SIDE) ? 'invisible' : ''}>
|
||||
<canvas
|
||||
id="video-scene"
|
||||
width="1280px"
|
||||
height="720px"
|
||||
/>
|
||||
<div
|
||||
className={
|
||||
appUiState.viewMode === VIEW_MODES.SIDE_BY_SIDE
|
||||
? "invisible"
|
||||
: ""
|
||||
}
|
||||
>
|
||||
<canvas id="video-scene" width="1280px" height="720px" />
|
||||
|
||||
{/* Top controls */}
|
||||
<div className="absolute left-0 top-0 w-full">
|
||||
@@ -65,19 +73,18 @@ export const PageEnigmaComponent = () => {
|
||||
<ControlsVideo />
|
||||
</div>
|
||||
</div>
|
||||
{
|
||||
appUiState.viewMode === VIEW_MODES.SIDE_BY_SIDE &&
|
||||
{appUiState.viewMode === VIEW_MODES.SIDE_BY_SIDE && (
|
||||
<ViewSideBySide />
|
||||
}
|
||||
)}
|
||||
<LoadingDots
|
||||
className="absolute top-0 left-0"
|
||||
className="absolute left-0 top-0"
|
||||
show={appUiState.showEditorLoader.isShow}
|
||||
type="bricks"
|
||||
message={appUiState.showEditorLoader.message}
|
||||
transition
|
||||
/>
|
||||
</div>
|
||||
|
||||
|
||||
{/* Side panel */}
|
||||
<SidePanel>
|
||||
<SidePanelTabs />
|
||||
@@ -85,7 +92,7 @@ export const PageEnigmaComponent = () => {
|
||||
</div>
|
||||
|
||||
{/* Timeline */}
|
||||
<Timeline timelineHeight={appUiState.timelineHeight} />
|
||||
<Timeline />
|
||||
</div>
|
||||
</EngineProvider>
|
||||
</AppUIProvider>
|
||||
|
||||
@@ -11,11 +11,7 @@ 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) => {
|
||||
export const Timeline = () => {
|
||||
const {
|
||||
characters,
|
||||
objects,
|
||||
@@ -69,7 +65,7 @@ export const Timeline = ({ timelineHeight }: Props) => {
|
||||
|
||||
return (
|
||||
<>
|
||||
<LowerPanel timelineHeight={timelineHeight}>
|
||||
<LowerPanel>
|
||||
<div
|
||||
className={[
|
||||
"prevent-select mt-4",
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
import React, { useCallback, useContext, useEffect, useState } from "react";
|
||||
import { TrackContext } from "~/pages/PageEnigma/contexts/TrackContext/TrackContext";
|
||||
|
||||
export const useMouseEventsHeight = () => {
|
||||
const { timelineHeight, setTimelineHeight } = useContext(TrackContext);
|
||||
const [isActive, setIsActive] = useState(false);
|
||||
const [clientY, setClientY] = useState(0);
|
||||
|
||||
const [height, setHeight] = useState(-1);
|
||||
|
||||
useEffect(() => {
|
||||
const onPointerUp = () => {
|
||||
if (isActive) {
|
||||
setTimelineHeight(height);
|
||||
setIsActive(false);
|
||||
setHeight(-1);
|
||||
}
|
||||
};
|
||||
|
||||
const onMouseMove = (event: MouseEvent) => {
|
||||
if (isActive) {
|
||||
const delta = event.clientY - clientY;
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
if (timelineHeight - delta < 30) {
|
||||
return;
|
||||
}
|
||||
setHeight(timelineHeight - delta);
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
window.addEventListener("pointerup", onPointerUp);
|
||||
window.addEventListener("pointermove", onMouseMove);
|
||||
|
||||
return () => {
|
||||
window.removeEventListener("pointerup", onPointerUp);
|
||||
window.removeEventListener("pointermove", onMouseMove);
|
||||
};
|
||||
}, [clientY, isActive, height, timelineHeight, setTimelineHeight]);
|
||||
|
||||
return {
|
||||
onPointerDown: useCallback(
|
||||
(event: React.PointerEvent<HTMLDivElement>) => {
|
||||
if (event.button === 0) {
|
||||
event.stopPropagation();
|
||||
setClientY(event.clientY);
|
||||
setIsActive(true);
|
||||
setHeight(timelineHeight);
|
||||
}
|
||||
},
|
||||
[timelineHeight],
|
||||
),
|
||||
height,
|
||||
};
|
||||
};
|
||||
@@ -102,6 +102,10 @@ export const TrackContext = createContext<{
|
||||
// total length of the film clip
|
||||
length: number;
|
||||
|
||||
// height of the timeline section
|
||||
timelineHeight: number;
|
||||
setTimelineHeight: (height: number) => void;
|
||||
|
||||
// computed width length * 60 * 4 * scale
|
||||
fullWidth: number;
|
||||
}>({
|
||||
@@ -154,4 +158,6 @@ export const TrackContext = createContext<{
|
||||
updateCurrentTime: () => {},
|
||||
length: 12,
|
||||
fullWidth: 0,
|
||||
timelineHeight: 0,
|
||||
setTimelineHeight: () => {},
|
||||
});
|
||||
@@ -39,6 +39,12 @@ export const TrackProvider = ({ children }: Props) => {
|
||||
});
|
||||
}, []);
|
||||
|
||||
const [timelineHeight, setTimelineHeight] = useState(0);
|
||||
useEffect(() => {
|
||||
const windowHeight = window.outerHeight;
|
||||
setTimelineHeight(windowHeight * 0.25);
|
||||
}, []);
|
||||
|
||||
// cross group functions
|
||||
const dropClip = useCallback(() => {
|
||||
const { canDrop, dragType, dropId, dragId, dropOffset } = dragDrop;
|
||||
@@ -94,6 +100,8 @@ export const TrackProvider = ({ children }: Props) => {
|
||||
updateCurrentTime,
|
||||
length,
|
||||
fullWidth,
|
||||
timelineHeight,
|
||||
setTimelineHeight,
|
||||
};
|
||||
}, [
|
||||
characters,
|
||||
@@ -115,6 +123,7 @@ export const TrackProvider = ({ children }: Props) => {
|
||||
fullWidth,
|
||||
length,
|
||||
scale,
|
||||
timelineHeight,
|
||||
]);
|
||||
return (
|
||||
<TrackContext.Provider value={values}>{children}</TrackContext.Provider>
|
||||
|
||||
Reference in new issue
Block a user