init backend, added admin page in front
Signed-off-by: Nicolas Froger <nicolas@kektus.xyz>
This commit is contained in:
parent
5c6e641fbd
commit
ddc6c64f0f
89 changed files with 5083 additions and 9 deletions
46
summer2024-frontend/src/components/ui/carousel/Carousel.vue
Normal file
46
summer2024-frontend/src/components/ui/carousel/Carousel.vue
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
<script setup>
|
||||
import { useProvideCarousel } from "./useCarousel";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
const props = defineProps({
|
||||
opts: { type: null, required: false },
|
||||
plugins: { type: null, required: false },
|
||||
orientation: { type: String, required: false, default: "horizontal" },
|
||||
class: { type: null, required: false },
|
||||
});
|
||||
|
||||
const emits = defineEmits(["init-api"]);
|
||||
|
||||
const carouselArgs = useProvideCarousel(props, emits);
|
||||
|
||||
defineExpose(carouselArgs);
|
||||
|
||||
function onKeyDown(event) {
|
||||
const prevKey = props.orientation === "vertical" ? "ArrowUp" : "ArrowLeft";
|
||||
const nextKey = props.orientation === "vertical" ? "ArrowDown" : "ArrowRight";
|
||||
|
||||
if (event.key === prevKey) {
|
||||
event.preventDefault();
|
||||
carouselArgs.scrollPrev();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.key === nextKey) {
|
||||
event.preventDefault();
|
||||
carouselArgs.scrollNext();
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div
|
||||
:class="cn('relative', props.class)"
|
||||
role="region"
|
||||
aria-roledescription="carousel"
|
||||
tabindex="0"
|
||||
@keydown="onKeyDown"
|
||||
>
|
||||
<slot v-bind="carouselArgs" />
|
||||
</div>
|
||||
</template>
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
<script setup>
|
||||
import { useCarousel } from "./useCarousel";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
defineOptions({
|
||||
inheritAttrs: false,
|
||||
});
|
||||
|
||||
const props = defineProps({
|
||||
class: { type: null, required: false },
|
||||
});
|
||||
|
||||
const { carouselRef, orientation } = useCarousel();
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div ref="carouselRef" class="overflow-hidden">
|
||||
<div
|
||||
:class="
|
||||
cn(
|
||||
'flex',
|
||||
orientation === 'horizontal' ? '-ml-4' : '-mt-4 flex-col',
|
||||
props.class,
|
||||
)
|
||||
"
|
||||
v-bind="$attrs"
|
||||
>
|
||||
<slot />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
<script setup>
|
||||
import { useCarousel } from "./useCarousel";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
const props = defineProps({
|
||||
class: { type: null, required: false },
|
||||
});
|
||||
|
||||
const { orientation } = useCarousel();
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div
|
||||
role="group"
|
||||
aria-roledescription="slide"
|
||||
:class="
|
||||
cn(
|
||||
'min-w-0 shrink-0 grow-0 basis-full',
|
||||
orientation === 'horizontal' ? 'pl-4' : 'pt-4',
|
||||
props.class,
|
||||
)
|
||||
"
|
||||
>
|
||||
<slot />
|
||||
</div>
|
||||
</template>
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
<script setup>
|
||||
import { ArrowRight } from "lucide-vue-next";
|
||||
import { useCarousel } from "./useCarousel";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { Button } from "@/components/ui/button";
|
||||
|
||||
const props = defineProps({
|
||||
class: { type: null, required: false },
|
||||
});
|
||||
|
||||
const { orientation, canScrollNext, scrollNext } = useCarousel();
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Button
|
||||
:disabled="!canScrollNext"
|
||||
:class="
|
||||
cn(
|
||||
'touch-manipulation absolute h-8 w-8 rounded-full p-0',
|
||||
orientation === 'horizontal'
|
||||
? '-right-12 top-1/2 -translate-y-1/2'
|
||||
: '-bottom-12 left-1/2 -translate-x-1/2 rotate-90',
|
||||
props.class,
|
||||
)
|
||||
"
|
||||
variant="outline"
|
||||
@click="scrollNext"
|
||||
>
|
||||
<slot>
|
||||
<ArrowRight class="h-4 w-4 text-current" />
|
||||
<span class="sr-only">Next Slide</span>
|
||||
</slot>
|
||||
</Button>
|
||||
</template>
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
<script setup>
|
||||
import { ArrowLeft } from "lucide-vue-next";
|
||||
import { useCarousel } from "./useCarousel";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { Button } from "@/components/ui/button";
|
||||
|
||||
const props = defineProps({
|
||||
class: { type: null, required: false },
|
||||
});
|
||||
|
||||
const { orientation, canScrollPrev, scrollPrev } = useCarousel();
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Button
|
||||
:disabled="!canScrollPrev"
|
||||
:class="
|
||||
cn(
|
||||
'touch-manipulation absolute h-8 w-8 rounded-full p-0',
|
||||
orientation === 'horizontal'
|
||||
? '-left-12 top-1/2 -translate-y-1/2'
|
||||
: '-top-12 left-1/2 -translate-x-1/2 rotate-90',
|
||||
props.class,
|
||||
)
|
||||
"
|
||||
variant="outline"
|
||||
@click="scrollPrev"
|
||||
>
|
||||
<slot>
|
||||
<ArrowLeft class="h-4 w-4 text-current" />
|
||||
<span class="sr-only">Previous Slide</span>
|
||||
</slot>
|
||||
</Button>
|
||||
</template>
|
||||
6
summer2024-frontend/src/components/ui/carousel/index.js
Normal file
6
summer2024-frontend/src/components/ui/carousel/index.js
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
export { default as Carousel } from "./Carousel.vue";
|
||||
export { default as CarouselContent } from "./CarouselContent.vue";
|
||||
export { default as CarouselItem } from "./CarouselItem.vue";
|
||||
export { default as CarouselPrevious } from "./CarouselPrevious.vue";
|
||||
export { default as CarouselNext } from "./CarouselNext.vue";
|
||||
export { useCarousel } from "./useCarousel";
|
||||
|
|
@ -0,0 +1 @@
|
|||
export {};
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
import { createInjectionState } from "@vueuse/core";
|
||||
import emblaCarouselVue from "embla-carousel-vue";
|
||||
import { onMounted, ref } from "vue";
|
||||
|
||||
const [useProvideCarousel, useInjectCarousel] = createInjectionState(
|
||||
({ opts, orientation, plugins }, emits) => {
|
||||
const [emblaNode, emblaApi] = emblaCarouselVue(
|
||||
{
|
||||
...opts,
|
||||
axis: orientation === "horizontal" ? "x" : "y",
|
||||
},
|
||||
plugins,
|
||||
);
|
||||
|
||||
function scrollPrev() {
|
||||
emblaApi.value?.scrollPrev();
|
||||
}
|
||||
function scrollNext() {
|
||||
emblaApi.value?.scrollNext();
|
||||
}
|
||||
|
||||
const canScrollNext = ref(false);
|
||||
const canScrollPrev = ref(false);
|
||||
|
||||
function onSelect(api) {
|
||||
canScrollNext.value = api?.canScrollNext() || false;
|
||||
canScrollPrev.value = api?.canScrollPrev() || false;
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
if (!emblaApi.value) return;
|
||||
|
||||
emblaApi.value?.on("init", onSelect);
|
||||
emblaApi.value?.on("reInit", onSelect);
|
||||
emblaApi.value?.on("select", onSelect);
|
||||
|
||||
emits("init-api", emblaApi.value);
|
||||
});
|
||||
|
||||
return {
|
||||
carouselRef: emblaNode,
|
||||
carouselApi: emblaApi,
|
||||
canScrollPrev,
|
||||
canScrollNext,
|
||||
scrollPrev,
|
||||
scrollNext,
|
||||
orientation,
|
||||
};
|
||||
},
|
||||
);
|
||||
|
||||
function useCarousel() {
|
||||
const carouselState = useInjectCarousel();
|
||||
|
||||
if (!carouselState)
|
||||
throw new Error("useCarousel must be used within a <Carousel />");
|
||||
|
||||
return carouselState;
|
||||
}
|
||||
|
||||
export { useCarousel, useProvideCarousel };
|
||||
Loading…
Add table
Add a link
Reference in a new issue