update
This commit is contained in:
@@ -11,7 +11,7 @@ EFFORT = "high"
|
|||||||
PARALLEL = 5 # gleichzeitige Kapitel-Agenten
|
PARALLEL = 5 # gleichzeitige Kapitel-Agenten
|
||||||
MAX_TURNS = 800
|
MAX_TURNS = 800
|
||||||
KONSISTENZ_GRUPPE = 5 # Kapitel je Querverweis-Agent
|
KONSISTENZ_GRUPPE = 5 # Kapitel je Querverweis-Agent
|
||||||
LESE_WPM = 180
|
LESE_WPM = 120
|
||||||
|
|
||||||
STUFEN = [
|
STUFEN = [
|
||||||
("recherche", "Thema deuten und Quellen beschaffen"),
|
("recherche", "Thema deuten und Quellen beschaffen"),
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ class ThemaNeu(BaseModel):
|
|||||||
|
|
||||||
class Position(BaseModel):
|
class Position(BaseModel):
|
||||||
abschnitt: str | None = None
|
abschnitt: str | None = None
|
||||||
lesemodus: int | None = None
|
lesemodus: str | int | None = None # neu: key des Bildschirms, alt: Index
|
||||||
|
|
||||||
|
|
||||||
def _pruefen(name: str) -> dict:
|
def _pruefen(name: str) -> dict:
|
||||||
|
|||||||
@@ -8,25 +8,41 @@ const emit = defineEmits(['schliessen'])
|
|||||||
const buehne = ref(null)
|
const buehne = ref(null)
|
||||||
const pos = ref(0)
|
const pos = ref(0)
|
||||||
|
|
||||||
// Bildschirme: Vorwort, je Kapitel ein Intro, je Abschnitt ein Bildschirm, Ende.
|
// Ein Abschnitt wird an seinen Zwischenüberschriften (###) in Seiten geteilt; Codeblöcke bleiben ganz.
|
||||||
|
function teile(text) {
|
||||||
|
const out = []
|
||||||
|
let akt = [], zaun = false
|
||||||
|
for (const zeile of (text || '').split('\n')) {
|
||||||
|
if (/^(```|~~~)/.test(zeile)) zaun = !zaun
|
||||||
|
if (!zaun && /^### /.test(zeile) && akt.some((z) => z.trim())) { out.push(akt.join('\n')); akt = [] }
|
||||||
|
akt.push(zeile)
|
||||||
|
}
|
||||||
|
if (akt.some((z) => z.trim())) out.push(akt.join('\n'))
|
||||||
|
return out.length ? out : ['']
|
||||||
|
}
|
||||||
|
// Bildschirme: Vorwort, je Kapitel ein Intro, je Seite eines Abschnitts ein Bildschirm, Ende.
|
||||||
|
// key ist die gespeicherte Leseposition und bleibt stabil, wenn Kapitel dazukommen.
|
||||||
const screens = computed(() => {
|
const screens = computed(() => {
|
||||||
const out = []
|
const out = []
|
||||||
const kaps = props.daten?.kapitel || []
|
const kaps = props.daten?.kapitel || []
|
||||||
if (props.daten?.vorwort) out.push({ typ: 'vorwort' })
|
if (props.daten?.vorwort) out.push({ typ: 'vorwort', key: 'vorwort' })
|
||||||
kaps.forEach((kap, ki) => {
|
kaps.forEach((kap, ki) => {
|
||||||
out.push({ typ: 'kapitel', kap, nr: ki + 1, von: kaps.length })
|
out.push({ typ: 'kapitel', kap, nr: ki + 1, von: kaps.length, key: 'k' + (ki + 1) })
|
||||||
for (const a of kap.abschnitte) out.push({ typ: 'abschnitt', a, kap })
|
for (const a of kap.abschnitte) {
|
||||||
|
const t = teile(a.text)
|
||||||
|
t.forEach((text, i) => out.push({ typ: 'abschnitt', a, kap, text, i, n: t.length, key: a.id + ':' + i }))
|
||||||
|
}
|
||||||
})
|
})
|
||||||
out.push({ typ: 'ende' })
|
out.push({ typ: 'ende', key: 'ende' })
|
||||||
return out
|
return out
|
||||||
})
|
})
|
||||||
const screen = computed(() => screens.value[pos.value] || { typ: 'ende' })
|
const screen = computed(() => screens.value[pos.value] || { typ: 'ende' })
|
||||||
const gesamt = computed(() => screens.value.filter((s) => s.typ === 'abschnitt').length)
|
const gesamt = computed(() => screens.value.filter((s) => s.typ === 'abschnitt').length)
|
||||||
const gelesen = computed(() => screens.value.slice(0, pos.value + 1).filter((s) => s.typ === 'abschnitt').length)
|
const gelesen = computed(() => screens.value.slice(0, pos.value + 1).filter((s) => s.typ === 'abschnitt').length)
|
||||||
const cache = new Map()
|
const cache = new Map()
|
||||||
function html(a) {
|
function html(s) {
|
||||||
const key = a.id + ':' + (a.text || '').length
|
const key = s.key + ':' + s.text.length
|
||||||
if (!cache.has(key)) cache.set(key, render(a.text))
|
if (!cache.has(key)) cache.set(key, render(s.text))
|
||||||
return cache.get(key)
|
return cache.get(key)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -36,7 +52,8 @@ let merkTimer = null
|
|||||||
watch(pos, (p) => {
|
watch(pos, (p) => {
|
||||||
buehne.value?.scrollTo({ top: 0 })
|
buehne.value?.scrollTo({ top: 0 })
|
||||||
clearTimeout(merkTimer)
|
clearTimeout(merkTimer)
|
||||||
merkTimer = setTimeout(() => api.positionSetzen(props.topic, { lesemodus: p }).catch(() => {}), 1500)
|
const key = screens.value[p]?.key
|
||||||
|
if (key) merkTimer = setTimeout(() => api.positionSetzen(props.topic, { lesemodus: key }).catch(() => {}), 1500)
|
||||||
})
|
})
|
||||||
|
|
||||||
function taste(e) {
|
function taste(e) {
|
||||||
@@ -65,8 +82,10 @@ function wischEnde(e) {
|
|||||||
}
|
}
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
window.addEventListener('keydown', taste)
|
window.addEventListener('keydown', taste)
|
||||||
const merk = Number((await api.position(props.topic).catch(() => ({}))).lesemodus || 0)
|
const merk = (await api.position(props.topic).catch(() => ({}))).lesemodus
|
||||||
pos.value = Math.min(merk, screens.value.length - 1)
|
// Alte Positionen waren ein Index, neue sind ein key.
|
||||||
|
const 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))
|
onUnmounted(() => window.removeEventListener('keydown', taste))
|
||||||
</script>
|
</script>
|
||||||
@@ -74,9 +93,9 @@ onUnmounted(() => window.removeEventListener('keydown', taste))
|
|||||||
<template>
|
<template>
|
||||||
<div class="lesemodus" @touchstart.passive="wischStart" @touchend.passive="wischEnde">
|
<div class="lesemodus" @touchstart.passive="wischStart" @touchend.passive="wischEnde">
|
||||||
<header class="lm-kopf">
|
<header class="lm-kopf">
|
||||||
<span>{{ gelesen }} / {{ gesamt }} Abschnitte</span>
|
<span>{{ gelesen }} / {{ gesamt }} Seiten</span>
|
||||||
<div class="balken"><i :style="{ width: (gesamt ? 100 * gelesen / gesamt : 0) + '%' }"></i></div>
|
<div class="balken"><i :style="{ width: (gesamt ? 100 * gelesen / gesamt : 0) + '%' }"></i></div>
|
||||||
<span v-if="screen.typ === 'abschnitt'">{{ screen.kap.titel }}</span>
|
<span v-if="screen.typ === 'abschnitt'">{{ screen.a.nr }} · {{ screen.i + 1 }} / {{ screen.n }}</span>
|
||||||
<button title="Schließen (Esc)" @click="emit('schliessen')">✕</button>
|
<button title="Schließen (Esc)" @click="emit('schliessen')">✕</button>
|
||||||
</header>
|
</header>
|
||||||
<main ref="buehne" class="lm-buehne">
|
<main ref="buehne" class="lm-buehne">
|
||||||
@@ -95,13 +114,13 @@ onUnmounted(() => window.removeEventListener('keydown', taste))
|
|||||||
<div v-else class="stats">{{ screen.kap.abschnitte.length }} Abschnitte · {{ zeit(screen.kap.minuten) }}</div>
|
<div v-else class="stats">{{ screen.kap.abschnitte.length }} Abschnitte · {{ zeit(screen.kap.minuten) }}</div>
|
||||||
</section>
|
</section>
|
||||||
<section v-else-if="screen.typ === 'abschnitt'" class="lm-screen">
|
<section v-else-if="screen.typ === 'abschnitt'" class="lm-screen">
|
||||||
<div class="lm-label">{{ screen.kap.titel }}</div>
|
<div class="lm-label">{{ screen.kap.titel }}<template v-if="screen.i > 0"> · {{ screen.a.nr }} {{ screen.a.titel }}</template></div>
|
||||||
<h2>{{ screen.a.nr }} {{ screen.a.titel }}</h2>
|
<h2 v-if="screen.i === 0">{{ screen.a.nr }} {{ screen.a.titel }}</h2>
|
||||||
<div v-html="html(screen.a)"></div>
|
<div v-html="html(screen)"></div>
|
||||||
</section>
|
</section>
|
||||||
<section v-else class="lm-screen ende">
|
<section v-else class="lm-screen ende">
|
||||||
<h1>Fertig gelesen</h1>
|
<h1>Fertig gelesen</h1>
|
||||||
<p class="intro">Alle {{ gesamt }} Abschnitte von „{{ daten.titel }}“.</p>
|
<p class="intro">Alle {{ gesamt }} Seiten von „{{ daten.titel }}“.</p>
|
||||||
<button class="sekundaer" style="margin-top: 16px" @click="pos = 0">Von vorn</button>
|
<button class="sekundaer" style="margin-top: 16px" @click="pos = 0">Von vorn</button>
|
||||||
</section>
|
</section>
|
||||||
</main>
|
</main>
|
||||||
|
|||||||
Reference in New Issue
Block a user