upgrade to tamagui v2 and guest pwa overhaul

This commit is contained in:
Codex Agent
2026-02-02 13:01:20 +01:00
parent 2e78f3ab8d
commit 7c6e14ffe2
168 changed files with 47462 additions and 8914 deletions

View File

@@ -262,7 +262,7 @@ export default function MobileQrLayoutCustomizePage() {
<Stepper current={step} onStepChange={setStep} />
<MobileCard space="$2" marginTop="$2">
<MobileCard gap="$2" marginTop="$2">
{step === 'background' && (
<BackgroundStep
onBack={back}
@@ -330,8 +330,8 @@ function Stepper({ current, onStepChange }: { current: Step; onStepChange: (step
const progress = ((currentIndex + 1) / steps.length) * 100;
return (
<YStack space="$2" marginTop="$2">
<XStack space="$2" alignItems="center">
<YStack gap="$2" marginTop="$2">
<XStack gap="$2" alignItems="center">
{steps.map((step, idx) => {
const active = step.key === current;
const completed = idx < currentIndex;
@@ -800,10 +800,10 @@ function BackgroundStep({
];
return (
<YStack space="$3" marginTop="$2">
<XStack alignItems="center" space="$2">
<YStack gap="$3" marginTop="$2">
<XStack alignItems="center" gap="$2">
<Pressable onPress={onBack}>
<XStack alignItems="center" space="$1">
<XStack alignItems="center" gap="$1">
<ArrowLeft size={16} color={textStrong} />
<Text fontSize="$sm" color={textStrong}>
{t('common.back', 'Zurück')}
@@ -813,7 +813,7 @@ function BackgroundStep({
<PillBadge tone="muted">{formatLabel}</PillBadge>
</XStack>
<YStack space="$2">
<YStack gap="$2">
<Text fontSize="$sm" fontWeight="700" color={textStrong}>
{disablePresets
? t('events.qr.backgroundPickerFoldable', 'Hintergrund für A5 (Gradient/Farbe)')
@@ -859,7 +859,7 @@ function BackgroundStep({
</>
) : null}
<YStack space="$2" marginTop="$2">
<YStack gap="$2" marginTop="$2">
<Text fontSize="$sm" fontWeight="700" color={textStrong}>
{t('events.qr.gradients', 'Gradienten')}
</Text>
@@ -894,7 +894,7 @@ function BackgroundStep({
</XStack>
</YStack>
<YStack space="$2" marginTop="$2">
<YStack gap="$2" marginTop="$2">
<Text fontSize="$sm" fontWeight="700" color={textStrong}>
{t('events.qr.colors', 'Vollfarbe')}
</Text>
@@ -966,10 +966,10 @@ function TextStep({
};
return (
<YStack space="$3" marginTop="$2">
<XStack alignItems="center" space="$2">
<YStack gap="$3" marginTop="$2">
<XStack alignItems="center" gap="$2">
<Pressable onPress={onBack}>
<XStack alignItems="center" space="$1">
<XStack alignItems="center" gap="$1">
<ArrowLeft size={16} color={textStrong} />
<Text fontSize="$sm" color={textStrong}>
{t('common.back', 'Zurück')}
@@ -979,7 +979,7 @@ function TextStep({
<PillBadge tone="muted">{t('events.qr.textStep', 'Texte & Hinweise')}</PillBadge>
</XStack>
<YStack space="$2">
<YStack gap="$2">
<Text fontSize="$sm" fontWeight="700" color={textStrong}>
{t('events.qr.textFields', 'Texte')}
</Text>
@@ -1000,12 +1000,12 @@ function TextStep({
/>
</YStack>
<YStack space="$2">
<YStack gap="$2">
<Text fontSize="$sm" fontWeight="700" color={textStrong}>
{t('events.qr.instructions', 'Anleitung')}
</Text>
{textFields.instructions.map((item, idx) => (
<XStack key={idx} alignItems="center" space="$2">
<XStack key={idx} alignItems="center" gap="$2">
<MobileTextArea
value={item}
onChange={(event) => updateInstruction(idx, event.target.value)}
@@ -1196,10 +1196,10 @@ function PreviewStep({
const qrImageSrc = qrPngUrl ?? qrUrl ?? '';
return (
<YStack space="$3" marginTop="$2">
<XStack alignItems="center" space="$2">
<YStack gap="$3" marginTop="$2">
<XStack alignItems="center" gap="$2">
<Pressable onPress={onBack}>
<XStack alignItems="center" space="$1">
<XStack alignItems="center" gap="$1">
<ArrowLeft size={16} color={textStrong} />
<Text fontSize="$sm" color={textStrong}>
{t('common.back', 'Zurück')}
@@ -1211,7 +1211,7 @@ function PreviewStep({
</PillBadge>
</XStack>
<YStack space="$2">
<YStack gap="$2">
<Text fontSize="$sm" fontWeight="700" color={textStrong}>
{t('events.qr.preview', 'Vorschau')}
</Text>
@@ -1243,7 +1243,7 @@ function PreviewStep({
<LayoutControls slots={resolvedSlots} slotOverrides={slotOverrides} onUpdateSlot={onUpdateSlot} tenantFonts={tenantFonts} qrUrl={qrImageSrc} />
<XStack space="$2" width="100%" flexWrap="wrap">
<XStack gap="$2" width="100%" flexWrap="wrap">
<CTAButton
label={t('events.qr.exportPdf', 'Export PDF')}
onPress={async () => {
@@ -1318,7 +1318,7 @@ function LayoutControls({
const decimals = step % 1 === 0 ? 0 : Math.min(4, `${step}`.split('.')[1]?.length ?? 1);
const formatValue = (val: number) => val.toFixed(decimals);
return (
<XStack space="$1" alignItems="center">
<XStack gap="$1" alignItems="center">
<Pressable onPress={dec}>
<XStack width={36} height={36} borderRadius={10} alignItems="center" justifyContent="center" borderWidth={1} borderColor={border} backgroundColor={surface}>
<Text fontSize="$md" fontWeight="800" color={textStrong}>
@@ -1398,13 +1398,13 @@ function LayoutControls({
</XStack>
</Accordion.Trigger>
<Accordion.Content {...({ paddingTop: "$2" } as any)}>
<YStack space="$2" padding="$2" borderWidth={1} borderColor={border} borderRadius={12}>
<XStack space="$3">
<YStack flex={1} space="$1">
<YStack gap="$2" padding="$2" borderWidth={1} borderColor={border} borderRadius={12}>
<XStack gap="$3">
<YStack flex={1} gap="$1">
<Text fontSize="$xs" color={muted}>
{t('events.qr.positionX', 'X (%)')}
</Text>
<XStack space="$2" alignItems="center">
<XStack gap="$2" alignItems="center">
<StepperInput
value={currentX * 100}
min={0}
@@ -1428,7 +1428,7 @@ function LayoutControls({
</Pressable>
</XStack>
</YStack>
<YStack flex={1} space="$1">
<YStack flex={1} gap="$1">
<Text fontSize="$xs" color={muted}>
{t('events.qr.positionY', 'Y (%)')}
</Text>
@@ -1440,7 +1440,7 @@ function LayoutControls({
onChange={(val) => onPercentChange('y')(val)}
/>
</YStack>
<YStack flex={1} space="$1">
<YStack flex={1} gap="$1">
<Text fontSize="$xs" color={muted}>
{t('events.qr.width', 'Breite (%)')}
</Text>
@@ -1454,14 +1454,14 @@ function LayoutControls({
</YStack>
</XStack>
<XStack space="$3">
<YStack flex={1} space="$1">
<XStack gap="$3">
<YStack flex={1} gap="$1">
<Text fontSize="$xs" color={muted}>
{t('events.qr.fontSize', 'Font Size (px)')}
</Text>
<StepperInput value={override.fontSize ?? slot.fontSize ?? 16} min={8} max={200} step={1} onChange={(val) => onFontSizeChange(val)} />
</YStack>
<YStack flex={1} space="$1">
<YStack flex={1} gap="$1">
<Text fontSize="$xs" color={muted}>
{t('events.qr.fontFamily', 'Font Family')}
</Text>
@@ -1477,12 +1477,12 @@ function LayoutControls({
))}
</MobileSelect>
</YStack>
<YStack flex={1} space="$1">
<YStack flex={1} gap="$1">
<Text fontSize="$xs" color={muted}>
{t('events.qr.fontColor', 'Schriftfarbe')}
</Text>
<YStack space="$2">
<XStack space="$2" alignItems="center">
<YStack gap="$2">
<XStack gap="$2" alignItems="center">
<Pressable onPress={() => setOpenColorSlot(openColorSlot === slotKey ? null : slotKey)}>
<XStack
width={48}
@@ -1536,7 +1536,7 @@ function LayoutControls({
onChange={(val) => onUpdateSlot(slotKey, { color: val })}
style={{ width: 240, height: 200 }}
/>
<XStack space="$2" justifyContent="flex-end">
<XStack gap="$2" justifyContent="flex-end">
<Pressable onPress={() => setOpenColorSlot(null)}>
<XStack
paddingHorizontal="$3"
@@ -1560,8 +1560,8 @@ function LayoutControls({
</YStack>
</XStack>
<XStack space="$2">
<YStack flex={1} space="$1">
<XStack gap="$2">
<YStack flex={1} gap="$1">
<Text fontSize="$xs" color={muted}>
{t('events.qr.align', 'Align')}
</Text>
@@ -1574,7 +1574,7 @@ function LayoutControls({
<option value="right">{t('common.right', 'Rechts')}</option>
</MobileSelect>
</YStack>
<YStack flex={1} space="$1">
<YStack flex={1} gap="$1">
<Text fontSize="$xs" color={muted}>
{t('events.qr.lineHeight', 'Line Height')}
</Text>
@@ -1606,7 +1606,7 @@ function LayoutControls({
const accordionDefaults = ['headline'];
return (
<YStack space="$3" marginTop="$2">
<YStack gap="$3" marginTop="$2">
<Text fontSize="$sm" fontWeight="700" color={textStrong}>
{t('events.qr.layoutControls', 'Layout & Schrift')}
</Text>
@@ -1627,9 +1627,9 @@ function LayoutControls({
</XStack>
</Accordion.Trigger>
<Accordion.Content {...({ paddingTop: "$2" } as any)}>
<YStack space="$2" padding="$2" borderWidth={1} borderColor={border} borderRadius={12}>
<XStack space="$2">
<YStack flex={1} space="$1">
<YStack gap="$2" padding="$2" borderWidth={1} borderColor={border} borderRadius={12}>
<XStack gap="$2">
<YStack flex={1} gap="$1">
<Text fontSize="$xs" color={muted}>
{t('events.qr.positionX', 'X (%)')}
</Text>
@@ -1641,7 +1641,7 @@ function LayoutControls({
onChange={(val) => onQrPercentChange('x')(val)}
/>
</YStack>
<YStack flex={1} space="$1">
<YStack flex={1} gap="$1">
<Text fontSize="$xs" color={muted}>
{t('events.qr.positionY', 'Y (%)')}
</Text>
@@ -1653,7 +1653,7 @@ function LayoutControls({
onChange={(val) => onQrPercentChange('y')(val)}
/>
</YStack>
<YStack flex={1} space="$1">
<YStack flex={1} gap="$1">
<Text fontSize="$xs" color={muted}>
{t('events.qr.size', 'Größe (%)')}
</Text>