import type { KeyboardLayout } from "../types"; import { getLevelByNumber } from "./levels"; // QWERTZ rows -- each row is an array of key labels // For DE and CH layouts (identical for letters, differ on special chars above level 14) const KEYBOARD_ROWS_DE = [ ["1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "ß"], ["q", "w", "e", "r", "t", "z", "u", "i", "o", "p", "ü"], ["a", "s", "d", "f", "g", "h", "j", "k", "l", "ö", "ä"], ["y", "x", "c", "v", "b", "n", "m"], [" "], // Spacebar ]; const KEYBOARD_ROWS_CH = [ ["1", "2", "3", "4", "5", "6", "7", "8", "9", "0"], ["q", "w", "e", "r", "t", "z", "u", "i", "o", "p", "ü"], ["a", "s", "d", "f", "g", "h", "j", "k", "l", "ö", "ä"], ["y", "x", "c", "v", "b", "n", "m"], [" "], ]; // Finger color mapping (shared with levels.ts fingerMap) const fingerColorMap: Record = { q: "--finger-l-pinky", a: "--finger-l-pinky", y: "--finger-l-pinky", "1": "--finger-l-pinky", w: "--finger-l-ring", s: "--finger-l-ring", x: "--finger-l-ring", "2": "--finger-l-ring", e: "--finger-l-mid", d: "--finger-l-mid", c: "--finger-l-mid", "3": "--finger-l-mid", r: "--finger-l-index", f: "--finger-l-index", v: "--finger-l-index", "4": "--finger-l-index", t: "--finger-l-index", g: "--finger-l-index", b: "--finger-l-index", "5": "--finger-l-index", z: "--finger-r-index", h: "--finger-r-index", n: "--finger-r-index", "6": "--finger-r-index", u: "--finger-r-index", j: "--finger-r-index", m: "--finger-r-index", "7": "--finger-r-index", i: "--finger-r-mid", k: "--finger-r-mid", "8": "--finger-r-mid", o: "--finger-r-ring", l: "--finger-r-ring", "9": "--finger-r-ring", p: "--finger-r-pinky", ö: "--finger-r-pinky", ä: "--finger-r-pinky", ü: "--finger-r-pinky", "0": "--finger-r-pinky", ß: "--finger-r-pinky", " ": "--finger-thumb", }; const keyElements: Map = new Map(); export function renderKeyboard( container: HTMLElement, layout: KeyboardLayout, currentLevel: number, ): void { keyElements.clear(); container.innerHTML = ""; container.className = "keyboard"; const rows = layout === "ch" ? KEYBOARD_ROWS_CH : KEYBOARD_ROWS_DE; const level = getLevelByNumber(currentLevel); const activeKeys = level ? level.allKeys : []; for (let rowIndex = 0; rowIndex < rows.length; rowIndex++) { const row = rows[rowIndex]!; const rowEl = document.createElement("div"); rowEl.className = `keyboard__row keyboard__row--${rowIndex}`; for (const key of row) { const keyEl = document.createElement("div"); const isActive = activeKeys.includes(key); const colorVar = fingerColorMap[key]; keyEl.className = "keyboard__key"; if (key === " ") keyEl.classList.add("keyboard__key--space"); if (isActive && colorVar) { keyEl.style.backgroundColor = `var(${colorVar})`; keyEl.classList.add("keyboard__key--active"); } else { keyEl.classList.add("keyboard__key--inactive"); } keyEl.textContent = key === " " ? "" : key.toUpperCase(); keyEl.dataset.key = key; keyElements.set(key, keyEl); rowEl.appendChild(keyEl); } container.appendChild(rowEl); } } export function highlightKey(key: string): void { // Remove previous highlights for (const el of keyElements.values()) { el.classList.remove("keyboard__key--highlight"); } const el = keyElements.get(key.toLowerCase()); if (el) el.classList.add("keyboard__key--highlight"); } export function pressKey(key: string): void { const el = keyElements.get(key.toLowerCase()); if (el) { el.classList.add("keyboard__key--pressed"); setTimeout(() => el.classList.remove("keyboard__key--pressed"), 150); } } export function updateKeyboardForLevel(currentLevel: number): void { const level = getLevelByNumber(currentLevel); const activeKeys = level ? level.allKeys : []; for (const [key, el] of keyElements) { const colorVar = fingerColorMap[key]; if (activeKeys.includes(key) && colorVar) { el.style.backgroundColor = `var(${colorVar})`; el.classList.remove("keyboard__key--inactive"); el.classList.add("keyboard__key--active"); } else { el.style.backgroundColor = ""; el.classList.remove("keyboard__key--active"); el.classList.add("keyboard__key--inactive"); } } }