generated from alphane/template
flashcards in the frontend!!!
This commit is contained in:
@@ -0,0 +1,88 @@
|
||||
<template>
|
||||
<v-row class="fill-height">
|
||||
<v-col
|
||||
cols="12"
|
||||
md="3"
|
||||
>
|
||||
<v-card
|
||||
height="100%"
|
||||
class="pa-2"
|
||||
>
|
||||
<FlashcardDeckTree
|
||||
ref="deckTree"
|
||||
@select="onDeckSelected"
|
||||
/>
|
||||
</v-card>
|
||||
</v-col>
|
||||
|
||||
<v-col
|
||||
cols="12"
|
||||
md="9"
|
||||
>
|
||||
<template v-if="selectedDeck">
|
||||
<div class="d-flex align-center justify-space-between mb-4">
|
||||
<v-spacer />
|
||||
<v-btn
|
||||
color="primary"
|
||||
variant="tonal"
|
||||
prepend-icon="mdi-plus"
|
||||
text="Add Flashcard"
|
||||
@click="openFlashcardCreateDialog"
|
||||
/>
|
||||
<FlashcardDeckStartReviewBtn :flashcard-deck-id="selectedDeck.id" />
|
||||
</div>
|
||||
|
||||
<v-divider class="my-5" />
|
||||
|
||||
<v-card :border="true">
|
||||
<FlashcardsDataTableServer
|
||||
ref="flashcardsTable"
|
||||
:where="{ flashcardDeckId: selectedDeck.id }"
|
||||
/>
|
||||
</v-card>
|
||||
|
||||
<FlashcardCreateDialog
|
||||
v-if="selectedDeck"
|
||||
ref="flashcardCreateDialog"
|
||||
:flashcard-deck-id="selectedDeck.id"
|
||||
@created="flashcardsTable?.refresh()"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<div
|
||||
v-else
|
||||
class="d-flex align-center justify-center h-100 text-medium-emphasis"
|
||||
>
|
||||
Select a deck to view its flashcards
|
||||
</div>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref } from "vue"
|
||||
|
||||
import useBreadcrumbs from "@/use/use-breadcrumbs"
|
||||
|
||||
import FlashcardDeckTree, {
|
||||
type DeckNode,
|
||||
} from "@/components/flashcard-decks/FlashcardDeckTree.vue"
|
||||
import FlashcardsDataTableServer from "@/components/flashcards/FlashcardsDataTableServer.vue"
|
||||
import FlashcardCreateDialog from "@/components/flashcards/FlashcardCreateDialog.vue"
|
||||
import FlashcardDeckStartReviewBtn from "@/components/flashcard-decks/FlashcardDeckStartReviewBtn.vue"
|
||||
|
||||
const deckTree = ref<InstanceType<typeof FlashcardDeckTree> | null>(null)
|
||||
const selectedDeck = ref<DeckNode | null>(null)
|
||||
const flashcardsTable = ref<InstanceType<typeof FlashcardsDataTableServer> | null>(null)
|
||||
const flashcardCreateDialog = ref<InstanceType<typeof FlashcardCreateDialog> | null>(null)
|
||||
|
||||
function onDeckSelected(deck: DeckNode) {
|
||||
selectedDeck.value = deck
|
||||
}
|
||||
|
||||
function openFlashcardCreateDialog() {
|
||||
flashcardCreateDialog.value?.show()
|
||||
}
|
||||
|
||||
useBreadcrumbs("Study")
|
||||
</script>
|
||||
@@ -0,0 +1,118 @@
|
||||
<template>
|
||||
<div>
|
||||
<div class="d-flex">
|
||||
<v-spacer />
|
||||
<v-btn
|
||||
class="mt-2"
|
||||
variant="tonal"
|
||||
prepend-icon="mdi-shuffle"
|
||||
text="Shuffle"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<v-skeleton-loader
|
||||
v-if="isLoading"
|
||||
type="card"
|
||||
/>
|
||||
<div v-else-if="isEmpty(flashcards)"></div>
|
||||
<div
|
||||
v-else
|
||||
class="review-layout"
|
||||
>
|
||||
<FlashcardReviewCard
|
||||
:key="currentIndex"
|
||||
class="mt-5"
|
||||
:flashcard="flashcards[currentIndex]"
|
||||
/>
|
||||
<div class="review-nav">
|
||||
<v-btn
|
||||
icon="mdi-chevron-left"
|
||||
variant="text"
|
||||
size="x-large"
|
||||
:disabled="currentIndex === 0"
|
||||
@click="prev"
|
||||
/>
|
||||
<v-btn
|
||||
class="mr-3"
|
||||
color="error"
|
||||
variant="tonal"
|
||||
prepend-icon="mdi-close"
|
||||
>
|
||||
0
|
||||
</v-btn>
|
||||
<v-btn
|
||||
class="ml-3"
|
||||
color="success"
|
||||
variant="tonal"
|
||||
append-icon="mdi-check"
|
||||
>
|
||||
0
|
||||
</v-btn>
|
||||
<v-btn
|
||||
icon="mdi-chevron-right"
|
||||
variant="text"
|
||||
size="x-large"
|
||||
:disabled="currentIndex === flashcards.length - 1"
|
||||
@click="next"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { isEmpty, isNil } from "lodash"
|
||||
import { computed, ref } from "vue"
|
||||
|
||||
import useFlashcardDeck from "@/use/use-flashcard-deck"
|
||||
import useFlashcards, { FlashcardQueryOptions } from "@/use/use-flashcards"
|
||||
|
||||
import FlashcardReviewCard from "@/components/flashcards/FlashcardReviewCard.vue"
|
||||
|
||||
const props = defineProps<{ flashcardDeckId: string }>()
|
||||
|
||||
const flashcardDeckIdAsNumber = computed(() => parseInt(props.flashcardDeckId))
|
||||
|
||||
const { flashcardDeck } = useFlashcardDeck(flashcardDeckIdAsNumber)
|
||||
|
||||
const flashcardsQueryOptions = computed<FlashcardQueryOptions>(() => {
|
||||
return {
|
||||
where: {
|
||||
flashcardDeckId: flashcardDeck.value?.id,
|
||||
},
|
||||
}
|
||||
})
|
||||
|
||||
const { flashcards, isLoading } = useFlashcards(flashcardsQueryOptions, {
|
||||
skipWatchIf: () => isNil(flashcardDeck.value),
|
||||
})
|
||||
|
||||
const currentIndex = ref(0)
|
||||
|
||||
function next() {
|
||||
if (currentIndex.value < flashcards.value.length - 1) {
|
||||
currentIndex.value++
|
||||
}
|
||||
}
|
||||
|
||||
function prev() {
|
||||
if (currentIndex.value > 0) {
|
||||
currentIndex.value--
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.review-layout {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.review-nav {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user