mirror of
https://github.com/storytold/artcraft.git
synced 2026-11-09 11:31:27 +00:00
change all loading transitions to use headlessui transitions
This commit is contained in:
1 parent
a5cd47baeb
commit
9bef1022b6
8 files changed
+151
-96
No files matched your search
@@ -1,9 +1,12 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import { Transition } from '@headlessui/react';
|
||||
import { twMerge } from 'tailwind-merge';
|
||||
import { H4 } from '.';
|
||||
|
||||
|
||||
interface LoadingBarProps{
|
||||
label?: string;
|
||||
progress?: number;
|
||||
isShowing?: boolean;
|
||||
variant?: string;
|
||||
message?: string;
|
||||
wrapperClassName?: string;
|
||||
@@ -11,12 +14,57 @@ interface LoadingBarProps{
|
||||
}
|
||||
export const LoadingBar = ({
|
||||
label,
|
||||
progress = 0,
|
||||
progress: propsProgress = 0,
|
||||
isShowing = true,
|
||||
variant = 'primary',
|
||||
message,
|
||||
wrapperClassName : propsWrapperClassName,
|
||||
useFakeTimer = (1000 * 60) //defaults to 1min
|
||||
useFakeTimer
|
||||
}: LoadingBarProps) => {
|
||||
const [progress, setProgress] = useState<number>(propsProgress);
|
||||
|
||||
// this takes the real progress coming from parent
|
||||
useEffect(()=>{
|
||||
setProgress(propsProgress);
|
||||
}, [propsProgress]);
|
||||
|
||||
// this sets a fake progress, it goes to 96%
|
||||
// in the amount of miliseconds provided by the flag
|
||||
useEffect(()=>{
|
||||
let loop: NodeJS.Timeout;
|
||||
if(useFakeTimer){
|
||||
if(useFakeTimer >= 30000){
|
||||
// this math produce 96 cuts so the progress bar updates more
|
||||
loop = setInterval(function step(){
|
||||
setProgress((curr)=>{
|
||||
if(curr<96){
|
||||
return curr + 3
|
||||
}else{
|
||||
clearInterval(loop);
|
||||
return curr;
|
||||
}
|
||||
})
|
||||
},Math.round(useFakeTimer/96)*3);
|
||||
}else{
|
||||
// this math produce less cuts if useFakeTimer predicts
|
||||
// a shorter load time, shorter thatn 30s
|
||||
const progressPerInterval = useFakeTimer/500
|
||||
loop = loop = setInterval(function step(){
|
||||
setProgress((curr)=>{
|
||||
if(curr + progressPerInterval < 96){
|
||||
return curr + progressPerInterval
|
||||
}else if (curr< 96 && curr + progressPerInterval >= 96){
|
||||
return 96;
|
||||
}else{
|
||||
clearInterval(loop);
|
||||
return curr;
|
||||
}
|
||||
})
|
||||
}, 300);
|
||||
}
|
||||
}
|
||||
return () => clearInterval(loop);
|
||||
}, []);
|
||||
|
||||
function getVariantClassNames(variant: string) {
|
||||
switch (variant) {
|
||||
@@ -40,7 +88,16 @@ export const LoadingBar = ({
|
||||
);
|
||||
|
||||
return (
|
||||
<div className={wrapperClassName}>
|
||||
<Transition
|
||||
className={wrapperClassName}
|
||||
show={isShowing}
|
||||
enter="transition-opacity duration-150"
|
||||
enterFrom="opacity-0"
|
||||
enterTo="opacity-100"
|
||||
leave="transition-opacity duration-1000"
|
||||
leaveFrom="opacity-100"
|
||||
leaveTo="opacity-0"
|
||||
>
|
||||
{label && <label>{label}</label>}
|
||||
<div className="w-full bg-gray-500 rounded-full h-2.5">
|
||||
<div
|
||||
@@ -48,7 +105,7 @@ export const LoadingBar = ({
|
||||
style={{width: progress + '%'}}
|
||||
/>
|
||||
</div>
|
||||
{message && <H4>{message}</H4>}
|
||||
</div>
|
||||
{message && <p>{message}</p>}
|
||||
</Transition>
|
||||
);
|
||||
}
|
||||
@@ -1,22 +1,19 @@
|
||||
import { useState, useEffect } from 'react';
|
||||
import { Transition } from '@headlessui/react';
|
||||
import { twMerge } from 'tailwind-merge';
|
||||
|
||||
import { H4 } from '.';
|
||||
|
||||
interface LoadingDotsProps {
|
||||
className?: string;
|
||||
show?: boolean;
|
||||
transition?: boolean;
|
||||
transitionDuration?: number;
|
||||
isShowing?: boolean;
|
||||
};
|
||||
|
||||
interface LoadingDotsInnerProps {
|
||||
className?: string;
|
||||
show?: boolean;
|
||||
isShowing?: boolean;
|
||||
type?: 'typing'|'bricks';
|
||||
message?: string;
|
||||
transition?: boolean;
|
||||
transitionDuration?: number;
|
||||
};
|
||||
|
||||
export const LoadingDotsTyping = (props: LoadingDotsProps)=>{
|
||||
@@ -32,54 +29,34 @@ export const LoadingDotsBricks = (props: LoadingDotsProps)=>{
|
||||
|
||||
export function LoadingDots({
|
||||
className,
|
||||
show=true,
|
||||
transition = false,
|
||||
isShowing=true,
|
||||
type = 'typing',
|
||||
message,
|
||||
transitionDuration = 1000,
|
||||
}: LoadingDotsInnerProps){
|
||||
const [state, setState] = useState<'loading'|'loaded'|'completed'>('loading');
|
||||
const transitionClasses =
|
||||
(transition ? `transition-opacity duration-${transitionDuration} `: "")
|
||||
+ (state === 'loading' ? 'opacity-100' : 'opacity-0');
|
||||
const classNames = twMerge("w-full h-full flex flex-col justify-center items-center bg-ui-background gap-6", className);
|
||||
|
||||
const classNames = twMerge("w-full h-full flex flex-col justify-center items-center bg-ui-background gap-6",transitionClasses, className);
|
||||
useEffect(()=>{
|
||||
if(!show){
|
||||
if(transition){
|
||||
setState((curr)=>{
|
||||
if (curr === 'loading') return 'loaded'
|
||||
else return curr;
|
||||
});
|
||||
setTimeout(()=>setState('completed'), 2000);
|
||||
} else {
|
||||
setState('completed');
|
||||
return(
|
||||
<Transition
|
||||
className={classNames}
|
||||
show={isShowing}
|
||||
enter="transition-opacity duration-150"
|
||||
enterFrom="opacity-0"
|
||||
enterTo="opacity-100"
|
||||
leave="transition-opacity duration-1000"
|
||||
leaveFrom="opacity-100"
|
||||
leaveTo="opacity-0"
|
||||
>
|
||||
{ type==='typing' &&
|
||||
<div className="dot-typing"></div>
|
||||
}
|
||||
}else{
|
||||
setState((curr) => {
|
||||
if (curr!=='loading') return 'loading';
|
||||
else return curr;
|
||||
});
|
||||
}
|
||||
}, [show, transition]);
|
||||
|
||||
if(state!== 'completed'){
|
||||
return(
|
||||
<div className={classNames}>
|
||||
{ type==='typing' &&
|
||||
<div className="dot-typing"></div>
|
||||
}
|
||||
{ type==='bricks' &&
|
||||
<div className="dot-bricks"></div>
|
||||
}
|
||||
{
|
||||
message &&
|
||||
<H4>{message}</H4>
|
||||
}
|
||||
</div>
|
||||
);
|
||||
}else{
|
||||
return null;
|
||||
}
|
||||
{ type==='bricks' &&
|
||||
<div className="dot-bricks"></div>
|
||||
}
|
||||
{
|
||||
message &&
|
||||
<H4>{message}</H4>
|
||||
}
|
||||
</Transition>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -66,10 +66,9 @@ export const PageEnigmaComponent = () => {
|
||||
}
|
||||
<LoadingDots
|
||||
className="absolute top-0 left-0"
|
||||
show={appUiState.showEditorLoader.isShow}
|
||||
isShowing={appUiState.showEditorLoader.isShow}
|
||||
type="bricks"
|
||||
message={appUiState.showEditorLoader.message}
|
||||
transition
|
||||
/>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ export const PreviewEngineCamera = ()=>{
|
||||
src="/resources/uiAssets/video_player_placeholder.gif"
|
||||
/>
|
||||
<div className="absolute w-full h-full top-0 left-0">
|
||||
<LoadingDotsTyping show={showLoader} transition/>
|
||||
<LoadingDotsTyping isShowing={showLoader}/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -5,7 +5,7 @@ const initialState:State = {
|
||||
timelineHeight: 260,
|
||||
viewMode: VIEW_MODES.EDITOR,
|
||||
showEditorLoader: {
|
||||
isShow:true,
|
||||
isShowing:true,
|
||||
message: 'loading Editor Engine 🦊'
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ export type State = {
|
||||
viewMode: ViewModes;
|
||||
timelineHeight: number;
|
||||
showEditorLoader: {
|
||||
isShow:boolean
|
||||
isShowing:boolean;
|
||||
message:string|undefined;
|
||||
};
|
||||
};
|
||||
|
||||
+15
-18
@@ -1,4 +1,5 @@
|
||||
import { useState, useEffect } from "react";
|
||||
import { Transition } from "@headlessui/react";
|
||||
import { LinksFunction } from "@remix-run/deno";
|
||||
import {
|
||||
Links,
|
||||
@@ -47,13 +48,11 @@ export const links: LinksFunction = () => [
|
||||
export default function App() {
|
||||
const [topBarInnerComponent, setTopBarInnerComponent] =
|
||||
useState<JSX.Element | null>(null);
|
||||
const [isLoaded, setIsLoaded] = useState<'loading'|'loaded'|'completed'>('loading');
|
||||
const [showLoader, setShowLoader] = useState<boolean>(true);
|
||||
useEffect(()=>{
|
||||
setIsLoaded('loaded');
|
||||
setTimeout(()=>setIsLoaded('completed'), 2000);
|
||||
setTimeout(()=>setShowLoader(false), 2500);
|
||||
},[]);
|
||||
|
||||
|
||||
return (
|
||||
<html lang="en">
|
||||
<head>
|
||||
@@ -63,15 +62,7 @@ export default function App() {
|
||||
<Links />
|
||||
</head>
|
||||
<body className="overflow-hidden bg-ui-background">
|
||||
{isLoaded !== 'completed' &&
|
||||
<CompleteTakeoverLoadingScreen
|
||||
className={
|
||||
isLoaded === 'loading'
|
||||
? "transition-opacity duration-1000 opacity-100"
|
||||
: "transition-opacity duration-1000 opacity-0"
|
||||
}
|
||||
/>
|
||||
}
|
||||
<CompleteTakeoverLoadingScreen isShowing={showLoader}/>
|
||||
<TopBarInnerContext.Provider
|
||||
value={{
|
||||
TopBarInner: topBarInnerComponent,
|
||||
@@ -89,11 +80,17 @@ export default function App() {
|
||||
);
|
||||
}
|
||||
|
||||
function CompleteTakeoverLoadingScreen({className}:{className:string}){
|
||||
function CompleteTakeoverLoadingScreen({isShowing}:{isShowing:boolean}){
|
||||
return(
|
||||
<div
|
||||
<Transition
|
||||
id='complete-takeover-loading-screen'
|
||||
className={className}
|
||||
show={isShowing}
|
||||
enter="transition-opacity duration-150"
|
||||
enterFrom="opacity-0"
|
||||
enterTo="opacity-100"
|
||||
leave="transition-opacity duration-1000"
|
||||
leaveFrom="opacity-100"
|
||||
leaveTo="opacity-0"
|
||||
style={{
|
||||
backgroundColor: '#1a1a27',
|
||||
position: 'fixed',
|
||||
@@ -107,7 +104,7 @@ function CompleteTakeoverLoadingScreen({className}:{className:string}){
|
||||
zIndex: 9999,
|
||||
}}
|
||||
>
|
||||
<LoadingDotsBricks />
|
||||
</div>
|
||||
<LoadingDotsBricks />
|
||||
</Transition>
|
||||
);
|
||||
};
|
||||
@@ -1,4 +1,4 @@
|
||||
import { useState, useEffect } from "react";
|
||||
import { useCallback, useEffect, useRef, useState } from "react";
|
||||
import {
|
||||
Button,
|
||||
ButtonLink,
|
||||
@@ -11,20 +11,28 @@ import {
|
||||
|
||||
export default function ComponentLibrary () {
|
||||
const [progress, setProgress] = useState(0);
|
||||
const loopRef = useRef<NodeJS.Timeout | null>(null);
|
||||
|
||||
const pushProgressBar: ()=>void = useCallback(()=>{
|
||||
loopRef.current = setInterval(function timer(){
|
||||
setProgress((curr)=>{
|
||||
if (curr < 100){
|
||||
return curr+10;
|
||||
}else{
|
||||
if(loopRef.current)
|
||||
clearInterval(loopRef.current);
|
||||
return curr;
|
||||
}
|
||||
})}
|
||||
, 3000);
|
||||
}, []);
|
||||
useEffect(()=>{
|
||||
if(progress === 0){
|
||||
const loop = setInterval(function timer(){
|
||||
setProgress((curr)=>{
|
||||
if (curr < 100){
|
||||
return curr+10;
|
||||
}else{
|
||||
clearTimeout(loop);
|
||||
return curr;
|
||||
}
|
||||
})}
|
||||
, 3000);
|
||||
pushProgressBar();
|
||||
return ()=>{
|
||||
if(loopRef.current)
|
||||
clearInterval(loopRef.current)
|
||||
}
|
||||
}, [progress]);
|
||||
},[progress]);
|
||||
|
||||
return(
|
||||
<div className='bg-ui-panel w-10/12 max-w-7xl h-full min-h-96 mx-auto my-6 rounded-lg p-6'>
|
||||
@@ -57,14 +65,31 @@ export default function ComponentLibrary () {
|
||||
|
||||
<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 className="flex gap-2 items-center">
|
||||
<LoadingBar
|
||||
progress={progress}
|
||||
isShowing={progress !== 100}
|
||||
wrapperClassName="rounded-lg"
|
||||
message="this takes progress from parent"
|
||||
/>
|
||||
<Button
|
||||
className="h-fit"
|
||||
onClick={()=>setProgress(0)}
|
||||
>
|
||||
Reset
|
||||
</Button>
|
||||
</div>
|
||||
<LoadingBar
|
||||
label="labeling the bar"
|
||||
message="displaying a message"
|
||||
pulsing
|
||||
/>
|
||||
<LoadingBar
|
||||
label="useFakeTimer = 30000 (30secs)"
|
||||
useFakeTimer={30000}
|
||||
/>
|
||||
<LoadingBar
|
||||
label="useFakeTimer = 3000 (3secs)"
|
||||
useFakeTimer={3000}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in new issue
Block a user