website refactor
This commit is contained in:
59
apps/website/components/onboarding/OnboardingCTA.tsx
Normal file
59
apps/website/components/onboarding/OnboardingCTA.tsx
Normal file
@@ -0,0 +1,59 @@
|
||||
import { Button } from '@/ui/Button';
|
||||
import { Stack } from '@/ui/primitives/Stack';
|
||||
|
||||
interface OnboardingCTAProps {
|
||||
onBack?: () => void;
|
||||
onNext?: () => void;
|
||||
nextLabel?: string;
|
||||
backLabel?: string;
|
||||
isLastStep?: boolean;
|
||||
canNext?: boolean;
|
||||
isLoading?: boolean;
|
||||
type?: 'button' | 'submit';
|
||||
}
|
||||
|
||||
export function OnboardingCTA({
|
||||
onBack,
|
||||
onNext,
|
||||
nextLabel = 'Continue',
|
||||
backLabel = 'Back',
|
||||
isLastStep = false,
|
||||
canNext = true,
|
||||
isLoading = false,
|
||||
type = 'button',
|
||||
}: OnboardingCTAProps) {
|
||||
return (
|
||||
<Stack direction="row" justify="between" mt={8} gap={4}>
|
||||
{onBack ? (
|
||||
<Button
|
||||
type="button"
|
||||
variant="secondary"
|
||||
onClick={onBack}
|
||||
disabled={isLoading}
|
||||
className="px-8"
|
||||
>
|
||||
{backLabel}
|
||||
</Button>
|
||||
) : (
|
||||
<div />
|
||||
)}
|
||||
|
||||
<Button
|
||||
type={type}
|
||||
variant="primary"
|
||||
onClick={onNext}
|
||||
disabled={isLoading || !canNext}
|
||||
className="px-8 min-w-[140px]"
|
||||
>
|
||||
{isLoading ? (
|
||||
<Stack direction="row" gap={2} align="center">
|
||||
<span className="animate-spin">⟳</span>
|
||||
<span>Processing...</span>
|
||||
</Stack>
|
||||
) : (
|
||||
isLastStep ? 'Complete Setup' : nextLabel
|
||||
)}
|
||||
</Button>
|
||||
</Stack>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
export function OnboardingCardAccent() {
|
||||
return (
|
||||
<div className="absolute top-0 right-0 w-40 h-40 bg-gradient-to-bl from-primary-blue/10 to-transparent rounded-bl-full" />
|
||||
);
|
||||
}
|
||||
11
apps/website/components/onboarding/OnboardingContainer.tsx
Normal file
11
apps/website/components/onboarding/OnboardingContainer.tsx
Normal file
@@ -0,0 +1,11 @@
|
||||
interface OnboardingContainerProps {
|
||||
children: React.ReactNode;
|
||||
}
|
||||
|
||||
export function OnboardingContainer({ children }: OnboardingContainerProps) {
|
||||
return (
|
||||
<div className="max-w-3xl mx-auto px-4 py-10">
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
25
apps/website/components/onboarding/OnboardingError.tsx
Normal file
25
apps/website/components/onboarding/OnboardingError.tsx
Normal file
@@ -0,0 +1,25 @@
|
||||
import { Box } from '../../ui/primitives/Box';
|
||||
import { Text } from '../../ui/Text';
|
||||
|
||||
interface OnboardingErrorProps {
|
||||
message: string;
|
||||
}
|
||||
|
||||
export function OnboardingError({ message }: OnboardingErrorProps) {
|
||||
return (
|
||||
<Box
|
||||
mt={6}
|
||||
display="flex"
|
||||
alignItems="start"
|
||||
gap={3}
|
||||
p={4}
|
||||
rounded="xl"
|
||||
bg="bg-red-500/10"
|
||||
border
|
||||
borderColor="border-red-500/30"
|
||||
>
|
||||
<Text color="text-red-400" flexShrink={0} mt={0.5}>⚠</Text>
|
||||
<Text size="sm" color="text-red-400">{message}</Text>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
15
apps/website/components/onboarding/OnboardingForm.tsx
Normal file
15
apps/website/components/onboarding/OnboardingForm.tsx
Normal file
@@ -0,0 +1,15 @@
|
||||
import { FormEvent, ReactNode } from 'react';
|
||||
import { Box } from '../../ui/primitives/Box';
|
||||
|
||||
interface OnboardingFormProps {
|
||||
children: ReactNode;
|
||||
onSubmit: (e: FormEvent) => void;
|
||||
}
|
||||
|
||||
export function OnboardingForm({ children, onSubmit }: OnboardingFormProps) {
|
||||
return (
|
||||
<Box as="form" onSubmit={onSubmit} position="relative">
|
||||
{children}
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
17
apps/website/components/onboarding/OnboardingHeader.tsx
Normal file
17
apps/website/components/onboarding/OnboardingHeader.tsx
Normal file
@@ -0,0 +1,17 @@
|
||||
interface OnboardingHeaderProps {
|
||||
title: string;
|
||||
subtitle: string;
|
||||
emoji: string;
|
||||
}
|
||||
|
||||
export function OnboardingHeader({ title, subtitle, emoji }: OnboardingHeaderProps) {
|
||||
return (
|
||||
<div className="text-center mb-8">
|
||||
<div className="flex h-16 w-16 items-center justify-center rounded-2xl bg-gradient-to-br from-primary-blue/20 to-purple-600/10 border border-primary-blue/30 mx-auto mb-4">
|
||||
<span className="text-2xl">{emoji}</span>
|
||||
</div>
|
||||
<h1 className="text-4xl font-bold mb-2">{title}</h1>
|
||||
<p className="text-gray-400">{subtitle}</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
export function OnboardingHelpText() {
|
||||
return (
|
||||
<p className="text-center text-xs text-gray-500 mt-6">
|
||||
Your avatar will be AI-generated based on your photo and chosen suit color
|
||||
</p>
|
||||
);
|
||||
}
|
||||
58
apps/website/components/onboarding/OnboardingNavigation.tsx
Normal file
58
apps/website/components/onboarding/OnboardingNavigation.tsx
Normal file
@@ -0,0 +1,58 @@
|
||||
import { Button } from '@/ui/Button';
|
||||
|
||||
interface OnboardingNavigationProps {
|
||||
onBack: () => void;
|
||||
onNext?: () => void;
|
||||
isLastStep: boolean;
|
||||
canSubmit: boolean;
|
||||
loading: boolean;
|
||||
}
|
||||
|
||||
export function OnboardingNavigation({ onBack, onNext, isLastStep, canSubmit, loading }: OnboardingNavigationProps) {
|
||||
return (
|
||||
<div className="mt-8 flex items-center justify-between">
|
||||
<Button
|
||||
type="button"
|
||||
variant="secondary"
|
||||
onClick={onBack}
|
||||
disabled={loading}
|
||||
className="flex items-center gap-2"
|
||||
>
|
||||
<span>←</span>
|
||||
Back
|
||||
</Button>
|
||||
|
||||
{!isLastStep ? (
|
||||
<Button
|
||||
type="button"
|
||||
variant="primary"
|
||||
onClick={onNext}
|
||||
disabled={loading}
|
||||
className="flex items-center gap-2"
|
||||
>
|
||||
Continue
|
||||
<span>→</span>
|
||||
</Button>
|
||||
) : (
|
||||
<Button
|
||||
type="submit"
|
||||
variant="primary"
|
||||
disabled={loading || !canSubmit}
|
||||
className="flex items-center gap-2"
|
||||
>
|
||||
{loading ? (
|
||||
<>
|
||||
<span className="animate-spin">⟳</span>
|
||||
Creating Profile...
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<span>✓</span>
|
||||
Complete Setup
|
||||
</>
|
||||
)}
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
22
apps/website/components/onboarding/OnboardingStepHeader.tsx
Normal file
22
apps/website/components/onboarding/OnboardingStepHeader.tsx
Normal file
@@ -0,0 +1,22 @@
|
||||
import { Stack } from '@/ui/primitives/Stack';
|
||||
import { Text } from '@/ui/Text';
|
||||
|
||||
interface OnboardingStepHeaderProps {
|
||||
title: string;
|
||||
description?: string;
|
||||
}
|
||||
|
||||
export function OnboardingStepHeader({ title, description }: OnboardingStepHeaderProps) {
|
||||
return (
|
||||
<Stack gap={1} mb={6}>
|
||||
<Text size="2xl" color="text-white" weight="bold" className="tracking-tight" block>
|
||||
{title}
|
||||
</Text>
|
||||
{description && (
|
||||
<Text size="sm" color="text-gray-400" block>
|
||||
{description}
|
||||
</Text>
|
||||
)}
|
||||
</Stack>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user