This commit is contained in:
team3
2026-07-13 16:11:00 +02:00
parent 9cd8e02e22
commit a8e8e077bd
14 changed files with 454 additions and 62 deletions

View File

@@ -14,6 +14,7 @@ const neuName = ref('')
const neuArt = ref('thema')
const fehler = ref('')
const theme = ref(localStorage.getItem('theme') || 'auto')
const guideRef = ref(null) // Header-Play-Button startet den Lernmodus im Guide
// mobil (≤768px) startet die Navigation eingeklappt, sofern nie manuell gesetzt
const navAuf = ref(localStorage.getItem('navAuf') !== null
? localStorage.getItem('navAuf') !== '0'
@@ -209,6 +210,8 @@ function runBadge(run) {
<span v-if="state?.run?.grund" class="badge gelb">{{ state.run.grund }}</span>
<span v-if="fehler" class="badge rot">{{ fehler }}</span>
<span style="flex: 1"></span>
<button v-if="tab === 'guide' && state" class="lm-start" title="Lernmodus (Vollbild)"
@click="guideRef?.lesemodusStarten()"></button>
<select v-model="theme" title="Farbschema">
<option value="hell">hell</option>
<option value="dunkel">dunkel</option>
@@ -219,7 +222,7 @@ function runBadge(run) {
<div class="inhalt">
<Board v-if="tab === 'board'" :state="state" :topic="topic" @reload="stateLaden"
@fehler="(e) => (fehler = e)" />
<Guide v-else-if="tab === 'guide'" :topic="topic" :state="state" />
<Guide v-else-if="tab === 'guide'" ref="guideRef" :topic="topic" :state="state" />
<Ueben v-else-if="tab === 'üben'" :topic="topic" />
<Kennzahlen v-else :run="state?.run" />
</div>

View File

@@ -55,6 +55,16 @@ const info = (key) => props.state?.ebenen?.find((e) => e.name === key) || {}
const aktiveAtome = computed(() =>
(props.state?.atome || []).filter((a) => !['gemerged', 'verworfen'].includes(a.status)))
// Spaltenkopf Artefakte: Gesamtfortschritt = Summe verifiziert / Summe Soll
const artefakteSumme = computed(() => {
let ok = 0, ziel = 0
for (const a of aktiveAtome.value) {
ok += a.artefakte?.verifiziert || 0
ziel += a.artefakte?.gesamt || 0
}
return { ok, ziel }
})
function karten(key) {
const s = props.state
if (!s) return []
@@ -146,7 +156,11 @@ const k = (n) => (n >= 1e6 ? `${(n / 1e6).toFixed(1)}M` : n >= 1000 ? `${Math.ro
<div class="spaltekopf">
<div class="zeile">
<span class="titel">{{ e.titel }}
<span class="badge">{{ karten(e.key).length }}</span></span>
<span class="badge">{{ karten(e.key).length }}</span>
<span v-if="e.key === 'artefakte' && artefakteSumme.ziel" class="badge"
:class="artefakteSumme.ok >= artefakteSumme.ziel ? 'gruen' : ''">
{{ artefakteSumme.ok }}/{{ artefakteSumme.ziel }} verifiziert
</span></span>
<span class="badge" :class="info(e.key).laeuft ? 'blau' : info(e.key).fertig ? 'gruen' : ''">
{{ info(e.key).laeuft ? 'läuft' : info(e.key).fertig ? 'fertig' : 'offen' }}
</span>

View File

@@ -6,6 +6,8 @@ import Lesemodus from './Lesemodus.vue'
const props = defineProps({ topic: String, state: Object })
const lesemodus = ref(false) // Vollbild-Lernmodus (Fundament + Abrufprüfung)
// Header-Play-Button (App.vue) startet den Lernmodus von außen
defineExpose({ lesemodusStarten: () => { lesemodus.value = true } })
const daten = ref(null)
const level = ref('E') // Durchgang-Wahl: jede Stufe ist ein eigener Lese-Durchgang
const ansicht = ref('erklaerend') // erklaerend = Fließtext | kompakt = Stichpunkte
@@ -158,8 +160,6 @@ function onScroll(e) {
</button>
<button class="schalter-solo" title="Fokus-Modus (ablenkungsfrei lesen)"
@click="fokus = true"></button>
<button v-if="daten" class="schalter-solo lm-start" title="Lernmodus (Vollbild)"
@click="lesemodus = true"></button>
</div>
<div class="fortschritt">
<div>Kapitel {{ aktiv + 1 }} / {{ anzeige.length }}</div>

View File

@@ -61,6 +61,24 @@ function taste(e) {
else if (e.key === 'ArrowLeft') zurueck()
}
// Wisch-Navigation (mobil): klar horizontal + kurz genug = blättern.
// Vertikales Scrollen und Text-Markieren bleiben unberührt (dy-Vergleich).
let wisch = null
function wischStart(e) {
const t = e.touches[0]
wisch = { x: t.clientX, y: t.clientY }
}
function wischEnde(e) {
if (!wisch) return
const t = e.changedTouches[0]
const dx = t.clientX - wisch.x
const dy = t.clientY - wisch.y
wisch = null
if (Math.abs(dx) < 60 || Math.abs(dx) < 2 * Math.abs(dy)) return
if (dx < 0) vor()
else zurueck()
}
// ── Abrufprüfung (Karteikarten) ────────────────────────────────────────────────
const stapel = ref([])
const zeigeAntwort = ref(false)
@@ -155,7 +173,8 @@ onUnmounted(() => {
</script>
<template>
<div ref="wurzel" class="lesemodus">
<div ref="wurzel" class="lesemodus"
@touchstart.passive="wischStart" @touchend.passive="wischEnde">
<header class="lm-kopf">
<span class="lm-fort">{{ fortschrittText }}</span>
<button class="lm-x" title="Schließen" @click="schliessen"></button>
@@ -205,7 +224,6 @@ onUnmounted(() => {
'pf-wahr': urteil(x.id) === true,
'pf-falsch2': urteil(x.id) === false }"
@click.prevent="toggle(x.id)">
<input type="checkbox" :checked="auswahl.has(x.id)" @click.stop="toggle(x.id)" />
<span class="markdown" v-html="render(x.text)"></span>
</label>
</div>

View File

@@ -332,8 +332,12 @@ table.kennzahlen th { color: var(--dim); }
padding: 12px 14px; border: 1px solid var(--rand); border-radius: 10px;
background: var(--karte);
}
.pf-aussage input { margin-top: 5px; flex: 0 0 auto; }
.pf-aussage.gewaehlt { border-color: var(--akzent); }
/* Auswahl ohne Checkbox: die ganze Karte ist der Klickbereich */
.pf-aussage.gewaehlt {
border-color: var(--akzent);
background: color-mix(in srgb, var(--akzent) 10%, var(--karte));
box-shadow: inset 3px 0 0 var(--akzent);
}
.pf-aussage.pf-wahr { border-color: #2f7d32; background: color-mix(in srgb, #2f7d32 14%, var(--karte)); }
.pf-aussage.pf-falsch2 { border-color: #a23b3b; background: color-mix(in srgb, #a23b3b 12%, var(--karte)); }
.pf-feedback { margin-top: 14px; padding: 10px 14px; border-radius: 8px; font-size: 15px; }