frontend: run lint
Signed-off-by: Nicolas Froger <nicolas@kektus.xyz>
This commit is contained in:
parent
3d6a2991b1
commit
2647ac244d
61 changed files with 426 additions and 592 deletions
|
|
@ -9,12 +9,16 @@ const appVersion = ref(import.meta.env.VITE_APP_VERSION)
|
|||
<template>
|
||||
<div class="fixed w-full top-0 z-50 flex items-center backdrop-blur-md bg-black/10 gap-2 px-3">
|
||||
<a href="https://www.kektus.fr"
|
||||
><h1 id="kektus" class="font-bold select-none mx-3 my-3 text-2xl hover:text-3xl transition-all duration-300">
|
||||
kektus</h1></a
|
||||
><h1
|
||||
id="kektus"
|
||||
class="font-bold select-none mx-3 my-3 text-2xl hover:text-3xl transition-all duration-300"
|
||||
>
|
||||
kektus
|
||||
</h1></a
|
||||
>
|
||||
<h1 class="font-light text-lg my-2 mr-3">carnet de voyage été 2024</h1>
|
||||
<div class="flex-grow"></div>
|
||||
<RouterLink :to="{name: 'home'}">
|
||||
<RouterLink :to="{ name: 'home' }">
|
||||
<div class="p-2 bg-black/10 hover:bg-black/20 transition-colors duration-300 rounded-lg">
|
||||
<Images size="20" />
|
||||
</div>
|
||||
|
|
@ -26,8 +30,11 @@ const appVersion = ref(import.meta.env.VITE_APP_VERSION)
|
|||
</RouterLink>
|
||||
</div>
|
||||
<RouterView />
|
||||
<p class="fixed right-0 bottom-0 z-50 p-1 font-extralight text-sm"><a
|
||||
href="https://gitlab.kektus.xyz/kektus/services/summer2024" target="_blank">v{{ appVersion }}</a></p>
|
||||
<p class="fixed right-0 bottom-0 z-50 p-1 font-extralight text-sm">
|
||||
<a href="https://gitlab.kektus.xyz/kektus/services/summer2024" target="_blank"
|
||||
>v{{ appVersion }}</a
|
||||
>
|
||||
</p>
|
||||
</template>
|
||||
|
||||
<style scoped></style>
|
||||
|
|
|
|||
|
|
@ -2,20 +2,20 @@
|
|||
@import url('https://fonts.googleapis.com/css2?family=Montserrat:ital,wght@0,100..900;1,100..900&display=swap');
|
||||
|
||||
body {
|
||||
font-family: 'Raleway', sans-serif;
|
||||
font-family: 'Raleway', sans-serif;
|
||||
}
|
||||
|
||||
#kektus {
|
||||
font-family: 'Montserrat', sans-serif;
|
||||
font-family: 'Montserrat', sans-serif;
|
||||
}
|
||||
|
||||
.ol-zoom {
|
||||
top: 120px !important;
|
||||
left: .5em;
|
||||
top: 120px !important;
|
||||
left: 0.5em;
|
||||
}
|
||||
|
||||
@media screen and (min-width: 500px) {
|
||||
.ol-zoom {
|
||||
top: 70px !important;
|
||||
}
|
||||
}
|
||||
.ol-zoom {
|
||||
top: 70px !important;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ const countdownInterval = setInterval(() => {
|
|||
const now = new Date().getTime()
|
||||
const distance = countdownDate - now
|
||||
if (distance < 0) {
|
||||
countdownDisplay.value = 'c\'est parti !'
|
||||
countdownDisplay.value = "c'est parti !"
|
||||
clearInterval(countdownInterval)
|
||||
return
|
||||
}
|
||||
|
|
@ -20,18 +20,20 @@ const countdownInterval = setInterval(() => {
|
|||
const minutes = Math.floor((distance % (1000 * 60 * 60)) / (1000 * 60))
|
||||
const seconds = Math.floor((distance % (1000 * 60)) / 1000)
|
||||
|
||||
countdownDisplay.value = `${days} jour` + (days > 1 ? 's' : '') +
|
||||
` ${hours} heure` + (hours > 1 ? 's' : '') +
|
||||
` ${minutes} minute` + (minutes > 1 ? 's' : '') +
|
||||
` ${seconds} seconde` + (seconds > 1 ? 's' : '')
|
||||
countdownDisplay.value =
|
||||
`${days} jour` +
|
||||
(days > 1 ? 's' : '') +
|
||||
` ${hours} heure` +
|
||||
(hours > 1 ? 's' : '') +
|
||||
` ${minutes} minute` +
|
||||
(minutes > 1 ? 's' : '') +
|
||||
` ${seconds} seconde` +
|
||||
(seconds > 1 ? 's' : '')
|
||||
}, 1000)
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<p :class="props.class">{{ countdownDisplay }}</p>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
<style scoped></style>
|
||||
|
|
|
|||
|
|
@ -14,42 +14,42 @@ const postActionBtn = ref(null)
|
|||
function postDataToggle() {
|
||||
if (postDataVisible.value) {
|
||||
for (const data of postData.value) {
|
||||
data.classList.remove('backdrop-blur-sm');
|
||||
data.classList.remove('bg-gray-400/10');
|
||||
data.classList.add('bg-gray-400/0');
|
||||
data.classList.remove('backdrop-blur-sm')
|
||||
data.classList.remove('bg-gray-400/10')
|
||||
data.classList.add('bg-gray-400/0')
|
||||
}
|
||||
for (const title of postDataTitle.value) {
|
||||
title.classList.add("opacity-0");
|
||||
title.classList.add('opacity-0')
|
||||
}
|
||||
for (const desc of postDataDescription.value) {
|
||||
desc.classList.add("opacity-0");
|
||||
desc.classList.remove("scrollable-element");
|
||||
desc.classList.add('opacity-0')
|
||||
desc.classList.remove('scrollable-element')
|
||||
}
|
||||
for (const btn of postActionBtn.value) {
|
||||
btn.classList.remove("top-0");
|
||||
btn.classList.remove("right-0");
|
||||
btn.classList.add("left-0");
|
||||
btn.classList.add("bottom-0");
|
||||
btn.classList.remove('top-0')
|
||||
btn.classList.remove('right-0')
|
||||
btn.classList.add('left-0')
|
||||
btn.classList.add('bottom-0')
|
||||
}
|
||||
postDataVisible.value = false
|
||||
} else {
|
||||
for (const data of postData.value) {
|
||||
data.classList.add('backdrop-blur-sm');
|
||||
data.classList.add('bg-gray-400/10');
|
||||
data.classList.remove('bg-gray-400/0');
|
||||
data.classList.add('backdrop-blur-sm')
|
||||
data.classList.add('bg-gray-400/10')
|
||||
data.classList.remove('bg-gray-400/0')
|
||||
}
|
||||
for (const title of postDataTitle.value) {
|
||||
title.classList.remove("opacity-0");
|
||||
title.classList.remove('opacity-0')
|
||||
}
|
||||
for (const desc of postDataDescription.value) {
|
||||
desc.classList.remove("opacity-0");
|
||||
desc.classList.add("scrollable-element");
|
||||
desc.classList.remove('opacity-0')
|
||||
desc.classList.add('scrollable-element')
|
||||
}
|
||||
for (const btn of postActionBtn.value) {
|
||||
btn.classList.add("top-0");
|
||||
btn.classList.add("right-0");
|
||||
btn.classList.remove("left-0");
|
||||
btn.classList.remove("bottom-0");
|
||||
btn.classList.add('top-0')
|
||||
btn.classList.add('right-0')
|
||||
btn.classList.remove('left-0')
|
||||
btn.classList.remove('bottom-0')
|
||||
}
|
||||
postDataVisible.value = true
|
||||
}
|
||||
|
|
@ -83,5 +83,4 @@ function postDataToggle() {
|
|||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
</style>
|
||||
<style scoped></style>
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
<script setup>
|
||||
import { alertVariants } from ".";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { alertVariants } from '.'
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
const props = defineProps({
|
||||
class: { type: null, required: false },
|
||||
variant: { type: null, required: false },
|
||||
});
|
||||
variant: { type: null, required: false }
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
<script setup>
|
||||
import { cn } from "@/lib/utils";
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
const props = defineProps({
|
||||
class: { type: null, required: false },
|
||||
});
|
||||
class: { type: null, required: false }
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
<script setup>
|
||||
import { cn } from "@/lib/utils";
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
const props = defineProps({
|
||||
class: { type: null, required: false },
|
||||
});
|
||||
class: { type: null, required: false }
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
|
|
|||
|
|
@ -1,21 +1,21 @@
|
|||
import { cva } from "class-variance-authority";
|
||||
import { cva } from 'class-variance-authority'
|
||||
|
||||
export { default as Alert } from "./Alert.vue";
|
||||
export { default as AlertTitle } from "./AlertTitle.vue";
|
||||
export { default as AlertDescription } from "./AlertDescription.vue";
|
||||
export { default as Alert } from './Alert.vue'
|
||||
export { default as AlertTitle } from './AlertTitle.vue'
|
||||
export { default as AlertDescription } from './AlertDescription.vue'
|
||||
|
||||
export const alertVariants = cva(
|
||||
"relative w-full rounded-lg border p-4 [&>svg~*]:pl-7 [&>svg+div]:translate-y-[-3px] [&>svg]:absolute [&>svg]:left-4 [&>svg]:top-4 [&>svg]:text-foreground",
|
||||
'relative w-full rounded-lg border p-4 [&>svg~*]:pl-7 [&>svg+div]:translate-y-[-3px] [&>svg]:absolute [&>svg]:left-4 [&>svg]:top-4 [&>svg]:text-foreground',
|
||||
{
|
||||
variants: {
|
||||
variant: {
|
||||
default: "bg-background text-foreground",
|
||||
default: 'bg-background text-foreground',
|
||||
destructive:
|
||||
"border-destructive/50 text-destructive dark:border-destructive [&>svg]:text-destructive",
|
||||
},
|
||||
'border-destructive/50 text-destructive dark:border-destructive [&>svg]:text-destructive'
|
||||
}
|
||||
},
|
||||
defaultVariants: {
|
||||
variant: "default",
|
||||
},
|
||||
},
|
||||
);
|
||||
variant: 'default'
|
||||
}
|
||||
}
|
||||
)
|
||||
|
|
|
|||
|
|
@ -1,20 +1,13 @@
|
|||
<script setup>
|
||||
import { cn } from "@/lib/utils";
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
const props = defineProps({
|
||||
class: { type: null, required: false },
|
||||
});
|
||||
class: { type: null, required: false }
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div
|
||||
:class="
|
||||
cn(
|
||||
'rounded-lg border bg-card text-card-foreground shadow-sm',
|
||||
props.class,
|
||||
)
|
||||
"
|
||||
>
|
||||
<div :class="cn('rounded-lg border bg-card text-card-foreground shadow-sm', props.class)">
|
||||
<slot />
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
<script setup>
|
||||
import { cn } from "@/lib/utils";
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
const props = defineProps({
|
||||
class: { type: null, required: false },
|
||||
});
|
||||
class: { type: null, required: false }
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
<script setup>
|
||||
import { cn } from "@/lib/utils";
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
const props = defineProps({
|
||||
class: { type: null, required: false },
|
||||
});
|
||||
class: { type: null, required: false }
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
<script setup>
|
||||
import { cn } from "@/lib/utils";
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
const props = defineProps({
|
||||
class: { type: null, required: false },
|
||||
});
|
||||
class: { type: null, required: false }
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
<script setup>
|
||||
import { cn } from "@/lib/utils";
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
const props = defineProps({
|
||||
class: { type: null, required: false },
|
||||
});
|
||||
class: { type: null, required: false }
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
|
|
|||
|
|
@ -1,17 +1,13 @@
|
|||
<script setup>
|
||||
import { cn } from "@/lib/utils";
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
const props = defineProps({
|
||||
class: { type: null, required: false },
|
||||
});
|
||||
class: { type: null, required: false }
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<h3
|
||||
:class="
|
||||
cn('text-2xl font-semibold leading-none tracking-tight', props.class)
|
||||
"
|
||||
>
|
||||
<h3 :class="cn('text-2xl font-semibold leading-none tracking-tight', props.class)">
|
||||
<slot />
|
||||
</h3>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
export { default as Card } from "./Card.vue";
|
||||
export { default as CardHeader } from "./CardHeader.vue";
|
||||
export { default as CardTitle } from "./CardTitle.vue";
|
||||
export { default as CardDescription } from "./CardDescription.vue";
|
||||
export { default as CardContent } from "./CardContent.vue";
|
||||
export { default as CardFooter } from "./CardFooter.vue";
|
||||
export { default as Card } from './Card.vue'
|
||||
export { default as CardHeader } from './CardHeader.vue'
|
||||
export { default as CardTitle } from './CardTitle.vue'
|
||||
export { default as CardDescription } from './CardDescription.vue'
|
||||
export { default as CardContent } from './CardContent.vue'
|
||||
export { default as CardFooter } from './CardFooter.vue'
|
||||
|
|
|
|||
|
|
@ -1,34 +1,34 @@
|
|||
<script setup>
|
||||
import { useProvideCarousel } from "./useCarousel";
|
||||
import { cn } from "@/lib/utils";
|
||||
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 },
|
||||
});
|
||||
orientation: { type: String, required: false, default: 'horizontal' },
|
||||
class: { type: null, required: false }
|
||||
})
|
||||
|
||||
const emits = defineEmits(["init-api"]);
|
||||
const emits = defineEmits(['init-api'])
|
||||
|
||||
const carouselArgs = useProvideCarousel(props, emits);
|
||||
const carouselArgs = useProvideCarousel(props, emits)
|
||||
|
||||
defineExpose(carouselArgs);
|
||||
defineExpose(carouselArgs)
|
||||
|
||||
function onKeyDown(event) {
|
||||
const prevKey = props.orientation === "vertical" ? "ArrowUp" : "ArrowLeft";
|
||||
const nextKey = props.orientation === "vertical" ? "ArrowDown" : "ArrowRight";
|
||||
const prevKey = props.orientation === 'vertical' ? 'ArrowUp' : 'ArrowLeft'
|
||||
const nextKey = props.orientation === 'vertical' ? 'ArrowDown' : 'ArrowRight'
|
||||
|
||||
if (event.key === prevKey) {
|
||||
event.preventDefault();
|
||||
carouselArgs.scrollPrev();
|
||||
event.preventDefault()
|
||||
carouselArgs.scrollPrev()
|
||||
|
||||
return;
|
||||
return
|
||||
}
|
||||
|
||||
if (event.key === nextKey) {
|
||||
event.preventDefault();
|
||||
carouselArgs.scrollNext();
|
||||
event.preventDefault()
|
||||
carouselArgs.scrollNext()
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -1,28 +1,22 @@
|
|||
<script setup>
|
||||
import { useCarousel } from "./useCarousel";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { useCarousel } from './useCarousel'
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
defineOptions({
|
||||
inheritAttrs: false,
|
||||
});
|
||||
inheritAttrs: false
|
||||
})
|
||||
|
||||
const props = defineProps({
|
||||
class: { type: null, required: false },
|
||||
});
|
||||
class: { type: null, required: false }
|
||||
})
|
||||
|
||||
const { carouselRef, orientation } = useCarousel();
|
||||
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,
|
||||
)
|
||||
"
|
||||
:class="cn('flex', orientation === 'horizontal' ? '-ml-4' : '-mt-4 flex-col', props.class)"
|
||||
v-bind="$attrs"
|
||||
>
|
||||
<slot />
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
<script setup>
|
||||
import { useCarousel } from "./useCarousel";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { useCarousel } from './useCarousel'
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
const props = defineProps({
|
||||
class: { type: null, required: false },
|
||||
});
|
||||
class: { type: null, required: false }
|
||||
})
|
||||
|
||||
const { orientation } = useCarousel();
|
||||
const { orientation } = useCarousel()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
|
@ -17,7 +17,7 @@ const { orientation } = useCarousel();
|
|||
cn(
|
||||
'min-w-0 shrink-0 grow-0 basis-full',
|
||||
orientation === 'horizontal' ? 'pl-4' : 'pt-4',
|
||||
props.class,
|
||||
props.class
|
||||
)
|
||||
"
|
||||
>
|
||||
|
|
|
|||
|
|
@ -1,14 +1,14 @@
|
|||
<script setup>
|
||||
import { ArrowRight } from "lucide-vue-next";
|
||||
import { useCarousel } from "./useCarousel";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { Button } from "@/components/ui/button";
|
||||
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 },
|
||||
});
|
||||
class: { type: null, required: false }
|
||||
})
|
||||
|
||||
const { orientation, canScrollNext, scrollNext } = useCarousel();
|
||||
const { orientation, canScrollNext, scrollNext } = useCarousel()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
|
@ -20,7 +20,7 @@ const { orientation, canScrollNext, scrollNext } = useCarousel();
|
|||
orientation === 'horizontal'
|
||||
? '-right-12 top-1/2 -translate-y-1/2'
|
||||
: '-bottom-12 left-1/2 -translate-x-1/2 rotate-90',
|
||||
props.class,
|
||||
props.class
|
||||
)
|
||||
"
|
||||
variant="outline"
|
||||
|
|
|
|||
|
|
@ -1,14 +1,14 @@
|
|||
<script setup>
|
||||
import { ArrowLeft } from "lucide-vue-next";
|
||||
import { useCarousel } from "./useCarousel";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { Button } from "@/components/ui/button";
|
||||
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 },
|
||||
});
|
||||
class: { type: null, required: false }
|
||||
})
|
||||
|
||||
const { orientation, canScrollPrev, scrollPrev } = useCarousel();
|
||||
const { orientation, canScrollPrev, scrollPrev } = useCarousel()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
|
@ -20,7 +20,7 @@ const { orientation, canScrollPrev, scrollPrev } = useCarousel();
|
|||
orientation === 'horizontal'
|
||||
? '-left-12 top-1/2 -translate-y-1/2'
|
||||
: '-top-12 left-1/2 -translate-x-1/2 rotate-90',
|
||||
props.class,
|
||||
props.class
|
||||
)
|
||||
"
|
||||
variant="outline"
|
||||
|
|
|
|||
|
|
@ -1,6 +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";
|
||||
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'
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
export {};
|
||||
export {}
|
||||
|
|
|
|||
|
|
@ -1,41 +1,41 @@
|
|||
import { createInjectionState } from "@vueuse/core";
|
||||
import emblaCarouselVue from "embla-carousel-vue";
|
||||
import { onMounted, ref } from "vue";
|
||||
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",
|
||||
axis: orientation === 'horizontal' ? 'x' : 'y'
|
||||
},
|
||||
plugins,
|
||||
);
|
||||
plugins
|
||||
)
|
||||
|
||||
function scrollPrev() {
|
||||
emblaApi.value?.scrollPrev();
|
||||
emblaApi.value?.scrollPrev()
|
||||
}
|
||||
function scrollNext() {
|
||||
emblaApi.value?.scrollNext();
|
||||
emblaApi.value?.scrollNext()
|
||||
}
|
||||
|
||||
const canScrollNext = ref(false);
|
||||
const canScrollPrev = ref(false);
|
||||
const canScrollNext = ref(false)
|
||||
const canScrollPrev = ref(false)
|
||||
|
||||
function onSelect(api) {
|
||||
canScrollNext.value = api?.canScrollNext() || false;
|
||||
canScrollPrev.value = api?.canScrollPrev() || false;
|
||||
canScrollNext.value = api?.canScrollNext() || false
|
||||
canScrollPrev.value = api?.canScrollPrev() || false
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
if (!emblaApi.value) return;
|
||||
if (!emblaApi.value) return
|
||||
|
||||
emblaApi.value?.on("init", onSelect);
|
||||
emblaApi.value?.on("reInit", onSelect);
|
||||
emblaApi.value?.on("select", onSelect);
|
||||
emblaApi.value?.on('init', onSelect)
|
||||
emblaApi.value?.on('reInit', onSelect)
|
||||
emblaApi.value?.on('select', onSelect)
|
||||
|
||||
emits("init-api", emblaApi.value);
|
||||
});
|
||||
emits('init-api', emblaApi.value)
|
||||
})
|
||||
|
||||
return {
|
||||
carouselRef: emblaNode,
|
||||
|
|
@ -44,18 +44,17 @@ const [useProvideCarousel, useInjectCarousel] = createInjectionState(
|
|||
canScrollNext,
|
||||
scrollPrev,
|
||||
scrollNext,
|
||||
orientation,
|
||||
};
|
||||
},
|
||||
);
|
||||
orientation
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
function useCarousel() {
|
||||
const carouselState = useInjectCarousel();
|
||||
const carouselState = useInjectCarousel()
|
||||
|
||||
if (!carouselState)
|
||||
throw new Error("useCarousel must be used within a <Carousel />");
|
||||
if (!carouselState) throw new Error('useCarousel must be used within a <Carousel />')
|
||||
|
||||
return carouselState;
|
||||
return carouselState
|
||||
}
|
||||
|
||||
export { useCarousel, useProvideCarousel };
|
||||
export { useCarousel, useProvideCarousel }
|
||||
|
|
|
|||
|
|
@ -1,16 +1,14 @@
|
|||
<script setup>
|
||||
import { Slot } from "radix-vue";
|
||||
import { useFormField } from "./useFormField";
|
||||
import { Slot } from 'radix-vue'
|
||||
import { useFormField } from './useFormField'
|
||||
|
||||
const { error, formItemId, formDescriptionId, formMessageId } = useFormField();
|
||||
const { error, formItemId, formDescriptionId, formMessageId } = useFormField()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Slot
|
||||
:id="formItemId"
|
||||
:aria-describedby="
|
||||
!error ? `${formDescriptionId}` : `${formDescriptionId} ${formMessageId}`
|
||||
"
|
||||
:aria-describedby="!error ? `${formDescriptionId}` : `${formDescriptionId} ${formMessageId}`"
|
||||
:aria-invalid="!!error"
|
||||
>
|
||||
<slot />
|
||||
|
|
|
|||
|
|
@ -1,19 +1,16 @@
|
|||
<script setup>
|
||||
import { useFormField } from "./useFormField";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { useFormField } from './useFormField'
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
const props = defineProps({
|
||||
class: { type: null, required: false },
|
||||
});
|
||||
class: { type: null, required: false }
|
||||
})
|
||||
|
||||
const { formDescriptionId } = useFormField();
|
||||
const { formDescriptionId } = useFormField()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<p
|
||||
:id="formDescriptionId"
|
||||
:class="cn('text-sm text-muted-foreground', props.class)"
|
||||
>
|
||||
<p :id="formDescriptionId" :class="cn('text-sm text-muted-foreground', props.class)">
|
||||
<slot />
|
||||
</p>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -1,15 +1,15 @@
|
|||
<script setup>
|
||||
import { provide } from "vue";
|
||||
import { useId } from "radix-vue";
|
||||
import { FORM_ITEM_INJECTION_KEY } from "./injectionKeys";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { provide } from 'vue'
|
||||
import { useId } from 'radix-vue'
|
||||
import { FORM_ITEM_INJECTION_KEY } from './injectionKeys'
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
const props = defineProps({
|
||||
class: { type: null, required: false },
|
||||
});
|
||||
class: { type: null, required: false }
|
||||
})
|
||||
|
||||
const id = useId();
|
||||
provide(FORM_ITEM_INJECTION_KEY, id);
|
||||
const id = useId()
|
||||
provide(FORM_ITEM_INJECTION_KEY, id)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
|
|
|||
|
|
@ -1,23 +1,20 @@
|
|||
<script setup>
|
||||
import { useFormField } from "./useFormField";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { Label } from "@/components/ui/label";
|
||||
import { useFormField } from './useFormField'
|
||||
import { cn } from '@/lib/utils'
|
||||
import { Label } from '@/components/ui/label'
|
||||
|
||||
const props = defineProps({
|
||||
for: { type: String, required: false },
|
||||
asChild: { type: Boolean, required: false },
|
||||
as: { type: null, required: false },
|
||||
class: { type: null, required: false },
|
||||
});
|
||||
class: { type: null, required: false }
|
||||
})
|
||||
|
||||
const { error, formItemId } = useFormField();
|
||||
const { error, formItemId } = useFormField()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Label
|
||||
:class="cn(error && 'text-destructive', props.class)"
|
||||
:for="formItemId"
|
||||
>
|
||||
<Label :class="cn(error && 'text-destructive', props.class)" :for="formItemId">
|
||||
<slot />
|
||||
</Label>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
<script setup>
|
||||
import { ErrorMessage } from "vee-validate";
|
||||
import { toValue } from "vue";
|
||||
import { useFormField } from "./useFormField";
|
||||
import { ErrorMessage } from 'vee-validate'
|
||||
import { toValue } from 'vue'
|
||||
import { useFormField } from './useFormField'
|
||||
|
||||
const { name, formMessageId } = useFormField();
|
||||
const { name, formMessageId } = useFormField()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
export { Form, Field as FormField } from "vee-validate";
|
||||
export { default as FormItem } from "./FormItem.vue";
|
||||
export { default as FormLabel } from "./FormLabel.vue";
|
||||
export { default as FormControl } from "./FormControl.vue";
|
||||
export { default as FormMessage } from "./FormMessage.vue";
|
||||
export { default as FormDescription } from "./FormDescription.vue";
|
||||
export { FORM_ITEM_INJECTION_KEY } from "./injectionKeys";
|
||||
export { Form, Field as FormField } from 'vee-validate'
|
||||
export { default as FormItem } from './FormItem.vue'
|
||||
export { default as FormLabel } from './FormLabel.vue'
|
||||
export { default as FormControl } from './FormControl.vue'
|
||||
export { default as FormMessage } from './FormMessage.vue'
|
||||
export { default as FormDescription } from './FormDescription.vue'
|
||||
export { FORM_ITEM_INJECTION_KEY } from './injectionKeys'
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
export const FORM_ITEM_INJECTION_KEY = Symbol();
|
||||
export const FORM_ITEM_INJECTION_KEY = Symbol()
|
||||
|
|
|
|||
|
|
@ -3,27 +3,26 @@ import {
|
|||
useFieldError,
|
||||
useIsFieldDirty,
|
||||
useIsFieldTouched,
|
||||
useIsFieldValid,
|
||||
} from "vee-validate";
|
||||
import { inject } from "vue";
|
||||
import { FORM_ITEM_INJECTION_KEY } from "./injectionKeys";
|
||||
useIsFieldValid
|
||||
} from 'vee-validate'
|
||||
import { inject } from 'vue'
|
||||
import { FORM_ITEM_INJECTION_KEY } from './injectionKeys'
|
||||
|
||||
export function useFormField() {
|
||||
const fieldContext = inject(FieldContextKey);
|
||||
const fieldItemContext = inject(FORM_ITEM_INJECTION_KEY);
|
||||
const fieldContext = inject(FieldContextKey)
|
||||
const fieldItemContext = inject(FORM_ITEM_INJECTION_KEY)
|
||||
|
||||
if (!fieldContext)
|
||||
throw new Error("useFormField should be used within <FormField>");
|
||||
if (!fieldContext) throw new Error('useFormField should be used within <FormField>')
|
||||
|
||||
const { name } = fieldContext;
|
||||
const id = fieldItemContext;
|
||||
const { name } = fieldContext
|
||||
const id = fieldItemContext
|
||||
|
||||
const fieldState = {
|
||||
valid: useIsFieldValid(name),
|
||||
isDirty: useIsFieldDirty(name),
|
||||
isTouched: useIsFieldTouched(name),
|
||||
error: useFieldError(name),
|
||||
};
|
||||
error: useFieldError(name)
|
||||
}
|
||||
|
||||
return {
|
||||
id,
|
||||
|
|
@ -31,6 +30,6 @@ export function useFormField() {
|
|||
formItemId: `${id}-form-item`,
|
||||
formDescriptionId: `${id}-form-item-description`,
|
||||
formMessageId: `${id}-form-item-message`,
|
||||
...fieldState,
|
||||
};
|
||||
...fieldState
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,19 +1,19 @@
|
|||
<script setup>
|
||||
import { useVModel } from "@vueuse/core";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { useVModel } from '@vueuse/core'
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
const props = defineProps({
|
||||
defaultValue: { type: [String, Number], required: false },
|
||||
modelValue: { type: [String, Number], required: false },
|
||||
class: { type: null, required: false },
|
||||
});
|
||||
class: { type: null, required: false }
|
||||
})
|
||||
|
||||
const emits = defineEmits(["update:modelValue"]);
|
||||
const emits = defineEmits(['update:modelValue'])
|
||||
|
||||
const modelValue = useVModel(props, "modelValue", emits, {
|
||||
const modelValue = useVModel(props, 'modelValue', emits, {
|
||||
passive: true,
|
||||
defaultValue: props.defaultValue,
|
||||
});
|
||||
defaultValue: props.defaultValue
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
|
@ -22,7 +22,7 @@ const modelValue = useVModel(props, "modelValue", emits, {
|
|||
:class="
|
||||
cn(
|
||||
'flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50',
|
||||
props.class,
|
||||
props.class
|
||||
)
|
||||
"
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
export { default as Input } from "./Input.vue";
|
||||
export { default as Input } from './Input.vue'
|
||||
|
|
|
|||
|
|
@ -1,20 +1,20 @@
|
|||
<script setup>
|
||||
import { computed } from "vue";
|
||||
import { Label } from "radix-vue";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { computed } from 'vue'
|
||||
import { Label } from 'radix-vue'
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
const props = defineProps({
|
||||
for: { type: String, required: false },
|
||||
asChild: { type: Boolean, required: false },
|
||||
as: { type: null, required: false },
|
||||
class: { type: null, required: false },
|
||||
});
|
||||
class: { type: null, required: false }
|
||||
})
|
||||
|
||||
const delegatedProps = computed(() => {
|
||||
const { class: _, ...delegated } = props;
|
||||
const { class: _, ...delegated } = props
|
||||
|
||||
return delegated;
|
||||
});
|
||||
return delegated
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
|
@ -23,7 +23,7 @@ const delegatedProps = computed(() => {
|
|||
:class="
|
||||
cn(
|
||||
'text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70',
|
||||
props.class,
|
||||
props.class
|
||||
)
|
||||
"
|
||||
>
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
export { default as Label } from "./Label.vue";
|
||||
export { default as Label } from './Label.vue'
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
<script setup>
|
||||
import { cn } from "@/lib/utils";
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
const props = defineProps({
|
||||
class: { type: null, required: false },
|
||||
});
|
||||
class: { type: null, required: false }
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
<script setup>
|
||||
import { cn } from "@/lib/utils";
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
const props = defineProps({
|
||||
class: { type: null, required: false },
|
||||
});
|
||||
class: { type: null, required: false }
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
<script setup>
|
||||
import { cn } from "@/lib/utils";
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
const props = defineProps({
|
||||
class: { type: null, required: false },
|
||||
});
|
||||
class: { type: null, required: false }
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
|
|
|||
|
|
@ -1,15 +1,13 @@
|
|||
<script setup>
|
||||
import { cn } from "@/lib/utils";
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
const props = defineProps({
|
||||
class: { type: null, required: false },
|
||||
});
|
||||
class: { type: null, required: false }
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<td
|
||||
:class="cn('p-4 align-middle [&:has([role=checkbox])]:pr-0', props.class)"
|
||||
>
|
||||
<td :class="cn('p-4 align-middle [&:has([role=checkbox])]:pr-0', props.class)">
|
||||
<slot />
|
||||
</td>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -1,29 +1,25 @@
|
|||
<script setup>
|
||||
import { computed } from "vue";
|
||||
import TableRow from "./TableRow.vue";
|
||||
import TableCell from "./TableCell.vue";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { computed } from 'vue'
|
||||
import TableRow from './TableRow.vue'
|
||||
import TableCell from './TableCell.vue'
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
const props = defineProps({
|
||||
class: { type: null, required: false },
|
||||
colspan: { type: Number, required: false, default: 1 },
|
||||
});
|
||||
colspan: { type: Number, required: false, default: 1 }
|
||||
})
|
||||
|
||||
const delegatedProps = computed(() => {
|
||||
const { class: _, ...delegated } = props;
|
||||
const { class: _, ...delegated } = props
|
||||
|
||||
return delegated;
|
||||
});
|
||||
return delegated
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<TableRow>
|
||||
<TableCell
|
||||
:class="
|
||||
cn(
|
||||
'p-4 whitespace-nowrap align-middle text-sm text-foreground',
|
||||
props.class
|
||||
)"
|
||||
:class="cn('p-4 whitespace-nowrap align-middle text-sm text-foreground', props.class)"
|
||||
v-bind="delegatedProps"
|
||||
>
|
||||
<div class="flex items-center justify-center py-10">
|
||||
|
|
|
|||
|
|
@ -1,17 +1,13 @@
|
|||
<script setup>
|
||||
import { cn } from "@/lib/utils";
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
const props = defineProps({
|
||||
class: { type: null, required: false },
|
||||
});
|
||||
class: { type: null, required: false }
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<tfoot
|
||||
:class="
|
||||
cn('border-t bg-muted/50 font-medium [&>tr]:last:border-b-0', props.class)
|
||||
"
|
||||
>
|
||||
<tfoot :class="cn('border-t bg-muted/50 font-medium [&>tr]:last:border-b-0', props.class)">
|
||||
<slot />
|
||||
</tfoot>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
<script setup>
|
||||
import { cn } from "@/lib/utils";
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
const props = defineProps({
|
||||
class: { type: null, required: false },
|
||||
});
|
||||
class: { type: null, required: false }
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
|
@ -11,7 +11,7 @@ const props = defineProps({
|
|||
:class="
|
||||
cn(
|
||||
'h-12 px-4 text-left align-middle font-medium text-muted-foreground [&:has([role=checkbox])]:pr-0',
|
||||
props.class,
|
||||
props.class
|
||||
)
|
||||
"
|
||||
>
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
<script setup>
|
||||
import { cn } from "@/lib/utils";
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
const props = defineProps({
|
||||
class: { type: null, required: false },
|
||||
});
|
||||
class: { type: null, required: false }
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
|
|
|||
|
|
@ -1,18 +1,15 @@
|
|||
<script setup>
|
||||
import { cn } from "@/lib/utils";
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
const props = defineProps({
|
||||
class: { type: null, required: false },
|
||||
});
|
||||
class: { type: null, required: false }
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<tr
|
||||
:class="
|
||||
cn(
|
||||
'border-b transition-colors hover:bg-muted/50 data-[state=selected]:bg-muted',
|
||||
props.class,
|
||||
)
|
||||
cn('border-b transition-colors hover:bg-muted/50 data-[state=selected]:bg-muted', props.class)
|
||||
"
|
||||
>
|
||||
<slot />
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
export { default as Table } from "./Table.vue";
|
||||
export { default as TableBody } from "./TableBody.vue";
|
||||
export { default as TableCell } from "./TableCell.vue";
|
||||
export { default as TableHead } from "./TableHead.vue";
|
||||
export { default as TableHeader } from "./TableHeader.vue";
|
||||
export { default as TableFooter } from "./TableFooter.vue";
|
||||
export { default as TableRow } from "./TableRow.vue";
|
||||
export { default as TableCaption } from "./TableCaption.vue";
|
||||
export { default as TableEmpty } from "./TableEmpty.vue";
|
||||
export { default as Table } from './Table.vue'
|
||||
export { default as TableBody } from './TableBody.vue'
|
||||
export { default as TableCell } from './TableCell.vue'
|
||||
export { default as TableHead } from './TableHead.vue'
|
||||
export { default as TableHeader } from './TableHeader.vue'
|
||||
export { default as TableFooter } from './TableFooter.vue'
|
||||
export { default as TableRow } from './TableRow.vue'
|
||||
export { default as TableCaption } from './TableCaption.vue'
|
||||
export { default as TableEmpty } from './TableEmpty.vue'
|
||||
|
|
|
|||
|
|
@ -1,19 +1,19 @@
|
|||
<script setup>
|
||||
import { useVModel } from "@vueuse/core";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { useVModel } from '@vueuse/core'
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
const props = defineProps({
|
||||
class: { type: null, required: false },
|
||||
defaultValue: { type: [String, Number], required: false },
|
||||
modelValue: { type: [String, Number], required: false },
|
||||
});
|
||||
modelValue: { type: [String, Number], required: false }
|
||||
})
|
||||
|
||||
const emits = defineEmits(["update:modelValue"]);
|
||||
const emits = defineEmits(['update:modelValue'])
|
||||
|
||||
const modelValue = useVModel(props, "modelValue", emits, {
|
||||
const modelValue = useVModel(props, 'modelValue', emits, {
|
||||
passive: true,
|
||||
defaultValue: props.defaultValue,
|
||||
});
|
||||
defaultValue: props.defaultValue
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
|
@ -22,7 +22,7 @@ const modelValue = useVModel(props, "modelValue", emits, {
|
|||
:class="
|
||||
cn(
|
||||
'flex min-h-20 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50',
|
||||
props.class,
|
||||
props.class
|
||||
)
|
||||
"
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
export { default as Textarea } from "./Textarea.vue";
|
||||
export { default as Textarea } from './Textarea.vue'
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
<script setup>
|
||||
import { TooltipRoot, useForwardPropsEmits } from "radix-vue";
|
||||
import { TooltipRoot, useForwardPropsEmits } from 'radix-vue'
|
||||
|
||||
const props = defineProps({
|
||||
defaultOpen: { type: Boolean, required: false },
|
||||
|
|
@ -8,11 +8,11 @@ const props = defineProps({
|
|||
disableHoverableContent: { type: Boolean, required: false },
|
||||
disableClosingTrigger: { type: Boolean, required: false },
|
||||
disabled: { type: Boolean, required: false },
|
||||
ignoreNonKeyboardFocus: { type: Boolean, required: false },
|
||||
});
|
||||
const emits = defineEmits(["update:open"]);
|
||||
ignoreNonKeyboardFocus: { type: Boolean, required: false }
|
||||
})
|
||||
const emits = defineEmits(['update:open'])
|
||||
|
||||
const forwarded = useForwardPropsEmits(props, emits);
|
||||
const forwarded = useForwardPropsEmits(props, emits)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
<script setup>
|
||||
import { computed } from "vue";
|
||||
import { TooltipContent, TooltipPortal, useForwardPropsEmits } from "radix-vue";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { computed } from 'vue'
|
||||
import { TooltipContent, TooltipPortal, useForwardPropsEmits } from 'radix-vue'
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
defineOptions({
|
||||
inheritAttrs: false,
|
||||
});
|
||||
inheritAttrs: false
|
||||
})
|
||||
|
||||
const props = defineProps({
|
||||
forceMount: { type: Boolean, required: false },
|
||||
|
|
@ -22,18 +22,18 @@ const props = defineProps({
|
|||
arrowPadding: { type: Number, required: false },
|
||||
sticky: { type: String, required: false },
|
||||
hideWhenDetached: { type: Boolean, required: false },
|
||||
class: { type: null, required: false },
|
||||
});
|
||||
class: { type: null, required: false }
|
||||
})
|
||||
|
||||
const emits = defineEmits(["escapeKeyDown", "pointerDownOutside"]);
|
||||
const emits = defineEmits(['escapeKeyDown', 'pointerDownOutside'])
|
||||
|
||||
const delegatedProps = computed(() => {
|
||||
const { class: _, ...delegated } = props;
|
||||
const { class: _, ...delegated } = props
|
||||
|
||||
return delegated;
|
||||
});
|
||||
return delegated
|
||||
})
|
||||
|
||||
const forwarded = useForwardPropsEmits(delegatedProps, emits);
|
||||
const forwarded = useForwardPropsEmits(delegatedProps, emits)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
|
@ -43,7 +43,7 @@ const forwarded = useForwardPropsEmits(delegatedProps, emits);
|
|||
:class="
|
||||
cn(
|
||||
'z-50 overflow-hidden rounded-md border bg-popover px-3 py-1.5 text-sm text-popover-foreground shadow-md animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2',
|
||||
props.class,
|
||||
props.class
|
||||
)
|
||||
"
|
||||
>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
<script setup>
|
||||
import { TooltipProvider } from "radix-vue";
|
||||
import { TooltipProvider } from 'radix-vue'
|
||||
|
||||
const props = defineProps({
|
||||
delayDuration: { type: Number, required: false },
|
||||
|
|
@ -7,8 +7,8 @@ const props = defineProps({
|
|||
disableHoverableContent: { type: Boolean, required: false },
|
||||
disableClosingTrigger: { type: Boolean, required: false },
|
||||
disabled: { type: Boolean, required: false },
|
||||
ignoreNonKeyboardFocus: { type: Boolean, required: false },
|
||||
});
|
||||
ignoreNonKeyboardFocus: { type: Boolean, required: false }
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
<script setup>
|
||||
import { TooltipTrigger } from "radix-vue";
|
||||
import { TooltipTrigger } from 'radix-vue'
|
||||
|
||||
const props = defineProps({
|
||||
asChild: { type: Boolean, required: false },
|
||||
as: { type: null, required: false },
|
||||
});
|
||||
as: { type: null, required: false }
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
export { default as Tooltip } from "./Tooltip.vue";
|
||||
export { default as TooltipContent } from "./TooltipContent.vue";
|
||||
export { default as TooltipTrigger } from "./TooltipTrigger.vue";
|
||||
export { default as TooltipProvider } from "./TooltipProvider.vue";
|
||||
export { default as Tooltip } from './Tooltip.vue'
|
||||
export { default as TooltipContent } from './TooltipContent.vue'
|
||||
export { default as TooltipTrigger } from './TooltipTrigger.vue'
|
||||
export { default as TooltipProvider } from './TooltipProvider.vue'
|
||||
|
|
|
|||
|
|
@ -9,14 +9,14 @@ import VueFullPage from 'vue-fullpage.js'
|
|||
import App from './App.vue'
|
||||
import router from './router'
|
||||
|
||||
import "vue3-openlayers/styles.css";
|
||||
import OpenLayersMap from "vue3-openlayers";
|
||||
import 'vue3-openlayers/styles.css'
|
||||
import OpenLayersMap from 'vue3-openlayers'
|
||||
|
||||
const app = createApp(App)
|
||||
|
||||
app.use(VueFullPage)
|
||||
app.use(createPinia())
|
||||
app.use(router)
|
||||
app.use(OpenLayersMap);
|
||||
app.use(OpenLayersMap)
|
||||
|
||||
app.mount('#app')
|
||||
|
|
|
|||
|
|
@ -2,41 +2,39 @@ import { defineStore } from 'pinia'
|
|||
import { ref } from 'vue'
|
||||
import { API_BASE_URL } from '@/config.js'
|
||||
|
||||
export const useAuthStore = defineStore("auth", () => {
|
||||
const adminToken = ref("");
|
||||
const isAuth = ref(false);
|
||||
const error = ref(false);
|
||||
export const useAuthStore = defineStore('auth', () => {
|
||||
const adminToken = ref('')
|
||||
const isAuth = ref(false)
|
||||
const error = ref(false)
|
||||
|
||||
function login(token) {
|
||||
adminToken.value = "";
|
||||
isAuth.value = false;
|
||||
error.value = false;
|
||||
adminToken.value = ''
|
||||
isAuth.value = false
|
||||
error.value = false
|
||||
|
||||
return fetch(API_BASE_URL + "/admin/auth/check", {
|
||||
return fetch(API_BASE_URL + '/admin/auth/check', {
|
||||
headers: {
|
||||
"X-admin-token": token
|
||||
'X-admin-token': token
|
||||
}
|
||||
}).then(resp => {
|
||||
}).then((resp) => {
|
||||
if (resp.ok) {
|
||||
adminToken.value = token;
|
||||
isAuth.value = true;
|
||||
localStorage.setItem("kektus-summer-admin-token", token)
|
||||
adminToken.value = token
|
||||
isAuth.value = true
|
||||
localStorage.setItem('kektus-summer-admin-token', token)
|
||||
} else {
|
||||
error.value = true;
|
||||
error.value = true
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function checkFromLocalStorage() {
|
||||
const storedToken = localStorage.getItem("kektus-summer-admin-token")
|
||||
const storedToken = localStorage.getItem('kektus-summer-admin-token')
|
||||
if (storedToken) {
|
||||
return login(storedToken)
|
||||
}
|
||||
|
||||
return Promise.resolve();
|
||||
return Promise.resolve()
|
||||
}
|
||||
|
||||
|
||||
|
||||
return { adminToken, login, checkFromLocalStorage, isAuth, error }
|
||||
})
|
||||
})
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
<script setup>
|
||||
|
||||
import { Button } from '@/components/ui/button/index.js'
|
||||
import { CirclePlus, Pencil, Trash, MapPin } from 'lucide-vue-next'
|
||||
import { useAdminPostsStore } from '@/stores/adminPosts.js'
|
||||
|
|
@ -72,6 +71,4 @@ onMounted(() => {
|
|||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
<style scoped></style>
|
||||
|
|
|
|||
|
|
@ -8,7 +8,14 @@ import { Label } from '@/components/ui/label/index.js'
|
|||
import { toTypedSchema } from '@vee-validate/zod'
|
||||
import { z } from 'zod'
|
||||
import { onMounted, onUnmounted, ref } from 'vue'
|
||||
import { AlertCircle, ArrowLeft, ArrowRight, CircleCheckBig, CirclePlus, RefreshCcw } from 'lucide-vue-next'
|
||||
import {
|
||||
AlertCircle,
|
||||
ArrowLeft,
|
||||
ArrowRight,
|
||||
CircleCheckBig,
|
||||
CirclePlus,
|
||||
RefreshCcw
|
||||
} from 'lucide-vue-next'
|
||||
import {
|
||||
Carousel,
|
||||
CarouselContent,
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
<script setup>
|
||||
|
||||
import { useAuthStore } from '@/stores/auth.js'
|
||||
import { toTypedSchema } from '@vee-validate/zod'
|
||||
import { z } from 'zod'
|
||||
|
|
@ -14,15 +13,17 @@ import router from '@/router/index.js'
|
|||
import { useRoute } from 'vue-router'
|
||||
|
||||
const authStore = useAuthStore()
|
||||
const nextView = useRoute().query.redirect;
|
||||
const nextView = useRoute().query.redirect
|
||||
|
||||
onMounted(() => {
|
||||
authStore.checkFromLocalStorage().then(onLogin);
|
||||
authStore.checkFromLocalStorage().then(onLogin)
|
||||
})
|
||||
|
||||
const formSchema = toTypedSchema(z.object({
|
||||
token: z.string().min(1)
|
||||
}))
|
||||
const formSchema = toTypedSchema(
|
||||
z.object({
|
||||
token: z.string().min(1)
|
||||
})
|
||||
)
|
||||
const form = useForm({
|
||||
validationSchema: formSchema
|
||||
})
|
||||
|
|
@ -32,16 +33,14 @@ const onSubmit = form.handleSubmit((values) => {
|
|||
})
|
||||
|
||||
function onLogin() {
|
||||
if (!authStore.isAuth)
|
||||
return;
|
||||
if (!authStore.isAuth) return
|
||||
|
||||
if (nextView) {
|
||||
router.push(nextView);
|
||||
router.push(nextView)
|
||||
} else {
|
||||
router.push({name: "admin"});
|
||||
router.push({ name: 'admin' })
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
|
@ -57,7 +56,6 @@ function onLogin() {
|
|||
<AlertDescription>Token invalide</AlertDescription>
|
||||
</Alert>
|
||||
|
||||
|
||||
<div id="form-container" ref="formContainer">
|
||||
<form id="login-form" class="space-y-6" @submit="onSubmit">
|
||||
<FormField v-slot="{ componentField }" name="token">
|
||||
|
|
@ -68,15 +66,11 @@ function onLogin() {
|
|||
</FormControl>
|
||||
</FormItem>
|
||||
</FormField>
|
||||
<Button class="mt-6 w-full" type="submit">
|
||||
Login
|
||||
</Button>
|
||||
<Button class="mt-6 w-full" type="submit"> Login </Button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
<style scoped></style>
|
||||
|
|
|
|||
|
|
@ -1,9 +1,13 @@
|
|||
<script setup>
|
||||
|
||||
import { usePostsStore } from '@/stores/posts.js'
|
||||
import { computed, onMounted, ref } from 'vue'
|
||||
import { Camera, Goal, MapPin } from 'lucide-vue-next'
|
||||
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@/components/ui/tooltip/index.js'
|
||||
import {
|
||||
Tooltip,
|
||||
TooltipContent,
|
||||
TooltipProvider,
|
||||
TooltipTrigger
|
||||
} from '@/components/ui/tooltip/index.js'
|
||||
import { useLocationStore } from '@/stores/location.js'
|
||||
import { fromLonLat } from 'ol/proj.js'
|
||||
|
||||
|
|
@ -39,16 +43,8 @@ const goalLocations = ref([
|
|||
|
||||
<template>
|
||||
<div class="fixed h-full w-full">
|
||||
<ol-map
|
||||
:loadTilesWhileAnimating="true"
|
||||
:loadTilesWhileInteracting="true"
|
||||
class="h-full w-full"
|
||||
>
|
||||
<ol-view
|
||||
ref="view"
|
||||
:zoom="3.6"
|
||||
:center="[ 652293.6169027708, 6425265.202945196 ]"
|
||||
/>
|
||||
<ol-map :loadTilesWhileAnimating="true" :loadTilesWhileInteracting="true" class="h-full w-full">
|
||||
<ol-view ref="view" :zoom="3.6" :center="[652293.6169027708, 6425265.202945196]" />
|
||||
|
||||
<ol-tile-layer>
|
||||
<ol-source-osm />
|
||||
|
|
@ -56,16 +52,18 @@ const goalLocations = ref([
|
|||
<ol-scaleline-control />
|
||||
|
||||
<ol-overlay
|
||||
v-for="post in postStore.posts" :key="post.id"
|
||||
v-for="post in postStore.posts"
|
||||
:key="post.id"
|
||||
:position="post.projectedCoordinates"
|
||||
:autoPan="true"
|
||||
>
|
||||
<TooltipProvider>
|
||||
<Tooltip :default-open="true">
|
||||
<TooltipTrigger as-child>
|
||||
<RouterLink :to="{ name: 'home', hash: '#post-' + post.id}">
|
||||
<RouterLink :to="{ name: 'home', hash: '#post-' + post.id }">
|
||||
<div
|
||||
class="-translate-x-1/2 -translate-y-1/2 p-1 rounded-lg bg-indigo-950 hover:bg-indigo-900 transition-colors duration-200">
|
||||
class="-translate-x-1/2 -translate-y-1/2 p-1 rounded-lg bg-indigo-950 hover:bg-indigo-900 transition-colors duration-200"
|
||||
>
|
||||
<Camera size="16" />
|
||||
</div>
|
||||
</RouterLink>
|
||||
|
|
@ -85,7 +83,8 @@ const goalLocations = ref([
|
|||
<Tooltip :default-open="true">
|
||||
<TooltipTrigger as-child>
|
||||
<div
|
||||
class="-translate-x-1/2 -translate-y-1/2 p-1 rounded-lg bg-rose-950 hover:bg-rose-900 transition-colors duration-200">
|
||||
class="-translate-x-1/2 -translate-y-1/2 p-1 rounded-lg bg-rose-950 hover:bg-rose-900 transition-colors duration-200"
|
||||
>
|
||||
<MapPin size="16" />
|
||||
</div>
|
||||
</TooltipTrigger>
|
||||
|
|
@ -97,7 +96,8 @@ const goalLocations = ref([
|
|||
</ol-overlay>
|
||||
|
||||
<ol-overlay
|
||||
v-for="loc in goalLocations" :key="loc.name"
|
||||
v-for="loc in goalLocations"
|
||||
:key="loc.name"
|
||||
:position="loc.coords"
|
||||
:autoPan="true"
|
||||
>
|
||||
|
|
@ -105,7 +105,8 @@ const goalLocations = ref([
|
|||
<Tooltip>
|
||||
<TooltipTrigger as-child>
|
||||
<div
|
||||
class="-translate-x-1/2 -translate-y-1/2 p-1 rounded-lg bg-emerald-800 hover:bg-emerald-700 transition-colors duration-200">
|
||||
class="-translate-x-1/2 -translate-y-1/2 p-1 rounded-lg bg-emerald-800 hover:bg-emerald-700 transition-colors duration-200"
|
||||
>
|
||||
<Goal size="16" />
|
||||
</div>
|
||||
</TooltipTrigger>
|
||||
|
|
@ -119,15 +120,9 @@ const goalLocations = ref([
|
|||
<ol-vector-layer v-if="postsLinesCoordinates.length > 1">
|
||||
<ol-source-vector>
|
||||
<ol-feature ref="profileFeatureRef">
|
||||
<ol-geom-line-string
|
||||
:coordinates="postsLinesCoordinates"
|
||||
></ol-geom-line-string>
|
||||
<ol-geom-line-string :coordinates="postsLinesCoordinates"></ol-geom-line-string>
|
||||
<ol-style>
|
||||
<ol-style-stroke
|
||||
color="white"
|
||||
width="5"
|
||||
:lineDash="[15, 15]"
|
||||
></ol-style-stroke>
|
||||
<ol-style-stroke color="white" width="5" :lineDash="[15, 15]"></ol-style-stroke>
|
||||
</ol-style>
|
||||
</ol-feature>
|
||||
</ol-source-vector>
|
||||
|
|
@ -136,5 +131,4 @@ const goalLocations = ref([
|
|||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
</style>
|
||||
<style scoped></style>
|
||||
|
|
|
|||
|
|
@ -32,8 +32,7 @@ instance it still finds a way to be alive and break when changing views????
|
|||
*/
|
||||
|
||||
async function initFullpage() {
|
||||
if (fullPageInit)
|
||||
return
|
||||
if (fullPageInit) return
|
||||
|
||||
fullpageKey.value += 5
|
||||
fullpageEnable.value = true
|
||||
|
|
@ -41,7 +40,9 @@ async function initFullpage() {
|
|||
try {
|
||||
fullpage.value.init()
|
||||
} catch (e) {
|
||||
console.log('failed to reload fullpage.js because it sucks with vue, reloading page as last resort')
|
||||
console.log(
|
||||
'failed to reload fullpage.js because it sucks with vue, reloading page as last resort'
|
||||
)
|
||||
window.location.reload()
|
||||
return
|
||||
}
|
||||
|
|
@ -57,7 +58,10 @@ onMounted(() => {
|
|||
|
||||
onBeforeUnmount(async () => {
|
||||
console.log('caught post view unmount')
|
||||
if (typeof window.fullpage_api !== 'undefined' && typeof window.fullpage_api.destroy !== 'undefined') {
|
||||
if (
|
||||
typeof window.fullpage_api !== 'undefined' &&
|
||||
typeof window.fullpage_api.destroy !== 'undefined'
|
||||
) {
|
||||
window.fullpage_api.destroy('all')
|
||||
}
|
||||
fullpageKey.value++
|
||||
|
|
@ -100,11 +104,18 @@ function onLeave(origin, destination, direction, trigger) {
|
|||
class="col-start-1 col-span-full row-start-1 max-h-52 h-fit mt-28 sm:mt-16 lg:m-0 lg:col-start-5 lg:col-span-1 lg:row-start-3 lg:row-span-1 pointer-events-auto overflow-y-scroll transition-opacity duration-1000 opacity-0"
|
||||
ref="menu"
|
||||
>
|
||||
<li :data-menuanchor="'post-' + post.id" v-for="post in postsStore.posts" :key="post.id"
|
||||
class="m-2 backdrop-blur-sm rounded-lg bg-black/10 hover:bg-gray-500/10 transition-colors duration-200"
|
||||
ref="menuItems">
|
||||
<a :href="'#post-' + post.id"
|
||||
class="block text-right px-4 py-3 transition-all duration-300">{{ post.formatedDate }}</a>
|
||||
<li
|
||||
:data-menuanchor="'post-' + post.id"
|
||||
v-for="post in postsStore.posts"
|
||||
:key="post.id"
|
||||
class="m-2 backdrop-blur-sm rounded-lg bg-black/10 hover:bg-gray-500/10 transition-colors duration-200"
|
||||
ref="menuItems"
|
||||
>
|
||||
<a
|
||||
:href="'#post-' + post.id"
|
||||
class="block text-right px-4 py-3 transition-all duration-300"
|
||||
>{{ post.formatedDate }}</a
|
||||
>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
|
@ -123,7 +134,6 @@ function onLeave(origin, destination, direction, trigger) {
|
|||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
#menu li.active,
|
||||
#menu li.active:hover {
|
||||
background-color: rgba(255, 255, 255, 0.1);
|
||||
|
|
|
|||
|
|
@ -13,10 +13,12 @@ import { API_BASE_URL } from '@/config.js'
|
|||
|
||||
const authStore = useAuthStore()
|
||||
|
||||
const formSchema = toTypedSchema(z.object({
|
||||
latitude: z.number(),
|
||||
longitude: z.number()
|
||||
}))
|
||||
const formSchema = toTypedSchema(
|
||||
z.object({
|
||||
latitude: z.number(),
|
||||
longitude: z.number()
|
||||
})
|
||||
)
|
||||
const form = useForm({
|
||||
validationSchema: formSchema
|
||||
})
|
||||
|
|
@ -33,8 +35,7 @@ const formStatus = ref({
|
|||
})
|
||||
|
||||
const onSubmit = form.handleSubmit(async (values) => {
|
||||
if (!authStore.isAuth)
|
||||
return
|
||||
if (!authStore.isAuth) return
|
||||
|
||||
console.log('Envoi de la localisation...')
|
||||
formContainer.value.classList.add('hidden')
|
||||
|
|
@ -55,7 +56,8 @@ const onSubmit = form.handleSubmit(async (values) => {
|
|||
console.log('POST post API failed: ' + response.statusText + '\n\n' + response.body)
|
||||
formStatus.value.sending = false
|
||||
formStatus.value.error = true
|
||||
formStatus.value.errorMsg = 'Une erreur est survenue lors de l\'envoi du poste : ' + response.statusText
|
||||
formStatus.value.errorMsg =
|
||||
"Une erreur est survenue lors de l'envoi du poste : " + response.statusText
|
||||
formContainer.value.classList.remove('hidden')
|
||||
return
|
||||
}
|
||||
|
|
@ -79,7 +81,6 @@ onUnmounted(() => {
|
|||
navigator.geolocation.clearWatch(geoWatchId)
|
||||
}
|
||||
})
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
|
@ -133,5 +134,4 @@ onUnmounted(() => {
|
|||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
</style>
|
||||
<style scoped></style>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue