Spaces:
Running
Running
Update index.html
Browse files- index.html +96 -28
index.html
CHANGED
|
@@ -85,7 +85,7 @@
|
|
| 85 |
|
| 86 |
<!-- 主選單:新增單字 & 模式選擇 -->
|
| 87 |
<div id="main-menu" class="w-full max-w-2xl bg-white p-6 rounded-3xl shadow-2xl transition-all duration-500">
|
| 88 |
-
<h1 class="text-4xl font-extrabold text-center text-gray-900 mb-6"
|
| 89 |
|
| 90 |
<!-- 模式選擇區塊 -->
|
| 91 |
<div id="mode-selection-section">
|
|
@@ -103,31 +103,41 @@
|
|
| 103 |
<span class="font-semibold text-gray-700">-</span>
|
| 104 |
<input type="number" id="end-range" min="1" class="w-20 p-2 border border-gray-300 rounded-lg text-center" placeholder="到">
|
| 105 |
</div>
|
| 106 |
-
|
| 107 |
-
|
| 108 |
-
|
| 109 |
-
|
| 110 |
-
|
| 111 |
-
|
| 112 |
-
|
| 113 |
-
|
| 114 |
-
|
| 115 |
-
|
| 116 |
-
|
| 117 |
-
|
| 118 |
-
|
| 119 |
-
|
| 120 |
-
|
| 121 |
-
|
| 122 |
-
|
| 123 |
-
|
| 124 |
-
|
| 125 |
-
|
| 126 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 127 |
</div>
|
| 128 |
-
<button id="manage-words-btn" class="w-full mt-6 bg-gray-500 text-white font-bold py-3 rounded-full hover:bg-gray-600 focus:outline-none focus:ring-4 focus:ring-gray-300 transition-all">
|
| 129 |
-
單字列表管理
|
| 130 |
-
</button>
|
| 131 |
</div>
|
| 132 |
</div>
|
| 133 |
|
|
@@ -140,6 +150,16 @@
|
|
| 140 |
</button>
|
| 141 |
</div>
|
| 142 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 143 |
<!-- 新增單字區塊 -->
|
| 144 |
<div id="add-words-section" class="mb-6 p-4 bg-gray-50 rounded-2xl hidden">
|
| 145 |
<h3 class="text-xl font-semibold mb-4 text-gray-700">新增單字</h3>
|
|
@@ -315,12 +335,17 @@
|
|
| 315 |
</div>
|
| 316 |
</div>
|
| 317 |
</div>
|
| 318 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 319 |
|
| 320 |
<script>
|
| 321 |
document.addEventListener('DOMContentLoaded', () => {
|
| 322 |
// DOM 元素
|
| 323 |
const mainMenu = document.getElementById('main-menu');
|
|
|
|
| 324 |
const learningMode = document.getElementById('learning-mode');
|
| 325 |
const modeSelectionSection = document.getElementById('mode-selection-section');
|
| 326 |
const highscoreDisplay = document.getElementById('highscore-display');
|
|
@@ -331,6 +356,9 @@
|
|
| 331 |
|
| 332 |
// 單字管理介面
|
| 333 |
const wordManagementView = document.getElementById('word-management-view');
|
|
|
|
|
|
|
|
|
|
| 334 |
const backToModesFromManageBtn = document.getElementById('back-to-modes-from-manage-btn');
|
| 335 |
const addWordsSection = document.getElementById('add-words-section');
|
| 336 |
const showAddWordsSectionBtn = document.getElementById('show-add-words-section-btn');
|
|
@@ -406,6 +434,8 @@
|
|
| 406 |
let currentCardIndex = 0;
|
| 407 |
let currentMode = '';
|
| 408 |
let completionStatus = {};
|
|
|
|
|
|
|
| 409 |
const MANAGE_PASSWORD = 'Ghjh';
|
| 410 |
let highScore = 0;
|
| 411 |
let currentScore = 0;
|
|
@@ -426,6 +456,14 @@
|
|
| 426 |
learningMode.classList.toggle('hidden', view !== 'learning');
|
| 427 |
wordManagementView.classList.toggle('hidden', view !== 'manage');
|
| 428 |
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 429 |
|
| 430 |
// --- 資料處理 ---
|
| 431 |
const saveWordsToStorage = () => {
|
|
@@ -473,7 +511,7 @@
|
|
| 473 |
editChineseInput.value = words[index].chinese;
|
| 474 |
editWordModal.classList.remove('hidden');
|
| 475 |
} else if (button.classList.contains('delete-btn')) {
|
| 476 |
-
if (
|
| 477 |
const itemElement = button.closest('.list-item');
|
| 478 |
itemElement.classList.add('removing');
|
| 479 |
setTimeout(() => {
|
|
@@ -533,6 +571,8 @@
|
|
| 533 |
manageWordsBtn.addEventListener('click', () => {
|
| 534 |
passwordInput.value = '';
|
| 535 |
passwordError.textContent = '';
|
|
|
|
|
|
|
| 536 |
passwordModal.classList.remove('hidden');
|
| 537 |
setTimeout(() => passwordInput.focus(), 50);
|
| 538 |
});
|
|
@@ -829,7 +869,7 @@
|
|
| 829 |
nextBtn.addEventListener('click', () => { if (currentCardIndex < wordsForCurrentMode.length - 1) { currentCardIndex++; displayCard(); }});
|
| 830 |
quizForm.addEventListener('submit', (e) => { e.preventDefault(); checkAnswer(); });
|
| 831 |
speakBtn.addEventListener('click', (e) => { e.stopPropagation(); const word = getCurrentWordToSpeak(); if(word) speakWord(word, 0.75); });
|
| 832 |
-
speakSlowBtn.addEventListener('click', (e) => { e.stopPropagation(); const word = getCurrentWordToSpeak(); if(word) speakWord(word, 0.
|
| 833 |
hintBtn.addEventListener('click', () => {
|
| 834 |
const card = currentMode === 'speed' ? currentSpeedCard : quizQueue[0];
|
| 835 |
if (!card) return;
|
|
@@ -859,6 +899,30 @@
|
|
| 859 |
});
|
| 860 |
cancelPasswordBtn.addEventListener('click', () => passwordModal.classList.add('hidden'));
|
| 861 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 862 |
shareGameBtn.addEventListener('click', () => {
|
| 863 |
try {
|
| 864 |
const wordsString = JSON.stringify(words);
|
|
@@ -938,6 +1002,10 @@
|
|
| 938 |
}
|
| 939 |
}
|
| 940 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 941 |
completionStatus = JSON.parse(localStorage.getItem('completionStatus')) || {};
|
| 942 |
updateCompletionUI();
|
| 943 |
highScore = parseInt(localStorage.getItem('flashcardsHighScore') || '0', 10);
|
|
|
|
| 85 |
|
| 86 |
<!-- 主選單:新增單字 & 模式選擇 -->
|
| 87 |
<div id="main-menu" class="w-full max-w-2xl bg-white p-6 rounded-3xl shadow-2xl transition-all duration-500">
|
| 88 |
+
<h1 id="main-title" class="text-4xl font-extrabold text-center text-gray-900 mb-6"></h1>
|
| 89 |
|
| 90 |
<!-- 模式選擇區塊 -->
|
| 91 |
<div id="mode-selection-section">
|
|
|
|
| 103 |
<span class="font-semibold text-gray-700">-</span>
|
| 104 |
<input type="number" id="end-range" min="1" class="w-20 p-2 border border-gray-300 rounded-lg text-center" placeholder="到">
|
| 105 |
</div>
|
| 106 |
+
|
| 107 |
+
<!-- 主要功能 -->
|
| 108 |
+
<div class="mb-4">
|
| 109 |
+
<h3 class="text-lg font-semibold text-gray-600 mb-3 text-center border-b pb-2">主要功能</h3>
|
| 110 |
+
<div class="grid grid-cols-1 sm:grid-cols-2 gap-4">
|
| 111 |
+
<button data-mode="review" class="mode-btn bg-sky-500 hover:bg-sky-600">複習模式</button>
|
| 112 |
+
<button data-mode="zh-en" class="mode-btn bg-teal-500 hover:bg-teal-600 relative">
|
| 113 |
+
中翻英測驗
|
| 114 |
+
<span class="crown-icon hidden absolute -top-2 -right-1 text-4xl" style="transform: rotate(15deg);">👑</span>
|
| 115 |
+
</button>
|
| 116 |
+
<button data-mode="en-zh" class="mode-btn bg-amber-500 hover:bg-amber-600 relative">
|
| 117 |
+
英翻中測驗
|
| 118 |
+
<span class="crown-icon hidden absolute -top-2 -right-1 text-4xl" style="transform: rotate(15deg);">👑</span>
|
| 119 |
+
</button>
|
| 120 |
+
<button data-mode="listen" class="mode-btn bg-rose-500 hover:bg-rose-600 relative">
|
| 121 |
+
聽力測驗
|
| 122 |
+
<span class="crown-icon hidden absolute -top-2 -right-1 text-4xl" style="transform: rotate(15deg);">👑</span>
|
| 123 |
+
</button>
|
| 124 |
+
</div>
|
| 125 |
+
</div>
|
| 126 |
+
|
| 127 |
+
<!-- 補充功能 -->
|
| 128 |
+
<div class="mb-4">
|
| 129 |
+
<h3 class="text-lg font-semibold text-gray-600 mb-3 text-center border-b pb-2">補充功能</h3>
|
| 130 |
+
<div class="grid grid-cols-1 sm:grid-cols-2 gap-4">
|
| 131 |
+
<button data-mode="hard" class="mode-btn bg-red-700 hover:bg-red-800">🧠 困難單字複習</button>
|
| 132 |
+
<button data-mode="speed" class="mode-btn bg-slate-700 hover:bg-slate-800">⚡ 極速挑戰 ⚡</button>
|
| 133 |
+
</div>
|
| 134 |
+
</div>
|
| 135 |
+
|
| 136 |
+
<!-- 教師工具 -->
|
| 137 |
+
<div class="mt-8 pt-4 border-t flex justify-end items-center gap-3">
|
| 138 |
+
<button id="share-game-btn" class="text-white font-semibold py-2 px-5 rounded-full transition-transform hover:scale-105 bg-violet-500 hover:bg-violet-600 text-sm">🔗 分享</button>
|
| 139 |
+
<button id="manage-words-btn" class="text-white font-semibold py-2 px-5 rounded-full transition-transform hover:scale-105 bg-gray-500 hover:bg-gray-600 text-sm">⚙️ 管理</button>
|
| 140 |
</div>
|
|
|
|
|
|
|
|
|
|
| 141 |
</div>
|
| 142 |
</div>
|
| 143 |
|
|
|
|
| 150 |
</button>
|
| 151 |
</div>
|
| 152 |
|
| 153 |
+
<!-- 標題���定區塊 -->
|
| 154 |
+
<div class="mb-6 p-4 bg-gray-50 rounded-2xl">
|
| 155 |
+
<h3 class="text-xl font-semibold mb-4 text-gray-700">標題設定</h3>
|
| 156 |
+
<div class="flex items-center gap-4">
|
| 157 |
+
<input type="text" id="book-input" class="w-full p-2 border border-gray-300 rounded-lg" placeholder="冊次 (例如 B3)">
|
| 158 |
+
<input type="text" id="lesson-input" class="w-full p-2 border border-gray-300 rounded-lg" placeholder="課次 (例如 L1)">
|
| 159 |
+
<button id="save-title-btn" class="bg-indigo-600 text-white font-bold py-2 px-6 rounded-full hover:bg-indigo-700 shrink-0 transition-colors">儲存標題</button>
|
| 160 |
+
</div>
|
| 161 |
+
</div>
|
| 162 |
+
|
| 163 |
<!-- 新增單字區塊 -->
|
| 164 |
<div id="add-words-section" class="mb-6 p-4 bg-gray-50 rounded-2xl hidden">
|
| 165 |
<h3 class="text-xl font-semibold mb-4 text-gray-700">新增單字</h3>
|
|
|
|
| 335 |
</div>
|
| 336 |
</div>
|
| 337 |
</div>
|
| 338 |
+
|
| 339 |
+
<footer class="fixed bottom-4 right-4 text-xs text-gray-500 text-right z-50">
|
| 340 |
+
<p>遊戲設計者:新竹縣精華國中藍星宇</p>
|
| 341 |
+
<p>FB教育社群:<a href="https://www.facebook.com/groups/1554372228718393" target="_blank" rel="noopener noreferrer" class="text-blue-500 hover:underline">萬物皆數</a></p>
|
| 342 |
+
</footer>
|
| 343 |
|
| 344 |
<script>
|
| 345 |
document.addEventListener('DOMContentLoaded', () => {
|
| 346 |
// DOM 元素
|
| 347 |
const mainMenu = document.getElementById('main-menu');
|
| 348 |
+
const mainTitle = document.getElementById('main-title');
|
| 349 |
const learningMode = document.getElementById('learning-mode');
|
| 350 |
const modeSelectionSection = document.getElementById('mode-selection-section');
|
| 351 |
const highscoreDisplay = document.getElementById('highscore-display');
|
|
|
|
| 356 |
|
| 357 |
// 單字管理介面
|
| 358 |
const wordManagementView = document.getElementById('word-management-view');
|
| 359 |
+
const bookInput = document.getElementById('book-input');
|
| 360 |
+
const lessonInput = document.getElementById('lesson-input');
|
| 361 |
+
const saveTitleBtn = document.getElementById('save-title-btn');
|
| 362 |
const backToModesFromManageBtn = document.getElementById('back-to-modes-from-manage-btn');
|
| 363 |
const addWordsSection = document.getElementById('add-words-section');
|
| 364 |
const showAddWordsSectionBtn = document.getElementById('show-add-words-section-btn');
|
|
|
|
| 434 |
let currentCardIndex = 0;
|
| 435 |
let currentMode = '';
|
| 436 |
let completionStatus = {};
|
| 437 |
+
let bookTitle = '';
|
| 438 |
+
let lessonTitle = '';
|
| 439 |
const MANAGE_PASSWORD = 'Ghjh';
|
| 440 |
let highScore = 0;
|
| 441 |
let currentScore = 0;
|
|
|
|
| 456 |
learningMode.classList.toggle('hidden', view !== 'learning');
|
| 457 |
wordManagementView.classList.toggle('hidden', view !== 'manage');
|
| 458 |
};
|
| 459 |
+
|
| 460 |
+
const updateMainTitle = () => {
|
| 461 |
+
if (bookTitle && lessonTitle) {
|
| 462 |
+
mainTitle.textContent = `${bookTitle} ${lessonTitle} 單字閃卡`;
|
| 463 |
+
} else {
|
| 464 |
+
mainTitle.textContent = '單字閃卡';
|
| 465 |
+
}
|
| 466 |
+
};
|
| 467 |
|
| 468 |
// --- 資料處理 ---
|
| 469 |
const saveWordsToStorage = () => {
|
|
|
|
| 511 |
editChineseInput.value = words[index].chinese;
|
| 512 |
editWordModal.classList.remove('hidden');
|
| 513 |
} else if (button.classList.contains('delete-btn')) {
|
| 514 |
+
if (confirm(`確定要刪除 "${words[index].english}" 嗎?`)) {
|
| 515 |
const itemElement = button.closest('.list-item');
|
| 516 |
itemElement.classList.add('removing');
|
| 517 |
setTimeout(() => {
|
|
|
|
| 571 |
manageWordsBtn.addEventListener('click', () => {
|
| 572 |
passwordInput.value = '';
|
| 573 |
passwordError.textContent = '';
|
| 574 |
+
bookInput.value = bookTitle;
|
| 575 |
+
lessonInput.value = lessonTitle;
|
| 576 |
passwordModal.classList.remove('hidden');
|
| 577 |
setTimeout(() => passwordInput.focus(), 50);
|
| 578 |
});
|
|
|
|
| 869 |
nextBtn.addEventListener('click', () => { if (currentCardIndex < wordsForCurrentMode.length - 1) { currentCardIndex++; displayCard(); }});
|
| 870 |
quizForm.addEventListener('submit', (e) => { e.preventDefault(); checkAnswer(); });
|
| 871 |
speakBtn.addEventListener('click', (e) => { e.stopPropagation(); const word = getCurrentWordToSpeak(); if(word) speakWord(word, 0.75); });
|
| 872 |
+
speakSlowBtn.addEventListener('click', (e) => { e.stopPropagation(); const word = getCurrentWordToSpeak(); if(word) speakWord(word, 0.35); });
|
| 873 |
hintBtn.addEventListener('click', () => {
|
| 874 |
const card = currentMode === 'speed' ? currentSpeedCard : quizQueue[0];
|
| 875 |
if (!card) return;
|
|
|
|
| 899 |
});
|
| 900 |
cancelPasswordBtn.addEventListener('click', () => passwordModal.classList.add('hidden'));
|
| 901 |
|
| 902 |
+
saveTitleBtn.addEventListener('click', () => {
|
| 903 |
+
const newBook = bookInput.value.trim();
|
| 904 |
+
const newLesson = lessonInput.value.trim();
|
| 905 |
+
if (newBook && newLesson) {
|
| 906 |
+
bookTitle = newBook;
|
| 907 |
+
lessonTitle = newLesson;
|
| 908 |
+
localStorage.setItem('flashcardsBookTitle', bookTitle);
|
| 909 |
+
localStorage.setItem('flashcardsLessonTitle', lessonTitle);
|
| 910 |
+
updateMainTitle();
|
| 911 |
+
// Simple feedback
|
| 912 |
+
const originalText = saveTitleBtn.textContent;
|
| 913 |
+
saveTitleBtn.textContent = '已儲存!';
|
| 914 |
+
saveTitleBtn.classList.remove('bg-indigo-600', 'hover:bg-indigo-700');
|
| 915 |
+
saveTitleBtn.classList.add('bg-green-500', 'hover:bg-green-600');
|
| 916 |
+
setTimeout(() => {
|
| 917 |
+
saveTitleBtn.textContent = originalText;
|
| 918 |
+
saveTitleBtn.classList.remove('bg-green-500', 'hover:bg-green-600');
|
| 919 |
+
saveTitleBtn.classList.add('bg-indigo-600', 'hover:bg-indigo-700');
|
| 920 |
+
}, 2000);
|
| 921 |
+
} else {
|
| 922 |
+
alert('冊次和課次不能為空!');
|
| 923 |
+
}
|
| 924 |
+
});
|
| 925 |
+
|
| 926 |
shareGameBtn.addEventListener('click', () => {
|
| 927 |
try {
|
| 928 |
const wordsString = JSON.stringify(words);
|
|
|
|
| 1002 |
}
|
| 1003 |
}
|
| 1004 |
|
| 1005 |
+
bookTitle = localStorage.getItem('flashcardsBookTitle') || 'B3';
|
| 1006 |
+
lessonTitle = localStorage.getItem('flashcardsLessonTitle') || 'L1';
|
| 1007 |
+
updateMainTitle();
|
| 1008 |
+
|
| 1009 |
completionStatus = JSON.parse(localStorage.getItem('completionStatus')) || {};
|
| 1010 |
updateCompletionUI();
|
| 1011 |
highScore = parseInt(localStorage.getItem('flashcardsHighScore') || '0', 10);
|