mirror of
https://github.com/storytold/artcraft.git
synced 2026-11-04 17:38:10 +00:00
Merge pull request #24 from storytold/feature/loading-bar
Feature/loading bar
This commit is contained in:
11 files changed
+249
-52
No files matched your search
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
)
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
}
|
||||
@@ -55,6 +55,11 @@ function LoadingDots({
|
||||
} else {
|
||||
setState('completed');
|
||||
}
|
||||
}else{
|
||||
setState((curr) => {
|
||||
if (curr!=='loading') return 'loading';
|
||||
else return curr;
|
||||
});
|
||||
}
|
||||
}, [show, transition]);
|
||||
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
@@ -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
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
};
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
};
|
||||
Reference in new issue
Block a user