109 lines
3.1 KiB
TypeScript
109 lines
3.1 KiB
TypeScript
import React from 'react';
|
|
import { ChevronLeft } from 'lucide-react';
|
|
import { YStack, XStack } from '@tamagui/stacks';
|
|
import { SizableText as Text } from '@tamagui/text';
|
|
import { Pressable } from '@tamagui/react-native-web-lite';
|
|
import { useTranslation } from 'react-i18next';
|
|
import { useAdminTheme } from '../theme';
|
|
|
|
type OnboardingShellProps = {
|
|
eyebrow?: string;
|
|
title: string;
|
|
subtitle?: string;
|
|
children: React.ReactNode;
|
|
onBack?: () => void;
|
|
onSkip?: () => void;
|
|
footer?: React.ReactNode;
|
|
backLabel?: string;
|
|
skipLabel?: string;
|
|
};
|
|
|
|
export function OnboardingShell({
|
|
eyebrow,
|
|
title,
|
|
subtitle,
|
|
children,
|
|
onBack,
|
|
onSkip,
|
|
footer,
|
|
backLabel,
|
|
skipLabel,
|
|
}: OnboardingShellProps) {
|
|
const { t } = useTranslation('onboarding');
|
|
const { background, surface, text, textStrong, muted, border, shadow } = useAdminTheme();
|
|
const resolvedBackLabel = backLabel ?? t('layout.back', 'Back');
|
|
const resolvedSkipLabel = skipLabel ?? t('layout.skip', 'Skip');
|
|
|
|
return (
|
|
<YStack minHeight="100vh" backgroundColor={background} alignItems="center">
|
|
<YStack
|
|
width="100%"
|
|
maxWidth={860}
|
|
paddingHorizontal="$5"
|
|
paddingTop="$5"
|
|
paddingBottom="$6"
|
|
space="$4"
|
|
style={{
|
|
paddingTop: 'calc(env(safe-area-inset-top, 0px) + 20px)',
|
|
paddingBottom: 'calc(env(safe-area-inset-bottom, 0px) + 24px)',
|
|
}}
|
|
>
|
|
<XStack alignItems="center" justifyContent="space-between">
|
|
{onBack ? (
|
|
<Pressable onPress={onBack} aria-label={resolvedBackLabel}>
|
|
<XStack alignItems="center" space="$1.5">
|
|
<ChevronLeft size={22} color={text} />
|
|
<Text fontSize="$sm" fontWeight="700" color={text}>
|
|
{resolvedBackLabel}
|
|
</Text>
|
|
</XStack>
|
|
</Pressable>
|
|
) : (
|
|
<XStack width={64} />
|
|
)}
|
|
|
|
{onSkip ? (
|
|
<Pressable onPress={onSkip} aria-label={resolvedSkipLabel}>
|
|
<Text fontSize="$sm" fontWeight="700" color={muted}>
|
|
{resolvedSkipLabel}
|
|
</Text>
|
|
</Pressable>
|
|
) : (
|
|
<XStack width={64} />
|
|
)}
|
|
</XStack>
|
|
|
|
<YStack
|
|
padding="$4"
|
|
borderRadius={20}
|
|
borderWidth={1}
|
|
borderColor={border}
|
|
backgroundColor={surface}
|
|
shadowColor={shadow}
|
|
shadowOpacity={0.06}
|
|
shadowRadius={14}
|
|
shadowOffset={{ width: 0, height: 8 }}
|
|
space="$2"
|
|
>
|
|
{eyebrow ? (
|
|
<Text fontSize="$xs" fontWeight="700" color={muted} textTransform="uppercase" letterSpacing={0.6}>
|
|
{eyebrow}
|
|
</Text>
|
|
) : null}
|
|
<Text fontSize="$xl" fontWeight="900" color={textStrong}>
|
|
{title}
|
|
</Text>
|
|
{subtitle ? (
|
|
<Text fontSize="$sm" color={muted}>
|
|
{subtitle}
|
|
</Text>
|
|
) : null}
|
|
</YStack>
|
|
|
|
<YStack space="$4">{children}</YStack>
|
|
{footer ? <YStack marginTop="$2">{footer}</YStack> : null}
|
|
</YStack>
|
|
</YStack>
|
|
);
|
|
}
|