82 lines
2.6 KiB
Vue
82 lines
2.6 KiB
Vue
<script setup lang="ts">
|
|
import LearningPathScrollButton from "@/pages/learningPath/learningPathPage/LearningPathScrollButton.vue";
|
|
import { useScroll } from "@vueuse/core";
|
|
import { computed, nextTick, ref, watch } from "vue";
|
|
import type { LearningContentWithCompletion, LearningPathType } from "@/types";
|
|
import LoadingSpinner from "@/components/ui/LoadingSpinner.vue";
|
|
import LearningPathPathTopic from "./LearningPathPathTopic.vue";
|
|
|
|
const props = defineProps<{
|
|
learningPath: LearningPathType | undefined;
|
|
nextLearningContent: LearningContentWithCompletion | undefined;
|
|
useMobileLayout: boolean;
|
|
hideButtons?: boolean;
|
|
overrideCircleUrlBase?: string;
|
|
filter?: string;
|
|
}>();
|
|
|
|
const scrollIncrement = 600;
|
|
|
|
const learnPathDiagram = ref<HTMLElement | null>(null);
|
|
const { x, arrivedState } = useScroll(learnPathDiagram, { behavior: "smooth" });
|
|
|
|
const scrollRight = () => scrollLearnPathDiagram(scrollIncrement);
|
|
|
|
const scrollLeft = () => scrollLearnPathDiagram(-scrollIncrement);
|
|
|
|
const scrollLearnPathDiagram = (offset: number) => {
|
|
x.value += offset;
|
|
};
|
|
|
|
const topics = computed(() => props.learningPath?.topics ?? []);
|
|
|
|
watch(
|
|
() => props.filter,
|
|
() => {
|
|
// we need to update the scroll state of the element, otherwise the arrows won't match the scroll state
|
|
// https://github.com/vueuse/vueuse/issues/2875
|
|
nextTick(() => {
|
|
if (learnPathDiagram.value) {
|
|
const scrollEvent = new Event("scroll");
|
|
learnPathDiagram.value.dispatchEvent(scrollEvent);
|
|
}
|
|
});
|
|
}
|
|
);
|
|
</script>
|
|
|
|
<template>
|
|
<div v-if="!props.learningPath" class="m-8 flex justify-center">
|
|
<LoadingSpinner />
|
|
</div>
|
|
<div v-else class="relative flex flex-row items-center">
|
|
<LearningPathScrollButton
|
|
v-show="!arrivedState.left"
|
|
direction="left"
|
|
:hidden="props.useMobileLayout"
|
|
@click="scrollLeft"
|
|
></LearningPathScrollButton>
|
|
<div
|
|
ref="learnPathDiagram"
|
|
class="no-scrollbar flex h-96 snap-x flex-row overflow-auto py-5 sm:py-10"
|
|
>
|
|
<LearningPathPathTopic
|
|
v-for="(topic, topicIndex) in props.learningPath?.topics ?? []"
|
|
:key="topic.title"
|
|
:topic-index="topicIndex"
|
|
:topic="topic"
|
|
:next-learning-content="nextLearningContent"
|
|
:override-circle-url-base="overrideCircleUrlBase"
|
|
:filter="filter"
|
|
:is-last-topic="topicIndex === topics.length - 1"
|
|
/>
|
|
</div>
|
|
<LearningPathScrollButton
|
|
v-show="!arrivedState.right"
|
|
direction="right"
|
|
:hidden="props.useMobileLayout"
|
|
@click="scrollRight"
|
|
></LearningPathScrollButton>
|
|
</div>
|
|
</template>
|