whisper-money/resources/js/layouts/onboarding-layout.tsx

77 lines
2.6 KiB
TypeScript

import AppLogoIcon from '@/components/app-logo-icon';
import { cn } from '@/lib/utils';
import { type PropsWithChildren, useEffect, useState } from 'react';
interface OnboardingLayoutProps {
currentStep: number;
totalSteps: number;
stepKey: string;
align?: 'start' | 'center';
}
export default function OnboardingLayout({
children,
currentStep,
totalSteps,
stepKey,
align = 'start',
}: PropsWithChildren<OnboardingLayoutProps>) {
const [isVisible, setIsVisible] = useState(false);
useEffect(() => {
setIsVisible(false);
const timer = setTimeout(() => setIsVisible(true), 50);
return () => clearTimeout(timer);
}, [stepKey]);
return (
<div className="flex min-h-svh flex-col bg-background">
<header className="pt-safe flex items-center justify-between p-4 md:p-6">
<AppLogoIcon
className={cn([
'size-6 fill-current text-[var(--foreground)] sm:opacity-75 dark:text-white',
{ 'opacity-0': currentStep === 0 },
])}
/>
<div className="flex items-center gap-2">
{Array.from({ length: totalSteps }).map((_, index) => (
<div
key={index}
className={cn(
'h-2 w-2 rounded-full transition-all duration-300',
index < currentStep
? 'bg-primary'
: index === currentStep
? 'scale-125 bg-primary'
: 'bg-primary/15',
)}
/>
))}
</div>
<div className="size-6"></div>
</header>
<main
className={cn(
'flex flex-1 flex-col items-center justify-start px-4 pt-12 pb-12 md:px-6',
align === 'center' && 'sm:justify-center',
)}
>
<div
key={stepKey}
className={cn(
'w-full max-w-2xl transition-all duration-300 ease-out',
isVisible
? 'translate-y-0 opacity-100'
: 'translate-y-5 opacity-0',
)}
>
{children}
</div>
</main>
</div>
);
}