fix(01): add lesson cancel button and handle level 6 completion

- Back button in lesson screen to return to forest without completing
- "Alle Stufen geschafft!" message when all 6 levels are done
- Cap currentLevel at MAX_LEVEL to prevent out-of-bounds progression

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-29 11:30:55 +02:00
co-authored by Claude Opus 4.6
parent 46fa2e28d5
commit 78d516c55d
5 changed files with 69 additions and 3 deletions
+10 -1
View File
@@ -20,6 +20,8 @@ export function getDB(): IDBDatabase {
return db;
}
const MAX_LEVEL = 6;
async function handleLessonComplete(completedLevel: number): Promise<void> {
// Update progress after lesson completion
const progress = await getProgress(db);
@@ -31,7 +33,8 @@ async function handleLessonComplete(completedLevel: number): Promise<void> {
}
// Advance to next level if this was the current level (LEVL-02, LEVL-03)
if (completedLevel === progress.currentLevel) {
// Cap at MAX_LEVEL + 1 so we don't go beyond defined levels
if (completedLevel === progress.currentLevel && completedLevel < MAX_LEVEL) {
progress.currentLevel = completedLevel + 1;
}
@@ -51,6 +54,11 @@ async function handleLessonComplete(completedLevel: number): Promise<void> {
showScreen("forest");
}
async function handleLessonCancel(): Promise<void> {
await initForestScreen(db, startLessonFromForest);
showScreen("forest");
}
function startLessonFromForest(level: number): void {
// Clean up previous lesson if any
if (lessonCleanup) {
@@ -69,6 +77,7 @@ function startLessonFromForest(level: number): void {
level,
layout,
handleLessonComplete,
handleLessonCancel,
);
});
}
+17 -2
View File
@@ -48,6 +48,8 @@ export function renderLevelMap(
});
}
const MAX_LEVEL = 6;
export async function initForestScreen(
db: IDBDatabase,
onStartLesson: (level: number) => void,
@@ -61,6 +63,19 @@ export async function initForestScreen(
renderLevelMap(mapContainer, progress, onStartLesson);
// Continue button starts the current level
continueBtn.onclick = () => onStartLesson(progress.currentLevel);
const allComplete = levels.every((l) =>
progress.completedLevels.includes(l.level),
);
if (allComplete) {
continueBtn.textContent = "Alle Stufen geschafft!";
continueBtn.disabled = true;
continueBtn.classList.add("forest__continue-btn--done");
} else {
continueBtn.textContent = "Weiter ueben";
continueBtn.disabled = false;
continueBtn.classList.remove("forest__continue-btn--done");
continueBtn.onclick = () =>
onStartLesson(Math.min(progress.currentLevel, MAX_LEVEL));
}
}
+32
View File
@@ -259,6 +259,15 @@ h3 {
transform: scale(1.05);
}
.forest__continue-btn--done {
background: var(--accent-gold);
cursor: default;
}
.forest__continue-btn--done:hover {
transform: none;
}
/* Lesson screen */
.lesson {
display: flex;
@@ -269,6 +278,29 @@ h3 {
padding: 2rem;
min-height: 100vh;
background: var(--bg-cream);
position: relative;
}
.lesson__back-btn {
position: absolute;
top: 1rem;
left: 1rem;
font-family: "Quicksand", sans-serif;
font-size: 1rem;
font-weight: 600;
color: var(--text-warm);
background: var(--bg-forest);
border: 2px solid var(--accent-green);
border-radius: 12px;
padding: 0.5rem 1rem;
cursor: pointer;
transition: background 0.2s ease, transform 0.1s ease;
}
.lesson__back-btn:hover {
background: var(--accent-green);
color: white;
transform: scale(1.05);
}
.lesson__letter-area {
+9
View File
@@ -79,9 +79,11 @@ export function initLessonScreen(
level: number,
layout: KeyboardLayout,
onComplete: (level: number) => void,
onCancel?: () => void,
): () => void {
const letterArea = document.getElementById("letter-area")!;
const keyboardContainer = document.getElementById("lesson-keyboard")!;
const backBtn = document.getElementById("lesson-back-btn") as HTMLButtonElement;
const state = createExerciseState(level);
// Render keyboard
@@ -131,6 +133,13 @@ export function initLessonScreen(
document.addEventListener("keydown", onKeyDown);
// Back button to cancel lesson
backBtn.onclick = () => {
document.removeEventListener("keydown", onKeyDown);
letterArea.innerHTML = "";
if (onCancel) onCancel();
};
// Return cleanup function
return () => {
document.removeEventListener("keydown", onKeyDown);