diff --git a/src/app.ts b/src/app.ts index b23d559..4d95d68 100644 --- a/src/app.ts +++ b/src/app.ts @@ -38,6 +38,7 @@ function migrateProgress( if (!progress.lastPlayedLevels) progress.lastPlayedLevels = []; if (progress.totalCorrect === undefined) progress.totalCorrect = 0; if (progress.totalErrors === undefined) progress.totalErrors = 0; + if (progress.currentForestPage === undefined) progress.currentForestPage = 0; } async function handleLessonComplete( @@ -120,7 +121,9 @@ async function handleLessonComplete( async () => { // "Zurück zum Wald" -- show forest with new element animated await initForestScreen(db, startLessonFromForest); - await renderForestScene(db, elementId); + const prog = await getProgress(db); + const page = prog?.currentForestPage ?? 0; + await renderForestScene(db, page, elementId); showScreen("forest"); }, ); diff --git a/src/forest/scene.ts b/src/forest/scene.ts index f04d162..e1c29ee 100644 --- a/src/forest/scene.ts +++ b/src/forest/scene.ts @@ -5,8 +5,11 @@ import { playForestElementSound } from "../audio/sounds"; let activeObjectUrls: string[] = []; +export const SLOTS_PER_PAGE = 12; + export async function renderForestScene( db: IDBDatabase, + page: number, newElementId?: number, ): Promise { const grid = document.getElementById("forest-grid"); @@ -21,9 +24,10 @@ export async function renderForestScene( const elements = await getForestElements(db); grid.innerHTML = ""; - // Render up to 12 elements (4x3 grid) - const maxSlots = 12; - const toRender = elements.slice(0, maxSlots); + // Render elements for the given page (4x3 grid per page) + const start = page * SLOTS_PER_PAGE; + const end = start + SLOTS_PER_PAGE; + const toRender = elements.slice(start, end); for (const element of toRender) { const slot = document.createElement("div"); @@ -51,6 +55,28 @@ export async function renderForestScene( slot.appendChild(img); grid.appendChild(slot); } + + // Update navigation UI + const totalPages = Math.max(1, Math.ceil(elements.length / SLOTS_PER_PAGE)); + const navContainer = document.getElementById("forest-nav"); + if (navContainer) { + const prevBtn = document.getElementById( + "forest-nav-prev", + ) as HTMLButtonElement; + const nextBtn = document.getElementById( + "forest-nav-next", + ) as HTMLButtonElement; + const pageText = document.getElementById("forest-nav-text"); + + if (totalPages <= 1) { + navContainer.style.display = "none"; + } else { + navContainer.style.display = "flex"; + prevBtn.disabled = page <= 0; + nextBtn.disabled = page >= totalPages - 1; + if (pageText) pageText.textContent = `Wald ${page + 1} von ${totalPages}`; + } + } } export function getLevelStatus( @@ -113,7 +139,8 @@ export async function initForestScreen( if (!progress) return; renderLevelMap(mapContainer, progress, onStartLesson); - await renderForestScene(db); + const currentPage = progress.currentForestPage ?? 0; + await renderForestScene(db, currentPage); const allComplete = levels.every((l) => progress.completedLevels.includes(l.level), diff --git a/src/storage/db.test.ts b/src/storage/db.test.ts index afa6354..578338a 100644 --- a/src/storage/db.test.ts +++ b/src/storage/db.test.ts @@ -37,6 +37,7 @@ describe("IndexedDB wrapper", () => { totalErrors: 0, errorKeyCounts: {}, lastPlayedLevels: [], + currentForestPage: 0, }; await saveProgress(db, progress); const result = await getProgress(db); diff --git a/src/types.ts b/src/types.ts index 08363b4..2fd55b5 100644 --- a/src/types.ts +++ b/src/types.ts @@ -18,6 +18,7 @@ export interface Progress { totalErrors: number; errorKeyCounts: Record; lastPlayedLevels: number[]; // last 3 played levels for review mechanic + currentForestPage: number; // 0-indexed, default 0 } export type LessonPhase = "discover" | "practice" | "words"; diff --git a/src/ui/screens.ts b/src/ui/screens.ts index de0d7dc..64ee85b 100644 --- a/src/ui/screens.ts +++ b/src/ui/screens.ts @@ -83,6 +83,7 @@ export function initWelcomeScreen( totalErrors: 0, errorKeyCounts: {}, lastPlayedLevels: [], + currentForestPage: 0, }; await saveProgress(db, progress); navigateTo("forest");