/** * CardView — rendert EINE Karte einer aria_view-Spec (M1). Schaltet nach * card.type auf den passenden Renderer. Unbekannte Typen werden als Text- * Fallback gezeigt (nie crashen). * * Bewusst dependency-leicht (v1): Markdown wird als Klartext dargestellt, Map * als Marker-Liste (kein Karten-Lib), Code als Monospace-Block. Spaeter koennen * einzelne Renderer aufgebohrt werden, ohne die Spec/den Fluss zu aendern. */ import React from 'react'; import { Image, ScrollView, StyleSheet, Text, View } from 'react-native'; import { ViewCard, ViewMarker } from '../services/ariaView'; const ImageBody: React.FC<{ src?: string }> = ({ src }) => { const isUrl = !!src && /^https?:\/\//i.test(src); if (isUrl) { return ; } return 🖼️ {src || '(kein Bild)'}; }; const ListBody: React.FC<{ md?: string }> = ({ md }) => { const lines = (md || '') .split('\n') .map((l) => l.replace(/^\s*[-*•]\s?/, '').trim()) .filter(Boolean); if (lines.length === 0) return (leer); return ( {lines.map((l, i) => ( {l} ))} ); }; const MapBody: React.FC<{ markers?: ViewMarker[] }> = ({ markers }) => { const ms = Array.isArray(markers) ? markers : []; return ( 🗺️ Karte ({ms.length} Orte) {ms.map((m, i) => ( 📍 {m.label || `${m.lat?.toFixed?.(4)}, ${m.lon?.toFixed?.(4)}`} ))} ); }; const CodeBody: React.FC<{ md?: string; path?: string; lang?: string }> = ({ md, path, lang }) => ( {(path || lang) && ( {path || ''}{lang ? ` · ${lang}` : ''} )} {md || ''} ); const CardView: React.FC<{ card: ViewCard }> = ({ card }) => { return ( {!!card.title && {card.title}} {card.type === 'image' ? ( ) : card.type === 'list' ? ( ) : card.type === 'map' ? ( ) : card.type === 'code' ? ( ) : ( {card.md || ''} )} ); }; const styles = StyleSheet.create({ card: { backgroundColor: 'rgba(18,18,42,0.92)', borderColor: 'rgba(123,92,255,0.35)', borderWidth: 1, borderRadius: 14, padding: 14, marginVertical: 8, shadowColor: '#7B5CFF', shadowOpacity: 0.25, shadowRadius: 12, shadowOffset: { width: 0, height: 2 }, elevation: 6, }, cardTitle: { color: '#C9C9FF', fontSize: 15, fontWeight: '700', marginBottom: 8 }, text: { color: '#E6E6F0', fontSize: 14, lineHeight: 20, flexShrink: 1 }, muted: { color: '#8A8AB0', fontSize: 13, fontStyle: 'italic' }, image: { width: '100%', height: 200, borderRadius: 8, backgroundColor: '#0D0D1A' }, listRow: { flexDirection: 'row', alignItems: 'flex-start', marginVertical: 2 }, bullet: { color: '#7B5CFF', marginRight: 8, fontSize: 14, lineHeight: 20 }, map: { backgroundColor: '#0D0D1A', borderRadius: 8, padding: 10 }, mapHint: { color: '#00B4D8', fontSize: 13, fontWeight: '600', marginBottom: 6 }, codeCaption: { color: '#8A8AB0', fontSize: 12, marginBottom: 6 }, codeScroll: { backgroundColor: '#0A0A14', borderRadius: 8, padding: 10 }, code: { color: '#B9F5C9', fontFamily: 'monospace', fontSize: 12.5, lineHeight: 18 }, }); export default React.memo(CardView);