From 53adf79f292480019d499ae1187346939104b668 Mon Sep 17 00:00:00 2001 From: sascha Date: Sat, 27 Dec 2025 10:30:59 +0000 Subject: [PATCH] Dateien nach "app/static" hochladen --- app/static/script.js | 158 +++++++++++++++++++++++++++++++++ app/static/style.css | 207 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 365 insertions(+) create mode 100644 app/static/script.js create mode 100644 app/static/style.css diff --git a/app/static/script.js b/app/static/script.js new file mode 100644 index 0000000..3208c19 --- /dev/null +++ b/app/static/script.js @@ -0,0 +1,158 @@ +let currentMode = 'random'; +let selectedPages = []; +let quizQueue = []; +let currentCard = null; +let attempts = 0; +let stats = { correct: 0, total: 0 }; + +document.addEventListener('DOMContentLoaded', () => { + fetchPages(); + document.getElementById('answer-input').addEventListener('keypress', function (e) { + if (e.key === 'Enter') { + if (document.getElementById('next-btn').style.display !== 'none') { + nextQuestion(); + } else { + checkAnswer(); + } + } + }); +}); + +function setMode(mode) { + currentMode = mode; + document.querySelectorAll('.mode-select button').forEach(b => b.classList.remove('active')); + document.getElementById(`btn-${mode}`).classList.add('active'); +} + +function fetchPages() { + fetch('/api/pages') + .then(res => res.json()) + .then(pages => { + const list = document.getElementById('page-list'); + list.innerHTML = ''; + pages.forEach(p => { + const div = document.createElement('div'); + div.className = 'page-item'; + div.innerHTML = ` + + + `; + list.appendChild(div); + }); + }); +} + +function updatePageSelection() { + const checkboxes = document.querySelectorAll('#page-list input:checked'); + selectedPages = Array.from(checkboxes).map(cb => parseInt(cb.value)); + const disp = document.getElementById('selected-pages-display'); + if (selectedPages.length === 0) disp.innerText = "Alle Seiten"; + else disp.innerText = `${selectedPages.length} Seite(n) ausgewählt`; +} + +function openPageOverlay() { document.getElementById('overlay').style.display = 'flex'; } +function closeOverlay() { document.getElementById('overlay').style.display = 'none'; } + +function startQuiz() { + fetch('/api/start', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ pages: selectedPages, mode: currentMode }) + }) + .then(res => res.json()) + .then(data => { + quizQueue = data; + stats = { correct: 0, total: 0 }; + updateProgress(); + document.getElementById('setup-screen').style.display = 'none'; + document.getElementById('quiz-screen').style.display = 'block'; + nextQuestion(); + }); +} + +function nextQuestion() { + if (quizQueue.length === 0) { + alert("Runde beendet! Alle Vokabeln gelernt."); + stopQuiz(); + return; + } + + currentCard = quizQueue.pop(); + attempts = 0; + + document.getElementById('question-label').innerText = currentCard.direction === 'de-en' ? "Deutsch -> Englisch" : "Englisch -> Deutsch"; + document.getElementById('question-text').innerText = currentCard.question; + document.getElementById('answer-input').value = ''; + document.getElementById('answer-input').focus(); + document.getElementById('feedback-msg').innerText = ''; + + document.getElementById('check-btn').style.display = 'inline-block'; + document.getElementById('next-btn').style.display = 'none'; +} + +function checkAnswer() { + const input = document.getElementById('answer-input').value; + + fetch('/api/check', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ input: input, correct: currentCard.answer }) + }) + .then(res => res.json()) + .then(res => { + const feedback = document.getElementById('feedback-msg'); + feedback.className = ''; + + if (res.status === 'correct') { + feedback.innerText = res.msg; + feedback.classList.add('msg-correct'); + stats.correct++; + stats.total++; + updateProgress(); + setTimeout(nextQuestion, 1000); + } else if (res.status === 'typo') { + feedback.innerText = res.msg; + feedback.classList.add('msg-typo'); + attempts++; + checkAttempts(); + } else { + feedback.innerText = res.msg; + feedback.classList.add('msg-wrong'); + attempts++; + checkAttempts(); + } + }); +} + +function checkAttempts() { + if (attempts >= 3) { + const feedback = document.getElementById('feedback-msg'); + feedback.innerText = `Leider nicht geschafft. Lösung: ${currentCard.answer}`; + document.getElementById('check-btn').style.display = 'none'; + document.getElementById('next-btn').style.display = 'inline-block'; + stats.total++; + updateProgress(); + } +} + +function updateProgress() { + let percent = 0; + if (stats.total > 0) { + percent = Math.round((stats.correct / stats.total) * 100); + } + const text = document.getElementById('progress-text'); + const bar = document.getElementById('progress-bar'); + + text.innerText = `${percent}% Richtig (${stats.correct}/${stats.total})`; + bar.style.width = `${percent}%`; + + if (percent < 50) bar.style.backgroundColor = '#dc3545'; + else if (percent < 65) bar.style.backgroundColor = '#f08080'; + else if (percent < 85) bar.style.backgroundColor = '#ffc107'; + else bar.style.backgroundColor = '#28a745'; +} + +function stopQuiz() { + document.getElementById('quiz-screen').style.display = 'none'; + document.getElementById('setup-screen').style.display = 'block'; +} diff --git a/app/static/style.css b/app/static/style.css new file mode 100644 index 0000000..1b7008d --- /dev/null +++ b/app/static/style.css @@ -0,0 +1,207 @@ +:root { + --primary: #007bff; + --success: #28a745; + --danger: #dc3545; + --warning: #ffc107; + --secondary: #6c757d; + --bg: #f4f4f9; + --card-bg: #ffffff; + --text: #333; +} +body { + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif; + background-color: var(--bg); + color: var(--text); + margin: 0; + display: flex; + flex-direction: column; + min-height: 100vh; +} +.container { + flex: 1; + display: flex; + flex-direction: column; + align-items: center; + padding: 20px; + max-width: 600px; + margin: 0 auto; + width: 100%; + box-sizing: border-box; +} +h1 { + font-size: 1.8rem; + margin-bottom: 20px; + text-align: center; + color: #444; +} +.card { + background: var(--card-bg); + padding: 25px; + border-radius: 12px; + box-shadow: 0 4px 12px rgba(0,0,0,0.08); + width: 100%; + text-align: center; + box-sizing: border-box; + margin-bottom: 20px; +} +.label { + font-size: 0.9rem; + color: #666; + text-transform: uppercase; + letter-spacing: 1px; + margin-bottom: 10px; +} +.question { + font-size: 1.6rem; + font-weight: 700; + margin: 15px 0 25px 0; + word-wrap: break-word; +} +input[type="text"] { + width: 100%; + padding: 12px 15px; + font-size: 1.1rem; + border: 2px solid #ddd; + border-radius: 8px; + box-sizing: border-box; + outline: none; + transition: border-color 0.3s; + -webkit-appearance: none; +} +input[type="text"]:focus { + border-color: var(--primary); +} +button { + width: 100%; + padding: 14px; + border: none; + border-radius: 8px; + cursor: pointer; + font-size: 1rem; + font-weight: 600; + margin-bottom: 10px; + transition: transform 0.1s, opacity 0.2s; + -webkit-tap-highlight-color: transparent; +} +button:active { + transform: scale(0.98); +} +.mode-select { + display: grid; + grid-template-columns: 1fr 1fr 1fr; + gap: 8px; + margin-bottom: 20px; + width: 100%; +} +.mode-select button { + font-size: 0.9rem; + padding: 10px 5px; + background: #e0e0e0; + color: #555; + margin-bottom: 0; +} +.mode-select button.active { + background: var(--primary); + color: white; +} +.action-btn.primary { background-color: var(--primary); color: white; } +.action-btn.secondary { background-color: var(--secondary); color: white; } +.action-btn.danger { background-color: var(--danger); color: white; } +.action-btn { margin-top: 5px; } +#feedback-msg { + margin-top: 15px; + min-height: 1.2em; + font-weight: 500; + line-height: 1.4; +} +.msg-correct { color: var(--success); } +.msg-wrong { color: var(--danger); } +.msg-typo { color: #d39e00; } +.overlay { + display: none; + position: fixed; + top: 0; left: 0; + width: 100%; height: 100%; + background: rgba(0,0,0,0.6); + z-index: 1000; + justify-content: center; + align-items: center; + padding: 20px; + box-sizing: border-box; +} +.overlay-content { + background: white; + padding: 20px; + border-radius: 12px; + width: 100%; + max-width: 400px; + max-height: 80vh; + display: flex; + flex-direction: column; +} +.page-grid { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(70px, 1fr)); + gap: 10px; + margin: 20px 0; + overflow-y: auto; + flex: 1; +} +.page-item { position: relative; } +.page-item input[type="checkbox"] { + position: absolute; + opacity: 0; + width: 100%; + height: 100%; + cursor: pointer; +} +.page-item label { + display: block; + padding: 10px; + background: #f0f0f0; + border-radius: 6px; + text-align: center; + font-weight: bold; + color: #555; + border: 2px solid transparent; + transition: all 0.2s; +} +.page-item input:checked + label { + background: #e3f2fd; + border-color: var(--primary); + color: var(--primary); +} +.progress-container { + background: #fff; + border-top: 1px solid #eee; + padding: 15px 20px; + width: 100%; + box-sizing: border-box; + position: sticky; + bottom: 0; +} +.progress-text { + text-align: center; + margin-bottom: 8px; + font-size: 0.9rem; + font-weight: 600; + color: #555; +} +.progress-bar-bg { + background: #e9ecef; + height: 12px; + border-radius: 6px; + overflow: hidden; +} +.progress-bar-fill { + height: 100%; + width: 0%; + transition: width 0.4s ease, background-color 0.4s ease; +} +@media (max-width: 480px) { + h1 { font-size: 1.5rem; } + .card { padding: 20px; } + .question { font-size: 1.4rem; } + .mode-select { display: flex; flex-direction: column; } + .mode-select button { width: 100%; padding: 12px; } +}