frontend: run lint

Signed-off-by: Nicolas Froger <nicolas@kektus.xyz>
This commit is contained in:
Nicolas Froger 2024-07-27 02:10:59 +02:00
commit 2647ac244d
No known key found for this signature in database
61 changed files with 426 additions and 592 deletions

View file

@ -1,134 +0,0 @@
[
{
"id": 4,
"date": "2022-07-01T22:20:43.000Z",
"location": {
"lat": 48.93071193154141,
"lon": 2.1544736306563346,
"city": "Sartrouville",
"country": "France"
},
"description": "je suis en train de me prendre en photo dans la rue",
"assets": [
"https://www.kektus.fr/img/DSC09764.jpg"
]
},
{
"id": 5,
"date": "2023-12-28T23:18:43.511Z",
"location": {
"lat": 45.8307086344589862,
"lon": -1.107245822424634,
"city": "Marennes-Hiers-Brouage",
"country": "France"
},
"description": "ce mec est très dangereux",
"assets": [
"https://www.kektus.fr/img/DSC00671.jpg"
]
},
{
"id": 6,
"date": "2024-07-21T18:25:43.511Z",
"location": {
"lat": 45.98963904301394,
"lon": -1.3010006132332887,
"city": "Saint-Georges-d'Oléron",
"country": "France"
},
"description": "ceci est une **plage** avec un très long texte.\n\nLorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque et viverra lacus, vitae ultrices urna. Nunc purus nulla, iaculis at turpis ac, pretium vestibulum odio. Nullam posuere, magna nec ornare interdum, purus sem malesuada lectus, eget mattis lacus turpis et diam. Quisque orci sapien, elementum vitae pretium a, varius vitae ante. Morbi elementum elementum dignissim. Nulla venenatis est et velit pharetra eleifend. Nunc eu eros et augue convallis laoreet feugiat nec purus.\n\n Nunc mi justo, tempus sed aliquet ac, vulputate non sem. Phasellus vel massa aliquam, dapibus neque vitae, convallis odio. Duis in massa bibendum, lacinia arcu vitae, varius enim. Aenean posuere hendrerit neque vel rhoncus. Morbi rutrum nunc vitae fringilla luctus. Phasellus sapien risus, tincidunt in finibus non, mattis ut est. Fusce vehicula efficitur nisi a ultricies. Mauris cursus ut sem vitae fringilla.",
"assets": [
"https://www.kektus.fr/img/DSC00684.jpg",
"https://www.kektus.fr/img/DSC00723.jpg",
"https://www.kektus.fr/img/DSC00739.jpg"
]
},
{
"id": 7,
"date": "2022-07-01T22:20:43.000Z",
"location": {
"lat": 48.93071193154141,
"lon": 2.1544736306563346,
"city": "Sartrouville",
"country": "France"
},
"description": "je suis en train de me prendre en photo dans la rue",
"assets": [
"https://www.kektus.fr/img/DSC09764.jpg"
]
},
{
"id": 8,
"date": "2023-12-28T23:18:43.511Z",
"location": {
"lat": 45.8307086344589862,
"lon": -1.107245822424634,
"city": "Marennes-Hiers-Brouage",
"country": "France"
},
"description": "ce mec est très dangereux",
"assets": [
"https://www.kektus.fr/img/DSC00671.jpg"
]
},
{
"id": 9,
"date": "2024-07-21T18:25:43.511Z",
"location": {
"lat": 45.98963904301394,
"lon": -1.3010006132332887,
"city": "Saint-Georges-d'Oléron",
"country": "France"
},
"description": "ceci est une **plage** avec un très long texte.\n\nLorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque et viverra lacus, vitae ultrices urna. Nunc purus nulla, iaculis at turpis ac, pretium vestibulum odio. Nullam posuere, magna nec ornare interdum, purus sem malesuada lectus, eget mattis lacus turpis et diam. Quisque orci sapien, elementum vitae pretium a, varius vitae ante. Morbi elementum elementum dignissim. Nulla venenatis est et velit pharetra eleifend. Nunc eu eros et augue convallis laoreet feugiat nec purus.\n\n Nunc mi justo, tempus sed aliquet ac, vulputate non sem. Phasellus vel massa aliquam, dapibus neque vitae, convallis odio. Duis in massa bibendum, lacinia arcu vitae, varius enim. Aenean posuere hendrerit neque vel rhoncus. Morbi rutrum nunc vitae fringilla luctus. Phasellus sapien risus, tincidunt in finibus non, mattis ut est. Fusce vehicula efficitur nisi a ultricies. Mauris cursus ut sem vitae fringilla.",
"assets": [
"https://www.kektus.fr/img/DSC00684.jpg",
"https://www.kektus.fr/img/DSC00723.jpg",
"https://www.kektus.fr/img/DSC00739.jpg"
]
},
{
"id": 10,
"date": "2022-07-01T22:20:43.000Z",
"location": {
"lat": 48.93071193154141,
"lon": 2.1544736306563346,
"city": "Sartrouville",
"country": "France"
},
"description": "je suis en train de me prendre en photo dans la rue",
"assets": [
"https://www.kektus.fr/img/DSC09764.jpg"
]
},
{
"id": 11,
"date": "2023-12-28T23:18:43.511Z",
"location": {
"lat": 45.8307086344589862,
"lon": -1.107245822424634,
"city": "Marennes-Hiers-Brouage",
"country": "France"
},
"description": "ce mec est très dangereux",
"assets": [
"https://www.kektus.fr/img/DSC00671.jpg"
]
},
{
"id": 12,
"date": "2024-07-21T18:25:43.511Z",
"location": {
"lat": 45.98963904301394,
"lon": -1.3010006132332887,
"city": "Saint-Georges-d'Oléron",
"country": "France"
},
"description": "ceci est une **plage** avec un très long texte.\n\nLorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque et viverra lacus, vitae ultrices urna. Nunc purus nulla, iaculis at turpis ac, pretium vestibulum odio. Nullam posuere, magna nec ornare interdum, purus sem malesuada lectus, eget mattis lacus turpis et diam. Quisque orci sapien, elementum vitae pretium a, varius vitae ante. Morbi elementum elementum dignissim. Nulla venenatis est et velit pharetra eleifend. Nunc eu eros et augue convallis laoreet feugiat nec purus.\n\n Nunc mi justo, tempus sed aliquet ac, vulputate non sem. Phasellus vel massa aliquam, dapibus neque vitae, convallis odio. Duis in massa bibendum, lacinia arcu vitae, varius enim. Aenean posuere hendrerit neque vel rhoncus. Morbi rutrum nunc vitae fringilla luctus. Phasellus sapien risus, tincidunt in finibus non, mattis ut est. Fusce vehicula efficitur nisi a ultricies. Mauris cursus ut sem vitae fringilla.",
"assets": [
"https://www.kektus.fr/img/DSC00684.jpg",
"https://www.kektus.fr/img/DSC00723.jpg",
"https://www.kektus.fr/img/DSC00739.jpg"
]
}
]

View file

@ -9,12 +9,16 @@ const appVersion = ref(import.meta.env.VITE_APP_VERSION)
<template> <template>
<div class="fixed w-full top-0 z-50 flex items-center backdrop-blur-md bg-black/10 gap-2 px-3"> <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" <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"> ><h1
kektus</h1></a 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> <h1 class="font-light text-lg my-2 mr-3">carnet de voyage été 2024</h1>
<div class="flex-grow"></div> <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"> <div class="p-2 bg-black/10 hover:bg-black/20 transition-colors duration-300 rounded-lg">
<Images size="20" /> <Images size="20" />
</div> </div>
@ -26,8 +30,11 @@ const appVersion = ref(import.meta.env.VITE_APP_VERSION)
</RouterLink> </RouterLink>
</div> </div>
<RouterView /> <RouterView />
<p class="fixed right-0 bottom-0 z-50 p-1 font-extralight text-sm"><a <p class="fixed right-0 bottom-0 z-50 p-1 font-extralight text-sm">
href="https://gitlab.kektus.xyz/kektus/services/summer2024" target="_blank">v{{ appVersion }}</a></p> <a href="https://gitlab.kektus.xyz/kektus/services/summer2024" target="_blank"
>v{{ appVersion }}</a
>
</p>
</template> </template>
<style scoped></style> <style scoped></style>

View file

@ -2,20 +2,20 @@
@import url('https://fonts.googleapis.com/css2?family=Montserrat:ital,wght@0,100..900;1,100..900&display=swap'); @import url('https://fonts.googleapis.com/css2?family=Montserrat:ital,wght@0,100..900;1,100..900&display=swap');
body { body {
font-family: 'Raleway', sans-serif; font-family: 'Raleway', sans-serif;
} }
#kektus { #kektus {
font-family: 'Montserrat', sans-serif; font-family: 'Montserrat', sans-serif;
} }
.ol-zoom { .ol-zoom {
top: 120px !important; top: 120px !important;
left: .5em; left: 0.5em;
} }
@media screen and (min-width: 500px) { @media screen and (min-width: 500px) {
.ol-zoom { .ol-zoom {
top: 70px !important; top: 70px !important;
} }
} }

View file

@ -10,7 +10,7 @@ const countdownInterval = setInterval(() => {
const now = new Date().getTime() const now = new Date().getTime()
const distance = countdownDate - now const distance = countdownDate - now
if (distance < 0) { if (distance < 0) {
countdownDisplay.value = 'c\'est parti !' countdownDisplay.value = "c'est parti !"
clearInterval(countdownInterval) clearInterval(countdownInterval)
return return
} }
@ -20,18 +20,20 @@ const countdownInterval = setInterval(() => {
const minutes = Math.floor((distance % (1000 * 60 * 60)) / (1000 * 60)) const minutes = Math.floor((distance % (1000 * 60 * 60)) / (1000 * 60))
const seconds = Math.floor((distance % (1000 * 60)) / 1000) const seconds = Math.floor((distance % (1000 * 60)) / 1000)
countdownDisplay.value = `${days} jour` + (days > 1 ? 's' : '') + countdownDisplay.value =
` ${hours} heure` + (hours > 1 ? 's' : '') + `${days} jour` +
` ${minutes} minute` + (minutes > 1 ? 's' : '') + (days > 1 ? 's' : '') +
` ${seconds} seconde` + (seconds > 1 ? 's' : '') ` ${hours} heure` +
(hours > 1 ? 's' : '') +
` ${minutes} minute` +
(minutes > 1 ? 's' : '') +
` ${seconds} seconde` +
(seconds > 1 ? 's' : '')
}, 1000) }, 1000)
</script> </script>
<template> <template>
<p :class="props.class">{{ countdownDisplay }}</p> <p :class="props.class">{{ countdownDisplay }}</p>
</template> </template>
<style scoped> <style scoped></style>
</style>

View file

@ -14,42 +14,42 @@ const postActionBtn = ref(null)
function postDataToggle() { function postDataToggle() {
if (postDataVisible.value) { if (postDataVisible.value) {
for (const data of postData.value) { for (const data of postData.value) {
data.classList.remove('backdrop-blur-sm'); data.classList.remove('backdrop-blur-sm')
data.classList.remove('bg-gray-400/10'); data.classList.remove('bg-gray-400/10')
data.classList.add('bg-gray-400/0'); data.classList.add('bg-gray-400/0')
} }
for (const title of postDataTitle.value) { for (const title of postDataTitle.value) {
title.classList.add("opacity-0"); title.classList.add('opacity-0')
} }
for (const desc of postDataDescription.value) { for (const desc of postDataDescription.value) {
desc.classList.add("opacity-0"); desc.classList.add('opacity-0')
desc.classList.remove("scrollable-element"); desc.classList.remove('scrollable-element')
} }
for (const btn of postActionBtn.value) { for (const btn of postActionBtn.value) {
btn.classList.remove("top-0"); btn.classList.remove('top-0')
btn.classList.remove("right-0"); btn.classList.remove('right-0')
btn.classList.add("left-0"); btn.classList.add('left-0')
btn.classList.add("bottom-0"); btn.classList.add('bottom-0')
} }
postDataVisible.value = false postDataVisible.value = false
} else { } else {
for (const data of postData.value) { for (const data of postData.value) {
data.classList.add('backdrop-blur-sm'); data.classList.add('backdrop-blur-sm')
data.classList.add('bg-gray-400/10'); data.classList.add('bg-gray-400/10')
data.classList.remove('bg-gray-400/0'); data.classList.remove('bg-gray-400/0')
} }
for (const title of postDataTitle.value) { for (const title of postDataTitle.value) {
title.classList.remove("opacity-0"); title.classList.remove('opacity-0')
} }
for (const desc of postDataDescription.value) { for (const desc of postDataDescription.value) {
desc.classList.remove("opacity-0"); desc.classList.remove('opacity-0')
desc.classList.add("scrollable-element"); desc.classList.add('scrollable-element')
} }
for (const btn of postActionBtn.value) { for (const btn of postActionBtn.value) {
btn.classList.add("top-0"); btn.classList.add('top-0')
btn.classList.add("right-0"); btn.classList.add('right-0')
btn.classList.remove("left-0"); btn.classList.remove('left-0')
btn.classList.remove("bottom-0"); btn.classList.remove('bottom-0')
} }
postDataVisible.value = true postDataVisible.value = true
} }
@ -83,5 +83,4 @@ function postDataToggle() {
</div> </div>
</template> </template>
<style scoped> <style scoped></style>
</style>

View file

@ -1,11 +1,11 @@
<script setup> <script setup>
import { alertVariants } from "."; import { alertVariants } from '.'
import { cn } from "@/lib/utils"; import { cn } from '@/lib/utils'
const props = defineProps({ const props = defineProps({
class: { type: null, required: false }, class: { type: null, required: false },
variant: { type: null, required: false }, variant: { type: null, required: false }
}); })
</script> </script>
<template> <template>

View file

@ -1,9 +1,9 @@
<script setup> <script setup>
import { cn } from "@/lib/utils"; import { cn } from '@/lib/utils'
const props = defineProps({ const props = defineProps({
class: { type: null, required: false }, class: { type: null, required: false }
}); })
</script> </script>
<template> <template>

View file

@ -1,9 +1,9 @@
<script setup> <script setup>
import { cn } from "@/lib/utils"; import { cn } from '@/lib/utils'
const props = defineProps({ const props = defineProps({
class: { type: null, required: false }, class: { type: null, required: false }
}); })
</script> </script>
<template> <template>

View file

@ -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 Alert } from './Alert.vue'
export { default as AlertTitle } from "./AlertTitle.vue"; export { default as AlertTitle } from './AlertTitle.vue'
export { default as AlertDescription } from "./AlertDescription.vue"; export { default as AlertDescription } from './AlertDescription.vue'
export const alertVariants = cva( 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: { variants: {
variant: { variant: {
default: "bg-background text-foreground", default: 'bg-background text-foreground',
destructive: destructive:
"border-destructive/50 text-destructive dark:border-destructive [&>svg]:text-destructive", 'border-destructive/50 text-destructive dark:border-destructive [&>svg]:text-destructive'
}, }
}, },
defaultVariants: { defaultVariants: {
variant: "default", variant: 'default'
}, }
}, }
); )

View file

@ -1,20 +1,13 @@
<script setup> <script setup>
import { cn } from "@/lib/utils"; import { cn } from '@/lib/utils'
const props = defineProps({ const props = defineProps({
class: { type: null, required: false }, class: { type: null, required: false }
}); })
</script> </script>
<template> <template>
<div <div :class="cn('rounded-lg border bg-card text-card-foreground shadow-sm', props.class)">
:class="
cn(
'rounded-lg border bg-card text-card-foreground shadow-sm',
props.class,
)
"
>
<slot /> <slot />
</div> </div>
</template> </template>

View file

@ -1,9 +1,9 @@
<script setup> <script setup>
import { cn } from "@/lib/utils"; import { cn } from '@/lib/utils'
const props = defineProps({ const props = defineProps({
class: { type: null, required: false }, class: { type: null, required: false }
}); })
</script> </script>
<template> <template>

View file

@ -1,9 +1,9 @@
<script setup> <script setup>
import { cn } from "@/lib/utils"; import { cn } from '@/lib/utils'
const props = defineProps({ const props = defineProps({
class: { type: null, required: false }, class: { type: null, required: false }
}); })
</script> </script>
<template> <template>

View file

@ -1,9 +1,9 @@
<script setup> <script setup>
import { cn } from "@/lib/utils"; import { cn } from '@/lib/utils'
const props = defineProps({ const props = defineProps({
class: { type: null, required: false }, class: { type: null, required: false }
}); })
</script> </script>
<template> <template>

View file

@ -1,9 +1,9 @@
<script setup> <script setup>
import { cn } from "@/lib/utils"; import { cn } from '@/lib/utils'
const props = defineProps({ const props = defineProps({
class: { type: null, required: false }, class: { type: null, required: false }
}); })
</script> </script>
<template> <template>

View file

@ -1,17 +1,13 @@
<script setup> <script setup>
import { cn } from "@/lib/utils"; import { cn } from '@/lib/utils'
const props = defineProps({ const props = defineProps({
class: { type: null, required: false }, class: { type: null, required: false }
}); })
</script> </script>
<template> <template>
<h3 <h3 :class="cn('text-2xl font-semibold leading-none tracking-tight', props.class)">
:class="
cn('text-2xl font-semibold leading-none tracking-tight', props.class)
"
>
<slot /> <slot />
</h3> </h3>
</template> </template>

View file

@ -1,6 +1,6 @@
export { default as Card } from "./Card.vue"; export { default as Card } from './Card.vue'
export { default as CardHeader } from "./CardHeader.vue"; export { default as CardHeader } from './CardHeader.vue'
export { default as CardTitle } from "./CardTitle.vue"; export { default as CardTitle } from './CardTitle.vue'
export { default as CardDescription } from "./CardDescription.vue"; export { default as CardDescription } from './CardDescription.vue'
export { default as CardContent } from "./CardContent.vue"; export { default as CardContent } from './CardContent.vue'
export { default as CardFooter } from "./CardFooter.vue"; export { default as CardFooter } from './CardFooter.vue'

View file

@ -1,34 +1,34 @@
<script setup> <script setup>
import { useProvideCarousel } from "./useCarousel"; import { useProvideCarousel } from './useCarousel'
import { cn } from "@/lib/utils"; import { cn } from '@/lib/utils'
const props = defineProps({ const props = defineProps({
opts: { type: null, required: false }, opts: { type: null, required: false },
plugins: { type: null, required: false }, plugins: { type: null, required: false },
orientation: { type: String, required: false, default: "horizontal" }, orientation: { type: String, required: false, default: 'horizontal' },
class: { type: null, required: false }, 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) { function onKeyDown(event) {
const prevKey = props.orientation === "vertical" ? "ArrowUp" : "ArrowLeft"; const prevKey = props.orientation === 'vertical' ? 'ArrowUp' : 'ArrowLeft'
const nextKey = props.orientation === "vertical" ? "ArrowDown" : "ArrowRight"; const nextKey = props.orientation === 'vertical' ? 'ArrowDown' : 'ArrowRight'
if (event.key === prevKey) { if (event.key === prevKey) {
event.preventDefault(); event.preventDefault()
carouselArgs.scrollPrev(); carouselArgs.scrollPrev()
return; return
} }
if (event.key === nextKey) { if (event.key === nextKey) {
event.preventDefault(); event.preventDefault()
carouselArgs.scrollNext(); carouselArgs.scrollNext()
} }
} }
</script> </script>

View file

@ -1,28 +1,22 @@
<script setup> <script setup>
import { useCarousel } from "./useCarousel"; import { useCarousel } from './useCarousel'
import { cn } from "@/lib/utils"; import { cn } from '@/lib/utils'
defineOptions({ defineOptions({
inheritAttrs: false, inheritAttrs: false
}); })
const props = defineProps({ const props = defineProps({
class: { type: null, required: false }, class: { type: null, required: false }
}); })
const { carouselRef, orientation } = useCarousel(); const { carouselRef, orientation } = useCarousel()
</script> </script>
<template> <template>
<div ref="carouselRef" class="overflow-hidden"> <div ref="carouselRef" class="overflow-hidden">
<div <div
:class=" :class="cn('flex', orientation === 'horizontal' ? '-ml-4' : '-mt-4 flex-col', props.class)"
cn(
'flex',
orientation === 'horizontal' ? '-ml-4' : '-mt-4 flex-col',
props.class,
)
"
v-bind="$attrs" v-bind="$attrs"
> >
<slot /> <slot />

View file

@ -1,12 +1,12 @@
<script setup> <script setup>
import { useCarousel } from "./useCarousel"; import { useCarousel } from './useCarousel'
import { cn } from "@/lib/utils"; import { cn } from '@/lib/utils'
const props = defineProps({ const props = defineProps({
class: { type: null, required: false }, class: { type: null, required: false }
}); })
const { orientation } = useCarousel(); const { orientation } = useCarousel()
</script> </script>
<template> <template>
@ -17,7 +17,7 @@ const { orientation } = useCarousel();
cn( cn(
'min-w-0 shrink-0 grow-0 basis-full', 'min-w-0 shrink-0 grow-0 basis-full',
orientation === 'horizontal' ? 'pl-4' : 'pt-4', orientation === 'horizontal' ? 'pl-4' : 'pt-4',
props.class, props.class
) )
" "
> >

View file

@ -1,14 +1,14 @@
<script setup> <script setup>
import { ArrowRight } from "lucide-vue-next"; import { ArrowRight } from 'lucide-vue-next'
import { useCarousel } from "./useCarousel"; import { useCarousel } from './useCarousel'
import { cn } from "@/lib/utils"; import { cn } from '@/lib/utils'
import { Button } from "@/components/ui/button"; import { Button } from '@/components/ui/button'
const props = defineProps({ const props = defineProps({
class: { type: null, required: false }, class: { type: null, required: false }
}); })
const { orientation, canScrollNext, scrollNext } = useCarousel(); const { orientation, canScrollNext, scrollNext } = useCarousel()
</script> </script>
<template> <template>
@ -20,7 +20,7 @@ const { orientation, canScrollNext, scrollNext } = useCarousel();
orientation === 'horizontal' orientation === 'horizontal'
? '-right-12 top-1/2 -translate-y-1/2' ? '-right-12 top-1/2 -translate-y-1/2'
: '-bottom-12 left-1/2 -translate-x-1/2 rotate-90', : '-bottom-12 left-1/2 -translate-x-1/2 rotate-90',
props.class, props.class
) )
" "
variant="outline" variant="outline"

View file

@ -1,14 +1,14 @@
<script setup> <script setup>
import { ArrowLeft } from "lucide-vue-next"; import { ArrowLeft } from 'lucide-vue-next'
import { useCarousel } from "./useCarousel"; import { useCarousel } from './useCarousel'
import { cn } from "@/lib/utils"; import { cn } from '@/lib/utils'
import { Button } from "@/components/ui/button"; import { Button } from '@/components/ui/button'
const props = defineProps({ const props = defineProps({
class: { type: null, required: false }, class: { type: null, required: false }
}); })
const { orientation, canScrollPrev, scrollPrev } = useCarousel(); const { orientation, canScrollPrev, scrollPrev } = useCarousel()
</script> </script>
<template> <template>
@ -20,7 +20,7 @@ const { orientation, canScrollPrev, scrollPrev } = useCarousel();
orientation === 'horizontal' orientation === 'horizontal'
? '-left-12 top-1/2 -translate-y-1/2' ? '-left-12 top-1/2 -translate-y-1/2'
: '-top-12 left-1/2 -translate-x-1/2 rotate-90', : '-top-12 left-1/2 -translate-x-1/2 rotate-90',
props.class, props.class
) )
" "
variant="outline" variant="outline"

View file

@ -1,6 +1,6 @@
export { default as Carousel } from "./Carousel.vue"; export { default as Carousel } from './Carousel.vue'
export { default as CarouselContent } from "./CarouselContent.vue"; export { default as CarouselContent } from './CarouselContent.vue'
export { default as CarouselItem } from "./CarouselItem.vue"; export { default as CarouselItem } from './CarouselItem.vue'
export { default as CarouselPrevious } from "./CarouselPrevious.vue"; export { default as CarouselPrevious } from './CarouselPrevious.vue'
export { default as CarouselNext } from "./CarouselNext.vue"; export { default as CarouselNext } from './CarouselNext.vue'
export { useCarousel } from "./useCarousel"; export { useCarousel } from './useCarousel'

View file

@ -1 +1 @@
export {}; export {}

View file

@ -1,41 +1,41 @@
import { createInjectionState } from "@vueuse/core"; import { createInjectionState } from '@vueuse/core'
import emblaCarouselVue from "embla-carousel-vue"; import emblaCarouselVue from 'embla-carousel-vue'
import { onMounted, ref } from "vue"; import { onMounted, ref } from 'vue'
const [useProvideCarousel, useInjectCarousel] = createInjectionState( const [useProvideCarousel, useInjectCarousel] = createInjectionState(
({ opts, orientation, plugins }, emits) => { ({ opts, orientation, plugins }, emits) => {
const [emblaNode, emblaApi] = emblaCarouselVue( const [emblaNode, emblaApi] = emblaCarouselVue(
{ {
...opts, ...opts,
axis: orientation === "horizontal" ? "x" : "y", axis: orientation === 'horizontal' ? 'x' : 'y'
}, },
plugins, plugins
); )
function scrollPrev() { function scrollPrev() {
emblaApi.value?.scrollPrev(); emblaApi.value?.scrollPrev()
} }
function scrollNext() { function scrollNext() {
emblaApi.value?.scrollNext(); emblaApi.value?.scrollNext()
} }
const canScrollNext = ref(false); const canScrollNext = ref(false)
const canScrollPrev = ref(false); const canScrollPrev = ref(false)
function onSelect(api) { function onSelect(api) {
canScrollNext.value = api?.canScrollNext() || false; canScrollNext.value = api?.canScrollNext() || false
canScrollPrev.value = api?.canScrollPrev() || false; canScrollPrev.value = api?.canScrollPrev() || false
} }
onMounted(() => { onMounted(() => {
if (!emblaApi.value) return; if (!emblaApi.value) return
emblaApi.value?.on("init", onSelect); emblaApi.value?.on('init', onSelect)
emblaApi.value?.on("reInit", onSelect); emblaApi.value?.on('reInit', onSelect)
emblaApi.value?.on("select", onSelect); emblaApi.value?.on('select', onSelect)
emits("init-api", emblaApi.value); emits('init-api', emblaApi.value)
}); })
return { return {
carouselRef: emblaNode, carouselRef: emblaNode,
@ -44,18 +44,17 @@ const [useProvideCarousel, useInjectCarousel] = createInjectionState(
canScrollNext, canScrollNext,
scrollPrev, scrollPrev,
scrollNext, scrollNext,
orientation, orientation
}; }
}, }
); )
function useCarousel() { function useCarousel() {
const carouselState = useInjectCarousel(); const carouselState = useInjectCarousel()
if (!carouselState) if (!carouselState) throw new Error('useCarousel must be used within a <Carousel />')
throw new Error("useCarousel must be used within a <Carousel />");
return carouselState; return carouselState
} }
export { useCarousel, useProvideCarousel }; export { useCarousel, useProvideCarousel }

View file

@ -1,16 +1,14 @@
<script setup> <script setup>
import { Slot } from "radix-vue"; import { Slot } from 'radix-vue'
import { useFormField } from "./useFormField"; import { useFormField } from './useFormField'
const { error, formItemId, formDescriptionId, formMessageId } = useFormField(); const { error, formItemId, formDescriptionId, formMessageId } = useFormField()
</script> </script>
<template> <template>
<Slot <Slot
:id="formItemId" :id="formItemId"
:aria-describedby=" :aria-describedby="!error ? `${formDescriptionId}` : `${formDescriptionId} ${formMessageId}`"
!error ? `${formDescriptionId}` : `${formDescriptionId} ${formMessageId}`
"
:aria-invalid="!!error" :aria-invalid="!!error"
> >
<slot /> <slot />

View file

@ -1,19 +1,16 @@
<script setup> <script setup>
import { useFormField } from "./useFormField"; import { useFormField } from './useFormField'
import { cn } from "@/lib/utils"; import { cn } from '@/lib/utils'
const props = defineProps({ const props = defineProps({
class: { type: null, required: false }, class: { type: null, required: false }
}); })
const { formDescriptionId } = useFormField(); const { formDescriptionId } = useFormField()
</script> </script>
<template> <template>
<p <p :id="formDescriptionId" :class="cn('text-sm text-muted-foreground', props.class)">
:id="formDescriptionId"
:class="cn('text-sm text-muted-foreground', props.class)"
>
<slot /> <slot />
</p> </p>
</template> </template>

View file

@ -1,15 +1,15 @@
<script setup> <script setup>
import { provide } from "vue"; import { provide } from 'vue'
import { useId } from "radix-vue"; import { useId } from 'radix-vue'
import { FORM_ITEM_INJECTION_KEY } from "./injectionKeys"; import { FORM_ITEM_INJECTION_KEY } from './injectionKeys'
import { cn } from "@/lib/utils"; import { cn } from '@/lib/utils'
const props = defineProps({ const props = defineProps({
class: { type: null, required: false }, class: { type: null, required: false }
}); })
const id = useId(); const id = useId()
provide(FORM_ITEM_INJECTION_KEY, id); provide(FORM_ITEM_INJECTION_KEY, id)
</script> </script>
<template> <template>

View file

@ -1,23 +1,20 @@
<script setup> <script setup>
import { useFormField } from "./useFormField"; import { useFormField } from './useFormField'
import { cn } from "@/lib/utils"; import { cn } from '@/lib/utils'
import { Label } from "@/components/ui/label"; import { Label } from '@/components/ui/label'
const props = defineProps({ const props = defineProps({
for: { type: String, required: false }, for: { type: String, required: false },
asChild: { type: Boolean, required: false }, asChild: { type: Boolean, required: false },
as: { type: null, 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> </script>
<template> <template>
<Label <Label :class="cn(error && 'text-destructive', props.class)" :for="formItemId">
:class="cn(error && 'text-destructive', props.class)"
:for="formItemId"
>
<slot /> <slot />
</Label> </Label>
</template> </template>

View file

@ -1,9 +1,9 @@
<script setup> <script setup>
import { ErrorMessage } from "vee-validate"; import { ErrorMessage } from 'vee-validate'
import { toValue } from "vue"; import { toValue } from 'vue'
import { useFormField } from "./useFormField"; import { useFormField } from './useFormField'
const { name, formMessageId } = useFormField(); const { name, formMessageId } = useFormField()
</script> </script>
<template> <template>

View file

@ -1,7 +1,7 @@
export { Form, Field as FormField } from "vee-validate"; export { Form, Field as FormField } from 'vee-validate'
export { default as FormItem } from "./FormItem.vue"; export { default as FormItem } from './FormItem.vue'
export { default as FormLabel } from "./FormLabel.vue"; export { default as FormLabel } from './FormLabel.vue'
export { default as FormControl } from "./FormControl.vue"; export { default as FormControl } from './FormControl.vue'
export { default as FormMessage } from "./FormMessage.vue"; export { default as FormMessage } from './FormMessage.vue'
export { default as FormDescription } from "./FormDescription.vue"; export { default as FormDescription } from './FormDescription.vue'
export { FORM_ITEM_INJECTION_KEY } from "./injectionKeys"; export { FORM_ITEM_INJECTION_KEY } from './injectionKeys'

View file

@ -1 +1 @@
export const FORM_ITEM_INJECTION_KEY = Symbol(); export const FORM_ITEM_INJECTION_KEY = Symbol()

View file

@ -3,27 +3,26 @@ import {
useFieldError, useFieldError,
useIsFieldDirty, useIsFieldDirty,
useIsFieldTouched, useIsFieldTouched,
useIsFieldValid, useIsFieldValid
} from "vee-validate"; } from 'vee-validate'
import { inject } from "vue"; import { inject } from 'vue'
import { FORM_ITEM_INJECTION_KEY } from "./injectionKeys"; import { FORM_ITEM_INJECTION_KEY } from './injectionKeys'
export function useFormField() { export function useFormField() {
const fieldContext = inject(FieldContextKey); const fieldContext = inject(FieldContextKey)
const fieldItemContext = inject(FORM_ITEM_INJECTION_KEY); const fieldItemContext = inject(FORM_ITEM_INJECTION_KEY)
if (!fieldContext) if (!fieldContext) throw new Error('useFormField should be used within <FormField>')
throw new Error("useFormField should be used within <FormField>");
const { name } = fieldContext; const { name } = fieldContext
const id = fieldItemContext; const id = fieldItemContext
const fieldState = { const fieldState = {
valid: useIsFieldValid(name), valid: useIsFieldValid(name),
isDirty: useIsFieldDirty(name), isDirty: useIsFieldDirty(name),
isTouched: useIsFieldTouched(name), isTouched: useIsFieldTouched(name),
error: useFieldError(name), error: useFieldError(name)
}; }
return { return {
id, id,
@ -31,6 +30,6 @@ export function useFormField() {
formItemId: `${id}-form-item`, formItemId: `${id}-form-item`,
formDescriptionId: `${id}-form-item-description`, formDescriptionId: `${id}-form-item-description`,
formMessageId: `${id}-form-item-message`, formMessageId: `${id}-form-item-message`,
...fieldState, ...fieldState
}; }
} }

View file

@ -1,19 +1,19 @@
<script setup> <script setup>
import { useVModel } from "@vueuse/core"; import { useVModel } from '@vueuse/core'
import { cn } from "@/lib/utils"; import { cn } from '@/lib/utils'
const props = defineProps({ const props = defineProps({
defaultValue: { type: [String, Number], required: false }, defaultValue: { type: [String, Number], required: false },
modelValue: { 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, passive: true,
defaultValue: props.defaultValue, defaultValue: props.defaultValue
}); })
</script> </script>
<template> <template>
@ -22,7 +22,7 @@ const modelValue = useVModel(props, "modelValue", emits, {
:class=" :class="
cn( 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', '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
) )
" "
/> />

View file

@ -1 +1 @@
export { default as Input } from "./Input.vue"; export { default as Input } from './Input.vue'

View file

@ -1,20 +1,20 @@
<script setup> <script setup>
import { computed } from "vue"; import { computed } from 'vue'
import { Label } from "radix-vue"; import { Label } from 'radix-vue'
import { cn } from "@/lib/utils"; import { cn } from '@/lib/utils'
const props = defineProps({ const props = defineProps({
for: { type: String, required: false }, for: { type: String, required: false },
asChild: { type: Boolean, required: false }, asChild: { type: Boolean, required: false },
as: { type: null, required: false }, as: { type: null, required: false },
class: { type: null, required: false }, class: { type: null, required: false }
}); })
const delegatedProps = computed(() => { const delegatedProps = computed(() => {
const { class: _, ...delegated } = props; const { class: _, ...delegated } = props
return delegated; return delegated
}); })
</script> </script>
<template> <template>
@ -23,7 +23,7 @@ const delegatedProps = computed(() => {
:class=" :class="
cn( cn(
'text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70', 'text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70',
props.class, props.class
) )
" "
> >

View file

@ -1 +1 @@
export { default as Label } from "./Label.vue"; export { default as Label } from './Label.vue'

View file

@ -1,9 +1,9 @@
<script setup> <script setup>
import { cn } from "@/lib/utils"; import { cn } from '@/lib/utils'
const props = defineProps({ const props = defineProps({
class: { type: null, required: false }, class: { type: null, required: false }
}); })
</script> </script>
<template> <template>

View file

@ -1,9 +1,9 @@
<script setup> <script setup>
import { cn } from "@/lib/utils"; import { cn } from '@/lib/utils'
const props = defineProps({ const props = defineProps({
class: { type: null, required: false }, class: { type: null, required: false }
}); })
</script> </script>
<template> <template>

View file

@ -1,9 +1,9 @@
<script setup> <script setup>
import { cn } from "@/lib/utils"; import { cn } from '@/lib/utils'
const props = defineProps({ const props = defineProps({
class: { type: null, required: false }, class: { type: null, required: false }
}); })
</script> </script>
<template> <template>

View file

@ -1,15 +1,13 @@
<script setup> <script setup>
import { cn } from "@/lib/utils"; import { cn } from '@/lib/utils'
const props = defineProps({ const props = defineProps({
class: { type: null, required: false }, class: { type: null, required: false }
}); })
</script> </script>
<template> <template>
<td <td :class="cn('p-4 align-middle [&:has([role=checkbox])]:pr-0', props.class)">
:class="cn('p-4 align-middle [&:has([role=checkbox])]:pr-0', props.class)"
>
<slot /> <slot />
</td> </td>
</template> </template>

View file

@ -1,29 +1,25 @@
<script setup> <script setup>
import { computed } from "vue"; import { computed } from 'vue'
import TableRow from "./TableRow.vue"; import TableRow from './TableRow.vue'
import TableCell from "./TableCell.vue"; import TableCell from './TableCell.vue'
import { cn } from "@/lib/utils"; import { cn } from '@/lib/utils'
const props = defineProps({ const props = defineProps({
class: { type: null, required: false }, class: { type: null, required: false },
colspan: { type: Number, required: false, default: 1 }, colspan: { type: Number, required: false, default: 1 }
}); })
const delegatedProps = computed(() => { const delegatedProps = computed(() => {
const { class: _, ...delegated } = props; const { class: _, ...delegated } = props
return delegated; return delegated
}); })
</script> </script>
<template> <template>
<TableRow> <TableRow>
<TableCell <TableCell
:class=" :class="cn('p-4 whitespace-nowrap align-middle text-sm text-foreground', props.class)"
cn(
'p-4 whitespace-nowrap align-middle text-sm text-foreground',
props.class
)"
v-bind="delegatedProps" v-bind="delegatedProps"
> >
<div class="flex items-center justify-center py-10"> <div class="flex items-center justify-center py-10">

View file

@ -1,17 +1,13 @@
<script setup> <script setup>
import { cn } from "@/lib/utils"; import { cn } from '@/lib/utils'
const props = defineProps({ const props = defineProps({
class: { type: null, required: false }, class: { type: null, required: false }
}); })
</script> </script>
<template> <template>
<tfoot <tfoot :class="cn('border-t bg-muted/50 font-medium [&>tr]:last:border-b-0', props.class)">
:class="
cn('border-t bg-muted/50 font-medium [&>tr]:last:border-b-0', props.class)
"
>
<slot /> <slot />
</tfoot> </tfoot>
</template> </template>

View file

@ -1,9 +1,9 @@
<script setup> <script setup>
import { cn } from "@/lib/utils"; import { cn } from '@/lib/utils'
const props = defineProps({ const props = defineProps({
class: { type: null, required: false }, class: { type: null, required: false }
}); })
</script> </script>
<template> <template>
@ -11,7 +11,7 @@ const props = defineProps({
:class=" :class="
cn( cn(
'h-12 px-4 text-left align-middle font-medium text-muted-foreground [&:has([role=checkbox])]:pr-0', 'h-12 px-4 text-left align-middle font-medium text-muted-foreground [&:has([role=checkbox])]:pr-0',
props.class, props.class
) )
" "
> >

View file

@ -1,9 +1,9 @@
<script setup> <script setup>
import { cn } from "@/lib/utils"; import { cn } from '@/lib/utils'
const props = defineProps({ const props = defineProps({
class: { type: null, required: false }, class: { type: null, required: false }
}); })
</script> </script>
<template> <template>

View file

@ -1,18 +1,15 @@
<script setup> <script setup>
import { cn } from "@/lib/utils"; import { cn } from '@/lib/utils'
const props = defineProps({ const props = defineProps({
class: { type: null, required: false }, class: { type: null, required: false }
}); })
</script> </script>
<template> <template>
<tr <tr
:class=" :class="
cn( cn('border-b transition-colors hover:bg-muted/50 data-[state=selected]:bg-muted', props.class)
'border-b transition-colors hover:bg-muted/50 data-[state=selected]:bg-muted',
props.class,
)
" "
> >
<slot /> <slot />

View file

@ -1,9 +1,9 @@
export { default as Table } from "./Table.vue"; export { default as Table } from './Table.vue'
export { default as TableBody } from "./TableBody.vue"; export { default as TableBody } from './TableBody.vue'
export { default as TableCell } from "./TableCell.vue"; export { default as TableCell } from './TableCell.vue'
export { default as TableHead } from "./TableHead.vue"; export { default as TableHead } from './TableHead.vue'
export { default as TableHeader } from "./TableHeader.vue"; export { default as TableHeader } from './TableHeader.vue'
export { default as TableFooter } from "./TableFooter.vue"; export { default as TableFooter } from './TableFooter.vue'
export { default as TableRow } from "./TableRow.vue"; export { default as TableRow } from './TableRow.vue'
export { default as TableCaption } from "./TableCaption.vue"; export { default as TableCaption } from './TableCaption.vue'
export { default as TableEmpty } from "./TableEmpty.vue"; export { default as TableEmpty } from './TableEmpty.vue'

View file

@ -1,19 +1,19 @@
<script setup> <script setup>
import { useVModel } from "@vueuse/core"; import { useVModel } from '@vueuse/core'
import { cn } from "@/lib/utils"; import { cn } from '@/lib/utils'
const props = defineProps({ const props = defineProps({
class: { type: null, required: false }, class: { type: null, required: false },
defaultValue: { type: [String, Number], 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, passive: true,
defaultValue: props.defaultValue, defaultValue: props.defaultValue
}); })
</script> </script>
<template> <template>
@ -22,7 +22,7 @@ const modelValue = useVModel(props, "modelValue", emits, {
:class=" :class="
cn( 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', '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
) )
" "
/> />

View file

@ -1 +1 @@
export { default as Textarea } from "./Textarea.vue"; export { default as Textarea } from './Textarea.vue'

View file

@ -1,5 +1,5 @@
<script setup> <script setup>
import { TooltipRoot, useForwardPropsEmits } from "radix-vue"; import { TooltipRoot, useForwardPropsEmits } from 'radix-vue'
const props = defineProps({ const props = defineProps({
defaultOpen: { type: Boolean, required: false }, defaultOpen: { type: Boolean, required: false },
@ -8,11 +8,11 @@ const props = defineProps({
disableHoverableContent: { type: Boolean, required: false }, disableHoverableContent: { type: Boolean, required: false },
disableClosingTrigger: { type: Boolean, required: false }, disableClosingTrigger: { type: Boolean, required: false },
disabled: { type: Boolean, required: false }, disabled: { type: Boolean, required: false },
ignoreNonKeyboardFocus: { type: Boolean, required: false }, ignoreNonKeyboardFocus: { type: Boolean, required: false }
}); })
const emits = defineEmits(["update:open"]); const emits = defineEmits(['update:open'])
const forwarded = useForwardPropsEmits(props, emits); const forwarded = useForwardPropsEmits(props, emits)
</script> </script>
<template> <template>

View file

@ -1,11 +1,11 @@
<script setup> <script setup>
import { computed } from "vue"; import { computed } from 'vue'
import { TooltipContent, TooltipPortal, useForwardPropsEmits } from "radix-vue"; import { TooltipContent, TooltipPortal, useForwardPropsEmits } from 'radix-vue'
import { cn } from "@/lib/utils"; import { cn } from '@/lib/utils'
defineOptions({ defineOptions({
inheritAttrs: false, inheritAttrs: false
}); })
const props = defineProps({ const props = defineProps({
forceMount: { type: Boolean, required: false }, forceMount: { type: Boolean, required: false },
@ -22,18 +22,18 @@ const props = defineProps({
arrowPadding: { type: Number, required: false }, arrowPadding: { type: Number, required: false },
sticky: { type: String, required: false }, sticky: { type: String, required: false },
hideWhenDetached: { type: Boolean, 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 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> </script>
<template> <template>
@ -43,7 +43,7 @@ const forwarded = useForwardPropsEmits(delegatedProps, emits);
:class=" :class="
cn( 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', '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
) )
" "
> >

View file

@ -1,5 +1,5 @@
<script setup> <script setup>
import { TooltipProvider } from "radix-vue"; import { TooltipProvider } from 'radix-vue'
const props = defineProps({ const props = defineProps({
delayDuration: { type: Number, required: false }, delayDuration: { type: Number, required: false },
@ -7,8 +7,8 @@ const props = defineProps({
disableHoverableContent: { type: Boolean, required: false }, disableHoverableContent: { type: Boolean, required: false },
disableClosingTrigger: { type: Boolean, required: false }, disableClosingTrigger: { type: Boolean, required: false },
disabled: { type: Boolean, required: false }, disabled: { type: Boolean, required: false },
ignoreNonKeyboardFocus: { type: Boolean, required: false }, ignoreNonKeyboardFocus: { type: Boolean, required: false }
}); })
</script> </script>
<template> <template>

View file

@ -1,10 +1,10 @@
<script setup> <script setup>
import { TooltipTrigger } from "radix-vue"; import { TooltipTrigger } from 'radix-vue'
const props = defineProps({ const props = defineProps({
asChild: { type: Boolean, required: false }, asChild: { type: Boolean, required: false },
as: { type: null, required: false }, as: { type: null, required: false }
}); })
</script> </script>
<template> <template>

View file

@ -1,4 +1,4 @@
export { default as Tooltip } from "./Tooltip.vue"; export { default as Tooltip } from './Tooltip.vue'
export { default as TooltipContent } from "./TooltipContent.vue"; export { default as TooltipContent } from './TooltipContent.vue'
export { default as TooltipTrigger } from "./TooltipTrigger.vue"; export { default as TooltipTrigger } from './TooltipTrigger.vue'
export { default as TooltipProvider } from "./TooltipProvider.vue"; export { default as TooltipProvider } from './TooltipProvider.vue'

View file

@ -9,14 +9,14 @@ import VueFullPage from 'vue-fullpage.js'
import App from './App.vue' import App from './App.vue'
import router from './router' import router from './router'
import "vue3-openlayers/styles.css"; import 'vue3-openlayers/styles.css'
import OpenLayersMap from "vue3-openlayers"; import OpenLayersMap from 'vue3-openlayers'
const app = createApp(App) const app = createApp(App)
app.use(VueFullPage) app.use(VueFullPage)
app.use(createPinia()) app.use(createPinia())
app.use(router) app.use(router)
app.use(OpenLayersMap); app.use(OpenLayersMap)
app.mount('#app') app.mount('#app')

View file

@ -2,41 +2,39 @@ import { defineStore } from 'pinia'
import { ref } from 'vue' import { ref } from 'vue'
import { API_BASE_URL } from '@/config.js' import { API_BASE_URL } from '@/config.js'
export const useAuthStore = defineStore("auth", () => { export const useAuthStore = defineStore('auth', () => {
const adminToken = ref(""); const adminToken = ref('')
const isAuth = ref(false); const isAuth = ref(false)
const error = ref(false); const error = ref(false)
function login(token) { function login(token) {
adminToken.value = ""; adminToken.value = ''
isAuth.value = false; isAuth.value = false
error.value = false; error.value = false
return fetch(API_BASE_URL + "/admin/auth/check", { return fetch(API_BASE_URL + '/admin/auth/check', {
headers: { headers: {
"X-admin-token": token 'X-admin-token': token
} }
}).then(resp => { }).then((resp) => {
if (resp.ok) { if (resp.ok) {
adminToken.value = token; adminToken.value = token
isAuth.value = true; isAuth.value = true
localStorage.setItem("kektus-summer-admin-token", token) localStorage.setItem('kektus-summer-admin-token', token)
} else { } else {
error.value = true; error.value = true
} }
}) })
} }
function checkFromLocalStorage() { function checkFromLocalStorage() {
const storedToken = localStorage.getItem("kektus-summer-admin-token") const storedToken = localStorage.getItem('kektus-summer-admin-token')
if (storedToken) { if (storedToken) {
return login(storedToken) return login(storedToken)
} }
return Promise.resolve(); return Promise.resolve()
} }
return { adminToken, login, checkFromLocalStorage, isAuth, error } return { adminToken, login, checkFromLocalStorage, isAuth, error }
}) })

View file

@ -1,5 +1,4 @@
<script setup> <script setup>
import { Button } from '@/components/ui/button/index.js' import { Button } from '@/components/ui/button/index.js'
import { CirclePlus, Pencil, Trash, MapPin } from 'lucide-vue-next' import { CirclePlus, Pencil, Trash, MapPin } from 'lucide-vue-next'
import { useAdminPostsStore } from '@/stores/adminPosts.js' import { useAdminPostsStore } from '@/stores/adminPosts.js'
@ -72,6 +71,4 @@ onMounted(() => {
</div> </div>
</template> </template>
<style scoped> <style scoped></style>
</style>

View file

@ -8,7 +8,14 @@ import { Label } from '@/components/ui/label/index.js'
import { toTypedSchema } from '@vee-validate/zod' import { toTypedSchema } from '@vee-validate/zod'
import { z } from 'zod' import { z } from 'zod'
import { onMounted, onUnmounted, ref } from 'vue' 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 { import {
Carousel, Carousel,
CarouselContent, CarouselContent,

View file

@ -1,5 +1,4 @@
<script setup> <script setup>
import { useAuthStore } from '@/stores/auth.js' import { useAuthStore } from '@/stores/auth.js'
import { toTypedSchema } from '@vee-validate/zod' import { toTypedSchema } from '@vee-validate/zod'
import { z } from 'zod' import { z } from 'zod'
@ -14,15 +13,17 @@ import router from '@/router/index.js'
import { useRoute } from 'vue-router' import { useRoute } from 'vue-router'
const authStore = useAuthStore() const authStore = useAuthStore()
const nextView = useRoute().query.redirect; const nextView = useRoute().query.redirect
onMounted(() => { onMounted(() => {
authStore.checkFromLocalStorage().then(onLogin); authStore.checkFromLocalStorage().then(onLogin)
}) })
const formSchema = toTypedSchema(z.object({ const formSchema = toTypedSchema(
token: z.string().min(1) z.object({
})) token: z.string().min(1)
})
)
const form = useForm({ const form = useForm({
validationSchema: formSchema validationSchema: formSchema
}) })
@ -32,16 +33,14 @@ const onSubmit = form.handleSubmit((values) => {
}) })
function onLogin() { function onLogin() {
if (!authStore.isAuth) if (!authStore.isAuth) return
return;
if (nextView) { if (nextView) {
router.push(nextView); router.push(nextView)
} else { } else {
router.push({name: "admin"}); router.push({ name: 'admin' })
} }
} }
</script> </script>
<template> <template>
@ -57,7 +56,6 @@ function onLogin() {
<AlertDescription>Token invalide</AlertDescription> <AlertDescription>Token invalide</AlertDescription>
</Alert> </Alert>
<div id="form-container" ref="formContainer"> <div id="form-container" ref="formContainer">
<form id="login-form" class="space-y-6" @submit="onSubmit"> <form id="login-form" class="space-y-6" @submit="onSubmit">
<FormField v-slot="{ componentField }" name="token"> <FormField v-slot="{ componentField }" name="token">
@ -68,15 +66,11 @@ function onLogin() {
</FormControl> </FormControl>
</FormItem> </FormItem>
</FormField> </FormField>
<Button class="mt-6 w-full" type="submit"> <Button class="mt-6 w-full" type="submit"> Login </Button>
Login
</Button>
</form> </form>
</div> </div>
</div> </div>
</div> </div>
</template> </template>
<style scoped> <style scoped></style>
</style>

View file

@ -1,9 +1,13 @@
<script setup> <script setup>
import { usePostsStore } from '@/stores/posts.js' import { usePostsStore } from '@/stores/posts.js'
import { computed, onMounted, ref } from 'vue' import { computed, onMounted, ref } from 'vue'
import { Camera, Goal, MapPin } from 'lucide-vue-next' 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 { useLocationStore } from '@/stores/location.js'
import { fromLonLat } from 'ol/proj.js' import { fromLonLat } from 'ol/proj.js'
@ -39,16 +43,8 @@ const goalLocations = ref([
<template> <template>
<div class="fixed h-full w-full"> <div class="fixed h-full w-full">
<ol-map <ol-map :loadTilesWhileAnimating="true" :loadTilesWhileInteracting="true" class="h-full w-full">
:loadTilesWhileAnimating="true" <ol-view ref="view" :zoom="3.6" :center="[652293.6169027708, 6425265.202945196]" />
:loadTilesWhileInteracting="true"
class="h-full w-full"
>
<ol-view
ref="view"
:zoom="3.6"
:center="[ 652293.6169027708, 6425265.202945196 ]"
/>
<ol-tile-layer> <ol-tile-layer>
<ol-source-osm /> <ol-source-osm />
@ -56,16 +52,18 @@ const goalLocations = ref([
<ol-scaleline-control /> <ol-scaleline-control />
<ol-overlay <ol-overlay
v-for="post in postStore.posts" :key="post.id" v-for="post in postStore.posts"
:key="post.id"
:position="post.projectedCoordinates" :position="post.projectedCoordinates"
:autoPan="true" :autoPan="true"
> >
<TooltipProvider> <TooltipProvider>
<Tooltip :default-open="true"> <Tooltip :default-open="true">
<TooltipTrigger as-child> <TooltipTrigger as-child>
<RouterLink :to="{ name: 'home', hash: '#post-' + post.id}"> <RouterLink :to="{ name: 'home', hash: '#post-' + post.id }">
<div <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" /> <Camera size="16" />
</div> </div>
</RouterLink> </RouterLink>
@ -85,7 +83,8 @@ const goalLocations = ref([
<Tooltip :default-open="true"> <Tooltip :default-open="true">
<TooltipTrigger as-child> <TooltipTrigger as-child>
<div <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" /> <MapPin size="16" />
</div> </div>
</TooltipTrigger> </TooltipTrigger>
@ -97,7 +96,8 @@ const goalLocations = ref([
</ol-overlay> </ol-overlay>
<ol-overlay <ol-overlay
v-for="loc in goalLocations" :key="loc.name" v-for="loc in goalLocations"
:key="loc.name"
:position="loc.coords" :position="loc.coords"
:autoPan="true" :autoPan="true"
> >
@ -105,7 +105,8 @@ const goalLocations = ref([
<Tooltip> <Tooltip>
<TooltipTrigger as-child> <TooltipTrigger as-child>
<div <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" /> <Goal size="16" />
</div> </div>
</TooltipTrigger> </TooltipTrigger>
@ -119,15 +120,9 @@ const goalLocations = ref([
<ol-vector-layer v-if="postsLinesCoordinates.length > 1"> <ol-vector-layer v-if="postsLinesCoordinates.length > 1">
<ol-source-vector> <ol-source-vector>
<ol-feature ref="profileFeatureRef"> <ol-feature ref="profileFeatureRef">
<ol-geom-line-string <ol-geom-line-string :coordinates="postsLinesCoordinates"></ol-geom-line-string>
:coordinates="postsLinesCoordinates"
></ol-geom-line-string>
<ol-style> <ol-style>
<ol-style-stroke <ol-style-stroke color="white" width="5" :lineDash="[15, 15]"></ol-style-stroke>
color="white"
width="5"
:lineDash="[15, 15]"
></ol-style-stroke>
</ol-style> </ol-style>
</ol-feature> </ol-feature>
</ol-source-vector> </ol-source-vector>
@ -136,5 +131,4 @@ const goalLocations = ref([
</div> </div>
</template> </template>
<style scoped> <style scoped></style>
</style>

View file

@ -32,8 +32,7 @@ instance it still finds a way to be alive and break when changing views????
*/ */
async function initFullpage() { async function initFullpage() {
if (fullPageInit) if (fullPageInit) return
return
fullpageKey.value += 5 fullpageKey.value += 5
fullpageEnable.value = true fullpageEnable.value = true
@ -41,7 +40,9 @@ async function initFullpage() {
try { try {
fullpage.value.init() fullpage.value.init()
} catch (e) { } 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() window.location.reload()
return return
} }
@ -57,7 +58,10 @@ onMounted(() => {
onBeforeUnmount(async () => { onBeforeUnmount(async () => {
console.log('caught post view unmount') 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') window.fullpage_api.destroy('all')
} }
fullpageKey.value++ 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" 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" ref="menu"
> >
<li :data-menuanchor="'post-' + post.id" v-for="post in postsStore.posts" :key="post.id" <li
class="m-2 backdrop-blur-sm rounded-lg bg-black/10 hover:bg-gray-500/10 transition-colors duration-200" :data-menuanchor="'post-' + post.id"
ref="menuItems"> v-for="post in postsStore.posts"
<a :href="'#post-' + post.id" :key="post.id"
class="block text-right px-4 py-3 transition-all duration-300">{{ post.formatedDate }}</a> 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> </li>
</ul> </ul>
</div> </div>
@ -123,7 +134,6 @@ function onLeave(origin, destination, direction, trigger) {
</template> </template>
<style scoped> <style scoped>
#menu li.active, #menu li.active,
#menu li.active:hover { #menu li.active:hover {
background-color: rgba(255, 255, 255, 0.1); background-color: rgba(255, 255, 255, 0.1);

View file

@ -13,10 +13,12 @@ import { API_BASE_URL } from '@/config.js'
const authStore = useAuthStore() const authStore = useAuthStore()
const formSchema = toTypedSchema(z.object({ const formSchema = toTypedSchema(
latitude: z.number(), z.object({
longitude: z.number() latitude: z.number(),
})) longitude: z.number()
})
)
const form = useForm({ const form = useForm({
validationSchema: formSchema validationSchema: formSchema
}) })
@ -33,8 +35,7 @@ const formStatus = ref({
}) })
const onSubmit = form.handleSubmit(async (values) => { const onSubmit = form.handleSubmit(async (values) => {
if (!authStore.isAuth) if (!authStore.isAuth) return
return
console.log('Envoi de la localisation...') console.log('Envoi de la localisation...')
formContainer.value.classList.add('hidden') 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) console.log('POST post API failed: ' + response.statusText + '\n\n' + response.body)
formStatus.value.sending = false formStatus.value.sending = false
formStatus.value.error = true 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') formContainer.value.classList.remove('hidden')
return return
} }
@ -79,7 +81,6 @@ onUnmounted(() => {
navigator.geolocation.clearWatch(geoWatchId) navigator.geolocation.clearWatch(geoWatchId)
} }
}) })
</script> </script>
<template> <template>
@ -133,5 +134,4 @@ onUnmounted(() => {
</div> </div>
</template> </template>
<style scoped> <style scoped></style>
</style>