change all loading transitions to use headlessui transitions

This commit is contained in:
wil authored and Quicksticks-oss committed 2024-03-28 14:45:44 -04:00
1 parent a5cd47baeb
commit 9bef1022b6
8 files changed
+151 -96

No files matched your search

+63 -6
View File
@@ -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>
);
}
+27 -50
View File
@@ -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>
);
};
+1 -2
View File
@@ -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>
+1 -1
View File
@@ -5,7 +5,7 @@ const initialState:State = {
timelineHeight: 260,
viewMode: VIEW_MODES.EDITOR,
showEditorLoader: {
isShow:true,
isShowing:true,
message: 'loading Editor Engine 🦊'
}
}
+1 -1
View File
@@ -9,7 +9,7 @@ export type State = {
viewMode: ViewModes;
timelineHeight: number;
showEditorLoader: {
isShow:boolean
isShowing:boolean;
message:string|undefined;
};
};
+15 -18
View File
@@ -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>
);
};
+42 -17
View File
@@ -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>