179 lines
4.0 KiB
Vue
179 lines
4.0 KiB
Vue
<template>
|
|
<div>
|
|
<nav v-if="v">
|
|
<div :class="$style.mark">
|
|
<button type="button" name="right" @click="mark(true)">✓</button>
|
|
<button
|
|
type="button"
|
|
name="wrong"
|
|
@click="mark(false)"
|
|
style="font-size: large"
|
|
>
|
|
↻
|
|
</button>
|
|
</div>
|
|
|
|
<div>
|
|
<span v-if="v.audio">
|
|
{{ v.ko }}
|
|
<AudioButton :src="v.audio" />
|
|
</span>
|
|
<TTS v-else>
|
|
{{ v.ko }}
|
|
</TTS>
|
|
<span>{{ " = " }}</span>
|
|
<span class="spoiler"> {{ v.en }} </span>
|
|
</div>
|
|
|
|
<details v-if="example" ref="sdetails">
|
|
<summary>
|
|
<span v-if="example.audio">
|
|
{{ example.ko }}
|
|
<AudioButton :src="example.audio" />
|
|
</span>
|
|
<TTS v-else ref="stts">
|
|
{{ example.ko }}
|
|
</TTS>
|
|
</summary>
|
|
<span>{{ example.en }}</span>
|
|
</details>
|
|
</nav>
|
|
<details>
|
|
<summary>Quiz options</summary>
|
|
<nav>
|
|
<span v-for="c in vCats" :key="c">
|
|
<input type="checkbox" :name="c" checked @change="updateCats(c)" />
|
|
<label :for="c"> {{ c }} </label>
|
|
</span>
|
|
</nav>
|
|
<nav>
|
|
<input
|
|
type="checkbox"
|
|
name="autoplay-audio"
|
|
v-model="vSentAutoplayAudio"
|
|
/>
|
|
<label for="autoplay-audio">autoplay sentence audio</label>
|
|
</nav>
|
|
</details>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import { useData } from "vitepress";
|
|
import { computed, nextTick, ref, useTemplateRef } from "vue";
|
|
import TTS from "./TTS.vue";
|
|
|
|
const vCats = ref<string[]>([]);
|
|
const vChosenCats = ref<string[]>([]);
|
|
const vList = ref<IVoc[]>([]);
|
|
const vIndex = ref(-1);
|
|
const vSentAutoplayAudio = ref(true);
|
|
|
|
const sentenceDetails = useTemplateRef("sdetails");
|
|
const stts = useTemplateRef<InstanceType<typeof TTS>>("stts");
|
|
|
|
const v = computed(() => vList.value[vIndex.value]);
|
|
const example = computed(() => {
|
|
if (!v.value.examples?.length) return null;
|
|
const ex = v.value.examples;
|
|
return ex[Math.floor(Math.random() * ex.length)];
|
|
});
|
|
|
|
const MAX_VOC = 5;
|
|
|
|
interface IVoc {
|
|
ko: string;
|
|
audio?: string;
|
|
en: string;
|
|
usages?: IVoc[];
|
|
notes?: string;
|
|
examples?: IVoc[];
|
|
}
|
|
|
|
const { frontmatter } = useData();
|
|
const { vocabulary } = frontmatter.value as {
|
|
vocabulary: Record<string, IVoc[]>;
|
|
};
|
|
|
|
vCats.value = Object.keys(vocabulary);
|
|
vChosenCats.value = [...vCats.value];
|
|
makeVList();
|
|
|
|
function makeVList() {
|
|
nextTick(() => {
|
|
if (sentenceDetails.value) {
|
|
sentenceDetails.value.open = false;
|
|
}
|
|
});
|
|
|
|
vList.value = Object.entries(vocabulary)
|
|
.filter(([k]) => vChosenCats.value.includes(k))
|
|
.flatMap(([, v]) => v);
|
|
vList.value = vList.value
|
|
.map((s) => ({ s, k: Math.random() }))
|
|
.sort((a, b) => a.k - b.k)
|
|
.map((a) => a.s);
|
|
|
|
vIndex.value = Math.floor(
|
|
Math.random() * Math.min(MAX_VOC, vList.value.length),
|
|
);
|
|
}
|
|
|
|
function mark(isRight: boolean) {
|
|
nextTick(() => {
|
|
if (sentenceDetails.value) {
|
|
sentenceDetails.value.open = false;
|
|
}
|
|
|
|
if (vSentAutoplayAudio.value) {
|
|
if (stts.value) {
|
|
stts.value.playAudio();
|
|
} else if (example.value?.audio) {
|
|
new Audio(example.value.audio).play();
|
|
}
|
|
}
|
|
});
|
|
|
|
if (isRight) {
|
|
vList.value = [...vList.value.filter((_, i) => i !== vIndex.value)];
|
|
vIndex.value = -1;
|
|
|
|
if (vList.value.length === 0) {
|
|
makeVList();
|
|
return;
|
|
}
|
|
}
|
|
|
|
const i = Math.floor(
|
|
Math.random() * (Math.min(MAX_VOC, vList.value.length) - 1),
|
|
);
|
|
|
|
if (i >= vIndex.value) {
|
|
vIndex.value = i + 1;
|
|
} else {
|
|
vIndex.value = i;
|
|
}
|
|
}
|
|
|
|
function updateCats(cat: string) {
|
|
const i = vChosenCats.value.indexOf(cat);
|
|
if (i === -1) {
|
|
vChosenCats.value = [...vChosenCats.value, cat];
|
|
} else {
|
|
vChosenCats.value = [...vChosenCats.value.filter((_, j) => j !== i)];
|
|
}
|
|
|
|
makeVList();
|
|
}
|
|
</script>
|
|
|
|
<style module>
|
|
.mark {
|
|
float: right;
|
|
|
|
> * + * {
|
|
margin-inline-start: 1em;
|
|
}
|
|
}
|
|
</style>
|