feat: update image capability inside quiz

This commit is contained in:
a2nr 2026-05-10 20:38:35 +07:00
parent 60469925ea
commit 438d96ef13
3 changed files with 35 additions and 5 deletions

View File

@ -473,7 +473,10 @@ Untuk memudahkan pengajar, Elemes menyediakan parser Markdown khusus di `lesson_
- Jika ditemukan pola `- []` atau `- [x]`, elemen diparse sebagai `type: 'mcq'`.
- Jika tidak, diparse sebagai `type: 'flashcard'`.
4. **Explanation**: Menangkap blok kutipan `>` sebagai penjelasan yang muncul setelah kuis dijawab.
5. **Rendering**: Pertanyaan dan jawaban di-render menggunakan filter Markdown standar (mendukung formatting, code snippets, dll).
5. **Images**: Mendukung penambahan gambar melalui:
- Keyword `image: URL` tepat di bawah heading pertanyaan (akan tampil sebagai gambar utama).
- Syntax Markdown standar `![alt](url)` di dalam teks pertanyaan, opsi, atau penjelasan.
6. **Rendering**: Pertanyaan dan jawaban di-render menggunakan filter Markdown standar (mendukung formatting, code snippets, dll).
### Quiz State Management

View File

@ -11,6 +11,7 @@
question?: string;
options?: Option[];
explanation?: string;
image?: string;
}
interface Props {
@ -203,6 +204,9 @@
<div class="question-box">
<div class="side-label">Pertanyaan</div>
<div class="card-content">
{#if currentCard.image}
<img src={currentCard.image} alt="Pertanyaan" class="quiz-image" />
{/if}
{@html currentCard.question}
</div>
</div>
@ -245,7 +249,12 @@
<div class="flashcard" class:flipped={isFlipped}>
<div class="flashcard-front">
<div class="side-label">Pertanyaan</div>
<div class="card-content">{@html currentCard.front}</div>
<div class="card-content">
{#if currentCard.image}
<img src={currentCard.image} alt="Pertanyaan" class="quiz-image" />
{/if}
{@html currentCard.front}
</div>
<div class="flip-hint">Klik untuk melihat jawaban</div>
</div>
<div class="flashcard-back">
@ -349,7 +358,17 @@
.flashcard-back { transform: rotateY(180deg); background: var(--color-bg); }
.side-label { font-size: 0.7rem; text-transform: uppercase; letter-spacing: 0.05em; color: var(--color-text-muted); margin-bottom: 1rem; font-weight: 700; border-bottom: 1px solid var(--color-border); padding-bottom: 0.5rem; }
.card-content { flex: 1; display: flex; flex-direction: column; justify-content: center; align-items: center; text-align: center; font-size: 1.25rem; color: var(--color-text); line-height: 1.5; }
:global(.card-content code) { background: var(--color-bg); border: 1px solid var(--color-border); padding: 0.2rem 0.4rem; border-radius: 4px; font-family: var(--font-mono); }
.quiz-image {
max-width: 100%;
max-height: 300px;
object-fit: contain;
border-radius: 8px;
margin-bottom: 1rem;
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
}
:global(.card-content img) { max-width: 100%; height: auto; border-radius: 8px; margin: 1rem 0; }
:global(.option-text img) { max-width: 100%; height: auto; border-radius: 4px; display: block; margin: 0.5rem 0; }
:global(.card-content p) { margin: 0; }
.flip-hint { font-size: 0.75rem; color: var(--color-text-muted); margin-top: 1rem; font-style: italic; }

View File

@ -343,6 +343,12 @@ def _parse_flashcards(text):
option_pattern = re.compile(r'^\s*-\s*\[([ xX]?)\]\s*(.*)$', re.MULTILINE)
options = option_pattern.findall(body)
# Check for image: URL
image_match = re.search(r'^\s*image:\s*(.*)$', body, re.MULTILINE)
image_url = image_match.group(1).strip() if image_match else ""
if image_match:
body = re.sub(r'^\s*image:\s*.*$', '', body, flags=re.MULTILINE).strip()
# Check for explanation (blockquote starting with >)
explanation_match = re.search(r'^\s*>\s*(.*)$', body, re.MULTILINE | re.DOTALL)
explanation = explanation_match.group(1).strip() if explanation_match else ""
@ -361,7 +367,8 @@ def _parse_flashcards(text):
'type': 'mcq',
'question': md.markdown(question, extensions=MD_EXTENSIONS),
'options': parsed_options,
'explanation': md.markdown(explanation, extensions=MD_EXTENSIONS) if explanation else ""
'explanation': md.markdown(explanation, extensions=MD_EXTENSIONS) if explanation else "",
'image': image_url
})
else:
# It's a simple Flashcard
@ -374,7 +381,8 @@ def _parse_flashcards(text):
'type': 'flashcard',
'front': md.markdown(question, extensions=MD_EXTENSIONS),
'back': md.markdown(clean_back, extensions=MD_EXTENSIONS),
'explanation': md.markdown(explanation, extensions=MD_EXTENSIONS) if explanation else ""
'explanation': md.markdown(explanation, extensions=MD_EXTENSIONS) if explanation else "",
'image': image_url
})
return flashcards