update
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
<script setup>
|
||||
import BausteinPanel from './BausteinPanel.vue'
|
||||
import { renderMarkdown } from '../markdown.js'
|
||||
import { stufeFuer, STUFEN } from '../stufen.js'
|
||||
|
||||
const props = defineProps({
|
||||
baustein: { type: Object, required: true }, // { title, md, num }
|
||||
@@ -12,7 +13,7 @@ const props = defineProps({
|
||||
ansicht: { type: String, default: 'kompakt' }, // kompakt | erklärend — linke Guide-Spalte
|
||||
hasPrev: { type: Boolean, default: false },
|
||||
hasNext: { type: Boolean, default: false },
|
||||
fortschritt: { type: Object, default: () => ({ total: 0, absolviert: 0, verstanden: 0, gemeistert: 0 }) },
|
||||
fortschritt: { type: Object, default: () => ({ total: 0, anfaenger: 0, fortgeschritten: 0, experte: 0, meister: 0 }) },
|
||||
})
|
||||
|
||||
import { computed, onMounted, onUnmounted, ref } from 'vue'
|
||||
@@ -58,13 +59,14 @@ onUnmounted(() => {
|
||||
|
||||
const pct = (n) => (100 * n / (props.fortschritt.total || 1)) + '%'
|
||||
|
||||
// Akzentfarbe nach Stand des aktuellen Bausteins: gemeistert=gold, verstanden=lila, absolviert=grün.
|
||||
// Akzentfarbe nach Stufe des aktuellen Bausteins (grün/blau/lila/gold) oder neutral.
|
||||
const standFarbe = computed(() => {
|
||||
const s = props.status || {}
|
||||
if (s.gemeistert) return '#d4af37'
|
||||
if (s.verstanden) return '#8b5cf6'
|
||||
if (s.absolviert) return 'var(--success-border)'
|
||||
return 'var(--border)'
|
||||
return stufeFuer(s.gute_antworten || 0, s.cap || props.cap)?.farbe || 'var(--border)'
|
||||
})
|
||||
const stufe = computed(() => {
|
||||
const s = props.status || {}
|
||||
return stufeFuer(s.gute_antworten || 0, s.cap || props.cap)
|
||||
})
|
||||
</script>
|
||||
|
||||
@@ -76,17 +78,16 @@ const standFarbe = computed(() => {
|
||||
<button class="fokus-btn" :disabled="!hasPrev" title="Voriger Baustein" @click="$emit('prev')">←</button>
|
||||
<button class="fokus-btn" :disabled="!hasNext" title="Nächster Baustein" @click="$emit('next')">→</button>
|
||||
<span class="fokus-titel">{{ baustein.title }}</span>
|
||||
<span v-if="status?.gemeistert" class="stand-badge gold">✓✓✓ Gemeistert</span>
|
||||
<span v-else-if="status?.verstanden" class="stand-badge lila">✓✓ Verstanden</span>
|
||||
<span v-else-if="status?.absolviert" class="stand-badge gruen">✓ Absolviert</span>
|
||||
<span v-if="stufe" class="stand-badge" :style="{ color: stufe.farbe, borderColor: stufe.farbe }">{{ stufe.kurz }} {{ stufe.label }}</span>
|
||||
<span class="fokus-spacer"></span>
|
||||
<button class="fokus-btn" title="Vollansicht beenden" @click="$emit('close')">✕</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="fokus-xp" :title="`${fortschritt.absolviert}/${fortschritt.total} absolviert · ${fortschritt.verstanden} verstanden · ${fortschritt.gemeistert} gemeistert`">
|
||||
<div class="xp-seg gold" :style="{ width: pct(fortschritt.gemeistert) }"></div>
|
||||
<div class="xp-seg lila" :style="{ width: pct(fortschritt.verstanden - fortschritt.gemeistert) }"></div>
|
||||
<div class="xp-seg gruen" :style="{ width: pct(fortschritt.absolviert - fortschritt.verstanden) }"></div>
|
||||
<div class="fokus-xp" :title="`${fortschritt.anfaenger}/${fortschritt.total} ab Anfänger · ${fortschritt.fortgeschritten} Fortgeschritten · ${fortschritt.experte} Experte · ${fortschritt.meister} Meister`">
|
||||
<div class="xp-seg" :style="{ width: pct(fortschritt.meister), background: 'var(--stufe-meister)' }"></div>
|
||||
<div class="xp-seg" :style="{ width: pct(fortschritt.experte - fortschritt.meister), background: 'var(--stufe-experte)' }"></div>
|
||||
<div class="xp-seg" :style="{ width: pct(fortschritt.fortgeschritten - fortschritt.experte), background: 'var(--stufe-fortgeschritten)' }"></div>
|
||||
<div class="xp-seg" :style="{ width: pct(fortschritt.anfaenger - fortschritt.fortgeschritten), background: 'var(--stufe-anfaenger)' }"></div>
|
||||
</div>
|
||||
<div class="fokus-body">
|
||||
<div ref="guideEl" class="fokus-col left">
|
||||
|
||||
@@ -3,6 +3,7 @@ import { computed, nextTick, onMounted, onUnmounted, ref } from 'vue'
|
||||
import { chatBaustein, pruefeBaustein, fetchFrageMuster } from '../api.js'
|
||||
import { usePruefSlot } from '../pruefungCache.js'
|
||||
import { renderMarkdown, renderMarkdownInline } from '../markdown.js'
|
||||
import { stufeFuer, malusRegel } from '../stufen.js'
|
||||
import { useChat, istUnten } from '../composables/useChat.js'
|
||||
|
||||
const props = defineProps({
|
||||
@@ -22,74 +23,40 @@ const props = defineProps({
|
||||
|
||||
const emit = defineEmits(['statusChanged', 'openFokus', 'setAnsicht'])
|
||||
|
||||
// Meilensteine (Score-Bänder): Quiz→6, Lückentext→12, Erklären→18, FullGuide-Max 30.
|
||||
const ABSOLVIERT = 6
|
||||
const VERSTANDEN = 12
|
||||
const GEMEISTERT = 18
|
||||
const VOLL = 30
|
||||
const st = computed(() => props.status || { gute_antworten: 0, streak: 0, absolviert: false, verstanden: false, gemeistert: false })
|
||||
// Volle Prüfung (cap 30): durchgehend zufällig aus allen 5 Formen. Kurze Prüfung (cap 6):
|
||||
// Score-Band + Schwierigkeit (ALT+E). Ohne Frage-Muster (alter Baustein) nur Erklären.
|
||||
// Lernstufen relativ zum cap (stufen.js): grün/blau/lila/gold @ 20/40/60/100 %.
|
||||
// Prüfung IMMER zufällig aus 5 Formen (mit Muster); cap = 2×relevante Subbausteine.
|
||||
const MODI = ['quiz_leicht', 'quiz_schwer', 'lueck_leicht', 'lueck_schwer', 'erklaeren']
|
||||
const st = computed(() => props.status || { gute_antworten: 0, streak: 0, cap: props.cap })
|
||||
const score = computed(() => st.value.gute_antworten || 0)
|
||||
const schwerWahl = ref(false) // leicht/schwer in den Bändern unter 19 (ALT+E)
|
||||
// Band aus einem Score: Lückentext ab 6, Erklären ab 12, Zufall ab 18 (Meilenstein-inklusiv).
|
||||
function bandFuer(s) {
|
||||
if (s >= GEMEISTERT) return 'zufall'
|
||||
if (s >= VERSTANDEN) return 'erklaeren'
|
||||
if (s >= ABSOLVIERT) return 'lueckentext'
|
||||
return 'quiz'
|
||||
}
|
||||
// Am Format-Max: Score eingefroren („Max"). Gilt auch bei cap 30 (FullGuide, endgültig).
|
||||
const amDeckel = computed(() => score.value >= props.cap)
|
||||
// Aktuelles Band: volle Prüfung (cap 30) ist DURCHGEHEND zufällig aus allen 5 Formen.
|
||||
// Sonst score-basiert (am Deckel das Band des erreichten Formats, cap−1).
|
||||
// Ohne Frage-Muster (alter Baustein) gibt es nur Erklären.
|
||||
const aktuellesBand = computed(() =>
|
||||
!musterModus.value ? 'erklaeren'
|
||||
: props.cap >= VOLL ? 'zufall'
|
||||
: bandFuer(amDeckel.value ? props.cap - 1 : score.value))
|
||||
// 'zufall' = Platzhalter; das gezogene Objekt trägt die echte Form/Schwierigkeit.
|
||||
const aktiverModus = computed(() => {
|
||||
const b = aktuellesBand.value
|
||||
if (b === 'lueckentext') return schwerWahl.value ? 'lueck_schwer' : 'lueck_leicht'
|
||||
if (b === 'quiz') return schwerWahl.value ? 'quiz_schwer' : 'quiz_leicht'
|
||||
return b // 'erklaeren' | 'zufall'
|
||||
})
|
||||
const cap = computed(() => st.value.cap || props.cap)
|
||||
const scoreAnzeige = computed(() => Math.min(score.value, cap.value)) // Altbestand kann cap übersteigen
|
||||
const stufe = computed(() => stufeFuer(score.value, cap.value)) // Objekt {key,label,kurz,farbe} | null
|
||||
const schwerWahl = ref(false) // ungenutzt im Zufallsmodus (immer zufällig)
|
||||
const amDeckel = computed(() => score.value >= cap.value)
|
||||
// Mit Frage-Muster zufällig aus 5 Formen; ohne Muster (alter Baustein) nur Erklären.
|
||||
const aktuellesBand = computed(() => musterModus.value ? 'zufall' : 'erklaeren')
|
||||
const imZufall = computed(() => aktuellesBand.value === 'zufall')
|
||||
const aktiveForm = computed(() => {
|
||||
const m = aktiverModus.value
|
||||
if (m === 'zufall') return 'quiz' // Platzhalter fürs idle-Widget; Objekt überschreibt
|
||||
return m.startsWith('quiz') ? 'quiz' : m.startsWith('lueck') ? 'lueckentext' : 'erklaeren'
|
||||
})
|
||||
const schwer = computed(() => aktiverModus.value.endsWith('_schwer'))
|
||||
// Angezeigte Form: folgt der aktiven Form, friert aber ein, solange eine gezogene Frage
|
||||
// sichtbar ist (sonst verschwindet das Ergebnis, wenn die Antwort eine Bandgrenze überschreitet).
|
||||
const aktiverModus = computed(() => aktuellesBand.value) // 'zufall' | 'erklaeren'
|
||||
const aktiveForm = computed(() => imZufall.value ? 'quiz' : 'erklaeren') // Platzhalter; gezogenes Objekt überschreibt
|
||||
const schwer = computed(() => false)
|
||||
// Angezeigte Form: folgt der aktiven Form, friert ein, solange eine gezogene Frage sichtbar ist.
|
||||
const anzeigeForm = ref(null)
|
||||
const zeigeForm = computed(() => anzeigeForm.value || aktiveForm.value)
|
||||
// Band, in dem die gezeigte Frage gezogen wurde. Weicht es vom aktuellen Band ab, hat die
|
||||
// letzte Antwort einen Meilenstein überschritten → Button „Zum nächsten Abschnitt".
|
||||
const anzeigeBand = ref(null)
|
||||
const abschnittWechsel = computed(() => anzeigeBand.value && anzeigeBand.value !== aktuellesBand.value)
|
||||
// Schwierigkeit des gerade gezeigten Widgets (eingefroren) bzw. der aktiven Wahl.
|
||||
// Schwierigkeit des gerade gezeigten Widgets (vom gezogenen Objekt).
|
||||
const aktSchwer = computed(() => {
|
||||
if (zeigeForm.value === 'quiz' && quizAktuell.value) return quizAktuell.value.schwer
|
||||
if (zeigeForm.value === 'lueckentext' && lueckAktuell.value) return lueckAktuell.value.schwer
|
||||
return schwer.value
|
||||
return false
|
||||
})
|
||||
const modusRegel = computed(() => {
|
||||
const m = score.value >= GEMEISTERT ? '−3' : '−1' // Fehler kostet erst ab Score 18 −3
|
||||
const m = malusRegel(score.value, cap.value) // '0' | '−1' | '−2' | '−3' nach Fortschritt
|
||||
if (zeigeForm.value === 'quiz') return aktSchwer.value ? `x von 4 · +3/${m}` : `1 von 4 · +1/${m}`
|
||||
if (zeigeForm.value === 'lueckentext') return aktSchwer.value ? `frei tippen · +3/${m}` : `Begriff aus 4 · +1/${m}`
|
||||
return score.value >= GEMEISTERT ? '+1/+2/+3 · Fehler −3' : '+1/+2/+3 · Nachfragen max +1 · schwach −1'
|
||||
})
|
||||
// Ende des aktuellen Bands (nächster Meilenstein).
|
||||
const bandZiel = computed(() => {
|
||||
if (score.value >= GEMEISTERT) return VOLL
|
||||
if (score.value >= VERSTANDEN) return GEMEISTERT
|
||||
if (score.value >= ABSOLVIERT) return VERSTANDEN
|
||||
return ABSOLVIERT
|
||||
return `+1/+2/+3 · Fehler ${m}`
|
||||
})
|
||||
const bandZiel = computed(() => cap.value)
|
||||
const FORM_NAME = { quiz: 'Quiz', lueckentext: 'Lückentext', erklaeren: 'Erklären' }
|
||||
|
||||
// --- Toggle-Bereich ---
|
||||
@@ -141,7 +108,7 @@ function onPruefScroll() {
|
||||
|
||||
function applyPruefung(res) {
|
||||
// res.streak nur bei antwort_pruefen gesetzt (verbindlich, persistiert); sonst Streak unverändert lassen.
|
||||
emit('statusChanged', { baustein: props.baustein, ...st.value, gute_antworten: res.gute_antworten, streak: res.streak ?? st.value.streak, absolviert: res.absolviert, verstanden: res.verstanden, gemeistert: res.gemeistert })
|
||||
emit('statusChanged', { baustein: props.baustein, ...st.value, gute_antworten: res.gute_antworten, streak: res.streak ?? st.value.streak, cap: res.cap ?? cap.value })
|
||||
}
|
||||
|
||||
async function pruefScroll() {
|
||||
@@ -310,8 +277,8 @@ function poolFormPruefen() {
|
||||
function poolFuellen() {
|
||||
poolFormPruefen()
|
||||
const keyBeginn = poolKey.value
|
||||
const cap = musterModus.value ? Infinity : 3
|
||||
while (pool.value.length + inflight.value < POOL_ZIEL && poolMiss < cap) {
|
||||
const missCap = musterModus.value ? Infinity : 3
|
||||
while (pool.value.length + inflight.value < POOL_ZIEL && poolMiss < missCap) {
|
||||
inflight.value++
|
||||
frageEinzeln()
|
||||
.then((obj) => {
|
||||
@@ -326,10 +293,10 @@ function poolFuellen() {
|
||||
// Ein Frage-Objekt aus dem Pool nehmen; ist er leer, auf das erste eintreffende warten.
|
||||
async function poolNehmen() {
|
||||
if (!pool.value.length) {
|
||||
const cap = musterModus.value ? Infinity : 3
|
||||
const missCap = musterModus.value ? Infinity : 3
|
||||
pruefLoading.value = true
|
||||
try {
|
||||
while (!pool.value.length && (inflight.value > 0 || poolMiss < cap)) {
|
||||
while (!pool.value.length && (inflight.value > 0 || poolMiss < missCap)) {
|
||||
if (!inflight.value) poolFuellen()
|
||||
await new Promise((r) => setTimeout(r, 120))
|
||||
}
|
||||
@@ -657,10 +624,8 @@ function onPruefKey(e) {
|
||||
</button>
|
||||
<button :class="{ active: activeTab === 'pruefung' }" @click="tabKlick('pruefung')">
|
||||
Prüfung
|
||||
<span v-if="st.gemeistert" class="bp-chip gold" :title="`Gemeistert (${GEMEISTERT})`">✓✓✓ {{ score }}/{{ cap }}</span>
|
||||
<span v-else-if="st.verstanden" class="bp-chip lila" :title="`Verstanden (${VERSTANDEN})`">✓✓ {{ score }}/{{ cap }}</span>
|
||||
<span v-else-if="st.absolviert" class="bp-chip done" :title="`Absolviert (${ABSOLVIERT})`">✓ {{ score }}/{{ cap }}</span>
|
||||
<span v-else-if="score" class="bp-chip">{{ score }}/{{ cap }}</span>
|
||||
<span v-if="stufe" class="bp-chip" :style="{ borderColor: stufe.farbe, color: stufe.farbe }" :title="`${stufe.label} (${cap})`">{{ stufe.kurz }} {{ scoreAnzeige }}/{{ cap }}</span>
|
||||
<span v-else-if="score" class="bp-chip">{{ scoreAnzeige }}/{{ cap }}</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@@ -692,9 +657,9 @@ function onPruefKey(e) {
|
||||
<!-- Prüfung: gesteuerter Dialog -->
|
||||
<div v-else>
|
||||
<p class="bp-hint">
|
||||
<template v-if="amDeckel">{{ FORM_NAME[zeigeForm] }} · {{ score }}/{{ cap }} — <strong>Max</strong>.</template>
|
||||
<template v-else-if="imZufall && !anzeigeForm">Zufällig · {{ score }}/{{ cap }}</template>
|
||||
<template v-else-if="imZufall">{{ FORM_NAME[zeigeForm] }} · {{ score }}/{{ cap }} · {{ modusRegel }}</template>
|
||||
<template v-if="amDeckel">{{ FORM_NAME[zeigeForm] }} · {{ scoreAnzeige }}/{{ cap }} — <strong>Max</strong>.</template>
|
||||
<template v-else-if="imZufall && !anzeigeForm">Zufällig · {{ scoreAnzeige }}/{{ cap }}</template>
|
||||
<template v-else-if="imZufall">{{ FORM_NAME[zeigeForm] }} · {{ scoreAnzeige }}/{{ cap }} · {{ modusRegel }}</template>
|
||||
<template v-else>{{ FORM_NAME[zeigeForm] }} · {{ score }}/{{ bandZiel }} · {{ modusRegel }}</template>
|
||||
</p>
|
||||
<button
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
import { computed, reactive, ref, watch, nextTick, onMounted, onUnmounted } from 'vue'
|
||||
import { fetchGuideContent, chatGuide, fetchBausteinLernstand } from '../api.js'
|
||||
import { renderMarkdown } from '../markdown.js'
|
||||
import { stufeFuer, schwelle } from '../stufen.js'
|
||||
import { useChat } from '../composables/useChat.js'
|
||||
import BausteinPanel from './BausteinPanel.vue'
|
||||
import BausteinFokus from './BausteinFokus.vue'
|
||||
@@ -83,10 +84,15 @@ async function loadContent() {
|
||||
}
|
||||
|
||||
// --- Baustein-Lernen: Prüfungs-Stand pro Baustein-Titel (lernstand oben deklariert) ---
|
||||
function stufeVon(title) {
|
||||
const l = lernstand.value[title]
|
||||
return l ? stufeFuer(l.gute_antworten || 0, l.cap || 10) : null
|
||||
}
|
||||
function onBausteinStatus(baustein, status) {
|
||||
const warAbsolviert = lernstand.value[baustein]?.absolviert
|
||||
const alt = stufeVon(baustein)?.key || null
|
||||
lernstand.value = { ...lernstand.value, [baustein]: status }
|
||||
if (status.absolviert && !warAbsolviert) emit('progressChanged') // Locks/Stats neu laden
|
||||
const neu = stufeFuer(status.gute_antworten || 0, status.cap || 10)?.key || null
|
||||
if (neu !== alt) emit('progressChanged') // Stufenwechsel → Locks/Stats neu laden
|
||||
}
|
||||
|
||||
// --- Vollbild-Fokus: ein Baustein groß, Guide links + Prüfung rechts ---
|
||||
@@ -116,20 +122,25 @@ function fokusNext() {
|
||||
for (let i = fokusIndex.value + 1; i < bausteine.value.length; i++) if (istPruefbar(bausteine.value[i])) { fokusIndex.value = i; return }
|
||||
}
|
||||
|
||||
// Erfahrungsleiste: Lernstand über alle Bausteine des Guides (sticky, absolviert ⊇ verstanden ⊇ gemeistert).
|
||||
// Erfahrungsleiste: kumulativer Stufen-Stand über alle Bausteine (gold ⊆ lila ⊆ blau ⊆ grün).
|
||||
const fortschritt = computed(() => {
|
||||
let a = 0, v = 0, g = 0
|
||||
const z = { total: bausteine.value.length, anfaenger: 0, fortgeschritten: 0, experte: 0, meister: 0 }
|
||||
for (const s of bausteine.value) {
|
||||
const l = lernstand.value[s.title] || {}
|
||||
if (l.absolviert) a++
|
||||
if (l.verstanden) v++
|
||||
if (l.gemeistert) g++
|
||||
const l = lernstand.value[s.title]
|
||||
if (!l) continue
|
||||
const sc = l.gute_antworten || 0, cp = l.cap || 10
|
||||
if (sc >= schwelle(0.2, cp)) z.anfaenger++
|
||||
if (sc >= schwelle(0.4, cp)) z.fortgeschritten++
|
||||
if (sc >= schwelle(0.6, cp)) z.experte++
|
||||
if (sc >= schwelle(1.0, cp)) z.meister++
|
||||
}
|
||||
return { total: bausteine.value.length, absolviert: a, verstanden: v, gemeistert: g }
|
||||
return z
|
||||
})
|
||||
|
||||
// Prüfung läuft voll 0–30, sobald Guide ODER FullGuide fertig ist (gleicher Baustein-Score).
|
||||
const cap = computed(() => ((props.doneByFormat?.Guide || props.doneByFormat?.FullGuide) ? 30 : 6))
|
||||
// cap je Baustein = 2×relevante Subbausteine (vom Backend in lernstand[title].cap geliefert).
|
||||
function capVon(title) {
|
||||
return lernstand.value[title]?.cap || 10
|
||||
}
|
||||
|
||||
// Section prüfbar? Rest nie. Sonst prüfbar, außer das Feld ist explizit false (FullGuide-Rand).
|
||||
// Fehlt das Feld (alte Guides ohne `pruefbar`) → prüfbar, damit Bestands-Guides weiter funktionieren.
|
||||
@@ -223,7 +234,7 @@ function extractContext() {
|
||||
<header class="guide-head">
|
||||
<h1>{{ previewGuide.topic }}</h1>
|
||||
<span class="guide-format">{{ previewGuide.format }}</span>
|
||||
<span v-if="themaAbgeschlossen" class="thema-done" title="Alle Bausteine gemeistert (18/18)">✓ Thema abgeschlossen</span>
|
||||
<span v-if="themaAbgeschlossen" class="thema-done" title="Alle Bausteine auf Meister">✓ Thema abgeschlossen</span>
|
||||
</header>
|
||||
|
||||
<section
|
||||
@@ -238,14 +249,13 @@ function extractContext() {
|
||||
v-for="s in ch.sections"
|
||||
:key="s.num"
|
||||
:data-num="s.num"
|
||||
:class="['section-card', lernstand[s.title]?.gemeistert ? 'gemeistert' : (lernstand[s.title]?.verstanden ? 'verstanden' : (lernstand[s.title]?.absolviert ? 'absolviert' : ''))]"
|
||||
class="section-card"
|
||||
:style="stufeVon(s.title) ? { borderLeftColor: stufeVon(s.title).farbe } : {}"
|
||||
>
|
||||
<h3 :class="{ 'baustein-klick': istPruefbar(s) }" @click="istPruefbar(s) && openFokus(s, 'pruefung')">
|
||||
{{ s.title }}
|
||||
<template v-if="istPruefbar(s)">
|
||||
<span v-if="lernstand[s.title]?.gemeistert" class="baustein-done gemeistert" title="Gemeistert (25/25)">✓✓✓ Gemeistert</span>
|
||||
<span v-else-if="lernstand[s.title]?.verstanden" class="baustein-done verstanden" title="Vollständig verstanden (10/10)">✓✓ Verstanden</span>
|
||||
<span v-else-if="lernstand[s.title]?.absolviert" class="baustein-done" title="Prüfung bestanden">✓ Absolviert</span>
|
||||
<template v-if="istPruefbar(s) && stufeVon(s.title)">
|
||||
<span class="baustein-done" :style="{ color: stufeVon(s.title).farbe, borderColor: stufeVon(s.title).farbe }" :title="`${stufeVon(s.title).label} (${capVon(s.title)})`">{{ stufeVon(s.title).kurz }} {{ stufeVon(s.title).label }}</span>
|
||||
</template>
|
||||
</h3>
|
||||
<div v-if="sichtbar[s.num]" class="section-body markdown" v-html="htmlFor(s)"></div>
|
||||
@@ -255,7 +265,7 @@ function extractContext() {
|
||||
mode="trigger"
|
||||
:baustein="s.title"
|
||||
:status="lernstand[s.title]"
|
||||
:cap="cap"
|
||||
:cap="capVon(s.title)"
|
||||
:topic="previewGuide.topic"
|
||||
@open-fokus="(tab) => openFokus(s, tab)"
|
||||
/>
|
||||
@@ -280,7 +290,7 @@ function extractContext() {
|
||||
:provider="provider"
|
||||
:fortschritt="fortschritt"
|
||||
:status="lernstand[fokusBaustein.title]"
|
||||
:cap="cap"
|
||||
:cap="capVon(fokusBaustein.title)"
|
||||
:tab="fokusTab"
|
||||
:ansicht="ansichtModus"
|
||||
:has-prev="fokusIndex > 0"
|
||||
|
||||
Reference in New Issue
Block a user