generated from knso/webklar-preview-template
App Phase 2: Antwort-Assistent als 3-Schritte-Assistent (Design-Layout)
- Fortschrittsbalken + 'Schritt X von 3' - Schritt 1: Antwort-Art als Karten (Icon + Beschreibung, 'Empfohlen'-Tag fuer die vom Brief vorgeschlagenen Typen) - Schritt 2: optionale Angaben + Info-Box (Aktenzeichen/Behoerde kommen automatisch aus dem Brief), dann KI-Entwurf - Schritt 3: Entwurf pruefen/bearbeiten + PDF-Export + Teilen - alle Funktionen erhalten (generiereAntwort, sichern, PDF, Teilen); bei vorhandenem Entwurf Start direkt in Schritt 3 - warme Design-Farben durchs zentrale Theme Typecheck + 30 Tests gruen. Visuelle Pruefung (Analyse + Antwort) im Simulator steht noch aus. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -1,12 +1,15 @@
|
|||||||
/**
|
/**
|
||||||
* Antwort-Generator: Vorlage wählen -> KI-Entwurf -> frei bearbeiten ->
|
* Antwort-Assistent — 3-Schritte-Assistent nach dem Claude-Design-Entwurf:
|
||||||
* als PDF exportieren oder als Text teilen.
|
* 1. Antwort-Art wählen 2. Angaben ergänzen 3. Entwurf prüfen & exportieren
|
||||||
|
* Der KI-Entwurf (generiereAntwort) bleibt das Herzstück; nur die Führung ist
|
||||||
|
* jetzt klar in Schritte gegliedert, mit Fortschrittsbalken.
|
||||||
*/
|
*/
|
||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
import {
|
import {
|
||||||
Alert,
|
Alert,
|
||||||
KeyboardAvoidingView,
|
KeyboardAvoidingView,
|
||||||
Platform,
|
Platform,
|
||||||
|
Pressable,
|
||||||
ScrollView,
|
ScrollView,
|
||||||
Share,
|
Share,
|
||||||
StyleSheet,
|
StyleSheet,
|
||||||
@@ -22,6 +25,7 @@ import { useAppStore } from '../store/useAppStore';
|
|||||||
import { generiereAntwort } from '../services/antwort';
|
import { generiereAntwort } from '../services/antwort';
|
||||||
import { ClaudeFehler } from '../services/claudeClient';
|
import { ClaudeFehler } from '../services/claudeClient';
|
||||||
import { GrossButton } from '../components/GrossButton';
|
import { GrossButton } from '../components/GrossButton';
|
||||||
|
import { Ikone, IkonenName } from '../components/Ikone';
|
||||||
import { farben, schrift, abstand } from '../theme';
|
import { farben, schrift, abstand } from '../theme';
|
||||||
|
|
||||||
type Props = NativeStackScreenProps<RootStackParamList, 'Antwort'>;
|
type Props = NativeStackScreenProps<RootStackParamList, 'Antwort'>;
|
||||||
@@ -34,10 +38,19 @@ const ALLE_TYPEN: AntwortTyp[] = [
|
|||||||
'rueckfrage',
|
'rueckfrage',
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const TYP_INFO: Record<AntwortTyp, { ikone: IkonenName; beschreibung: string }> = {
|
||||||
|
terminbestaetigung: { ikone: 'checkAn', beschreibung: 'Sie bestätigen, dass Sie zum Termin kommen.' },
|
||||||
|
terminverschiebung: { ikone: 'kalender', beschreibung: 'Sie bitten um einen neuen Termin.' },
|
||||||
|
widerspruch: { ikone: 'warnung', beschreibung: 'Sie sind nicht einverstanden und legen Einspruch ein.' },
|
||||||
|
unterlagen_nachreichen: { ikone: 'dokument', beschreibung: 'Sie reichen die geforderten Unterlagen ein.' },
|
||||||
|
rueckfrage: { ikone: 'info', beschreibung: 'Sie haben eine Frage zum Brief.' },
|
||||||
|
};
|
||||||
|
|
||||||
export function AntwortScreen({ route }: Props) {
|
export function AntwortScreen({ route }: Props) {
|
||||||
const brief = useAppStore((s) => s.briefe.find((b) => b.id === route.params.briefId));
|
const brief = useAppStore((s) => s.briefe.find((b) => b.id === route.params.briefId));
|
||||||
const setzeAntwortEntwurf = useAppStore((s) => s.setzeAntwortEntwurf);
|
const setzeAntwortEntwurf = useAppStore((s) => s.setzeAntwortEntwurf);
|
||||||
|
|
||||||
|
const [schritt, setSchritt] = useState<1 | 2 | 3>(brief?.antwortEntwurf?.text ? 3 : 1);
|
||||||
const [typ, setTyp] = useState<AntwortTyp | null>(brief?.antwortEntwurf?.typ ?? null);
|
const [typ, setTyp] = useState<AntwortTyp | null>(brief?.antwortEntwurf?.typ ?? null);
|
||||||
const [hinweise, setHinweise] = useState('');
|
const [hinweise, setHinweise] = useState('');
|
||||||
const [betreff, setBetreff] = useState(brief?.antwortEntwurf?.betreff ?? '');
|
const [betreff, setBetreff] = useState(brief?.antwortEntwurf?.betreff ?? '');
|
||||||
@@ -52,12 +65,16 @@ export function AntwortScreen({ route }: Props) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Vom Brief vorgeschlagene Vorlagen zuerst, Rest danach
|
|
||||||
const optionen = [
|
const optionen = [
|
||||||
...brief.analyse.antwort_optionen,
|
...brief.analyse.antwort_optionen,
|
||||||
...ALLE_TYPEN.filter((t) => !brief.analyse.antwort_optionen.includes(t)),
|
...ALLE_TYPEN.filter((t) => !brief.analyse.antwort_optionen.includes(t)),
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const typWaehlen = (t: AntwortTyp) => {
|
||||||
|
setTyp(t);
|
||||||
|
setSchritt(2);
|
||||||
|
};
|
||||||
|
|
||||||
const erzeugen = async () => {
|
const erzeugen = async () => {
|
||||||
if (!typ) return;
|
if (!typ) return;
|
||||||
setLaedt(true);
|
setLaedt(true);
|
||||||
@@ -66,6 +83,7 @@ export function AntwortScreen({ route }: Props) {
|
|||||||
setBetreff(entwurf.betreff);
|
setBetreff(entwurf.betreff);
|
||||||
setText(entwurf.text);
|
setText(entwurf.text);
|
||||||
await setzeAntwortEntwurf(brief.id, { typ, ...entwurf });
|
await setzeAntwortEntwurf(brief.id, { typ, ...entwurf });
|
||||||
|
setSchritt(3);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
Alert.alert(
|
Alert.alert(
|
||||||
'Fehler',
|
'Fehler',
|
||||||
@@ -76,17 +94,13 @@ export function AntwortScreen({ route }: Props) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Bearbeiteten Stand sichern (beim Export/Teilen automatisch). */
|
|
||||||
const sichern = async () => {
|
const sichern = async () => {
|
||||||
if (typ && text) {
|
if (typ && text) await setzeAntwortEntwurf(brief.id, { typ, betreff, text });
|
||||||
await setzeAntwortEntwurf(brief.id, { typ, betreff, text });
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const alsPdf = async () => {
|
const alsPdf = async () => {
|
||||||
await sichern();
|
await sichern();
|
||||||
try {
|
try {
|
||||||
// Einfaches, sauberes Brief-Layout für den Ausdruck
|
|
||||||
const html = `
|
const html = `
|
||||||
<html><head><meta charset="utf-8"><style>
|
<html><head><meta charset="utf-8"><style>
|
||||||
body { font-family: Helvetica, Arial, sans-serif; font-size: 12pt; margin: 2.5cm; color: #111; }
|
body { font-family: Helvetica, Arial, sans-serif; font-size: 12pt; margin: 2.5cm; color: #111; }
|
||||||
@@ -98,10 +112,7 @@ export function AntwortScreen({ route }: Props) {
|
|||||||
</body></html>`;
|
</body></html>`;
|
||||||
const { uri } = await Print.printToFileAsync({ html });
|
const { uri } = await Print.printToFileAsync({ html });
|
||||||
if (await Sharing.isAvailableAsync()) {
|
if (await Sharing.isAvailableAsync()) {
|
||||||
await Sharing.shareAsync(uri, {
|
await Sharing.shareAsync(uri, { mimeType: 'application/pdf', dialogTitle: 'Antwort als PDF' });
|
||||||
mimeType: 'application/pdf',
|
|
||||||
dialogTitle: 'Antwort als PDF',
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
} catch {
|
} catch {
|
||||||
Alert.alert('Fehler', 'Das PDF konnte nicht erstellt werden.');
|
Alert.alert('Fehler', 'Das PDF konnte nicht erstellt werden.');
|
||||||
@@ -114,108 +125,181 @@ export function AntwortScreen({ route }: Props) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<KeyboardAvoidingView
|
<KeyboardAvoidingView style={{ flex: 1 }} behavior={Platform.OS === 'ios' ? 'padding' : undefined}>
|
||||||
style={{ flex: 1 }}
|
<ScrollView style={styles.container} contentContainerStyle={{ padding: abstand.m, paddingBottom: abstand.xl }}>
|
||||||
behavior={Platform.OS === 'ios' ? 'padding' : undefined}
|
{/* Fortschritt */}
|
||||||
>
|
<Text style={styles.schrittLabel}>Schritt {schritt} von 3</Text>
|
||||||
<ScrollView style={styles.container} contentContainerStyle={{ padding: abstand.m }}>
|
<View style={styles.fortschritt}>
|
||||||
<Text style={styles.abschnittTitel}>1. Was möchten Sie antworten?</Text>
|
{[1, 2, 3].map((n) => (
|
||||||
<View style={styles.typListe}>
|
<View
|
||||||
{optionen.map((t) => (
|
key={n}
|
||||||
<GrossButton
|
style={[styles.balken, { backgroundColor: n <= schritt ? farben.primaer : farben.rand }]}
|
||||||
key={t}
|
|
||||||
titel={
|
|
||||||
ANTWORT_TYP_LABEL[t] +
|
|
||||||
(brief.analyse.antwort_optionen.includes(t) ? ' ★' : '')
|
|
||||||
}
|
|
||||||
variante={typ === t ? 'primaer' : 'sekundaer'}
|
|
||||||
onPress={() => setTyp(t)}
|
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</View>
|
</View>
|
||||||
|
|
||||||
<Text style={styles.abschnittTitel}>2. Zusätzliche Angaben (optional)</Text>
|
{/* ── Schritt 1: Art wählen ── */}
|
||||||
<TextInput
|
{schritt === 1 && (
|
||||||
style={styles.eingabe}
|
<View>
|
||||||
placeholder="z. B. Wunschtermin, Grund der Verschiebung…"
|
<Text style={styles.titel}>Welche Antwort brauchen Sie?</Text>
|
||||||
placeholderTextColor={farben.textSekundaer}
|
<Text style={styles.unterTitel}>
|
||||||
value={hinweise}
|
Für {brief.analyse.brieftyp} von {brief.analyse.absender}.
|
||||||
onChangeText={setHinweise}
|
|
||||||
multiline
|
|
||||||
/>
|
|
||||||
|
|
||||||
<GrossButton
|
|
||||||
titel={text ? 'Neuen Entwurf erstellen' : 'Entwurf erstellen'}
|
|
||||||
ikone="funken"
|
|
||||||
onPress={erzeugen}
|
|
||||||
deaktiviert={!typ}
|
|
||||||
laedt={laedt}
|
|
||||||
/>
|
|
||||||
|
|
||||||
{text !== '' && (
|
|
||||||
<>
|
|
||||||
<Text style={styles.abschnittTitel}>3. Entwurf prüfen und anpassen</Text>
|
|
||||||
<Text style={styles.hinweis}>
|
|
||||||
Ersetzen Sie die Platzhalter in [eckigen Klammern] durch Ihre Daten.
|
|
||||||
</Text>
|
</Text>
|
||||||
|
<View style={{ gap: abstand.s, marginTop: abstand.s }}>
|
||||||
|
{optionen.map((t) => {
|
||||||
|
const empfohlen = brief.analyse.antwort_optionen.includes(t);
|
||||||
|
return (
|
||||||
|
<Pressable
|
||||||
|
key={t}
|
||||||
|
onPress={() => typWaehlen(t)}
|
||||||
|
accessibilityRole="button"
|
||||||
|
style={({ pressed }) => [styles.typKarte, pressed && { opacity: 0.7 }]}
|
||||||
|
>
|
||||||
|
<View style={styles.typIkone}>
|
||||||
|
<Ikone name={TYP_INFO[t].ikone} groesse={22} farbe={farben.primaer} />
|
||||||
|
</View>
|
||||||
|
<View style={{ flex: 1 }}>
|
||||||
|
<View style={{ flexDirection: 'row', alignItems: 'center', gap: 8 }}>
|
||||||
|
<Text style={styles.typTitel}>{ANTWORT_TYP_LABEL[t]}</Text>
|
||||||
|
{empfohlen && (
|
||||||
|
<View style={styles.empfohlenTag}>
|
||||||
|
<Text style={styles.empfohlenText}>Empfohlen</Text>
|
||||||
|
</View>
|
||||||
|
)}
|
||||||
|
</View>
|
||||||
|
<Text style={styles.typBeschreibung}>{TYP_INFO[t].beschreibung}</Text>
|
||||||
|
</View>
|
||||||
|
<Ikone name="pfeilRechts" groesse={16} farbe={farben.textTertiaer} />
|
||||||
|
</Pressable>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* ── Schritt 2: Angaben ── */}
|
||||||
|
{schritt === 2 && typ && (
|
||||||
|
<View>
|
||||||
|
<View style={styles.wahlPill}>
|
||||||
|
<Ikone name={TYP_INFO[typ].ikone} groesse={15} farbe={farben.primaerFuellung} />
|
||||||
|
<Text style={styles.wahlPillText}>{ANTWORT_TYP_LABEL[typ]}</Text>
|
||||||
|
</View>
|
||||||
|
<Text style={styles.titel}>Angaben ergänzen</Text>
|
||||||
|
<Text style={styles.feldLabel}>Zusätzliche Angaben (optional)</Text>
|
||||||
<TextInput
|
<TextInput
|
||||||
style={[styles.eingabe, styles.betreffEingabe]}
|
style={[styles.eingabe, styles.mehrzeilig]}
|
||||||
|
placeholder="z. B. Wunschtermin, Grund der Verschiebung, was Sie beilegen…"
|
||||||
|
placeholderTextColor={farben.textTertiaer}
|
||||||
|
value={hinweise}
|
||||||
|
onChangeText={setHinweise}
|
||||||
|
multiline
|
||||||
|
textAlignVertical="top"
|
||||||
|
/>
|
||||||
|
<View style={styles.infoBox}>
|
||||||
|
<Ikone name="funken" groesse={16} farbe={farben.primaerFuellung} />
|
||||||
|
<Text style={styles.infoBoxText}>
|
||||||
|
Aktenzeichen, Behörde und die Angaben aus dem Brief übernimmt die App
|
||||||
|
automatisch — Sie müssen nichts abtippen.
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
|
<View style={{ marginTop: abstand.m }}>
|
||||||
|
<GrossButton titel="Entwurf erstellen" ikone="funken" onPress={erzeugen} laedt={laedt} />
|
||||||
|
</View>
|
||||||
|
<Pressable onPress={() => setSchritt(1)} style={styles.zurueck} accessibilityRole="button">
|
||||||
|
<Ikone name="pfeilLinks" groesse={14} farbe={farben.primaerFuellung} />
|
||||||
|
<Text style={styles.zurueckText}>Andere Antwort wählen</Text>
|
||||||
|
</Pressable>
|
||||||
|
</View>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* ── Schritt 3: Entwurf ── */}
|
||||||
|
{schritt === 3 && (
|
||||||
|
<View>
|
||||||
|
<Text style={styles.titel}>Ihr Schreiben ist fertig</Text>
|
||||||
|
<Text style={styles.unterTitel}>
|
||||||
|
Prüfen Sie den Entwurf und ersetzen Sie die Platzhalter in [eckigen
|
||||||
|
Klammern] durch Ihre Daten.
|
||||||
|
</Text>
|
||||||
|
<Text style={styles.feldLabel}>Betreff</Text>
|
||||||
|
<TextInput
|
||||||
|
style={[styles.eingabe, { fontWeight: '700' }]}
|
||||||
value={betreff}
|
value={betreff}
|
||||||
onChangeText={setBetreff}
|
onChangeText={setBetreff}
|
||||||
accessibilityLabel="Betreff"
|
accessibilityLabel="Betreff"
|
||||||
/>
|
/>
|
||||||
|
<Text style={styles.feldLabel}>Schreiben</Text>
|
||||||
<TextInput
|
<TextInput
|
||||||
style={[styles.eingabe, styles.textEingabe]}
|
style={[styles.eingabe, styles.briefText]}
|
||||||
value={text}
|
value={text}
|
||||||
onChangeText={setText}
|
onChangeText={setText}
|
||||||
multiline
|
multiline
|
||||||
textAlignVertical="top"
|
textAlignVertical="top"
|
||||||
accessibilityLabel="Brieftext"
|
accessibilityLabel="Brieftext"
|
||||||
/>
|
/>
|
||||||
<View style={{ gap: abstand.s }}>
|
<View style={{ gap: abstand.s, marginTop: abstand.s }}>
|
||||||
<GrossButton titel="Als PDF exportieren" ikone="dokument" onPress={alsPdf} />
|
<GrossButton titel="Als PDF exportieren" ikone="dokument" onPress={alsPdf} />
|
||||||
<GrossButton titel="Als Text teilen / kopieren" ikone="teilen" variante="sekundaer" onPress={alsText} />
|
<GrossButton titel="Als Text teilen / kopieren" ikone="teilen" variante="sekundaer" onPress={alsText} />
|
||||||
</View>
|
</View>
|
||||||
</>
|
<Pressable onPress={() => setSchritt(2)} style={styles.zurueck} accessibilityRole="button">
|
||||||
|
<Ikone name="pfeilLinks" groesse={14} farbe={farben.primaerFuellung} />
|
||||||
|
<Text style={styles.zurueckText}>Angaben ändern & neu erstellen</Text>
|
||||||
|
</Pressable>
|
||||||
|
</View>
|
||||||
)}
|
)}
|
||||||
<View style={{ height: abstand.xl }} />
|
|
||||||
</ScrollView>
|
</ScrollView>
|
||||||
</KeyboardAvoidingView>
|
</KeyboardAvoidingView>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function escapeHtml(s: string): string {
|
function escapeHtml(s: string): string {
|
||||||
return s
|
return s.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"');
|
||||||
.replace(/&/g, '&')
|
|
||||||
.replace(/</g, '<')
|
|
||||||
.replace(/>/g, '>')
|
|
||||||
.replace(/"/g, '"');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
container: { flex: 1, backgroundColor: farben.hintergrund },
|
container: { flex: 1, backgroundColor: farben.hintergrund },
|
||||||
zentriert: { flex: 1, justifyContent: 'center', alignItems: 'center' },
|
zentriert: { flex: 1, justifyContent: 'center', alignItems: 'center' },
|
||||||
abschnittTitel: {
|
|
||||||
fontSize: schrift.gross,
|
|
||||||
fontWeight: '700',
|
|
||||||
color: farben.primaer,
|
|
||||||
marginTop: abstand.l,
|
|
||||||
marginBottom: abstand.s,
|
|
||||||
},
|
|
||||||
typListe: { gap: abstand.s },
|
|
||||||
eingabe: {
|
|
||||||
borderWidth: 1,
|
|
||||||
borderColor: farben.rand,
|
|
||||||
borderRadius: 12,
|
|
||||||
padding: abstand.s,
|
|
||||||
fontSize: schrift.basis,
|
|
||||||
color: farben.text,
|
|
||||||
backgroundColor: farben.hintergrund,
|
|
||||||
minHeight: 56,
|
|
||||||
marginBottom: abstand.m,
|
|
||||||
},
|
|
||||||
betreffEingabe: { fontWeight: '700' },
|
|
||||||
textEingabe: { minHeight: 320, lineHeight: 26 },
|
|
||||||
hinweis: { fontSize: schrift.klein, color: farben.textSekundaer, marginBottom: abstand.s },
|
|
||||||
text: { fontSize: schrift.basis, color: farben.text },
|
text: { fontSize: schrift.basis, color: farben.text },
|
||||||
|
|
||||||
|
schrittLabel: { fontSize: schrift.klein, color: farben.textSekundaer, fontWeight: '600', marginBottom: abstand.xs },
|
||||||
|
fortschritt: { flexDirection: 'row', gap: 6, marginBottom: abstand.l },
|
||||||
|
balken: { flex: 1, height: 5, borderRadius: 3 },
|
||||||
|
|
||||||
|
titel: { fontSize: schrift.titel, fontWeight: '800', color: farben.text, marginBottom: 4 },
|
||||||
|
unterTitel: { fontSize: schrift.klein, color: farben.textSekundaer, lineHeight: 22, marginBottom: abstand.s },
|
||||||
|
|
||||||
|
// Schritt 1 — Karten
|
||||||
|
typKarte: {
|
||||||
|
flexDirection: 'row', alignItems: 'center', gap: abstand.s,
|
||||||
|
backgroundColor: farben.flaeche, borderRadius: 14, padding: abstand.m,
|
||||||
|
},
|
||||||
|
typIkone: {
|
||||||
|
width: 44, height: 44, borderRadius: 12, borderWidth: 1, borderColor: farben.primaer,
|
||||||
|
alignItems: 'center', justifyContent: 'center', flexShrink: 0,
|
||||||
|
},
|
||||||
|
typTitel: { fontSize: schrift.basis, fontWeight: '700', color: farben.text },
|
||||||
|
typBeschreibung: { fontSize: schrift.klein, color: farben.textSekundaer, marginTop: 2, lineHeight: 20 },
|
||||||
|
empfohlenTag: { backgroundColor: farben.hervorhebung, borderRadius: 6, paddingHorizontal: 8, paddingVertical: 2 },
|
||||||
|
empfohlenText: { fontSize: 11, fontWeight: '700', color: farben.primaerFuellung },
|
||||||
|
|
||||||
|
// Schritt 2/3
|
||||||
|
wahlPill: {
|
||||||
|
flexDirection: 'row', alignSelf: 'flex-start', alignItems: 'center', gap: 7,
|
||||||
|
borderWidth: 1, borderColor: farben.primaer, borderRadius: 9999,
|
||||||
|
paddingHorizontal: 12, paddingVertical: 6, marginBottom: abstand.m,
|
||||||
|
},
|
||||||
|
wahlPillText: { fontSize: schrift.klein, color: farben.primaerFuellung, fontWeight: '600' },
|
||||||
|
feldLabel: { fontSize: schrift.klein, color: farben.textSekundaer, fontWeight: '600', marginTop: abstand.s, marginBottom: 6 },
|
||||||
|
eingabe: {
|
||||||
|
borderWidth: 1, borderColor: farben.rand, borderRadius: 12, padding: abstand.s,
|
||||||
|
fontSize: schrift.basis, color: farben.text, backgroundColor: farben.flaeche, minHeight: 52,
|
||||||
|
},
|
||||||
|
mehrzeilig: { minHeight: 110 },
|
||||||
|
briefText: { minHeight: 300, lineHeight: 26 },
|
||||||
|
infoBox: {
|
||||||
|
flexDirection: 'row', gap: abstand.s, alignItems: 'flex-start',
|
||||||
|
backgroundColor: farben.hervorhebung, borderRadius: 12, padding: abstand.m, marginTop: abstand.m,
|
||||||
|
},
|
||||||
|
infoBoxText: { flex: 1, fontSize: schrift.klein, color: farben.text, lineHeight: 21 },
|
||||||
|
zurueck: { flexDirection: 'row', alignItems: 'center', justifyContent: 'center', gap: 6, marginTop: abstand.m, paddingVertical: abstand.s },
|
||||||
|
zurueckText: { fontSize: schrift.klein, color: farben.primaerFuellung, fontWeight: '600' },
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user