lesson 13 grammar sentence quiz + adapt component

This commit is contained in:
polv committed 2026-07-18 23:29:19 +07:00
1 parent e6a8a6027c
commit 045f62d951
2 files changed
+146 -18

No files matched your search

+38 -18
View File
@@ -9,7 +9,11 @@
<button type="button" @click="onVContentSave()">Save</button>
<button type="button" @click="isEdit = false">×</button>
</nav>
<textarea v-model="vEditContent" spellcheck="false"></textarea>
<textarea
v-model="vEditContent"
spellcheck="false"
ref="textarea"
></textarea>
</div>
</Teleport>
@@ -31,7 +35,9 @@
<SentenceAudio :v="v" lang="ko" ref="vaud" />
</span>
<span>{{ " = " }}</span>
<span :class="isKoFirst ? 'spoiler' : ''"> {{ v.en }} </span>
<span :class="isKoFirst ? 'spoiler' : ''">
<SentenceAudio :v="v" lang="en" />
</span>
</div>
<details v-if="example || v.notes" ref="sdetails">
@@ -53,8 +59,8 @@
</details>
</nav>
<details :class="$style.options">
<summary>Quiz options</summary>
<nav>
<summary>🧐 Quiz options</summary>
<nav v-if="vCats.length > 1">
<label v-for="c in vCats" :key="c">
<input type="checkbox" :name="c" checked @change="updateCats(c)" />
{{ c.replace(/_/g, " ") }}
@@ -104,8 +110,9 @@ import SentenceAudio from "./SentenceAudio.vue";
import { supabase } from "../supabase.ts";
import { IVoc, Voc } from "../types.ts";
const { fmKey = "vocabulary" } = defineProps<{
const { fmKey = "vocabulary", category } = defineProps<{
fmKey?: string;
category?: string;
}>();
const vCats = ref<string[]>([]);
@@ -122,6 +129,8 @@ const isAutoplayAudio = ref(true);
const isKoFirst = ref(true);
const modalRef = useTemplateRef("modal");
const textareaRef = useTemplateRef("textarea");
const sentenceDetails = useTemplateRef("sdetails");
const saud = useTemplateRef<InstanceType<typeof SentenceAudio>>("saud");
const vaud = useTemplateRef<InstanceType<typeof SentenceAudio>>("vaud");
@@ -139,15 +148,21 @@ const { frontmatter, page } = useData();
const vocabulary: Record<string, IVoc[]> = {};
for (const fk of fmKey.split(/[, ]+/g)) {
for (const [k, vs] of Object.entries(
frontmatter.value[fk] as Record<string, IVoc[]>,
)) {
vocabulary[k] = [...(vocabulary[k] || []), ...vs];
for (const [k, vs] of Object.entries(
frontmatter.value[fmKey] as Record<string, IVoc[]>,
)) {
vocabulary[k] = [...(vocabulary[k] || []), ...vs];
if (!vCats.value.includes(k)) {
vCats.value = [...vCats.value, k];
}
if (!vCats.value.includes(k)) {
vCats.value = [...vCats.value, k];
}
}
if (category) {
const vCatsSet = new Set(category.split(/[, ]+/g));
const newVCats = vCats.value.filter((c) => vCatsSet.has(c));
if (newVCats.length) {
vCats.value = newVCats;
}
}
@@ -161,6 +176,12 @@ watch(isEdit, () => {
if (isEdit.value) {
const { ko, ...vContent } = v.value;
vEditContent.value = yaml.stringify(vContent);
nextTick(() => {
if (textareaRef.value) {
textareaRef.value.style.height = textareaRef.value.scrollHeight + "px";
}
});
} else {
vEditContent.value = "";
}
@@ -265,7 +286,6 @@ async function onVContentSave() {
vCount.set(v.ko, i + 1);
if (oldV.ko === v.ko && oldV.en === v.en) {
// TODO: handling multiple fmKey comma-separated
key = JSON.stringify([fmKey, k]);
vKey = vK;
@@ -439,10 +459,10 @@ onBeforeUnmount(() => {
.modal {
--margin-top: calc(120px + env(safe-area-inset-top));
position: absolute;
top: var(--margin-top);
position: fixed;
top: 50%;
left: 50%;
transform: translateX(-50%);
transform: translate(-50%, -50%);
width: calc(100vw - 4em);
max-width: 1000px;
@@ -460,7 +480,7 @@ onBeforeUnmount(() => {
textarea {
width: 100%;
height: calc(90vh - var(--margin-top) - env(safe-area-inset-bottom));
max-height: calc(90vh - var(--margin-top) - env(safe-area-inset-bottom));
padding: 1em;
border-radius: 0 0 0.5em 0.5em;
font-family: sans-serif;