This commit is contained in:
team3
2026-07-12 04:20:07 +02:00
parent 14bcf1b8e9
commit a284e03225
29 changed files with 866 additions and 329 deletions

View File

@@ -1,14 +1,15 @@
<script setup>
import { computed, nextTick, onUnmounted, ref, watch } from 'vue'
import { api } from '../api.js'
import { render, gefiltert, lesestat, renderGestuft } from '../markdown.js'
import { render, lesestat } from '../markdown.js'
const props = defineProps({ topic: String, state: Object })
const daten = ref(null)
const level = ref('E') // Default: Einstieg — Umfang wächst per Toggle (E→M→S)
const level = ref('E') // Durchgang-Wahl: jede Stufe ist ein eigener Lese-Durchgang
const ansicht = ref('erklaerend') // erklaerend = Fließtext | kompakt = Stichpunkte
const LEVEL_ICON = { E: '●○○', M: '●●○', S: '●●●' }
const LEVEL_NAME = { E: 'Umfang: Grundgerüst', M: 'Umfang: + Standardstoff', S: 'Umfang: alles' }
const LEVEL_NAME = { E: 'Durchgang 1: Grundgerüst', M: 'Durchgang 2: Standardstoff',
S: 'Durchgang 3: Feinheiten' }
const fokus = ref(false) // Fokus: Vollbild — App-Chrome + Navigation weg, Karten aufgelöst
watch(fokus, (f) => document.body.classList.toggle('vollbild', f))
onUnmounted(() => document.body.classList.remove('vollbild'))
@@ -28,10 +29,9 @@ const htmlCache = new Map()
watch(daten, () => htmlCache.clear())
function html(s) {
const key = `${ansicht.value}|${level.value}|${s.baustein}`
const key = `${ansicht.value}|${s.baustein}`
if (!htmlCache.has(key)) {
htmlCache.set(key, ansicht.value === 'kompakt'
? render(s.kompakt || s.lang) : renderGestuft(s.lang, level.value))
htmlCache.set(key, render(ansicht.value === 'kompakt' ? s.kompakt : s.lang))
}
return htmlCache.get(key)
}
@@ -47,23 +47,29 @@ function hoehe(i) {
function setAnsicht(a) {
ansicht.value = a
laden()
}
// Nur Durchgänge anbieten, die es in diesem Thema gibt (ohne E- oder
// S-Bausteine überspringt der Toggle die Stufe)
const levels = computed(() => {
const da = new Set((daten.value?.kapitel || []).map((k) => k.level))
const folge = ['E', 'M', 'S'].filter((l) => da.has(l))
return folge.length ? folge : ['E']
})
watch(levels, (l) => { if (!l.includes(level.value)) level.value = l[0] })
function levelToggle() {
const folge = ['E', 'M', 'S']
level.value = folge[(folge.indexOf(level.value) + 1) % 3]
laden()
const folge = levels.value
level.value = folge[(folge.indexOf(level.value) + 1) % folge.length]
}
// Nur Kapitel/Bausteine mit Inhalt im gewählten Umfang anzeigen — der
// Level-Filter ließe sonst leere Titel-Hüllen stehen (36/66 Bausteine ohne E)
// Der gewählte Durchgang: nur seine Kapitel, nur Sections mit Inhalt
const anzeige = computed(() => {
const out = []
for (const kap of daten.value?.kapitel || []) {
const sections = kap.sections.filter((s) => ansicht.value === 'kompakt'
? (s.kompakt || s.lang || '').trim()
: lesestat(gefiltert(s.lang, level.value)).woerter >= 10)
if (kap.level !== level.value) continue
const sections = kap.sections.filter((s) =>
((ansicht.value === 'kompakt' ? s.kompakt : s.lang) || '').trim())
if (sections.length) out.push({ ...kap, sections })
}
return out
@@ -77,8 +83,7 @@ const stats = computed(() => {
let woerter = ansicht.value === 'kompakt' ? 0 : lesestat(kap.intro).woerter
let formeln = 0
for (const s of kap.sections) {
const st = lesestat(ansicht.value === 'kompakt' ? (s.kompakt || s.lang)
: gefiltert(s.lang, level.value))
const st = lesestat(ansicht.value === 'kompakt' ? s.kompakt : s.lang)
woerter += st.woerter
formeln += st.displayFormeln
}
@@ -156,12 +161,23 @@ function onScroll(e) {
<div v-for="(kap, i) in anzeige" :key="kap.kapitel_id" class="kapitel"
:ref="(el) => setKapEl(i, el)">
<h2 class="kapitel-titel">{{ i + 1 }}. {{ kap.titel }}</h2>
<div class="kapitel-meta">
{{ (stats.je[i]?.woerter || 0).toLocaleString('de-DE') }} Wörter ·
{{ zeit(stats.je[i]?.minuten || 0) }}
</div>
<template v-if="sichtbar(i)">
<p v-if="kap.intro && ansicht === 'erklaerend'"
style="color: var(--dim); margin-top: 0">{{ kap.intro }}</p>
<div v-for="s in kap.sections" :key="s.baustein" class="guide-section">
<h3 style="margin-top: 0">{{ s.titel }}</h3>
<div :class="ansicht === 'kompakt' ? 'kompakt' : 'markdown'" v-html="html(s)"></div>
<details v-if="ansicht === 'erklaerend' && s.fragen?.length" class="antworten">
<summary>Antworten zu Prüfe dich"</summary>
<div v-for="(f, fi) in s.fragen" :key="fi" class="antwort">
<div class="frage">{{ f.frage }}</div>
<div v-html="render(f.antwort)"></div>
</div>
</details>
</div>
</template>
<div v-else class="kapitel-platzhalter" :style="{ height: hoehe(i) + 'px' }"></div>