Files
fotospiel-app/resources/js/admin/mobile/components/OnboardingShell.tsx
Codex Agent b1f9f7cee0
Some checks failed
linter / quality (push) Has been cancelled
tests / ci (push) Has been cancelled
tests / ui (push) Has been cancelled
Fix TypeScript typecheck errors
2026-01-30 15:56:06 +01:00

112 lines
3.2 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';
import { useDocumentTitle } from '../hooks/useDocumentTitle';
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');
useDocumentTitle(title);
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>
);
}