update
This commit is contained in:
@@ -7,9 +7,9 @@ import Ueben from './components/Ueben.vue'
|
||||
import Kennzahlen from './components/Kennzahlen.vue'
|
||||
|
||||
const topics = ref([])
|
||||
const topic = ref('')
|
||||
const topic = ref(localStorage.getItem('topic') || '') // Auswahl über Reload halten
|
||||
const state = ref(null)
|
||||
const tab = ref('board')
|
||||
const tab = ref(localStorage.getItem('tab') || 'board')
|
||||
const neuName = ref('')
|
||||
const neuArt = ref('thema')
|
||||
const fehler = ref('')
|
||||
@@ -24,6 +24,9 @@ function navToggle() {
|
||||
localStorage.setItem('navAuf', navAuf.value ? '1' : '0')
|
||||
}
|
||||
watch(navAuf, (a) => document.body.classList.toggle('nav-zu', !a), { immediate: true })
|
||||
// Ansicht über Reload halten: gewähltes Topic + Tab merken
|
||||
watch(topic, (t) => localStorage.setItem('topic', t))
|
||||
watch(tab, (t) => localStorage.setItem('tab', t))
|
||||
|
||||
let wsSchliessen = null
|
||||
let timer = null
|
||||
@@ -40,6 +43,8 @@ media.addEventListener('change', themeAnwenden)
|
||||
|
||||
async function topicsLaden() {
|
||||
topics.value = await api.topics()
|
||||
// gemerktes Topic gelöscht? → verwerfen, dann erst auf das erste zurückfallen
|
||||
if (topic.value && !topics.value.some((t) => t.name === topic.value)) topic.value = ''
|
||||
if (!topic.value && topics.value.length) topic.value = topics.value[0].name
|
||||
}
|
||||
|
||||
|
||||
@@ -41,7 +41,6 @@ const EBENEN = [
|
||||
{ key: 'inventar', titel: 'Atome' },
|
||||
{ key: 'artefakte', titel: 'Artefakte' },
|
||||
{ key: 'struktur', titel: 'Bausteine' },
|
||||
{ key: 'diagramme', titel: 'Diagramme' },
|
||||
{ key: 'guide', titel: 'Guide' },
|
||||
]
|
||||
|
||||
@@ -80,10 +79,6 @@ function karten(key) {
|
||||
return s.bausteine.map((b) => ({ id: b.id, text: `${b.ord + 1}. ${b.titel}`,
|
||||
badges: [[b.status, statusFarbe(b.status)]] }))
|
||||
}
|
||||
if (key === 'diagramme') {
|
||||
return (s.diagramme || []).map((d) => ({ id: d.id, text: `${d.ord + 1}. ${d.titel}`,
|
||||
badges: [[d.status, statusFarbe(d.status)], [`${d.typ} · ${d.quelle}`, 'blau']] }))
|
||||
}
|
||||
return s.bausteine.map((b) => ({ id: b.id, text: `${b.ord + 1}. ${b.titel}`,
|
||||
badges: [[b.stage || 'offen', b.stage === 'done' ? 'gruen' : 'blau']] }))
|
||||
}
|
||||
|
||||
@@ -1,14 +1,8 @@
|
||||
<script setup>
|
||||
import { computed, nextTick, onUnmounted, ref, watch } from 'vue'
|
||||
import mermaid from 'mermaid'
|
||||
import { api } from '../api.js'
|
||||
import { render, lesestat } from '../markdown.js'
|
||||
|
||||
// securityLevel:'strict' → kein foreignObject/HTML-Label (umgeht DOMPurify-Filter),
|
||||
// keine Klick-Handler. startOnLoad:false → wir rendern selbst nach jedem Einblenden.
|
||||
mermaid.initialize({ startOnLoad: false, securityLevel: 'strict', theme: 'neutral' })
|
||||
let mmId = 0
|
||||
|
||||
const props = defineProps({ topic: String, state: Object })
|
||||
const daten = ref(null)
|
||||
const level = ref('E') // Durchgang-Wahl: jede Stufe ist ein eigener Lese-Durchgang
|
||||
@@ -46,27 +40,6 @@ function html(s) {
|
||||
return htmlCache.get(key)
|
||||
}
|
||||
|
||||
// Mermaid rendert asynchron ins DOM — nach jedem Einblenden (Scroll/Level/Ansicht)
|
||||
// die noch nicht verarbeiteten ```mermaid-Blöcke im sichtbaren Bereich rendern.
|
||||
async function renderMermaid() {
|
||||
await nextTick()
|
||||
const wurzel = scrollEl.value
|
||||
if (!wurzel) return
|
||||
for (const code of wurzel.querySelectorAll('code.language-mermaid:not([data-mm])')) {
|
||||
code.setAttribute('data-mm', '1')
|
||||
const pre = code.closest('pre')
|
||||
try {
|
||||
const { svg } = await mermaid.render(`mm-${mmId++}`, code.textContent)
|
||||
const figur = document.createElement('div')
|
||||
figur.className = 'mermaid-figur'
|
||||
figur.innerHTML = svg
|
||||
pre?.replaceWith(figur)
|
||||
} catch {
|
||||
pre?.classList.add('mermaid-fehler') // kaputt: als Codeblock stehen lassen
|
||||
}
|
||||
}
|
||||
}
|
||||
watch([aktiv, ansicht, level, daten], renderMermaid, { flush: 'post' })
|
||||
|
||||
// Nur aktives Kapitel ±1 im DOM; der Rest ist ein Platzhalter mit Schätzhöhe
|
||||
const sichtbar = (i) => Math.abs(i - aktiv.value) <= 1
|
||||
|
||||
@@ -64,7 +64,7 @@ const MARKER = /<!--\s*atom:.*?-->/g
|
||||
export function lesestat(text) {
|
||||
let displayFormeln = 0
|
||||
const t = (text || '')
|
||||
.replace(/```[\s\S]*?```/g, ' ') // Code-/Diagramm-Fences zählen nicht als Text
|
||||
.replace(/```[\s\S]*?```/g, ' ') // Code-Fences zählen nicht als Text
|
||||
.replace(MARKER, ' ')
|
||||
.replace(/\$\$[\s\S]+?\$\$/g, () => { displayFormeln += 1; return ' ' })
|
||||
.replace(/\\\[[\s\S]+?\\\]/g, () => { displayFormeln += 1; return ' ' })
|
||||
|
||||
@@ -123,7 +123,7 @@ input, select {
|
||||
/* Board: Ebenen-Spalten links→rechts, Listen VOLLSTÄNDIG scrollbar */
|
||||
.board { display: flex; gap: 10px; padding: 12px; overflow-x: auto; flex: 1; min-height: 0; }
|
||||
.spalte {
|
||||
min-width: 265px; max-width: 320px; flex: 1; display: flex; flex-direction: column;
|
||||
min-width: 0; max-width: 320px; flex: 1; display: flex; flex-direction: column;
|
||||
background: var(--panel); border: 1px solid var(--rand); border-radius: 8px;
|
||||
}
|
||||
.spaltekopf { padding: 8px 10px; border-bottom: 1px solid var(--rand); display: grid; gap: 6px; }
|
||||
@@ -223,8 +223,6 @@ body.nav-zu .hauptbereich { padding-top: 38px; }
|
||||
}
|
||||
.guide-section .ziel { color: var(--akzent); font-size: 13px; }
|
||||
:is(.markdown, .kompakt) .katex-display { overflow-x: auto; overflow-y: hidden; padding: 4px 0; }
|
||||
.mermaid-figur { overflow-x: auto; text-align: center; margin: 16px 0; }
|
||||
.mermaid-figur svg { max-width: 100%; height: auto; }
|
||||
.markdown blockquote {
|
||||
margin: 12px 0; padding: 8px 14px; border-left: 3px solid var(--akzent);
|
||||
background: var(--karte); border-radius: 0 6px 6px 0; color: var(--text);
|
||||
|
||||
Reference in New Issue
Block a user