feat: update image capability inside quiz
This commit is contained in:
parent
60469925ea
commit
438d96ef13
|
|
@ -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 `` 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
|
||||
|
||||
|
|
|
|||
|
|
@ -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; }
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Reference in New Issue