Update japanese.html

This commit is contained in:
Didi
2025-10-27 11:28:29 +10:30
committed by GitHub
parent d5f40d88bc
commit c6f3a91522

View File

@@ -3,211 +3,39 @@
<head> <head>
<meta charset="UTF-8" /> <meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" /> <meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Hiragana Mastery Quiz Made by jordi, Damola - Scroll Enabled</title> <title>Hiragana/Katakana Duel Quiz - Jordi & Damola</title>
<style> <style>
html, body { html, body {margin:0; padding:0; height:100%; font-family:'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; background-color:#121212; color:#e0e0e0; overflow-y:auto; display:flex; flex-direction:column; align-items:center; scroll-behavior:smooth; user-select:none;}
margin: 0; padding: 0; h1 {margin:20px 0 12px 0; color:#ffcc00; font-weight:900; font-size:2.2rem; text-align:center;}
height: 100%; #mode-toggle {margin:10px; padding:12px 20px; font-weight:800; background:#333; color:#ffcc00; border:none; border-radius:12px; cursor:pointer; transition:0.25s;}
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; #mode-toggle:hover {background:#ffcc00; color:#121212;}
background-color: #121212; #row-select, #difficulty-overlay {display:flex; flex-wrap:wrap; gap:10px; justify-content:center; width:90vw; max-width:680px; margin-bottom:12px;}
background-image: radial-gradient(circle at 20% 20%, #1f1f1f 2px, transparent 3px), .row-btn, .difficulty-btn, #confirm-rows {background-color:#333; color:#eee; border:none; padding:14px 22px; font-size:1.1rem; font-weight:800; border-radius:10px; cursor:pointer; transition:all 0.25s ease-in-out; text-transform:uppercase;}
radial-gradient(circle at 80% 80%, #1f1f1f 2px, transparent 3px); .row-btn:hover, .difficulty-btn:hover, #confirm-rows:hover {background-color:#ffcc00; color:#121212;}
background-size: 40px 40px; .row-btn.selected {background-color:#ffcc00; color:#121212;}
color: #e0e0e0; #confirm-rows {margin-top:10px; background-color:#555;}
overflow-y: auto; #difficulty-modal {position:fixed; top:0; left:0; width:100vw; height:100vh; background:rgba(18,18,18,0.96); display:none; align-items:center; justify-content:center; flex-direction:column; z-index:9999;}
-webkit-font-smoothing: antialiased; #quiz-container {width:90vw; max-width:700px; padding:0 0 40px 0; margin-bottom:20px; display:flex; flex-direction:column; gap:20px;}
-moz-osx-font-smoothing: grayscale; .question-block {background:rgba(32,32,32,0.9); border-radius:18px; box-shadow:0 0 40px rgba(255,204,0,0.3); padding:30px 25px; display:flex; flex-direction:column; align-items:center;}
scroll-behavior: smooth; .question-char {font-size:5rem; font-weight:900; color:#ffd700; margin-bottom:24px;}
user-select: none; .options {width:100%; display:grid; gap:14px; grid-template-columns:repeat(auto-fit,minmax(120px,1fr));}
height: 100vh; button.option-btn {background-color:#222; border-radius:12px; padding:20px 0; font-size:2.3rem; color:#eee; font-weight:900; border:3px solid transparent; cursor:pointer; transition:all 0.25s;}
display: flex; button.option-btn.correct {background-color:#00c853; border-color:#00e676;}
flex-direction: column; button.option-btn.incorrect {background-color:#d50000; border-color:#ff1744;}
align-items: center; .feedback {margin-top:14px; font-size:1.4rem; font-weight:700; height:20px; color:#ffcc00;}
} .timer-bar-container {width:100%; height:10px; background:#333; border-radius:10px; overflow:hidden; margin-top:12px;}
h1 { .timer-bar {height:100%; background-color:#ff6f00; transition:width 0.1s linear; width:100%;}
margin: 20px 0 12px 0; #streak-container, #difficulty-indicator {position:fixed; top:8px; background:rgba(255,204,0,0.85); color:#121212; font-weight:800; padding:10px 18px; border-radius:12px; font-size:1.15rem; user-select:none; z-index:9999;}
color: #ffcc00; #streak-container {right:16px;}
font-weight: 900; #difficulty-indicator {left:16px;}
font-size: 2.2rem; #back-home-btn {margin:10px auto 40px auto; background-color:#444; color:#ffcc00; padding:12px 28px; font-size:1.2rem; border-radius:12px; cursor:pointer; font-weight:800; border:none; width:fit-content; transition:0.25s;}
text-align: center; #back-home-btn:hover {background-color:#ffcc00; color:#121212;}
user-select: none;
flex-shrink: 0;
}
#row-select, #difficulty-overlay {
display: flex;
flex-wrap: wrap;
gap: 10px;
justify-content: center;
width: 90vw;
max-width: 680px;
margin-bottom: 12px;
flex-shrink: 0;
}
.row-btn, .difficulty-btn, #confirm-rows {
background-color: #333;
color: #eee;
border: none;
padding: 14px 22px;
font-size: 1.1rem;
font-weight: 800;
border-radius: 10px;
cursor: pointer;
transition: all 0.25s ease-in-out;
text-transform: uppercase;
letter-spacing: 1px;
box-shadow: 0 4px 12px rgba(0,0,0,0.3);
}
.row-btn:hover, .difficulty-btn:hover, #confirm-rows:hover {
background-color: #ffcc00;
color: #121212;
}
.row-btn.selected {
background-color: #ffcc00;
color: #121212;
}
#confirm-rows {
margin-top: 10px;
background-color: #555;
flex-shrink: 0;
}
#difficulty-modal {
position: fixed;
top: 0; left: 0;
width: 100vw;
height: 100vh;
background: rgba(18,18,18,0.96);
display: none;
align-items: center;
justify-content: center;
flex-direction: column;
z-index: 9999;
}
#quiz-container {
width: 90vw;
max-width: 700px;
padding: 0 0 40px 0;
margin-bottom: 20px;
display: flex;
flex-direction: column;
gap: 20px;
user-select: none;
}
.question-block {
background: rgba(32,32,32,0.9);
border-radius: 18px;
box-shadow: 0 0 40px rgba(255,204,0,0.3);
padding: 30px 25px;
display: flex;
flex-direction: column;
align-items: center;
animation: slideInUp 0.3s ease forwards;
}
@keyframes slideInUp {
0% {opacity: 0; transform: translateY(20px);}
100% {opacity: 1; transform: translateY(0);}
}
.question-char {
font-size: 5rem;
font-weight: 900;
color: #ffd700;
margin-bottom: 24px;
}
.options {
width: 100%;
display: grid;
gap: 14px;
grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
}
button.option-btn {
background-color: #222;
border-radius: 12px;
padding: 20px 0;
font-size: 2.3rem;
color: #eee;
font-weight: 900;
border: 3px solid transparent;
cursor: pointer;
transition: all 0.25s ease;
user-select: none;
}
button.option-btn.correct {
background-color: #00c853;
border-color: #00e676;
}
button.option-btn.incorrect {
background-color: #d50000;
border-color: #ff1744;
}
.feedback {
margin-top: 14px;
font-size: 1.4rem;
font-weight: 700;
height: 20px;
color: #ffcc00;
user-select: none;
}
.timer-bar-container {
width: 100%;
height: 10px;
background: #333;
border-radius: 10px;
overflow: hidden;
margin-top: 12px;
}
.timer-bar {
height: 100%;
background-color: #ff6f00;
transition: width 0.1s linear;
width: 100%;
}
#streak-container {
position: fixed;
top: 8px;
right: 16px;
background: rgba(255, 204, 0, 0.85);
color: #121212;
font-weight: 800;
padding: 10px 18px;
border-radius: 12px;
font-size: 1.15rem;
user-select: none;
z-index: 9999;
}
#difficulty-indicator {
position: fixed;
top: 8px;
left: 16px;
background: rgba(255, 204, 0, 0.85);
color: #121212;
font-weight: 800;
padding: 10px 18px;
border-radius: 12px;
font-size: 1.15rem;
user-select: none;
z-index: 9999;
}
#back-home-btn {
margin: 10px auto 40px auto;
background-color: #444;
color: #ffcc00;
padding: 12px 28px;
font-size: 1.2rem;
border-radius: 12px;
cursor: pointer;
font-weight: 800;
border: none;
width: fit-content;
user-select: none;
transition: background-color 0.25s ease;
}
#back-home-btn:hover {
background-color: #ffcc00;
color: #121212;
}
</style> </style>
</head> </head>
<body> <body>
<h1>Hiragana Mastery by Jordi and Damola</h1>
<h1 id="quiz-title">Hiragana Mastery</h1>
<button id="mode-toggle">Switch to Katakana</button>
<div id="row-select"> <div id="row-select">
<button class="row-btn" data-row="a">A</button> <button class="row-btn" data-row="a">A</button>
@@ -237,11 +65,9 @@
<div id="streak-container">Streak: 0 | Best: 0</div> <div id="streak-container">Streak: 0 | Best: 0</div>
<div id="difficulty-indicator">Difficulty: Easy</div> <div id="difficulty-indicator">Difficulty: Easy</div>
<button id="back-home-btn" style="display:none;">Back to Home</button> <button id="back-home-btn" style="display:none;">Back to Home</button>
<script> <script>
// Elements
const rowButtons = document.querySelectorAll(".row-btn"); const rowButtons = document.querySelectorAll(".row-btn");
const difficultyModal = document.getElementById("difficulty-modal"); const difficultyModal = document.getElementById("difficulty-modal");
const confirmRows = document.getElementById("confirm-rows"); const confirmRows = document.getElementById("confirm-rows");
@@ -250,8 +76,10 @@
const streakContainer = document.getElementById("streak-container"); const streakContainer = document.getElementById("streak-container");
const difficultyIndicator = document.getElementById("difficulty-indicator"); const difficultyIndicator = document.getElementById("difficulty-indicator");
const backHomeBtn = document.getElementById("back-home-btn"); const backHomeBtn = document.getElementById("back-home-btn");
const modeToggle = document.getElementById("mode-toggle");
const quizTitle = document.getElementById("quiz-title");
// Data // Character Maps
const hiraganaMap = { const hiraganaMap = {
a:[["あ","a"],["い","i"],["う","u"],["え","e"],["お","o"]], a:[["あ","a"],["い","i"],["う","u"],["え","e"],["お","o"]],
k:[["か","ka"],["き","ki"],["く","ku"],["け","ke"],["こ","ko"]], k:[["か","ka"],["き","ki"],["く","ku"],["け","ke"],["こ","ko"]],
@@ -262,39 +90,49 @@
m:[["ま","ma"],["み","mi"],["む","mu"],["め","me"],["も","mo"]], m:[["ま","ma"],["み","mi"],["む","mu"],["め","me"],["も","mo"]],
y:[["や","ya"],["ゆ","yu"],["よ","yo"]], y:[["や","ya"],["ゆ","yu"],["よ","yo"]],
r:[["ら","ra"],["り","ri"],["る","ru"],["れ","re"],["ろ","ro"]], r:[["ら","ra"],["り","ri"],["る","ru"],["れ","re"],["ろ","ro"]],
w: [["わ", "wa"], ["を", "wo"], ["ん", "n"]], w:[["わ","wa"],["を","wo"],["ん","n"]]
};
const katakanaMap = {
a:[["ア","a"],["イ","i"],["ウ","u"],["エ","e"],["オ","o"]],
k:[["カ","ka"],["キ","ki"],["ク","ku"],["ケ","ke"],["コ","ko"]],
s:[["サ","sa"],["シ","shi"],["ス","su"],["セ","se"],["ソ","so"]],
t:[["タ","ta"],["チ","chi"],["ツ","tsu"],["テ","te"],["ト","to"]],
n:[["ナ","na"],["ニ","ni"],["ヌ","nu"],["ネ","ne"],["","no"]],
h:[["ハ","ha"],["ヒ","hi"],["フ","fu"],["ヘ","he"],["ホ","ho"]],
m:[["マ","ma"],["ミ","mi"],["ム","mu"],["メ","me"],["モ","mo"]],
y:[["ヤ","ya"],["ユ","yu"],["ヨ","yo"]],
r:[["ラ","ra"],["リ","ri"],["ル","ru"],["レ","re"],["ロ","ro"]],
w:[["ワ","wa"],["ヲ","wo"],["ン","n"]]
}; };
// State
let mode = "hiragana"; // default
let selectedRows = new Set(); let selectedRows = new Set();
let currentDifficulty = "easy"; let currentDifficulty = "easy";
let streak = 0, bestStreak = 0;
let allPairs = [];
let currentQuestion = null;
let timerInterval = null; let timerInterval = null;
let timeLimit = 7; let timeLimit = 7;
let questionCount = 0; let questionCount = 0;
let answeredThisQuestion = false; let answeredThisQuestion = false;
// Separate scores
const stats = {
hiragana: {streak:0,best:0,allPairs:[]},
katakana: {streak:0,best:0,allPairs:[]}
};
let currentQuestion = null;
// Row selection // Row selection
rowButtons.forEach(btn=>{ rowButtons.forEach(btn=>{
btn.onclick = ()=>{ btn.onclick = ()=>{
const row=btn.dataset.row; const row=btn.dataset.row;
if (selectedRows.has(row)) { if(selectedRows.has(row)){selectedRows.delete(row);btn.classList.remove("selected");}
selectedRows.delete(row); else{selectedRows.add(row);btn.classList.add("selected");}
btn.classList.remove("selected");
} else {
selectedRows.add(row);
btn.classList.add("selected");
}
}; };
}); });
// Confirm rows, show difficulty modal // Confirm rows
confirmRows.onclick=()=>{ confirmRows.onclick=()=>{
if (selectedRows.size === 0) { if(selectedRows.size===0){alert("Select at least one row."); return;}
alert("Select at least one row.");
return;
}
difficultyModal.style.display="flex"; difficultyModal.style.display="flex";
confirmRows.style.display="none"; confirmRows.style.display="none";
rowButtons.forEach(btn=>btn.disabled=true); rowButtons.forEach(btn=>btn.disabled=true);
@@ -310,50 +148,49 @@
}; };
}); });
// Back to home button // Back to home
backHomeBtn.onclick = () => { backHomeBtn.onclick=()=>{location.reload();};
location.reload();
// Toggle Mode
modeToggle.onclick=()=>{
mode = (mode==="hiragana")?"katakana":"hiragana";
quizTitle.textContent = (mode==="hiragana")?"Hiragana Mastery":"Katakana Mastery";
modeToggle.textContent = (mode==="hiragana")?"Switch to Katakana":"Switch to Hiragana";
updateStreakDisplay();
startGame(true);
}; };
function startGame() { function startGame(switching=false){
allPairs = Array.from(selectedRows).flatMap(row => hiraganaMap[row] || []); stats[mode].allPairs = Array.from(selectedRows).flatMap(r=> (mode==="hiragana"?hiraganaMap[r]:katakanaMap[r]) || []);
streak = 0; if(!switching){stats[mode].streak=0; stats[mode].best=0;}
bestStreak = 0; questionCount=0;
streakContainer.textContent = `Streak: 0 | Best: 0`; quizContainer.innerHTML="";
backHomeBtn.style.display="inline-block"; backHomeBtn.style.display="inline-block";
nextQuestion(); nextQuestion();
} }
// Create and push a new question block into the container
function nextQuestion(){ function nextQuestion(){
answeredThisQuestion=false; answeredThisQuestion=false;
questionCount++; questionCount++;
currentQuestion = stats[mode].allPairs[Math.floor(Math.random()*stats[mode].allPairs.length)];
currentQuestion = allPairs[Math.floor(Math.random() * allPairs.length)];
let options=[currentQuestion[1]]; let options=[currentQuestion[1]];
while(options.length<4){ while(options.length<4){
const candidate = allPairs[Math.floor(Math.random() * allPairs.length)][1]; const candidate=stats[mode].allPairs[Math.floor(Math.random()*stats[mode].allPairs.length)][1];
if(!options.includes(candidate)) options.push(candidate); if(!options.includes(candidate)) options.push(candidate);
} }
shuffleArray(options); shuffleArray(options);
// Build question block DOM
const qBlock=document.createElement("div"); const qBlock=document.createElement("div");
qBlock.className="question-block"; qBlock.className="question-block";
qBlock.id="q-"+questionCount; qBlock.id="q-"+questionCount;
const qChar=document.createElement("div"); const qChar=document.createElement("div");
qChar.className="question-char"; qChar.className="question-char";
qChar.textContent=currentQuestion[0]; qChar.textContent=currentQuestion[0];
const optionsDiv=document.createElement("div"); const optionsDiv=document.createElement("div");
optionsDiv.className="options"; optionsDiv.className="options";
const feedback=document.createElement("div"); const feedback=document.createElement("div");
feedback.className="feedback"; feedback.className="feedback";
// Timer bar container
const timerBarContainer=document.createElement("div"); const timerBarContainer=document.createElement("div");
timerBarContainer.className="timer-bar-container"; timerBarContainer.className="timer-bar-container";
const timerBar=document.createElement("div"); const timerBar=document.createElement("div");
@@ -373,10 +210,8 @@
qBlock.appendChild(optionsDiv); qBlock.appendChild(optionsDiv);
qBlock.appendChild(timerBarContainer); qBlock.appendChild(timerBarContainer);
qBlock.appendChild(feedback); qBlock.appendChild(feedback);
quizContainer.appendChild(qBlock); quizContainer.appendChild(qBlock);
scrollToBottom(); scrollToBottom();
startTimer(timerBar,qBlock,feedback); startTimer(timerBar,qBlock,feedback);
} }
@@ -384,96 +219,60 @@
if(answeredThisQuestion) return; if(answeredThisQuestion) return;
answeredThisQuestion=true; answeredThisQuestion=true;
clearInterval(timerInterval); clearInterval(timerInterval);
// Disable all option buttons in this block
const buttons=questionBlock.querySelectorAll(".option-btn"); const buttons=questionBlock.querySelectorAll(".option-btn");
buttons.forEach(b=>b.disabled=true); buttons.forEach(b=>b.disabled=true);
if(answer===currentQuestion[1]){ if(answer===currentQuestion[1]){
streak++; stats[mode].streak++;
bestStreak = Math.max(bestStreak, streak); stats[mode].best=Math.max(stats[mode].best,stats[mode].streak);
button.classList.add("correct"); button.classList.add("correct");
feedback.textContent="Correct!"; feedback.textContent="Correct!";
feedback.style.color="#00c853"; feedback.style.color="#00c853";
} else { } else {
streak = 0; stats[mode].streak=0;
button.classList.add("incorrect"); button.classList.add("incorrect");
feedback.textContent=`Wrong! Correct: ${currentQuestion[1]}`; feedback.textContent=`Wrong! Correct: ${currentQuestion[1]}`;
feedback.style.color="#d50000"; feedback.style.color="#d50000";
// Highlight correct answer buttons.forEach(b=>{if(b.textContent===currentQuestion[1])b.classList.add("correct");});
buttons.forEach(b => {
if (b.textContent === currentQuestion[1]) b.classList.add("correct");
});
} }
streakContainer.textContent = `Streak: ${streak} | Best: ${bestStreak}`; updateStreakDisplay();
// Small delay before next question
setTimeout(()=>nextQuestion(),1000); setTimeout(()=>nextQuestion(),1000);
} }
function startTimer(timerBar,questionBlock,feedback){ function startTimer(timerBar,questionBlock,feedback){
const difficultyTime = { const difficultyTime={easy:10,medium:7,hard:5,sensei:3};
easy: 10,
medium: 7,
hard: 5,
sensei: 3
};
timeLimit=difficultyTime[currentDifficulty]||7; timeLimit=difficultyTime[currentDifficulty]||7;
let timeLeft=timeLimit; let timeLeft=timeLimit;
timerBar.style.width="100%"; timerBar.style.width="100%";
timerInterval=setInterval(()=>{ timerInterval=setInterval(()=>{
timeLeft-=0.1; timeLeft-=0.1;
if(timeLeft<0) timeLeft=0; if(timeLeft<0) timeLeft=0;
timerBar.style.width=`${(timeLeft/timeLimit)*100}%`; timerBar.style.width=`${(timeLeft/timeLimit)*100}%`;
if(timeLeft<=0){ if(timeLeft<=0){
clearInterval(timerInterval); clearInterval(timerInterval);
if(!answeredThisQuestion){ if(!answeredThisQuestion){
answeredThisQuestion=true; answeredThisQuestion=true;
// Disable buttons on timeout
const buttons=questionBlock.querySelectorAll(".option-btn"); const buttons=questionBlock.querySelectorAll(".option-btn");
buttons.forEach(b=>b.disabled=true); buttons.forEach(b=>b.disabled=true);
// Show correct answer buttons.forEach(b=>{if(b.textContent===currentQuestion[1])b.classList.add("correct");});
buttons.forEach(b => {
if (b.textContent === currentQuestion[1]) b.classList.add("correct");
});
feedback.textContent=`Time's up! Correct: ${currentQuestion[1]}`; feedback.textContent=`Time's up! Correct: ${currentQuestion[1]}`;
feedback.style.color="#d50000"; feedback.style.color="#d50000";
streak = 0; stats[mode].streak=0;
streakContainer.textContent = `Streak: ${streak} | Best: ${bestStreak}`; updateStreakDisplay();
setTimeout(()=>nextQuestion(),1500); setTimeout(()=>nextQuestion(),1500);
} }
} }
},100); },100);
} }
// Utility: Shuffle array inplace function updateStreakDisplay(){
// jordi, damolas work u stealers this is ours dont rob us streakContainer.textContent=`Streak: ${stats[mode].streak} | Best: ${stats[mode].best}`;
// jordi, damolas work u stealers this is ours dont rob us
function shuffleArray(arr) {
for (let i = arr.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[arr[i], arr[j]] = [arr[j], arr[i]];
}
} }
// Scroll container to bottom to reveal new question function shuffleArray(arr){for(let i=arr.length-1;i>0;i--){const j=Math.floor(Math.random()*(i+1));[arr[i],arr[j]]=[arr[j],arr[i]];}}
// jordi, damolas work u stealers this is ours dont rob us
function scrollToBottom() {
// Smooth scroll the window or container to bottom
window.scrollTo({
top: document.body.scrollHeight,
behavior: "smooth"
});
}
// Capitalize helper function scrollToBottom(){window.scrollTo({top:document.body.scrollHeight,behavior:"smooth"});}
// jordi, damolas work u stealers this is ours dont rob us function capitalize(s){return s.charAt(0).toUpperCase()+s.slice(1);}
function capitalize(s) {
return s.charAt(0).toUpperCase() + s.slice(1);
}
</script> </script>
</body> </body>