Spaces:
Sleeping
Sleeping
Update index.html
Browse files- index.html +188 -16
index.html
CHANGED
|
@@ -209,6 +209,24 @@
|
|
| 209 |
</div>
|
| 210 |
</div>
|
| 211 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 212 |
<!-- Player Controls and Phrase Loop -->
|
| 213 |
<div class="mt-4 border-t pt-4">
|
| 214 |
<audio id="audioPlayer" controls class="w-full mb-4"></audio>
|
|
@@ -223,8 +241,37 @@
|
|
| 223 |
</div>
|
| 224 |
</div>
|
| 225 |
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 226 |
|
| 227 |
-
|
|
|
|
| 228 |
<div id="flashcardsPanel" class="card">
|
| 229 |
<h2 class="text-xl font-semibold mb-4 text-gray-700">Your Flashcards (Study Session)</h2>
|
| 230 |
<div id="flashcardList" class="space-y-3">
|
|
@@ -282,7 +329,14 @@
|
|
| 282 |
const flashcardList = document.getElementById('flashcardList');
|
| 283 |
const noCardsMessage = document.getElementById('noCardsMessage');
|
| 284 |
const speedSelector = document.getElementById('speedSelector');
|
| 285 |
-
const modelSelector = document.getElementById('modelSelector');
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 286 |
|
| 287 |
const MAX_CHARS = 5000;
|
| 288 |
let isLooping = false;
|
|
@@ -321,6 +375,8 @@
|
|
| 321 |
const currentLength = getEditorText().length;
|
| 322 |
charCount.textContent = currentLength;
|
| 323 |
playButton.disabled = currentLength === 0;
|
|
|
|
|
|
|
| 324 |
});
|
| 325 |
|
| 326 |
// Update character count on load
|
|
@@ -345,7 +401,6 @@
|
|
| 345 |
loadingSpinner.classList.remove('hidden');
|
| 346 |
|
| 347 |
try {
|
| 348 |
-
// Route for the backend using gTTS
|
| 349 |
const response = await fetch('/tts-proxy', {
|
| 350 |
method: 'POST',
|
| 351 |
headers: { 'Content-Type': 'application/json' },
|
|
@@ -415,6 +470,126 @@
|
|
| 415 |
}
|
| 416 |
});
|
| 417 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 418 |
// --- Quick Translation Functionality (Double Click) ---
|
| 419 |
|
| 420 |
async function fetchExplanationAndTranslation(word, context, isFlashcard=false) {
|
|
@@ -423,25 +598,24 @@
|
|
| 423 |
const translationText = isFlashcard ? null : document.getElementById('translationText');
|
| 424 |
|
| 425 |
const modelValue = modelSelector.value;
|
|
|
|
| 426 |
|
| 427 |
if (!isFlashcard) {
|
| 428 |
-
// Show loading state in modal
|
| 429 |
explanationText.textContent = '';
|
| 430 |
translationText.textContent = '';
|
| 431 |
}
|
| 432 |
spinner.classList.remove('hidden');
|
| 433 |
|
| 434 |
try {
|
| 435 |
-
// Route for the backend using Gemini/Groq for explanation/translation
|
| 436 |
const response = await fetch('/explain-proxy', {
|
| 437 |
method: 'POST',
|
| 438 |
headers: { 'Content-Type': 'application/json' },
|
| 439 |
-
// Sends the clicked word, context, and the selected model
|
| 440 |
body: JSON.stringify({
|
| 441 |
word: word,
|
| 442 |
context: context,
|
| 443 |
for_flashcard: isFlashcard,
|
| 444 |
-
model: modelValue
|
|
|
|
| 445 |
})
|
| 446 |
});
|
| 447 |
|
|
@@ -453,7 +627,7 @@
|
|
| 453 |
const data = await response.json();
|
| 454 |
|
| 455 |
if (isFlashcard) {
|
| 456 |
-
return data;
|
| 457 |
} else {
|
| 458 |
explanationText.textContent = data.explanation || 'Could not retrieve explanation.';
|
| 459 |
translationText.textContent = data.translation || 'Could not retrieve translation.';
|
|
@@ -477,17 +651,17 @@
|
|
| 477 |
|
| 478 |
// Logic to open the Modal on double click
|
| 479 |
textEditor.addEventListener('dblclick', (event) => {
|
| 480 |
-
const
|
|
|
|
| 481 |
|
| 482 |
if (selectedWord) {
|
| 483 |
const fullText = getEditorText();
|
| 484 |
-
const index = fullText.indexOf(
|
| 485 |
-
const context = fullText.substring(Math.max(0, index - 50), index +
|
| 486 |
|
| 487 |
document.getElementById('wordSelected').textContent = selectedWord;
|
| 488 |
openModal();
|
| 489 |
|
| 490 |
-
// Start fetching explanation and translation
|
| 491 |
fetchExplanationAndTranslation(selectedWord, context);
|
| 492 |
}
|
| 493 |
});
|
|
@@ -508,7 +682,6 @@
|
|
| 508 |
createCardButton.innerHTML = `<div class="spinner mr-2"></div> Creating Card...`;
|
| 509 |
|
| 510 |
try {
|
| 511 |
-
// Fetch the structured data for the flashcard
|
| 512 |
const cardData = await fetchExplanationAndTranslation(selectedText, context, true);
|
| 513 |
|
| 514 |
if (cardData && cardData.term && cardData.translation && cardData.example) {
|
|
@@ -529,17 +702,16 @@
|
|
| 529 |
const cardElement = document.createElement('div');
|
| 530 |
cardElement.className = 'flashcard';
|
| 531 |
|
| 532 |
-
//
|
| 533 |
cardElement.innerHTML = `
|
| 534 |
<div class="flashcard-front">
|
| 535 |
<p class="flashcard-term">${data.term.toUpperCase()}</p>
|
| 536 |
<p class="flashcard-definition">PT: ${data.translation}</p>
|
| 537 |
<p class="flashcard-example">Example: ${data.example}</p>
|
| 538 |
</div>
|
| 539 |
-
<!-- Back side (Definition) can be toggled via JS if needed -->
|
| 540 |
`;
|
| 541 |
|
| 542 |
-
flashcardList.prepend(cardElement);
|
| 543 |
}
|
| 544 |
|
| 545 |
|
|
|
|
| 209 |
</div>
|
| 210 |
</div>
|
| 211 |
|
| 212 |
+
<!-- Context Selector (NEW) -->
|
| 213 |
+
<div class="grid grid-cols-1 md:grid-cols-2 gap-4 mt-4">
|
| 214 |
+
<div>
|
| 215 |
+
<label for="contextSelector" class="block text-sm font-medium text-gray-700">Vocabulary Context / Focus Area</label>
|
| 216 |
+
<select id="contextSelector" class="mt-1 block w-full pl-3 pr-10 py-2 text-base border-gray-300 focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm rounded-md shadow-sm">
|
| 217 |
+
<option value="General/Social (Casual conversation, daily life)">General/Social (Casual conversation, daily life)</option>
|
| 218 |
+
<option value="Professional/Business (Meetings, emails, reports)">Professional/Business (Meetings, emails, reports)</option>
|
| 219 |
+
<option value="Technical/IT (Software, Engineering, Tech topics)">Technical/IT (Software, Engineering, Tech topics)</option>
|
| 220 |
+
</select>
|
| 221 |
+
</div>
|
| 222 |
+
<!-- Full Translation Button -->
|
| 223 |
+
<div class="flex items-end">
|
| 224 |
+
<button id="translateFullTextButton" onclick="translateFullText()" class="btn-secondary w-full py-2.5 rounded-lg font-semibold disabled:opacity-50">
|
| 225 |
+
Translate Full Text (PT)
|
| 226 |
+
</button>
|
| 227 |
+
</div>
|
| 228 |
+
</div>
|
| 229 |
+
|
| 230 |
<!-- Player Controls and Phrase Loop -->
|
| 231 |
<div class="mt-4 border-t pt-4">
|
| 232 |
<audio id="audioPlayer" controls class="w-full mb-4"></audio>
|
|
|
|
| 241 |
</div>
|
| 242 |
</div>
|
| 243 |
</div>
|
| 244 |
+
|
| 245 |
+
<!-- Writing/Translation Activity Panel (NEW) -->
|
| 246 |
+
<div class="card mb-6">
|
| 247 |
+
<h2 class="text-xl font-semibold mb-4 text-gray-700">Writing & Translation Activities</h2>
|
| 248 |
+
<div class="grid grid-cols-1 md:grid-cols-3 gap-4 mb-4">
|
| 249 |
+
<!-- Activity Selector -->
|
| 250 |
+
<div class="md:col-span-2">
|
| 251 |
+
<label for="activityTypeSelector" class="block text-sm font-medium text-gray-700">Activity Type</label>
|
| 252 |
+
<select id="activityTypeSelector" class="mt-1 block w-full pl-3 pr-10 py-2 text-base border-gray-300 focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm rounded-md shadow-sm">
|
| 253 |
+
<option value="translation_pt_en">Translation from PT to EN (Practice Writing)</option>
|
| 254 |
+
<option value="email_writing">Formal Email Prompt (Professional Practice)</option>
|
| 255 |
+
<option value="summary_writing">Summarization Prompt (Reading & Writing)</option>
|
| 256 |
+
</select>
|
| 257 |
+
</div>
|
| 258 |
+
<!-- Generate Button -->
|
| 259 |
+
<div class="md:col-span-1 flex items-end">
|
| 260 |
+
<button id="generateActivityButton" onclick="generateActivity()" class="btn-primary w-full py-2.5 rounded-lg font-semibold flex items-center justify-center">
|
| 261 |
+
<span id="activityText">Generate Activity</span>
|
| 262 |
+
<div id="activitySpinner" class="spinner ml-3 hidden"></div>
|
| 263 |
+
</button>
|
| 264 |
+
</div>
|
| 265 |
+
</div>
|
| 266 |
+
|
| 267 |
+
<!-- Activity Output -->
|
| 268 |
+
<div id="activityOutput" class="border p-4 mt-4 rounded-lg bg-gray-50 min-h-[100px]">
|
| 269 |
+
<p class="text-gray-500 italic">Select an activity and context to generate your first prompt.</p>
|
| 270 |
+
</div>
|
| 271 |
+
</div>
|
| 272 |
|
| 273 |
+
|
| 274 |
+
<!-- Flashcards Panel -->
|
| 275 |
<div id="flashcardsPanel" class="card">
|
| 276 |
<h2 class="text-xl font-semibold mb-4 text-gray-700">Your Flashcards (Study Session)</h2>
|
| 277 |
<div id="flashcardList" class="space-y-3">
|
|
|
|
| 329 |
const flashcardList = document.getElementById('flashcardList');
|
| 330 |
const noCardsMessage = document.getElementById('noCardsMessage');
|
| 331 |
const speedSelector = document.getElementById('speedSelector');
|
| 332 |
+
const modelSelector = document.getElementById('modelSelector');
|
| 333 |
+
const contextSelector = document.getElementById('contextSelector'); // NEW
|
| 334 |
+
const activityTypeSelector = document.getElementById('activityTypeSelector'); // NEW
|
| 335 |
+
const generateActivityButton = document.getElementById('generateActivityButton'); // NEW
|
| 336 |
+
const activityOutput = document.getElementById('activityOutput'); // NEW
|
| 337 |
+
const activitySpinner = document.getElementById('activitySpinner'); // NEW
|
| 338 |
+
const activityText = document.getElementById('activityText'); // NEW
|
| 339 |
+
const translateFullTextButton = document.getElementById('translateFullTextButton'); // NEW
|
| 340 |
|
| 341 |
const MAX_CHARS = 5000;
|
| 342 |
let isLooping = false;
|
|
|
|
| 375 |
const currentLength = getEditorText().length;
|
| 376 |
charCount.textContent = currentLength;
|
| 377 |
playButton.disabled = currentLength === 0;
|
| 378 |
+
// Enable/disable translate full text button based on content
|
| 379 |
+
translateFullTextButton.disabled = currentLength === 0;
|
| 380 |
});
|
| 381 |
|
| 382 |
// Update character count on load
|
|
|
|
| 401 |
loadingSpinner.classList.remove('hidden');
|
| 402 |
|
| 403 |
try {
|
|
|
|
| 404 |
const response = await fetch('/tts-proxy', {
|
| 405 |
method: 'POST',
|
| 406 |
headers: { 'Content-Type': 'application/json' },
|
|
|
|
| 470 |
}
|
| 471 |
});
|
| 472 |
|
| 473 |
+
// --- Full Text Translation Functionality (NEW) ---
|
| 474 |
+
|
| 475 |
+
async function translateFullText() {
|
| 476 |
+
const fullText = getEditorText();
|
| 477 |
+
if (!fullText) {
|
| 478 |
+
alert("Please enter text to translate.");
|
| 479 |
+
return;
|
| 480 |
+
}
|
| 481 |
+
|
| 482 |
+
translateFullTextButton.disabled = true;
|
| 483 |
+
translateFullTextButton.innerHTML = `<div class="spinner mr-2"></div> Translating...`;
|
| 484 |
+
const modelValue = modelSelector.value;
|
| 485 |
+
const context = contextSelector.value;
|
| 486 |
+
|
| 487 |
+
try {
|
| 488 |
+
// Use a generic prompt for full translation
|
| 489 |
+
const prompt = `Translate the following English text into clear, modern Portuguese, ensuring the translation adheres to the context: ${context}.\n\nENGLISH TEXT:\n---${fullText}---`;
|
| 490 |
+
|
| 491 |
+
const response = await fetch('/explain-proxy', { // Reusing explain-proxy for simple text generation
|
| 492 |
+
method: 'POST',
|
| 493 |
+
headers: { 'Content-Type': 'application/json' },
|
| 494 |
+
body: JSON.stringify({
|
| 495 |
+
word: "FULL_TRANSLATION", // Marker word, not used by backend for full text
|
| 496 |
+
context: fullText, // Full text as context
|
| 497 |
+
for_flashcard: false,
|
| 498 |
+
model: modelValue,
|
| 499 |
+
custom_prompt: prompt // Pass the custom prompt
|
| 500 |
+
})
|
| 501 |
+
});
|
| 502 |
+
|
| 503 |
+
if (!response.ok) {
|
| 504 |
+
throw new Error(`HTTP Error: ${response.status}. Check API Keys.`);
|
| 505 |
+
}
|
| 506 |
+
|
| 507 |
+
const data = await response.json();
|
| 508 |
+
const translation = data.translation;
|
| 509 |
+
|
| 510 |
+
// Open a temporary modal or alert the user with the result
|
| 511 |
+
alert("FULL TEXT TRANSLATION:\n\n" + translation);
|
| 512 |
+
|
| 513 |
+
} catch (error) {
|
| 514 |
+
console.error('Error translating full text:', error);
|
| 515 |
+
alert('Failed to translate full text. Check console and API Keys.');
|
| 516 |
+
} finally {
|
| 517 |
+
translateFullTextButton.disabled = false;
|
| 518 |
+
translateFullTextButton.textContent = "Translate Full Text (PT)";
|
| 519 |
+
}
|
| 520 |
+
}
|
| 521 |
+
|
| 522 |
+
|
| 523 |
+
// --- Activity Generation Functionality (NEW) ---
|
| 524 |
+
|
| 525 |
+
async function generateActivity() {
|
| 526 |
+
const activityType = activityTypeSelector.value;
|
| 527 |
+
const context = contextSelector.value;
|
| 528 |
+
const modelValue = modelSelector.value;
|
| 529 |
+
const sourceText = getEditorText();
|
| 530 |
+
|
| 531 |
+
generateActivityButton.disabled = true;
|
| 532 |
+
activityText.textContent = "Generating...";
|
| 533 |
+
activitySpinner.classList.remove('hidden');
|
| 534 |
+
activityOutput.innerHTML = `<p class="text-gray-500 italic">Generating prompt...</p>`;
|
| 535 |
+
|
| 536 |
+
let prompt = "";
|
| 537 |
+
let title = "";
|
| 538 |
+
|
| 539 |
+
if (activityType === 'translation_pt_en') {
|
| 540 |
+
title = "Translation Exercise (PT to EN)";
|
| 541 |
+
// We ask the AI to generate a Portuguese phrase first, based on the context, and then give the prompt.
|
| 542 |
+
prompt = `You are a language teacher. Generate a single, challenging, but short Portuguese phrase that is perfectly relevant to the '${context}' context. Then, provide the Portuguese phrase to the user and prompt them to translate it to English. Format the output as: [PORTUGUESE PHRASE] \n\n Your Task: Translate the phrase above into English.`;
|
| 543 |
+
} else if (activityType === 'email_writing') {
|
| 544 |
+
title = "Formal Email Writing Prompt";
|
| 545 |
+
prompt = `You are a language teacher. Generate a challenging, realistic scenario for a formal email writing exercise, based strictly on the '${context}' context. The prompt must be in English and clearly state the recipient (e.g., 'Your Manager'), the goal (e.g., 'Requesting a budget'), and the required tone (e.g., 'Formal and concise').`;
|
| 546 |
+
} else if (activityType === 'summary_writing' && sourceText) {
|
| 547 |
+
title = "Summarization Prompt";
|
| 548 |
+
prompt = `You are a language teacher. Summarize the following English text in a single, complex English sentence, and then ask the user to expand your summary back into a paragraph, ensuring they use complex vocabulary related to the '${context}' context. The text to summarize is:\n\n---${sourceText}---`;
|
| 549 |
+
} else {
|
| 550 |
+
activityOutput.innerHTML = `<p class="text-red-500 font-semibold">Please enter text in the editor to use the Summarization Prompt.</p>`;
|
| 551 |
+
generateActivityButton.disabled = false;
|
| 552 |
+
activityText.textContent = "Generate Activity";
|
| 553 |
+
activitySpinner.classList.add('hidden');
|
| 554 |
+
return;
|
| 555 |
+
}
|
| 556 |
+
|
| 557 |
+
try {
|
| 558 |
+
// Reusing explain-proxy for simple text generation
|
| 559 |
+
const response = await fetch('/explain-proxy', {
|
| 560 |
+
method: 'POST',
|
| 561 |
+
headers: { 'Content-Type': 'application/json' },
|
| 562 |
+
body: JSON.stringify({
|
| 563 |
+
word: "ACTIVITY_GEN",
|
| 564 |
+
context: context,
|
| 565 |
+
for_flashcard: false,
|
| 566 |
+
model: modelValue,
|
| 567 |
+
custom_prompt: prompt
|
| 568 |
+
})
|
| 569 |
+
});
|
| 570 |
+
|
| 571 |
+
if (!response.ok) {
|
| 572 |
+
throw new Error(`HTTP Error: ${response.status}. Check API Keys.`);
|
| 573 |
+
}
|
| 574 |
+
|
| 575 |
+
const data = await response.json();
|
| 576 |
+
// The explanation field holds the generated activity text
|
| 577 |
+
const activityResult = data.explanation || data.translation || "Failed to generate activity prompt.";
|
| 578 |
+
|
| 579 |
+
activityOutput.innerHTML = `<h3 class="font-bold mb-2">${title}</h3><div class="whitespace-pre-wrap">${activityResult}</div>`;
|
| 580 |
+
|
| 581 |
+
|
| 582 |
+
} catch (error) {
|
| 583 |
+
console.error('Error generating activity:', error);
|
| 584 |
+
activityOutput.innerHTML = `<p class="text-red-500 font-semibold">Activity generation failed. Check if API Keys are configured correctly for ${modelValue}.</p>`;
|
| 585 |
+
} finally {
|
| 586 |
+
generateActivityButton.disabled = false;
|
| 587 |
+
activityText.textContent = "Generate Activity";
|
| 588 |
+
activitySpinner.classList.add('hidden');
|
| 589 |
+
}
|
| 590 |
+
}
|
| 591 |
+
|
| 592 |
+
|
| 593 |
// --- Quick Translation Functionality (Double Click) ---
|
| 594 |
|
| 595 |
async function fetchExplanationAndTranslation(word, context, isFlashcard=false) {
|
|
|
|
| 598 |
const translationText = isFlashcard ? null : document.getElementById('translationText');
|
| 599 |
|
| 600 |
const modelValue = modelSelector.value;
|
| 601 |
+
const contextFocus = contextSelector.value; // Pass context focus
|
| 602 |
|
| 603 |
if (!isFlashcard) {
|
|
|
|
| 604 |
explanationText.textContent = '';
|
| 605 |
translationText.textContent = '';
|
| 606 |
}
|
| 607 |
spinner.classList.remove('hidden');
|
| 608 |
|
| 609 |
try {
|
|
|
|
| 610 |
const response = await fetch('/explain-proxy', {
|
| 611 |
method: 'POST',
|
| 612 |
headers: { 'Content-Type': 'application/json' },
|
|
|
|
| 613 |
body: JSON.stringify({
|
| 614 |
word: word,
|
| 615 |
context: context,
|
| 616 |
for_flashcard: isFlashcard,
|
| 617 |
+
model: modelValue,
|
| 618 |
+
context_focus: contextFocus // NEW: Pass context focus for accurate flashcards
|
| 619 |
})
|
| 620 |
});
|
| 621 |
|
|
|
|
| 627 |
const data = await response.json();
|
| 628 |
|
| 629 |
if (isFlashcard) {
|
| 630 |
+
return data;
|
| 631 |
} else {
|
| 632 |
explanationText.textContent = data.explanation || 'Could not retrieve explanation.';
|
| 633 |
translationText.textContent = data.translation || 'Could not retrieve translation.';
|
|
|
|
| 651 |
|
| 652 |
// Logic to open the Modal on double click
|
| 653 |
textEditor.addEventListener('dblclick', (event) => {
|
| 654 |
+
const selection = window.getSelection().toString().trim();
|
| 655 |
+
const selectedWord = selection.replace(/[^a-zA-Z']/g, ''); // Basic word selection logic
|
| 656 |
|
| 657 |
if (selectedWord) {
|
| 658 |
const fullText = getEditorText();
|
| 659 |
+
const index = fullText.indexOf(selection);
|
| 660 |
+
const context = fullText.substring(Math.max(0, index - 50), index + selection.length + 50);
|
| 661 |
|
| 662 |
document.getElementById('wordSelected').textContent = selectedWord;
|
| 663 |
openModal();
|
| 664 |
|
|
|
|
| 665 |
fetchExplanationAndTranslation(selectedWord, context);
|
| 666 |
}
|
| 667 |
});
|
|
|
|
| 682 |
createCardButton.innerHTML = `<div class="spinner mr-2"></div> Creating Card...`;
|
| 683 |
|
| 684 |
try {
|
|
|
|
| 685 |
const cardData = await fetchExplanationAndTranslation(selectedText, context, true);
|
| 686 |
|
| 687 |
if (cardData && cardData.term && cardData.translation && cardData.example) {
|
|
|
|
| 702 |
const cardElement = document.createElement('div');
|
| 703 |
cardElement.className = 'flashcard';
|
| 704 |
|
| 705 |
+
// Render card content
|
| 706 |
cardElement.innerHTML = `
|
| 707 |
<div class="flashcard-front">
|
| 708 |
<p class="flashcard-term">${data.term.toUpperCase()}</p>
|
| 709 |
<p class="flashcard-definition">PT: ${data.translation}</p>
|
| 710 |
<p class="flashcard-example">Example: ${data.example}</p>
|
| 711 |
</div>
|
|
|
|
| 712 |
`;
|
| 713 |
|
| 714 |
+
flashcardList.prepend(cardElement);
|
| 715 |
}
|
| 716 |
|
| 717 |
|