import SwiftUI /// Rendert die Karten-Inhalte je nach `CardType`. Front-/Back-Seite /// werden über `isFlipped` gesteuert. /// /// β-2 deckt `basic`, `basic-reverse`, `cloze` ab. Restliche Typen /// zeigen einen Placeholder mit Hinweis auf die kommende Phase. struct CardRenderer: View { let card: ReviewCard let subIndex: Int let isFlipped: Bool var body: some View { Group { switch card.type { case .basic: basicView(front: "front", back: "back") case .basicReverse: // sub_index 0 = front→back, sub_index 1 = back→front if subIndex == 0 { basicView(front: "front", back: "back") } else { basicView(front: "back", back: "front") } case .cloze: clozeView case .imageOcclusion, .audioFront, .typing, .multipleChoice: placeholderView } } .padding(24) .frame(maxWidth: .infinity, maxHeight: .infinity) } @ViewBuilder private func basicView(front frontKey: String, back backKey: String) -> some View { VStack(spacing: 16) { text(card.fields[frontKey] ?? "") .font(.title2) .foregroundStyle(CardsTheme.foreground) if isFlipped { Divider().background(CardsTheme.border) text(card.fields[backKey] ?? "") .font(.title3) .foregroundStyle(CardsTheme.mutedForeground) } } } @ViewBuilder private var clozeView: some View { let raw = card.fields["text"] ?? "" let clusterId = Cloze.clusterId(for: raw, subIndex: subIndex) ?? 1 let rendered = isFlipped ? Cloze.renderAnswer(raw, activeClusterId: clusterId) : Cloze.renderPrompt(raw, activeClusterId: clusterId) VStack(spacing: 12) { text(rendered) .font(.title3) .foregroundStyle(CardsTheme.foreground) } } @ViewBuilder private var placeholderView: some View { VStack(spacing: 8) { Image(systemName: "questionmark.square.dashed") .font(.largeTitle) .foregroundStyle(CardsTheme.mutedForeground) Text("Card-Type »\(card.type.rawValue)« kommt in einer späteren Phase") .font(.caption) .multilineTextAlignment(.center) .foregroundStyle(CardsTheme.mutedForeground) } } /// Markdown-Bold (`**...**`) wird auf SwiftUI's AttributedString gemappt. private func text(_ markdown: String) -> some View { let attributed = (try? AttributedString( markdown: markdown, options: AttributedString.MarkdownParsingOptions( interpretedSyntax: .inlineOnlyPreservingWhitespace ) )) ?? AttributedString(markdown) return Text(attributed) .multilineTextAlignment(.center) } }