Web: Laufansicht zentriert, Favicon, dynamischer Seitentitel, aktive Stufe hervorgehoben

Tastaturhinweis im Lesemodus nur bei Maus/Tastatur.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
team3
2026-10-05 16:45:14 +02:00
parent bbae194554
commit 8d28680a12
4 changed files with 11 additions and 2 deletions

View File

@@ -4,7 +4,7 @@
<meta charset="UTF-8" /> <meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>buchwerk</title> <title>buchwerk</title>
<link rel="icon" href="data:," /> <link rel="icon" type="image/svg+xml" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'><rect width='32' height='32' rx='7' fill='%237a5b2c'/><path d='M8 8h7a3 3 0 0 1 3 3v13a2 2 0 0 0-2-2H8zM24 8h-7a3 3 0 0 0-3 3v13a2 2 0 0 1 2-2h8z' fill='%23f8f1de'/></svg>" />
</head> </head>
<body> <body>
<div id="app"></div> <div id="app"></div>

View File

@@ -37,6 +37,7 @@ watch(topic, (t) => { localStorage.setItem('topic', t); urlSchreiben(false) })
watch(tab, (t) => { localStorage.setItem('tab', t); urlSchreiben(true) }) watch(tab, (t) => { localStorage.setItem('tab', t); urlSchreiben(true) })
const aktuell = computed(() => topics.value.find((t) => t.name === topic.value)) const aktuell = computed(() => topics.value.find((t) => t.name === topic.value))
watch([aktuell, tab], ([a, t]) => { if (t !== 'buch') document.title = a ? `${a.titel} – buchwerk` : 'buchwerk' }, { immediate: true })
const laeuft = computed(() => state.value?.status === 'laeuft') const laeuft = computed(() => state.value?.status === 'laeuft')
const fortschritt = computed(() => (state.value?.stufen || []).reduce((n, s) => n + (s.fertig || 0), 0)) const fortschritt = computed(() => (state.value?.stufen || []).reduce((n, s) => n + (s.fertig || 0), 0))

View File

@@ -74,6 +74,12 @@ const gelesen = computed(() => {
return ids.length ? Math.round(100 * Math.max(0, i) / ids.length) : 0 return ids.length ? Math.round(100 * Math.max(0, i) / ids.length) : 0
}) })
// Kapitel, in dem die aktive Stelle liegt — nur dieses zeigt in der Nav seine Abschnitte; sonst das erste // Kapitel, in dem die aktive Stelle liegt — nur dieses zeigt in der Nav seine Abschnitte; sonst das erste
// Seitentitel: aktueller Abschnitt und Buch, für Tabs und Verlauf.
watch([aktiv, daten], ([id, d]) => {
if (!d) return
const a = d.kapitel.flatMap((k) => k.abschnitte).find((x) => 'a' + x.id === id)
document.title = a ? `${a.nr} ${a.titel} – ${d.titel}` : `${d.titel} – buchwerk`
})
const aktivKap = computed(() => { const aktivKap = computed(() => {
const id = aktiv.value, ks = daten.value?.kapitel || [] const id = aktiv.value, ks = daten.value?.kapitel || []
const k = ks.find((k) => 'k' + k.id === id || k.abschnitte.some((a) => 'a' + a.id === id)) const k = ks.find((k) => 'k' + k.id === id || k.abschnitte.some((a) => 'a' + a.id === id))

View File

@@ -66,7 +66,7 @@ a.knopf { display: inline-block; text-decoration: none; line-height: normal; }
.fehler { margin: 10px 16px; padding: 8px 12px; border: 1px solid var(--rot); border-radius: 6px; color: var(--rot); cursor: pointer; } .fehler { margin: 10px 16px; padding: 8px 12px; border: 1px solid var(--rot); border-radius: 6px; color: var(--rot); cursor: pointer; }
/* Lauf-Ansicht */ /* Lauf-Ansicht */
.lauf { padding: 18px 22px; overflow-y: auto; } .lauf { padding: 18px max(22px, calc((100% - 760px) / 2)); overflow-y: auto; } /* Spalte zentriert wie in der Buchansicht */
.lauf .aktionen { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; margin-bottom: 14px; } .lauf .aktionen { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; margin-bottom: 14px; }
.lauf .grund { margin: 8px 0 14px; padding: 8px 12px; background: var(--karte); border-left: 3px solid var(--gelb); border-radius: 4px; } .lauf .grund { margin: 8px 0 14px; padding: 8px 12px; background: var(--karte); border-left: 3px solid var(--gelb); border-radius: 4px; }
.deutung { max-width: 760px; margin: 0 0 16px; padding: 12px 14px; background: var(--panel); border: 1px solid var(--rand); border-radius: 8px; } .deutung { max-width: 760px; margin: 0 0 16px; padding: 12px 14px; background: var(--panel); border: 1px solid var(--rand); border-radius: 8px; }
@@ -77,6 +77,7 @@ a.knopf { display: inline-block; text-decoration: none; line-height: normal; }
.deutung .fakten b { font-weight: 600; color: var(--text); margin-right: 4px; } .deutung .fakten b { font-weight: 600; color: var(--text); margin-right: 4px; }
.stufen { display: grid; gap: 6px; max-width: 760px; } .stufen { display: grid; gap: 6px; max-width: 760px; }
.stufe { display: grid; grid-template-columns: 26px 1fr auto auto; gap: 10px; align-items: center; padding: 9px 12px; background: var(--panel); border: 1px solid var(--rand); border-radius: 8px; } .stufe { display: grid; grid-template-columns: 26px 1fr auto auto; gap: 10px; align-items: center; padding: 9px 12px; background: var(--panel); border: 1px solid var(--rand); border-radius: 8px; }
.stufe.laeuft { border-color: var(--akzent); box-shadow: inset 3px 0 0 var(--akzent); }
.stufe .kreis { width: 18px; height: 18px; border-radius: 50%; border: 2px solid var(--rand); display: grid; place-items: center; font-size: 11px; } .stufe .kreis { width: 18px; height: 18px; border-radius: 50%; border: 2px solid var(--rand); display: grid; place-items: center; font-size: 11px; }
.stufe.fertig .kreis { background: var(--gruen); border-color: var(--gruen); color: #fff; } .stufe.fertig .kreis { background: var(--gruen); border-color: var(--gruen); color: #fff; }
.stufe.laeuft .kreis { border-color: var(--akzent); border-top-color: transparent; animation: dreh 0.9s linear infinite; } .stufe.laeuft .kreis { border-color: var(--akzent); border-top-color: transparent; animation: dreh 0.9s linear infinite; }
@@ -199,6 +200,7 @@ a.knopf { display: inline-block; text-decoration: none; line-height: normal; }
.lm-fuss { display: flex; justify-content: space-between; padding: 10px 18px; border-top: 1px solid var(--lese-rand); font-family: system-ui, sans-serif; } .lm-fuss { display: flex; justify-content: space-between; padding: 10px 18px; border-top: 1px solid var(--lese-rand); font-family: system-ui, sans-serif; }
.lm-fuss button { background: var(--karte); color: var(--text); border: 1px solid var(--rand); } .lm-fuss button { background: var(--karte); color: var(--text); border: 1px solid var(--rand); }
.lm-fuss button.weiter { background: var(--akzent); color: #fff; border: 0; } .lm-fuss button.weiter { background: var(--akzent); color: #fff; border: 0; }
@media (hover: none) { kbd { display: none; } } /* Tastaturhinweis nur mit Maus/Tastatur */
kbd { font: 11px system-ui, sans-serif; border: 1px solid var(--rand); border-radius: 4px; padding: 0 5px; margin-left: 6px; color: var(--dim); } kbd { font: 11px system-ui, sans-serif; border: 1px solid var(--rand); border-radius: 4px; padding: 0 5px; margin-left: 6px; color: var(--dim); }
/* Barrierefreiheit: sichtbarer Fokus für Tastatur, Sprunglink, keine Animationen auf Wunsch */ /* Barrierefreiheit: sichtbarer Fokus für Tastatur, Sprunglink, keine Animationen auf Wunsch */