Skip to content

Commit

Permalink
refactor: course contents
Browse files Browse the repository at this point in the history
  • Loading branch information
cuixiaorui committed Aug 15, 2024
1 parent c5eb4b1 commit 4b6fa0f
Show file tree
Hide file tree
Showing 6 changed files with 179 additions and 152 deletions.
106 changes: 0 additions & 106 deletions apps/client/components/main/Contents/Contents.vue

This file was deleted.

41 changes: 0 additions & 41 deletions apps/client/components/main/Contents/useContents.ts

This file was deleted.

147 changes: 147 additions & 0 deletions apps/client/components/main/CourseContents.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
<template>
<UModal v-model="contentsVisible">
<UContainer
:ui="{
base: 'w-[90vw] h-[80vh] flex flex-col',
constrained: 'max-w-[880px] max-h-[880px]',
}"
>
<div class="mb-4">
<h1 class="text-center text-2xl font-bold text-purple-800 dark:text-white">课程目录</h1>
<div class="absolute right-2 top-2">
<UButton
color="gray"
variant="ghost"
icon="i-heroicons-x-mark-20-solid"
@click="hideCourseContents"
tabindex="-1"
:ui="{ color: { gray: { ghost: 'dark:hover:bg-gray-600' } } }"
/>
</div>
</div>
<!-- 添加选项菜单 -->
<div class="mb-4 flex justify-end">
<USelect
v-model="filterOption"
:options="options"
>
</USelect>
</div>
<div class="h-full space-y-3 overflow-y-auto">
<div
v-for="(item, index) in filteredContentsList"
:key="item.id"
ref="itemRefs"
class="flex items-center justify-between rounded-lg bg-purple-100 p-4 transition-colors duration-300 hover:bg-purple-200 dark:bg-purple-700 dark:hover:bg-purple-600"
@click="jumpTo(index, item)"
:class="{ 'cursor-pointer': !item.isMastered, 'cursor-not-allowed': item.isMastered }"
>
<div class="group flex w-full flex-grow">
<div class="mr-4 flex w-6 flex-shrink-0 flex-col items-center justify-center">
<span class="text-lg font-semibold text-purple-600 dark:text-purple-300">
{{ index + 1 }}
</span>
<UIcon
v-if="item.isMastered"
name="i-icon-park-outline:correct"
class="mt-1 h-5 w-5 text-green-700 dark:text-green-500"
></UIcon>
</div>
<div class="flex-grow overflow-hidden">
<div
class="truncate text-lg font-bold text-purple-800 group-hover:text-clip group-hover:whitespace-normal dark:text-white"
>
{{ item.english }}
</div>
<div
class="truncate text-lg text-purple-600 group-hover:text-clip group-hover:whitespace-normal dark:text-purple-300"
>
{{ item.chinese }}
</div>
<div
class="truncate text-lg text-gray-500 group-hover:text-clip group-hover:whitespace-normal dark:text-gray-400"
>
{{ item.soundmark }}
</div>
</div>
<div
@click=""
class="flex w-11 flex-shrink-0 cursor-pointer items-center justify-center transition-transform duration-300 hover:scale-110"
>
<UTooltip text="播放发音">
<UIcon
name="i-ph-speaker-simple-high"
class="ml-1 inline-block h-7 w-7 cursor-pointer"
@click="handlePlayEnglishSound($event, item.english)"
></UIcon>
</UTooltip>
</div>
</div>
</div>
</div>
</UContainer>
</UModal>
</template>

<script setup lang="ts">
import { computed, nextTick, ref, watch } from "vue";
import { playEnglish } from "~/composables/main/englishSound";
import { useGameMode } from "~/composables/main/game";
import { useCourseContents } from "~/composables/main/useCourseContents";
import { useCourseStore } from "~/store/course";
const { contentsVisible, hideCourseContents } = useCourseContents();
const itemRefs = ref<(HTMLElement | null)[]>([]);
const coursesStore = useCourseStore();
const { showQuestion } = useGameMode();
const contentsList = computed(() => {
return coursesStore.currentCourse?.statements || [];
});
const filterOption = ref("all"); // 新增过滤选项
const options = [
{ label: "全部", value: "all" },
{ label: "已经掌握", value: "mastered" },
{ label: "未掌握", value: "notMastered" },
];
const filteredContentsList = computed(() => {
if (filterOption.value === "mastered") {
return contentsList.value.filter((item) => item.isMastered);
} else if (filterOption.value === "notMastered") {
return contentsList.value.filter((item) => !item.isMastered);
}
return contentsList.value; // 默认显示全部
});
function jumpTo(index: number, item: any) {
if (item.isMastered) {
return;
}
showQuestion();
hideCourseContents();
coursesStore.toSpecificStatement(index);
}
function handlePlayEnglishSound(event: Event, english: string) {
event.stopPropagation();
playEnglish(english);
}
watch(
() => contentsVisible.value,
(newValue) => {
if (newValue) {
nextTick(() => {
const targetElement = itemRefs.value[coursesStore.statementIndex];
if (targetElement) {
targetElement.scrollIntoView({ behavior: "smooth", block: "start" });
}
});
}
},
);
</script>

<style scoped></style>
12 changes: 7 additions & 5 deletions apps/client/components/main/Tool.vue
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
</NuxtLink>
<div
class="clickable-item ml-4"
@click="toggleContents"
@click="openCourseContents"
>
<UTooltip text="课程题目列表">
{{ currentCourseInfo }}
Expand Down Expand Up @@ -58,7 +58,7 @@
</div>
</div>

<MainContents />
<MainCourseContents v-model:isOpen="isOpenCourseContents"></MainCourseContents>
</div>

<CommonProgressBar
Expand All @@ -70,25 +70,25 @@

<script setup lang="ts">
import { useModal } from "#imports";
import { computed } from "vue";
import { computed, ref } from "vue";
import Dialog from "~/components/common/Dialog.vue";
import { useQuestionInput } from "~/components/main/QuestionInput/questionInputHelper";
import { courseTimer } from "~/composables/courses/courseTimer";
import { useGameMode } from "~/composables/main/game";
import { clearQuestionInput } from "~/composables/main/question";
import { useCourseContents } from "~/composables/main/useCourseContents";
import { useGamePause } from "~/composables/main/useGamePause";
import { useRanking } from "~/composables/rank/rankingList";
import { parseShortcut, useShortcutKeyMode } from "~/composables/user/shortcutKey";
import { isAuthenticated } from "~/services/auth";
import { useCourseStore } from "~/store/course";
import { useContent } from "./Contents/useContents";
const { shortcutKeys } = useShortcutKeyMode();
const rankingStore = useRanking();
const courseStore = useCourseStore();
const { focusInput } = useQuestionInput();
const { toggleContents } = useContent();
const { openCourseContents } = useCourseContents();
const { handleDoAgain } = useDoAgain();
const { pauseGame } = useGamePause();
const modal = useModal();
Expand All @@ -110,6 +110,8 @@ const currentPercentage = computed(() => {
);
});
const isOpenCourseContents = ref(false);
function useDoAgain() {
const { showQuestion } = useGameMode();
Expand Down
6 changes: 6 additions & 0 deletions apps/client/composables/main/englishSound/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,9 @@ export function readOneSentencePerDayAloud(str: string) {
updateSource(pronunciationUrl);
play();
}

export function playEnglish(english: string) {
const pronunciationUrl = getPronunciationUrl(english);
updateSource(pronunciationUrl);
play();
}
19 changes: 19 additions & 0 deletions apps/client/composables/main/useCourseContents.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { ref } from "vue";

const contentsVisible = ref(false);

export function useCourseContents() {
function openCourseContents() {
contentsVisible.value = true;
}

function hideCourseContents() {
contentsVisible.value = false;
}

return {
contentsVisible,
openCourseContents,
hideCourseContents,
};
}

0 comments on commit 4b6fa0f

Please sign in to comment.