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
|
|
@ -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"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
|
|
@ -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>
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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>
|
|
||||||
|
|
|
||||||
|
|
@ -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>
|
|
||||||
|
|
|
||||||
|
|
@ -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>
|
||||||
|
|
|
||||||
|
|
@ -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>
|
||||||
|
|
|
||||||
|
|
@ -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>
|
||||||
|
|
|
||||||
|
|
@ -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'
|
||||||
},
|
}
|
||||||
},
|
}
|
||||||
);
|
)
|
||||||
|
|
|
||||||
|
|
@ -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>
|
||||||
|
|
|
||||||
|
|
@ -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>
|
||||||
|
|
|
||||||
|
|
@ -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>
|
||||||
|
|
|
||||||
|
|
@ -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>
|
||||||
|
|
|
||||||
|
|
@ -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>
|
||||||
|
|
|
||||||
|
|
@ -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>
|
||||||
|
|
|
||||||
|
|
@ -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'
|
||||||
|
|
|
||||||
|
|
@ -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>
|
||||||
|
|
|
||||||
|
|
@ -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 />
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
)
|
)
|
||||||
"
|
"
|
||||||
>
|
>
|
||||||
|
|
|
||||||
|
|
@ -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"
|
||||||
|
|
|
||||||
|
|
@ -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"
|
||||||
|
|
|
||||||
|
|
@ -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'
|
||||||
|
|
|
||||||
|
|
@ -1 +1 @@
|
||||||
export {};
|
export {}
|
||||||
|
|
|
||||||
|
|
@ -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 }
|
||||||
|
|
|
||||||
|
|
@ -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 />
|
||||||
|
|
|
||||||
|
|
@ -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>
|
||||||
|
|
|
||||||
|
|
@ -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>
|
||||||
|
|
|
||||||
|
|
@ -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>
|
||||||
|
|
|
||||||
|
|
@ -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>
|
||||||
|
|
|
||||||
|
|
@ -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'
|
||||||
|
|
|
||||||
|
|
@ -1 +1 @@
|
||||||
export const FORM_ITEM_INJECTION_KEY = Symbol();
|
export const FORM_ITEM_INJECTION_KEY = Symbol()
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
)
|
)
|
||||||
"
|
"
|
||||||
/>
|
/>
|
||||||
|
|
|
||||||
|
|
@ -1 +1 @@
|
||||||
export { default as Input } from "./Input.vue";
|
export { default as Input } from './Input.vue'
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
)
|
)
|
||||||
"
|
"
|
||||||
>
|
>
|
||||||
|
|
|
||||||
|
|
@ -1 +1 @@
|
||||||
export { default as Label } from "./Label.vue";
|
export { default as Label } from './Label.vue'
|
||||||
|
|
|
||||||
|
|
@ -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>
|
||||||
|
|
|
||||||
|
|
@ -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>
|
||||||
|
|
|
||||||
|
|
@ -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>
|
||||||
|
|
|
||||||
|
|
@ -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>
|
||||||
|
|
|
||||||
|
|
@ -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">
|
||||||
|
|
|
||||||
|
|
@ -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>
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
)
|
)
|
||||||
"
|
"
|
||||||
>
|
>
|
||||||
|
|
|
||||||
|
|
@ -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>
|
||||||
|
|
|
||||||
|
|
@ -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 />
|
||||||
|
|
|
||||||
|
|
@ -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'
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
)
|
)
|
||||||
"
|
"
|
||||||
/>
|
/>
|
||||||
|
|
|
||||||
|
|
@ -1 +1 @@
|
||||||
export { default as Textarea } from "./Textarea.vue";
|
export { default as Textarea } from './Textarea.vue'
|
||||||
|
|
|
||||||
|
|
@ -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>
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
)
|
)
|
||||||
"
|
"
|
||||||
>
|
>
|
||||||
|
|
|
||||||
|
|
@ -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>
|
||||||
|
|
|
||||||
|
|
@ -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>
|
||||||
|
|
|
||||||
|
|
@ -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'
|
||||||
|
|
|
||||||
|
|
@ -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')
|
||||||
|
|
|
||||||
|
|
@ -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 }
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -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>
|
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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>
|
|
||||||
|
|
|
||||||
|
|
@ -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>
|
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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>
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue