106 lines
3.4 KiB
Vue
106 lines
3.4 KiB
Vue
<script setup lang="ts">
|
|
import LearningPathCircleColumn from "@/pages/learningPath/learningPathPage/LearningPathCircleColumn.vue";
|
|
import LearningPathScrollButton from "@/pages/learningPath/learningPathPage/LearningPathScrollButton.vue";
|
|
import { useScroll } from "@vueuse/core";
|
|
import { ref } from "vue";
|
|
import type {
|
|
LearningContentWithCompletion,
|
|
LearningPathType,
|
|
TopicType,
|
|
} from "@/types";
|
|
import LoadingSpinner from "@/components/ui/LoadingSpinner.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 isFirstCircle = (topicIndex: number, circleIndex: number) =>
|
|
topicIndex === 0 && circleIndex === 0;
|
|
|
|
const isLastCircle = (topicIndex: number, circleIndex: number, numCircles: number) =>
|
|
topicIndex === (props.learningPath?.topics ?? []).length - 1 &&
|
|
circleIndex === numCircles - 1;
|
|
|
|
const scrollRight = () => scrollLearnPathDiagram(scrollIncrement);
|
|
|
|
const scrollLeft = () => scrollLearnPathDiagram(-scrollIncrement);
|
|
|
|
const scrollLearnPathDiagram = (offset: number) => {
|
|
x.value += offset;
|
|
};
|
|
|
|
const filterCircles = (topic: TopicType) => {
|
|
// return [];
|
|
if (props.filter) {
|
|
return topic.circles.filter((circle) => circle.profiles.indexOf(props.filter) > -1);
|
|
}
|
|
return topic.circles;
|
|
};
|
|
</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"
|
|
>
|
|
<div
|
|
v-for="(topic, topicIndex) in props.learningPath?.topics ?? []"
|
|
:key="topic.title"
|
|
class="border-l border-gray-500"
|
|
:class="topicIndex == 0 ? 'ml-6 sm:ml-12' : ''"
|
|
>
|
|
<p
|
|
:id="`topic-${topic.slug}`"
|
|
class="inline-block h-12 self-start px-4 font-bold text-gray-800"
|
|
data-cy="lp-topic"
|
|
>
|
|
{{ topic.title }}
|
|
</p>
|
|
<div class="flex flex-row pt-6">
|
|
<LearningPathCircleColumn
|
|
v-for="(circle, circleIndex) in filterCircles(topic)"
|
|
:key="circle.id"
|
|
:circle="circle"
|
|
:next-learning-content="props.nextLearningContent"
|
|
:is-first-circle="isFirstCircle(topicIndex, circleIndex)"
|
|
:is-last-circle="
|
|
isLastCircle(topicIndex, circleIndex, topic.circles.length)
|
|
"
|
|
:override-circle-url="
|
|
props.overrideCircleUrlBase
|
|
? `${props.overrideCircleUrlBase}/${circle.slug}`
|
|
: undefined
|
|
"
|
|
></LearningPathCircleColumn>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<LearningPathScrollButton
|
|
v-show="!arrivedState.right"
|
|
direction="right"
|
|
:hidden="props.useMobileLayout"
|
|
@click="scrollRight"
|
|
></LearningPathScrollButton>
|
|
</div>
|
|
</template>
|