Merge pull request #24 from storytold/feature/loading-bar

Feature/loading bar
This commit is contained in:
wil authored and GitHub committed 2024-03-27 17:05:03 -04:00
commit 75840fdd7a
11 files changed
+249 -52

No files matched your search

+7 -2
View File
@@ -12,11 +12,16 @@ export const Button = ({
icon,
children,
className: propsClassName,
variant = "primary",
variant: propsVariant = "primary",
disabled,
...rest
}: ButtonPropsI) => {
const variant = disabled ? 'disabled' : propsVariant;
function getVariantClassNames(variant: string) {
switch (variant) {
case "disabled":{
return "bg-brand-secondary-500 text-brand-secondary-300"
}
case "secondary": {
return " bg-brand-secondary hover:bg-brand-secondary-900 text-white focus-visible:outline-brand-secondary";
}
@@ -34,7 +39,7 @@ export const Button = ({
);
return (
<button className={className} {...rest}>
<button className={className} disabled={disabled} {...rest}>
{icon && <FontAwesomeIcon className="mr-2" icon={icon} />}
{children}
</button>
+1 -1
View File
@@ -25,7 +25,7 @@ export const ItemPicker = ({
onClick={handleSelected}
>
<img className="aspect-square min-w-20" {...imgProps} />
<div className="bg-gradient-to-t from-gray-700 to-transparent absolute top-0 left-0 w-full h-full"/>
<div className="bg-gradient-to-t from-gray-700 absolute top-0 left-0 w-full h-full"/>
<H4 className="absolute bottom-0 left-2 drop-shadow-md">{label}</H4>
</div>
)
+54
View File
@@ -0,0 +1,54 @@
import { twMerge } from 'tailwind-merge';
import { H4 } from '.';
interface LoadingBarProps{
label?: string;
progress?: number;
variant?: string;
message?: string;
wrapperClassName?: string;
useFakeTimer?: number;
}
export const LoadingBar = ({
label,
progress = 0,
variant = 'primary',
message,
wrapperClassName : propsWrapperClassName,
useFakeTimer = (1000 * 60) //defaults to 1min
}: LoadingBarProps) => {
function getVariantClassNames(variant: string) {
switch (variant) {
case "secondary": {
return " bg-brand-secondary text-white ";
}
case "primary":
default: {
return " bg-brand-primary text-white ";
}
}
}
const wrapperClassName = twMerge(
"w-full h-full flex flex-col justify-center items-center bg-ui-background p-4 gap-4",
propsWrapperClassName,
)
const progressClassName = twMerge(
"h-2.5 rounded-full transition-all duration-1000",
getVariantClassNames(variant),
);
return (
<div className={wrapperClassName}>
{label && <label>{label}</label>}
<div className="w-full bg-gray-500 rounded-full h-2.5">
<div
className={progressClassName}
style={{width: progress + '%'}}
/>
</div>
{message && <H4>{message}</H4>}
</div>
);
}
+5
View File
@@ -55,6 +55,11 @@ function LoadingDots({
} else {
setState('completed');
}
}else{
setState((curr) => {
if (curr!=='loading') return 'loading';
else return curr;
});
}
}, [show, transition]);
+2
View File
@@ -6,6 +6,7 @@ import { Input } from "./Input";
import { H4 } from "./H4";
import { ItemPicker } from "./ItemPicker";
import { Textarea } from "./Textarea";
import { LoadingBar } from "./LoadingBar";
import { LoadingDotsBricks, LoadingDotsTyping } from "./LoadingDots";
export {
@@ -17,6 +18,7 @@ export {
ItemPicker,
Textarea,
Input,
LoadingBar,
LoadingDotsBricks,
LoadingDotsTyping,
};
+1 -1
View File
@@ -20,7 +20,7 @@ export const Tabs = ({ tabs: tabProps }: { tabs: TabType[] }) => {
return (
<div className="w-full max-w-md px-2 sm:px-0">
<Tab.Group>
<Tab.Group defaultIndex={3}>
<Tab.List className="flex">
{tabs.map((tab, idx) => (
<Tab
+7 -8
View File
@@ -1,4 +1,4 @@
import { useEffect, useRef, useReducer } from "react";
import { useEffect, useReducer } from "react";
import { faSparkles } from "@fortawesome/pro-solid-svg-icons";
@@ -20,21 +20,21 @@ import { ViewSideBySide } from "./comps/ViewSideBySide";
export const PageEnigmaComponent = () => {
const [appUiState, dispatchAppUiState] = useReducer(reducer, initialState);
const canvasRef = useRef<HTMLCanvasElement | null>(null);
useEffect(()=>{
setTimeout(()=>dispatchAppUiState({
type: ACTION_TYPES.HIDE_EDITOR_LOADER
}), 3000);
},[]);
return (
<div>
<TopBarHelmet>
<Button icon={faSparkles}>Generate Movie</Button>
</TopBarHelmet>
<EngineProvider>
<AppUIProvider value={[appUiState, dispatchAppUiState]} >
<AppUIProvider value={[appUiState, dispatchAppUiState]} >
<EngineProvider>
<div style={{ height: "calc(100vh - 68px)" }}>
{/* Engine section/side panel */}
<div
@@ -46,7 +46,6 @@ export const PageEnigmaComponent = () => {
<div className="relative w-full overflow-hidden bg-transparent">
<div className={(appUiState.viewMode === VIEW_MODES.SIDE_BY_SIDE) ? 'invisible' : ''}>
<canvas
ref={canvasRef}
id="video-scene"
width="1280px"
height="720px"
@@ -86,8 +85,8 @@ export const PageEnigmaComponent = () => {
{/* Timeline */}
<Timeline timelineHeight={appUiState.timelineHeight} />
</div>
</AppUIProvider>
</EngineProvider>
</EngineProvider>
</AppUIProvider>
</div>
);
};
@@ -6,16 +6,22 @@ import { EngineContext } from "../../contexts/EngineContext";
export const ControlsTopButtons = () => {
const editorEngine = useContext(EngineContext);
const [sceneName, setSceneName] = useState<string>("");
const [sceneToken, setSceneToken] = useState<string>("");
const handleButtonSave = () => {
console.log(`SceneName is ${sceneName}`);
// editorEngine?.save();
editorEngine?.save();
};
const handleButtonCameraView = () => {
editorEngine?.change_camera_view();
const handleButtonLoadScene = () => {
console.log(`Scene Token is ${sceneToken}`);
// editorEngine?.dosomething();
};
// const handleButtonCameraView = () => {
// editorEngine?.change_camera_view();
// };
const handleButtonPlayBack = () => {
editorEngine?.start_playback();
};
@@ -24,16 +30,31 @@ export const ControlsTopButtons = () => {
};
const handleButtonRender = () => {
console.log("Saving GLB to server for reference");
editorEngine._upload_for_testing();
editorEngine?._upload_for_testing();
//editorEngine?.togglePlayback();
};
const handleButtonPlay = () => {};
return (
<div className="flex gap-2 pl-3 pt-3">
<Button variant="secondary" onClick={handleButtonPlayBack}>
Toggle Camera View
</Button>
<div className="flex flex-col gap-2 pl-3 pt-3">
<div className="flex gap-2">
<ButtonDialogue
buttonProps={{
variant: "secondary",
label: "Load Scene",
}}
title="Load Scene"
confirmButtonProps={{
label: "Load",
disabled: sceneToken === "" ? true : false,
onClick: handleButtonLoadScene,
}}
>
<Input
label="Please provide the Token of the scene you wished to load:"
onChange={(e)=>{setSceneToken(e.target.value)}}
/>
</ButtonDialogue>
<ButtonDialogue
buttonProps={{
@@ -47,23 +68,32 @@ export const ControlsTopButtons = () => {
onClick: handleButtonSave,
}}
>
<Input label="Please Enter a name for your scene" />
<Input
label="Please Enter a name for your scene"
onChange={(e)=>{setSceneName(e.target.value)}}
/>
</ButtonDialogue>
<ButtonDialogue
buttonProps={{
variant: "secondary",
label: "Help",
}}
title="Help"
>
<p>Do you need help?</p>
<p>Ask Michael about this project</p>
<p>Ask Miles about ThreeJS</p>
<p>Ask Wil about React</p>
</ButtonDialogue>
<ButtonDialogue
buttonProps={{
variant: "secondary",
label: "Help",
}}
title="Help"
>
<p>Do you need help?</p>
<p>Ask Michael about this project</p>
<p>Ask Miles about ThreeJS</p>
<p>Ask Wil about React</p>
</ButtonDialogue>
</div>
<div className="fixed flex gap-2" style={{ top: 124, left: 12 }}>
<div className="flex gap-2">
<Button variant="secondary" onClick={handleButtonPlayBack}>
Toggle Camera View
</Button>
</div>
<div className="flex gap-2">
<Button onClick={handleButtonLoad}>Load</Button>
<Button onClick={handleButtonRender}>Render</Button>
<Button onClick={handleButtonPlay}>Play</Button>
@@ -1,30 +1,49 @@
import { ReactNode, useEffect, useRef, useState } from "react";
import { EngineContext } from "./EngineContext";
import { ReactNode, useContext, useEffect, useState } from "react";
import Editor from "~/pages/PageEnigma/js/editor";
import { EngineContext } from "./EngineContext";
import { AppUiContext } from "./AppUiContext";
interface Props {
children: ReactNode;
}
export const EngineProvider = ({ children }: Props) => {
const [editor, setEditor] = useState<Editor | null>(null);
const [appUiState, dispatchAppUiState] = useContext(AppUiContext);
useEffect(() => {
//componentDidMount
if (editor !== null) {
console.warn("Editor Engine already exist");
} else if (document.getElementById("video-scene") === null) {
if (document.getElementById("video-scene") === null) {
console.error(
'Editor Engine need a target cavas with the id "video-scene"',
'Editor Engine need a target canvas with the id "video-scene"',
);
} else {
const editor = new Editor();
editor.initialize();
setEditor(editor);
} else {
setEditor((curr)=>{
if(curr!==null){
console.warn("Editor Engine already exist");
return curr;
}else{
return new Editor();
}
});
}
}, []);
useEffect(()=>{
if (editor && editor.can_initailize && dispatchAppUiState!==null){
console.log("initializing Editor");
editor.initialize({
dispatchAppUiState
});
}
}, [editor, dispatchAppUiState]);
return (
<EngineContext.Provider value={editor}>{children}</EngineContext.Provider>
<EngineContext.Provider value={editor}>
{children}
</EngineContext.Provider>
);
};
+23 -1
View File
@@ -22,6 +22,7 @@ import { LipSync } from "./lipsync.js";
import { LipSyncEngine } from "./lip_sync_engine.ts";
import { AnimationEngine } from "./animation_engine.ts";
import { faL } from "@fortawesome/pro-solid-svg-icons";
import { ACTION_TYPES } from "../reducer";
if (typeof window !== "undefined") {
import("ccapture.js")
@@ -114,13 +115,23 @@ class Editor {
this.test_box_uuid = null;
this.current_frame = 0;
this.test_playback = false;
//Reactland Callbacks
this.dispatchAppUiState = null;
}
// Initializes the main scene and ThreeJS essentials.
initialize() {
/*
config :{
dispatchAppUiState: dispatch function to react app
}
*/
initialize(config) {
if (this.can_initailize == false) {
return;
}
this.can_initailize == false;
// Gets the canvas.
this.canvReference = document.getElementById("video-scene");
// Base width and height.
@@ -164,6 +175,8 @@ class Editor {
this.timeline.scene = this.activeScene;
//setup reactland Callbacks
this.dispatchAppUiState = config.dispatchAppUiState
this._test_demo()
}
@@ -377,6 +390,15 @@ class Editor {
//this.audio_engine.playClip("m_f7jnwt3d1ddchatdk5vaqt0n4mb1hg");
//console.log(this.selected);
this.dispatchAppUiState({
type: ACTION_TYPES.SHOW_EDITOR_LOADER
});
// this.dispatchAppUiState({
// type: ACTION_TYPES.HIDE_EDITOR_LOADER
// });
if (this.selected == null) {
return;
}
+67 -6
View File
@@ -1,11 +1,72 @@
import { Button } from "~/components/Button";
import { ButtonLink } from "~/components/ButtonLink";
import { useState, useEffect } from "react";
import {
Button,
ButtonLink,
H4,
LoadingBar,
LoadingDotsTyping,
LoadingDotsBricks,
} from "~/components";
export default function ComponentLibrary () {
const [progress, setProgress] = useState(0);
useEffect(()=>{
if(progress === 0){
const loop = setInterval(function timer(){
setProgress((curr)=>{
if (curr < 100){
return curr+10;
}else{
clearTimeout(loop);
return curr;
}
})}
, 3000);
}
}, [progress]);
return(
<>
<Button>Button</Button>
<ButtonLink to="/">Button with Link</ButtonLink>
</>
<div className='bg-ui-panel w-10/12 max-w-7xl h-full min-h-96 mx-auto my-6 rounded-lg p-6'>
<div className="flex flex-col gap-2 mb-4">
<H4>Buttons</H4>
<div className="flex gap-2">
<Button>Primary</Button>
<Button variant="secondary">Secondary</Button>
<Button disabled>Disabled</Button>
</div>
</div>
<div className="flex flex-col gap-2 mb-4">
<H4>ButtonLink</H4>
<ButtonLink to="/">Back to /</ButtonLink>
</div>
<div className="flex flex-col gap-2 mb-4">
<H4>Loading Dots</H4>
<div className="flex gap-2">
<div className="w-60 h-40 rounded-lg overflow-hidden">
<LoadingDotsTyping />
</div>
<div className="w-60 h-40 rounded-lg overflow-hidden">
<LoadingDotsBricks />
</div>
</div>
</div>
<div className="flex flex-col gap-2 mb-4">
<H4>Loading Bar</H4>
<div className="flex gap-2">
<LoadingBar progress={progress} wrapperClassName="rounded-lg"/>
<Button onClick={()=>setProgress(0)}>Reset</Button>
</div>
<LoadingBar
label="labeling the bar"
message="displaying a message"
pulsing
/>
</div>
</div>
);
};