generated from knso/webklar-preview-template
Initial commit
This commit is contained in:
@@ -1,8 +1,10 @@
|
|||||||
/**
|
/**
|
||||||
* Ergebnis-Ansicht: Ampel, einfache Erklärung, Übersetzung, Fachbegriffe,
|
* Brief-Detail ("Ihr Brief erklärt") — Layout nach dem Claude-Design-Entwurf:
|
||||||
* Frist/Termin mit Kalender-Export, Checkliste und Antwort-Einstieg.
|
* große Frist-Karte mit Countdown oben, dann "Das ist passiert",
|
||||||
|
* "Das müssen Sie tun", schwere Wörter und der Einstieg zur Antwort.
|
||||||
|
* Alle Funktionen bleiben: Übersetzung, Vorlesen, Kalender, Löschen.
|
||||||
*/
|
*/
|
||||||
import React, { useState } from 'react';
|
import React, { useLayoutEffect, useState } from 'react';
|
||||||
import {
|
import {
|
||||||
Alert,
|
Alert,
|
||||||
Modal,
|
Modal,
|
||||||
@@ -19,9 +21,7 @@ import { useAppStore } from '../store/useAppStore';
|
|||||||
import { uebersetzeAnalyse } from '../services/uebersetzung';
|
import { uebersetzeAnalyse } from '../services/uebersetzung';
|
||||||
import { ClaudeFehler } from '../services/claudeClient';
|
import { ClaudeFehler } from '../services/claudeClient';
|
||||||
import { terminZumKalender } from '../services/kalender';
|
import { terminZumKalender } from '../services/kalender';
|
||||||
import { formatiereDatum } from '../services/erinnerungen';
|
import { berechneAmpel, naechsteFrist, formatiereLangDatum } from '../utils/ampel';
|
||||||
import { berechneAmpel } from '../utils/ampel';
|
|
||||||
import { Ampel } from '../components/Ampel';
|
|
||||||
import { GrossButton } from '../components/GrossButton';
|
import { GrossButton } from '../components/GrossButton';
|
||||||
import { Ikone } from '../components/Ikone';
|
import { Ikone } from '../components/Ikone';
|
||||||
import { farben, schrift, abstand, TOUCH_TARGET } from '../theme';
|
import { farben, schrift, abstand, TOUCH_TARGET } from '../theme';
|
||||||
@@ -30,6 +30,12 @@ type Props = NativeStackScreenProps<RootStackParamList, 'Analyse'>;
|
|||||||
|
|
||||||
const DEUTSCH: Sprache = { code: 'de', name: 'Deutsch', eigenname: 'Deutsch' };
|
const DEUTSCH: Sprache = { code: 'de', name: 'Deutsch', eigenname: 'Deutsch' };
|
||||||
|
|
||||||
|
const STUFEN_LABEL: Record<string, string> = {
|
||||||
|
rot: 'Dringend',
|
||||||
|
gelb: 'Handlung nötig',
|
||||||
|
gruen: 'Zur Kenntnis',
|
||||||
|
};
|
||||||
|
|
||||||
export function AnalyseScreen({ navigation, route }: Props) {
|
export function AnalyseScreen({ navigation, 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 setzeUebersetzung = useAppStore((s) => s.setzeUebersetzung);
|
const setzeUebersetzung = useAppStore((s) => s.setzeUebersetzung);
|
||||||
@@ -41,8 +47,12 @@ export function AnalyseScreen({ navigation, route }: Props) {
|
|||||||
const [liest, setLiest] = useState(false);
|
const [liest, setLiest] = useState(false);
|
||||||
const [erledigt, setErledigt] = useState<Record<number, boolean>>({});
|
const [erledigt, setErledigt] = useState<Record<number, boolean>>({});
|
||||||
|
|
||||||
|
// Header-Titel = Brieftyp (wie im Entwurf), sobald der Brief geladen ist
|
||||||
|
useLayoutEffect(() => {
|
||||||
|
if (brief) navigation.setOptions({ title: brief.analyse.brieftyp });
|
||||||
|
}, [navigation, brief]);
|
||||||
|
|
||||||
if (!brief) {
|
if (!brief) {
|
||||||
// Brief wurde gelöscht — zurück zum Start
|
|
||||||
return (
|
return (
|
||||||
<View style={styles.zentriert}>
|
<View style={styles.zentriert}>
|
||||||
<Text style={styles.text}>Brief nicht gefunden.</Text>
|
<Text style={styles.text}>Brief nicht gefunden.</Text>
|
||||||
@@ -52,6 +62,8 @@ export function AnalyseScreen({ navigation, route }: Props) {
|
|||||||
|
|
||||||
const { analyse } = brief;
|
const { analyse } = brief;
|
||||||
const ampel = berechneAmpel(analyse);
|
const ampel = berechneAmpel(analyse);
|
||||||
|
const frist = naechsteFrist(analyse);
|
||||||
|
const stufenLabel = STUFEN_LABEL[ampel.stufe];
|
||||||
|
|
||||||
// Anzeige-Inhalte: deutsch oder aus dem Übersetzungs-Cache
|
// Anzeige-Inhalte: deutsch oder aus dem Übersetzungs-Cache
|
||||||
const cache = sprache.code !== 'de' ? brief.uebersetzungen[sprache.code] : undefined;
|
const cache = sprache.code !== 'de' ? brief.uebersetzungen[sprache.code] : undefined;
|
||||||
@@ -64,7 +76,6 @@ export function AnalyseScreen({ navigation, route }: Props) {
|
|||||||
setSprachwahlOffen(false);
|
setSprachwahlOffen(false);
|
||||||
setSprache(neu);
|
setSprache(neu);
|
||||||
if (neu.code === 'de' || brief.uebersetzungen[neu.code]) return;
|
if (neu.code === 'de' || brief.uebersetzungen[neu.code]) return;
|
||||||
// Noch nicht im Cache -> einmalig übersetzen
|
|
||||||
setUebersetzt(true);
|
setUebersetzt(true);
|
||||||
try {
|
try {
|
||||||
const u = await uebersetzeAnalyse(analyse, neu);
|
const u = await uebersetzeAnalyse(analyse, neu);
|
||||||
@@ -80,7 +91,6 @@ export function AnalyseScreen({ navigation, route }: Props) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Vorlese-Funktion für Menschen mit Leseschwäche. */
|
|
||||||
const vorlesen = () => {
|
const vorlesen = () => {
|
||||||
if (liest) {
|
if (liest) {
|
||||||
Speech.stop();
|
Speech.stop();
|
||||||
@@ -123,135 +133,169 @@ export function AnalyseScreen({ navigation, route }: Props) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ScrollView style={styles.container} contentContainerStyle={{ padding: abstand.m }}>
|
<ScrollView style={styles.container} contentContainerStyle={{ padding: abstand.m, paddingBottom: abstand.xl }}>
|
||||||
{/* Dringlichkeits-Ampel ganz oben */}
|
{/* ── Frist-Karte mit Countdown ── */}
|
||||||
<Ampel status={ampel} />
|
{frist ? (
|
||||||
|
<View style={[styles.fristKarte, { backgroundColor: ampel.hintergrund, borderColor: ampel.farbe }]}>
|
||||||
{/* Sprach-Auswahl */}
|
<View style={styles.fristKopf}>
|
||||||
<Pressable
|
<Ikone name="uhr" groesse={16} farbe={ampel.farbe} />
|
||||||
style={styles.sprachButton}
|
<Text style={[styles.fristKicker, { color: ampel.farbe }]}>
|
||||||
onPress={() => setSprachwahlOffen(true)}
|
{frist.label} · {stufenLabel}
|
||||||
accessibilityRole="button"
|
|
||||||
accessibilityLabel={`Sprache ändern. Aktuell: ${sprache.name}`}
|
|
||||||
>
|
|
||||||
<View style={styles.sprachZeileInhalt}>
|
|
||||||
<Ikone name="globus" groesse={20} farbe={farben.primaer} />
|
|
||||||
<Text style={styles.sprachButtonText}>
|
|
||||||
{sprache.eigenname} {uebersetzt ? ' (übersetzt…)' : ''}
|
|
||||||
</Text>
|
</Text>
|
||||||
<Ikone name="pfeilRechts" groesse={16} farbe={farben.textTertiaer} />
|
|
||||||
</View>
|
</View>
|
||||||
</Pressable>
|
<View style={{ flexDirection: 'row', alignItems: 'flex-end', gap: 12 }}>
|
||||||
|
<Text style={[styles.grosseZahl, { color: ampel.farbe }]}>
|
||||||
{/* Kernaussage: Was will das Amt von mir? */}
|
{frist.tage < 0 ? '!' : frist.tage}
|
||||||
<View style={styles.karteWichtig}>
|
</Text>
|
||||||
<Text style={styles.abschnittTitel}>Was will das Amt von mir?</Text>
|
<View style={{ paddingBottom: 8 }}>
|
||||||
<Text style={styles.kernaussage}>{kernaussage}</Text>
|
<Text style={[styles.zahlEinheit, { color: ampel.farbe }]}>
|
||||||
<View style={{ marginTop: abstand.s }}>
|
{frist.tage < 0 ? 'überfällig' : 'Tage'}
|
||||||
<GrossButton
|
</Text>
|
||||||
titel={liest ? 'Vorlesen stoppen' : 'Vorlesen'}
|
<Text style={styles.zahlUnter}>{frist.tage < 0 ? '' : 'verbleiben'}</Text>
|
||||||
ikone={liest ? 'stopp' : 'vorlesen'}
|
|
||||||
variante="sekundaer"
|
|
||||||
onPress={vorlesen}
|
|
||||||
/>
|
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
|
<View style={styles.trenner} />
|
||||||
{/* Frist / Termin */}
|
<View style={styles.datenZeile}>
|
||||||
{(analyse.frist || analyse.termin) && (
|
<Text style={styles.datenLabel}>{frist.label === 'Termin' ? 'Termin am' : 'Fällig am'}</Text>
|
||||||
<View
|
<Text style={styles.datenWert}>{formatiereLangDatum(frist.datumIso)}</Text>
|
||||||
style={[
|
</View>
|
||||||
styles.karte,
|
{analyse.frist?.aktion && (
|
||||||
{ backgroundColor: ampel.hintergrund, borderLeftWidth: 6, borderLeftColor: ampel.farbe },
|
<View style={styles.datenZeile}>
|
||||||
]}
|
<Text style={styles.datenLabel}>Zu tun</Text>
|
||||||
>
|
<Text style={[styles.datenWert, { color: ampel.farbe, flex: 1, textAlign: 'right' }]}>
|
||||||
{analyse.frist && (
|
|
||||||
<Text style={styles.fristText}>
|
|
||||||
Frist: <Text style={styles.fett}>{formatiereDatum(analyse.frist.datum)}</Text>
|
|
||||||
{'\n'}
|
|
||||||
{analyse.frist.aktion}
|
{analyse.frist.aktion}
|
||||||
</Text>
|
</Text>
|
||||||
|
</View>
|
||||||
)}
|
)}
|
||||||
{analyse.termin && (
|
{analyse.termin && (
|
||||||
<>
|
<>
|
||||||
<Text style={styles.fristText}>
|
{(analyse.termin.uhrzeit || analyse.termin.ort) && (
|
||||||
Termin: <Text style={styles.fett}>{formatiereDatum(analyse.termin.datum)}</Text>
|
<View style={styles.datenZeile}>
|
||||||
{analyse.termin.uhrzeit ? ` um ${analyse.termin.uhrzeit} Uhr` : ''}
|
<Text style={styles.datenLabel}>Wo & wann</Text>
|
||||||
{analyse.termin.ort ? `\nOrt: ${analyse.termin.ort}` : ''}
|
<Text style={[styles.datenWert, { flex: 1, textAlign: 'right' }]}>
|
||||||
|
{analyse.termin.uhrzeit ? `${analyse.termin.uhrzeit} Uhr` : ''}
|
||||||
|
{analyse.termin.uhrzeit && analyse.termin.ort ? ' · ' : ''}
|
||||||
|
{analyse.termin.ort ?? ''}
|
||||||
</Text>
|
</Text>
|
||||||
|
</View>
|
||||||
|
)}
|
||||||
|
<View style={{ marginTop: abstand.s }}>
|
||||||
<GrossButton
|
<GrossButton
|
||||||
titel="Termin zum Kalender hinzufügen"
|
titel="Termin zum Kalender hinzufügen"
|
||||||
ikone="kalender"
|
ikone="kalender"
|
||||||
variante="sekundaer"
|
variante="sekundaer"
|
||||||
onPress={kalenderExport}
|
onPress={kalenderExport}
|
||||||
/>
|
/>
|
||||||
|
</View>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</View>
|
</View>
|
||||||
|
) : (
|
||||||
|
<View style={styles.keineFrist}>
|
||||||
|
<Ikone name="info" groesse={20} farbe={farben.ampelGruen} />
|
||||||
|
<View style={{ flex: 1 }}>
|
||||||
|
<Text style={styles.keineFristTitel}>Keine Frist</Text>
|
||||||
|
<Text style={styles.keineFristText}>Dieser Brief ist nur zur Kenntnis. Sie müssen nichts tun.</Text>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/* Ausführliche Erklärung */}
|
{/* ── Steuerung: Sprache + Vorlesen ── */}
|
||||||
<View style={styles.karte}>
|
<View style={styles.werkzeugZeile}>
|
||||||
<Text style={styles.abschnittTitel}>Erklärung in einfacher Sprache</Text>
|
|
||||||
<Text style={styles.text}>{erklaerung}</Text>
|
|
||||||
</View>
|
|
||||||
|
|
||||||
{/* Checkliste */}
|
|
||||||
{checkliste.length > 0 && (
|
|
||||||
<View style={styles.karte}>
|
|
||||||
<Text style={styles.abschnittTitel}>Das müssen Sie tun</Text>
|
|
||||||
{checkliste.map((punkt, i) => (
|
|
||||||
<Pressable
|
<Pressable
|
||||||
key={i}
|
style={styles.werkzeug}
|
||||||
style={styles.checkZeile}
|
onPress={() => setSprachwahlOffen(true)}
|
||||||
onPress={() => setErledigt((e) => ({ ...e, [i]: !e[i] }))}
|
accessibilityRole="button"
|
||||||
accessibilityRole="checkbox"
|
accessibilityLabel={`Sprache ändern. Aktuell: ${sprache.name}`}
|
||||||
accessibilityState={{ checked: !!erledigt[i] }}
|
|
||||||
>
|
>
|
||||||
<Ikone
|
<Ikone name="globus" groesse={18} farbe={farben.primaer} />
|
||||||
name={erledigt[i] ? 'checkAn' : 'checkAus'}
|
<Text style={styles.werkzeugText} numberOfLines={1}>
|
||||||
groesse={26}
|
{uebersetzt ? 'übersetzt…' : sprache.eigenname}
|
||||||
farbe={erledigt[i] ? farben.ampelGruen : farben.textTertiaer}
|
|
||||||
/>
|
|
||||||
<Text style={[styles.text, { flex: 1 }, erledigt[i] && styles.durchgestrichen]}>
|
|
||||||
{punkt}
|
|
||||||
</Text>
|
</Text>
|
||||||
</Pressable>
|
</Pressable>
|
||||||
))}
|
<Pressable style={styles.werkzeug} onPress={vorlesen} accessibilityRole="button">
|
||||||
|
<Ikone name={liest ? 'stopp' : 'vorlesen'} groesse={18} farbe={farben.primaer} />
|
||||||
|
<Text style={styles.werkzeugText}>{liest ? 'Stopp' : 'Vorlesen'}</Text>
|
||||||
|
</Pressable>
|
||||||
</View>
|
</View>
|
||||||
|
|
||||||
|
{/* ── Das ist passiert ── */}
|
||||||
|
<Text style={styles.kicker}>Das ist passiert</Text>
|
||||||
|
<Text style={styles.kernaussage}>{kernaussage}</Text>
|
||||||
|
<Text style={styles.erklaerung}>{erklaerung}</Text>
|
||||||
|
|
||||||
|
{/* ── Das müssen Sie tun ── */}
|
||||||
|
{checkliste.length > 0 && (
|
||||||
|
<>
|
||||||
|
<View style={styles.dünnerTrenner} />
|
||||||
|
<Text style={styles.kicker}>Das müssen Sie tun</Text>
|
||||||
|
<View style={{ gap: abstand.s }}>
|
||||||
|
{checkliste.map((punkt, i) => {
|
||||||
|
const fertig = !!erledigt[i];
|
||||||
|
return (
|
||||||
|
<Pressable
|
||||||
|
key={i}
|
||||||
|
style={styles.todoZeile}
|
||||||
|
onPress={() => setErledigt((e) => ({ ...e, [i]: !e[i] }))}
|
||||||
|
accessibilityRole="checkbox"
|
||||||
|
accessibilityState={{ checked: fertig }}
|
||||||
|
>
|
||||||
|
<View style={[styles.todoKreis, fertig && styles.todoKreisFertig]}>
|
||||||
|
{fertig ? (
|
||||||
|
<Ikone name="checkAn" groesse={16} farbe={farben.primaerText} />
|
||||||
|
) : (
|
||||||
|
<Text style={styles.todoNummer}>{i + 1}</Text>
|
||||||
|
)}
|
||||||
|
</View>
|
||||||
|
<Text style={[styles.todoText, fertig && styles.durchgestrichen]}>{punkt}</Text>
|
||||||
|
</Pressable>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</View>
|
||||||
|
</>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/* Fachbegriffe */}
|
{/* ── Schwere Wörter ── */}
|
||||||
{fachbegriffe.length > 0 && (
|
{fachbegriffe.length > 0 && (
|
||||||
<View style={styles.karte}>
|
<>
|
||||||
<Text style={styles.abschnittTitel}>Schwere Wörter erklärt</Text>
|
<View style={styles.dünnerTrenner} />
|
||||||
|
<Text style={styles.kicker}>Schwere Wörter erklärt</Text>
|
||||||
|
<View style={{ gap: abstand.s }}>
|
||||||
{fachbegriffe.map((f, i) => (
|
{fachbegriffe.map((f, i) => (
|
||||||
<View key={i} style={styles.begriffBlock}>
|
<View key={i} style={styles.begriffKarte}>
|
||||||
<Text style={styles.begriff}>{f.begriff}</Text>
|
<Text style={styles.begriff}>{f.begriff}</Text>
|
||||||
<Text style={styles.text}>{f.erklaerung}</Text>
|
<Text style={styles.begriffText}>{f.erklaerung}</Text>
|
||||||
</View>
|
</View>
|
||||||
))}
|
))}
|
||||||
</View>
|
</View>
|
||||||
|
</>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/* Antwort erstellen */}
|
{/* ── Antwort ── */}
|
||||||
{analyse.antwort_noetig && (
|
{analyse.antwort_noetig && (
|
||||||
|
<View style={{ marginTop: abstand.l }}>
|
||||||
<GrossButton
|
<GrossButton
|
||||||
titel="Antwort erstellen"
|
titel="Antwort erstellen"
|
||||||
ikone="stift"
|
ikone="stift"
|
||||||
onPress={() => navigation.navigate('Antwort', { briefId: brief.id })}
|
onPress={() => navigation.navigate('Antwort', { briefId: brief.id })}
|
||||||
/>
|
/>
|
||||||
|
</View>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<View style={{ height: abstand.m }} />
|
{/* ── Datenschutz-Fuß + Löschen ── */}
|
||||||
|
<View style={styles.schutzZeile}>
|
||||||
|
<Ikone name="schloss" groesse={13} farbe={farben.textTertiaer} />
|
||||||
|
<Text style={styles.schutzText}>Auf Ihrem Gerät ausgewertet · verschlüsselt gespeichert</Text>
|
||||||
|
</View>
|
||||||
|
<View style={{ marginTop: abstand.m }}>
|
||||||
<GrossButton titel="Brief löschen" ikone="muell" variante="gefahr" onPress={loeschen} />
|
<GrossButton titel="Brief löschen" ikone="muell" variante="gefahr" onPress={loeschen} />
|
||||||
<View style={{ height: abstand.xl }} />
|
</View>
|
||||||
|
|
||||||
{/* Sprach-Auswahl-Dialog */}
|
{/* Sprach-Auswahl-Dialog */}
|
||||||
<Modal visible={sprachwahlOffen} transparent animationType="fade">
|
<Modal visible={sprachwahlOffen} transparent animationType="fade">
|
||||||
<Pressable style={styles.modalHintergrund} onPress={() => setSprachwahlOffen(false)}>
|
<Pressable style={styles.modalHintergrund} onPress={() => setSprachwahlOffen(false)}>
|
||||||
<View style={styles.modalKarte}>
|
<View style={styles.modalKarte}>
|
||||||
<Text style={styles.abschnittTitel}>Sprache wählen</Text>
|
<Text style={styles.modalTitel}>Sprache wählen</Text>
|
||||||
<ScrollView>
|
<ScrollView>
|
||||||
{[DEUTSCH, ...SPRACHEN].map((s) => (
|
{[DEUTSCH, ...SPRACHEN].map((s) => (
|
||||||
<Pressable
|
<Pressable
|
||||||
@@ -263,7 +307,7 @@ export function AnalyseScreen({ navigation, route }: Props) {
|
|||||||
<Text
|
<Text
|
||||||
style={[
|
style={[
|
||||||
styles.sprachZeileText,
|
styles.sprachZeileText,
|
||||||
s.code === sprache.code && { fontWeight: '700', color: farben.primaer },
|
s.code === sprache.code && { fontWeight: '700', color: farben.primaerFuellung },
|
||||||
]}
|
]}
|
||||||
>
|
>
|
||||||
{s.eigenname} {s.code !== 'de' ? `(${s.name})` : ''}
|
{s.eigenname} {s.code !== 'de' ? `(${s.name})` : ''}
|
||||||
@@ -282,64 +326,68 @@ export function AnalyseScreen({ navigation, route }: Props) {
|
|||||||
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' },
|
||||||
karte: {
|
|
||||||
backgroundColor: farben.flaeche,
|
// Frist-Karte
|
||||||
borderRadius: 12,
|
fristKarte: { borderRadius: 16, borderWidth: 1, padding: abstand.l },
|
||||||
padding: abstand.m,
|
fristKopf: { flexDirection: 'row', alignItems: 'center', gap: 8, marginBottom: 10 },
|
||||||
marginTop: abstand.m,
|
fristKicker: { fontSize: 12, letterSpacing: 0.6, textTransform: 'uppercase', fontWeight: '700' },
|
||||||
gap: abstand.s,
|
grosseZahl: { fontSize: 64, lineHeight: 64, fontWeight: '800', fontVariant: ['tabular-nums'] },
|
||||||
|
zahlEinheit: { fontSize: 22, fontWeight: '700', lineHeight: 24 },
|
||||||
|
zahlUnter: { fontSize: 13, color: farben.textSekundaer },
|
||||||
|
trenner: { height: 1, backgroundColor: farben.rand, marginVertical: 14 },
|
||||||
|
datenZeile: { flexDirection: 'row', justifyContent: 'space-between', gap: 12, marginTop: 5 },
|
||||||
|
datenLabel: { fontSize: schrift.klein, color: farben.textSekundaer },
|
||||||
|
datenWert: { fontSize: schrift.klein, fontWeight: '700', color: farben.text },
|
||||||
|
|
||||||
|
keineFrist: {
|
||||||
|
flexDirection: 'row', gap: abstand.s, alignItems: 'center',
|
||||||
|
backgroundColor: farben.ampelGruenHintergrund, borderRadius: 12,
|
||||||
|
borderLeftWidth: 4, borderLeftColor: farben.ampelGruen, padding: abstand.m,
|
||||||
},
|
},
|
||||||
// DIE Antwort der App — dezent im Marken-Tint hervorgehoben
|
keineFristTitel: { fontSize: schrift.basis, fontWeight: '700', color: farben.text },
|
||||||
karteWichtig: {
|
keineFristText: { fontSize: schrift.klein, color: farben.textSekundaer, marginTop: 2 },
|
||||||
backgroundColor: farben.hervorhebung,
|
|
||||||
borderRadius: 12,
|
// Werkzeuge
|
||||||
borderWidth: 1,
|
werkzeugZeile: { flexDirection: 'row', gap: abstand.s, marginTop: abstand.m },
|
||||||
borderColor: farben.hervorhebungRand,
|
werkzeug: {
|
||||||
padding: abstand.m,
|
flex: 1, flexDirection: 'row', alignItems: 'center', justifyContent: 'center', gap: 7,
|
||||||
marginTop: abstand.m,
|
backgroundColor: farben.flaeche, borderRadius: 12, minHeight: 48, paddingHorizontal: abstand.s,
|
||||||
},
|
},
|
||||||
abschnittTitel: {
|
werkzeugText: { fontSize: schrift.klein, fontWeight: '600', color: farben.primaerFuellung },
|
||||||
fontSize: schrift.gross,
|
|
||||||
fontWeight: '700',
|
kicker: {
|
||||||
color: farben.primaer,
|
fontSize: 12, letterSpacing: 1.1, textTransform: 'uppercase',
|
||||||
marginBottom: abstand.xs,
|
color: farben.primaer, fontWeight: '700', marginTop: abstand.l, marginBottom: abstand.xs,
|
||||||
},
|
},
|
||||||
kernaussage: { fontSize: schrift.gross, color: farben.text, lineHeight: 30, fontWeight: '500' },
|
kernaussage: { fontSize: schrift.gross, color: farben.text, lineHeight: 29, fontWeight: '600' },
|
||||||
text: { fontSize: schrift.basis, color: farben.text, lineHeight: 27 },
|
erklaerung: { fontSize: schrift.basis, color: farben.textSekundaer, lineHeight: 27, marginTop: abstand.s },
|
||||||
fett: { fontWeight: '700' },
|
dünnerTrenner: { height: 1, backgroundColor: farben.rand, marginTop: abstand.l },
|
||||||
fristText: { fontSize: schrift.basis, color: farben.text, lineHeight: 28 },
|
|
||||||
checkZeile: {
|
// To-do
|
||||||
flexDirection: 'row',
|
todoZeile: { flexDirection: 'row', gap: abstand.s, alignItems: 'flex-start', minHeight: 40 },
|
||||||
alignItems: 'flex-start',
|
todoKreis: {
|
||||||
gap: abstand.s,
|
width: 28, height: 28, borderRadius: 14, borderWidth: 1.5, borderColor: farben.primaer,
|
||||||
minHeight: 44,
|
alignItems: 'center', justifyContent: 'center', marginTop: 1,
|
||||||
paddingVertical: 4,
|
|
||||||
},
|
},
|
||||||
|
todoKreisFertig: { backgroundColor: farben.ampelGruen, borderColor: farben.ampelGruen },
|
||||||
|
todoNummer: { fontSize: schrift.klein, fontWeight: '700', color: farben.primaerFuellung, fontVariant: ['tabular-nums'] },
|
||||||
|
todoText: { flex: 1, fontSize: schrift.basis, color: farben.text, lineHeight: 25, paddingTop: 3 },
|
||||||
durchgestrichen: { textDecorationLine: 'line-through', color: farben.textSekundaer },
|
durchgestrichen: { textDecorationLine: 'line-through', color: farben.textSekundaer },
|
||||||
begriffBlock: { marginBottom: abstand.s },
|
|
||||||
begriff: { fontSize: schrift.basis, fontWeight: '700', color: farben.text },
|
// Fachbegriffe
|
||||||
sprachButton: {
|
begriffKarte: { backgroundColor: farben.flaeche, borderRadius: 12, padding: abstand.m },
|
||||||
marginTop: abstand.m,
|
begriff: { fontSize: schrift.basis, fontWeight: '700', color: farben.text, marginBottom: 3 },
|
||||||
minHeight: TOUCH_TARGET,
|
begriffText: { fontSize: schrift.klein, color: farben.textSekundaer, lineHeight: 23 },
|
||||||
borderRadius: 12,
|
|
||||||
backgroundColor: farben.flaeche,
|
schutzZeile: { flexDirection: 'row', alignItems: 'center', justifyContent: 'center', gap: 6, marginTop: abstand.l },
|
||||||
justifyContent: 'center',
|
schutzText: { fontSize: 11.5, color: farben.textTertiaer },
|
||||||
paddingHorizontal: abstand.m,
|
|
||||||
},
|
text: { fontSize: schrift.basis, color: farben.text, lineHeight: 27 },
|
||||||
sprachZeileInhalt: { flexDirection: 'row', alignItems: 'center', gap: abstand.s },
|
|
||||||
sprachButtonText: { flex: 1, fontSize: schrift.basis, color: farben.text, fontWeight: '600' },
|
// Modal
|
||||||
modalHintergrund: {
|
modalHintergrund: { flex: 1, backgroundColor: 'rgba(0,0,0,0.45)', justifyContent: 'center', padding: abstand.l },
|
||||||
flex: 1,
|
modalKarte: { backgroundColor: farben.flaeche, borderRadius: 14, padding: abstand.m, maxHeight: '75%' },
|
||||||
backgroundColor: 'rgba(0,0,0,0.5)',
|
modalTitel: { fontSize: schrift.gross, fontWeight: '700', color: farben.text, marginBottom: abstand.xs },
|
||||||
justifyContent: 'center',
|
|
||||||
padding: abstand.l,
|
|
||||||
},
|
|
||||||
modalKarte: {
|
|
||||||
backgroundColor: farben.flaeche,
|
|
||||||
borderRadius: 14,
|
|
||||||
padding: abstand.m,
|
|
||||||
maxHeight: '75%',
|
|
||||||
},
|
|
||||||
sprachZeile: { minHeight: TOUCH_TARGET, justifyContent: 'center' },
|
sprachZeile: { minHeight: TOUCH_TARGET, justifyContent: 'center' },
|
||||||
sprachZeileText: { fontSize: schrift.gross, color: farben.text },
|
sprachZeileText: { fontSize: schrift.gross, color: farben.text },
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user