Merge pull request #23 from AlexisNP/features/add-hidden-event-functionnality
Add hidden events UI
This commit is contained in:
@@ -2,7 +2,8 @@
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
:root {
|
||||
@layer base {
|
||||
:root {
|
||||
--background: 0 0% 100%;
|
||||
--foreground: 222.2 84% 4.9%;
|
||||
|
||||
@@ -35,7 +36,7 @@
|
||||
--radius: 0.5rem;
|
||||
}
|
||||
|
||||
:root.dark {
|
||||
.dark {
|
||||
--background: 222.2 84% 4.9%;
|
||||
--foreground: 210 40% 98%;
|
||||
|
||||
@@ -64,6 +65,7 @@
|
||||
--destructive-foreground: 210 40% 98%;
|
||||
|
||||
--ring: 212.7 26.8% 83.9%;
|
||||
}
|
||||
}
|
||||
|
||||
@layer base {
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"$schema": "https://shadcn-vue.com/schema.json",
|
||||
"style": "default",
|
||||
"typescript": true,
|
||||
"tsConfigPath": ".nuxt/tsconfig.json",
|
||||
"tailwind": {
|
||||
"config": "tailwind.config.js",
|
||||
"css": "assets/main.css",
|
||||
|
||||
@@ -60,6 +60,7 @@ onMounted(() => {
|
||||
class="text-xs px-2 py-1 block w-full text-left rounded-sm focus-visible:bg-red-200"
|
||||
:class="
|
||||
cn({
|
||||
'italic': event.hidden,
|
||||
'text-white bg-slate-600 hover:bg-slate-700': !event.category,
|
||||
'text-white bg-lime-600 hover:bg-lime-700': event.category?.name === 'naissance',
|
||||
'text-white bg-stone-500 hover:bg-stone-700': event.category?.name === 'mort',
|
||||
|
||||
@@ -9,7 +9,8 @@ import {
|
||||
PhHourglassHigh,
|
||||
PhHourglassLow,
|
||||
PhMapPinArea,
|
||||
PhDotsThreeOutlineVertical
|
||||
PhDotsThreeOutlineVertical,
|
||||
PhEye
|
||||
} from '@phosphor-icons/vue'
|
||||
|
||||
const { defaultDate, getFormattedDateTitle, jumpToDate, getRelativeString } = useCalendar()
|
||||
@@ -189,6 +190,19 @@ function deployDeleteModal() {
|
||||
</button>
|
||||
</UiBadge>
|
||||
</nav>
|
||||
|
||||
<UiTooltipProvider v-if="event.hidden" :delay-duration="250">
|
||||
<UiTooltip>
|
||||
<UiTooltipTrigger as-child>
|
||||
<UiBadge class="absolute -top-2 right-2 flex gap-1 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>
|
||||
</UiPopoverContent>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<script lang="ts" setup>
|
||||
import type { RPGDate } from '~/models/Date';
|
||||
|
||||
import { PhAlarm, PhCircleNotch, PhMapPinArea } from '@phosphor-icons/vue'
|
||||
import { PopoverAnchor } from 'radix-vue';
|
||||
import { PhAlarm, PhCircleNotch, PhEye, PhEyeClosed, PhMapPinArea } from '@phosphor-icons/vue'
|
||||
|
||||
const { eventSkeleton, operationInProgress } = storeToRefs(useCalendarEvents())
|
||||
const { resetSkeleton, submitSkeleton, cancelLatestRequest } = useCalendarEvents()
|
||||
@@ -80,9 +80,9 @@ function handleCancel() {
|
||||
|
||||
<template>
|
||||
<UiPopover v-model:open="popoverOpen">
|
||||
<UiPopoverTrigger as-child>
|
||||
<button :class="btnClass" @click="openEventCreatePopover()" />
|
||||
</UiPopoverTrigger>
|
||||
<PopoverAnchor as-child>
|
||||
<button :class="btnClass" @dblclick="openEventCreatePopover()" />
|
||||
</PopoverAnchor>
|
||||
<UiPopoverContent
|
||||
:align="'center'"
|
||||
:side="'right'"
|
||||
@@ -96,7 +96,7 @@ function handleCancel() {
|
||||
@pointer-down-outside="handleClosing"
|
||||
>
|
||||
<form @submit.prevent="handleSubmit">
|
||||
<div class="grid grid-cols-2 gap-y-4">
|
||||
<div class="grid grid-cols-2 gap-y-6">
|
||||
<div class="col-span-2 pl-8">
|
||||
<input
|
||||
id="new-event-title"
|
||||
@@ -119,7 +119,7 @@ function handleCancel() {
|
||||
</div>
|
||||
|
||||
<div class="col-span-2">
|
||||
<div class="flex items-center gap-2">
|
||||
<div class="flex items-center gap-4">
|
||||
<PhAlarm size="18" weight="fill" />
|
||||
|
||||
<CalendarInputRPGDate
|
||||
@@ -140,7 +140,7 @@ function handleCancel() {
|
||||
</div>
|
||||
|
||||
<div class="col-span-2">
|
||||
<div class="flex items-center gap-2">
|
||||
<div class="flex items-center gap-4">
|
||||
<PhMapPinArea size="18" weight="fill" />
|
||||
|
||||
<input
|
||||
@@ -153,6 +153,25 @@ function handleCancel() {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-span-2">
|
||||
<div class="flex items-center gap-4">
|
||||
<PhEye v-if="!eventSkeleton.hidden" size="18" weight="fill" />
|
||||
<PhEyeClosed v-else size="18" />
|
||||
|
||||
<div class="flex items-center gap-x-2">
|
||||
<UiSwitch id="new-event-visibility" v-model:checked="eventSkeleton.hidden" />
|
||||
<UiLabel for="new-event-visibility">
|
||||
<template v-if="!eventSkeleton.hidden">
|
||||
Évènement visible
|
||||
</template>
|
||||
<template v-else>
|
||||
Évènement caché
|
||||
</template>
|
||||
</UiLabel>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="text-red-500 pl-8">
|
||||
<span class="text-sm">
|
||||
{{ formErrors.message }}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script lang="ts" setup>
|
||||
import { PhAlarm, PhCircleNotch, PhMapPinArea, PhPencilSimpleLine } from '@phosphor-icons/vue'
|
||||
import { PhAlarm, PhCircleNotch, PhEye, PhEyeClosed, PhMapPinArea, PhPencilSimpleLine } from '@phosphor-icons/vue'
|
||||
import { VisuallyHidden } from 'radix-vue'
|
||||
|
||||
const { isEditEventModalOpen } = storeToRefs(useCalendarEvents())
|
||||
@@ -81,9 +81,9 @@ function handleCancel() {
|
||||
</VisuallyHidden>
|
||||
|
||||
<form @submit.prevent="handleAction">
|
||||
<div class="grid grid-cols-2 gap-y-4">
|
||||
<div class="grid grid-cols-2 gap-y-6">
|
||||
<div class="col-span-2">
|
||||
<div class="flex items-center gap-2">
|
||||
<div class="flex items-center gap-4">
|
||||
<PhPencilSimpleLine size="20" weight="fill" />
|
||||
|
||||
<input
|
||||
@@ -109,7 +109,7 @@ function handleCancel() {
|
||||
</div>
|
||||
|
||||
<div class="col-span-2">
|
||||
<div class="flex items-center gap-2">
|
||||
<div class="flex items-center gap-4">
|
||||
<PhAlarm size="18" weight="fill" />
|
||||
|
||||
<CalendarInputRPGDate
|
||||
@@ -130,7 +130,7 @@ function handleCancel() {
|
||||
</div>
|
||||
|
||||
<div class="col-span-2">
|
||||
<div class="flex items-center gap-2">
|
||||
<div class="flex items-center gap-4">
|
||||
<PhMapPinArea size="18" weight="fill" />
|
||||
|
||||
<input
|
||||
@@ -143,6 +143,25 @@ function handleCancel() {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-span-2">
|
||||
<div class="flex items-center gap-4">
|
||||
<PhEye v-if="!eventSkeleton.hidden" size="18" weight="fill" />
|
||||
<PhEyeClosed v-else size="18" />
|
||||
|
||||
<div class="flex items-center gap-x-2">
|
||||
<UiSwitch id="new-event-visibility" v-model:checked="eventSkeleton.hidden" />
|
||||
<UiLabel for="new-event-visibility">
|
||||
<template v-if="!eventSkeleton.hidden">
|
||||
Évènement visible par tous
|
||||
</template>
|
||||
<template v-else>
|
||||
Évènement caché
|
||||
</template>
|
||||
</UiLabel>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="text-red-500 ml-8">
|
||||
<span class="text-sm">
|
||||
{{ formErrors.message }}
|
||||
|
||||
@@ -3,7 +3,7 @@ import type { RPGDate } from '@/models/Date'
|
||||
import type { CalendarEvent } from '@/models/CalendarEvent'
|
||||
import { useCalendar } from '@/stores/CalendarStore'
|
||||
|
||||
import { PhArrowSquareOut, PhHourglassMedium, PhAlarm, PhMapPinArea } from '@phosphor-icons/vue'
|
||||
import { PhArrowSquareOut, PhHourglassMedium, PhAlarm, PhMapPinArea, PhEye } from '@phosphor-icons/vue'
|
||||
|
||||
const props = defineProps<{
|
||||
event: CalendarEvent
|
||||
@@ -27,6 +27,7 @@ const dateDuration: string | null = props.event.endDate
|
||||
<button
|
||||
class="relative block w-full text-left py-3 px-4 rounded-sm transition-colors"
|
||||
:class="{
|
||||
'pt-4': event.hidden,
|
||||
'text-white bg-slate-600 hover:bg-slate-700': !event.category,
|
||||
'text-white bg-lime-600 hover:bg-lime-700': event.category?.name === 'naissance',
|
||||
'text-white bg-stone-500 hover:bg-stone-700': event.category?.name === 'mort',
|
||||
@@ -49,8 +50,8 @@ const dateDuration: string | null = props.event.endDate
|
||||
}"
|
||||
@click="$emit('query:date-jump', event.startDate)"
|
||||
>
|
||||
<div class="flex gap-2 items-center">
|
||||
<h2 class="font-bold">
|
||||
<div class="flex gap-2 items-center mb-1">
|
||||
<h2 class="font-bold text-lg">
|
||||
{{ event.title }}
|
||||
</h2>
|
||||
<div v-if="event.wiki">
|
||||
@@ -115,5 +116,18 @@ const dateDuration: string | null = props.event.endDate
|
||||
{{ event.description }}
|
||||
</span>
|
||||
</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>
|
||||
</template>
|
||||
|
||||
27
components/ui/label/Label.vue
Normal file
27
components/ui/label/Label.vue
Normal file
@@ -0,0 +1,27 @@
|
||||
<script setup lang="ts">
|
||||
import { type HTMLAttributes, computed } from 'vue'
|
||||
import { Label, type LabelProps } from 'radix-vue'
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
const props = defineProps<LabelProps & { class?: HTMLAttributes['class'] }>()
|
||||
|
||||
const delegatedProps = computed(() => {
|
||||
const { class: _, ...delegated } = props
|
||||
|
||||
return delegated
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Label
|
||||
v-bind="delegatedProps"
|
||||
:class="
|
||||
cn(
|
||||
'text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70',
|
||||
props.class,
|
||||
)
|
||||
"
|
||||
>
|
||||
<slot />
|
||||
</Label>
|
||||
</template>
|
||||
1
components/ui/label/index.ts
Normal file
1
components/ui/label/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export { default as Label } from './Label.vue'
|
||||
37
components/ui/switch/Switch.vue
Normal file
37
components/ui/switch/Switch.vue
Normal file
@@ -0,0 +1,37 @@
|
||||
<script setup lang="ts">
|
||||
import { type HTMLAttributes, computed } from 'vue'
|
||||
import {
|
||||
SwitchRoot,
|
||||
type SwitchRootEmits,
|
||||
type SwitchRootProps,
|
||||
SwitchThumb,
|
||||
useForwardPropsEmits,
|
||||
} from 'radix-vue'
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
const props = defineProps<SwitchRootProps & { class?: HTMLAttributes['class'] }>()
|
||||
|
||||
const emits = defineEmits<SwitchRootEmits>()
|
||||
|
||||
const delegatedProps = computed(() => {
|
||||
const { class: _, ...delegated } = props
|
||||
|
||||
return delegated
|
||||
})
|
||||
|
||||
const forwarded = useForwardPropsEmits(delegatedProps, emits)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<SwitchRoot
|
||||
v-bind="forwarded"
|
||||
:class="cn(
|
||||
'peer inline-flex h-6 w-11 shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=unchecked]:bg-input',
|
||||
props.class,
|
||||
)"
|
||||
>
|
||||
<SwitchThumb
|
||||
:class="cn('pointer-events-none block h-5 w-5 rounded-full bg-background shadow-lg ring-0 transition-transform data-[state=checked]:translate-x-5 data-[state=unchecked]:translate-x-0')"
|
||||
/>
|
||||
</SwitchRoot>
|
||||
</template>
|
||||
1
components/ui/switch/index.ts
Normal file
1
components/ui/switch/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export { default as Switch } from './Switch.vue'
|
||||
@@ -24,7 +24,8 @@ export const postEventBodySchema = z.object({
|
||||
description: z.string().optional().nullable(),
|
||||
location: z.string().optional().nullable(),
|
||||
startDate: dateSchema.required(),
|
||||
endDate: dateSchema.optional().nullable()
|
||||
endDate: dateSchema.optional().nullable(),
|
||||
hidden: z.boolean().optional().nullable()
|
||||
}),
|
||||
calendarId: z.number({ coerce: true }).int().positive()
|
||||
})
|
||||
|
||||
@@ -41,6 +41,7 @@ export default defineEventHandler(async (event) => {
|
||||
title: bodyData?.event.title,
|
||||
description: bodyData.event.description,
|
||||
location: bodyData.event.location,
|
||||
hidden: bodyData.event.hidden,
|
||||
calendar_id: bodyData?.calendarId
|
||||
} as never
|
||||
)
|
||||
|
||||
@@ -25,6 +25,7 @@ export default defineEventHandler(async (event) => {
|
||||
title: bodyData?.event.title,
|
||||
description: bodyData.event.description,
|
||||
location: bodyData.event.location,
|
||||
hidden: bodyData.event.hidden,
|
||||
calendar_id: bodyData?.calendarId
|
||||
} as never
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user