Files
wortkraft/index.html
T

507 lines
25 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover" />
<meta name="theme-color" content="#18181b" />
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
<title>WortKraft — Beyond Duolingo German A2/B1</title>
<link rel="icon" type="image/svg+xml" href="icon.svg" />
<link rel="apple-touch-icon" href="icon.svg" />
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&display=swap" rel="stylesheet">
<link rel="stylesheet" href="styles.css?v=6" />
</head>
<body>
<!-- TOP HEADER -->
<header class="top-header">
<div class="header-inner">
<div class="brand" onclick="app.switchView('dashboard')">
<div class="brand-flag" aria-hidden="true"></div>
<div>
<div class="brand-title">
WortKraft
<span class="level-pill">A2 → B1</span>
</div>
<div class="brand-subtitle">Active German Vocabulary & Context Studio</div>
</div>
</div>
<nav class="nav-tabs" aria-label="Main Navigation">
<button class="nav-tab active" data-view="dashboard" onclick="app.switchView('dashboard')">
<span>📊</span> Übersicht
</button>
<button class="nav-tab" data-view="trainer" onclick="app.switchView('trainer')">
<span>⚡</span> Trainer
<span class="nav-badge" id="nav-due-badge">0</span>
</button>
<button class="nav-tab" data-view="builder" onclick="app.switchView('builder')">
<span>🧱</span> Wortbaukasten
</button>
<button class="nav-tab" data-view="prepositions" onclick="app.switchView('prepositions')">
<span>🎯</span> Präpositionen
</button>
<button class="nav-tab" data-view="listening" onclick="app.switchView('listening')">
<span>🎧</span> Hörtraining
</button>
<button class="nav-tab" data-view="reader" onclick="app.switchView('reader')">
<span>📖</span> Leseecke
</button>
<button class="nav-tab" data-view="practice" onclick="app.switchView('practice')">
<span>💬</span> Sprachpraxis
</button>
<button class="nav-tab" data-view="dictionary" onclick="app.switchView('dictionary')">
<span>🗂️</span> Wörterbuch
</button>
</nav>
<div class="header-actions">
<button id="hover-translate-toggle" class="hover-toggle-btn active" onclick="app.toggleHoverTranslate()" title="Wörter beim Drüberfahren (Hover) oder Antippen automatisch ins Englische übersetzen">
🔍 <span class="hover-label-text">Hover-Übersetzer: </span><span id="hover-translate-status">AN</span>
</button>
<div class="streak-chip" title="1400+ Days Foundation + Active Recall Streak">
🔥 <span id="streak-count">1401</span> <span class="streak-days-word">Tage</span>
</div>
<button class="icon-btn" onclick="app.openModal('add-word-modal')" title="Neues Wort hinzufügen (+)">➕</button>
<button class="icon-btn" onclick="app.openModal('settings-modal')" title="KI & Einstellungen">⚙️</button>
</div>
</div>
</header>
<!-- MAIN CONTENT AREA -->
<main class="main-container">
<!-- 1. DASHBOARD VIEW -->
<section id="view-dashboard" class="view-section active">
<div class="hero-banner">
<div class="hero-text">
<h1>Vom passiven Wiedererkennen zum aktiven Wortschatz.</h1>
<p>
After 1,400 days on Duolingo, you already have a strong intuition for basic German structure.
<strong>WortKraft</strong> bridges the A2→B1 plateau by training <em>active recall with articles</em>,
<em>compound word logic</em>, <em>verb + preposition cases</em>, and <em>native listening & production</em>.
</p>
<div class="gender-legend-bar">
<span class="gender-badge gender-der">der • Maskulin</span>
<span class="gender-badge gender-die">die • Feminin (-ung, -heit, -keit)</span>
<span class="gender-badge gender-das">das • Neutrum (-chen, -nis, -um)</span>
<span class="gender-badge gender-pl">die • Plural</span>
</div>
</div>
<div class="hero-cta-group">
<button class="btn btn-primary" onclick="app.switchView('trainer')">
⚡ Jetzt trainieren (<span id="hero-due-count">0</span> fällig)
</button>
<button class="btn btn-light" onclick="app.switchView('builder')">
🧱 Wortbaukasten
</button>
</div>
</div>
<div class="stats-grid">
<div class="stat-card">
<div class="stat-label">Fällig zur Wiederholung</div>
<div class="stat-value" id="stat-due">0</div>
<div class="stat-sub">Bereit für aktiven Abruf (SRS)</div>
</div>
<div class="stat-card">
<div class="stat-label">Aktiver Wortschatz</div>
<div class="stat-value" id="stat-learned">0 / 48</div>
<div class="stat-sub" id="stat-mastered-sub">0 gemeistert • 0 im Training</div>
</div>
<div class="stat-card">
<div class="stat-label">Artikel- & Übungsquote</div>
<div class="stat-value" id="stat-accuracy">—</div>
<div class="stat-sub">der / die / das & Präpositionen</div>
</div>
<div class="stat-card">
<div class="stat-label">Aktive Sätze produziert</div>
<div class="stat-value" id="stat-sentences">0</div>
<div class="stat-sub">Sprachpraxis & Hörtraining</div>
</div>
</div>
<div class="dashboard-columns">
<div class="panel-card">
<div class="panel-header">
<h2 class="panel-title">Deine 6 Trainings-Module (A2 → B1)</h2>
</div>
<div class="module-launcher-list">
<div class="launcher-item" onclick="app.startTrainerMode('cloze')">
<div class="launcher-left">
<div class="launcher-icon">⚡</div>
<div>
<div class="launcher-title">1. Aktiver Abruf im Kontext (SRS-Trainer)</div>
<div class="launcher-desc">Lückensätze, Englisch → Deutsch mit Artikel & Plural-Drill statt Multiple-Choice.</div>
</div>
</div>
<span>→</span>
</div>
<div class="launcher-item" onclick="app.switchView('builder')">
<div class="launcher-left">
<div class="launcher-icon">🧱</div>
<div>
<div class="launcher-title">2. Wortbaukasten (Komposita & Präfix-Labor)</div>
<div class="launcher-desc">Verstehe trennbare/untrennbare Verben (nehmen, stellen, kommen) & lange zusammengesetzte Nomen.</div>
</div>
</div>
<span>→</span>
</div>
<div class="launcher-item" onclick="app.switchView('prepositions')">
<div class="launcher-left">
<div class="launcher-icon">🎯</div>
<div>
<div class="launcher-title">3. Verben mit Präposition & Kasus (Rektion + Da-/Wo-)</div>
<div class="launcher-desc">Meistere warten auf (+Akk), teilnehmen an (+Dat), sich kümmern um (+Akk) & darauf/worauf.</div>
</div>
</div>
<span>→</span>
</div>
<div class="launcher-item" onclick="app.switchView('listening')">
<div class="launcher-left">
<div class="launcher-icon">🎧</div>
<div>
<div class="launcher-title">4. Hörtraining & Aussprache-Check (Diktat & Mikrofon)</div>
<div class="launcher-desc">Höre echte Alltagssätze ohne Text, tippe was du hörst, oder sprich den Satz selbst ins Mikrofon.</div>
</div>
</div>
<span>→</span>
</div>
<div class="launcher-item" onclick="app.switchView('reader')">
<div class="launcher-left">
<div class="launcher-icon">📖</div>
<div>
<div class="launcher-title">5. Interaktive Leseecke (A2/B1 Geschichten & Alltag)</div>
<div class="launcher-desc">Hover-Übersetzer + Klick auf jedes Wort für Artikel, Stammform, Audio & 1-Klick-SRS-Speichern.</div>
</div>
</div>
<span>→</span>
</div>
<div class="launcher-item" onclick="app.switchView('practice')">
<div class="launcher-left">
<div class="launcher-icon">💬</div>
<div>
<div class="launcher-title">6. Sprachpraxis mit Zielwörtern</div>
<div class="launcher-desc">Löse echte Alltagssituationen (Arzt, Bürgeramt, Feierabend) und nutze gezielt 5 Zielwörter.</div>
</div>
</div>
<span>→</span>
</div>
</div>
</div>
<div class="panel-card">
<div class="panel-header">
<h2 class="panel-title">Fokus-Wörter des Tages</h2>
<button class="btn btn-secondary" style="padding: 0.35rem 0.7rem; font-size: 0.8rem;" onclick="app.refreshDailySpotlight()">🔄 Neu mischen</button>
</div>
<div id="daily-spotlight-list" style="display: flex; flex-direction: column; gap: 0.75rem;"></div>
</div>
</div>
</section>
<!-- 2. WORTSCHATZ-TRAINER (ACTIVE RECALL & SRS) -->
<section id="view-trainer" class="view-section">
<div class="trainer-controls">
<div class="mode-pills" role="tablist">
<button class="mode-pill active" data-mode="cloze" onclick="app.setTrainerMode('cloze')">
🧩 Lückensatz im Kontext
</button>
<button class="mode-pill" data-mode="production" onclick="app.setTrainerMode('production')">
✍️ Aktiv Schreiben (EN → DE + Artikel)
</button>
<button class="mode-pill" data-mode="gender" onclick="app.setTrainerMode('gender')">
🎨 Artikel & Plural-Blitz
</button>
<button class="mode-pill" data-mode="flashcard" onclick="app.setTrainerMode('flashcard')">
🃏 Karteikarte & Wortbau
</button>
</div>
<div style="display: flex; gap: 0.6rem; align-items: center;">
<select id="trainer-category-select" class="german-input" style="padding: 0.45rem 0.8rem; font-size: 0.86rem;" onchange="app.filterTrainerDeck()">
<option value="due">🔥 Fällige & Neue Wörter</option>
<option value="all">Alle Wörter (48+)</option>
<option value="Everyday & Bureaucracy">Alltag & Behörden</option>
<option value="Housing & Errands">Wohnen & Einkaufen</option>
<option value="Health & Wellbeing">Gesundheit & Arzt</option>
<option value="Social & Work">Soziales & Feierabend</option>
<option value="Verbs & Expressions">Verben mit Präposition</option>
<option value="Travel & Culture">Reisen & Kultur</option>
<option value="Fluency Connectors">Konnektoren (obwohl, deshalb...)</option>
</select>
</div>
</div>
<div id="trainer-stage-container"></div>
</section>
<!-- 3. WORTBAUKASTEN (COMPOUND WORD & PREFIX LAB) -->
<section id="view-builder" class="view-section">
<div class="trainer-controls">
<div class="mode-pills">
<button class="mode-pill active" id="builder-tab-prefixes" onclick="app.setBuilderSubmode('prefixes')">
🔀 Verb-Stämme & Präfix-Labor (trennbar vs. untrennbar)
</button>
<button class="mode-pill" id="builder-tab-compounds" onclick="app.setBuilderSubmode('compounds')">
🧱 Komposita-Knacker (Zusammengesetzte Nomen)
</button>
<button class="mode-pill" id="builder-tab-quiz" onclick="app.setBuilderSubmode('quiz')">
⚡ Präfix- & Komposita-Quiz
</button>
</div>
</div>
<div id="builder-stage-container"></div>
</section>
<!-- 4. VERBEN MIT PRÄPOSITION (REKTION & DA-/WO- TRAINER) -->
<section id="view-prepositions" class="view-section">
<div class="trainer-controls">
<div class="mode-pills">
<button class="mode-pill active" id="prep-tab-drill" onclick="app.setPrepSubmode('drill')">
🎯 Präposition + Kasus-Trainer (auf den / am / um das)
</button>
<button class="mode-pill" id="prep-tab-dawo" onclick="app.setPrepSubmode('dawo')">
🔗 Da- & Wo-Baukasten (darauf, worauf, darum, daran)
</button>
<button class="mode-pill" id="prep-tab-reference" onclick="app.setPrepSubmode('reference')">
📋 Übersichtstabelle (Akkusativ vs. Dativ)
</button>
</div>
</div>
<div id="prepositions-stage-container"></div>
</section>
<!-- 5. HÖRTRAINING & AUSSPRACHE (LISTENING DICTATION & SHADOWING) -->
<section id="view-listening" class="view-section">
<div id="listening-stage-container"></div>
</section>
<!-- 6. INTERACTIVE READER (LESEECKE) -->
<section id="view-reader" class="view-section">
<div class="reader-layout">
<aside class="story-sidebar">
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 0.25rem;">
<h2 style="font-size: 1.05rem; font-weight: 800;">Textauswahl (A2/B1)</h2>
<button class="btn btn-secondary" style="padding: 0.35rem 0.65rem; font-size: 0.78rem;" onclick="app.openModal('import-text-modal')">
📄 Eigener Text
</button>
</div>
<div id="story-list-container" style="display: flex; flex-direction: column; gap: 0.65rem;"></div>
</aside>
<div class="reader-main">
<div id="reader-content-area"></div>
</div>
</div>
</section>
<!-- 7. CONVERSATION & WRITING PRACTICE (SPRACHPRAXIS) -->
<section id="view-practice" class="view-section">
<div class="scenario-layout">
<aside class="story-sidebar">
<h2 style="font-size: 1.05rem; font-weight: 800; margin-bottom: 0.25rem;">Szenarien & Rollenspiele</h2>
<p style="font-size: 0.82rem; color: var(--text-secondary); margin-bottom: 0.5rem;">
Wähle eine Alltagssituation und verwende die 5 Zielwörter aktiv in deinen Antworten.
</p>
<div id="scenario-list-container" style="display: flex; flex-direction: column; gap: 0.65rem;"></div>
</aside>
<div class="panel-card" id="practice-stage-area"></div>
</div>
</section>
<!-- 8. VOCABULARY BANK (WÖRTERBUCH) -->
<section id="view-dictionary" class="view-section">
<div class="panel-header" style="margin-bottom: 1.25rem; flex-wrap: wrap;">
<div>
<h2 style="font-size: 1.35rem; font-weight: 800;">Mein A2/B1 Wortschatz-Archiv</h2>
<p style="font-size: 0.88rem; color: var(--text-secondary);">
Farbcodiert nach Genus (der/die/das), inklusive Wortfamilien, Pluralformen und SRS-Status.
</p>
</div>
<button class="btn btn-primary" onclick="app.openModal('add-word-modal')">
➕ Eigenes Wort hinzufügen
</button>
</div>
<div class="vocab-filter-bar">
<input
type="text"
id="dict-search-input"
class="german-input"
placeholder="Suche nach Deutsch, Englisch, Beispielsatz..."
style="max-width: 340px; padding: 0.55rem 0.9rem; font-size: 0.9rem;"
oninput="app.renderDictionary()"
/>
<select id="dict-gender-filter" class="german-input" style="max-width: 190px; padding: 0.55rem 0.8rem; font-size: 0.9rem;" onchange="app.renderDictionary()">
<option value="all">Alle Wortarten / Artikel</option>
<option value="der">🔵 der (Maskulin)</option>
<option value="die">🔴 die (Feminin)</option>
<option value="das">🟢 das (Neutrum)</option>
<option value="verb">⚡ Verben & Ausdrücke</option>
</select>
<select id="dict-category-filter" class="german-input" style="max-width: 220px; padding: 0.55rem 0.8rem; font-size: 0.9rem;" onchange="app.renderDictionary()">
<option value="all">Alle Kategorien</option>
<option value="Everyday & Bureaucracy">Alltag & Behörden</option>
<option value="Housing & Errands">Wohnen & Einkaufen</option>
<option value="Health & Wellbeing">Gesundheit & Arzt</option>
<option value="Social & Work">Soziales & Feierabend</option>
<option value="Verbs & Expressions">Verben mit Präposition</option>
<option value="Travel & Culture">Reisen & Kultur</option>
<option value="Fluency Connectors">Konnektoren</option>
<option value="Saved from Reading">Aus Leseecke gespeichert</option>
</select>
</div>
<div id="dictionary-grid" class="vocab-grid"></div>
</section>
</main>
<!-- MODAL: ADD CUSTOM WORD -->
<div class="modal-backdrop" id="add-word-modal">
<div class="modal-card">
<div class="panel-header">
<h3 class="panel-title">➕ Neues Wort zum SRS-Trainer hinzufügen</h3>
<button class="icon-btn" onclick="app.closeModal('add-word-modal')">✕</button>
</div>
<form onsubmit="app.handleAddCustomWord(event)" style="display: flex; flex-direction: column; gap: 0.85rem;">
<div style="display: grid; grid-template-columns: 120px 1fr; gap: 0.65rem;">
<div>
<label class="detail-label" style="margin-bottom: 0.25rem;">Artikel</label>
<select id="custom-article" class="german-input" style="width: 100%; padding: 0.55rem; font-size: 0.9rem;">
<option value="">— (Kein Nomen)</option>
<option value="der">der (m)</option>
<option value="die">die (f)</option>
<option value="das">das (n)</option>
<option value="die (Pl.)">die (Pl.)</option>
</select>
</div>
<div>
<label class="detail-label" style="margin-bottom: 0.25rem;">Deutsches Wort *</label>
<input type="text" id="custom-word" required class="german-input" style="width: 100%; padding: 0.55rem; font-size: 0.9rem;" placeholder="z.B. Verantwortung / sich gewöhnen an" />
</div>
</div>
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 0.65rem;">
<div>
<label class="detail-label" style="margin-bottom: 0.25rem;">Englische Bedeutung *</label>
<input type="text" id="custom-english" required class="german-input" style="width: 100%; padding: 0.55rem; font-size: 0.9rem;" placeholder="e.g. responsibility" />
</div>
<div>
<label class="detail-label" style="margin-bottom: 0.25rem;">Plural / Verbformen</label>
<input type="text" id="custom-plural" class="german-input" style="width: 100%; padding: 0.55rem; font-size: 0.9rem;" placeholder="z.B. die Verantwortungen" />
</div>
</div>
<div>
<label class="detail-label" style="margin-bottom: 0.25rem;">Beispielsatz auf Deutsch *</label>
<input type="text" id="custom-example-de" required class="german-input" style="width: 100%; padding: 0.55rem; font-size: 0.9rem;" placeholder="z.B. Das ist eine große Verantwortung." />
</div>
<div>
<label class="detail-label" style="margin-bottom: 0.25rem;">Beispielsatz auf Englisch</label>
<input type="text" id="custom-example-en" class="german-input" style="width: 100%; padding: 0.55rem; font-size: 0.9rem;" placeholder="e.g. That is a big responsibility." />
</div>
<div>
<label class="detail-label" style="margin-bottom: 0.25rem;">Wortbau / Eselsbrücke (Optional)</label>
<input type="text" id="custom-tip" class="german-input" style="width: 100%; padding: 0.55rem; font-size: 0.9rem;" placeholder="z.B. Endung -ung ist immer feminin (die)" />
</div>
<div style="display: flex; justify-content: flex-end; gap: 0.6rem; margin-top: 0.5rem;">
<button type="button" class="btn btn-secondary" onclick="app.closeModal('add-word-modal')">Abbrechen</button>
<button type="submit" class="btn btn-primary">Im Deck speichern</button>
</div>
</form>
</div>
</div>
<!-- MODAL: IMPORT CUSTOM GERMAN TEXT -->
<div class="modal-backdrop" id="import-text-modal">
<div class="modal-card">
<div class="panel-header">
<h3 class="panel-title">📄 Eigenen deutschen Text importieren</h3>
<button class="icon-btn" onclick="app.closeModal('import-text-modal')">✕</button>
</div>
<p style="font-size: 0.86rem; color: var(--text-secondary); margin-bottom: 0.85rem;">
Füge einen deutschen Artikel, eine E-Mail oder eine Geschichte ein. Jedes Wort wird sofort klickbar und kann zu deinem SRS-Trainer hinzugefügt werden!
</p>
<form onsubmit="app.handleImportCustomStory(event)" style="display: flex; flex-direction: column; gap: 0.85rem;">
<div>
<label class="detail-label" style="margin-bottom: 0.25rem;">Titel des Textes *</label>
<input type="text" id="import-story-title" required class="german-input" style="width: 100%; padding: 0.55rem; font-size: 0.9rem;" placeholder="z.B. E-Mail von der Hausverwaltung" />
</div>
<div>
<label class="detail-label" style="margin-bottom: 0.25rem;">Deutscher Text (Absätze durch Leerzeile trennen) *</label>
<textarea id="import-story-body" required rows="6" class="german-input" style="width: 100%; padding: 0.65rem; font-size: 0.9rem;" placeholder="Sehr geehrte Hausbewohner, am kommenden Mittwoch findet zwischen 9 und 12 Uhr die jährliche Wartung der Heizung statt..."></textarea>
</div>
<div style="display: flex; justify-content: flex-end; gap: 0.6rem;">
<button type="button" class="btn btn-secondary" onclick="app.closeModal('import-text-modal')">Abbrechen</button>
<button type="submit" class="btn btn-primary">In der Leseecke öffnen</button>
</div>
</form>
</div>
</div>
<!-- MODAL: SETTINGS & OPTIONAL AI KEY -->
<div class="modal-backdrop" id="settings-modal">
<div class="modal-card">
<div class="panel-header">
<h3 class="panel-title">⚙️ Einstellungen & Live-KI-Konversation</h3>
<button class="icon-btn" onclick="app.closeModal('settings-modal')">✕</button>
</div>
<div style="display: flex; flex-direction: column; gap: 1rem; font-size: 0.9rem;">
<p style="color: var(--text-secondary);">
<strong>WortKraft</strong> funktioniert komplett ohne API-Schlüssel mit integriertem Grammatik- & Zielwort-Coaching.
Optional kannst du einen <strong>Gemini API Key</strong> oder <strong>OpenAI API Key</strong> hinterlegen (wird nur lokal in deinem Browser gespeichert), um detailliertes Live-KI-Coaching in der Sprachpraxis zu aktivieren.
</p>
<div>
<label class="detail-label" style="margin-bottom: 0.25rem;">KI-Anbieter (Optional)</label>
<select id="settings-ai-provider" class="german-input" style="width: 100%; padding: 0.55rem; font-size: 0.9rem;">
<option value="builtin">Integrierter Smart-Coach (Sofort einsatzbereit, kein Key nötig)</option>
<option value="gemini">Google Gemini API (gemini-2.5-flash)</option>
<option value="openai">OpenAI API (gpt-4o-mini)</option>
</select>
</div>
<div>
<label class="detail-label" style="margin-bottom: 0.25rem;">API-Schlüssel (lokal im Browser gespeichert)</label>
<input type="password" id="settings-api-key" class="german-input" style="width: 100%; padding: 0.55rem; font-size: 0.9rem;" placeholder="AIza... oder sk-..." />
</div>
<hr style="border: none; border-top: 1px solid var(--border-color);" />
<div style="display: flex; justify-content: space-between; align-items: center; gap: 0.75rem; flex-wrap: wrap;">
<button type="button" class="btn btn-secondary" onclick="app.exportProgress()">💾 Fortschritt exportieren</button>
<button type="button" class="btn btn-secondary" style="color: var(--danger);" onclick="app.resetProgress()">🗑️ Lernstand zurücksetzen</button>
</div>
<div style="display: flex; justify-content: flex-end; gap: 0.6rem; margin-top: 0.5rem;">
<button type="button" class="btn btn-primary" onclick="app.saveSettings()">Einstellungen speichern</button>
</div>
</div>
</div>
</div>
<!-- HOVER TRANSLATE TOOLTIP -->
<div id="hover-translate-tooltip" class="hover-translate-tooltip"></div>
<!-- TOAST NOTIFICATION -->
<div id="toast" class="toast-notification"></div>
<!-- SCRIPTS -->
<script src="data/vocabulary.js?v=6"></script>
<script src="data/stories.js?v=6"></script>
<script src="data/scenarios.js?v=6"></script>
<script src="data/hover_dict.js?v=6"></script>
<script src="data/labs.js?v=6"></script>
<script src="app.js?v=6"></script>
</body>
</html>