From fdfd2d392a89963959a1a45fadee6500bf7948e1 Mon Sep 17 00:00:00 2001 From: JUSN Date: Thu, 16 Jul 2026 21:14:11 +0200 Subject: [PATCH] =?UTF-8?q?App-Design-Politur:=20Papier-Look,=20Kacheln,?= =?UTF-8?q?=20Ampel-Streifen,=20gro=C3=9Fer=20Titel?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Theme: warmer Papier-Hintergrund (#FAF7F0) wie die Webseite, Inhalte als weiße Karten mit dezentem Schatten + warmem Rand; Marker-Gelb als Akzentfarbe für die Kernaussage - Home: iOS-Großtitel (kollabiert beim Scrollen), Hero-Button mit Schatten, Kachel-Navigation statt halbbreiter Text-Buttons (behebt Umbruch "Einstellunge/n"), Abschnitts-Label, Brief-Karten mit Ampel-Farbstreifen links, freundlicher Leerzustand - Analyse: Kernaussage als Textmarker-Karte (Markenzeichen), Frist/ Termin-Karte in Ampel-Tönung mit Farbstreifen, einheitliche Karten - Ampel-Banner: Streifen-Look statt Vollrahmen - Layout-Fix: Home als FlatList-Wurzel mit automatischem Inset (vorher verdeckte der große Titel die Kopf-Buttons) Barrierefreiheit unverändert: Schriftgrößen, Touch-Targets, Kontraste. Co-Authored-By: Claude Fable 5 --- App.tsx | 12 +- rechtliches/~$hoerdenKlar-Datenschutz.docx | Bin 0 -> 162 bytes src/components/Ampel.tsx | 5 +- src/components/GrossButton.tsx | 16 +- src/screens/AnalyseScreen.tsx | 32 ++-- src/screens/HomeScreen.tsx | 164 ++++++++++++++------- src/theme.ts | 21 ++- 7 files changed, 176 insertions(+), 74 deletions(-) create mode 100644 rechtliches/~$hoerdenKlar-Datenschutz.docx diff --git a/App.tsx b/App.tsx index 7f1f8ed..031b0ed 100644 --- a/App.tsx +++ b/App.tsx @@ -36,13 +36,23 @@ export default function App() { - + diff --git a/rechtliches/~$hoerdenKlar-Datenschutz.docx b/rechtliches/~$hoerdenKlar-Datenschutz.docx new file mode 100644 index 0000000000000000000000000000000000000000..d4d194c140f89e0bf821418590ee8792d317145b GIT binary patch literal 162 ycmd<_DlIO_%v12rNzKe-AQtd2crlbR6f=}CWHRJ2C@^?4; @@ -154,7 +154,12 @@ export function AnalyseScreen({ navigation, route }: Props) { {/* Frist / Termin */} {(analyse.frist || analyse.termin) && ( - + {analyse.frist && ( 📅 Frist: {formatiereDatum(analyse.frist.datum)} @@ -270,18 +275,23 @@ const styles = StyleSheet.create({ zentriert: { flex: 1, justifyContent: 'center', alignItems: 'center' }, karte: { backgroundColor: farben.flaeche, - borderRadius: 14, + borderRadius: 16, + borderWidth: 1, + borderColor: farben.rand, padding: abstand.m, marginTop: abstand.m, gap: abstand.s, + ...kartenSchatten, }, + // DIE Antwort der App — als "Textmarker"-Karte hervorgehoben (Markenzeichen) karteWichtig: { - backgroundColor: farben.flaeche, - borderRadius: 14, - borderWidth: 2, - borderColor: farben.primaer, + backgroundColor: farben.markerHintergrund, + borderRadius: 16, + borderWidth: 1, + borderColor: farben.markerRand, padding: abstand.m, marginTop: abstand.m, + ...kartenSchatten, }, abschnittTitel: { fontSize: schrift.gross, @@ -289,7 +299,7 @@ const styles = StyleSheet.create({ color: farben.primaer, marginBottom: abstand.xs, }, - kernaussage: { fontSize: schrift.gross, color: farben.text, lineHeight: 30 }, + kernaussage: { fontSize: schrift.gross, color: farben.text, lineHeight: 30, fontWeight: '500' }, text: { fontSize: schrift.basis, color: farben.text, lineHeight: 27 }, fett: { fontWeight: '700' }, fristText: { fontSize: schrift.basis, color: farben.text, lineHeight: 28 }, @@ -307,11 +317,13 @@ const styles = StyleSheet.create({ sprachButton: { marginTop: abstand.m, minHeight: TOUCH_TARGET, - borderRadius: 14, - borderWidth: 2, + borderRadius: 16, + borderWidth: 1, borderColor: farben.rand, + backgroundColor: farben.flaeche, justifyContent: 'center', paddingHorizontal: abstand.m, + ...kartenSchatten, }, sprachButtonText: { fontSize: schrift.basis, color: farben.text, fontWeight: '600' }, modalHintergrund: { diff --git a/src/screens/HomeScreen.tsx b/src/screens/HomeScreen.tsx index f229bac..5c9461a 100644 --- a/src/screens/HomeScreen.tsx +++ b/src/screens/HomeScreen.tsx @@ -18,10 +18,36 @@ import { holeConsent } from '../services/storage'; import { berechneAmpel } from '../utils/ampel'; import { formatiereDatum } from '../services/erinnerungen'; import { GrossButton } from '../components/GrossButton'; -import { farben, schrift, abstand } from '../theme'; +import { farben, schrift, abstand, kartenSchatten, TOUCH_TARGET } from '../theme'; type Props = NativeStackScreenProps; +/** Quadratische Navigations-Kachel: Symbol oben, Beschriftung darunter. + * (Löst das Platzproblem nebeneinanderstehender Text-Buttons.) */ +function Kachel({ + symbol, + titel, + onPress, +}: { + symbol: string; + titel: string; + onPress: () => void; +}) { + return ( + [styles.kachel, pressed && { opacity: 0.7 }]} + onPress={onPress} + accessibilityRole="button" + accessibilityLabel={titel} + > + {symbol} + + {titel} + + + ); +} + export function HomeScreen({ navigation }: Props) { const briefe = useAppStore((s) => s.briefe); const removeBrief = useAppStore((s) => s.removeBrief); @@ -58,13 +84,16 @@ export function HomeScreen({ navigation }: Props) { const ampel = berechneAmpel(item.analyse); return ( [styles.karte, pressed && { opacity: 0.7 }]} + style={({ pressed }) => [ + styles.karte, + { borderLeftColor: ampel.farbe }, + pressed && { opacity: 0.7 }, + ]} onPress={() => navigation.navigate('Analyse', { briefId: item.id })} onLongPress={() => loeschenBestaetigen(item)} accessibilityRole="button" accessibilityLabel={`Brief: ${item.analyse.brieftyp}. ${ampel.text}. Lange drücken zum Löschen.`} > - {item.analyse.brieftyp} @@ -82,65 +111,89 @@ export function HomeScreen({ navigation }: Props) { }; return ( - - - - - - navigation.navigate('Glossar')} - /> - - - - b.id} + renderItem={renderBrief} + contentContainerStyle={styles.inhalt} + ListHeaderComponent={ + + + + navigation.navigate('Glossar')} /> + navigation.navigate('Einstellungen')} /> + {briefe.length > 0 && ( + <> + Ihre Briefe + + + )} - - - {briefe.length > 0 && ( - - )} - - b.id} - renderItem={renderBrief} - contentContainerStyle={{ padding: abstand.m, paddingTop: 0 }} - ListEmptyComponent={ - - {briefe.length === 0 - ? 'Noch keine Briefe.\nScannen Sie Ihren ersten Behördenbrief!' - : 'Keine Treffer.'} - - } - /> - + } + ListEmptyComponent={ + briefe.length === 0 ? ( + + 📬 + Noch keine Briefe + + Scannen Sie Ihren ersten Behördenbrief —{'\n'}in einer Minute + wissen Sie, was er bedeutet. + + + ) : ( + Keine Treffer. + ) + } + /> ); } const styles = StyleSheet.create({ container: { flex: 1, backgroundColor: farben.hintergrund }, - kopf: { padding: abstand.m, gap: abstand.s }, - reihe: { flexDirection: 'row' }, + inhalt: { paddingHorizontal: abstand.m, paddingBottom: abstand.l }, + kopf: { paddingTop: abstand.s, paddingBottom: abstand.s, gap: abstand.s }, + reihe: { flexDirection: 'row', gap: abstand.s }, + kachel: { + flex: 1, + minHeight: TOUCH_TARGET + 22, + backgroundColor: farben.flaeche, + borderRadius: 16, + borderWidth: 1, + borderColor: farben.rand, + alignItems: 'center', + justifyContent: 'center', + paddingVertical: abstand.s, + gap: 4, + ...kartenSchatten, + }, + kachelSymbol: { fontSize: 26 }, + kachelTitel: { fontSize: schrift.klein + 1, fontWeight: '600', color: farben.primaer }, + abschnittsLabel: { + marginTop: abstand.m, + fontSize: schrift.klein - 1, + fontWeight: '600', + letterSpacing: 1.2, + textTransform: 'uppercase', + color: farben.textSekundaer, + }, suche: { - marginHorizontal: abstand.m, - marginBottom: abstand.s, + backgroundColor: farben.flaeche, borderWidth: 1, borderColor: farben.rand, borderRadius: 12, @@ -154,20 +207,25 @@ const styles = StyleSheet.create({ alignItems: 'center', backgroundColor: farben.flaeche, borderRadius: 14, + borderWidth: 1, + borderColor: farben.rand, + borderLeftWidth: 6, padding: abstand.m, marginBottom: abstand.s, gap: abstand.s, + ...kartenSchatten, }, - ampelPunkt: { width: 16, height: 16, borderRadius: 8 }, kartenTitel: { fontSize: schrift.basis, fontWeight: '700', color: farben.text }, kartenUntertitel: { fontSize: schrift.klein, color: farben.textSekundaer, marginTop: 2 }, kartenAmpelText: { fontSize: schrift.klein, fontWeight: '600', marginTop: 2 }, pfeil: { fontSize: 32, color: farben.textSekundaer }, + leerBox: { alignItems: 'center', marginTop: abstand.xl, gap: abstand.xs }, + leerSymbol: { fontSize: 52 }, + leerTitel: { fontSize: schrift.gross, fontWeight: '700', color: farben.text }, leer: { textAlign: 'center', fontSize: schrift.basis, color: farben.textSekundaer, - marginTop: abstand.xl, lineHeight: 28, }, }); diff --git a/src/theme.ts b/src/theme.ts index 4149430..5d2fbfb 100644 --- a/src/theme.ts +++ b/src/theme.ts @@ -5,14 +5,18 @@ * - Große Touch-Targets (min. 56px Höhe) */ export const farben = { - // Grundfarben - hintergrund: '#FFFFFF', - flaeche: '#F2F5F9', + // Grundfarben — warmer Papier-Ton als Markenzeichen (wie die Webseite): + // Inhalte liegen als weiße "Blätter" auf Papier + hintergrund: '#FAF7F0', + flaeche: '#FFFFFF', primaer: '#1A365D', // dunkles, ruhiges Blau primaerText: '#FFFFFF', text: '#1A202C', textSekundaer: '#4A5568', - rand: '#CBD5E0', + rand: '#E4DECF', + // Akzent: Textmarker-Gelb (sparsam einsetzen — nur für DIE Kernaussage) + markerHintergrund: '#FFF6D2', + markerRand: '#EBDD9A', // Dringlichkeits-Ampel (kräftig, gut unterscheidbar) ampelRot: '#C0392B', @@ -43,3 +47,12 @@ export const abstand = { /** Mindesthöhe für alle interaktiven Elemente (Barrierefreiheit). */ export const TOUCH_TARGET = 56; + +/** Dezenter Schatten, damit weiße Karten sich vom Papier-Grund abheben. */ +export const kartenSchatten = { + shadowColor: '#1A202C', + shadowOffset: { width: 0, height: 2 }, + shadowOpacity: 0.07, + shadowRadius: 6, + elevation: 2, +} as const;