Fix auth translations and admin PWA UI
This commit is contained in:
@@ -5,12 +5,12 @@ import { ArrowLeft, RefreshCcw, Plus, ChevronDown } 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 { Input, TextArea } from 'tamagui';
|
||||
import { Accordion } from '@tamagui/accordion';
|
||||
import { HexColorPicker } from 'react-colorful';
|
||||
import { Portal } from '@tamagui/portal';
|
||||
import { MobileShell, HeaderActionButton } from './components/MobileShell';
|
||||
import { MobileCard, CTAButton, PillBadge } from './components/Primitives';
|
||||
import { MobileInput, MobileSelect, MobileTextArea } from './components/FormControls';
|
||||
import {
|
||||
TenantEvent,
|
||||
EventQrInvite,
|
||||
@@ -753,7 +753,7 @@ function BackgroundStep({
|
||||
{presets.map((preset) => {
|
||||
const isSelected = selectedPreset === preset.id;
|
||||
return (
|
||||
<Pressable key={preset.id} onPress={() => onSelectPreset(preset.id)} style={{ width: '48%' }}>
|
||||
<Pressable key={preset.id ?? preset.labelKey} onPress={() => onSelectPreset(preset.id)} style={{ width: '48%' }}>
|
||||
<YStack
|
||||
aspectRatio={210 / 297}
|
||||
maxHeight={220}
|
||||
@@ -795,7 +795,7 @@ function BackgroundStep({
|
||||
{t('events.qr.gradients', 'Gradienten')}
|
||||
</Text>
|
||||
<XStack flexWrap="wrap" gap="$2">
|
||||
{gradientPresets.map((gradient, idx) => {
|
||||
{gradientPresets.map((gradient) => {
|
||||
const isSelected =
|
||||
selectedGradient &&
|
||||
selectedGradient.angle === gradient.angle &&
|
||||
@@ -803,9 +803,10 @@ function BackgroundStep({
|
||||
const style = {
|
||||
backgroundImage: `linear-gradient(${gradient.angle}deg, ${gradient.stops.join(',')})`,
|
||||
} as React.CSSProperties;
|
||||
const key = `${gradient.labelKey}-${gradient.angle}`;
|
||||
return (
|
||||
<Pressable
|
||||
key={idx}
|
||||
key={key}
|
||||
onPress={() => onSelectGradient(gradient)}
|
||||
style={{ width: '30%' }}
|
||||
aria-label={t(gradient.labelKey, gradient.label)}
|
||||
@@ -829,10 +830,11 @@ function BackgroundStep({
|
||||
{t('events.qr.colors', 'Vollfarbe')}
|
||||
</Text>
|
||||
<XStack flexWrap="wrap" gap="$2">
|
||||
{solidPresets.map((color) => {
|
||||
{solidPresets.map((color, idx) => {
|
||||
const isSelected = selectedSolid === color;
|
||||
const key = `${color}-${idx}`;
|
||||
return (
|
||||
<Pressable key={color} onPress={() => onSelectSolid(color)} style={{ width: '20%' }}>
|
||||
<Pressable key={key} onPress={() => onSelectSolid(color)} style={{ width: '20%' }}>
|
||||
<YStack
|
||||
height={50}
|
||||
borderRadius={12}
|
||||
@@ -912,24 +914,20 @@ function TextStep({
|
||||
<Text fontSize="$sm" fontWeight="700" color={textStrong}>
|
||||
{t('events.qr.textFields', 'Texte')}
|
||||
</Text>
|
||||
<Input
|
||||
<MobileInput
|
||||
placeholder={t('events.qr.headline', 'Headline')}
|
||||
value={textFields.headline}
|
||||
onChangeText={(val) => updateField('headline', val)}
|
||||
size="$4"
|
||||
onChange={(event) => updateField('headline', event.target.value)}
|
||||
/>
|
||||
<Input
|
||||
<MobileInput
|
||||
placeholder={t('events.qr.subtitle', 'Subtitle')}
|
||||
value={textFields.subtitle}
|
||||
onChangeText={(val) => updateField('subtitle', val)}
|
||||
size="$4"
|
||||
onChange={(event) => updateField('subtitle', event.target.value)}
|
||||
/>
|
||||
<TextArea
|
||||
<MobileTextArea
|
||||
placeholder={t('events.qr.bottomNote', 'Unterer Hinweistext')}
|
||||
value={textFields.description}
|
||||
onChangeText={(val) => updateField('description', val)}
|
||||
size="$4"
|
||||
numberOfLines={3}
|
||||
onChange={(event) => updateField('description', event.target.value)}
|
||||
/>
|
||||
</YStack>
|
||||
|
||||
@@ -939,13 +937,12 @@ function TextStep({
|
||||
</Text>
|
||||
{textFields.instructions.map((item, idx) => (
|
||||
<XStack key={idx} alignItems="center" space="$2">
|
||||
<TextArea
|
||||
<MobileTextArea
|
||||
value={item}
|
||||
onChangeText={(val) => updateInstruction(idx, val)}
|
||||
onChange={(event) => updateInstruction(idx, event.target.value)}
|
||||
placeholder={t('events.qr.instructionsPlaceholder', 'Schritt hinzufügen')}
|
||||
numberOfLines={2}
|
||||
{...({ flex: 1 } as any)}
|
||||
size="$4"
|
||||
style={{ flex: 1 }}
|
||||
compact
|
||||
/>
|
||||
<Pressable onPress={() => removeInstruction(idx)} disabled={textFields.instructions.length === 1}>
|
||||
<XStack
|
||||
@@ -1204,36 +1201,13 @@ function LayoutControls({
|
||||
}) {
|
||||
const { t } = useTranslation('management');
|
||||
const [openColorSlot, setOpenColorSlot] = React.useState<string | null>(null);
|
||||
const { border, surface, surfaceMuted, text, textStrong, muted, overlay, shadow, danger } = useAdminTheme();
|
||||
const { border, surface, surfaceMuted, textStrong, muted, overlay, shadow, danger } = useAdminTheme();
|
||||
const fontOptions = React.useMemo(() => {
|
||||
const preset = ['Archivo Black', 'Manrope', 'Inter', 'Roboto', 'Lora'];
|
||||
const tenant = tenantFonts.map((font) => font.family);
|
||||
return Array.from(new Set([...tenant, ...preset]));
|
||||
}, [tenantFonts]);
|
||||
|
||||
const numberInputStyle: React.CSSProperties = {
|
||||
width: 90,
|
||||
padding: '10px 12px',
|
||||
border: `1px solid ${border}`,
|
||||
borderRadius: 12,
|
||||
fontSize: 14,
|
||||
fontFamily: DEFAULT_BODY_FONT,
|
||||
background: surfaceMuted,
|
||||
color: text,
|
||||
appearance: 'textfield',
|
||||
};
|
||||
|
||||
const selectStyle: React.CSSProperties = {
|
||||
width: '100%',
|
||||
padding: '10px 12px',
|
||||
border: `1px solid ${border}`,
|
||||
borderRadius: 12,
|
||||
fontSize: 14,
|
||||
fontFamily: DEFAULT_BODY_FONT,
|
||||
background: surfaceMuted,
|
||||
color: text,
|
||||
};
|
||||
|
||||
const StepperInput = ({
|
||||
value,
|
||||
min,
|
||||
@@ -1260,11 +1234,9 @@ function LayoutControls({
|
||||
</Text>
|
||||
</XStack>
|
||||
</Pressable>
|
||||
<input
|
||||
<MobileInput
|
||||
type="text"
|
||||
inputMode="decimal"
|
||||
min={min}
|
||||
max={max}
|
||||
value={formatValue(value)}
|
||||
onChange={(event) => {
|
||||
const next = Number(event.target.value);
|
||||
@@ -1272,7 +1244,13 @@ function LayoutControls({
|
||||
onChange(next);
|
||||
}
|
||||
}}
|
||||
style={numberInputStyle}
|
||||
compact
|
||||
style={{
|
||||
width: 90,
|
||||
textAlign: 'center',
|
||||
fontFamily: DEFAULT_BODY_FONT,
|
||||
backgroundColor: surfaceMuted,
|
||||
}}
|
||||
/>
|
||||
<Pressable onPress={inc}>
|
||||
<XStack width={36} height={36} borderRadius={10} alignItems="center" justifyContent="center" borderWidth={1} borderColor={border} backgroundColor={surface}>
|
||||
@@ -1395,10 +1373,9 @@ function LayoutControls({
|
||||
<Text fontSize="$xs" color={muted}>
|
||||
{t('events.qr.fontFamily', 'Font Family')}
|
||||
</Text>
|
||||
<select
|
||||
<MobileSelect
|
||||
value={override.fontFamily ?? slot.fontFamily ?? ''}
|
||||
onChange={(event) => onFontFamilyChange(event.target.value)}
|
||||
style={selectStyle}
|
||||
>
|
||||
<option value="">{t('events.qr.defaultFont', 'Standard')}</option>
|
||||
{fontOptions.map((family) => (
|
||||
@@ -1406,7 +1383,7 @@ function LayoutControls({
|
||||
{family}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
</MobileSelect>
|
||||
</YStack>
|
||||
<YStack flex={1} space="$1">
|
||||
<Text fontSize="$xs" color={muted}>
|
||||
@@ -1424,12 +1401,12 @@ function LayoutControls({
|
||||
backgroundColor={override.color ?? slot.color ?? textStrong}
|
||||
/>
|
||||
</Pressable>
|
||||
<input
|
||||
type="text"
|
||||
<MobileInput
|
||||
value={override.color ?? slot.color ?? ''}
|
||||
placeholder={ADMIN_COLORS.text}
|
||||
onChange={(event) => onUpdateSlot(slotKey, { color: event.target.value })}
|
||||
style={{ ...numberInputStyle, width: 110 }}
|
||||
compact
|
||||
style={{ width: 110, backgroundColor: surfaceMuted }}
|
||||
/>
|
||||
</XStack>
|
||||
{openColorSlot === slotKey ? (
|
||||
@@ -1496,15 +1473,14 @@ function LayoutControls({
|
||||
<Text fontSize="$xs" color={muted}>
|
||||
{t('events.qr.align', 'Align')}
|
||||
</Text>
|
||||
<select
|
||||
<MobileSelect
|
||||
value={override.align ?? slot.align ?? 'left'}
|
||||
onChange={(event) => onUpdateSlot(slotKey, { align: event.target.value as SlotDefinition['align'] })}
|
||||
style={selectStyle}
|
||||
>
|
||||
<option value="left">{t('common.left', 'Links')}</option>
|
||||
<option value="center">{t('common.center', 'Zentriert')}</option>
|
||||
<option value="right">{t('common.right', 'Rechts')}</option>
|
||||
</select>
|
||||
</MobileSelect>
|
||||
</YStack>
|
||||
<YStack flex={1} space="$1">
|
||||
<Text fontSize="$xs" color={muted}>
|
||||
|
||||
Reference in New Issue
Block a user