Files
creator/frontend/src/components/FlashcardWidget.vue
2026-06-27 00:58:46 +02:00

107 lines
3.8 KiB
Vue

<script setup>
import { ref, computed, watch } from 'vue'
import { renderMarkdownInline } from '../markdown.js'
const props = defineProps({ karten: { type: Array, default: () => [] } })
const offen = ref(false)
const reihenfolge = ref([])
const pos = ref(0)
const flipped = ref(false)
function reset() {
reihenfolge.value = props.karten.map((_, i) => i)
pos.value = 0
flipped.value = false
}
watch(() => props.karten, reset, { immediate: true })
const aktuelle = computed(() => props.karten[reihenfolge.value[pos.value]] || null)
const zaehler = computed(() => `${Math.min(pos.value + 1, reihenfolge.value.length)} / ${reihenfolge.value.length}`)
function weiter(gewusst) {
if (gewusst) {
pos.value++
} else {
// „Nochmal" → Karte ans Ende der Runde schieben (leichtes Spacing).
const [k] = reihenfolge.value.splice(pos.value, 1)
reihenfolge.value.push(k)
}
if (pos.value >= reihenfolge.value.length) pos.value = 0
flipped.value = false
}
</script>
<template>
<div v-if="karten.length" class="flashcards">
<button class="art-head" @click="offen = !offen">
<span class="art-icon">🃏</span> Karteikarten
<span class="art-count">{{ karten.length }}</span>
<span class="art-toggle">{{ offen ? '▾' : '▸' }}</span>
</button>
<div v-if="offen && aktuelle" class="fc-body">
<div class="fc-card" :class="{ flipped }" @click="flipped = !flipped">
<div class="fc-zaehler">{{ zaehler }}</div>
<div v-if="!flipped" class="fc-seite">
<span class="fc-label">Frage</span>
<div class="fc-text" v-html="renderMarkdownInline(aktuelle.frage)"></div>
<span class="fc-hint">Klick zum Umdrehen</span>
</div>
<div v-else class="fc-seite">
<span class="fc-label">Antwort</span>
<div class="fc-text" v-html="renderMarkdownInline(aktuelle.antwort)"></div>
</div>
</div>
<div v-if="flipped" class="fc-aktionen">
<button class="fc-btn nochmal" @click="weiter(false)">Nochmal</button>
<button class="fc-btn gewusst" @click="weiter(true)">Gewusst</button>
</div>
</div>
</div>
</template>
<style scoped>
.flashcards { margin-top: 0.75rem; }
.art-head {
display: flex; align-items: center; gap: 8px; width: 100%;
background: none; border: none; cursor: pointer; padding: 0.35rem 0;
font-size: 0.82rem; font-weight: 600; color: var(--text-muted);
}
.art-icon { font-size: 0.95rem; }
.art-count {
background: var(--panel-soft); border: 1px solid var(--border);
border-radius: 999px; padding: 0 0.45rem; font-size: 0.72rem;
}
.art-toggle { margin-left: auto; color: var(--text-faint); }
.fc-body { margin-top: 0.5rem; }
.fc-card {
position: relative; min-height: 120px; cursor: pointer;
border: 1px solid var(--border); border-radius: 10px;
padding: 1rem 1.1rem; background: var(--panel-soft);
display: flex; align-items: center; justify-content: center; text-align: center;
transition: border-color 0.15s;
}
.fc-card.flipped { border-color: var(--accent); }
.fc-zaehler {
position: absolute; top: 6px; right: 10px;
font-size: 0.68rem; color: var(--text-faint);
}
.fc-seite { display: flex; flex-direction: column; gap: 0.4rem; align-items: center; }
.fc-label {
font-size: 0.66rem; text-transform: uppercase; letter-spacing: 0.05em;
color: var(--text-faint); font-weight: 700;
}
.fc-text { font-size: 0.98rem; line-height: 1.45; }
.fc-hint { font-size: 0.7rem; color: var(--text-faint); margin-top: 0.2rem; }
.fc-aktionen { display: flex; gap: 8px; margin-top: 0.5rem; }
.fc-btn {
flex: 1; padding: 0.5rem; border-radius: 8px; cursor: pointer;
font-size: 0.82rem; font-weight: 600; border: 1px solid var(--border-strong);
background: var(--panel);
}
.fc-btn.gewusst { background: var(--success-soft); border-color: var(--success-border); color: var(--success); }
.fc-btn.nochmal { color: var(--text-muted); }
</style>