Merge pull request #23 from AlexisNP/features/add-hidden-event-functionnality

Add hidden events UI
This commit is contained in:
AlexisNP
2024-06-09 17:27:09 +02:00
committed by GitHub
14 changed files with 159 additions and 20 deletions

View File

@@ -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 {

View File

@@ -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",

View File

@@ -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',

View File

@@ -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>

View File

@@ -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 }}

View File

@@ -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 }}

View File

@@ -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>

View 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>

View File

@@ -0,0 +1 @@
export { default as Label } from './Label.vue'

View 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>

View File

@@ -0,0 +1 @@
export { default as Switch } from './Switch.vue'

View File

@@ -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()
})

View File

@@ -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
)

View File

@@ -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
)