Spaces:
Running
Running
Update index.html
Browse files- index.html +53 -5
index.html
CHANGED
|
@@ -8,6 +8,8 @@
|
|
| 8 |
<script src="https://cdn.tailwindcss.com"></script>
|
| 9 |
<!-- 載入彩帶效果庫 -->
|
| 10 |
<script src="https://cdn.jsdelivr.net/npm/canvas-confetti@1.9.2/dist/confetti.browser.min.js"></script>
|
|
|
|
|
|
|
| 11 |
<style>
|
| 12 |
/* 定義閃卡的翻轉效果 */
|
| 13 |
.flip-container {
|
|
@@ -79,6 +81,12 @@
|
|
| 79 |
opacity: 0;
|
| 80 |
transform: translateX(100%);
|
| 81 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 82 |
</style>
|
| 83 |
</head>
|
| 84 |
<body class="bg-gray-50 min-h-screen flex flex-col items-center p-4 sm:p-8 font-sans">
|
|
@@ -343,7 +351,7 @@
|
|
| 343 |
</label>
|
| 344 |
</div>
|
| 345 |
|
| 346 |
-
<button id="generate-link-btn" class="w-full mb-4 bg-indigo-600 text-white font-bold py-3 rounded-lg hover:bg-indigo-700 transition-colors">
|
| 347 |
產生分享連結
|
| 348 |
</button>
|
| 349 |
|
|
@@ -354,6 +362,7 @@
|
|
| 354 |
<button id="copy-link-btn" class="px-6 py-3 bg-violet-600 text-white rounded-lg hover:bg-violet-700 shrink-0">複製</button>
|
| 355 |
</div>
|
| 356 |
<p id="copy-feedback" class="text-green-600 text-sm h-5 mt-2 text-center font-semibold"></p>
|
|
|
|
| 357 |
</div>
|
| 358 |
|
| 359 |
<div class="flex justify-end mt-4">
|
|
@@ -487,6 +496,7 @@
|
|
| 487 |
const copyLinkBtn = document.getElementById('copy-link-btn');
|
| 488 |
const copyFeedback = document.getElementById('copy-feedback');
|
| 489 |
const closeShareModalBtn = document.getElementById('close-share-modal-btn');
|
|
|
|
| 490 |
const confirmClearModal = document.getElementById('confirm-clear-modal');
|
| 491 |
const cancelClearBtn = document.getElementById('cancel-clear-btn');
|
| 492 |
const confirmClearBtn = document.getElementById('confirm-clear-btn');
|
|
@@ -1020,6 +1030,21 @@
|
|
| 1020 |
});
|
| 1021 |
};
|
| 1022 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1023 |
// --- 事件監聽 ---
|
| 1024 |
document.querySelectorAll('.mode-btn[data-mode]').forEach(btn => {
|
| 1025 |
btn.addEventListener('click', () => setupLearningView(btn.dataset.mode));
|
|
@@ -1041,7 +1066,7 @@
|
|
| 1041 |
nextBtn.addEventListener('click', () => { if (currentCardIndex < wordsForCurrentMode.length - 1) { currentCardIndex++; displayCard(); }});
|
| 1042 |
quizForm.addEventListener('submit', (e) => { e.preventDefault(); checkAnswer(); });
|
| 1043 |
speakBtn.addEventListener('click', (e) => { e.stopPropagation(); const word = getCurrentWordToSpeak(); if(word) speakWord(word, 0.75); });
|
| 1044 |
-
speakSlowBtn.addEventListener('click', (e) => { e.stopPropagation(); const word = getCurrentWordToSpeak(); if(word) speakWord(word, 0.
|
| 1045 |
hintBtn.addEventListener('click', () => {
|
| 1046 |
const card = currentMode === 'speed' ? currentSpeedCard : quizQueue[0];
|
| 1047 |
if (!card) return;
|
|
@@ -1099,10 +1124,16 @@
|
|
| 1099 |
shareResultContainer.classList.add('hidden');
|
| 1100 |
shareLinkInput.value = '';
|
| 1101 |
copyFeedback.textContent = '';
|
|
|
|
|
|
|
|
|
|
| 1102 |
shareModal.classList.remove('hidden');
|
| 1103 |
});
|
| 1104 |
|
| 1105 |
-
generateLinkBtn.addEventListener('click', () => {
|
|
|
|
|
|
|
|
|
|
| 1106 |
try {
|
| 1107 |
const wordsString = JSON.stringify(words);
|
| 1108 |
const base64Words = btoa(unescape(encodeURIComponent(wordsString)));
|
|
@@ -1124,12 +1155,29 @@
|
|
| 1124 |
}
|
| 1125 |
}
|
| 1126 |
|
| 1127 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1128 |
shareResultContainer.classList.remove('hidden');
|
| 1129 |
|
| 1130 |
} catch (error) {
|
| 1131 |
console.error("產生分享連結時發生錯誤:", error);
|
| 1132 |
-
alert("
|
|
|
|
|
|
|
|
|
|
| 1133 |
}
|
| 1134 |
});
|
| 1135 |
|
|
|
|
| 8 |
<script src="https://cdn.tailwindcss.com"></script>
|
| 9 |
<!-- 載入彩帶效果庫 -->
|
| 10 |
<script src="https://cdn.jsdelivr.net/npm/canvas-confetti@1.9.2/dist/confetti.browser.min.js"></script>
|
| 11 |
+
<!-- 載入 QR Code 產生器 -->
|
| 12 |
+
<script src="https://cdn.jsdelivr.net/npm/qrcode-generator/qrcode.js"></script>
|
| 13 |
<style>
|
| 14 |
/* 定義閃卡的翻轉效果 */
|
| 15 |
.flip-container {
|
|
|
|
| 81 |
opacity: 0;
|
| 82 |
transform: translateX(100%);
|
| 83 |
}
|
| 84 |
+
#qrcode-container img {
|
| 85 |
+
margin: auto;
|
| 86 |
+
border: 6px solid white;
|
| 87 |
+
border-radius: 10px;
|
| 88 |
+
box-shadow: 0 4px 6px rgba(0,0,0,0.1);
|
| 89 |
+
}
|
| 90 |
</style>
|
| 91 |
</head>
|
| 92 |
<body class="bg-gray-50 min-h-screen flex flex-col items-center p-4 sm:p-8 font-sans">
|
|
|
|
| 351 |
</label>
|
| 352 |
</div>
|
| 353 |
|
| 354 |
+
<button id="generate-link-btn" class="w-full mb-4 bg-indigo-600 text-white font-bold py-3 rounded-lg hover:bg-indigo-700 transition-colors disabled:bg-indigo-400">
|
| 355 |
產生分享連結
|
| 356 |
</button>
|
| 357 |
|
|
|
|
| 362 |
<button id="copy-link-btn" class="px-6 py-3 bg-violet-600 text-white rounded-lg hover:bg-violet-700 shrink-0">複製</button>
|
| 363 |
</div>
|
| 364 |
<p id="copy-feedback" class="text-green-600 text-sm h-5 mt-2 text-center font-semibold"></p>
|
| 365 |
+
<div id="qrcode-container" class="mt-4 flex justify-center"></div>
|
| 366 |
</div>
|
| 367 |
|
| 368 |
<div class="flex justify-end mt-4">
|
|
|
|
| 496 |
const copyLinkBtn = document.getElementById('copy-link-btn');
|
| 497 |
const copyFeedback = document.getElementById('copy-feedback');
|
| 498 |
const closeShareModalBtn = document.getElementById('close-share-modal-btn');
|
| 499 |
+
const qrcodeContainer = document.getElementById('qrcode-container');
|
| 500 |
const confirmClearModal = document.getElementById('confirm-clear-modal');
|
| 501 |
const cancelClearBtn = document.getElementById('cancel-clear-btn');
|
| 502 |
const confirmClearBtn = document.getElementById('confirm-clear-btn');
|
|
|
|
| 1030 |
});
|
| 1031 |
};
|
| 1032 |
|
| 1033 |
+
const generateQRCode = (text) => {
|
| 1034 |
+
qrcodeContainer.innerHTML = '';
|
| 1035 |
+
try {
|
| 1036 |
+
const typeNumber = 4;
|
| 1037 |
+
const errorCorrectionLevel = 'L';
|
| 1038 |
+
const qr = qrcode(typeNumber, errorCorrectionLevel);
|
| 1039 |
+
qr.addData(text);
|
| 1040 |
+
qr.make();
|
| 1041 |
+
qrcodeContainer.innerHTML = qr.createImgTag(6, 12);
|
| 1042 |
+
} catch(e) {
|
| 1043 |
+
console.error("QR Code generation failed:", e);
|
| 1044 |
+
qrcodeContainer.textContent = 'QR碼產生失敗,網址可能過長。';
|
| 1045 |
+
}
|
| 1046 |
+
};
|
| 1047 |
+
|
| 1048 |
// --- 事件監聽 ---
|
| 1049 |
document.querySelectorAll('.mode-btn[data-mode]').forEach(btn => {
|
| 1050 |
btn.addEventListener('click', () => setupLearningView(btn.dataset.mode));
|
|
|
|
| 1066 |
nextBtn.addEventListener('click', () => { if (currentCardIndex < wordsForCurrentMode.length - 1) { currentCardIndex++; displayCard(); }});
|
| 1067 |
quizForm.addEventListener('submit', (e) => { e.preventDefault(); checkAnswer(); });
|
| 1068 |
speakBtn.addEventListener('click', (e) => { e.stopPropagation(); const word = getCurrentWordToSpeak(); if(word) speakWord(word, 0.75); });
|
| 1069 |
+
speakSlowBtn.addEventListener('click', (e) => { e.stopPropagation(); const word = getCurrentWordToSpeak(); if(word) speakWord(word, 0.35); });
|
| 1070 |
hintBtn.addEventListener('click', () => {
|
| 1071 |
const card = currentMode === 'speed' ? currentSpeedCard : quizQueue[0];
|
| 1072 |
if (!card) return;
|
|
|
|
| 1124 |
shareResultContainer.classList.add('hidden');
|
| 1125 |
shareLinkInput.value = '';
|
| 1126 |
copyFeedback.textContent = '';
|
| 1127 |
+
qrcodeContainer.innerHTML = '';
|
| 1128 |
+
generateLinkBtn.textContent = '產生分享連結';
|
| 1129 |
+
generateLinkBtn.disabled = false;
|
| 1130 |
shareModal.classList.remove('hidden');
|
| 1131 |
});
|
| 1132 |
|
| 1133 |
+
generateLinkBtn.addEventListener('click', async () => {
|
| 1134 |
+
generateLinkBtn.textContent = '產生中...';
|
| 1135 |
+
generateLinkBtn.disabled = true;
|
| 1136 |
+
|
| 1137 |
try {
|
| 1138 |
const wordsString = JSON.stringify(words);
|
| 1139 |
const base64Words = btoa(unescape(encodeURIComponent(wordsString)));
|
|
|
|
| 1155 |
}
|
| 1156 |
}
|
| 1157 |
|
| 1158 |
+
const longUrl = url.toString();
|
| 1159 |
+
|
| 1160 |
+
// 使用TinyURL API縮短網址
|
| 1161 |
+
const response = await fetch(`https://tinyurl.com/api-create.php?url=${encodeURIComponent(longUrl)}`);
|
| 1162 |
+
if (response.ok) {
|
| 1163 |
+
const shortUrl = await response.text();
|
| 1164 |
+
shareLinkInput.value = shortUrl;
|
| 1165 |
+
generateQRCode(shortUrl);
|
| 1166 |
+
} else {
|
| 1167 |
+
// 如果API失敗,則退回使用長網址
|
| 1168 |
+
shareLinkInput.value = longUrl;
|
| 1169 |
+
generateQRCode(longUrl);
|
| 1170 |
+
copyFeedback.textContent = '縮短網址失敗,已產生原始連結。';
|
| 1171 |
+
}
|
| 1172 |
+
|
| 1173 |
shareResultContainer.classList.remove('hidden');
|
| 1174 |
|
| 1175 |
} catch (error) {
|
| 1176 |
console.error("產生分享連結時發生錯誤:", error);
|
| 1177 |
+
alert("產生分享連結時發生錯誤,可能是網路問題或單字列表過大。");
|
| 1178 |
+
} finally {
|
| 1179 |
+
generateLinkBtn.textContent = '重新產生';
|
| 1180 |
+
generateLinkBtn.disabled = false;
|
| 1181 |
}
|
| 1182 |
});
|
| 1183 |
|