Merge branch 'dev'
This commit is contained in:
@@ -2,7 +2,7 @@
|
|||||||
import { useDark } from '@vueuse/core'
|
import { useDark } from '@vueuse/core'
|
||||||
import { RouterView } from 'vue-router'
|
import { RouterView } from 'vue-router'
|
||||||
|
|
||||||
const dark = useDark()
|
useDark()
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|||||||
@@ -1,28 +1,30 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { useCalendar } from '@/stores/CalendarStore'
|
import { useCalendar } from '@/stores/CalendarStore'
|
||||||
import { computed } from 'vue'
|
import { computed, type Component, type ComputedRef } from 'vue'
|
||||||
|
|
||||||
import CalendarMenu from './CalendarMenu.vue'
|
import CalendarMenu from './CalendarMenu.vue'
|
||||||
import Century from './state/Century.vue'
|
|
||||||
import Decade from './state/Decade.vue'
|
import MonthlyLayout from './state/monthly/Layout.vue'
|
||||||
import Monthly from './state/Monthly.vue'
|
import CenturyLayout from './state/centennially/Layout.vue'
|
||||||
import Year from './state/Year.vue'
|
import DecadeLayout from './state/decennially/Layout.vue'
|
||||||
|
import YearLayout from './state/yearly/Layout.vue'
|
||||||
|
|
||||||
const { currentConfig } = useCalendar()
|
const { currentConfig } = useCalendar()
|
||||||
|
|
||||||
const currentViewComponent = computed(() => {
|
const currentViewComponent: ComputedRef<Component> = computed<Component>(() => {
|
||||||
switch (currentConfig.viewType) {
|
switch (currentConfig.viewType) {
|
||||||
case 'month':
|
case 'month':
|
||||||
return Monthly
|
return MonthlyLayout
|
||||||
|
|
||||||
case 'year':
|
case 'year':
|
||||||
return Year
|
return YearLayout
|
||||||
|
|
||||||
case 'decade':
|
case 'decade':
|
||||||
return Decade
|
return DecadeLayout
|
||||||
|
|
||||||
case 'century':
|
case 'century':
|
||||||
default:
|
default:
|
||||||
return Century
|
return CenturyLayout
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
@@ -30,6 +32,8 @@ const currentViewComponent = computed(() => {
|
|||||||
<template>
|
<template>
|
||||||
<div class="h-full grid grid-rows-[auto,1fr]">
|
<div class="h-full grid grid-rows-[auto,1fr]">
|
||||||
<CalendarMenu />
|
<CalendarMenu />
|
||||||
<component :is="currentViewComponent" />
|
<KeepAlive>
|
||||||
|
<component :is="currentViewComponent" />
|
||||||
|
</KeepAlive>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
24
src/components/calendar/CalendarCurrentDate.vue
Normal file
24
src/components/calendar/CalendarCurrentDate.vue
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
<script lang="ts" setup>
|
||||||
|
import { getRelativeString } from '@/models/Date'
|
||||||
|
import { useCalendar } from '@/stores/CalendarStore'
|
||||||
|
import { storeToRefs } from 'pinia'
|
||||||
|
import { computed } from 'vue'
|
||||||
|
|
||||||
|
import { PhMapPin } from '@phosphor-icons/vue'
|
||||||
|
|
||||||
|
const { defaultDate, getFormattedDateTitle } = useCalendar()
|
||||||
|
const { selectedDate } = storeToRefs(useCalendar())
|
||||||
|
|
||||||
|
const mainDateTitle = computed(() => getFormattedDateTitle(selectedDate.value, true))
|
||||||
|
|
||||||
|
const dateDifference = computed(() => getRelativeString(defaultDate, selectedDate.value))
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<h1 class="text-2xl font-bold flex items-center gap-1">
|
||||||
|
<PhMapPin size="26" weight="bold" /> {{ mainDateTitle }}
|
||||||
|
</h1>
|
||||||
|
<h2 class="text-lg italic opacity-75">
|
||||||
|
{{ dateDifference }}
|
||||||
|
</h2>
|
||||||
|
</template>
|
||||||
@@ -33,6 +33,6 @@ defineProps<{
|
|||||||
</button>
|
</button>
|
||||||
</PopoverTrigger>
|
</PopoverTrigger>
|
||||||
|
|
||||||
<CalendarEventDetails :event />
|
<CalendarEventDetails :event v-once />
|
||||||
</Popover>
|
</Popover>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -2,7 +2,6 @@
|
|||||||
import { getRelativeString } from '@/models/Date'
|
import { getRelativeString } from '@/models/Date'
|
||||||
import type { CalendarEvent } from '@/models/Events'
|
import type { CalendarEvent } from '@/models/Events'
|
||||||
import { useCalendar } from '@/stores/CalendarStore'
|
import { useCalendar } from '@/stores/CalendarStore'
|
||||||
import { computed } from 'vue'
|
|
||||||
|
|
||||||
import { PhHourglassMedium } from '@phosphor-icons/vue'
|
import { PhHourglassMedium } from '@phosphor-icons/vue'
|
||||||
import { Badge } from '@/components/ui/badge'
|
import { Badge } from '@/components/ui/badge'
|
||||||
@@ -12,11 +11,30 @@ const { defaultDate, getFormattedDateTitle } = useCalendar()
|
|||||||
|
|
||||||
const props = defineProps<{ event: CalendarEvent }>()
|
const props = defineProps<{ event: CalendarEvent }>()
|
||||||
|
|
||||||
const dateDifference = computed(() => getRelativeString(defaultDate, props.event.date))
|
const dateDifference: string = getRelativeString(defaultDate, props.event.date)
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<PopoverContent class="w-96" align="start" :align-offset="50" :collision-padding="20">
|
<PopoverContent
|
||||||
|
class="w-96"
|
||||||
|
align="start"
|
||||||
|
:align-offset="50"
|
||||||
|
:collision-padding="20"
|
||||||
|
:class="{
|
||||||
|
'border-slate-800': !event.category,
|
||||||
|
'border-lime-800': event.category === 'naissance',
|
||||||
|
'border-stone-800': event.category === 'mort',
|
||||||
|
'border-orange-800': event.category === 'catastrophe',
|
||||||
|
'border-pink-800': event.category === 'catastrophe naturelle',
|
||||||
|
'border-sky-800': event.category === 'législation',
|
||||||
|
'border-purple-800': event.category === 'religion',
|
||||||
|
'border-emerald-800': event.category === 'joueurs',
|
||||||
|
'border-amber-800': event.category === 'inauguration',
|
||||||
|
'border-green-800': event.category === 'invention',
|
||||||
|
'border-cyan-800': event.category === 'science',
|
||||||
|
'border-yellow-800': event.category === 'bénédiction'
|
||||||
|
}"
|
||||||
|
>
|
||||||
<div class="grid gap-1">
|
<div class="grid gap-1">
|
||||||
<div class="text-lg font-semibold">
|
<div class="text-lg font-semibold">
|
||||||
{{ event.title }}
|
{{ event.title }}
|
||||||
@@ -51,3 +69,42 @@ const dateDifference = computed(() => getRelativeString(defaultDate, props.event
|
|||||||
</div>
|
</div>
|
||||||
</PopoverContent>
|
</PopoverContent>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.border-slate-800 {
|
||||||
|
background-color: color-mix(in srgb, var(--color-slate-800), var(--color-slate-950) 85%);
|
||||||
|
}
|
||||||
|
.border-lime-800 {
|
||||||
|
background-color: color-mix(in srgb, var(--color-lime-800), var(--color-slate-950) 85%);
|
||||||
|
}
|
||||||
|
.border-stone-800 {
|
||||||
|
background-color: color-mix(in srgb, var(--color-stone-800), var(--color-slate-950) 85%);
|
||||||
|
}
|
||||||
|
.border-orange-800 {
|
||||||
|
background-color: color-mix(in srgb, var(--color-orange-800), var(--color-slate-950) 85%);
|
||||||
|
}
|
||||||
|
.border-pink-800 {
|
||||||
|
background-color: color-mix(in srgb, var(--color-pink-800), var(--color-slate-950) 85%);
|
||||||
|
}
|
||||||
|
.border-sky-800 {
|
||||||
|
background-color: color-mix(in srgb, var(--color-sky-800), var(--color-slate-950) 85%);
|
||||||
|
}
|
||||||
|
.border-purple-800 {
|
||||||
|
background-color: color-mix(in srgb, var(--color-purple-800), var(--color-slate-950) 85%);
|
||||||
|
}
|
||||||
|
.border-emerald-800 {
|
||||||
|
background-color: color-mix(in srgb, var(--color-emerald-800), var(--color-slate-950) 85%);
|
||||||
|
}
|
||||||
|
.border-amber-800 {
|
||||||
|
background-color: color-mix(in srgb, var(--color-amber-800), var(--color-slate-950) 85%);
|
||||||
|
}
|
||||||
|
.border-green-800 {
|
||||||
|
background-color: color-mix(in srgb, var(--color-green-800), var(--color-slate-950) 85%);
|
||||||
|
}
|
||||||
|
.border-cyan-800 {
|
||||||
|
background-color: color-mix(in srgb, var(--color-cyan-800), var(--color-slate-950) 85%);
|
||||||
|
}
|
||||||
|
.border-yellow-800 {
|
||||||
|
background-color: color-mix(in srgb, var(--color-yellow-800), var(--color-slate-950) 85%);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|||||||
@@ -1,60 +1,45 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { getRelativeString } from '@/models/Date'
|
|
||||||
import { useCalendar } from '@/stores/CalendarStore'
|
import { useCalendar } from '@/stores/CalendarStore'
|
||||||
import { storeToRefs } from 'pinia'
|
|
||||||
import { computed } from 'vue'
|
|
||||||
|
|
||||||
import { PhMapPin } from '@phosphor-icons/vue'
|
import { Button } from '@/components/ui/button'
|
||||||
import CalendarMenuNav from './CalendarMenuNav.vue'
|
import CalendarMenuNav from './CalendarMenuNav.vue'
|
||||||
import CalendarMenuToday from './CalendarMenuToday.vue'
|
import CalendarMenuToday from './CalendarMenuToday.vue'
|
||||||
import CalendarSwitch from './CalendarSwitch.vue'
|
import CalendarSwitch from './CalendarSwitch.vue'
|
||||||
import CalendarSearch from './search/CalendarSearch.vue'
|
import CalendarCurrentDate from './CalendarCurrentDate.vue'
|
||||||
|
|
||||||
const { defaultDate, getFormattedDateTitle, currentDate } = useCalendar()
|
const { currentDate, revealAdvancedSearch } = useCalendar()
|
||||||
const { selectedDate } = storeToRefs(useCalendar())
|
|
||||||
|
|
||||||
const mainDateTitle = computed(() => getFormattedDateTitle(selectedDate.value, true))
|
|
||||||
|
|
||||||
const dateDifference = computed(() => getRelativeString(defaultDate, selectedDate.value))
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<header class="border-slate-700 border-b-[1px]">
|
<header class="pt-4 border-slate-700 border-b-[1px]">
|
||||||
<div class="pt-4 container">
|
<div class="px-6 flex justify-between">
|
||||||
<div class="grid md:grid-cols-12 items-center">
|
<menu class="flex items-center gap-2">
|
||||||
<div class="md:col-span-9">
|
<li class="flex items-center">
|
||||||
<div class="flex items-center gap-6">
|
<CalendarMenuToday />
|
||||||
<menu class="flex items-center gap-2">
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<CalendarSwitch />
|
<CalendarMenuNav />
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li class="ml-6">
|
||||||
<CalendarMenuToday />
|
<CalendarCurrentDate />
|
||||||
</li>
|
</li>
|
||||||
<li>
|
</menu>
|
||||||
<CalendarMenuNav />
|
|
||||||
</li>
|
<menu class="flex items-center gap-2">
|
||||||
</menu>
|
<li>
|
||||||
<div>
|
<Button search-slash @click="revealAdvancedSearch()">
|
||||||
<h1 class="text-2xl font-bold flex items-center gap-1">
|
<PhMagnifyingGlass size="20" weight="light" />
|
||||||
<PhMapPin size="26" weight="bold" /> {{ mainDateTitle }}
|
Recherche avancée
|
||||||
</h1>
|
</Button>
|
||||||
<h2 class="text-lg italic opacity-75">
|
</li>
|
||||||
{{ dateDifference }}
|
<li>
|
||||||
</h2>
|
<CalendarSwitch />
|
||||||
</div>
|
</li>
|
||||||
</div>
|
</menu>
|
||||||
</div>
|
|
||||||
<div class="md:col-span-3 flex justify-end">
|
|
||||||
<CalendarSearch />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="container">
|
<div class="ml-12 flex">
|
||||||
<div class="flex">
|
<div class="px-4 py-2 border-slate-700 border-x-[1px] border-t-[1px] rounded-t-sm">
|
||||||
<div class="px-4 py-2 border-slate-700 border-x-[1px] border-t-[1px] rounded-t-sm">
|
<span class="text-sm">{{ currentDate.currentDateTitle }}</span>
|
||||||
<span class="text-sm">{{ currentDate.currentDateTitle }}</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
|
|||||||
@@ -9,22 +9,151 @@ import {
|
|||||||
PhCaretRight
|
PhCaretRight
|
||||||
} from '@phosphor-icons/vue'
|
} from '@phosphor-icons/vue'
|
||||||
import Button from '../ui/button/Button.vue'
|
import Button from '../ui/button/Button.vue'
|
||||||
|
import { computed, type ComputedRef } from 'vue'
|
||||||
|
|
||||||
const { decrementMonth, incrementMonth, decrementYear, incrementYear } = useCalendar()
|
interface DirectionLabels {
|
||||||
|
pastFar: string
|
||||||
|
pastNear: string
|
||||||
|
futureNear: string
|
||||||
|
futureFar: string
|
||||||
|
}
|
||||||
|
|
||||||
|
const { currentConfig, decrementMonth, incrementMonth, decrementYear, incrementYear } =
|
||||||
|
useCalendar()
|
||||||
|
|
||||||
|
const activeDirectionLabels: ComputedRef<DirectionLabels> = computed(() => {
|
||||||
|
switch (currentConfig.viewType) {
|
||||||
|
case 'month':
|
||||||
|
return {
|
||||||
|
pastFar: 'Année précédente',
|
||||||
|
pastNear: 'Mois précédent',
|
||||||
|
futureNear: 'Mois suivant',
|
||||||
|
futureFar: 'Année suivante'
|
||||||
|
}
|
||||||
|
|
||||||
|
case 'year':
|
||||||
|
return {
|
||||||
|
pastFar: 'Décennie précédente',
|
||||||
|
pastNear: 'Année précédente',
|
||||||
|
futureNear: 'Année suivante',
|
||||||
|
futureFar: 'Décennie suivante'
|
||||||
|
}
|
||||||
|
|
||||||
|
case 'decade':
|
||||||
|
return {
|
||||||
|
pastFar: 'Siècle précédent',
|
||||||
|
pastNear: 'Décennie précédente',
|
||||||
|
futureNear: 'Décennie suivante',
|
||||||
|
futureFar: 'Siècle suivant'
|
||||||
|
}
|
||||||
|
|
||||||
|
case 'century':
|
||||||
|
default:
|
||||||
|
return {
|
||||||
|
pastFar: 'Millénaire précédent',
|
||||||
|
pastNear: 'Siècle précédent',
|
||||||
|
futureNear: 'Siècle suivant',
|
||||||
|
futureFar: 'Millénaire suivant'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
function toPastFar(): void {
|
||||||
|
switch (currentConfig.viewType) {
|
||||||
|
case 'month':
|
||||||
|
decrementYear()
|
||||||
|
break
|
||||||
|
|
||||||
|
case 'year':
|
||||||
|
decrementYear(10)
|
||||||
|
break
|
||||||
|
|
||||||
|
case 'decade':
|
||||||
|
decrementYear(100)
|
||||||
|
break
|
||||||
|
|
||||||
|
case 'century':
|
||||||
|
default:
|
||||||
|
decrementYear(1000)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function toPastNear(): void {
|
||||||
|
switch (currentConfig.viewType) {
|
||||||
|
case 'month':
|
||||||
|
decrementMonth()
|
||||||
|
break
|
||||||
|
|
||||||
|
case 'year':
|
||||||
|
decrementYear()
|
||||||
|
break
|
||||||
|
|
||||||
|
case 'decade':
|
||||||
|
decrementYear(10)
|
||||||
|
break
|
||||||
|
|
||||||
|
case 'century':
|
||||||
|
default:
|
||||||
|
decrementYear(100)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function toFutureNear(): void {
|
||||||
|
switch (currentConfig.viewType) {
|
||||||
|
case 'month':
|
||||||
|
incrementMonth()
|
||||||
|
break
|
||||||
|
|
||||||
|
case 'year':
|
||||||
|
incrementYear()
|
||||||
|
break
|
||||||
|
|
||||||
|
case 'decade':
|
||||||
|
incrementYear(10)
|
||||||
|
break
|
||||||
|
|
||||||
|
case 'century':
|
||||||
|
default:
|
||||||
|
incrementYear(100)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function toFutureFar(): void {
|
||||||
|
switch (currentConfig.viewType) {
|
||||||
|
case 'month':
|
||||||
|
incrementYear()
|
||||||
|
break
|
||||||
|
|
||||||
|
case 'year':
|
||||||
|
incrementYear(10)
|
||||||
|
break
|
||||||
|
|
||||||
|
case 'decade':
|
||||||
|
incrementYear(100)
|
||||||
|
break
|
||||||
|
|
||||||
|
case 'century':
|
||||||
|
default:
|
||||||
|
incrementYear(1000)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="flex items-center gap-2">
|
<div class="flex items-center gap-2">
|
||||||
<!-- Implement decrementDate to account for other mods -->
|
|
||||||
<TooltipProvider :delayDuration="250">
|
<TooltipProvider :delayDuration="250">
|
||||||
<Tooltip>
|
<Tooltip>
|
||||||
<TooltipTrigger>
|
<TooltipTrigger>
|
||||||
<Button variant="outline" size="icon" @click="decrementYear()">
|
<Button variant="outline" size="icon" @click="toPastFar()">
|
||||||
<PhCaretDoubleLeft size="18" />
|
<PhCaretDoubleLeft size="18" />
|
||||||
</Button>
|
</Button>
|
||||||
</TooltipTrigger>
|
</TooltipTrigger>
|
||||||
<TooltipContent>
|
<TooltipContent>
|
||||||
<p>Année précédente</p>
|
<p>{{ activeDirectionLabels.pastFar }}</p>
|
||||||
</TooltipContent>
|
</TooltipContent>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
</TooltipProvider>
|
</TooltipProvider>
|
||||||
@@ -32,12 +161,12 @@ const { decrementMonth, incrementMonth, decrementYear, incrementYear } = useCale
|
|||||||
<TooltipProvider :delayDuration="250">
|
<TooltipProvider :delayDuration="250">
|
||||||
<Tooltip>
|
<Tooltip>
|
||||||
<TooltipTrigger>
|
<TooltipTrigger>
|
||||||
<Button variant="outline" size="icon" @click="decrementMonth()">
|
<Button variant="outline" size="icon" @click="toPastNear()">
|
||||||
<PhCaretLeft size="18" />
|
<PhCaretLeft size="18" />
|
||||||
</Button>
|
</Button>
|
||||||
</TooltipTrigger>
|
</TooltipTrigger>
|
||||||
<TooltipContent>
|
<TooltipContent>
|
||||||
<p>Mois précédent</p>
|
<p>{{ activeDirectionLabels.pastNear }}</p>
|
||||||
</TooltipContent>
|
</TooltipContent>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
</TooltipProvider>
|
</TooltipProvider>
|
||||||
@@ -45,12 +174,12 @@ const { decrementMonth, incrementMonth, decrementYear, incrementYear } = useCale
|
|||||||
<TooltipProvider :delayDuration="250">
|
<TooltipProvider :delayDuration="250">
|
||||||
<Tooltip>
|
<Tooltip>
|
||||||
<TooltipTrigger>
|
<TooltipTrigger>
|
||||||
<Button variant="outline" size="icon" @click="incrementMonth()">
|
<Button variant="outline" size="icon" @click="toFutureNear()">
|
||||||
<PhCaretRight size="18" />
|
<PhCaretRight size="18" />
|
||||||
</Button>
|
</Button>
|
||||||
</TooltipTrigger>
|
</TooltipTrigger>
|
||||||
<TooltipContent>
|
<TooltipContent>
|
||||||
<p>Mois suivant</p>
|
<p>{{ activeDirectionLabels.futureNear }}</p>
|
||||||
</TooltipContent>
|
</TooltipContent>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
</TooltipProvider>
|
</TooltipProvider>
|
||||||
@@ -58,12 +187,12 @@ const { decrementMonth, incrementMonth, decrementYear, incrementYear } = useCale
|
|||||||
<TooltipProvider :delayDuration="250">
|
<TooltipProvider :delayDuration="250">
|
||||||
<Tooltip>
|
<Tooltip>
|
||||||
<TooltipTrigger>
|
<TooltipTrigger>
|
||||||
<Button variant="outline" size="icon" @click="incrementYear()">
|
<Button variant="outline" size="icon" @click="toFutureFar()">
|
||||||
<PhCaretDoubleRight size="18" />
|
<PhCaretDoubleRight size="18" />
|
||||||
</Button>
|
</Button>
|
||||||
</TooltipTrigger>
|
</TooltipTrigger>
|
||||||
<TooltipContent>
|
<TooltipContent>
|
||||||
<p>Année suivante</p>
|
<p>{{ activeDirectionLabels.futureFar }}</p>
|
||||||
</TooltipContent>
|
</TooltipContent>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
</TooltipProvider>
|
</TooltipProvider>
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import { areDatesIdentical } from '@/models/Date'
|
|||||||
const { defaultDate, selectedDate } = storeToRefs(useCalendar())
|
const { defaultDate, selectedDate } = storeToRefs(useCalendar())
|
||||||
const { jumpToDefaultDate, getFormattedDateTitle } = useCalendar()
|
const { jumpToDefaultDate, getFormattedDateTitle } = useCalendar()
|
||||||
|
|
||||||
const defaultDateFormatted = computed(() => getFormattedDateTitle(defaultDate.value, true))
|
const defaultDateFormatted = getFormattedDateTitle(defaultDate.value, true)
|
||||||
|
|
||||||
const isDefaultDate = computed(() => {
|
const isDefaultDate = computed(() => {
|
||||||
return areDatesIdentical(selectedDate.value, defaultDate.value)
|
return areDatesIdentical(selectedDate.value, defaultDate.value)
|
||||||
|
|||||||
@@ -1,83 +0,0 @@
|
|||||||
<script lang="ts" setup>
|
|
||||||
import { areDatesIdentical, type LeimDate } from '@/models/Date'
|
|
||||||
import { useCalendar } from '@/stores/CalendarStore'
|
|
||||||
import { useCalendarEvents } from '@/stores/EventStore'
|
|
||||||
import { storeToRefs } from 'pinia'
|
|
||||||
import { computed } from 'vue'
|
|
||||||
import CalendarEvent from './CalendarEvent.vue'
|
|
||||||
|
|
||||||
const props = defineProps<{
|
|
||||||
date: LeimDate
|
|
||||||
faded?: boolean
|
|
||||||
}>()
|
|
||||||
|
|
||||||
const { defaultDate, selectDate } = useCalendar()
|
|
||||||
const { selectedDate } = storeToRefs(useCalendar())
|
|
||||||
const { currentEvents } = storeToRefs(useCalendarEvents())
|
|
||||||
|
|
||||||
const eventsForTheDay = computed(() => {
|
|
||||||
return currentEvents.value.filter((currentEvent) => {
|
|
||||||
return areDatesIdentical(currentEvent.date, props.date)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
const isDefaultDate = computed(() => {
|
|
||||||
return areDatesIdentical(props.date, defaultDate)
|
|
||||||
})
|
|
||||||
|
|
||||||
const isSelectedDate = computed(() => {
|
|
||||||
return areDatesIdentical(props.date, selectedDate.value)
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<div
|
|
||||||
class="tile relative text-xs p-2 border-slate-700"
|
|
||||||
:class="{
|
|
||||||
'text-slate-500': props.faded,
|
|
||||||
'text-slate-300': !props.faded
|
|
||||||
}"
|
|
||||||
>
|
|
||||||
<!-- Used for "display all events" -->
|
|
||||||
<button class="absolute inset-0 w-full h-full cursor-default z-0" />
|
|
||||||
|
|
||||||
<button
|
|
||||||
class="relative z-10 group block w-full text-center cursor-pointer"
|
|
||||||
@click="selectDate(date)"
|
|
||||||
>
|
|
||||||
<span
|
|
||||||
class="inline-flex w-8 h-8 aspect-square items-center justify-center rounded-full border-2 border-transparent font-bold transition-colors group-hover:border-slate-800"
|
|
||||||
:class="{
|
|
||||||
'bg-slate-800': isDefaultDate && !isSelectedDate,
|
|
||||||
'text-white bg-blue-500': isSelectedDate
|
|
||||||
}"
|
|
||||||
>
|
|
||||||
{{ date.day }}
|
|
||||||
</span>
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<ul
|
|
||||||
v-if="eventsForTheDay.length > 0"
|
|
||||||
class="absolute top-12 bottom-2 inset-x-2 grid auto-rows-min gap-1 z-10 pointer-events-none transition-opacity"
|
|
||||||
:class="{
|
|
||||||
'opacity-40': props.faded && !isSelectedDate
|
|
||||||
}"
|
|
||||||
>
|
|
||||||
<li v-for="event in eventsForTheDay" :key="event.title" class="grid pointer-events-auto">
|
|
||||||
<CalendarEvent :event />
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
|
||||||
.tile {
|
|
||||||
&:not(:nth-child(10n)) {
|
|
||||||
border-right-width: 1px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:nth-child(n + 11) {
|
|
||||||
border-top-width: 1px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
56
src/components/calendar/Sidebar.vue
Normal file
56
src/components/calendar/Sidebar.vue
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
<script lang="ts" setup>
|
||||||
|
import { useCalendar } from '@/stores/CalendarStore'
|
||||||
|
|
||||||
|
import { PhList, PhHouse, PhMagnifyingGlass } from '@phosphor-icons/vue'
|
||||||
|
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@/components/ui/tooltip'
|
||||||
|
import Button from '../ui/button/Button.vue'
|
||||||
|
|
||||||
|
const { revealAdvancedSearch } = useCalendar()
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<nav class="w-16 py-6 border-r-[1px] border-l-slate-500 grid justify-center">
|
||||||
|
<menu class="flex flex-col gap-4">
|
||||||
|
<li class="mb-12">
|
||||||
|
<Button variant="ghost" size="icon" @click="console.log" class="rounded-full">
|
||||||
|
<PhList size="27" />
|
||||||
|
</Button>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<TooltipProvider :delayDuration="100">
|
||||||
|
<Tooltip>
|
||||||
|
<TooltipTrigger>
|
||||||
|
<Button variant="ghost" size="icon" class="rounded-full" as-child>
|
||||||
|
<RouterLink to="/">
|
||||||
|
<PhHouse size="24" weight="fill" />
|
||||||
|
</RouterLink>
|
||||||
|
</Button>
|
||||||
|
</TooltipTrigger>
|
||||||
|
<TooltipContent :side="'right'">
|
||||||
|
<p>Retourner aux outils</p>
|
||||||
|
</TooltipContent>
|
||||||
|
</Tooltip>
|
||||||
|
</TooltipProvider>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<TooltipProvider :delayDuration="100">
|
||||||
|
<Tooltip>
|
||||||
|
<TooltipTrigger>
|
||||||
|
<Button
|
||||||
|
variant="ghost"
|
||||||
|
size="icon"
|
||||||
|
class="rounded-full"
|
||||||
|
@click="revealAdvancedSearch()"
|
||||||
|
>
|
||||||
|
<PhMagnifyingGlass size="24" weight="fill" />
|
||||||
|
</Button>
|
||||||
|
</TooltipTrigger>
|
||||||
|
<TooltipContent :side="'right'">
|
||||||
|
<p>Recherche avancée</p>
|
||||||
|
</TooltipContent>
|
||||||
|
</Tooltip>
|
||||||
|
</TooltipProvider>
|
||||||
|
</li>
|
||||||
|
</menu>
|
||||||
|
</nav>
|
||||||
|
</template>
|
||||||
@@ -62,7 +62,7 @@ import SearchList from './lists/SearchList.vue'
|
|||||||
const { characters } = useCharacters()
|
const { characters } = useCharacters()
|
||||||
const { baseEvents } = useCalendarEvents()
|
const { baseEvents } = useCalendarEvents()
|
||||||
|
|
||||||
const modalOpen = ref<boolean>(false)
|
const modalOpen = defineModel({ default: false })
|
||||||
|
|
||||||
const searchQuery = ref<string>('')
|
const searchQuery = ref<string>('')
|
||||||
// const searchEnough = computed<boolean>(() => searchQuery.value.length >= 2)
|
// const searchEnough = computed<boolean>(() => searchQuery.value.length >= 2)
|
||||||
@@ -243,13 +243,6 @@ function handleCategorySelect(e: any) {
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<Dialog v-model:open="modalOpen" @update:open="resetSearch()">
|
<Dialog v-model:open="modalOpen" @update:open="resetSearch()">
|
||||||
<DialogTrigger>
|
|
||||||
<Button search-slash>
|
|
||||||
<PhMagnifyingGlass size="20" weight="light" />
|
|
||||||
Recherche avancée
|
|
||||||
</Button>
|
|
||||||
</DialogTrigger>
|
|
||||||
|
|
||||||
<DialogContent
|
<DialogContent
|
||||||
class="flex flex-col flex-nowrap top-16 -translate-y-0 data-[state=closed]:slide-out-to-top-[5%] data-[state=open]:slide-in-from-top-[5%]"
|
class="flex flex-col flex-nowrap top-16 -translate-y-0 data-[state=closed]:slide-out-to-top-[5%] data-[state=open]:slide-in-from-top-[5%]"
|
||||||
:class="{
|
:class="{
|
||||||
@@ -289,10 +282,10 @@ function handleCategorySelect(e: any) {
|
|||||||
v-model="selectedEntity"
|
v-model="selectedEntity"
|
||||||
@update:model-value="handleEntitySwitch()"
|
@update:model-value="handleEntitySwitch()"
|
||||||
>
|
>
|
||||||
<ToggleGroupItem value="events" aria-label="Uniquement les évènements">
|
<ToggleGroupItem value="events" aria-label="Uniquement les évènements" v-once>
|
||||||
Évènements
|
Évènements
|
||||||
</ToggleGroupItem>
|
</ToggleGroupItem>
|
||||||
<ToggleGroupItem value="characters" aria-label="Uniquement les personnages">
|
<ToggleGroupItem value="characters" aria-label="Uniquement les personnages" v-once>
|
||||||
Personnages
|
Personnages
|
||||||
</ToggleGroupItem>
|
</ToggleGroupItem>
|
||||||
</ToggleGroup>
|
</ToggleGroup>
|
||||||
|
|||||||
@@ -1,3 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div>Annuel</div>
|
|
||||||
</template>
|
|
||||||
139
src/components/calendar/state/monthly/DayTile.vue
Normal file
139
src/components/calendar/state/monthly/DayTile.vue
Normal file
@@ -0,0 +1,139 @@
|
|||||||
|
<script lang="ts" setup>
|
||||||
|
import { areDatesIdentical, type LeimDate } from '@/models/Date'
|
||||||
|
import { useCalendar } from '@/stores/CalendarStore'
|
||||||
|
import { useCalendarEvents } from '@/stores/EventStore'
|
||||||
|
import { useElementBounding } from '@vueuse/core'
|
||||||
|
import { storeToRefs } from 'pinia'
|
||||||
|
import { computed, ref, type ComputedRef } from 'vue'
|
||||||
|
|
||||||
|
import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover'
|
||||||
|
import CalendarEventButton from '../../CalendarEvent.vue'
|
||||||
|
import type { CalendarEvent } from '@/models/Events'
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
date: LeimDate
|
||||||
|
faded?: boolean
|
||||||
|
}>()
|
||||||
|
|
||||||
|
const calendarTile = ref()
|
||||||
|
const calendarEventsList = ref()
|
||||||
|
|
||||||
|
const { defaultDate, selectDate } = useCalendar()
|
||||||
|
const { selectedDate } = storeToRefs(useCalendar())
|
||||||
|
const { currentEvents } = storeToRefs(useCalendarEvents())
|
||||||
|
|
||||||
|
const eventsForTheDay = computed(() => {
|
||||||
|
return currentEvents.value.filter((currentEvent) => {
|
||||||
|
return areDatesIdentical(currentEvent.date, props.date)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
const isDefaultDate = computed(() => {
|
||||||
|
return areDatesIdentical(props.date, defaultDate)
|
||||||
|
})
|
||||||
|
|
||||||
|
const isSelectedDate = computed(() => {
|
||||||
|
return areDatesIdentical(props.date, selectedDate.value)
|
||||||
|
})
|
||||||
|
|
||||||
|
// Get bounding elements for both tile and events list
|
||||||
|
const { height: tileHeight, top: tileTop } = useElementBounding(calendarTile)
|
||||||
|
const { top: tileListTop } = useElementBounding(calendarEventsList)
|
||||||
|
|
||||||
|
// Compute the available number of events that can be displayed from refs heights
|
||||||
|
const numberOfEventsToFit: ComputedRef<number> = computed(() => {
|
||||||
|
if (!eventsForTheDay.value.length) return 0
|
||||||
|
|
||||||
|
return Math.trunc((tileHeight.value - (tileListTop.value - tileTop.value)) / 40)
|
||||||
|
})
|
||||||
|
|
||||||
|
const eventsToDisplay: ComputedRef<CalendarEvent[]> = computed(() => {
|
||||||
|
return [...eventsForTheDay.value].splice(0, numberOfEventsToFit.value)
|
||||||
|
})
|
||||||
|
const eventsNotDisplayed = computed(
|
||||||
|
() => eventsForTheDay.value.length - eventsToDisplay.value.length
|
||||||
|
)
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div
|
||||||
|
ref="calendarTile"
|
||||||
|
class="tile relative text-xs p-2 border-slate-700"
|
||||||
|
:class="{
|
||||||
|
'text-slate-500': props.faded,
|
||||||
|
'text-slate-300': !props.faded
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<!-- Used for "display all events" -->
|
||||||
|
<button class="absolute inset-0 w-full h-full cursor-default z-0" />
|
||||||
|
|
||||||
|
<button
|
||||||
|
class="relative z-10 group block w-full text-center cursor-pointer"
|
||||||
|
@click="selectDate(date)"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
class="inline-flex w-8 h-8 aspect-square items-center justify-center rounded-full border-2 border-transparent font-bold transition-colors group-hover:border-slate-800"
|
||||||
|
:class="{
|
||||||
|
'bg-slate-800': isDefaultDate && !isSelectedDate,
|
||||||
|
'text-white bg-blue-500': isSelectedDate
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
{{ date.day }}
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<ul
|
||||||
|
ref="calendarEventsList"
|
||||||
|
class="absolute top-12 bottom-2 inset-x-2 grid auto-rows-min gap-1 z-10 pointer-events-none transition-opacity"
|
||||||
|
:class="{
|
||||||
|
'opacity-40': props.faded && !isSelectedDate
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<li v-for="event in eventsToDisplay" :key="event.title" class="grid pointer-events-auto">
|
||||||
|
<CalendarEventButton :event />
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li v-if="eventsNotDisplayed > 0" class="pointer-events-auto">
|
||||||
|
<Popover>
|
||||||
|
<PopoverTrigger as-child>
|
||||||
|
<button
|
||||||
|
class="text-xs px-2 py-1 block w-full text-left font-bold rounded-sm whitespace-nowrap overflow-hidden text-ellipsis cursor-pointer transition-colors hover:bg-slate-800"
|
||||||
|
>
|
||||||
|
{{ eventsNotDisplayed }} autre{{ eventsNotDisplayed > 1 ? 's' : '' }}
|
||||||
|
</button>
|
||||||
|
</PopoverTrigger>
|
||||||
|
<PopoverContent class="w-80" :align="'center'" :side="'right'">
|
||||||
|
<div class="text-center mb-4">
|
||||||
|
<span
|
||||||
|
class="inline-flex w-12 h-12 aspect-square items-center justify-center text-lg font-semibold text-slate-300 bg-slate-800 rounded-full"
|
||||||
|
>
|
||||||
|
{{ date.day }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<ul class="grid auto-rows-min gap-1 z-10 pointer-events-none transition-opacity">
|
||||||
|
<li
|
||||||
|
v-for="event in eventsForTheDay"
|
||||||
|
:key="event.title"
|
||||||
|
class="grid pointer-events-auto"
|
||||||
|
>
|
||||||
|
<CalendarEventButton :event />
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</PopoverContent>
|
||||||
|
</Popover>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.tile {
|
||||||
|
&:not(:nth-child(10n)) {
|
||||||
|
border-right-width: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:nth-child(n + 11) {
|
||||||
|
border-top-width: 1px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -2,13 +2,12 @@
|
|||||||
import type { LeimDate } from '@/models/Date'
|
import type { LeimDate } from '@/models/Date'
|
||||||
import { useCalendar } from '@/stores/CalendarStore'
|
import { useCalendar } from '@/stores/CalendarStore'
|
||||||
import { useThrottleFn } from '@vueuse/core'
|
import { useThrottleFn } from '@vueuse/core'
|
||||||
import { computed } from 'vue'
|
|
||||||
|
|
||||||
import CalendarTile from '../CalendarTile.vue'
|
import DayTile from './DayTile.vue'
|
||||||
|
|
||||||
const { staticConfig, currentDate, decrementMonth, incrementMonth } = useCalendar()
|
const { staticConfig, currentDate, decrementMonth, incrementMonth } = useCalendar()
|
||||||
|
|
||||||
const daysPerMonth = computed(() => staticConfig.daysPerMonth)
|
const daysPerMonth = staticConfig.daysPerMonth
|
||||||
|
|
||||||
function getNextMonthDate(day: number): LeimDate {
|
function getNextMonthDate(day: number): LeimDate {
|
||||||
let nextDay = day
|
let nextDay = day
|
||||||
@@ -54,18 +53,17 @@ const moveCalendarRight = useThrottleFn(() => {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="grid" :class="`grid-cols-10`" @wheel="handleWheel">
|
<div class="grid grid-cols-10" @wheel="handleWheel">
|
||||||
<CalendarTile
|
<DayTile
|
||||||
v-for="day in daysPerMonth"
|
v-for="day in daysPerMonth"
|
||||||
:key="day"
|
:key="day"
|
||||||
:date="{
|
:date="{
|
||||||
day: day,
|
day: day,
|
||||||
month: currentDate.currentMonth,
|
month: currentDate.currentMonth,
|
||||||
year: currentDate.currentYear,
|
year: currentDate.currentYear
|
||||||
period: currentDate.currentPeriod
|
|
||||||
}"
|
}"
|
||||||
/>
|
/>
|
||||||
<CalendarTile
|
<DayTile
|
||||||
v-for="nextMonthDay in 8"
|
v-for="nextMonthDay in 8"
|
||||||
:key="nextMonthDay"
|
:key="nextMonthDay"
|
||||||
faded
|
faded
|
||||||
56
src/components/calendar/state/yearly/DayTile.vue
Normal file
56
src/components/calendar/state/yearly/DayTile.vue
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
<script lang="ts" setup>
|
||||||
|
import { areDatesIdentical, type LeimDate } from '@/models/Date'
|
||||||
|
import { useCalendar } from '@/stores/CalendarStore'
|
||||||
|
import { useCalendarEvents } from '@/stores/EventStore'
|
||||||
|
import { storeToRefs } from 'pinia'
|
||||||
|
import { computed, type ComputedRef } from 'vue'
|
||||||
|
|
||||||
|
const { currentDate, defaultDate, selectDate } = useCalendar()
|
||||||
|
const { selectedDate } = storeToRefs(useCalendar())
|
||||||
|
const { currentEvents } = storeToRefs(useCalendarEvents())
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
monthNumber: number
|
||||||
|
dayNumber: number
|
||||||
|
}>()
|
||||||
|
|
||||||
|
const tileDate: ComputedRef<LeimDate> = computed(() => {
|
||||||
|
return {
|
||||||
|
day: props.dayNumber,
|
||||||
|
month: props.monthNumber,
|
||||||
|
year: currentDate.currentYear
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const isDefaultDate = computed<boolean>(() => {
|
||||||
|
return areDatesIdentical(tileDate.value, defaultDate)
|
||||||
|
})
|
||||||
|
|
||||||
|
const isSelectedDate = computed<boolean>(() => {
|
||||||
|
return areDatesIdentical(tileDate.value, selectedDate.value)
|
||||||
|
})
|
||||||
|
|
||||||
|
const hasAtLeastOneEvent = computed<boolean>(() => {
|
||||||
|
return Boolean(
|
||||||
|
currentEvents.value.find((currentEvent) => {
|
||||||
|
return areDatesIdentical(currentEvent.date, tileDate.value)
|
||||||
|
})
|
||||||
|
)
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<button
|
||||||
|
class="relative grid place-items-center aspect-square rounded-full border-2 border-transparent transition-colors after:content-[''] after:absolute after:top-1 after:right-1 after:w-[.3rem] after:h-[.3rem] after:rounded-full after:transition-colors"
|
||||||
|
:class="{
|
||||||
|
'hover:bg-slate-800 hover:border-slate-800': !isDefaultDate && !isSelectedDate,
|
||||||
|
'bg-slate-800 hover:bg-slate-600 hover:border-slate-600': isDefaultDate && !isSelectedDate,
|
||||||
|
'text-white bg-blue-500 hover:bg-blue-600 hover:border-blue-600': isSelectedDate,
|
||||||
|
'after:bg-green-600': hasAtLeastOneEvent,
|
||||||
|
'after:bg-slate-950': hasAtLeastOneEvent && isSelectedDate
|
||||||
|
}"
|
||||||
|
@click="selectDate(tileDate)"
|
||||||
|
>
|
||||||
|
<span ref="tileRef" class="text-slate-300 text-[.85em]">{{ dayNumber }}</span>
|
||||||
|
</button>
|
||||||
|
</template>
|
||||||
37
src/components/calendar/state/yearly/Layout.vue
Normal file
37
src/components/calendar/state/yearly/Layout.vue
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
<script lang="ts" setup>
|
||||||
|
import { useCalendar } from '@/stores/CalendarStore'
|
||||||
|
import { useThrottleFn } from '@vueuse/core'
|
||||||
|
|
||||||
|
import MonthTile from './MonthTile.vue'
|
||||||
|
|
||||||
|
const { staticConfig, decrementYear, incrementYear } = useCalendar()
|
||||||
|
|
||||||
|
function handleWheel(e: WheelEvent) {
|
||||||
|
const isMovingUp = e.deltaY < 0
|
||||||
|
if (isMovingUp) {
|
||||||
|
moveCalendarLeft()
|
||||||
|
} else {
|
||||||
|
moveCalendarRight()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const moveCalendarLeft = useThrottleFn(() => {
|
||||||
|
decrementYear()
|
||||||
|
}, 100)
|
||||||
|
|
||||||
|
const moveCalendarRight = useThrottleFn(() => {
|
||||||
|
incrementYear()
|
||||||
|
}, 100)
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="container mt-[10vh] mb-auto" @wheel="handleWheel">
|
||||||
|
<div ref="test" class="grid grid-cols-5 gap-x-8 gap-y-16">
|
||||||
|
<MonthTile
|
||||||
|
v-for="month in staticConfig.monthsPerYear"
|
||||||
|
:key="month"
|
||||||
|
:month-number="month - 1"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
29
src/components/calendar/state/yearly/MonthTile.vue
Normal file
29
src/components/calendar/state/yearly/MonthTile.vue
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
<script lang="ts" setup>
|
||||||
|
import { useCalendar } from '@/stores/CalendarStore'
|
||||||
|
|
||||||
|
import DayTile from './DayTile.vue'
|
||||||
|
|
||||||
|
const { staticConfig, getMonthName } = useCalendar()
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
monthNumber: number
|
||||||
|
}>()
|
||||||
|
|
||||||
|
const tileMonthName: string = getMonthName(props.monthNumber)
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<div class="font-medium">
|
||||||
|
{{ tileMonthName }}
|
||||||
|
</div>
|
||||||
|
<div class="grid grid-cols-7">
|
||||||
|
<DayTile
|
||||||
|
v-for="day in staticConfig.daysPerMonth"
|
||||||
|
:key="day"
|
||||||
|
:month-number="monthNumber"
|
||||||
|
:day-number="day"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
29
src/components/ui/card/Card.vue
Normal file
29
src/components/ui/card/Card.vue
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import type { HTMLAttributes } from 'vue'
|
||||||
|
import { cn } from '@/lib/utils'
|
||||||
|
import { RouterLink } from 'vue-router'
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
class?: HTMLAttributes['class']
|
||||||
|
link?: string
|
||||||
|
}>()
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div
|
||||||
|
:class="
|
||||||
|
cn('rounded-lg border bg-card text-card-foreground shadow-sm transition-all', props.class, {
|
||||||
|
'relative outline outline-2 outline-offset-4 outline-transparent hover:bg-sky-950 hover:-translate-y-[.2rem] focus-within:outline-sky-900':
|
||||||
|
props.link
|
||||||
|
})
|
||||||
|
"
|
||||||
|
>
|
||||||
|
<slot />
|
||||||
|
|
||||||
|
<RouterLink
|
||||||
|
v-if="props.link"
|
||||||
|
:to="props.link"
|
||||||
|
class="absolute inset-0 focus-visible:outline-none"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
14
src/components/ui/card/CardContent.vue
Normal file
14
src/components/ui/card/CardContent.vue
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import type { HTMLAttributes } from 'vue'
|
||||||
|
import { cn } from '@/lib/utils'
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
class?: HTMLAttributes['class']
|
||||||
|
}>()
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div :class="cn('p-6 pt-0 text-muted-foreground', props.class)">
|
||||||
|
<slot />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
14
src/components/ui/card/CardDescription.vue
Normal file
14
src/components/ui/card/CardDescription.vue
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import type { HTMLAttributes } from 'vue'
|
||||||
|
import { cn } from '@/lib/utils'
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
class?: HTMLAttributes['class']
|
||||||
|
}>()
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<p :class="cn('text-sm text-muted-foreground mt-1', props.class)">
|
||||||
|
<slot />
|
||||||
|
</p>
|
||||||
|
</template>
|
||||||
14
src/components/ui/card/CardFooter.vue
Normal file
14
src/components/ui/card/CardFooter.vue
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import type { HTMLAttributes } from 'vue'
|
||||||
|
import { cn } from '@/lib/utils'
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
class?: HTMLAttributes['class']
|
||||||
|
}>()
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div :class="cn('flex items-center p-6 pt-0', props.class)">
|
||||||
|
<slot />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
14
src/components/ui/card/CardHeader.vue
Normal file
14
src/components/ui/card/CardHeader.vue
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import type { HTMLAttributes } from 'vue'
|
||||||
|
import { cn } from '@/lib/utils'
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
class?: HTMLAttributes['class']
|
||||||
|
}>()
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div :class="cn('flex flex-col gap-y-1.5 px-6 pt-6 pb-3', props.class)">
|
||||||
|
<slot />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
14
src/components/ui/card/CardTitle.vue
Normal file
14
src/components/ui/card/CardTitle.vue
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import type { HTMLAttributes } from 'vue'
|
||||||
|
import { cn } from '@/lib/utils'
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
class?: HTMLAttributes['class']
|
||||||
|
}>()
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<h3 :class="cn('text-2xl font-semibold leading-none tracking-tight', props.class)">
|
||||||
|
<slot />
|
||||||
|
</h3>
|
||||||
|
</template>
|
||||||
6
src/components/ui/card/index.ts
Normal file
6
src/components/ui/card/index.ts
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
export { default as Card } from './Card.vue'
|
||||||
|
export { default as CardHeader } from './CardHeader.vue'
|
||||||
|
export { default as CardTitle } from './CardTitle.vue'
|
||||||
|
export { default as CardDescription } from './CardDescription.vue'
|
||||||
|
export { default as CardContent } from './CardContent.vue'
|
||||||
|
export { default as CardFooter } from './CardFooter.vue'
|
||||||
@@ -83,28 +83,28 @@ export const regularEvents: CalendarEvent[] = [
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '2ème disparation à Cantane',
|
title: '2ème disparation à Cantane',
|
||||||
description: 'Seconde victime de la série de disparitions qui affecte Cantane',
|
description: 'Donovane le mineur kéturien disparait sans laisser de traces.',
|
||||||
date: { day: 32, month: 7, year: 3209 },
|
date: { day: 32, month: 7, year: 3209 },
|
||||||
category: 'mort',
|
category: 'mort',
|
||||||
hidden: true
|
hidden: true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '3ème disparation à Cantane',
|
title: '3ème disparation à Cantane',
|
||||||
description: 'Troisième victime de la série de disparitions qui affecte Cantane',
|
description: 'Disparition de Sébastien, gredin sauride.',
|
||||||
date: { day: 10, month: 8, year: 3209 },
|
date: { day: 10, month: 8, year: 3209 },
|
||||||
category: 'mort',
|
category: 'mort',
|
||||||
hidden: true
|
hidden: true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '4ème disparation à Cantane',
|
title: '4ème disparation à Cantane',
|
||||||
description: 'Quatrième victime de la série de disparitions qui affecte Cantane',
|
description: 'Disparition de Thérence, patrouilleur sauride de la Vieille Garde.',
|
||||||
date: { day: 19, month: 8, year: 3209 },
|
date: { day: 19, month: 8, year: 3209 },
|
||||||
category: 'mort',
|
category: 'mort',
|
||||||
hidden: true
|
hidden: true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '5ème disparation à Cantane',
|
title: '5ème disparation à Cantane',
|
||||||
description: 'Cinquième victime de la série de disparitions qui affecte Cantane',
|
description: 'Disparition de Mathilda Boulais, vendeuse de pierres.',
|
||||||
date: { day: 22, month: 8, year: 3209 },
|
date: { day: 22, month: 8, year: 3209 },
|
||||||
category: 'mort',
|
category: 'mort',
|
||||||
hidden: true
|
hidden: true
|
||||||
@@ -114,7 +114,6 @@ export const regularEvents: CalendarEvent[] = [
|
|||||||
description:
|
description:
|
||||||
'Les artisans et mineurs de Rougefer se réunissent à Cantane pour vendre le fruit de leur dur labeur.',
|
'Les artisans et mineurs de Rougefer se réunissent à Cantane pour vendre le fruit de leur dur labeur.',
|
||||||
date: { day: 23, month: 8, year: 3209 },
|
date: { day: 23, month: 8, year: 3209 },
|
||||||
category: 'inauguration',
|
category: 'inauguration'
|
||||||
hidden: true
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -1,13 +1,19 @@
|
|||||||
import { createRouter, createWebHistory } from 'vue-router'
|
import { createRouter, createWebHistory } from 'vue-router'
|
||||||
import HomeView from '../views/HomeView.vue'
|
import HomePage from '@/views/HomePage.vue'
|
||||||
|
import CalendarPage from '@/views/CalendarPage.vue'
|
||||||
|
|
||||||
const router = createRouter({
|
const router = createRouter({
|
||||||
history: createWebHistory(import.meta.env.BASE_URL),
|
history: createWebHistory(import.meta.env.BASE_URL),
|
||||||
routes: [
|
routes: [
|
||||||
{
|
{
|
||||||
path: '/',
|
path: '/',
|
||||||
name: 'home',
|
name: 'accueil',
|
||||||
component: HomeView
|
component: HomePage
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/calendrier',
|
||||||
|
name: 'calendrier',
|
||||||
|
component: CalendarPage
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -89,22 +89,10 @@ export const useCalendar = defineStore('calendar', () => {
|
|||||||
return {
|
return {
|
||||||
day: defaultDay,
|
day: defaultDay,
|
||||||
month: defaultMonth,
|
month: defaultMonth,
|
||||||
year: defaultYear,
|
year: defaultYear
|
||||||
period: 'nante'
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
// Assign default values if no params exist in URL
|
|
||||||
if (!params.day || typeof params.day === 'object' || !isInt(params.day)) {
|
|
||||||
params.day = defaultDay.toString()
|
|
||||||
}
|
|
||||||
if (!params.month || typeof params.month === 'object' || !isDigit(params.month)) {
|
|
||||||
params.month = defaultMonth.toString()
|
|
||||||
}
|
|
||||||
if (!params.year || typeof params.year === 'object' || !isSignedInt(params.year)) {
|
|
||||||
params.year = defaultYear.toString()
|
|
||||||
}
|
|
||||||
|
|
||||||
const currentDay = computed<number>(() => {
|
const currentDay = computed<number>(() => {
|
||||||
return Number(params.day)
|
return Number(params.day)
|
||||||
})
|
})
|
||||||
@@ -192,6 +180,19 @@ export const useCalendar = defineStore('calendar', () => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
function validateUrlParams(): void {
|
||||||
|
// Assign default values if no params exist in URL
|
||||||
|
if (!params.day || typeof params.day === 'object' || !isInt(params.day)) {
|
||||||
|
params.day = defaultDate.value.day.toString()
|
||||||
|
}
|
||||||
|
if (!params.month || typeof params.month === 'object' || !isDigit(params.month)) {
|
||||||
|
params.month = defaultDate.value.month.toString()
|
||||||
|
}
|
||||||
|
if (!params.year || typeof params.year === 'object' || !isSignedInt(params.year)) {
|
||||||
|
params.year = defaultDate.value.year.toString()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Moves the current date forward one month
|
* Moves the current date forward one month
|
||||||
*/
|
*/
|
||||||
@@ -378,7 +379,6 @@ export const useCalendar = defineStore('calendar', () => {
|
|||||||
*/
|
*/
|
||||||
function jumpToDefaultDate(): void {
|
function jumpToDefaultDate(): void {
|
||||||
jumpToDate(defaultDate.value)
|
jumpToDate(defaultDate.value)
|
||||||
currentConfig.value.viewType = 'month'
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -388,6 +388,12 @@ export const useCalendar = defineStore('calendar', () => {
|
|||||||
selectedDate.value = date
|
selectedDate.value = date
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const isAdvancedSearchOpen: Ref<boolean> = ref<boolean>(false)
|
||||||
|
|
||||||
|
function revealAdvancedSearch() {
|
||||||
|
isAdvancedSearchOpen.value = true
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
staticConfig,
|
staticConfig,
|
||||||
viewTypeOptions,
|
viewTypeOptions,
|
||||||
@@ -398,6 +404,7 @@ export const useCalendar = defineStore('calendar', () => {
|
|||||||
selectedDate,
|
selectedDate,
|
||||||
selectDate,
|
selectDate,
|
||||||
params,
|
params,
|
||||||
|
validateUrlParams,
|
||||||
getPeriodOfYear,
|
getPeriodOfYear,
|
||||||
incrementMonth,
|
incrementMonth,
|
||||||
decrementMonth,
|
decrementMonth,
|
||||||
@@ -412,6 +419,8 @@ export const useCalendar = defineStore('calendar', () => {
|
|||||||
getMonthName,
|
getMonthName,
|
||||||
setViewType,
|
setViewType,
|
||||||
getViewTypeTitle,
|
getViewTypeTitle,
|
||||||
isCurrentScreenActive
|
isCurrentScreenActive,
|
||||||
|
isAdvancedSearchOpen,
|
||||||
|
revealAdvancedSearch
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,20 +1,15 @@
|
|||||||
import { charactersList } from '@/data/Characters'
|
import { charactersList } from '@/data/Characters'
|
||||||
import type { Character } from '@/models/Characters'
|
import type { Character } from '@/models/Characters'
|
||||||
import { defineStore } from 'pinia'
|
import { defineStore } from 'pinia'
|
||||||
import { computed, type ComputedRef } from 'vue'
|
|
||||||
|
|
||||||
export const useCharacters = defineStore('characters', () => {
|
export const useCharacters = defineStore('characters', () => {
|
||||||
const characters: Character[] = charactersList
|
const characters: Character[] = charactersList
|
||||||
|
|
||||||
// Get all birth events
|
// Get all birth events
|
||||||
const charactersWithBirthData: ComputedRef<Character[]> = computed(() =>
|
const charactersWithBirthData: Character[] = characters.filter((character) => character.birth)
|
||||||
characters.filter((character) => character.birth)
|
|
||||||
)
|
|
||||||
|
|
||||||
// Get all death events
|
// Get all death events
|
||||||
const charactersWithDeathData: ComputedRef<Character[]> = computed(() =>
|
const charactersWithDeathData: Character[] = characters.filter((character) => character.death)
|
||||||
characters.filter((character) => character.death)
|
|
||||||
)
|
|
||||||
|
|
||||||
return { characters, charactersWithBirthData, charactersWithDeathData }
|
return { characters, charactersWithBirthData, charactersWithDeathData }
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,40 +1,34 @@
|
|||||||
import type { CalendarEvent } from '@/models/Events'
|
|
||||||
import { defineStore } from 'pinia'
|
|
||||||
import { computed, ref, watch, type Ref } from 'vue'
|
|
||||||
import { useCalendar } from './CalendarStore'
|
|
||||||
import { useCharacters } from './CharacterStore'
|
|
||||||
import { regularEvents } from '@/data/Events'
|
import { regularEvents } from '@/data/Events'
|
||||||
import { convertDateToDays, daysPerMonth } from '@/models/Date'
|
import { convertDateToDays, daysPerMonth } from '@/models/Date'
|
||||||
|
import type { CalendarEvent } from '@/models/Events'
|
||||||
|
import { defineStore } from 'pinia'
|
||||||
|
import { ref, watch, type Ref } from 'vue'
|
||||||
|
import { useCalendar } from './CalendarStore'
|
||||||
|
import { useCharacters } from './CharacterStore'
|
||||||
|
|
||||||
export const useCalendarEvents = defineStore('calendar-events', () => {
|
export const useCalendarEvents = defineStore('calendar-events', () => {
|
||||||
const { currentDate, currentConfig, currentLeimDate } = useCalendar()
|
const { currentDate, currentConfig } = useCalendar()
|
||||||
const { charactersWithBirthData, charactersWithDeathData } = useCharacters()
|
const { charactersWithBirthData, charactersWithDeathData } = useCharacters()
|
||||||
|
|
||||||
const baseEvents = ref<CalendarEvent[]>(regularEvents)
|
const baseEvents: CalendarEvent[] = regularEvents
|
||||||
|
|
||||||
const characterBirthEvents = computed(() => {
|
const characterBirthEvents = charactersWithBirthData.map((character) => {
|
||||||
return charactersWithBirthData.map((character) => {
|
return {
|
||||||
return {
|
title: `Naissance de ${character.name}`,
|
||||||
title: `Naissance de ${character.name}`,
|
date: character.birth,
|
||||||
date: character.birth,
|
category: 'naissance'
|
||||||
category: 'naissance'
|
} as CalendarEvent
|
||||||
} as CalendarEvent
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
|
|
||||||
const characterDeathEvents = computed(() => {
|
const characterDeathEvents = charactersWithDeathData.map((character) => {
|
||||||
return charactersWithDeathData.map((character) => {
|
return {
|
||||||
return {
|
title: `Décès de ${character.name}`,
|
||||||
title: `Décès de ${character.name}`,
|
date: character.death,
|
||||||
date: character.death,
|
category: 'mort'
|
||||||
category: 'mort'
|
} as CalendarEvent
|
||||||
} as CalendarEvent
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
|
|
||||||
const allEvents = computed(() => {
|
const allEvents = [...characterBirthEvents, ...characterDeathEvents, ...baseEvents]
|
||||||
return [...characterBirthEvents.value, ...characterDeathEvents.value, ...baseEvents.value]
|
|
||||||
})
|
|
||||||
|
|
||||||
// Gets all current event in its default state
|
// Gets all current event in its default state
|
||||||
const currentEvents: Ref<CalendarEvent[]> = ref(computeCurrentEvents())
|
const currentEvents: Ref<CalendarEvent[]> = ref(computeCurrentEvents())
|
||||||
@@ -100,7 +94,7 @@ export const useCalendarEvents = defineStore('calendar-events', () => {
|
|||||||
* @returns A list of events that can appear in the current view
|
* @returns A list of events that can appear in the current view
|
||||||
*/
|
*/
|
||||||
function computeCurrentEvents(): CalendarEvent[] {
|
function computeCurrentEvents(): CalendarEvent[] {
|
||||||
return allEvents.value.filter((event) => shouldEventBeDisplayed(event))
|
return allEvents.filter((event) => shouldEventBeDisplayed(event))
|
||||||
}
|
}
|
||||||
|
|
||||||
return { baseEvents, allEvents, currentEvents }
|
return { baseEvents, allEvents, currentEvents }
|
||||||
|
|||||||
23
src/views/CalendarPage.vue
Normal file
23
src/views/CalendarPage.vue
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
<script lang="ts" setup>
|
||||||
|
import { storeToRefs } from 'pinia'
|
||||||
|
import { onMounted } from 'vue'
|
||||||
|
import { useCalendar } from '@/stores/CalendarStore'
|
||||||
|
|
||||||
|
import Calendar from '@/components/calendar/Calendar.vue'
|
||||||
|
import Sidebar from '@/components/calendar/Sidebar.vue'
|
||||||
|
import CalendarSearch from '@/components/calendar/search/CalendarSearch.vue'
|
||||||
|
|
||||||
|
const { validateUrlParams } = useCalendar()
|
||||||
|
const { isAdvancedSearchOpen } = storeToRefs(useCalendar())
|
||||||
|
|
||||||
|
onMounted(() => validateUrlParams())
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<main class="h-full grid grid-cols-[auto_1fr]">
|
||||||
|
<Sidebar />
|
||||||
|
<Calendar />
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<CalendarSearch v-model:model-value="isAdvancedSearchOpen" />
|
||||||
|
</template>
|
||||||
22
src/views/HomePage.vue
Normal file
22
src/views/HomePage.vue
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'
|
||||||
|
import { Badge } from '@/components/ui/badge'
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<main class="h-full grid place-items-center" v-once>
|
||||||
|
<Card class="w-1/3 min-w-72" link="/calendrier">
|
||||||
|
<CardHeader>
|
||||||
|
<CardTitle>Calendrier</CardTitle>
|
||||||
|
<CardDescription>
|
||||||
|
<Badge class="mix-blend-luminosity font-bold bg-gray-600" variant="secondary">
|
||||||
|
chronologie
|
||||||
|
</Badge>
|
||||||
|
</CardDescription>
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent>
|
||||||
|
Chronologie complète de Léïm, rassemblant les évènements et personnages clés du monde
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
</main>
|
||||||
|
</template>
|
||||||
@@ -1,49 +0,0 @@
|
|||||||
<script lang="ts" setup>
|
|
||||||
import Calendar from '@/components/calendar/Calendar.vue'
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<main class="h-full">
|
|
||||||
<Calendar />
|
|
||||||
<!-- <pre>
|
|
||||||
{{ currentDate }}
|
|
||||||
</pre>
|
|
||||||
<div class="grid gap-2">
|
|
||||||
<div class="flex gap-2">
|
|
||||||
<button class="bg-slate-800 py-2 px-4 rounded-sm" @click="incrementMonth()">Month +</button>
|
|
||||||
<button class="bg-slate-800 py-2 px-4 rounded-sm" @click="decrementMonth()">Month -</button>
|
|
||||||
</div>
|
|
||||||
<div class="flex gap-2">
|
|
||||||
<button class="bg-slate-800 py-2 px-4 rounded-sm" @click="incrementYear()">Year +</button>
|
|
||||||
<button class="bg-slate-800 py-2 px-4 rounded-sm" @click="decrementYear()">Year -</button>
|
|
||||||
</div>
|
|
||||||
<div class="flex gap-2">
|
|
||||||
<button class="bg-slate-800 py-2 px-4 rounded-sm" @click="incrementYear(100)">
|
|
||||||
Century +
|
|
||||||
</button>
|
|
||||||
<button class="bg-slate-800 py-2 px-4 rounded-sm" @click="decrementYear(100)">
|
|
||||||
Century -
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<div class="flex gap-2">
|
|
||||||
<button class="bg-slate-800 py-2 px-4 rounded-sm" @click="incrementYear(1000)">
|
|
||||||
Millenia +
|
|
||||||
</button>
|
|
||||||
<button class="bg-slate-800 py-2 px-4 rounded-sm" @click="decrementYear(1000)">
|
|
||||||
Millenia -
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<div class="flex gap-2">
|
|
||||||
<input class="bg-slate-900" type="number" v-model="monthTarget" />
|
|
||||||
<button class="bg-slate-800 py-2 px-4 rounded-sm" @click="setMonth(monthTarget)">
|
|
||||||
Set Month
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<pre>
|
|
||||||
Current events:
|
|
||||||
{{ currentEvents }}
|
|
||||||
</pre> -->
|
|
||||||
</main>
|
|
||||||
</template>
|
|
||||||
@@ -89,5 +89,25 @@ module.exports = {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
plugins: [animate]
|
plugins: [
|
||||||
|
animate,
|
||||||
|
function ({ addBase, theme }) {
|
||||||
|
function extractColorVars(colorObj, colorGroup = '') {
|
||||||
|
return Object.keys(colorObj).reduce((vars, colorKey) => {
|
||||||
|
const value = colorObj[colorKey]
|
||||||
|
|
||||||
|
const newVars =
|
||||||
|
typeof value === 'string'
|
||||||
|
? { [`--color${colorGroup}-${colorKey}`]: value }
|
||||||
|
: extractColorVars(value, `-${colorKey}`)
|
||||||
|
|
||||||
|
return { ...vars, ...newVars }
|
||||||
|
}, {})
|
||||||
|
}
|
||||||
|
|
||||||
|
addBase({
|
||||||
|
':root': extractColorVars(theme('colors'))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user