diff --git a/backend/main.py b/backend/main.py index 7636a2a..64eb22b 100644 --- a/backend/main.py +++ b/backend/main.py @@ -34,6 +34,7 @@ class ThemaNeu(BaseModel): class Position(BaseModel): abschnitt: str | None = None lesemodus: str | int | None = None # neu: key des Bildschirms, alt: Index + zuletzt: str | None = None # 'buch' oder 'lesen': welche Ansicht zuletzt gelesen wurde def _thema(slug: str) -> dict: diff --git a/frontend/src/App.vue b/frontend/src/App.vue index 67d5c29..5a1efa1 100644 --- a/frontend/src/App.vue +++ b/frontend/src/App.vue @@ -201,7 +201,7 @@ function tokens(n) { return n >= 1e6 ? (n / 1e6).toFixed(1) + 'M' : n >= 1e3 ? M @neue-version="neueVersion" /> + @tab="(t) => geheZu({ tab: t })" @nr="(e) => geheZu({ nr: e.nr }, !e.push)" />
Thema links anlegen oder wählen.
diff --git a/frontend/src/components/Guide.vue b/frontend/src/components/Guide.vue index f482013..b19ba73 100644 --- a/frontend/src/components/Guide.vue +++ b/frontend/src/components/Guide.vue @@ -19,6 +19,17 @@ function idVonNr(nr) { } return '' } +// Lesemodus-Schlüssel (vorwort, k3, a03-4:2, ende) → Element-ID der Buchansicht, wenn zuletzt dort gelesen wurde +function idVonLesemodus(pos) { + if (pos.zuletzt !== 'lesen' || !pos.lesemodus || !daten.value) return '' + const m = pos.lesemodus + if (m === 'vorwort') return 'vorwort' + const kap = /^k(\d+)$/.exec(m) + if (kap) return 'k' + (daten.value.kapitel[Number(kap[1]) - 1]?.id || '') + const abs = /^(a[\d-]+):/.exec(m) + if (abs) return abs[1] + return '' +} function nrVonId(id) { if (!id || !daten.value) return '' if (id === 'vorwort') return 'vorwort' @@ -61,7 +72,7 @@ let ladeSeq = 0 let merkTimer = null function merken(id) { clearTimeout(merkTimer) - merkTimer = setTimeout(() => api.positionSetzen(props.slug, props.version, { abschnitt: id }).catch(() => {}), 1500) + merkTimer = setTimeout(() => api.positionSetzen(props.slug, props.version, { abschnitt: id, zuletzt: 'buch' }).catch(() => {}), 1500) } const cache = new Map() // Schlüssel: Abschnitt + Textlänge → unveränderte Abschnitte werden nicht neu gerendert @@ -75,8 +86,8 @@ async function laden() { daten.value = d await nextTick() spy() - // Abschnitt in der Adresse hat Vorrang vor der gemerkten Position; beides nur beim ersten Laden - const ziel = idVonNr(props.nr) || pos.abschnitt + // Gemerkte Position hat Vorrang (die Adresse spiegelt nur den letzten Scrollstand); zuletzt im Lesemodus gelesen → dessen Stelle + const ziel = idVonLesemodus(pos) || pos.abschnitt || idVonNr(props.nr) if (ziel && !aktiv.value) document.getElementById(ziel)?.scrollIntoView({ block: 'start' }) } watch(() => [props.slug, props.version], () => { aktiv.value = ''; cache.clear(); laden() }, { immediate: true }) @@ -118,6 +129,7 @@ const kapBadge = { geschrieben: ['gelb', 'geschrieben'], geprueft: ['blau', 'gep function spy() { beobachter?.disconnect() beobachter = new IntersectionObserver((es) => { + if (lesemodus.value) return for (const e of es) if (e.isIntersecting) { aktiv.value = e.target.id; merken(e.target.id); emit('nr', { nr: nrVonId(e.target.id), push: false }) } }, { root: lese.value, rootMargin: '0px 0px -75% 0px' }) document.querySelectorAll('.buch [data-spy]').forEach((el) => beobachter.observe(el)) diff --git a/frontend/src/components/Lesemodus.vue b/frontend/src/components/Lesemodus.vue index 657f2de..703e170 100644 --- a/frontend/src/components/Lesemodus.vue +++ b/frontend/src/components/Lesemodus.vue @@ -53,7 +53,7 @@ watch(pos, (p) => { buehne.value?.scrollTo({ top: 0 }) clearTimeout(merkTimer) const key = screens.value[p]?.key - if (key) merkTimer = setTimeout(() => api.positionSetzen(props.slug, props.version, { lesemodus: key }).catch(() => {}), 1500) + if (key) merkTimer = setTimeout(() => api.positionSetzen(props.slug, props.version, { lesemodus: key, zuletzt: 'lesen' }).catch(() => {}), 1500) }) function taste(e) { @@ -82,9 +82,16 @@ function wischEnde(e) { } onMounted(async () => { window.addEventListener('keydown', taste) - const merk = (await api.position(props.slug, props.version).catch(() => ({}))).lesemodus + const p = await api.position(props.slug, props.version).catch(() => ({})) + const merk = p.lesemodus + // Zuletzt in der Buchansicht gelesen → beim passenden Abschnitt bzw. Kapitel beginnen + let i = -1 + if (p.zuletzt === 'buch' && p.abschnitt) { + const a = p.abschnitt + i = screens.value.findIndex((s) => s.key === a || s.key.startsWith(a + ':') || (s.typ === 'kapitel' && 'k' + s.kap.id === a)) + } // Alte Positionen waren ein Index, neue sind ein key. - const i = typeof merk === 'string' ? screens.value.findIndex((s) => s.key === merk) : Number(merk || 0) + if (i < 0) i = typeof merk === 'string' ? screens.value.findIndex((s) => s.key === merk) : Number(merk || 0) pos.value = Math.min(Math.max(i, 0), screens.value.length - 1) }) onUnmounted(() => window.removeEventListener('keydown', taste))