Merge pull request #28 from AlexisNP/features/custom-calendar-creation

LGTM
This commit is contained in:
AlexisNP
2024-08-26 22:23:16 +02:00
committed by GitHub
190 changed files with 2963 additions and 1316 deletions

18
app.vue
View File

@@ -1,12 +1,12 @@
<script setup lang="ts"> <script setup lang="ts">
import { ConfigProvider } from 'radix-vue' import { ConfigProvider } from "radix-vue"
useHead({ useHead({
titleTemplate: (titleChunk) => { titleTemplate: (titleChunk) => {
return titleChunk ? `${titleChunk} — TTTools` : 'TTTools'; return titleChunk ? `${titleChunk} — TTTools` : "TTTools";
}, },
htmlAttrs: { htmlAttrs: {
lang: 'fr' lang: "fr"
}, },
meta: [ meta: [
{ name: "charset", content: "UTF-8" }, { name: "charset", content: "UTF-8" },
@@ -18,14 +18,14 @@ useHead({
{ name: "theme-color", content: "00aba9" }, { name: "theme-color", content: "00aba9" },
{ name: "og:type", content: "tabletop-tools" }, { name: "og:type", content: "tabletop-tools" },
{ name: "og:url", content: "ttt.alexcreates.fr" }, { name: "og:url", content: "ttt.alexcreates.fr" },
{ name: 'robots', content: 'noindex, nofollow'} { name: "robots", content: "noindex, nofollow"}
], ],
link: [ link: [
{ rel: 'apple-touch-icon', sizes: "76x76", href: '/apple-touch-icon.png' }, { rel: "apple-touch-icon", sizes: "76x76", href: "/apple-touch-icon.png" },
{ rel: 'icon', sizes: "32x32", type: 'image/png', href: '/favicon-32x32.png' }, { rel: "icon", sizes: "32x32", type: "image/png", href: "/favicon-32x32.png" },
{ rel: 'icon', sizes: "16x16", type: 'image/png', href: '/favicon-16x16.png' }, { rel: "icon", sizes: "16x16", type: "image/png", href: "/favicon-16x16.png" },
{ rel: 'manifest', href: '/site.webmanifest' }, { rel: "manifest", href: "/site.webmanifest" },
{ rel: 'mask-icon', href: '/safari-pinned-tab.svg', color: '#6595b4' }, { rel: "mask-icon", href: "/safari-pinned-tab.svg", color: "#6595b4" },
] ]
}) })

View File

@@ -1,142 +1,79 @@
<script lang="ts" setup> <script lang="ts" setup>
import { useCalendar } from '@/stores/CalendarStore' import { useCalendar } from "@/stores/CalendarStore"
import { computed, type Component, type ComputedRef } from 'vue' import { computed, type Component, type ComputedRef } from "vue"
import { PhMagnifyingGlass } from '@phosphor-icons/vue' // import { PhMagnifyingGlass } from '@phosphor-icons/vue'
import MonthlyLayout from './state/monthly/Layout.vue' import MonthlyLayout from "./state/monthly/Layout.vue"
import CenturyLayout from './state/centennially/Layout.vue' import CenturyLayout from "./state/centennially/Layout.vue"
import DecadeLayout from './state/decennially/Layout.vue' import DecadeLayout from "./state/decennially/Layout.vue"
import YearLayout from './state/yearly/Layout.vue' import YearLayout from "./state/yearly/Layout.vue"
const route = useRoute() import type { Calendar } from "~/models/CalendarConfig"
const worldId = route.params.id import type { Category } from "~/models/Category"
const { setCalendarId, setMonths, setDefaultDate, currentConfig, selectedDate, jumpToDate } = useCalendar() const props = defineProps<{
const { setEvents, setCategories } = useCalendarEvents() calendarData: Calendar,
const { setCharacters } = useCharacters() categories: Category[]
}>()
const { data: calendar, pending: calPending, refresh: calRefresh } = await useLazyFetch(`/api/calendars/query?world_id=${worldId}`) const { setActiveCalendar } = useCalendar()
const { data: characters, pending: charPending, refresh: charRefresh } = await useLazyFetch(`/api/characters/query?world_id=${worldId}`) setActiveCalendar(props.calendarData, props.categories)
const { data: categories, pending: categoryPending, refresh: categoryRefresh } = await useLazyFetch(`/api/calendars/categories/query`)
if (!calendar.value) { const { currentConfig, jumpToDate, selectedDate } = useCalendar()
await calRefresh()
} else {
if (calendar.value?.data?.id) {
setCalendarId(calendar.value?.data?.id)
}
if (calendar.value?.data?.months) {
setMonths(calendar.value?.data?.months)
}
if (calendar.value?.data?.months) {
setMonths(calendar.value?.data?.months)
}
if (calendar.value?.data?.today) {
setDefaultDate(calendar.value?.data?.today)
}
if (calendar.value?.data?.events) {
setEvents(calendar.value?.data?.events)
}
}
if (!categories.value) { // const { setCharacters } = useCharacters()
await categoryRefresh()
} else {
if (categories.value?.data) {
setCategories(categories.value?.data)
}
}
if (!characters.value) {
await charRefresh()
} else {
if (characters.value?.data) {
setCharacters(characters.value?.data)
}
}
watch(calPending, (newStatus) => {
if (!newStatus) {
if (calendar.value?.data?.id) {
setCalendarId(calendar.value?.data?.id)
}
if (calendar.value?.data?.months) {
setMonths(calendar.value?.data?.months)
}
if (calendar.value?.data?.today) {
setDefaultDate(calendar.value?.data?.today)
}
if (calendar.value?.data?.events) {
setEvents(calendar.value?.data?.events)
}
}
})
watch(categoryPending, (newStatus) => {
if (!newStatus) {
if (categories.value?.data) {
setCategories(categories.value?.data)
}
}
})
watch(charPending, (newStatus) => {
if (!newStatus) {
if (characters.value?.data) {
setCharacters(characters.value?.data)
}
}
})
const currentViewComponent: ComputedRef<Component> = computed<Component>(() => { const currentViewComponent: ComputedRef<Component> = computed<Component>(() => {
switch (currentConfig.viewType) { switch (currentConfig.viewType) {
case 'month': case "month":
return MonthlyLayout return MonthlyLayout
case 'year': case "year":
return YearLayout return YearLayout
case 'decade': case "decade":
return DecadeLayout return DecadeLayout
case 'century': case "century":
default: default:
return CenturyLayout return CenturyLayout
} }
}) })
const { setCurrentMenu } = useUiStore()
onMounted(() => { onMounted(() => {
jumpToDate(selectedDate) jumpToDate(selectedDate)
setCurrentMenu([
{
phIcon: shallowRef(PhMagnifyingGlass),
tooltip: 'Recherche avancée',
action: 'event-search'
}
])
}) })
</script> </script>
<template> <template>
<div class="h-full"> <div class="h-full w-full relative">
<template v-if="calPending || charPending || categoryPending">
<div class="h-full grid place-items-center">
Loading notamment
</div>
</template>
<template v-else>
<div class="h-full grid grid-rows-[auto,1fr]"> <div class="h-full grid grid-rows-[auto,1fr]">
<CalendarMenu /> <CalendarMenu />
<KeepAlive> <component :is="currentViewComponent" />
<component :is="currentViewComponent"/>
</KeepAlive>
</div>
<LazyCalendarSearch /> <CalendarSearch />
<LazyCalendarFormUpdateEvent /> <CalendarFormUpdateEvent />
<LazyCalendarFormDeleteEvent /> <CalendarFormDeleteEvent />
</template> </div>
</div> </div>
</template> </template>
<style lang="scss" scoped>
.screen-move, /* apply transition to moving elements */
.screen-enter-active,
.screen-leave-active {
transition: all .4s ease-out;
}
.screen-enter-from,
.screen-leave-to {
opacity: 0;
}
/* ensure leaving items are taken out of layout flow so that moving
animations can be calculated correctly. */
.screen-leave-active {
position: absolute;
}
</style>

View File

@@ -1,8 +1,8 @@
<script lang="ts" setup> <script lang="ts" setup>
import { storeToRefs } from 'pinia' import { storeToRefs } from "pinia"
import { computed } from 'vue' import { computed } from "vue"
import { PhMapPin } from '@phosphor-icons/vue' import { PhMapPin } from "@phosphor-icons/vue"
const { defaultDate, getFormattedDateTitle, getRelativeString } = useCalendar() const { defaultDate, getFormattedDateTitle, getRelativeString } = useCalendar()
const { selectedDate } = storeToRefs(useCalendar()) const { selectedDate } = storeToRefs(useCalendar())

View File

@@ -1,16 +1,15 @@
<script lang="ts" setup> <script lang="ts" setup>
import { cn } from '@/lib/utils' import { cn } from "@/lib/utils"
import type { RPGDate } from '@/models/Date' import type { RPGDate } from "@/models/Date"
import type { CalendarEvent } from '~/models/CalendarEvent' import type { CalendarEvent } from "~/models/CalendarEvent"
const props = defineProps<{ const props = defineProps<{
event: CalendarEvent event: CalendarEvent
tileDate: RPGDate tileDate: RPGDate
}>() }>()
const { areDatesIdentical } = useCalendar() const { areDatesIdentical, revealEditEventModal, revealDeleteEventModal } = useCalendar()
const { revealEditEventModal, revealDeleteEventModal } = useCalendarEvents() const { lastActiveEvent } = storeToRefs(useCalendar())
const { lastActiveEvent } = storeToRefs(useCalendarEvents())
const spansMultipleDays = computed(() => Boolean(props.event.startDate && props.event.endDate)) const spansMultipleDays = computed(() => Boolean(props.event.startDate && props.event.endDate))
const isStartEvent = computed(() => spansMultipleDays.value && areDatesIdentical(props.tileDate, props.event.startDate)) const isStartEvent = computed(() => spansMultipleDays.value && areDatesIdentical(props.tileDate, props.event.startDate))
@@ -40,12 +39,12 @@ function handleClosePopover() {
onMounted(() => { onMounted(() => {
// Listen for keydown events // Listen for keydown events
window.addEventListener('keydown', (e: KeyboardEvent) => { window.addEventListener("keydown", (e: KeyboardEvent) => {
// If the popover isn't opened, this is not the event we're trying to delete, so return // If the popover isn't opened, this is not the event we're trying to delete, so return
if (!isPopoverDetailsOpen.value) return if (!isPopoverDetailsOpen.value) return
// If the key isn't the delete one, return // If the key isn't the delete one, return
if (e.key !== 'Delete') return if (e.key !== "Delete") return
handleDelete() handleDelete()
}) })

View File

@@ -1,8 +1,8 @@
<script lang="ts" setup> <script lang="ts" setup>
import { cn } from '@/lib/utils' import { cn } from "@/lib/utils"
import type { RPGDate } from '@/models/Date' import type { RPGDate } from "@/models/Date"
import type { CalendarEvent } from '@/models/CalendarEvent' import type { CalendarEvent } from "@/models/CalendarEvent"
import { useCalendar } from '@/stores/CalendarStore' import { useCalendar } from "@/stores/CalendarStore"
import { import {
PhHourglassMedium, PhHourglassMedium,
@@ -12,11 +12,10 @@ import {
PhMapPinArea, PhMapPinArea,
PhDotsThreeOutlineVertical, PhDotsThreeOutlineVertical,
PhEye PhEye
} from '@phosphor-icons/vue' } from "@phosphor-icons/vue"
const { defaultDate, getFormattedDateTitle, jumpToDate, getRelativeString } = useCalendar() const { defaultDate, getFormattedDateTitle, jumpToDate, getRelativeString, revealEditEventModal, revealDeleteEventModal } = useCalendar()
const { revealEditEventModal, revealDeleteEventModal } = useCalendarEvents() const { lastActiveEvent } = storeToRefs(useCalendar())
const { lastActiveEvent } = storeToRefs(useCalendarEvents())
const props = defineProps<{ const props = defineProps<{
event: CalendarEvent event: CalendarEvent
@@ -28,16 +27,16 @@ const props = defineProps<{
// Ref for the popover // Ref for the popover
const eventDetails = ref<HTMLElement>() const eventDetails = ref<HTMLElement>()
const emit = defineEmits(['query:close-popover']) const emit = defineEmits(["query:close-popover"])
const dateDifference: string = getRelativeString(defaultDate, props.event.startDate) const dateDifference: string = getRelativeString(defaultDate, props.event.startDate)
const dateDuration: string | null = props.event.endDate const dateDuration: string | null = props.event.endDate
? getRelativeString(props.event.startDate, props.event.endDate, 'compact') ? getRelativeString(props.event.startDate, props.event.endDate, "compact")
: null : null
function handleJumpToDate(date: RPGDate) { function handleJumpToDate(date: RPGDate) {
jumpToDate(date) jumpToDate(date)
emit('query:close-popover') emit("query:close-popover")
} }
/** /**
@@ -136,7 +135,7 @@ function deployDeleteModal() {
</template> </template>
</div> </div>
<menu class="absolute top-4 right-4"> <menu class="absolute top-4 right-4" :class="cn({ 'top-6': event.hidden })">
<UiPopover v-model:open="commandMenuOpened"> <UiPopover v-model:open="commandMenuOpened">
<UiPopoverTrigger as-child> <UiPopoverTrigger as-child>
<UiButton size="icon" variant="ghost"> <UiButton size="icon" variant="ghost">

View File

@@ -1,7 +1,7 @@
<script lang="ts" setup> <script lang="ts" setup>
import { useCalendar } from '@/stores/CalendarStore' import { useCalendar } from "@/stores/CalendarStore"
import { PhMagnifyingGlass } from '@phosphor-icons/vue' import { PhMagnifyingGlass } from "@phosphor-icons/vue"
const { revealAdvancedSearch } = useCalendar() const { revealAdvancedSearch } = useCalendar()
</script> </script>
@@ -29,7 +29,9 @@ const { revealAdvancedSearch } = useCalendar()
</UiButton> </UiButton>
</li> </li>
<li> <li>
<ClientOnly>
<CalendarSwitch /> <CalendarSwitch />
</ClientOnly>
</li> </li>
</menu> </menu>
</div> </div>

View File

@@ -1,13 +1,13 @@
<script lang="ts" setup> <script lang="ts" setup>
import { computed, type ComputedRef } from 'vue' import { computed, type ComputedRef } from "vue"
import { useCalendar } from '@/stores/CalendarStore' import { useCalendar } from "@/stores/CalendarStore"
import { import {
PhCaretDoubleLeft, PhCaretDoubleLeft,
PhCaretDoubleRight, PhCaretDoubleRight,
PhCaretLeft, PhCaretLeft,
PhCaretRight PhCaretRight
} from '@phosphor-icons/vue' } from "@phosphor-icons/vue"
interface DirectionLabels { interface DirectionLabels {
pastFar: string pastFar: string
@@ -16,126 +16,126 @@ interface DirectionLabels {
futureFar: string futureFar: string
} }
const { currentConfig, decrementMonth, incrementMonth, decrementYear, incrementYear } = const { currentConfig, decrementViewMonth, incrementViewMonth, decrementViewYear, incrementViewYear } =
useCalendar() useCalendar()
const activeDirectionLabels: ComputedRef<DirectionLabels> = computed(() => { const activeDirectionLabels: ComputedRef<DirectionLabels> = computed(() => {
switch (currentConfig.viewType) { switch (currentConfig.viewType) {
case 'month': case "month":
return { return {
pastFar: 'Année précédente', pastFar: "Année précédente",
pastNear: 'Mois précédent', pastNear: "Mois précédent",
futureNear: 'Mois suivant', futureNear: "Mois suivant",
futureFar: 'Année suivante' futureFar: "Année suivante"
} }
case 'year': case "year":
return { return {
pastFar: 'Décennie précédente', pastFar: "Décennie précédente",
pastNear: 'Année précédente', pastNear: "Année précédente",
futureNear: 'Année suivante', futureNear: "Année suivante",
futureFar: 'Décennie suivante' futureFar: "Décennie suivante"
} }
case 'decade': case "decade":
return { return {
pastFar: 'Siècle précédent', pastFar: "Siècle précédent",
pastNear: 'Décennie précédente', pastNear: "Décennie précédente",
futureNear: 'Décennie suivante', futureNear: "Décennie suivante",
futureFar: 'Siècle suivant' futureFar: "Siècle suivant"
} }
case 'century': case "century":
default: default:
return { return {
pastFar: 'Millénaire précédent', pastFar: "Millénaire précédent",
pastNear: 'Siècle précédent', pastNear: "Siècle précédent",
futureNear: 'Siècle suivant', futureNear: "Siècle suivant",
futureFar: 'Millénaire suivant' futureFar: "Millénaire suivant"
} }
} }
}) })
function toPastFar(): void { function toPastFar(): void {
switch (currentConfig.viewType) { switch (currentConfig.viewType) {
case 'month': case "month":
decrementYear() decrementViewYear()
break break
case 'year': case "year":
decrementYear(10) decrementViewYear(10)
break break
case 'decade': case "decade":
decrementYear(100) decrementViewYear(100)
break break
case 'century': case "century":
default: default:
decrementYear(1000) decrementViewYear(1000)
break break
} }
} }
function toPastNear(): void { function toPastNear(): void {
switch (currentConfig.viewType) { switch (currentConfig.viewType) {
case 'month': case "month":
decrementMonth() decrementViewMonth()
break break
case 'year': case "year":
decrementYear() decrementViewYear()
break break
case 'decade': case "decade":
decrementYear(10) decrementViewYear(10)
break break
case 'century': case "century":
default: default:
decrementYear(100) decrementViewYear(100)
break break
} }
} }
function toFutureNear(): void { function toFutureNear(): void {
switch (currentConfig.viewType) { switch (currentConfig.viewType) {
case 'month': case "month":
incrementMonth() incrementViewMonth()
break break
case 'year': case "year":
incrementYear() incrementViewYear()
break break
case 'decade': case "decade":
incrementYear(10) incrementViewYear(10)
break break
case 'century': case "century":
default: default:
incrementYear(100) incrementViewYear(100)
break break
} }
} }
function toFutureFar(): void { function toFutureFar(): void {
switch (currentConfig.viewType) { switch (currentConfig.viewType) {
case 'month': case "month":
incrementYear() incrementViewYear()
break break
case 'year': case "year":
incrementYear(10) incrementViewYear(10)
break break
case 'decade': case "decade":
incrementYear(100) incrementViewYear(100)
break break
case 'century': case "century":
default: default:
incrementYear(1000) incrementViewYear(1000)
break break
} }
} }

View File

@@ -1,25 +1,22 @@
<script lang="ts" setup> <script lang="ts" setup>
import { type RPGDate } from '@/models/Date' import { type RPGDate } from "@/models/Date"
import { useCalendar } from '@/stores/CalendarStore'
import { useCalendarEvents } from '@/stores/EventStore'
import { PhArrowLineLeft, PhArrowLineRight } from '@phosphor-icons/vue' import { PhArrowLineLeft, PhArrowLineRight } from "@phosphor-icons/vue"
const { currentDate, currentConfig, jumpToDate } = useCalendar() const { currentDate, currentConfig, jumpToDate, getRelativeEventFromDate } = useCalendar()
const { getRelativeEventFromDate } = useCalendarEvents()
function handleGotoPreviousEventPage(position: 'next' | 'prev' = 'next') { function handleGotoPreviousEventPage(position: "next" | "prev" = "next") {
let fromDate: RPGDate let fromDate: RPGDate
// To modify, obviously // To modify, obviously
const daysPerMonth = 32 const daysPerMonth = 32
const monthsPerYear = 10 const monthsPerYear = 10
const toDay = position === 'next' ? daysPerMonth : 1 const toDay = position === "next" ? daysPerMonth : 1
const toMonth = position === 'next' ? monthsPerYear : 0 const toMonth = position === "next" ? monthsPerYear : 0
switch (currentConfig.viewType) { switch (currentConfig.viewType) {
case 'month': case "month":
fromDate = { fromDate = {
day: toDay, day: toDay,
month: currentDate.currentMonth, month: currentDate.currentMonth,
@@ -27,7 +24,7 @@ function handleGotoPreviousEventPage(position: 'next' | 'prev' = 'next') {
} }
break break
case 'year': case "year":
fromDate = { fromDate = {
day: toDay, day: toDay,
month: toMonth, month: toMonth,
@@ -35,7 +32,7 @@ function handleGotoPreviousEventPage(position: 'next' | 'prev' = 'next') {
} }
break break
case 'decade': case "decade":
fromDate = { fromDate = {
day: toDay, day: toDay,
month: currentDate.currentMonth, month: currentDate.currentMonth,
@@ -43,7 +40,7 @@ function handleGotoPreviousEventPage(position: 'next' | 'prev' = 'next') {
} }
break break
case 'century': case "century":
default: default:
fromDate = { fromDate = {
day: toDay, day: toDay,

View File

@@ -1,11 +1,9 @@
<script lang="ts" setup> <script lang="ts" setup>
import { useCalendar } from '@/stores/CalendarStore' import { storeToRefs } from "pinia"
import { storeToRefs } from 'pinia' import { computed } from "vue"
import { computed } from 'vue'
const { defaultDate, areDatesIdentical } = useCalendar() const { defaultDate, areDatesIdentical, jumpToDefaultDate, getFormattedDateTitle } = useCalendar()
const { selectedDate } = storeToRefs(useCalendar()) const { selectedDate } = storeToRefs(useCalendar())
const { jumpToDefaultDate, getFormattedDateTitle } = useCalendar()
const defaultDateFormatted: string = getFormattedDateTitle(defaultDate, true) const defaultDateFormatted: string = getFormattedDateTitle(defaultDate, true)

View File

@@ -1,7 +1,7 @@
<script setup lang="ts"> <script setup lang="ts">
import { useCalendar } from '@/stores/CalendarStore' import { useCalendar } from "@/stores/CalendarStore"
import { PhCalendarBlank } from '@phosphor-icons/vue' import { PhCalendarBlank } from "@phosphor-icons/vue"
import { computed } from 'vue' import { computed } from "vue"
const { currentConfig, viewTypeOptions, getViewTypeTitle, setViewType } = useCalendar() const { currentConfig, viewTypeOptions, getViewTypeTitle, setViewType } = useCalendar()

View File

@@ -1,3 +1,3 @@
export const searchUnifier = new RegExp(/[^a-zA-Z0-9\-'']/g) export const searchUnifier = new RegExp(/[^a-zA-Z0-9\-'']/g)
export type SearchMode = 'characters' | 'events' | undefined export type SearchMode = "characters" | "events" | undefined

View File

@@ -0,0 +1,44 @@
<script lang="ts" setup>
import { PhX } from "@phosphor-icons/vue";
import type { World } from "~/models/World";
defineProps<{
world: World,
modalState?: boolean
}>()
const calendarSkeletonName = ref<string>("")
function onChangedName(newName: string) {
calendarSkeletonName.value = newName
}
const emit = defineEmits(["on-close"])
function handleClose() {
emit("on-close")
}
</script>
<template>
<UiAlertDialog :open="modalState">
<UiAlertDialogContent class="grid grid-rows-[auto_1fr_auto] items-start min-h-[66vh] max-w-4xl gap-6">
<UiAlertDialogTitle>
<span class="text-2xl">
<strong class="font-bold">{{ world.name }}</strong>
<span class="opacity-30"> </span>
<span v-if="calendarSkeletonName">
{{ calendarSkeletonName }}
</span>
<span v-else>Nouveau calendrier</span>
</span>
</UiAlertDialogTitle>
<UiButton size="icon" variant="ghost" class="absolute top-4 right-4" title="Fermer la fenêtre" @click="handleClose">
<PhX size="20" />
</UiButton>
<CalendarFormCreate @on-changed-name="onChangedName" @on-close="handleClose" />
</UiAlertDialogContent>
</UiAlertDialog>
</template>

View File

@@ -0,0 +1,95 @@
<script lang="ts" setup>
import { PhCircleNotch } from "@phosphor-icons/vue";
import type { Calendar } from "~/models/CalendarConfig";
const props = defineProps<{
modalState: boolean,
calendar: Calendar | null
}>()
const isLoading = ref<boolean>(false)
const emit = defineEmits(["on-close"])
async function handleAction(): Promise<void> {
if (isLoading.value) return
if (!props.calendar) return
isLoading.value = true
try {
await $fetch(`/api/calendars/${props.calendar.id}`, { method: "DELETE" })
// isDeleteEventModalOpen.value = false
} catch (err) {
if (err instanceof Error) {
// formErrors.message = err.message
}
} finally {
isLoading.value = false
}
}
/**
* Prevents the modal from closing if's still loading
*
* @param e The closing event (can be keydown or click)
*/
function handleClosing() {
if (!isLoading.value) {
emit("on-close")
}
}
</script>
<template>
<UiAlertDialog :open="modalState">
<UiAlertDialogContent
:disable-outside-pointer-events="true"
:trap-focus="true"
class="min-w-96 bg-slate-900 border-slate-800"
@escape-key-down="handleClosing"
@focus-outside="handleClosing"
@interact-outside="handleClosing"
@pointer-down-outside="handleClosing"
>
<UiAlertDialogTitle> Êtes-vous sûr de supprimer ce calendrier ?</UiAlertDialogTitle>
<UiAlertDialogDescription>
Les évènements ne seront plus accessibles et vous ne pourrez plus récupérer les données !
</UiAlertDialogDescription>
<form @submit.prevent="handleAction">
<div class="grid grid-cols-2 gap-y-4">
<div class="text-red-500 ml-8">
<span class="text-sm">
<!-- {{ formErrors.message }} -->
</span>
</div>
</div>
<footer class="flex gap-2 justify-between">
<UiButton type="button" size="sm" variant="ghost" @click="handleClosing">
Retour
</UiButton>
<div class="flex gap-2 justify-end">
<Transition name="fade-delay">
<UiButton v-if="isLoading" type="button" size="sm" variant="destructive">
Annuler
</UiButton>
</Transition>
<UiButton v-if="calendar" size="sm" variant="destructive" :disabled="isLoading">
<Transition name="fade">
<PhCircleNotch v-if="isLoading" size="20" class="animate-spin"/>
</Transition>
Supprimer "{{ calendar?.name }}"
</UiButton>
</div>
</footer>
</form>
</UiAlertDialogContent>
</UiAlertDialog>
</template>

View File

@@ -0,0 +1,132 @@
<script lang="ts" setup>
import type { Calendar } from "~/models/CalendarConfig";
import { PhAlarm, PhCalendarDots, PhCircleNotch, PhWrench } from "@phosphor-icons/vue";
const defaultSkeleton: Calendar = { name: "", today: { day: 1, month: 0, year: 0 }, months: [], events: []}
const calendarSkeleton = ref<Calendar>({ ...defaultSkeleton })
onMounted(() => {
calendarSkeleton.value = { ...defaultSkeleton }
})
type FormTabs = "global" | "months" | "today"
const activeTab = ref<FormTabs>("global")
/**
* === Current date ===
*/
// If the months data change, just reset today's month
// This is a failsafe mainly because of 1) month positions and 2) month names
watch(calendarSkeleton.value.months, () => {
calendarSkeleton.value.today.month = 0
}, { deep: true })
/**
* === Form Validation ===
*/
/** Whether the skeleton has valid month data */
const validSkeletonMonths = computed(() => calendarSkeleton.value.months.length > 0)
/** Whether the skeleton has a valid name */
const validSkeletonGeneral = computed(() => calendarSkeleton.value.name)
/** Whether all the data checks above are a-ok */
const validSkeleton = computed(() => validSkeletonGeneral.value && validSkeletonMonths.value)
/** Send the data to the store for validation */
const isCreatingCalendar = ref<boolean>(false)
async function handleSubmit() {
try {
isCreatingCalendar.value = true
await $fetch("/api/calendars/create", { method: "POST", body: {...calendarSkeleton.value, worldId: 1 } })
emit("on-close")
} catch (err) {
console.log(err)
} finally {
isCreatingCalendar.value = false
}
}
/**
* === Watch for name changes to display above ===
*/
const emit = defineEmits<{
// eslint-disable-next-line no-unused-vars
(e: "on-changed-name", calendarName: string): void
// eslint-disable-next-line no-unused-vars
(e: "on-close"): void
}>()
/** Hook to emit a debounced event for the changed skeleton name */
const handleNameChange = useDebounceFn(() => {
emit("on-changed-name", calendarSkeleton.value.name)
}, 400)
function handleFormCancel() {
emit("on-close")
}
</script>
<template>
<template v-if="calendarSkeleton">
<form class="h-full grid grid-rows-[1fr_auto]" @submit.prevent="handleSubmit">
<UiTabs v-model:model-value="activeTab">
<UiTabsList class="grid w-full grid-cols-3 mb-4">
<UiTabsTrigger value="global" class="font-bold">
<div class="flex items-center gap-1">
<PhWrench size="18" weight="fill" />
Général
</div>
</UiTabsTrigger>
<UiTabsTrigger value="months" class="font-bold">
<div class="flex items-center gap-1">
<PhCalendarDots size="18" weight="fill" />
Mois de l'année
</div>
</UiTabsTrigger>
<UiTabsTrigger value="today" class="font-bold">
<div class="flex items-center gap-1">
<PhAlarm size="18" weight="fill" />
Aujourd'hui
</div>
</UiTabsTrigger>
</UiTabsList>
<UiTabsContent value="global">
<input
id="new-calendar-name"
v-model="calendarSkeleton.name"
type="text"
name="new-calendar-name"
required
placeholder="Titre"
class="w-full -my-1 py-2 -mx-1 px-1 text-xl border-b-[1px] bg-transparent focus-visible:outline-none focus-visible:border-blue-600"
@input="handleNameChange"
>
</UiTabsContent>
<UiTabsContent value="months">
<CalendarInputMonthList v-model:model-value="calendarSkeleton.months" />
</UiTabsContent>
<UiTabsContent value="today">
<CalendarInputTodaySelect v-model:model-value="calendarSkeleton.today" :available-months="calendarSkeleton.months"/>
</UiTabsContent>
</UiTabs>
<footer class="flex justify-end gap-2 mt-6">
<UiButton type="button" variant="destructive" @click="handleFormCancel">
Annuler
</UiButton>
<UiButton type="submit" :disabled="!validSkeleton || isCreatingCalendar">
<Transition name="fade">
<PhCircleNotch v-if="isCreatingCalendar" size="20" class="opacity-50 animate-spin"/>
</Transition>
Créer
</UiButton>
</footer>
</form>
</template>
</template>

View File

@@ -1,9 +1,9 @@
<script lang="ts" setup> <script lang="ts" setup>
import type { RPGDate } from '~/models/Date'; import type { RPGDate } from "~/models/Date";
import { PhAlarm, PhCircleNotch, PhEye, PhEyeClosed, PhMapPinArea, PhTag } from '@phosphor-icons/vue' import { PhAlarm, PhCircleNotch, PhEye, PhEyeClosed, PhMapPinArea, PhTag } from "@phosphor-icons/vue"
const { eventSkeleton, operationInProgress } = storeToRefs(useCalendarEvents()) const { eventSkeleton, operationInProgress } = storeToRefs(useCalendar())
const { resetSkeleton, submitSkeleton, cancelLatestRequest } = useCalendarEvents() const { resetSkeleton, submitSkeleton, cancelLatestRequest } = useCalendar()
const popoverOpen = ref(false) const popoverOpen = ref(false)
const isLoading = ref(false) const isLoading = ref(false)
@@ -104,7 +104,8 @@ function handleCancel() {
name="new-event-title" name="new-event-title"
required required
placeholder="Titre de l'évènement" placeholder="Titre de l'évènement"
class="w-full -my-1 py-1 -mx-1 px-1 text-lg border-b-[1px] bg-transparent focus-visible:outline-none focus-visible:border-blue-600"> class="w-full -my-1 py-1 -mx-1 px-1 text-lg border-b-[1px] bg-transparent focus-visible:outline-none focus-visible:border-blue-600"
>
</div> </div>
<div class="col-span-2 my-2 pl-8"> <div class="col-span-2 my-2 pl-8">

View File

@@ -1,12 +1,10 @@
<script lang="ts" setup> <script lang="ts" setup>
import { PhCircleNotch } from '@phosphor-icons/vue'; import { PhCircleNotch } from "@phosphor-icons/vue";
const { isDeleteEventModalOpen } = storeToRefs(useCalendarEvents()) const { resetSkeleton, deleteEventFromSkeleton, cancelLatestRequest } = useCalendar()
const { isDeleteEventModalOpen, eventSkeleton, lastActiveEvent } = storeToRefs(useCalendar())
const { resetSkeleton, deleteEventFromSkeleton, cancelLatestRequest } = useCalendarEvents() const isLoading = ref<boolean>(false)
const { eventSkeleton, lastActiveEvent } = storeToRefs(useCalendarEvents())
const isLoading = ref(false)
const formErrors = reactive<{ message: string | null }>({ const formErrors = reactive<{ message: string | null }>({
message: null message: null
@@ -19,7 +17,7 @@ watch(isDeleteEventModalOpen, (hasOpened, _o) => {
} }
}) })
async function handleAction() { async function handleAction(): Promise<void> {
if (isLoading.value) return if (isLoading.value) return
isLoading.value = true isLoading.value = true
@@ -43,7 +41,7 @@ async function handleAction() {
* *
* @param e The closing event (can be keydown or click) * @param e The closing event (can be keydown or click)
*/ */
function handleClosing(e: Event) { function handleClosing(e: Event): void {
if (isLoading.value) { if (isLoading.value) {
e.preventDefault() e.preventDefault()
} }
@@ -54,7 +52,7 @@ function handleClosing(e: Event) {
* *
* Must cancel the abortController in the store, and stop the loading * Must cancel the abortController in the store, and stop the loading
*/ */
function handleCancel() { function handleCancel(): void {
cancelLatestRequest() cancelLatestRequest()
isLoading.value = false isLoading.value = false
} }

View File

@@ -1,11 +1,9 @@
<script lang="ts" setup> <script lang="ts" setup>
import { PhAlarm, PhCircleNotch, PhEye, PhEyeClosed, PhMapPinArea, PhPencilSimpleLine, PhTag } from '@phosphor-icons/vue' import { PhAlarm, PhCircleNotch, PhEye, PhEyeClosed, PhMapPinArea, PhPencilSimpleLine, PhTag } from "@phosphor-icons/vue"
import { VisuallyHidden } from 'radix-vue' import { VisuallyHidden } from "radix-vue"
const { isEditEventModalOpen } = storeToRefs(useCalendarEvents()) const { resetSkeleton, updateEventFromSkeleton, cancelLatestRequest } = useCalendar()
const { eventSkeleton, lastActiveEvent, isEditEventModalOpen } = storeToRefs(useCalendar())
const { resetSkeleton, updateEventFromSkeleton, cancelLatestRequest } = useCalendarEvents()
const { eventSkeleton, lastActiveEvent } = storeToRefs(useCalendarEvents())
const isLoading = ref(false) const isLoading = ref(false)

View File

@@ -1,8 +1,7 @@
<script lang="ts" setup> <script lang="ts" setup>
import { cn } from '@/lib/utils' import type { Category } from "~/models/Category";
import type { Category } from '~/models/Category';
import { PhCaretDown, PhCheck } from '@phosphor-icons/vue'; import { PhCaretDown, PhCheck } from "@phosphor-icons/vue";
const isPopoverOpen = ref<boolean>(false) const isPopoverOpen = ref<boolean>(false)
@@ -17,12 +16,12 @@ watch(modelBuffer.value, () => {
model.value = [ ...modelBuffer.value ] model.value = [ ...modelBuffer.value ]
}) })
const { categories: availableCategories } = useCalendarEvents() const { categories: availableCategories } = useCalendar()
const searchTerm = ref<string>('') const searchTerm = ref<string>("")
const filteredCategories = computed(() => const filteredCategories = computed(() =>
searchTerm.value === '' searchTerm.value === ""
? availableCategories ? availableCategories
: availableCategories.filter((category) => { : availableCategories.filter((category) => {
return category.name.toLowerCase().includes(searchTerm.value.toLowerCase()) return category.name.toLowerCase().includes(searchTerm.value.toLowerCase())
@@ -70,9 +69,6 @@ const filteredCategories = computed(() =>
:key="category.id" :key="category.id"
:value="category" :value="category"
class="cursor-pointer flex justify-between items-center" class="cursor-pointer flex justify-between items-center"
:class="cn({
})"
> >
<span> <span>
{{ category.name }} {{ category.name }}

View File

@@ -1,6 +1,6 @@
<script lang="ts" setup> <script lang="ts" setup>
import { PhCaretDown } from '@phosphor-icons/vue'; import { PhCaretDown } from "@phosphor-icons/vue";
import type { Category } from '~/models/Category'; import type { Category } from "~/models/Category";
const isPopoverOpen = ref<boolean>(false) const isPopoverOpen = ref<boolean>(false)
@@ -10,16 +10,16 @@ const props = defineProps<{
const model = defineModel<Category>() const model = defineModel<Category>()
const { categories: availableCategories } = useCalendarEvents() const { categories: availableCategories } = useCalendar()
const searchTerm = ref<string>('') const searchTerm = ref<string>("")
function handleCatSelect() { function handleCatSelect() {
isPopoverOpen.value = false isPopoverOpen.value = false
} }
const filteredCategories = computed(() => const filteredCategories = computed(() =>
searchTerm.value === '' searchTerm.value === ""
? availableCategories ? availableCategories
: availableCategories.filter((category) => { : availableCategories.filter((category) => {
return category.name.toLowerCase().includes(searchTerm.value.toLowerCase()) return category.name.toLowerCase().includes(searchTerm.value.toLowerCase())

View File

@@ -0,0 +1,135 @@
<script lang="ts" setup>
import { cn } from "~/lib/utils";
import { useSortable } from "@vueuse/integrations/useSortable";
import type { CalendarMonth } from "~/models/CalendarMonth";
import { PhList, PhPlus, PhTrash } from "@phosphor-icons/vue";
const model = defineModel<CalendarMonth[]>({ required: true })
/**
* Input value for new month's name
*/
const monthName: Ref<string | undefined> = ref<string>()
const monthNameRef = ref<HTMLInputElement>()
const { focused: monthNameFocused } = useFocus(monthNameRef)
const validMonthNameDatatypes = ["string"]
const monthNameIsTaken = computed(() => model.value.find(m => m.name === monthName.value))
const validMonthName = computed(() => validMonthNameDatatypes.includes(typeof monthName.value) && !monthNameIsTaken.value)
/**
* Input value for new month's number of days
*/
const monthDays: Ref<number | undefined> = ref<number>()
const monthDaysRef = ref<HTMLInputElement>()
const validMonthDaysDatatypes = ["number"]
const validMonthDays = computed(() => validMonthDaysDatatypes.includes(typeof monthDays.value) && monthDays.value && monthDays.value >= 12)
const validNewMonth = computed(() => validMonthDays.value && validMonthName.value)
/**
* Add current month input data to the model list
*/
function addMonthToModel(): void {
if (!monthDays.value || !monthName.value) return
// Create month object to add
const monthToInsert: CalendarMonth = {
name: monthName.value,
days: monthDays.value,
position: model.value.length
}
model.value.push(monthToInsert)
// Reset form state
monthName.value = ""
monthNameFocused.value = true
}
/**
* Remove a specific month from the model
*
* @param index Index position of the month in the model
*/
function removeMonthFromModel(index: number) {
if (isNaN(index)) return
model.value.splice(index, 1)
}
// Sortable setup
const monthSortableList = ref<HTMLElement | null>(null)
useSortable(monthSortableList, model.value, { animation: 150, handle: ".handle" })
</script>
<template>
<div class="grid md:grid-cols-12 gap-4 items-center">
<div class="md:col-start-2 md:col-span-5">
<UiInput id="new-month-name" ref="monthNameRef" v-model="monthName" type="text" name="newMonthName" placeholder="Nom du mois" :class="cn({ 'border-red-600': monthNameIsTaken })"/>
</div>
<div class="md:col-span-5">
<UiInput id="new-month-days" ref="monthDaysRef" v-model="monthDays" type="number" name="newMonthName" placeholder="Nombre de jours" min="0" step="1" class="invalid:border-red-600" />
</div>
<div class="md:col-span-1">
<UiButton size="icon" class="rounded-full h-8 w-8" :disabled="!validNewMonth" @click.prevent="addMonthToModel">
<PhPlus size="17"/>
</UiButton>
</div>
<div class="md:col-span-full">
<div class="border-[1px] dark:border-slate-800 p-4 rounded-sm" :class="model.length ? 'md:grid md:grid-cols-12 md:gap-4 md:items-center' : ''">
<div v-if="model.length" class="hidden md:block col-span-1">
<ul class="grid gap-y-4 justify-center">
<li v-for="(m, i) in model" :key="`num-${m.name}`">
<UiButton size="icon" variant="secondary" class="h-8 w-8 rounded-full">
<span class="font-bold text-sm">{{ i + 1 }}</span>
</UiButton>
</li>
</ul>
</div>
<div class="md:col-span-11">
<ul ref="monthSortableList" class="grid gap-y-2" :class="model.length ? 'visible' : 'absolute invisible'">
<template v-if="model.length">
<li v-for="(m, i) in model" :key="m.name" class="grid md:grid-cols-12 gap-4 md:items-center text-slate-900 bg-slate-200 rounded-md">
<div class="md:col-span-1 text-right duration-200 ease-out transition transform origin-top-right">
<UiButton type="button" variant="ghost" size="icon" class="handle rounded-full h-8 w-8">
<PhList size="17" />
</UiButton>
</div>
<div class="md:col-span-3">
<div class="font-bold md:pl-2">
{{ m.name }}
</div>
</div>
<div class="md:col-span-2">
<UiInput :id="`month-days-n${i}`" v-model="m.days" class="bg-transparent border-none" type="number" :name="`monthDays-n${i}`" placeholder="Nombre de jours" min="0" />
</div>
<div class="md:col-span-1">
jour(s)
</div>
<div class="md:col-start-12">
<UiTooltipProvider>
<UiTooltip>
<UiTooltipTrigger as-child>
<UiButton type="button" variant="ghost" size="icon" class="rounded-full h-8 w-8" @click="removeMonthFromModel(i)">
<PhTrash size="17" />
</UiButton>
</UiTooltipTrigger>
<UiTooltipContent>
<p>Supprimer {{ m.name }} du calendrier</p>
</UiTooltipContent>
</UiTooltip>
</UiTooltipProvider>
</div>
</li>
</template>
</ul>
</div>
<template v-if="!model.length">
<p class="col-span-12 text-lg text-center italic opacity-50">Aucun mois pour l'instant</p>
</template>
</div>
</div>
</div>
</template>

View File

@@ -1,9 +1,9 @@
<script lang="ts" setup> <script lang="ts" setup>
import type { RPGDate } from '~/models/Date'; import type { RPGDate } from "~/models/Date";
import { import {
PhXCircle PhXCircle
} from '@phosphor-icons/vue' } from "@phosphor-icons/vue"
const model = defineModel<RPGDate | null>() const model = defineModel<RPGDate | null>()
@@ -27,7 +27,7 @@ const inputPlaceholder = computed<string>(() => {
return props.placeholder return props.placeholder
} }
return '' return ""
}) })
const initialDateValue = props.initialDate ? { ...props.initialDate } : null const initialDateValue = props.initialDate ? { ...props.initialDate } : null
@@ -37,7 +37,7 @@ const monthTitle = computed<string>(() => {
return getMonthName(model.value.month) return getMonthName(model.value.month)
} }
return '' return ""
}) })
const hasValue = computed<boolean>(() => !!model.value) const hasValue = computed<boolean>(() => !!model.value)

View File

@@ -0,0 +1,69 @@
<script lang="ts" setup>
import type { CalendarMonth } from "~/models/CalendarMonth";
import type { RPGDate } from "~/models/Date";
import { PhCalendarBlank } from "@phosphor-icons/vue";
const model = defineModel<RPGDate>({ required: true })
const props = defineProps<{
availableMonths: CalendarMonth[]
}>()
/**
*
* @param e The name of today's month
*/
function setTodayMonth(e: string) {
model.value.month = e
}
// When the model changes, get the month index from the month name
watch(model.value, (n, _o) => {
// If the month value is already an index, return early
if (!isNaN(+model.value.month)) return
const monthId = props.availableMonths.findIndex((m) => m.name === n.month)
if (monthId !== -1) {
model.value.month = monthId + 1
}
})
</script>
<template>
<div class="flex gap-2 items-stretch">
<UiInput id="new-month-current-day" v-model="model.day" type="number" name="newMonthCurrentDay" placeholder="Jour" min="1" step="1" class="invalid:border-red-600" />
<UiDropdownMenu>
<UiDropdownMenuTrigger as-child :disabled="props.availableMonths.length < 1">
<UiButton size="sm" variant="secondary">
<PhCalendarBlank size="18" weight="fill" />
<template v-if="props.availableMonths.length < 1">
Aucun mois disponible
</template>
<template v-else-if="model.month && typeof model.month === 'number'">
{{ props.availableMonths[model.month - 1].name }}
</template>
<template v-else>
Choisir le mois
</template>
</UiButton>
</UiDropdownMenuTrigger>
<UiDropdownMenuContent :side="'bottom'" :collision-padding="30">
<UiDropdownMenuLabel>Mois disponibles</UiDropdownMenuLabel>
<UiDropdownMenuSeparator />
<UiDropdownMenuItem
v-for="m in props.availableMonths"
:key="m.name"
@click="setTodayMonth(m.name)"
>
{{ m.name }}
</UiDropdownMenuItem>
</UiDropdownMenuContent>
</UiDropdownMenu>
<UiInput id="new-month-current-day" v-model="model.year" type="number" name="newMonthCurrentYear" placeholder="Année" step="1" class="invalid:border-red-600" />
</div>
</template>

View File

@@ -2,49 +2,46 @@
import { import {
isCharacter, isCharacter,
type Character, type Character,
} from '@/models/Characters' } from "@/models/Characters"
import type { RPGDateOrder } from '@/models/Date' import type { RPGDateOrder } from "@/models/Date"
import { import {
isCalendarEvent, isCalendarEvent,
type CalendarEvent, type CalendarEvent,
} from '~/models/CalendarEvent' } from "~/models/CalendarEvent"
import { useCharacters } from '@/stores/CharacterStore' import { capitalize } from "@/utils/Strings"
import { useCalendarEvents } from '@/stores/EventStore' import { useMagicKeys, useScroll, useStorage, whenever } from "@vueuse/core"
import { capitalize } from '@/utils/Strings' import { computed, ref, watch } from "vue"
import { useMagicKeys, useScroll, useStorage, whenever } from '@vueuse/core' import { searchUnifier, type SearchMode } from "../SearchMode"
import { computed, ref, watch } from 'vue'
import { searchUnifier, type SearchMode } from '../SearchMode'
import { PhClockClockwise, PhClockCounterClockwise, PhMagnifyingGlass } from '@phosphor-icons/vue' import { PhClockClockwise, PhClockCounterClockwise, PhMagnifyingGlass } from "@phosphor-icons/vue"
import { import {
ComboboxAnchor, ComboboxAnchor,
ComboboxInput, ComboboxInput,
ComboboxPortal, ComboboxPortal,
ComboboxRoot, ComboboxRoot,
VisuallyHidden VisuallyHidden
} from 'radix-vue' } from "radix-vue"
import SearchList from './lists/SearchList.vue' import SearchList from "./lists/SearchList.vue"
import type { Category } from '~/models/Category' import type { Category } from "~/models/Category"
const { isAdvancedSearchOpen } = storeToRefs(useCalendar()) const { isAdvancedSearchOpen, allEvents } = storeToRefs(useCalendar())
const { allEvents } = storeToRefs(useCalendarEvents())
const { characters } = storeToRefs(useCharacters()) const { characters } = storeToRefs(useCharacters())
const searchQuery = ref<string>('') const searchQuery = ref<string>("")
// const searchEnough = computed<boolean>(() => searchQuery.value.length >= 2) // const searchEnough = computed<boolean>(() => searchQuery.value.length >= 2)
const selectedEntity = useStorage('se', 'events' as SearchMode) const selectedEntity = useStorage("se", "events" as SearchMode)
// Order // Order
const selectedOrder = ref<RPGDateOrder>('asc') const selectedOrder = ref<RPGDateOrder>("asc")
function setOrderAsc() { function setOrderAsc() {
selectedOrder.value = 'asc' selectedOrder.value = "asc"
resetPage() resetPage()
} }
function setOrderDesc() { function setOrderDesc() {
selectedOrder.value = 'desc' selectedOrder.value = "desc"
resetPage() resetPage()
} }
@@ -68,9 +65,9 @@ const searchResults = computed<(Character | CalendarEvent)[]>(() => {
// Assign data to loop over and filter // Assign data to loop over and filter
// They are assigned this way for readability // They are assigned this way for readability
if (selectedEntity.value === 'events') { if (selectedEntity.value === "events") {
dataToFilter = allEvents.value dataToFilter = allEvents.value
} else if (selectedEntity.value === 'characters') { } else if (selectedEntity.value === "characters") {
dataToFilter = characters.value dataToFilter = characters.value
} else { } else {
dataToFilter = [...allEvents.value, ...characters.value] dataToFilter = [...allEvents.value, ...characters.value]
@@ -83,15 +80,15 @@ const searchResults = computed<(Character | CalendarEvent)[]>(() => {
// Filter calendar events // Filter calendar events
if (isCalendarEvent(item)) { if (isCalendarEvent(item)) {
const queryString = new String(searchQuery.value) const queryString = new String(searchQuery.value)
.replace(searchUnifier, '') .replace(searchUnifier, "")
.toLocaleLowerCase() .toLocaleLowerCase()
const hitTitle = item.title const hitTitle = item.title
.replace(searchUnifier, '') .replace(searchUnifier, "")
.toLocaleLowerCase() .toLocaleLowerCase()
.includes(queryString) .includes(queryString)
const hitDesc = item.description const hitDesc = item.description
?.replace(searchUnifier, '') ?.replace(searchUnifier, "")
.toLocaleLowerCase() .toLocaleLowerCase()
.includes(queryString) .includes(queryString)
@@ -121,11 +118,11 @@ const searchResults = computed<(Character | CalendarEvent)[]>(() => {
// Filter characters // Filter characters
if (isCharacter(item)) { if (isCharacter(item)) {
const queryString = new String(searchQuery.value) const queryString = new String(searchQuery.value)
.replace(searchUnifier, '') .replace(searchUnifier, "")
.toLocaleLowerCase() .toLocaleLowerCase()
const hitTitle = item.name const hitTitle = item.name
.replace(searchUnifier, '') .replace(searchUnifier, "")
.toLocaleLowerCase() .toLocaleLowerCase()
.includes(queryString) .includes(queryString)
@@ -160,7 +157,7 @@ const searchResults = computed<(Character | CalendarEvent)[]>(() => {
* Removes the search query, resets the pagination and removes all selected categories * Removes the search query, resets the pagination and removes all selected categories
*/ */
function resetSearch() { function resetSearch() {
searchQuery.value = '' searchQuery.value = ""
resetPage() resetPage()
selectedCategories.value = [] selectedCategories.value = []
} }
@@ -208,7 +205,7 @@ const currentCategories = computed(() => {
const selectedCategories = ref<(Category)[]>([]) const selectedCategories = ref<(Category)[]>([])
const categoryFilterOpened = ref<boolean>(false) const categoryFilterOpened = ref<boolean>(false)
const searchCategory = ref<string>('') const searchCategory = ref<string>("")
const filteredCategories = computed(() => const filteredCategories = computed(() =>
currentCategories.value.filter((i) => !selectedCategories.value.includes(i)) currentCategories.value.filter((i) => !selectedCategories.value.includes(i))
@@ -220,8 +217,8 @@ const filteredCategories = computed(() =>
* @param e Radix Change Event * @param e Radix Change Event
*/ */
function handleCategorySelect(e: (Category)) { function handleCategorySelect(e: (Category)) {
if (typeof e === 'string') { if (typeof e === "string") {
searchCategory.value = '' searchCategory.value = ""
selectedCategories.value.push(e) selectedCategories.value.push(e)
} }

View File

@@ -1,18 +1,18 @@
<script lang="ts" setup> <script lang="ts" setup>
import type { Character } from '@/models/Characters' import type { Character } from "@/models/Characters"
import type { RPGDate } from '@/models/Date' import type { RPGDate } from "@/models/Date"
import { useCalendar } from '@/stores/CalendarStore' import { useCalendar } from "@/stores/CalendarStore"
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@/components/ui/tooltip' import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/components/ui/tooltip"
import { Button } from '@/components/ui/button' import { Button } from "@/components/ui/button"
import { PhArrowSquareOut, PhPlant, PhSkull } from '@phosphor-icons/vue' import { PhArrowSquareOut, PhPlant, PhSkull } from "@phosphor-icons/vue"
const props = defineProps<{ const props = defineProps<{
character: Character character: Character
}>() }>()
defineEmits<{ defineEmits<{
(e: 'query:date-jump', payload: RPGDate): void (e: "query:date-jump", payload: RPGDate): void
}>() }>()
const { getFormattedDateTitle } = useCalendar() const { getFormattedDateTitle } = useCalendar()

View File

@@ -1,26 +1,23 @@
<script lang="ts" setup> <script lang="ts" setup>
import { cn } from '@/lib/utils' import { cn } from "@/lib/utils"
import type { RPGDate } from '@/models/Date' import type { RPGDate } from "@/models/Date"
import type { CalendarEvent } from '@/models/CalendarEvent' import type { CalendarEvent } from "@/models/CalendarEvent"
import { useCalendar } from '@/stores/CalendarStore'
import { PhArrowSquareOut, PhHourglassMedium, PhAlarm, PhMapPinArea, PhEye } from '@phosphor-icons/vue' import { PhArrowSquareOut, PhHourglassMedium, PhAlarm, PhMapPinArea, PhEye } from "@phosphor-icons/vue"
const props = defineProps<{ const props = defineProps<{
event: CalendarEvent event: CalendarEvent
}>() }>()
defineEmits<{ defineEmits<{
(e: 'query:date-jump', payload: RPGDate): void (e: "query:date-jump", payload: RPGDate): void
}>() }>()
const { getRelativeString } = useCalendar() const { getRelativeString, defaultDate, getFormattedDateTitle } = useCalendar()
const { defaultDate, getFormattedDateTitle } = useCalendar()
const dateDifference: string = getRelativeString(defaultDate, props.event.startDate) const dateDifference: string = getRelativeString(defaultDate, props.event.startDate)
const dateDuration: string | null = props.event.endDate const dateDuration: string | null = props.event.endDate
? getRelativeString(props.event.startDate, props.event.endDate, 'compact') ? getRelativeString(props.event.startDate, props.event.endDate, "compact")
: null : null
</script> </script>
@@ -48,18 +45,32 @@ const dateDuration: string | null = props.event.endDate
</div> </div>
</div> </div>
<div class="mb-1"> <div class="flex gap-2 items-center justify-between mb-1">
<template v-if="!event.endDate"> <template v-if="!event.endDate">
<p class="col-span-2 font-semibold text-sm opacity-75"> <p class="font-semibold text-sm opacity-75">
{{ getFormattedDateTitle(event.startDate, true) }} {{ getFormattedDateTitle(event.startDate, true) }}
</p> </p>
</template> </template>
<template v-else> <template v-else>
<p class="col-span-2 font-semibold text-sm opacity-75"> <p class="font-semibold text-sm opacity-75">
Du {{ getFormattedDateTitle(event.startDate, true) }} au Du {{ getFormattedDateTitle(event.startDate, true) }} au
{{ getFormattedDateTitle(event.endDate, true) }} {{ getFormattedDateTitle(event.endDate, true) }}
</p> </p>
</template> </template>
<div v-if="event.hidden" class="flex justify-end">
<UiTooltipProvider :delay-duration="250">
<UiTooltip>
<UiTooltipTrigger as-child>
<UiBadge class="flex gap-1 border-[1px] border-slate-900 hover:bg-slate-300 hover:opacity-100">
<PhEye size="16" weight="fill" /> Évènement privé
</UiBadge>
</UiTooltipTrigger>
<UiTooltipContent>
<p>Cet évènement est uniquement visible pour vous</p>
</UiTooltipContent>
</UiTooltip>
</UiTooltipProvider>
</div>
</div> </div>
<div class="mb-1 flex gap-x-2 items-center"> <div class="mb-1 flex gap-x-2 items-center">
@@ -100,18 +111,5 @@ const dateDuration: string | null = props.event.endDate
{{ event.description }} {{ event.description }}
</span> </span>
</div> </div>
<UiTooltipProvider v-if="event.hidden" :delay-duration="250">
<UiTooltip>
<UiTooltipTrigger as-child>
<UiBadge class="absolute -top-2 left-2 flex gap-1 border-[1px] border-slate-900 hover:bg-slate-300 hover:opacity-100">
<PhEye size="16" weight="fill" /> Évènement privé
</UiBadge>
</UiTooltipTrigger>
<UiTooltipContent>
<p>Cet évènement est uniquement visible pour vous</p>
</UiTooltipContent>
</UiTooltip>
</UiTooltipProvider>
</button> </button>
</template> </template>

View File

@@ -1,13 +1,13 @@
<script lang="ts" setup> <script lang="ts" setup>
import { isCharacter, type Character } from '@/models/Characters' import { isCharacter, type Character } from "@/models/Characters"
import type { RPGDate, RPGDateOrder } from '@/models/Date' import type { RPGDate, RPGDateOrder } from "@/models/Date"
import { useCalendar } from '@/stores/CalendarStore' import { useCalendar } from "@/stores/CalendarStore"
import { computed } from 'vue' import { computed } from "vue"
import { isCalendarEvent, type CalendarEvent } from '~/models/CalendarEvent' import { isCalendarEvent, type CalendarEvent } from "~/models/CalendarEvent"
import type { SearchMode } from '../../SearchMode' import type { SearchMode } from "../../SearchMode"
import CharacterCallout from './CharacterCallout.vue' import CharacterCallout from "./CharacterCallout.vue"
import EventCallout from './EventCallout.vue' import EventCallout from "./EventCallout.vue"
const props = defineProps<{ const props = defineProps<{
results: (Character | CalendarEvent)[] results: (Character | CalendarEvent)[]
@@ -18,7 +18,7 @@ const props = defineProps<{
limit?: number limit?: number
}>() }>()
const emit = defineEmits(['jumpedToDate']) const emit = defineEmits(["jumpedToDate"])
const { jumpToDate, compareDates } = useCalendar() const { jumpToDate, compareDates } = useCalendar()
@@ -26,7 +26,7 @@ function handleJumpToDate(date?: RPGDate) {
if (!date) return if (!date) return
jumpToDate(date) jumpToDate(date)
emit('jumpedToDate') emit("jumpedToDate")
} }
// Initial sorting of the results // Initial sorting of the results

View File

@@ -1,13 +1,11 @@
<script lang="ts" setup> <script lang="ts" setup>
import type { RPGDate } from '@/models/Date' import type { RPGDate } from "@/models/Date"
import type { CalendarEvent } from '@/models/CalendarEvent' import type { CalendarEvent } from "@/models/CalendarEvent"
import { useCalendar } from '@/stores/CalendarStore' import { useElementBounding } from "@vueuse/core"
import { useCalendarEvents } from '@/stores/EventStore' import { storeToRefs } from "pinia"
import { useElementBounding } from '@vueuse/core' import { computed, ref, type ComputedRef } from "vue"
import { storeToRefs } from 'pinia'
import { computed, ref, type ComputedRef } from 'vue'
import CalendarEventButton from '../../CalendarEvent.vue' import CalendarEventButton from "../../CalendarEvent.vue"
const props = defineProps<{ const props = defineProps<{
date: RPGDate date: RPGDate
@@ -18,8 +16,7 @@ const calendarTile = ref()
const calendarEventsList = ref() const calendarEventsList = ref()
const { defaultDate, selectDate, areDatesIdentical } = useCalendar() const { defaultDate, selectDate, areDatesIdentical } = useCalendar()
const { selectedDate } = storeToRefs(useCalendar()) const { selectedDate, currentEvents } = storeToRefs(useCalendar())
const { currentEvents } = storeToRefs(useCalendarEvents())
/** /**
* All events with a startDate / endDate that starts or ends on the tile * All events with a startDate / endDate that starts or ends on the tile

View File

@@ -1,8 +1,8 @@
<script lang="ts" setup> <script lang="ts" setup>
import { useCalendar } from '@/stores/CalendarStore' import { useCalendar } from "@/stores/CalendarStore"
import { useThrottleFn } from '@vueuse/core' import { useThrottleFn } from "@vueuse/core"
const { currentDate, decrementMonth, incrementMonth } = useCalendar() const { currentDate, decrementViewMonth, incrementViewMonth } = useCalendar()
const { currentMonthData } = storeToRefs(useCalendar()) const { currentMonthData } = storeToRefs(useCalendar())
function handleWheel(e: WheelEvent) { function handleWheel(e: WheelEvent) {
@@ -15,18 +15,19 @@ function handleWheel(e: WheelEvent) {
} }
const moveCalendarLeft = useThrottleFn(() => { const moveCalendarLeft = useThrottleFn(() => {
decrementMonth() decrementViewMonth()
}, 100) }, 100)
const moveCalendarRight = useThrottleFn(() => { const moveCalendarRight = useThrottleFn(() => {
incrementMonth() incrementViewMonth()
}, 100) }, 100)
</script> </script>
<template> <template>
<div class="grid grid-cols-10" @wheel="handleWheel"> <div class="grid grid-cols-10" @wheel="handleWheel">
<template v-if="currentMonthData">
<CalendarStateMonthlyDayTile <CalendarStateMonthlyDayTile
v-for="day in currentMonthData.days" v-for="day in currentMonthData?.days"
:key="`layout-month-grid-${day}`" :key="`layout-month-grid-${day}`"
:date="{ :date="{
day: day, day: day,
@@ -34,5 +35,6 @@ const moveCalendarRight = useThrottleFn(() => {
year: currentDate.currentYear year: currentDate.currentYear
}" }"
/> />
</template>
</div> </div>
</template> </template>

View File

@@ -1,21 +1,16 @@
<script lang="ts" setup> <script lang="ts" setup>
import type { RPGDate } from '@/models/Date' import type { RPGDate } from "@/models/Date"
import { useCalendar } from '@/stores/CalendarStore' import { storeToRefs } from "pinia"
import { useCalendarEvents } from '@/stores/EventStore' import { computed, type ComputedRef } from "vue"
import { storeToRefs } from 'pinia'
import { computed, type ComputedRef } from 'vue'
const { currentDate, defaultDate, selectDate } = useCalendar() const { currentDate, defaultDate, selectDate, areDatesIdentical } = useCalendar()
const { selectedDate } = storeToRefs(useCalendar()) const { selectedDate, currentEvents } = storeToRefs(useCalendar())
const { currentEvents } = storeToRefs(useCalendarEvents())
const props = defineProps<{ const props = defineProps<{
monthNumber: number monthNumber: number
dayNumber: number dayNumber: number
}>() }>()
const { areDatesIdentical } = useCalendar()
const tileDate: ComputedRef<RPGDate> = computed(() => { const tileDate: ComputedRef<RPGDate> = computed(() => {
return { return {
day: props.dayNumber, day: props.dayNumber,

View File

@@ -1,8 +1,8 @@
<script lang="ts" setup> <script lang="ts" setup>
import { useCalendar } from '@/stores/CalendarStore' import { useCalendar } from "@/stores/CalendarStore"
import { useThrottleFn } from '@vueuse/core' import { useThrottleFn } from "@vueuse/core"
const { decrementYear, incrementYear } = useCalendar() const { decrementViewYear, incrementViewYear } = useCalendar()
const { sortedMonths: months } = storeToRefs(useCalendar()) const { sortedMonths: months } = storeToRefs(useCalendar())
function handleWheel(e: WheelEvent) { function handleWheel(e: WheelEvent) {
@@ -15,11 +15,11 @@ function handleWheel(e: WheelEvent) {
} }
const moveCalendarLeft = useThrottleFn(() => { const moveCalendarLeft = useThrottleFn(() => {
decrementYear() decrementViewYear()
}, 100) }, 100)
const moveCalendarRight = useThrottleFn(() => { const moveCalendarRight = useThrottleFn(() => {
incrementYear() incrementViewYear()
}, 100) }, 100)
</script> </script>

View File

@@ -1,5 +1,5 @@
<script lang="ts" setup> <script lang="ts" setup>
import type { CalendarMonth } from '~/models/CalendarMonth'; import type { CalendarMonth } from "~/models/CalendarMonth";
defineProps<{ defineProps<{
month: CalendarMonth month: CalendarMonth

View File

@@ -0,0 +1,30 @@
<script lang="ts" setup>
import { cn } from "~/lib/utils";
interface SpacingProps {
size?: "xs" | "sm" | "md" | "lg" | "xlg" | "2xl" | "3xl"
}
const props = defineProps<SpacingProps>()
let spacingClass: string
switch (props.size) {
case "lg":
spacingClass = "space-y-4"
break;
case "md":
default:
spacingClass = "space-y-2"
break;
}
</script>
<template>
<div
:class="cn(spacingClass)"
>
<slot />
</div>
</template>

View File

@@ -1,18 +1,14 @@
<script lang="ts" setup> <script lang="ts" setup>
import { PhHouse, PhList } from '@phosphor-icons/vue' import { PhGlobeHemisphereWest, PhHouse, PhList } from "@phosphor-icons/vue"
import type { SidebarMenuActionType } from './SidebarProps'; import type { SidebarMenuActionType } from "./SidebarProps";
const route = useRoute()
const isHome = computed<boolean>(() => {
return route.fullPath === '/'
})
const { revealAdvancedSearch } = useCalendar() const { revealAdvancedSearch } = useCalendar()
const { currentMenu } = storeToRefs(useUiStore()) const { currentMenu } = storeToRefs(useUiStore())
const user = useSupabaseUser()
function handleMenuItemAction(actionType: SidebarMenuActionType) { function handleMenuItemAction(actionType: SidebarMenuActionType) {
if (actionType === 'event-search') { if (actionType === "event-search") {
revealAdvancedSearch() revealAdvancedSearch()
} }
} }
@@ -27,8 +23,9 @@ function handleMenuItemAction(actionType: SidebarMenuActionType) {
</UiButton> </UiButton>
</li> </li>
<li v-if="!isHome"> <template v-if="!user">
<UiTooltipProvider :delay-duration="100"> <li>
<UiTooltipProvider :delay-duration="50">
<UiTooltip> <UiTooltip>
<UiTooltipTrigger as-child> <UiTooltipTrigger as-child>
<UiButton variant="ghost" size="icon" class="rounded-full" as-child> <UiButton variant="ghost" size="icon" class="rounded-full" as-child>
@@ -37,15 +34,35 @@ function handleMenuItemAction(actionType: SidebarMenuActionType) {
</RouterLink> </RouterLink>
</UiButton> </UiButton>
</UiTooltipTrigger> </UiTooltipTrigger>
<UiTooltipContent :side="'right'"> <UiTooltipContent :side="'right'" :side-offset="6">
<p>Retourner aux outils</p> <p>Accueil</p>
</UiTooltipContent> </UiTooltipContent>
</UiTooltip> </UiTooltip>
</UiTooltipProvider> </UiTooltipProvider>
</li> </li>
</template>
<template v-else>
<li>
<UiTooltipProvider :delay-duration="50">
<UiTooltip>
<UiTooltipTrigger as-child>
<UiButton variant="ghost" size="icon" class="rounded-full" as-child>
<RouterLink to="/my">
<PhGlobeHemisphereWest size="24" weight="fill" />
</RouterLink>
</UiButton>
</UiTooltipTrigger>
<UiTooltipContent :side="'right'" :side-offset="6">
<p>Mondes</p>
</UiTooltipContent>
</UiTooltip>
</UiTooltipProvider>
</li>
</template>
<li v-for="(item, i) in currentMenu" :key="i"> <li v-for="(item, i) in currentMenu" :key="i">
<UiTooltipProvider :delay-duration="100"> <UiTooltipProvider :delay-duration="50">
<UiTooltip> <UiTooltip>
<UiTooltipTrigger as-child> <UiTooltipTrigger as-child>
<UiButton v-if="item.to" variant="ghost" size="icon" class="rounded-full" as-child> <UiButton v-if="item.to" variant="ghost" size="icon" class="rounded-full" as-child>
@@ -57,7 +74,7 @@ function handleMenuItemAction(actionType: SidebarMenuActionType) {
<component :is="item.phIcon" size="24" weight="fill" /> <component :is="item.phIcon" size="24" weight="fill" />
</UiButton> </UiButton>
</UiTooltipTrigger> </UiTooltipTrigger>
<UiTooltipContent :side="'right'"> <UiTooltipContent :side="'right'" :side-offset="6">
<p>{{ item.tooltip }}</p> <p>{{ item.tooltip }}</p>
</UiTooltipContent> </UiTooltipContent>
</UiTooltip> </UiTooltip>

View File

@@ -3,7 +3,7 @@ import type { ShallowRef } from "vue"
export type SidebarMenuActionType = "event-search" export type SidebarMenuActionType = "event-search"
export interface SidebarMenuItem { export interface SidebarMenuItem {
phIcon: ShallowRef phIcon: ShallowRef // use shallowRef to build phIcon
tooltip: string tooltip: string
action?: SidebarMenuActionType action?: SidebarMenuActionType
to?: string to?: string

View File

@@ -1,13 +1,15 @@
<script lang="ts" setup> <script lang="ts" setup>
import { computed } from 'vue' import { computed } from "vue"
import { PhUserCircle } from '@phosphor-icons/vue' import { PhGear, PhGlobeHemisphereWest, PhLaptop, PhMoon, PhPalette, PhSignOut, PhSun, PhTranslate, PhUserCircle } from "@phosphor-icons/vue"
const router = useRouter() const router = useRouter()
const { preference } = useColorMode()
const { auth } = useSupabaseClient() const { auth } = useSupabaseClient()
const user = useSupabaseUser() const user = useSupabaseUser()
const userMeta = computed(() => user.value?.user_metadata) const userMeta = computed(() => user.value?.user_metadata)
const profileUrl: string = `${useRequestURL().origin}/my/`
const menuOpened = ref<boolean>(false) const menuOpened = ref<boolean>(false)
@@ -19,12 +21,13 @@ watch(user, closeMenu)
async function handleGoogleLogin() { async function handleGoogleLogin() {
try { try {
auth.signInWithOAuth({ auth.signInWithOAuth({
provider: 'google', provider: "google",
options: { options: {
queryParams: { queryParams: {
access_type: 'offline', access_type: "offline",
prompt: 'consent' prompt: "consent"
} },
redirectTo: profileUrl
} }
}) })
} catch (err) { } catch (err) {
@@ -42,17 +45,20 @@ async function handleLogout() {
} }
} }
function gotoProfilePage() { type AvailableRoutes = "/my" | "/my/settings"
router.push({ path: '/profile' })
function pushRoute(to: AvailableRoutes) {
router.push({ path: to })
closeMenu() closeMenu()
} }
</script> </script>
<template> <template>
{{ preference }}
<ClientOnly> <ClientOnly>
<UiPopover v-model:open="menuOpened"> <UiDropdownMenu v-model:open="menuOpened">
<UiPopoverTrigger> <UiDropdownMenuTrigger>
<UiAvatar v-if="user" class="cursor-pointer"> <UiAvatar v-if="user" class="cursor-pointer">
<UiAvatarImage <UiAvatarImage
:src="userMeta?.avatar_url" :src="userMeta?.avatar_url"
@@ -64,20 +70,84 @@ function gotoProfilePage() {
<UiButton v-else variant="outline" size="icon"> <UiButton v-else variant="outline" size="icon">
<PhUserCircle size="18" /> <PhUserCircle size="18" />
</UiButton> </UiButton>
</UiPopoverTrigger> </UiDropdownMenuTrigger>
<UiPopoverContent class="w-fit p-0" :align="'start'" :side="'top'" :collision-padding="20"> <UiDropdownMenuContent class="w-fit p-0" :align="'start'" :side="'top'" :side-offset="10" :align-offset="25" :collision-padding="40">
<UiCommand>
<UiCommandList v-if="user"> <template v-if="user">
<UiCommandGroup :heading="`Connecté en tant que ${user?.email}`"> <p class="p-2 text-xs opacity-75">Connecté en tant que {{ user?.email }}</p>
<UiCommandItem value="profile" @select="gotoProfilePage"> Profil </UiCommandItem>
<UiCommandItem value="logout" @select="handleLogout"> Déconnexion </UiCommandItem> <UiDropdownMenuItem class="flex gap-[.5ch] items-center rounded-none" @click="pushRoute('/my')">
</UiCommandGroup> <PhGlobeHemisphereWest size="20" weight="fill" />
</UiCommandList> <span>Mondes</span>
<UiCommandList v-else> </UiDropdownMenuItem>
<UiCommandItem value="logout" @select="handleGoogleLogin"> Connexion </UiCommandItem>
</UiCommandList> <UiDropdownMenuSeparator />
</UiCommand>
</UiPopoverContent> <UiDropdownMenuSub>
</UiPopover> <UiDropdownMenuSubTrigger class="p-0">
<UiDropdownMenuItem class="flex gap-[.5ch] items-center rounded-none">
<PhPalette size="20" weight="fill" />
<span>Apparence</span>
</UiDropdownMenuItem>
</UiDropdownMenuSubTrigger>
<UiDropdownMenuPortal>
<UiDropdownMenuSubContent>
<UiDropdownMenuItem class="flex gap-[.5ch] items-center rounded-none" @click="$colorMode.preference = 'dark'">
<PhMoon size="20" />
<span>Sombre</span>
</UiDropdownMenuItem>
<UiDropdownMenuItem class="flex gap-[.5ch] items-center rounded-none" @click="$colorMode.preference = 'light'">
<PhSun size="20" />
<span>Clair</span>
</UiDropdownMenuItem>
<UiDropdownMenuItem class="flex gap-[.5ch] items-center rounded-none" @click="$colorMode.preference = 'system'">
<PhLaptop size="20" />
<span>Système</span>
</UiDropdownMenuItem>
</UiDropdownMenuSubContent>
</UiDropdownMenuPortal>
</UiDropdownMenuSub>
<UiDropdownMenuSub>
<UiDropdownMenuSubTrigger class="p-0">
<UiDropdownMenuItem class="flex gap-[.5ch] items-center rounded-none">
<PhTranslate size="20" />
<span>Langage</span>
</UiDropdownMenuItem>
</UiDropdownMenuSubTrigger>
<UiDropdownMenuPortal>
<UiDropdownMenuSubContent>
<UiDropdownMenuSubContent>
<UiDropdownMenuItem class="flex gap-[.5ch] items-center rounded-none">
<span>Français</span>
</UiDropdownMenuItem>
<UiDropdownMenuItem class="flex gap-[.5ch] items-center rounded-none">
<span>English</span>
</UiDropdownMenuItem>
</UiDropdownMenuSubContent>
</UiDropdownMenuSubContent>
</UiDropdownMenuPortal>
</UiDropdownMenuSub>
<UiDropdownMenuSeparator />
<UiDropdownMenuItem class="flex gap-[.5ch] items-center rounded-none" @click="pushRoute('/my/settings')">
<PhGear size="20" weight="fill" />
<span>Compte</span>
</UiDropdownMenuItem>
<UiDropdownMenuItem class="flex gap-[.5ch] items-center rounded-none" @click="handleLogout">
<PhSignOut size="20" weight="fill" />
<span>Déconnexion</span>
</UiDropdownMenuItem>
</template>
<template v-else>
<UiDropdownMenuItem class="flex gap-[.5ch] items-center rounded-none" @click="handleGoogleLogin">
<PhGear size="20" weight="fill" />
<span>Connexion</span>
</UiDropdownMenuItem>
</template>
</UiDropdownMenuContent>
</UiDropdownMenu>
</ClientOnly> </ClientOnly>
</template> </template>

View File

@@ -1,5 +1,5 @@
<script setup lang="ts"> <script setup lang="ts">
import { type AlertDialogEmits, type AlertDialogProps, AlertDialogRoot, useForwardPropsEmits } from 'radix-vue' import { type AlertDialogEmits, type AlertDialogProps, AlertDialogRoot, useForwardPropsEmits } from "radix-vue"
const props = defineProps<AlertDialogProps>() const props = defineProps<AlertDialogProps>()
const emits = defineEmits<AlertDialogEmits>() const emits = defineEmits<AlertDialogEmits>()

View File

@@ -1,10 +1,10 @@
<script setup lang="ts"> <script setup lang="ts">
import { type HTMLAttributes, computed } from 'vue' import { type HTMLAttributes, computed } from "vue"
import { AlertDialogAction, type AlertDialogActionProps } from 'radix-vue' import { AlertDialogAction, type AlertDialogActionProps } from "radix-vue"
import { cn } from '@/lib/utils' import { cn } from "@/lib/utils"
import { buttonVariants } from '@/components/ui/button/index' import { buttonVariants } from "@/components/ui/button/index"
const props = defineProps<AlertDialogActionProps & { class?: HTMLAttributes['class'] }>() const props = defineProps<AlertDialogActionProps & { class?: HTMLAttributes["class"] }>()
const delegatedProps = computed(() => { const delegatedProps = computed(() => {
const { class: _, ...delegated } = props const { class: _, ...delegated } = props

View File

@@ -1,10 +1,10 @@
<script setup lang="ts"> <script setup lang="ts">
import { type HTMLAttributes, computed } from 'vue' import { type HTMLAttributes, computed } from "vue"
import { AlertDialogCancel, type AlertDialogCancelProps } from 'radix-vue' import { AlertDialogCancel, type AlertDialogCancelProps } from "radix-vue"
import { cn } from '@/lib/utils' import { cn } from "@/lib/utils"
import { buttonVariants } from '@/components/ui/button/index' import { buttonVariants } from "@/components/ui/button/index"
const props = defineProps<AlertDialogCancelProps & { class?: HTMLAttributes['class'] }>() const props = defineProps<AlertDialogCancelProps & { class?: HTMLAttributes["class"] }>()
const delegatedProps = computed(() => { const delegatedProps = computed(() => {
const { class: _, ...delegated } = props const { class: _, ...delegated } = props

View File

@@ -1,5 +1,5 @@
<script setup lang="ts"> <script setup lang="ts">
import { type HTMLAttributes, computed } from 'vue' import { type HTMLAttributes, computed } from "vue"
import { import {
AlertDialogContent, AlertDialogContent,
type AlertDialogContentEmits, type AlertDialogContentEmits,
@@ -7,10 +7,10 @@ import {
AlertDialogOverlay, AlertDialogOverlay,
AlertDialogPortal, AlertDialogPortal,
useForwardPropsEmits, useForwardPropsEmits,
} from 'radix-vue' } from "radix-vue"
import { cn } from '@/lib/utils' import { cn } from "@/lib/utils"
const props = defineProps<AlertDialogContentProps & { class?: HTMLAttributes['class'] }>() const props = defineProps<AlertDialogContentProps & { class?: HTMLAttributes["class"] }>()
const emits = defineEmits<AlertDialogContentEmits>() const emits = defineEmits<AlertDialogContentEmits>()
const delegatedProps = computed(() => { const delegatedProps = computed(() => {
@@ -31,7 +31,7 @@ const forwarded = useForwardPropsEmits(delegatedProps, emits)
v-bind="forwarded" v-bind="forwarded"
:class=" :class="
cn( cn(
'fixed left-1/2 top-1/2 z-50 grid w-full max-w-lg -translate-x-1/2 -translate-y-1/2 gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg', 'fixed left-1/2 top-1/2 z-50 grid w-full max-w-3xl -translate-x-1/2 -translate-y-1/2 gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg',
props.class, props.class,
) )
" "

View File

@@ -1,12 +1,12 @@
<script setup lang="ts"> <script setup lang="ts">
import { type HTMLAttributes, computed } from 'vue' import { type HTMLAttributes, computed } from "vue"
import { import {
AlertDialogDescription, AlertDialogDescription,
type AlertDialogDescriptionProps, type AlertDialogDescriptionProps,
} from 'radix-vue' } from "radix-vue"
import { cn } from '@/lib/utils' import { cn } from "@/lib/utils"
const props = defineProps<AlertDialogDescriptionProps & { class?: HTMLAttributes['class'] }>() const props = defineProps<AlertDialogDescriptionProps & { class?: HTMLAttributes["class"] }>()
const delegatedProps = computed(() => { const delegatedProps = computed(() => {
const { class: _, ...delegated } = props const { class: _, ...delegated } = props

View File

@@ -1,9 +1,9 @@
<script setup lang="ts"> <script setup lang="ts">
import type { HTMLAttributes } from 'vue' import type { HTMLAttributes } from "vue"
import { cn } from '@/lib/utils' import { cn } from "@/lib/utils"
const props = defineProps<{ const props = defineProps<{
class?: HTMLAttributes['class'] class?: HTMLAttributes["class"]
}>() }>()
</script> </script>

View File

@@ -1,9 +1,9 @@
<script setup lang="ts"> <script setup lang="ts">
import type { HTMLAttributes } from 'vue' import type { HTMLAttributes } from "vue"
import { cn } from '@/lib/utils' import { cn } from "@/lib/utils"
const props = defineProps<{ const props = defineProps<{
class?: HTMLAttributes['class'] class?: HTMLAttributes["class"]
}>() }>()
</script> </script>

View File

@@ -1,9 +1,9 @@
<script setup lang="ts"> <script setup lang="ts">
import { type HTMLAttributes, computed } from 'vue' import { type HTMLAttributes, computed } from "vue"
import { AlertDialogTitle, type AlertDialogTitleProps } from 'radix-vue' import { AlertDialogTitle, type AlertDialogTitleProps } from "radix-vue"
import { cn } from '@/lib/utils' import { cn } from "@/lib/utils"
const props = defineProps<AlertDialogTitleProps & { class?: HTMLAttributes['class'] }>() const props = defineProps<AlertDialogTitleProps & { class?: HTMLAttributes["class"] }>()
const delegatedProps = computed(() => { const delegatedProps = computed(() => {
const { class: _, ...delegated } = props const { class: _, ...delegated } = props

View File

@@ -1,5 +1,5 @@
<script setup lang="ts"> <script setup lang="ts">
import { AlertDialogTrigger, type AlertDialogTriggerProps } from 'radix-vue' import { AlertDialogTrigger, type AlertDialogTriggerProps } from "radix-vue"
const props = defineProps<AlertDialogTriggerProps>() const props = defineProps<AlertDialogTriggerProps>()
</script> </script>

View File

@@ -1,9 +1,9 @@
export { default as AlertDialog } from './AlertDialog.vue' export { default as AlertDialog } from "./AlertDialog.vue"
export { default as AlertDialogTrigger } from './AlertDialogTrigger.vue' export { default as AlertDialogTrigger } from "./AlertDialogTrigger.vue"
export { default as AlertDialogContent } from './AlertDialogContent.vue' export { default as AlertDialogContent } from "./AlertDialogContent.vue"
export { default as AlertDialogHeader } from './AlertDialogHeader.vue' export { default as AlertDialogHeader } from "./AlertDialogHeader.vue"
export { default as AlertDialogTitle } from './AlertDialogTitle.vue' export { default as AlertDialogTitle } from "./AlertDialogTitle.vue"
export { default as AlertDialogDescription } from './AlertDialogDescription.vue' export { default as AlertDialogDescription } from "./AlertDialogDescription.vue"
export { default as AlertDialogFooter } from './AlertDialogFooter.vue' export { default as AlertDialogFooter } from "./AlertDialogFooter.vue"
export { default as AlertDialogAction } from './AlertDialogAction.vue' export { default as AlertDialogAction } from "./AlertDialogAction.vue"
export { default as AlertDialogCancel } from './AlertDialogCancel.vue' export { default as AlertDialogCancel } from "./AlertDialogCancel.vue"

View File

@@ -1,16 +1,16 @@
<script setup lang="ts"> <script setup lang="ts">
import type { HTMLAttributes } from 'vue' import type { HTMLAttributes } from "vue"
import { AvatarRoot } from 'radix-vue' import { AvatarRoot } from "radix-vue"
import { type AvatarVariants, avatarVariant } from '.' import { type AvatarVariants, avatarVariant } from "."
import { cn } from '@/lib/utils' import { cn } from "@/lib/utils"
const props = withDefaults(defineProps<{ const props = withDefaults(defineProps<{
class?: HTMLAttributes['class'] class?: HTMLAttributes["class"]
size?: AvatarVariants['size'] size?: AvatarVariants["size"]
shape?: AvatarVariants['shape'] shape?: AvatarVariants["shape"]
}>(), { }>(), {
size: 'sm', size: "sm",
shape: 'circle', shape: "circle",
}) })
</script> </script>

View File

@@ -1,5 +1,5 @@
<script setup lang="ts"> <script setup lang="ts">
import { AvatarFallback, type AvatarFallbackProps } from 'radix-vue' import { AvatarFallback, type AvatarFallbackProps } from "radix-vue"
const props = defineProps<AvatarFallbackProps>() const props = defineProps<AvatarFallbackProps>()
</script> </script>

View File

@@ -1,5 +1,5 @@
<script setup lang="ts"> <script setup lang="ts">
import { AvatarImage, type AvatarImageProps } from 'radix-vue' import { AvatarImage, type AvatarImageProps } from "radix-vue"
const props = defineProps<AvatarImageProps>() const props = defineProps<AvatarImageProps>()
</script> </script>

View File

@@ -1,21 +1,21 @@
import { type VariantProps, cva } from 'class-variance-authority' import { type VariantProps, cva } from "class-variance-authority"
export { default as Avatar } from './Avatar.vue' export { default as Avatar } from "./Avatar.vue"
export { default as AvatarImage } from './AvatarImage.vue' export { default as AvatarImage } from "./AvatarImage.vue"
export { default as AvatarFallback } from './AvatarFallback.vue' export { default as AvatarFallback } from "./AvatarFallback.vue"
export const avatarVariant = cva( export const avatarVariant = cva(
'inline-flex items-center justify-center font-normal text-foreground select-none shrink-0 bg-secondary overflow-hidden', "inline-flex items-center justify-center font-normal text-foreground select-none shrink-0 bg-secondary overflow-hidden",
{ {
variants: { variants: {
size: { size: {
sm: 'h-10 w-10 text-xs', sm: "h-10 w-10 text-xs",
base: 'h-16 w-16 text-2xl', base: "h-16 w-16 text-2xl",
lg: 'h-32 w-32 text-5xl', lg: "h-32 w-32 text-5xl",
}, },
shape: { shape: {
circle: 'rounded-full', circle: "rounded-full",
square: 'rounded-md', square: "rounded-md",
}, },
}, },
}, },

View File

@@ -1,11 +1,11 @@
<script setup lang="ts"> <script setup lang="ts">
import type { HTMLAttributes } from 'vue' import type { HTMLAttributes } from "vue"
import { type BadgeVariants, badgeVariants } from '.' import { type BadgeVariants, badgeVariants } from "."
import { cn } from '@/lib/utils' import { cn } from "@/lib/utils"
const props = defineProps<{ const props = defineProps<{
variant?: BadgeVariants['variant'] variant?: BadgeVariants["variant"]
class?: HTMLAttributes['class'] class?: HTMLAttributes["class"]
}>() }>()
</script> </script>

View File

@@ -1,23 +1,23 @@
import { type VariantProps, cva } from 'class-variance-authority' import { type VariantProps, cva } from "class-variance-authority"
export { default as Badge } from './Badge.vue' export { default as Badge } from "./Badge.vue"
export const badgeVariants = cva( export const badgeVariants = cva(
'inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2', "inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2",
{ {
variants: { variants: {
variant: { variant: {
default: default:
'border-transparent bg-primary text-primary-foreground hover:bg-primary/80', "border-transparent bg-primary text-primary-foreground hover:bg-primary/80",
secondary: secondary:
'border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80', "border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80",
destructive: destructive:
'border-transparent bg-destructive text-destructive-foreground hover:bg-destructive/80', "border-transparent bg-destructive text-destructive-foreground hover:bg-destructive/80",
outline: 'text-foreground', outline: "text-foreground",
}, },
}, },
defaultVariants: { defaultVariants: {
variant: 'default', variant: "default",
}, },
}, },
) )

View File

@@ -1,18 +1,18 @@
<script setup lang="ts"> <script setup lang="ts">
import type { HTMLAttributes } from 'vue' import type { HTMLAttributes } from "vue"
import { Primitive, type PrimitiveProps } from 'radix-vue' import { Primitive, type PrimitiveProps } from "radix-vue"
import { type ButtonVariants, buttonVariants } from '.' import { type ButtonVariants, buttonVariants } from "."
import { cn } from '@/lib/utils' import { cn } from "@/lib/utils"
interface Props extends PrimitiveProps { interface Props extends PrimitiveProps {
variant?: ButtonVariants['variant'] variant?: ButtonVariants["variant"]
size?: ButtonVariants['size'] size?: ButtonVariants["size"]
class?: HTMLAttributes['class'] class?: HTMLAttributes["class"]
searchSlash?: boolean searchSlash?: boolean
} }
const props = withDefaults(defineProps<Props>(), { const props = withDefaults(defineProps<Props>(), {
as: 'button' as: "button"
}) })
</script> </script>

View File

@@ -1,30 +1,30 @@
import { type VariantProps, cva } from 'class-variance-authority' import { type VariantProps, cva } from "class-variance-authority"
export { default as Button } from './Button.vue' export { default as Button } from "./Button.vue"
export const buttonVariants = cva( export const buttonVariants = cva(
'inline-flex items-center justify-center gap-1 whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50', "inline-flex items-center justify-center gap-1 whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50",
{ {
variants: { variants: {
variant: { variant: {
default: 'bg-primary text-primary-foreground hover:bg-primary/90', default: "bg-primary text-primary-foreground hover:bg-primary/90",
destructive: 'bg-destructive text-destructive-foreground hover:bg-destructive/90', destructive: "bg-destructive text-destructive-foreground hover:bg-destructive/90",
outline: 'border border-input bg-background hover:bg-accent hover:text-accent-foreground', outline: "border border-input bg-background hover:bg-accent hover:text-accent-foreground",
secondary: 'bg-secondary text-secondary-foreground hover:bg-secondary/80', secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80",
ghost: 'hover:bg-accent hover:text-accent-foreground', ghost: "hover:bg-accent hover:text-accent-foreground",
link: 'text-primary underline-offset-4 hover:underline' link: "text-primary underline-offset-4 hover:underline"
}, },
size: { size: {
default: 'h-10 px-4 py-2', default: "h-10 px-4 py-2",
xs: 'h-7 rounded-sm px-2 text-xs', xs: "h-7 rounded-sm px-2 text-xs",
sm: 'h-9 rounded-md px-3 text-sm', sm: "h-9 rounded-md px-3 text-sm",
lg: 'h-11 rounded-md px-8', lg: "h-11 rounded-md px-8",
icon: 'h-10 w-10' icon: "h-10 w-10"
} }
}, },
defaultVariants: { defaultVariants: {
variant: 'default', variant: "default",
size: 'default' size: "default"
} }
} }
) )

View File

@@ -1,9 +1,9 @@
<script setup lang="ts"> <script setup lang="ts">
import type { HTMLAttributes } from 'vue' import type { HTMLAttributes } from "vue"
import { cn } from '@/lib/utils' import { cn } from "@/lib/utils"
const props = defineProps<{ const props = defineProps<{
class?: HTMLAttributes['class'] class?: HTMLAttributes["class"]
link?: string link?: string
}>() }>()
</script> </script>
@@ -11,7 +11,7 @@ const props = defineProps<{
<template> <template>
<div <div
:class=" :class="
cn('rounded-lg border bg-card text-card-foreground shadow-sm transition-all', props.class, { cn('rounded-lg border bg-card text-card-foreground shadow-sm transition-all isolate', props.class, {
'relative outline outline-2 outline-offset-4 outline-transparent hover:-translate-y-[.2rem]': 'relative outline outline-2 outline-offset-4 outline-transparent hover:-translate-y-[.2rem]':
props.link props.link
}) })
@@ -22,7 +22,7 @@ const props = defineProps<{
<NuxtLink <NuxtLink
v-if="props.link" v-if="props.link"
:to="props.link" :to="props.link"
class="absolute inset-0 focus-visible:outline-none" class="absolute inset-0 z-10 focus-visible:outline-none"
/> />
</div> </div>
</template> </template>

View File

@@ -1,9 +1,9 @@
<script setup lang="ts"> <script setup lang="ts">
import type { HTMLAttributes } from 'vue' import type { HTMLAttributes } from "vue"
import { cn } from '@/lib/utils' import { cn } from "@/lib/utils"
const props = defineProps<{ const props = defineProps<{
class?: HTMLAttributes['class'] class?: HTMLAttributes["class"]
}>() }>()
</script> </script>

View File

@@ -1,9 +1,9 @@
<script setup lang="ts"> <script setup lang="ts">
import type { HTMLAttributes } from 'vue' import type { HTMLAttributes } from "vue"
import { cn } from '@/lib/utils' import { cn } from "@/lib/utils"
const props = defineProps<{ const props = defineProps<{
class?: HTMLAttributes['class'] class?: HTMLAttributes["class"]
}>() }>()
</script> </script>

View File

@@ -1,9 +1,9 @@
<script setup lang="ts"> <script setup lang="ts">
import type { HTMLAttributes } from 'vue' import type { HTMLAttributes } from "vue"
import { cn } from '@/lib/utils' import { cn } from "@/lib/utils"
const props = defineProps<{ const props = defineProps<{
class?: HTMLAttributes['class'] class?: HTMLAttributes["class"]
}>() }>()
</script> </script>

View File

@@ -1,9 +1,9 @@
<script setup lang="ts"> <script setup lang="ts">
import type { HTMLAttributes } from 'vue' import type { HTMLAttributes } from "vue"
import { cn } from '@/lib/utils' import { cn } from "@/lib/utils"
const props = defineProps<{ const props = defineProps<{
class?: HTMLAttributes['class'] class?: HTMLAttributes["class"]
}>() }>()
</script> </script>

View File

@@ -1,9 +1,9 @@
<script setup lang="ts"> <script setup lang="ts">
import type { HTMLAttributes } from 'vue' import type { HTMLAttributes } from "vue"
import { cn } from '@/lib/utils' import { cn } from "@/lib/utils"
const props = defineProps<{ const props = defineProps<{
class?: HTMLAttributes['class'] class?: HTMLAttributes["class"]
}>() }>()
</script> </script>

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,11 +1,11 @@
<script setup lang="ts"> <script setup lang="ts">
import { type HTMLAttributes, computed } from 'vue' import { type HTMLAttributes, computed } from "vue"
import type { CheckboxRootEmits, CheckboxRootProps } from 'radix-vue' import type { CheckboxRootEmits, CheckboxRootProps } from "radix-vue"
import { CheckboxIndicator, CheckboxRoot, useForwardPropsEmits } from 'radix-vue' import { CheckboxIndicator, CheckboxRoot, useForwardPropsEmits } from "radix-vue"
import { Check } from 'lucide-vue-next' import { Check } from "lucide-vue-next"
import { cn } from '@/lib/utils' import { cn } from "@/lib/utils"
const props = defineProps<CheckboxRootProps & { class?: HTMLAttributes['class'] }>() const props = defineProps<CheckboxRootProps & { class?: HTMLAttributes["class"] }>()
const emits = defineEmits<CheckboxRootEmits>() const emits = defineEmits<CheckboxRootEmits>()
const delegatedProps = computed(() => { const delegatedProps = computed(() => {

View File

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

View File

@@ -1,12 +1,12 @@
<script setup lang="ts"> <script setup lang="ts">
import { type HTMLAttributes, computed } from 'vue' import { type HTMLAttributes, computed } from "vue"
import type { ComboboxRootEmits, ComboboxRootProps } from 'radix-vue' import type { ComboboxRootEmits, ComboboxRootProps } from "radix-vue"
import { ComboboxRoot, useForwardPropsEmits } from 'radix-vue' import { ComboboxRoot, useForwardPropsEmits } from "radix-vue"
import { cn } from '@/lib/utils' import { cn } from "@/lib/utils"
const props = withDefaults(defineProps<ComboboxRootProps & { class?: HTMLAttributes['class'] }>(), { const props = withDefaults(defineProps<ComboboxRootProps & { class?: HTMLAttributes["class"] }>(), {
open: true, open: true,
modelValue: '' modelValue: ""
}) })
const emits = defineEmits<ComboboxRootEmits>() const emits = defineEmits<ComboboxRootEmits>()

View File

@@ -1,8 +1,8 @@
<script setup lang="ts"> <script setup lang="ts">
import { useForwardPropsEmits } from 'radix-vue' import { useForwardPropsEmits } from "radix-vue"
import type { DialogRootEmits, DialogRootProps } from 'radix-vue' import type { DialogRootEmits, DialogRootProps } from "radix-vue"
import Command from './Command.vue' import Command from "./Command.vue"
import { Dialog, DialogContent } from '@/components/ui/dialog' import { Dialog, DialogContent } from "@/components/ui/dialog"
const props = defineProps<DialogRootProps>() const props = defineProps<DialogRootProps>()
const emits = defineEmits<DialogRootEmits>() const emits = defineEmits<DialogRootEmits>()

View File

@@ -1,10 +1,10 @@
<script setup lang="ts"> <script setup lang="ts">
import { type HTMLAttributes, computed } from 'vue' import { type HTMLAttributes, computed } from "vue"
import type { ComboboxEmptyProps } from 'radix-vue' import type { ComboboxEmptyProps } from "radix-vue"
import { ComboboxEmpty } from 'radix-vue' import { ComboboxEmpty } from "radix-vue"
import { cn } from '@/lib/utils' import { cn } from "@/lib/utils"
const props = defineProps<ComboboxEmptyProps & { class?: HTMLAttributes['class'] }>() const props = defineProps<ComboboxEmptyProps & { class?: HTMLAttributes["class"] }>()
const delegatedProps = computed(() => { const delegatedProps = computed(() => {
const { class: _, ...delegated } = props const { class: _, ...delegated } = props

View File

@@ -1,12 +1,12 @@
<script setup lang="ts"> <script setup lang="ts">
import { type HTMLAttributes, computed } from 'vue' import { type HTMLAttributes, computed } from "vue"
import type { ComboboxGroupProps } from 'radix-vue' import type { ComboboxGroupProps } from "radix-vue"
import { ComboboxGroup, ComboboxLabel } from 'radix-vue' import { ComboboxGroup, ComboboxLabel } from "radix-vue"
import { cn } from '@/lib/utils' import { cn } from "@/lib/utils"
const props = defineProps< const props = defineProps<
ComboboxGroupProps & { ComboboxGroupProps & {
class?: HTMLAttributes['class'] class?: HTMLAttributes["class"]
heading?: string heading?: string
} }
>() >()

View File

@@ -1,8 +1,8 @@
<script setup lang="ts"> <script setup lang="ts">
import { type HTMLAttributes, computed } from 'vue' import { type HTMLAttributes, computed } from "vue"
import { Search } from 'lucide-vue-next' import { Search } from "lucide-vue-next"
import { ComboboxInput, type ComboboxInputProps, useForwardProps } from 'radix-vue' import { ComboboxInput, type ComboboxInputProps, useForwardProps } from "radix-vue"
import { cn } from '@/lib/utils' import { cn } from "@/lib/utils"
defineOptions({ defineOptions({
inheritAttrs: false inheritAttrs: false
@@ -10,7 +10,7 @@ defineOptions({
const props = defineProps< const props = defineProps<
ComboboxInputProps & { ComboboxInputProps & {
class?: HTMLAttributes['class'] class?: HTMLAttributes["class"]
} }
>() >()

View File

@@ -1,10 +1,10 @@
<script setup lang="ts"> <script setup lang="ts">
import { type HTMLAttributes, computed } from 'vue' import { type HTMLAttributes, computed } from "vue"
import type { ComboboxItemEmits, ComboboxItemProps } from 'radix-vue' import type { ComboboxItemEmits, ComboboxItemProps } from "radix-vue"
import { ComboboxItem, useForwardPropsEmits } from 'radix-vue' import { ComboboxItem, useForwardPropsEmits } from "radix-vue"
import { cn } from '@/lib/utils' import { cn } from "@/lib/utils"
const props = defineProps<ComboboxItemProps & { class?: HTMLAttributes['class'] }>() const props = defineProps<ComboboxItemProps & { class?: HTMLAttributes["class"] }>()
const emits = defineEmits<ComboboxItemEmits>() const emits = defineEmits<ComboboxItemEmits>()
const delegatedProps = computed(() => { const delegatedProps = computed(() => {

View File

@@ -1,11 +1,11 @@
<script setup lang="ts"> <script setup lang="ts">
import { type HTMLAttributes, computed } from 'vue' import { type HTMLAttributes, computed } from "vue"
import type { ComboboxContentEmits, ComboboxContentProps } from 'radix-vue' import type { ComboboxContentEmits, ComboboxContentProps } from "radix-vue"
import { ComboboxContent, useForwardPropsEmits } from 'radix-vue' import { ComboboxContent, useForwardPropsEmits } from "radix-vue"
import { cn } from '@/lib/utils' import { cn } from "@/lib/utils"
const props = withDefaults( const props = withDefaults(
defineProps<ComboboxContentProps & { class?: HTMLAttributes['class'] }>(), defineProps<ComboboxContentProps & { class?: HTMLAttributes["class"] }>(),
{ {
dismissable: false dismissable: false
} }

View File

@@ -1,10 +1,10 @@
<script setup lang="ts"> <script setup lang="ts">
import { type HTMLAttributes, computed } from 'vue' import { type HTMLAttributes, computed } from "vue"
import type { ComboboxSeparatorProps } from 'radix-vue' import type { ComboboxSeparatorProps } from "radix-vue"
import { ComboboxSeparator } from 'radix-vue' import { ComboboxSeparator } from "radix-vue"
import { cn } from '@/lib/utils' import { cn } from "@/lib/utils"
const props = defineProps<ComboboxSeparatorProps & { class?: HTMLAttributes['class'] }>() const props = defineProps<ComboboxSeparatorProps & { class?: HTMLAttributes["class"] }>()
const delegatedProps = computed(() => { const delegatedProps = computed(() => {
const { class: _, ...delegated } = props const { class: _, ...delegated } = props

View File

@@ -1,9 +1,9 @@
<script setup lang="ts"> <script setup lang="ts">
import type { HTMLAttributes } from 'vue' import type { HTMLAttributes } from "vue"
import { cn } from '@/lib/utils' import { cn } from "@/lib/utils"
const props = defineProps<{ const props = defineProps<{
class?: HTMLAttributes['class'] class?: HTMLAttributes["class"]
}>() }>()
</script> </script>

View File

@@ -1,11 +1,11 @@
export { ComboboxPortal } from 'radix-vue' export { ComboboxPortal } from "radix-vue"
export { default as Command } from './Command.vue' export { default as Command } from "./Command.vue"
export { default as CommandDialog } from './CommandDialog.vue' export { default as CommandDialog } from "./CommandDialog.vue"
export { default as CommandEmpty } from './CommandEmpty.vue' export { default as CommandEmpty } from "./CommandEmpty.vue"
export { default as CommandGroup } from './CommandGroup.vue' export { default as CommandGroup } from "./CommandGroup.vue"
export { default as CommandInput } from './CommandInput.vue' export { default as CommandInput } from "./CommandInput.vue"
export { default as CommandItem } from './CommandItem.vue' export { default as CommandItem } from "./CommandItem.vue"
export { default as CommandList } from './CommandList.vue' export { default as CommandList } from "./CommandList.vue"
export { default as CommandSeparator } from './CommandSeparator.vue' export { default as CommandSeparator } from "./CommandSeparator.vue"
export { default as CommandShortcut } from './CommandShortcut.vue' export { default as CommandShortcut } from "./CommandShortcut.vue"

View File

@@ -4,7 +4,7 @@ import {
type DialogRootEmits, type DialogRootEmits,
type DialogRootProps, type DialogRootProps,
useForwardPropsEmits useForwardPropsEmits
} from 'radix-vue' } from "radix-vue"
const props = defineProps<DialogRootProps>() const props = defineProps<DialogRootProps>()
const emits = defineEmits<DialogRootEmits>() const emits = defineEmits<DialogRootEmits>()

View File

@@ -1,5 +1,5 @@
<script setup lang="ts"> <script setup lang="ts">
import { DialogClose, type DialogCloseProps } from 'radix-vue' import { DialogClose, type DialogCloseProps } from "radix-vue"
const props = defineProps<DialogCloseProps>() const props = defineProps<DialogCloseProps>()
</script> </script>

View File

@@ -1,5 +1,5 @@
<script setup lang="ts"> <script setup lang="ts">
import { type HTMLAttributes, computed } from 'vue' import { type HTMLAttributes, computed } from "vue"
import { import {
DialogClose, DialogClose,
DialogContent, DialogContent,
@@ -8,11 +8,11 @@ import {
DialogOverlay, DialogOverlay,
DialogPortal, DialogPortal,
useForwardPropsEmits useForwardPropsEmits
} from 'radix-vue' } from "radix-vue"
import { X } from 'lucide-vue-next' import { X } from "lucide-vue-next"
import { cn } from '@/lib/utils' import { cn } from "@/lib/utils"
const props = defineProps<DialogContentProps & { class?: HTMLAttributes['class'] }>() const props = defineProps<DialogContentProps & { class?: HTMLAttributes["class"] }>()
const emits = defineEmits<DialogContentEmits>() const emits = defineEmits<DialogContentEmits>()
const delegatedProps = computed(() => { const delegatedProps = computed(() => {

View File

@@ -1,9 +1,9 @@
<script setup lang="ts"> <script setup lang="ts">
import { type HTMLAttributes, computed } from 'vue' import { type HTMLAttributes, computed } from "vue"
import { DialogDescription, type DialogDescriptionProps, useForwardProps } from 'radix-vue' import { DialogDescription, type DialogDescriptionProps, useForwardProps } from "radix-vue"
import { cn } from '@/lib/utils' import { cn } from "@/lib/utils"
const props = defineProps<DialogDescriptionProps & { class?: HTMLAttributes['class'] }>() const props = defineProps<DialogDescriptionProps & { class?: HTMLAttributes["class"] }>()
const delegatedProps = computed(() => { const delegatedProps = computed(() => {
const { class: _, ...delegated } = props const { class: _, ...delegated } = props

View File

@@ -1,8 +1,8 @@
<script setup lang="ts"> <script setup lang="ts">
import type { HTMLAttributes } from 'vue' import type { HTMLAttributes } from "vue"
import { cn } from '@/lib/utils' import { cn } from "@/lib/utils"
const props = defineProps<{ class?: HTMLAttributes['class'] }>() const props = defineProps<{ class?: HTMLAttributes["class"] }>()
</script> </script>
<template> <template>

View File

@@ -1,9 +1,9 @@
<script setup lang="ts"> <script setup lang="ts">
import type { HTMLAttributes } from 'vue' import type { HTMLAttributes } from "vue"
import { cn } from '@/lib/utils' import { cn } from "@/lib/utils"
const props = defineProps<{ const props = defineProps<{
class?: HTMLAttributes['class'] class?: HTMLAttributes["class"]
}>() }>()
</script> </script>

View File

@@ -1,5 +1,5 @@
<script setup lang="ts"> <script setup lang="ts">
import { type HTMLAttributes, computed } from 'vue' import { type HTMLAttributes, computed } from "vue"
import { import {
DialogClose, DialogClose,
DialogContent, DialogContent,
@@ -8,11 +8,11 @@ import {
DialogOverlay, DialogOverlay,
DialogPortal, DialogPortal,
useForwardPropsEmits useForwardPropsEmits
} from 'radix-vue' } from "radix-vue"
import { X } from 'lucide-vue-next' import { X } from "lucide-vue-next"
import { cn } from '@/lib/utils' import { cn } from "@/lib/utils"
const props = defineProps<DialogContentProps & { class?: HTMLAttributes['class'] }>() const props = defineProps<DialogContentProps & { class?: HTMLAttributes["class"] }>()
const emits = defineEmits<DialogContentEmits>() const emits = defineEmits<DialogContentEmits>()
const delegatedProps = computed(() => { const delegatedProps = computed(() => {

View File

@@ -1,9 +1,9 @@
<script setup lang="ts"> <script setup lang="ts">
import { type HTMLAttributes, computed } from 'vue' import { type HTMLAttributes, computed } from "vue"
import { DialogTitle, type DialogTitleProps, useForwardProps } from 'radix-vue' import { DialogTitle, type DialogTitleProps, useForwardProps } from "radix-vue"
import { cn } from '@/lib/utils' import { cn } from "@/lib/utils"
const props = defineProps<DialogTitleProps & { class?: HTMLAttributes['class'] }>() const props = defineProps<DialogTitleProps & { class?: HTMLAttributes["class"] }>()
const delegatedProps = computed(() => { const delegatedProps = computed(() => {
const { class: _, ...delegated } = props const { class: _, ...delegated } = props

View File

@@ -1,5 +1,5 @@
<script setup lang="ts"> <script setup lang="ts">
import { DialogTrigger, type DialogTriggerProps } from 'radix-vue' import { DialogTrigger, type DialogTriggerProps } from "radix-vue"
const props = defineProps<DialogTriggerProps>() const props = defineProps<DialogTriggerProps>()
</script> </script>

View File

@@ -1,9 +1,9 @@
export { default as Dialog } from './Dialog.vue' export { default as Dialog } from "./Dialog.vue"
export { default as DialogClose } from './DialogClose.vue' export { default as DialogClose } from "./DialogClose.vue"
export { default as DialogTrigger } from './DialogTrigger.vue' export { default as DialogTrigger } from "./DialogTrigger.vue"
export { default as DialogHeader } from './DialogHeader.vue' export { default as DialogHeader } from "./DialogHeader.vue"
export { default as DialogTitle } from './DialogTitle.vue' export { default as DialogTitle } from "./DialogTitle.vue"
export { default as DialogDescription } from './DialogDescription.vue' export { default as DialogDescription } from "./DialogDescription.vue"
export { default as DialogContent } from './DialogContent.vue' export { default as DialogContent } from "./DialogContent.vue"
export { default as DialogScrollContent } from './DialogScrollContent.vue' export { default as DialogScrollContent } from "./DialogScrollContent.vue"
export { default as DialogFooter } from './DialogFooter.vue' export { default as DialogFooter } from "./DialogFooter.vue"

View File

@@ -4,7 +4,7 @@ import {
type DropdownMenuRootEmits, type DropdownMenuRootEmits,
type DropdownMenuRootProps, type DropdownMenuRootProps,
useForwardPropsEmits useForwardPropsEmits
} from 'radix-vue' } from "radix-vue"
const props = defineProps<DropdownMenuRootProps>() const props = defineProps<DropdownMenuRootProps>()
const emits = defineEmits<DropdownMenuRootEmits>() const emits = defineEmits<DropdownMenuRootEmits>()

View File

@@ -1,16 +1,16 @@
<script setup lang="ts"> <script setup lang="ts">
import { type HTMLAttributes, computed } from 'vue' import { type HTMLAttributes, computed } from "vue"
import { import {
DropdownMenuCheckboxItem, DropdownMenuCheckboxItem,
type DropdownMenuCheckboxItemEmits, type DropdownMenuCheckboxItemEmits,
type DropdownMenuCheckboxItemProps, type DropdownMenuCheckboxItemProps,
DropdownMenuItemIndicator, DropdownMenuItemIndicator,
useForwardPropsEmits useForwardPropsEmits
} from 'radix-vue' } from "radix-vue"
import { Check } from 'lucide-vue-next' import { Check } from "lucide-vue-next"
import { cn } from '@/lib/utils' import { cn } from "@/lib/utils"
const props = defineProps<DropdownMenuCheckboxItemProps & { class?: HTMLAttributes['class'] }>() const props = defineProps<DropdownMenuCheckboxItemProps & { class?: HTMLAttributes["class"] }>()
const emits = defineEmits<DropdownMenuCheckboxItemEmits>() const emits = defineEmits<DropdownMenuCheckboxItemEmits>()
const delegatedProps = computed(() => { const delegatedProps = computed(() => {

View File

@@ -1,16 +1,16 @@
<script setup lang="ts"> <script setup lang="ts">
import { type HTMLAttributes, computed } from 'vue' import { type HTMLAttributes, computed } from "vue"
import { import {
DropdownMenuContent, DropdownMenuContent,
type DropdownMenuContentEmits, type DropdownMenuContentEmits,
type DropdownMenuContentProps, type DropdownMenuContentProps,
DropdownMenuPortal, DropdownMenuPortal,
useForwardPropsEmits useForwardPropsEmits
} from 'radix-vue' } from "radix-vue"
import { cn } from '@/lib/utils' import { cn } from "@/lib/utils"
const props = withDefaults( const props = withDefaults(
defineProps<DropdownMenuContentProps & { class?: HTMLAttributes['class'] }>(), defineProps<DropdownMenuContentProps & { class?: HTMLAttributes["class"] }>(),
{ {
sideOffset: 4 sideOffset: 4
} }

View File

@@ -1,5 +1,5 @@
<script setup lang="ts"> <script setup lang="ts">
import { DropdownMenuGroup, type DropdownMenuGroupProps } from 'radix-vue' import { DropdownMenuGroup, type DropdownMenuGroupProps } from "radix-vue"
const props = defineProps<DropdownMenuGroupProps>() const props = defineProps<DropdownMenuGroupProps>()
</script> </script>

View File

@@ -1,10 +1,10 @@
<script setup lang="ts"> <script setup lang="ts">
import { type HTMLAttributes, computed } from 'vue' import { type HTMLAttributes, computed } from "vue"
import { DropdownMenuItem, type DropdownMenuItemProps, useForwardProps } from 'radix-vue' import { DropdownMenuItem, type DropdownMenuItemProps, useForwardProps } from "radix-vue"
import { cn } from '@/lib/utils' import { cn } from "@/lib/utils"
const props = defineProps< const props = defineProps<
DropdownMenuItemProps & { class?: HTMLAttributes['class']; inset?: boolean } DropdownMenuItemProps & { class?: HTMLAttributes["class"]; inset?: boolean }
>() >()
const delegatedProps = computed(() => { const delegatedProps = computed(() => {

View File

@@ -1,10 +1,10 @@
<script setup lang="ts"> <script setup lang="ts">
import { type HTMLAttributes, computed } from 'vue' import { type HTMLAttributes, computed } from "vue"
import { DropdownMenuLabel, type DropdownMenuLabelProps, useForwardProps } from 'radix-vue' import { DropdownMenuLabel, type DropdownMenuLabelProps, useForwardProps } from "radix-vue"
import { cn } from '@/lib/utils' import { cn } from "@/lib/utils"
const props = defineProps< const props = defineProps<
DropdownMenuLabelProps & { class?: HTMLAttributes['class']; inset?: boolean } DropdownMenuLabelProps & { class?: HTMLAttributes["class"]; inset?: boolean }
>() >()
const delegatedProps = computed(() => { const delegatedProps = computed(() => {

View File

@@ -4,7 +4,7 @@ import {
type DropdownMenuRadioGroupEmits, type DropdownMenuRadioGroupEmits,
type DropdownMenuRadioGroupProps, type DropdownMenuRadioGroupProps,
useForwardPropsEmits useForwardPropsEmits
} from 'radix-vue' } from "radix-vue"
const props = defineProps<DropdownMenuRadioGroupProps>() const props = defineProps<DropdownMenuRadioGroupProps>()
const emits = defineEmits<DropdownMenuRadioGroupEmits>() const emits = defineEmits<DropdownMenuRadioGroupEmits>()

View File

@@ -1,16 +1,16 @@
<script setup lang="ts"> <script setup lang="ts">
import { type HTMLAttributes, computed } from 'vue' import { type HTMLAttributes, computed } from "vue"
import { import {
DropdownMenuItemIndicator, DropdownMenuItemIndicator,
DropdownMenuRadioItem, DropdownMenuRadioItem,
type DropdownMenuRadioItemEmits, type DropdownMenuRadioItemEmits,
type DropdownMenuRadioItemProps, type DropdownMenuRadioItemProps,
useForwardPropsEmits useForwardPropsEmits
} from 'radix-vue' } from "radix-vue"
import { Circle } from 'lucide-vue-next' import { Circle } from "lucide-vue-next"
import { cn } from '@/lib/utils' import { cn } from "@/lib/utils"
const props = defineProps<DropdownMenuRadioItemProps & { class?: HTMLAttributes['class'] }>() const props = defineProps<DropdownMenuRadioItemProps & { class?: HTMLAttributes["class"] }>()
const emits = defineEmits<DropdownMenuRadioItemEmits>() const emits = defineEmits<DropdownMenuRadioItemEmits>()

View File

@@ -1,11 +1,11 @@
<script setup lang="ts"> <script setup lang="ts">
import { type HTMLAttributes, computed } from 'vue' import { type HTMLAttributes, computed } from "vue"
import { DropdownMenuSeparator, type DropdownMenuSeparatorProps } from 'radix-vue' import { DropdownMenuSeparator, type DropdownMenuSeparatorProps } from "radix-vue"
import { cn } from '@/lib/utils' import { cn } from "@/lib/utils"
const props = defineProps< const props = defineProps<
DropdownMenuSeparatorProps & { DropdownMenuSeparatorProps & {
class?: HTMLAttributes['class'] class?: HTMLAttributes["class"]
} }
>() >()

View File

@@ -1,9 +1,9 @@
<script setup lang="ts"> <script setup lang="ts">
import type { HTMLAttributes } from 'vue' import type { HTMLAttributes } from "vue"
import { cn } from '@/lib/utils' import { cn } from "@/lib/utils"
const props = defineProps<{ const props = defineProps<{
class?: HTMLAttributes['class'] class?: HTMLAttributes["class"]
}>() }>()
</script> </script>

View File

@@ -4,7 +4,7 @@ import {
type DropdownMenuSubEmits, type DropdownMenuSubEmits,
type DropdownMenuSubProps, type DropdownMenuSubProps,
useForwardPropsEmits useForwardPropsEmits
} from 'radix-vue' } from "radix-vue"
const props = defineProps<DropdownMenuSubProps>() const props = defineProps<DropdownMenuSubProps>()
const emits = defineEmits<DropdownMenuSubEmits>() const emits = defineEmits<DropdownMenuSubEmits>()

View File

@@ -1,14 +1,14 @@
<script setup lang="ts"> <script setup lang="ts">
import { type HTMLAttributes, computed } from 'vue' import { type HTMLAttributes, computed } from "vue"
import { import {
DropdownMenuSubContent, DropdownMenuSubContent,
type DropdownMenuSubContentEmits, type DropdownMenuSubContentEmits,
type DropdownMenuSubContentProps, type DropdownMenuSubContentProps,
useForwardPropsEmits useForwardPropsEmits
} from 'radix-vue' } from "radix-vue"
import { cn } from '@/lib/utils' import { cn } from "@/lib/utils"
const props = defineProps<DropdownMenuSubContentProps & { class?: HTMLAttributes['class'] }>() const props = defineProps<DropdownMenuSubContentProps & { class?: HTMLAttributes["class"] }>()
const emits = defineEmits<DropdownMenuSubContentEmits>() const emits = defineEmits<DropdownMenuSubContentEmits>()
const delegatedProps = computed(() => { const delegatedProps = computed(() => {

View File

@@ -1,14 +1,14 @@
<script setup lang="ts"> <script setup lang="ts">
import { type HTMLAttributes, computed } from 'vue' import { type HTMLAttributes, computed } from "vue"
import { import {
DropdownMenuSubTrigger, DropdownMenuSubTrigger,
type DropdownMenuSubTriggerProps, type DropdownMenuSubTriggerProps,
useForwardProps useForwardProps
} from 'radix-vue' } from "radix-vue"
import { ChevronRight } from 'lucide-vue-next' import { ChevronRight } from "lucide-vue-next"
import { cn } from '@/lib/utils' import { cn } from "@/lib/utils"
const props = defineProps<DropdownMenuSubTriggerProps & { class?: HTMLAttributes['class'] }>() const props = defineProps<DropdownMenuSubTriggerProps & { class?: HTMLAttributes["class"] }>()
const delegatedProps = computed(() => { const delegatedProps = computed(() => {
const { class: _, ...delegated } = props const { class: _, ...delegated } = props

View File

@@ -1,5 +1,5 @@
<script setup lang="ts"> <script setup lang="ts">
import { DropdownMenuTrigger, type DropdownMenuTriggerProps, useForwardProps } from 'radix-vue' import { DropdownMenuTrigger, type DropdownMenuTriggerProps, useForwardProps } from "radix-vue"
const props = defineProps<DropdownMenuTriggerProps>() const props = defineProps<DropdownMenuTriggerProps>()

View File

@@ -1,16 +1,16 @@
export { DropdownMenuPortal } from 'radix-vue' export { DropdownMenuPortal } from "radix-vue"
export { default as DropdownMenu } from './DropdownMenu.vue' export { default as DropdownMenu } from "./DropdownMenu.vue"
export { default as DropdownMenuTrigger } from './DropdownMenuTrigger.vue' export { default as DropdownMenuTrigger } from "./DropdownMenuTrigger.vue"
export { default as DropdownMenuContent } from './DropdownMenuContent.vue' export { default as DropdownMenuContent } from "./DropdownMenuContent.vue"
export { default as DropdownMenuGroup } from './DropdownMenuGroup.vue' export { default as DropdownMenuGroup } from "./DropdownMenuGroup.vue"
export { default as DropdownMenuRadioGroup } from './DropdownMenuRadioGroup.vue' export { default as DropdownMenuRadioGroup } from "./DropdownMenuRadioGroup.vue"
export { default as DropdownMenuItem } from './DropdownMenuItem.vue' export { default as DropdownMenuItem } from "./DropdownMenuItem.vue"
export { default as DropdownMenuCheckboxItem } from './DropdownMenuCheckboxItem.vue' export { default as DropdownMenuCheckboxItem } from "./DropdownMenuCheckboxItem.vue"
export { default as DropdownMenuRadioItem } from './DropdownMenuRadioItem.vue' export { default as DropdownMenuRadioItem } from "./DropdownMenuRadioItem.vue"
export { default as DropdownMenuShortcut } from './DropdownMenuShortcut.vue' export { default as DropdownMenuShortcut } from "./DropdownMenuShortcut.vue"
export { default as DropdownMenuSeparator } from './DropdownMenuSeparator.vue' export { default as DropdownMenuSeparator } from "./DropdownMenuSeparator.vue"
export { default as DropdownMenuLabel } from './DropdownMenuLabel.vue' export { default as DropdownMenuLabel } from "./DropdownMenuLabel.vue"
export { default as DropdownMenuSub } from './DropdownMenuSub.vue' export { default as DropdownMenuSub } from "./DropdownMenuSub.vue"
export { default as DropdownMenuSubTrigger } from './DropdownMenuSubTrigger.vue' export { default as DropdownMenuSubTrigger } from "./DropdownMenuSubTrigger.vue"
export { default as DropdownMenuSubContent } from './DropdownMenuSubContent.vue' export { default as DropdownMenuSubContent } from "./DropdownMenuSubContent.vue"

View File

@@ -1,19 +1,19 @@
<script setup lang="ts"> <script setup lang="ts">
import type { HTMLAttributes } from 'vue' import type { HTMLAttributes } from "vue"
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?: string | number defaultValue?: string | number
modelValue?: string | number modelValue?: string | number
class?: HTMLAttributes['class'] class?: HTMLAttributes["class"]
}>() }>()
const emits = defineEmits<{ const emits = defineEmits<{
(e: 'update:modelValue', payload: string | number): void (e: "update:modelValue", payload: string | number): void
}>() }>()
const modelValue = useVModel(props, 'modelValue', emits, { const modelValue = useVModel(props, "modelValue", emits, {
passive: true, passive: true,
defaultValue: props.defaultValue defaultValue: props.defaultValue
}) })
@@ -28,5 +28,5 @@ const modelValue = useVModel(props, 'modelValue', emits, {
props.class props.class
) )
" "
/> >
</template> </template>

View File

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

Some files were not shown because too many files have changed in this diff Show More