Feature: 100-point scoring, question memory & spaced repetition, random wizard name generator, cache-busting v2.2, gold footer pills
This commit is contained in:
@@ -957,6 +957,32 @@ body {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.btn-dice {
|
||||
background: rgba(201, 168, 106, 0.18);
|
||||
border: 1px solid var(--gold);
|
||||
color: var(--gold-bright);
|
||||
padding: 0 14px;
|
||||
border-radius: 8px;
|
||||
cursor: pointer;
|
||||
font-size: 0.95rem;
|
||||
font-family: inherit;
|
||||
font-weight: bold;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
justify-content: center;
|
||||
transition: all 0.2s ease;
|
||||
min-height: 46px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.btn-dice:hover {
|
||||
background: var(--gold);
|
||||
color: #0b0b16;
|
||||
box-shadow: 0 0 12px rgba(201, 168, 106, 0.5);
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
/* Leaderboard tables & filters */
|
||||
.diff-filter-tabs {
|
||||
display: flex;
|
||||
@@ -1245,27 +1271,40 @@ body {
|
||||
}
|
||||
|
||||
.footer-links {
|
||||
margin-top: 8px;
|
||||
margin-top: 12px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
gap: 12px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.footer-link {
|
||||
color: var(--text-muted);
|
||||
color: var(--gold-soft);
|
||||
text-decoration: none;
|
||||
font-size: 0.8rem;
|
||||
transition: color 0.2s ease;
|
||||
font-size: 0.82rem;
|
||||
font-weight: 600;
|
||||
padding: 4px 12px;
|
||||
border-radius: 16px;
|
||||
background: rgba(201, 168, 106, 0.12);
|
||||
border: 1px solid rgba(201, 168, 106, 0.35);
|
||||
transition: all 0.2s ease;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 5px;
|
||||
}
|
||||
|
||||
.footer-link:hover {
|
||||
color: var(--gold-bright);
|
||||
text-decoration: underline;
|
||||
color: #0b0b16;
|
||||
background: var(--gold);
|
||||
border-color: var(--gold-bright);
|
||||
box-shadow: 0 0 12px rgba(201, 168, 106, 0.5);
|
||||
text-decoration: none;
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
.footer-sep {
|
||||
color: rgba(255, 255, 255, 0.2);
|
||||
display: none;
|
||||
}
|
||||
|
||||
.legal-card {
|
||||
|
||||
+79
-3
@@ -159,6 +159,58 @@ function applyQuizTranslations(lang) {
|
||||
}
|
||||
}
|
||||
|
||||
let sessionQuestionIds = [];
|
||||
|
||||
function getRecentQuestionIds() {
|
||||
try {
|
||||
const stored = localStorage.getItem("quiz_recent_qids");
|
||||
return stored ? JSON.parse(stored) : [];
|
||||
} catch(e) {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
function getWrongQuestionIds() {
|
||||
try {
|
||||
const stored = localStorage.getItem("quiz_wrong_qids");
|
||||
return stored ? JSON.parse(stored) : [];
|
||||
} catch(e) {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
function recordQuestionWrong(qid) {
|
||||
if (!qid) return;
|
||||
try {
|
||||
const wrong = getWrongQuestionIds();
|
||||
if (!wrong.includes(qid)) {
|
||||
wrong.push(qid);
|
||||
if (wrong.length > 30) wrong.shift();
|
||||
localStorage.setItem("quiz_wrong_qids", JSON.stringify(wrong));
|
||||
}
|
||||
} catch(e) {}
|
||||
}
|
||||
|
||||
function recordQuestionMastered(qid) {
|
||||
if (!qid) return;
|
||||
try {
|
||||
let wrong = getWrongQuestionIds();
|
||||
if (wrong.includes(qid)) {
|
||||
wrong = wrong.filter(id => id !== qid);
|
||||
localStorage.setItem("quiz_wrong_qids", JSON.stringify(wrong));
|
||||
}
|
||||
} catch(e) {}
|
||||
}
|
||||
|
||||
function saveRecentQuestions(ids) {
|
||||
if (!ids || ids.length === 0) return;
|
||||
try {
|
||||
let recent = getRecentQuestionIds();
|
||||
recent = Array.from(new Set([...ids, ...recent])).slice(0, 20);
|
||||
localStorage.setItem("quiz_recent_qids", JSON.stringify(recent));
|
||||
} catch(e) {}
|
||||
}
|
||||
|
||||
async function startGame() {
|
||||
const envelope = document.getElementById("envelope");
|
||||
const startBtn = document.getElementById("startBtn");
|
||||
@@ -167,6 +219,7 @@ async function startGame() {
|
||||
startBtn.disabled = true;
|
||||
startBtn.innerText = t.startBtnCasting;
|
||||
envelope.classList.add("envelope-opened");
|
||||
sessionQuestionIds = [];
|
||||
|
||||
// Start background music if enabled or first click
|
||||
const bgm = document.getElementById("bgm");
|
||||
@@ -183,12 +236,17 @@ async function startGame() {
|
||||
}
|
||||
|
||||
try {
|
||||
const recentIds = getRecentQuestionIds();
|
||||
const wrongIds = getWrongQuestionIds();
|
||||
|
||||
const res = await fetch("/api/game/start", {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({
|
||||
lang: currentLang,
|
||||
difficulty: selectedDifficulty
|
||||
difficulty: selectedDifficulty,
|
||||
recent_ids: recentIds,
|
||||
wrong_ids: wrongIds
|
||||
})
|
||||
});
|
||||
|
||||
@@ -239,6 +297,9 @@ function updateTimer() {
|
||||
|
||||
function renderQuestion(qData) {
|
||||
lastQuestionData = qData;
|
||||
if (qData.id && !sessionQuestionIds.includes(qData.id)) {
|
||||
sessionQuestionIds.push(qData.id);
|
||||
}
|
||||
const t = UI_TEXT[currentLang] || UI_TEXT.de;
|
||||
|
||||
document.getElementById("questionCounter").innerText = `${t.questionLabel} ${qData.question_number} ${t.ofLabel} ${totalQuestions}`;
|
||||
@@ -364,7 +425,17 @@ async function submitAnswer(answer, clickedBtn = null) {
|
||||
clickedBtn.classList.add("choice-correct");
|
||||
}
|
||||
frageBox.classList.add("sparkle-effect");
|
||||
feedbackBox.innerHTML = `<span class="feedback-correct">${t.correctFeedback}</span>`;
|
||||
|
||||
// Mark question as mastered in history
|
||||
if (result.question_id) {
|
||||
recordQuestionMastered(result.question_id);
|
||||
}
|
||||
|
||||
const pts = result.points_earned || 100;
|
||||
const ptsText = (currentLang === "en")
|
||||
? `✨ Correct! +${pts} House Points! ✨`
|
||||
: `✨ Richtig! +${pts} Hauspunkte für dein Haus! ✨`;
|
||||
feedbackBox.innerHTML = `<span class="feedback-correct">${ptsText}</span>`;
|
||||
|
||||
setTimeout(() => {
|
||||
frageBox.classList.remove("sparkle-effect");
|
||||
@@ -391,7 +462,11 @@ async function submitAnswer(answer, clickedBtn = null) {
|
||||
document.getElementById("attemptBadge").innerText = `${t.attemptLabel} ${Math.min(attemptsUsed + 1, maxAttempts)} ${t.ofLabel} ${maxAttempts}`;
|
||||
|
||||
if (result.attempts_left === 0) {
|
||||
// Exhausted all attempts
|
||||
// Exhausted all attempts -> record for spaced repetition learning
|
||||
if (result.question_id) {
|
||||
recordQuestionWrong(result.question_id);
|
||||
}
|
||||
|
||||
feedbackBox.innerHTML = `
|
||||
<div class="feedback-wrong">${t.exhaustedWrong}</div>
|
||||
<div class="feedback-revealed">${t.solutionLabel} <strong>${result.revealed_answer}</strong></div>
|
||||
@@ -448,6 +523,7 @@ async function requestHint() {
|
||||
|
||||
function finishGame() {
|
||||
if (timerInterval) clearInterval(timerInterval);
|
||||
saveRecentQuestions(sessionQuestionIds);
|
||||
document.getElementById("progressBar").style.width = "100%";
|
||||
window.location.href = `/finale?score=${currentScore}&total=${totalQuestions}&time=${elapsedSeconds}&lang=${currentLang}`;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user