Merge branch 'features/nuxt-supabase' into features/nuxt
This commit is contained in:
@@ -2,18 +2,62 @@
|
|||||||
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 CalendarMenu from './CalendarMenu.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 { currentConfig } = useCalendar()
|
const route = useRoute()
|
||||||
const { selectedDate, jumpToDate } = useCalendar()
|
const worldId = route.params.id
|
||||||
|
|
||||||
const { fetchEvents } = useCalendarEvents()
|
const { setMonths, setDefaultDate, currentConfig, selectedDate, jumpToDate } = useCalendar()
|
||||||
fetchEvents()
|
const { setEvents } = useCalendarEvents()
|
||||||
|
const { setCharacters } = useCharacters()
|
||||||
|
|
||||||
|
const { data: calendar, pending: calPending, refresh: calRefresh } = await useLazyFetch(`/api/calendars/query?world_id=${worldId}`)
|
||||||
|
const { data: characters, pending: charPending, refresh: charRefresh } = await useLazyFetch(`/api/characters/query?world_id=${worldId}`)
|
||||||
|
|
||||||
|
if (!calendar.value) {
|
||||||
|
await calRefresh()
|
||||||
|
} else {
|
||||||
|
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 (!characters.value) {
|
||||||
|
await charRefresh()
|
||||||
|
} else {
|
||||||
|
if (characters.value?.data) {
|
||||||
|
setCharacters(characters.value?.data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
watch(calPending, (newStatus) => {
|
||||||
|
if (!newStatus) {
|
||||||
|
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(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) {
|
||||||
@@ -38,11 +82,20 @@ onMounted(() => {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="h-full grid grid-rows-[auto,1fr]">
|
<div class="h-full">
|
||||||
<CalendarMenu />
|
<template v-if="calPending || charPending">
|
||||||
|
<div class="h-full grid place-items-center">
|
||||||
|
Loading notamment
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<template v-else>
|
||||||
|
<div class="h-full grid grid-rows-[auto,1fr]">
|
||||||
|
<CalendarMenu />
|
||||||
|
|
||||||
<KeepAlive>
|
<KeepAlive>
|
||||||
<component :is="currentViewComponent" />
|
<component :is="currentViewComponent"/>
|
||||||
</KeepAlive>
|
</KeepAlive>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { getRelativeString } from '@/models/Date'
|
|
||||||
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 } = useCalendar()
|
const { defaultDate, getFormattedDateTitle, getRelativeString } = useCalendar()
|
||||||
const { selectedDate } = storeToRefs(useCalendar())
|
const { selectedDate } = storeToRefs(useCalendar())
|
||||||
|
|
||||||
const mainDateTitle = computed(() => getFormattedDateTitle(selectedDate.value, true))
|
const mainDateTitle = computed(() => getFormattedDateTitle(selectedDate.value, true))
|
||||||
|
// const mainDateTitle = computed(() => convertDateToDays(selectedDate.value))
|
||||||
|
|
||||||
const dateDifference = computed(() => getRelativeString(defaultDate, selectedDate.value))
|
const dateDifference = computed(() => getRelativeString(defaultDate, selectedDate.value))
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -1,16 +1,16 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { ref } from 'vue'
|
import { ref } from 'vue'
|
||||||
import { cn } from '@/lib/utils'
|
import { cn } from '@/lib/utils'
|
||||||
import { areDatesIdentical, type LeimDate } from '@/models/Date'
|
import type { RPGDate } from '@/models/Date'
|
||||||
|
import type { CalendarEvent } from '~/models/CalendarEvent'
|
||||||
import type { CalendarEvent } from '@/models/Events'
|
|
||||||
import CalendarEventDetails from './CalendarEventDetails.vue'
|
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
event: CalendarEvent
|
event: CalendarEvent
|
||||||
tileDate: LeimDate
|
tileDate: RPGDate
|
||||||
}>()
|
}>()
|
||||||
|
|
||||||
|
const { areDatesIdentical } = useCalendar()
|
||||||
|
|
||||||
const spansMultipleDays = Boolean(props.event.startDate && props.event.endDate)
|
const spansMultipleDays = Boolean(props.event.startDate && props.event.endDate)
|
||||||
|
|
||||||
const isStartEvent = spansMultipleDays && areDatesIdentical(props.tileDate, props.event.startDate)
|
const isStartEvent = spansMultipleDays && areDatesIdentical(props.tileDate, props.event.startDate)
|
||||||
@@ -32,24 +32,24 @@ function handleClosePopover() {
|
|||||||
:class="
|
:class="
|
||||||
cn({
|
cn({
|
||||||
'text-white bg-slate-600 hover:bg-slate-700': !event.category,
|
'text-white bg-slate-600 hover:bg-slate-700': !event.category,
|
||||||
'text-white bg-lime-600 hover:bg-lime-700': event.category === 'naissance',
|
'text-white bg-lime-600 hover:bg-lime-700': event.category?.name === 'naissance',
|
||||||
'text-white bg-stone-500 hover:bg-stone-700': event.category === 'mort',
|
'text-white bg-stone-500 hover:bg-stone-700': event.category?.name === 'mort',
|
||||||
'text-white bg-orange-600 hover:bg-orange-700': event.category === 'catastrophe',
|
'text-white bg-orange-600 hover:bg-orange-700': event.category?.name === 'catastrophe',
|
||||||
'text-white bg-pink-600 hover:bg-pink-700': event.category === 'catastrophe naturelle',
|
'text-white bg-pink-600 hover:bg-pink-700': event.category?.name === 'catastrophe naturelle',
|
||||||
'text-white bg-sky-600 hover:bg-sky-700': event.category === 'législation',
|
'text-white bg-sky-600 hover:bg-sky-700': event.category?.name === 'législation',
|
||||||
'text-white bg-purple-600 hover:bg-purple-700': event.category === 'religion',
|
'text-white bg-purple-600 hover:bg-purple-700': event.category?.name === 'religion',
|
||||||
'text-white bg-emerald-600 hover:bg-emerald-700': event.category === 'joueurs',
|
'text-white bg-emerald-600 hover:bg-emerald-700': event.category?.name === 'joueurs',
|
||||||
'text-slate-900 bg-amber-300 hover:bg-amber-400': event.category === 'inauguration',
|
'text-slate-900 bg-amber-300 hover:bg-amber-400': event.category?.name === 'inauguration',
|
||||||
'text-slate-900 bg-emerald-200 hover:bg-emerald-300': event.category === 'invention',
|
'text-slate-900 bg-emerald-200 hover:bg-emerald-300': event.category?.name === 'invention',
|
||||||
'text-slate-900 bg-cyan-300 hover:bg-cyan-400': event.category === 'science',
|
'text-slate-900 bg-cyan-300 hover:bg-cyan-400': event.category?.name === 'science',
|
||||||
'text-slate-900 bg-white hover:bg-yellow-200': event.category === 'bénédiction',
|
'text-slate-900 bg-white hover:bg-yellow-200': event.category?.name === 'bénédiction',
|
||||||
'text-slate-900 bg-purple-200 hover:bg-purple-300': event.category === 'découverte',
|
'text-slate-900 bg-purple-200 hover:bg-purple-300': event.category?.name === 'découverte',
|
||||||
'text-slate-900 bg-indigo-200 hover:bg-indigo-300': event.category === 'exploration',
|
'text-slate-900 bg-indigo-200 hover:bg-indigo-300': event.category?.name === 'exploration',
|
||||||
'text-white bg-amber-600 hover:bg-amber-700': event.category === 'construction',
|
'text-white bg-amber-600 hover:bg-amber-700': event.category?.name === 'construction',
|
||||||
'text-slate-900 bg-violet-200 hover:bg-violet-300': event.category === 'arcanologie',
|
'text-slate-900 bg-violet-200 hover:bg-violet-300': event.category?.name === 'arcanologie',
|
||||||
'text-white bg-rose-600 hover:bg-rose-700': event.category === 'criminalité',
|
'text-white bg-rose-600 hover:bg-rose-700': event.category?.name === 'criminalité',
|
||||||
'text-white bg-stone-600 hover:bg-stone-700': event.category === 'scandale',
|
'text-white bg-stone-600 hover:bg-stone-700': event.category?.name === 'scandale',
|
||||||
'text-slate-900 bg-yellow-500 hover:bg-yellow-600': event.category === 'commerce',
|
'text-slate-900 bg-yellow-500 hover:bg-yellow-600': event.category?.name === 'commerce',
|
||||||
'rounded-r-none': isStartEvent,
|
'rounded-r-none': isStartEvent,
|
||||||
'rounded-l-none': isEndEvent
|
'rounded-l-none': isEndEvent
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { getRelativeString, type LeimDate } from '@/models/Date'
|
import type { RPGDate } from '@/models/Date'
|
||||||
import type { CalendarEvent } from '@/models/Events'
|
import type { CalendarEvent } from '@/models/CalendarEvent'
|
||||||
import { useCalendar } from '@/stores/CalendarStore'
|
import { useCalendar } from '@/stores/CalendarStore'
|
||||||
import { useCalendarEvents } from '@/stores/EventStore'
|
import { useCalendarEvents } from '@/stores/EventStore'
|
||||||
|
|
||||||
@@ -27,12 +27,14 @@ const emit = defineEmits<{
|
|||||||
(e: 'query:close-popover'): void
|
(e: 'query:close-popover'): void
|
||||||
}>()
|
}>()
|
||||||
|
|
||||||
|
const { getRelativeString } = 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
|
||||||
|
|
||||||
function handleJumpToDate(date: LeimDate) {
|
function handleJumpToDate(date: RPGDate) {
|
||||||
jumpToDate(date)
|
jumpToDate(date)
|
||||||
emit('query:close-popover')
|
emit('query:close-popover')
|
||||||
}
|
}
|
||||||
@@ -58,24 +60,24 @@ function handleGotoRelativeEvent(position: 'next' | 'prev' = 'next') {
|
|||||||
:hide-when-detached="true"
|
:hide-when-detached="true"
|
||||||
:class="{
|
:class="{
|
||||||
'border-slate-800': !event.category,
|
'border-slate-800': !event.category,
|
||||||
'border-lime-800': event.category === 'naissance',
|
'border-lime-800': event.category?.name === 'naissance',
|
||||||
'border-stone-600': event.category === 'mort',
|
'border-stone-600': event.category?.name === 'mort',
|
||||||
'border-orange-800': event.category === 'catastrophe',
|
'border-orange-800': event.category?.name === 'catastrophe',
|
||||||
'border-pink-800': event.category === 'catastrophe naturelle',
|
'border-pink-800': event.category?.name === 'catastrophe naturelle',
|
||||||
'border-sky-800': event.category === 'législation',
|
'border-sky-800': event.category?.name === 'législation',
|
||||||
'border-purple-800': event.category === 'religion',
|
'border-purple-800': event.category?.name === 'religion',
|
||||||
'border-emerald-800': event.category === 'joueurs',
|
'border-emerald-800': event.category?.name === 'joueurs',
|
||||||
'border-amber-800': event.category === 'inauguration',
|
'border-amber-800': event.category?.name === 'inauguration',
|
||||||
'border-green-800': event.category === 'invention',
|
'border-green-800': event.category?.name === 'invention',
|
||||||
'border-cyan-800': event.category === 'science',
|
'border-cyan-800': event.category?.name === 'science',
|
||||||
'border-slate-600': event.category === 'bénédiction',
|
'border-slate-600': event.category?.name === 'bénédiction',
|
||||||
'border-purple-700': event.category === 'découverte',
|
'border-purple-700': event.category?.name === 'découverte',
|
||||||
'border-indigo-700': event.category === 'exploration',
|
'border-indigo-700': event.category?.name === 'exploration',
|
||||||
'border-amber-700': event.category === 'construction',
|
'border-amber-700': event.category?.name === 'construction',
|
||||||
'border-violet-700': event.category === 'arcanologie',
|
'border-violet-700': event.category?.name === 'arcanologie',
|
||||||
'border-rose-800': event.category === 'criminalité',
|
'border-rose-800': event.category?.name === 'criminalité',
|
||||||
'border-stone-700': event.category === 'scandale',
|
'border-stone-700': event.category?.name === 'scandale',
|
||||||
'border-yellow-600': event.category === 'commerce'
|
'border-yellow-600': event.category?.name === 'commerce'
|
||||||
}"
|
}"
|
||||||
>
|
>
|
||||||
<div class="grid gap-1">
|
<div class="grid gap-1">
|
||||||
@@ -110,13 +112,13 @@ function handleGotoRelativeEvent(position: 'next' | 'prev' = 'next') {
|
|||||||
<ul class="flex gap-1">
|
<ul class="flex gap-1">
|
||||||
<li v-if="event.category">
|
<li v-if="event.category">
|
||||||
<UiBadge class="mix-blend-luminosity font-bold bg-gray-600" variant="secondary">
|
<UiBadge class="mix-blend-luminosity font-bold bg-gray-600" variant="secondary">
|
||||||
{{ event.category }}
|
{{ event.category?.name }}
|
||||||
</UiBadge>
|
</UiBadge>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<li v-for="cat in event.secondaryCategories" :key="cat">
|
<li v-for="cat in event.secondaryCategories" :key="cat.id">
|
||||||
<UiBadge class="mix-blend-luminosity bg-gray-600" variant="secondary">
|
<UiBadge class="mix-blend-luminosity bg-gray-600" variant="secondary">
|
||||||
{{ cat }}
|
{{ cat.name }}
|
||||||
</UiBadge>
|
</UiBadge>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|||||||
@@ -2,11 +2,6 @@
|
|||||||
import { useCalendar } from '@/stores/CalendarStore'
|
import { useCalendar } from '@/stores/CalendarStore'
|
||||||
|
|
||||||
import { PhMagnifyingGlass } from '@phosphor-icons/vue'
|
import { PhMagnifyingGlass } from '@phosphor-icons/vue'
|
||||||
import CalendarMenuNav from './CalendarMenuNav.vue'
|
|
||||||
import CalendarMenuSubnav from './CalendarMenuSubnav.vue'
|
|
||||||
import CalendarMenuToday from './CalendarMenuToday.vue'
|
|
||||||
import CalendarSwitch from './CalendarSwitch.vue'
|
|
||||||
import CalendarCurrentDate from './CalendarCurrentDate.vue'
|
|
||||||
|
|
||||||
const { revealAdvancedSearch } = useCalendar()
|
const { revealAdvancedSearch } = useCalendar()
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { daysPerMonth, monthsPerYear, type LeimDate } from '@/models/Date'
|
import { type RPGDate } from '@/models/Date'
|
||||||
import { useCalendar } from '@/stores/CalendarStore'
|
import { useCalendar } from '@/stores/CalendarStore'
|
||||||
import { useCalendarEvents } from '@/stores/EventStore'
|
import { useCalendarEvents } from '@/stores/EventStore'
|
||||||
|
|
||||||
@@ -9,7 +9,12 @@ const { currentDate, currentConfig, jumpToDate } = useCalendar()
|
|||||||
const { getRelativeEventFromDate } = useCalendarEvents()
|
const { getRelativeEventFromDate } = useCalendarEvents()
|
||||||
|
|
||||||
function handleGotoPreviousEventPage(position: 'next' | 'prev' = 'next') {
|
function handleGotoPreviousEventPage(position: 'next' | 'prev' = 'next') {
|
||||||
let fromDate: LeimDate
|
let fromDate: RPGDate
|
||||||
|
|
||||||
|
// To modify, obviously
|
||||||
|
const daysPerMonth = 32
|
||||||
|
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
|
||||||
|
|
||||||
|
|||||||
@@ -3,9 +3,7 @@ import { useCalendar } from '@/stores/CalendarStore'
|
|||||||
import { storeToRefs } from 'pinia'
|
import { storeToRefs } from 'pinia'
|
||||||
import { computed } from 'vue'
|
import { computed } from 'vue'
|
||||||
|
|
||||||
import { areDatesIdentical } from '@/models/Date'
|
const { defaultDate, areDatesIdentical } = useCalendar()
|
||||||
|
|
||||||
const { defaultDate } = useCalendar()
|
|
||||||
const { selectedDate } = storeToRefs(useCalendar())
|
const { selectedDate } = storeToRefs(useCalendar())
|
||||||
const { jumpToDefaultDate, getFormattedDateTitle } = useCalendar()
|
const { jumpToDefaultDate, getFormattedDateTitle } = useCalendar()
|
||||||
|
|
||||||
|
|||||||
@@ -1,17 +1,13 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import {
|
import {
|
||||||
characterCategories,
|
|
||||||
isCharacter,
|
isCharacter,
|
||||||
type Character,
|
type Character,
|
||||||
type CharacterCategory
|
|
||||||
} from '@/models/Characters'
|
} from '@/models/Characters'
|
||||||
import type { LeimDateOrder } from '@/models/Date'
|
import type { RPGDateOrder } from '@/models/Date'
|
||||||
import {
|
import {
|
||||||
calendarEventCategories,
|
|
||||||
isCalendarEvent,
|
isCalendarEvent,
|
||||||
type CalendarEvent,
|
type CalendarEvent,
|
||||||
type CalendarEventCategory
|
} from '~/models/CalendarEvent'
|
||||||
} from '@/models/Events'
|
|
||||||
import { useCharacters } from '@/stores/CharacterStore'
|
import { useCharacters } from '@/stores/CharacterStore'
|
||||||
import { useCalendarEvents } from '@/stores/EventStore'
|
import { useCalendarEvents } from '@/stores/EventStore'
|
||||||
import { capitalize } from '@/utils/Strings'
|
import { capitalize } from '@/utils/Strings'
|
||||||
@@ -29,6 +25,7 @@ import {
|
|||||||
} from 'radix-vue'
|
} from 'radix-vue'
|
||||||
|
|
||||||
import SearchList from './lists/SearchList.vue'
|
import SearchList from './lists/SearchList.vue'
|
||||||
|
import type { Category } from '~/models/Category'
|
||||||
|
|
||||||
const { characters } = storeToRefs(useCharacters())
|
const { characters } = storeToRefs(useCharacters())
|
||||||
const { allEvents } = storeToRefs(useCalendarEvents())
|
const { allEvents } = storeToRefs(useCalendarEvents())
|
||||||
@@ -41,7 +38,7 @@ const searchQuery = ref<string>('')
|
|||||||
const selectedEntity = useStorage('se', 'events' as SearchMode)
|
const selectedEntity = useStorage('se', 'events' as SearchMode)
|
||||||
|
|
||||||
// Order
|
// Order
|
||||||
const selectedOrder = ref<LeimDateOrder>('asc')
|
const selectedOrder = ref<RPGDateOrder>('asc')
|
||||||
function setOrderAsc() {
|
function setOrderAsc() {
|
||||||
selectedOrder.value = 'asc'
|
selectedOrder.value = 'asc'
|
||||||
resetPage()
|
resetPage()
|
||||||
@@ -105,7 +102,7 @@ const searchResults = computed<(Character | CalendarEvent)[]>(() => {
|
|||||||
|
|
||||||
// Handle categories logic
|
// Handle categories logic
|
||||||
let hitCategories: boolean = false
|
let hitCategories: boolean = false
|
||||||
const allCategories: CalendarEventCategory[] = []
|
const allCategories: Category[] = []
|
||||||
|
|
||||||
if (item.category) {
|
if (item.category) {
|
||||||
allCategories.push(item.category)
|
allCategories.push(item.category)
|
||||||
@@ -116,7 +113,7 @@ const searchResults = computed<(Character | CalendarEvent)[]>(() => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
hitCategories = selectedCategories.value.every((selectedCat) => {
|
hitCategories = selectedCategories.value.every((selectedCat) => {
|
||||||
return allCategories.includes(selectedCat as CalendarEventCategory)
|
return allCategories.includes(selectedCat as Category)
|
||||||
})
|
})
|
||||||
|
|
||||||
return (hitTitle || hitDesc) && hitCategories
|
return (hitTitle || hitDesc) && hitCategories
|
||||||
@@ -139,7 +136,7 @@ const searchResults = computed<(Character | CalendarEvent)[]>(() => {
|
|||||||
|
|
||||||
// Handle categories logic
|
// Handle categories logic
|
||||||
let hitCategories: boolean = false
|
let hitCategories: boolean = false
|
||||||
const allCategories: CharacterCategory[] = []
|
const allCategories: Category[] = []
|
||||||
|
|
||||||
if (item.category) {
|
if (item.category) {
|
||||||
allCategories.push(item.category)
|
allCategories.push(item.category)
|
||||||
@@ -150,7 +147,7 @@ const searchResults = computed<(Character | CalendarEvent)[]>(() => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
hitCategories = selectedCategories.value.every((selectedCat) => {
|
hitCategories = selectedCategories.value.every((selectedCat) => {
|
||||||
return allCategories.includes(selectedCat as CharacterCategory)
|
return allCategories.includes(selectedCat as Category)
|
||||||
})
|
})
|
||||||
|
|
||||||
return hitTitle && hitCategories
|
return hitTitle && hitCategories
|
||||||
@@ -207,14 +204,10 @@ watch([currentPage, selectedEntity], () => {
|
|||||||
|
|
||||||
// Compute categories based on current selectedEntity
|
// Compute categories based on current selectedEntity
|
||||||
const currentCategories = computed(() => {
|
const currentCategories = computed(() => {
|
||||||
if (selectedEntity.value === 'characters') {
|
return []
|
||||||
return [...characterCategories]
|
|
||||||
} else {
|
|
||||||
return [...calendarEventCategories]
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
|
||||||
const selectedCategories = ref<(CharacterCategory | CalendarEventCategory)[]>([])
|
const selectedCategories = ref<(Category)[]>([])
|
||||||
const categoryFilterOpened = ref<boolean>(false)
|
const categoryFilterOpened = ref<boolean>(false)
|
||||||
const searchCategory = ref<string>('')
|
const searchCategory = ref<string>('')
|
||||||
|
|
||||||
@@ -227,7 +220,7 @@ const filteredCategories = computed(() =>
|
|||||||
*
|
*
|
||||||
* @param e Radix Change Event
|
* @param e Radix Change Event
|
||||||
*/
|
*/
|
||||||
function handleCategorySelect(e: (CharacterCategory | CalendarEventCategory)) {
|
function handleCategorySelect(e: (Category)) {
|
||||||
if (typeof e === 'string') {
|
if (typeof e === 'string') {
|
||||||
searchCategory.value = ''
|
searchCategory.value = ''
|
||||||
selectedCategories.value.push(e)
|
selectedCategories.value.push(e)
|
||||||
@@ -290,9 +283,9 @@ function handleCategorySelect(e: (CharacterCategory | CalendarEventCategory)) {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex items-center gap-1">
|
<div class="flex items-center gap-1">
|
||||||
<UiTagsInput class="px-0 gap-0 w-72" :model-value="selectedCategories">
|
<UiTagsInput class="px-0 gap-0 w-72">
|
||||||
<div class="flex gap-2 flex-wrap items-center px-3">
|
<div class="flex gap-2 flex-wrap items-center px-3">
|
||||||
<UiTagsInputItem v-for="item in selectedCategories" :key="item" :value="item">
|
<UiTagsInputItem v-for="item in selectedCategories" :key="item.id" :value="item.name">
|
||||||
<UiTagsInputItemText class="capitalize" />
|
<UiTagsInputItemText class="capitalize" />
|
||||||
<UiTagsInputItemDelete />
|
<UiTagsInputItemDelete />
|
||||||
</UiTagsInputItem>
|
</UiTagsInputItem>
|
||||||
|
|||||||
@@ -1,21 +1,23 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import type { Character } from '@/models/Characters'
|
import type { Character } from '@/models/Characters'
|
||||||
import type { LeimDate } 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'
|
||||||
|
|
||||||
defineProps<{
|
const props = defineProps<{
|
||||||
character: Character
|
character: Character
|
||||||
}>()
|
}>()
|
||||||
|
|
||||||
defineEmits<{
|
defineEmits<{
|
||||||
(e: 'query:date-jump', payload: LeimDate): void
|
(e: 'query:date-jump', payload: RPGDate): void
|
||||||
}>()
|
}>()
|
||||||
|
|
||||||
const { getFormattedDateTitle } = useCalendar()
|
const { getFormattedDateTitle } = useCalendar()
|
||||||
|
|
||||||
|
console.log(props.character.birth)
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|||||||
@@ -1,10 +1,8 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { getRelativeString, type LeimDate } from '@/models/Date'
|
import type { RPGDate } from '@/models/Date'
|
||||||
import type { CalendarEvent } from '@/models/Events'
|
import type { CalendarEvent } from '@/models/CalendarEvent'
|
||||||
import { useCalendar } from '@/stores/CalendarStore'
|
import { useCalendar } from '@/stores/CalendarStore'
|
||||||
|
|
||||||
import { Badge } from '@/components/ui/badge'
|
|
||||||
import { Button } from '@/components/ui/button'
|
|
||||||
import { PhArrowSquareOut, PhHourglassMedium, PhAlarm } from '@phosphor-icons/vue'
|
import { PhArrowSquareOut, PhHourglassMedium, PhAlarm } from '@phosphor-icons/vue'
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
@@ -12,9 +10,11 @@ const props = defineProps<{
|
|||||||
}>()
|
}>()
|
||||||
|
|
||||||
defineEmits<{
|
defineEmits<{
|
||||||
(e: 'query:date-jump', payload: LeimDate): void
|
(e: 'query:date-jump', payload: RPGDate): void
|
||||||
}>()
|
}>()
|
||||||
|
|
||||||
|
const { getRelativeString } = useCalendar()
|
||||||
|
|
||||||
const { defaultDate, getFormattedDateTitle } = useCalendar()
|
const { defaultDate, getFormattedDateTitle } = useCalendar()
|
||||||
|
|
||||||
const dateDifference: string = getRelativeString(defaultDate, props.event.startDate)
|
const dateDifference: string = getRelativeString(defaultDate, props.event.startDate)
|
||||||
@@ -28,24 +28,24 @@ const dateDuration: string | null = props.event.endDate
|
|||||||
class="relative block w-full text-left py-3 px-4 rounded-sm transition-colors"
|
class="relative block w-full text-left py-3 px-4 rounded-sm transition-colors"
|
||||||
:class="{
|
:class="{
|
||||||
'text-white bg-slate-600 hover:bg-slate-700': !event.category,
|
'text-white bg-slate-600 hover:bg-slate-700': !event.category,
|
||||||
'text-white bg-lime-600 hover:bg-lime-700': event.category === 'naissance',
|
'text-white bg-lime-600 hover:bg-lime-700': event.category?.name === 'naissance',
|
||||||
'text-white bg-stone-500 hover:bg-stone-700': event.category === 'mort',
|
'text-white bg-stone-500 hover:bg-stone-700': event.category?.name === 'mort',
|
||||||
'text-white bg-orange-600 hover:bg-orange-700': event.category === 'catastrophe',
|
'text-white bg-orange-600 hover:bg-orange-700': event.category?.name === 'catastrophe',
|
||||||
'text-white bg-pink-600 hover:bg-pink-700': event.category === 'catastrophe naturelle',
|
'text-white bg-pink-600 hover:bg-pink-700': event.category?.name === 'catastrophe naturelle',
|
||||||
'text-white bg-sky-600 hover:bg-sky-700': event.category === 'législation',
|
'text-white bg-sky-600 hover:bg-sky-700': event.category?.name === 'législation',
|
||||||
'text-white bg-purple-600 hover:bg-purple-700': event.category === 'religion',
|
'text-white bg-purple-600 hover:bg-purple-700': event.category?.name === 'religion',
|
||||||
'text-white bg-emerald-600 hover:bg-emerald-700': event.category === 'joueurs',
|
'text-white bg-emerald-600 hover:bg-emerald-700': event.category?.name === 'joueurs',
|
||||||
'text-slate-900 bg-amber-300 hover:bg-amber-400': event.category === 'inauguration',
|
'text-slate-900 bg-amber-300 hover:bg-amber-400': event.category?.name === 'inauguration',
|
||||||
'text-slate-900 bg-emerald-200 hover:bg-emerald-300': event.category === 'invention',
|
'text-slate-900 bg-emerald-200 hover:bg-emerald-300': event.category?.name === 'invention',
|
||||||
'text-slate-900 bg-cyan-300 hover:bg-cyan-400': event.category === 'science',
|
'text-slate-900 bg-cyan-300 hover:bg-cyan-400': event.category?.name === 'science',
|
||||||
'text-slate-900 bg-white hover:bg-yellow-200': event.category === 'bénédiction',
|
'text-slate-900 bg-white hover:bg-yellow-200': event.category?.name === 'bénédiction',
|
||||||
'text-slate-900 bg-purple-200 hover:bg-purple-300': event.category === 'découverte',
|
'text-slate-900 bg-purple-200 hover:bg-purple-300': event.category?.name === 'découverte',
|
||||||
'text-slate-900 bg-indigo-200 hover:bg-indigo-300': event.category === 'exploration',
|
'text-slate-900 bg-indigo-200 hover:bg-indigo-300': event.category?.name === 'exploration',
|
||||||
'text-white bg-amber-600 hover:bg-amber-700': event.category === 'construction',
|
'text-white bg-amber-600 hover:bg-amber-700': event.category?.name === 'construction',
|
||||||
'text-slate-900 bg-violet-200 hover:bg-violet-300': event.category === 'arcanologie',
|
'text-slate-900 bg-violet-200 hover:bg-violet-300': event.category?.name === 'arcanologie',
|
||||||
'text-white bg-rose-600 hover:bg-rose-700': event.category === 'criminalité',
|
'text-white bg-rose-600 hover:bg-rose-700': event.category?.name === 'criminalité',
|
||||||
'text-white bg-stone-600 hover:bg-stone-700': event.category === 'scandale',
|
'text-white bg-stone-600 hover:bg-stone-700': event.category?.name === 'scandale',
|
||||||
'text-slate-900 bg-yellow-500 hover:bg-yellow-600': event.category === 'commerce'
|
'text-slate-900 bg-yellow-500 hover:bg-yellow-600': event.category?.name === 'commerce'
|
||||||
}"
|
}"
|
||||||
@click="$emit('query:date-jump', event.startDate)"
|
@click="$emit('query:date-jump', event.startDate)"
|
||||||
>
|
>
|
||||||
@@ -54,12 +54,12 @@ const dateDuration: string | null = props.event.endDate
|
|||||||
{{ event.title }}
|
{{ event.title }}
|
||||||
</h2>
|
</h2>
|
||||||
<div v-if="event.wiki">
|
<div v-if="event.wiki">
|
||||||
<Button variant="link" size="xs" as-child class="text-inherit">
|
<UiButton variant="link" size="xs" as-child class="text-inherit">
|
||||||
<a :href="event.wiki" target="_blank">
|
<a :href="event.wiki" target="_blank">
|
||||||
Wiki
|
Wiki
|
||||||
<PhArrowSquareOut size="16" weight="fill" />
|
<PhArrowSquareOut size="16" weight="fill" />
|
||||||
</a>
|
</a>
|
||||||
</Button>
|
</UiButton>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -91,15 +91,15 @@ const dateDuration: string | null = props.event.endDate
|
|||||||
<div v-if="event.category || event.secondaryCategories" class="absolute top-3 right-4">
|
<div v-if="event.category || event.secondaryCategories" class="absolute top-3 right-4">
|
||||||
<ul class="flex gap-1">
|
<ul class="flex gap-1">
|
||||||
<li v-if="event.category">
|
<li v-if="event.category">
|
||||||
<Badge class="mix-blend-luminosity font-bold bg-gray-600" variant="secondary">
|
<UiBadge class="mix-blend-luminosity font-bold bg-gray-600" variant="secondary">
|
||||||
{{ event.category }}
|
{{ event.category?.name }}
|
||||||
</Badge>
|
</UiBadge>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<li v-for="cat in event.secondaryCategories" :key="cat">
|
<li v-for="cat in event.secondaryCategories" :key="cat.id">
|
||||||
<Badge class="mix-blend-luminosity bg-gray-600" variant="secondary">
|
<UiBadge class="mix-blend-luminosity bg-gray-600" variant="secondary">
|
||||||
{{ cat }}
|
{{ cat.name }}
|
||||||
</Badge>
|
</UiBadge>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { isCharacter, type Character } from '@/models/Characters'
|
import { isCharacter, type Character } from '@/models/Characters'
|
||||||
import { compareDates, type LeimDate, type LeimDateOrder } from '@/models/Date'
|
import type { RPGDate, RPGDateOrder } from '@/models/Date'
|
||||||
import { isCalendarEvent, type CalendarEvent } from '@/models/Events'
|
|
||||||
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 type { SearchMode } from '../../SearchMode'
|
import type { SearchMode } from '../../SearchMode'
|
||||||
|
|
||||||
import CharacterCallout from './CharacterCallout.vue'
|
import CharacterCallout from './CharacterCallout.vue'
|
||||||
@@ -12,7 +12,7 @@ import EventCallout from './EventCallout.vue'
|
|||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
results: (Character | CalendarEvent)[]
|
results: (Character | CalendarEvent)[]
|
||||||
currentEntity: SearchMode
|
currentEntity: SearchMode
|
||||||
order: LeimDateOrder
|
order: RPGDateOrder
|
||||||
startAt: number
|
startAt: number
|
||||||
endAt: number
|
endAt: number
|
||||||
limit?: number
|
limit?: number
|
||||||
@@ -20,9 +20,9 @@ const props = defineProps<{
|
|||||||
|
|
||||||
const emit = defineEmits(['jumpedToDate'])
|
const emit = defineEmits(['jumpedToDate'])
|
||||||
|
|
||||||
const { jumpToDate } = useCalendar()
|
const { jumpToDate, compareDates } = useCalendar()
|
||||||
|
|
||||||
function handleJumpToDate(date?: LeimDate) {
|
function handleJumpToDate(date?: RPGDate) {
|
||||||
if (!date) return
|
if (!date) return
|
||||||
|
|
||||||
jumpToDate(date)
|
jumpToDate(date)
|
||||||
@@ -32,8 +32,8 @@ function handleJumpToDate(date?: LeimDate) {
|
|||||||
// Initial sorting of the results
|
// Initial sorting of the results
|
||||||
const sortedResults = computed(() => {
|
const sortedResults = computed(() => {
|
||||||
return [...props.results].sort((a, b) => {
|
return [...props.results].sort((a, b) => {
|
||||||
let firstDate: LeimDate
|
let firstDate: RPGDate
|
||||||
let secondDate: LeimDate
|
let secondDate: RPGDate
|
||||||
|
|
||||||
if (isCalendarEvent(a)) {
|
if (isCalendarEvent(a)) {
|
||||||
firstDate = a.startDate
|
firstDate = a.startDate
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { areDatesIdentical, type LeimDate } from '@/models/Date'
|
import type { RPGDate } from '@/models/Date'
|
||||||
import { useCalendar } from '@/stores/CalendarStore'
|
import { useCalendar } from '@/stores/CalendarStore'
|
||||||
import { useCalendarEvents } from '@/stores/EventStore'
|
import { useCalendarEvents } from '@/stores/EventStore'
|
||||||
import { useElementBounding } from '@vueuse/core'
|
import { useElementBounding } from '@vueuse/core'
|
||||||
@@ -7,17 +7,17 @@ import { storeToRefs } from 'pinia'
|
|||||||
import { computed, ref, type ComputedRef } from 'vue'
|
import { computed, ref, type ComputedRef } from 'vue'
|
||||||
|
|
||||||
import CalendarEventButton from '../../CalendarEvent.vue'
|
import CalendarEventButton from '../../CalendarEvent.vue'
|
||||||
import type { CalendarEvent } from '@/models/Events'
|
import type { CalendarEvent } from '~/models/CalendarEvent'
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
date: LeimDate
|
date: RPGDate
|
||||||
faded?: boolean
|
faded?: boolean
|
||||||
}>()
|
}>()
|
||||||
|
|
||||||
const calendarTile = ref()
|
const calendarTile = ref()
|
||||||
const calendarEventsList = ref()
|
const calendarEventsList = ref()
|
||||||
|
|
||||||
const { defaultDate, selectDate } = useCalendar()
|
const { defaultDate, selectDate, areDatesIdentical } = useCalendar()
|
||||||
const { selectedDate } = storeToRefs(useCalendar())
|
const { selectedDate } = storeToRefs(useCalendar())
|
||||||
const { currentEvents } = storeToRefs(useCalendarEvents())
|
const { currentEvents } = storeToRefs(useCalendarEvents())
|
||||||
|
|
||||||
|
|||||||
@@ -1,38 +1,9 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
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 DayTile from './DayTile.vue'
|
const { currentDate, decrementMonth, incrementMonth } = useCalendar()
|
||||||
|
const { currentMonthData } = storeToRefs(useCalendar())
|
||||||
const { staticConfig, currentDate, decrementMonth, incrementMonth } = useCalendar()
|
|
||||||
|
|
||||||
const daysPerMonth = staticConfig.daysPerMonth
|
|
||||||
|
|
||||||
function getNextMonthDate(day: number): LeimDate {
|
|
||||||
let nextDay = day
|
|
||||||
let nextMonth = currentDate.currentMonth + 1
|
|
||||||
let nextYear = currentDate.currentYear
|
|
||||||
let nextPeriod = currentDate.currentPeriod
|
|
||||||
|
|
||||||
// If the new value would exceed the max number of month per year
|
|
||||||
if (nextMonth >= staticConfig.monthsPerYear) {
|
|
||||||
nextMonth = 0
|
|
||||||
// Increment the year
|
|
||||||
nextYear++
|
|
||||||
}
|
|
||||||
|
|
||||||
if (nextYear >= 0) {
|
|
||||||
nextPeriod = 'nante'
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
day: nextDay,
|
|
||||||
month: nextMonth,
|
|
||||||
year: nextYear,
|
|
||||||
period: nextPeriod
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleWheel(e: WheelEvent) {
|
function handleWheel(e: WheelEvent) {
|
||||||
const isMovingUp = e.deltaY < 0
|
const isMovingUp = e.deltaY < 0
|
||||||
@@ -54,8 +25,8 @@ const moveCalendarRight = useThrottleFn(() => {
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="grid grid-cols-10" @wheel="handleWheel">
|
<div class="grid grid-cols-10" @wheel="handleWheel">
|
||||||
<DayTile
|
<CalendarStateMonthlyDayTile
|
||||||
v-for="day in daysPerMonth"
|
v-for="day in currentMonthData.days"
|
||||||
:key="day"
|
:key="day"
|
||||||
:date="{
|
:date="{
|
||||||
day: day,
|
day: day,
|
||||||
@@ -63,11 +34,5 @@ const moveCalendarRight = useThrottleFn(() => {
|
|||||||
year: currentDate.currentYear
|
year: currentDate.currentYear
|
||||||
}"
|
}"
|
||||||
/>
|
/>
|
||||||
<DayTile
|
|
||||||
v-for="nextMonthDay in 8"
|
|
||||||
:key="nextMonthDay"
|
|
||||||
faded
|
|
||||||
:date="getNextMonthDate(nextMonthDay)"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { areDatesIdentical, type LeimDate } from '@/models/Date'
|
import type { RPGDate } from '@/models/Date'
|
||||||
import { useCalendar } from '@/stores/CalendarStore'
|
import { useCalendar } from '@/stores/CalendarStore'
|
||||||
import { useCalendarEvents } from '@/stores/EventStore'
|
import { useCalendarEvents } from '@/stores/EventStore'
|
||||||
import { storeToRefs } from 'pinia'
|
import { storeToRefs } from 'pinia'
|
||||||
@@ -14,7 +14,9 @@ const props = defineProps<{
|
|||||||
dayNumber: number
|
dayNumber: number
|
||||||
}>()
|
}>()
|
||||||
|
|
||||||
const tileDate: ComputedRef<LeimDate> = computed(() => {
|
const { areDatesIdentical } = useCalendar()
|
||||||
|
|
||||||
|
const tileDate: ComputedRef<RPGDate> = computed(() => {
|
||||||
return {
|
return {
|
||||||
day: props.dayNumber,
|
day: props.dayNumber,
|
||||||
month: props.monthNumber,
|
month: props.monthNumber,
|
||||||
|
|||||||
@@ -2,9 +2,8 @@
|
|||||||
import { useCalendar } from '@/stores/CalendarStore'
|
import { useCalendar } from '@/stores/CalendarStore'
|
||||||
import { useThrottleFn } from '@vueuse/core'
|
import { useThrottleFn } from '@vueuse/core'
|
||||||
|
|
||||||
import MonthTile from './MonthTile.vue'
|
const { decrementYear, incrementYear } = useCalendar()
|
||||||
|
const { sortedMonths: months } = storeToRefs(useCalendar())
|
||||||
const { staticConfig, decrementYear, incrementYear } = useCalendar()
|
|
||||||
|
|
||||||
function handleWheel(e: WheelEvent) {
|
function handleWheel(e: WheelEvent) {
|
||||||
const isMovingUp = e.deltaY < 0
|
const isMovingUp = e.deltaY < 0
|
||||||
@@ -27,10 +26,10 @@ const moveCalendarRight = useThrottleFn(() => {
|
|||||||
<template>
|
<template>
|
||||||
<div class="container mt-[10vh] mb-auto" @wheel="handleWheel">
|
<div class="container mt-[10vh] mb-auto" @wheel="handleWheel">
|
||||||
<div class="grid grid-cols-5 gap-x-8 gap-y-16">
|
<div class="grid grid-cols-5 gap-x-8 gap-y-16">
|
||||||
<MonthTile
|
<CalendarStateYearlyMonthTile
|
||||||
v-for="month in staticConfig.monthsPerYear"
|
v-for="month in months"
|
||||||
:key="month"
|
:key="month.id"
|
||||||
:month-number="month - 1"
|
:month
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,27 +1,21 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { useCalendar } from '@/stores/CalendarStore'
|
import type { CalendarMonth } from '~/models/CalendarMonth';
|
||||||
|
|
||||||
import DayTile from './DayTile.vue'
|
defineProps<{
|
||||||
|
month: CalendarMonth
|
||||||
const { staticConfig, getMonthName } = useCalendar()
|
|
||||||
|
|
||||||
const props = defineProps<{
|
|
||||||
monthNumber: number
|
|
||||||
}>()
|
}>()
|
||||||
|
|
||||||
const tileMonthName: string = getMonthName(props.monthNumber)
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<div class="font-medium">
|
<div class="font-medium">
|
||||||
{{ tileMonthName }}
|
{{ month.name }}
|
||||||
</div>
|
</div>
|
||||||
<div class="grid grid-cols-7">
|
<div class="grid grid-cols-7">
|
||||||
<DayTile
|
<CalendarStateYearlyDayTile
|
||||||
v-for="day in staticConfig.daysPerMonth"
|
v-for="day in month.days"
|
||||||
:key="day"
|
:key="day"
|
||||||
:month-number="monthNumber"
|
:month-number="month.position"
|
||||||
:day-number="day"
|
:day-number="day"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
55
components/profile/Dashboard.vue
Normal file
55
components/profile/Dashboard.vue
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
<script lang="ts" setup>
|
||||||
|
const user = useSupabaseUser()
|
||||||
|
|
||||||
|
const { data: worlds } = await useLazyFetch('/api/worlds')
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<main class="p-8">
|
||||||
|
<Heading>{{ user?.user_metadata.full_name }}</Heading>
|
||||||
|
|
||||||
|
<section v-if="worlds?.data" class="mt-4">
|
||||||
|
<h2 class="mb-4 text-lg font-bold">
|
||||||
|
Mondes
|
||||||
|
</h2>
|
||||||
|
|
||||||
|
<ul class="grid md:grid-cols-3 gap-2">
|
||||||
|
<li v-for="(world, i) in worlds.data" :key="i">
|
||||||
|
<UiCard
|
||||||
|
class="w-full transition-all"
|
||||||
|
:link="`/calendar/${world.id}`"
|
||||||
|
:class="{
|
||||||
|
'hover:bg-slate-50 dark:hover:bg-sky-950 dark:focus-within:outline-sky-900': !world.color,
|
||||||
|
'bg-red-100 dark:bg-red-950 border-red-200 hover:bg-red-50 dark:hover:bg-red-900 dark:border-red-900 dark:focus-within:outline-red-900': world.color === 'red',
|
||||||
|
'bg-orange-100 dark:bg-orange-950 border-orange-200 hover:bg-orange-50 dark:hover:bg-orange-900 dark:border-orange-900 dark:focus-within:outline-orange-900': world.color === 'orange',
|
||||||
|
'bg-amber-100 dark:bg-amber-950 border-amber-200 hover:bg-amber-50 dark:hover:bg-amber-900 dark:border-amber-900 dark:focus-within:outline-amber-900': world.color === 'amber',
|
||||||
|
'bg-yellow-100 dark:bg-yellow-950 border-yellow-200 hover:bg-yellow-50 dark:hover:bg-yellow-900 dark:border-yellow-900 dark:focus-within:outline-yellow-900': world.color === 'yellow',
|
||||||
|
'bg-lime-100 dark:bg-lime-950 border-lime-200 hover:bg-lime-50 dark:hover:bg-lime-900 dark:border-lime-900 dark:focus-within:outline-lime-900': world.color === 'lime',
|
||||||
|
' bg-green-100 dark:bg-green-950 border-green-200 hover:bg-green-50 dark:hover:bg-green-900 dark:border-green-900 dark:focus-within:outline-green-900': world.color === 'green',
|
||||||
|
'bg-emerald-100 dark:bg-emerald-950 border-emerald-200 hover:bg-emerald-50 dark:hover:bg-emerald-900 dark:border-emerald-900 dark:focus-within:outline-emerald-900': world.color === 'emerald',
|
||||||
|
'bg-teal-100 dark:bg-teal-950 border-teal-200 hover:bg-teal-50 dark:hover:bg-teal-900 dark:border-teal-900 dark:focus-within:outline-teal-900': world.color === 'teal',
|
||||||
|
'bg-cyan-100 dark:bg-cyan-950 border-cyan-200 hover:bg-cyan-50 dark:hover:bg-cyan-900 dark:border-cyan-900 dark:focus-within:outline-cyan-900': world.color === 'cyan',
|
||||||
|
'bg-sky-100 dark:bg-sky-950 border-sky-200 hover:bg-sky-50 dark:hover:bg-sky-900 dark:border-sky-900 dark:focus-within:outline-sky-900': world.color === 'sky',
|
||||||
|
'bg-blue-100 dark:bg-blue-950 border-blue-200 hover:bg-blue-50 dark:hover:bg-blue-900 dark:border-blue-900 dark:focus-within:outline-blue-900': world.color === 'blue',
|
||||||
|
'bg-indigo-100 dark:bg-indigo-950 border-indigo-200 hover:bg-indigo-50 dark:hover:bg-indigo-900 dark:border-indigo-900 dark:focus-within:outline-indigo-900': world.color === 'indigo',
|
||||||
|
'bg-violet-100 dark:bg-violet-950 border-violet-200 hover:bg-violet-50 dark:hover:bg-violet-900 dark:border-violet-900 dark:focus-within:outline-violet-900': world.color === 'violet',
|
||||||
|
'bg-purple-100 dark:bg-purple-950 border-purple-200 hover:bg-purple-50 dark:hover:bg-purple-900 dark:border-purple-900 dark:focus-within:outline-purple-900': world.color === 'purple',
|
||||||
|
'bg-fuchsia-100 dark:bg-fuchsia-950 border-fuchsia-200 hover:bg-fuchsia-50 dark:hover:bg-fuchsia-900 dark:border-fuchsia-900 dark:focus-within:outline-fuchsia-900': world.color === 'fuchsia',
|
||||||
|
'bg-pink-100 dark:bg-pink-950 border-pink-200 hover:bg-pink-50 dark:hover:bg-pink-900 dark:border-pink-900 dark:focus-within:outline-pink-900': world.color === 'pink',
|
||||||
|
'bg-pink-100 dark:bg-rose-950 border-rose-200 hover:bg-rose-50 dark:hover:bg-rose-900 dark:border-rose-900 dark:focus-within:outline-rose-900': world.color === 'rose',
|
||||||
|
'text-slate-100 bg-slate-900 border-slate-700 hover:bg-slate-700 dark:hover:bg-slate-800 dark:border-slate-900 dark:focus-within:outline-slate-900': world.color === 'black',
|
||||||
|
' hover:bg-slate-50 dark:hover:text-slate-900 dark:hover:bg-slate-300 dark:border-slate-500 dark:focus-within:outline-slate-100': world.color === 'white',
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<UiCardHeader>
|
||||||
|
<UiCardTitle>{{ world.name }}</UiCardTitle>
|
||||||
|
</UiCardHeader>
|
||||||
|
<UiCardContent>
|
||||||
|
<p class="italic">{{ world.description }}</p>
|
||||||
|
</UiCardContent>
|
||||||
|
</UiCard>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</section>
|
||||||
|
</main>
|
||||||
|
</template>
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
<script lang="ts" setup>
|
|
||||||
const user = useSupabaseUser()
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<div class="p-8">
|
|
||||||
<Heading>{{ user?.user_metadata.full_name }}</Heading>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
@@ -12,7 +12,7 @@ const props = defineProps<{
|
|||||||
<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', props.class, {
|
||||||
'relative outline outline-2 outline-offset-4 outline-transparent hover:bg-sky-950 hover:-translate-y-[.2rem] focus-within:outline-sky-900':
|
'relative outline outline-2 outline-offset-4 outline-transparent hover:-translate-y-[.2rem]':
|
||||||
props.link
|
props.link
|
||||||
})
|
})
|
||||||
"
|
"
|
||||||
|
|||||||
15
models/CalendarConfig.ts
Normal file
15
models/CalendarConfig.ts
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
import type { CalendarEvent } from "./CalendarEvent"
|
||||||
|
import type { CalendarMonth } from "./CalendarMonth"
|
||||||
|
import type { RPGDate } from "./Date"
|
||||||
|
|
||||||
|
export interface CalendarConfig {
|
||||||
|
months: CalendarMonth[]
|
||||||
|
daysPerMonth: number
|
||||||
|
today: RPGDate
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Calendar extends CalendarConfig {
|
||||||
|
id: number
|
||||||
|
name: string
|
||||||
|
events: CalendarEvent[]
|
||||||
|
}
|
||||||
19
models/CalendarEvent.ts
Normal file
19
models/CalendarEvent.ts
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
import type { Category } from './Category'
|
||||||
|
import type { RPGDate } from './Date'
|
||||||
|
|
||||||
|
export interface CalendarEvent {
|
||||||
|
id: number
|
||||||
|
title: string
|
||||||
|
startDate: RPGDate
|
||||||
|
endDate?: RPGDate
|
||||||
|
description?: string
|
||||||
|
category?: Category
|
||||||
|
secondaryCategories?: Category[]
|
||||||
|
hidden?: boolean
|
||||||
|
wiki?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
|
export function isCalendarEvent(object: any): object is CalendarEvent {
|
||||||
|
return 'startDate' in object
|
||||||
|
}
|
||||||
6
models/CalendarMonth.ts
Normal file
6
models/CalendarMonth.ts
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
export interface CalendarMonth {
|
||||||
|
id: number
|
||||||
|
days: number,
|
||||||
|
name: string,
|
||||||
|
position: number,
|
||||||
|
}
|
||||||
4
models/Category.ts
Normal file
4
models/Category.ts
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
export interface Category {
|
||||||
|
id: number
|
||||||
|
name: string
|
||||||
|
}
|
||||||
@@ -1,31 +1,19 @@
|
|||||||
import type { LeimDate } from './Date'
|
import type { Category } from './Category'
|
||||||
|
import type { RPGDate } from './Date'
|
||||||
|
|
||||||
export interface Character {
|
export interface Character {
|
||||||
name: string
|
name: string
|
||||||
description?: string
|
description?: string
|
||||||
birth?: LeimDate
|
birth?: RPGDate
|
||||||
death?: LeimDate
|
death?: RPGDate
|
||||||
hiddenBirth?: boolean
|
hiddenBirth?: boolean
|
||||||
hiddenDeath?: boolean
|
hiddenDeath?: boolean
|
||||||
category?: CharacterCategory
|
category?: Category
|
||||||
secondaryCategories?: CharacterCategory[]
|
secondaryCategories?: Category[]
|
||||||
wiki?: string
|
wiki?: string
|
||||||
}
|
}
|
||||||
export const characterCategories = [
|
|
||||||
'joueur',
|
|
||||||
'comte',
|
|
||||||
'scientifique',
|
|
||||||
'mage',
|
|
||||||
'professeur',
|
|
||||||
'criminel',
|
|
||||||
'étincelle',
|
|
||||||
'buse blanche',
|
|
||||||
'ecclésiastique',
|
|
||||||
'sentinelle'
|
|
||||||
] as const
|
|
||||||
|
|
||||||
export type CharacterCategory = (typeof characterCategories)[number]
|
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
export function isCharacter(object: any): object is Character {
|
export function isCharacter(object: any): object is Character {
|
||||||
return 'birth' in object
|
return 'birth' in object
|
||||||
}
|
}
|
||||||
|
|||||||
179
models/Date.ts
179
models/Date.ts
@@ -1,187 +1,16 @@
|
|||||||
export interface LeimDate {
|
export interface RPGDate {
|
||||||
day: number
|
day: number
|
||||||
month: number
|
month: number
|
||||||
year: number
|
year: number
|
||||||
period?: LeimPeriod
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export type LeimPeriod = 'ante' | 'nante'
|
export type RPGDateOrder = 'asc' | 'desc'
|
||||||
export type LeimPeriodShort = 'A.R' | 'N.R'
|
|
||||||
export type LeimDateOrder = 'asc' | 'desc'
|
|
||||||
|
|
||||||
export const monthsPerYear: number = 10
|
// export function getRelativeDate(baseDate: RPGDate, relativeDate: RPGDate) {
|
||||||
export const daysPerYear: number = 320
|
|
||||||
export const daysPerMonth: number = 32
|
|
||||||
export const daysPerWeek: number = 6
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check whether two dates are identical
|
|
||||||
*
|
|
||||||
* @param date1 First date
|
|
||||||
* @param date2 Second date
|
|
||||||
* @returns True if the dates are identical
|
|
||||||
*/
|
|
||||||
export function areDatesIdentical(date1: LeimDate, date2: LeimDate): boolean {
|
|
||||||
return convertDateToDays({ ...date1 }) === convertDateToDays({ ...date2 })
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Compare dates
|
|
||||||
*
|
|
||||||
* @param date1 First date
|
|
||||||
* @param date2 Second date
|
|
||||||
* @returns 1 means the first date comes before the second, -1 means the second comes before the first, and 0 if they're identical
|
|
||||||
*/
|
|
||||||
export function compareDates(a: LeimDate, b: LeimDate, order: LeimDateOrder = 'desc'): number {
|
|
||||||
// Reverses the order if specified
|
|
||||||
const orderFactor: number = order === 'desc' ? 1 : -1
|
|
||||||
|
|
||||||
// Compare eras
|
|
||||||
if ((a.period === 'ante' && b.period === 'nante') || (a.year < 0 && b.year >= 0))
|
|
||||||
return -1 * orderFactor
|
|
||||||
if ((a.period === 'nante' && b.period === 'ante') || (a.year >= 0 && b.year < 0))
|
|
||||||
return 1 * orderFactor
|
|
||||||
|
|
||||||
// Compare years
|
|
||||||
if (a.year < b.year) return -1 * orderFactor
|
|
||||||
if (a.year > b.year) return 1 * orderFactor
|
|
||||||
|
|
||||||
// Compare months
|
|
||||||
if (a.month < b.month) return -1 * orderFactor
|
|
||||||
if (a.month > b.month) return 1 * orderFactor
|
|
||||||
|
|
||||||
// Compare days
|
|
||||||
if (a.day < b.day) return -1 * orderFactor
|
|
||||||
if (a.day > b.day) return 1 * orderFactor
|
|
||||||
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Converts a LeimDate to its equivalent in days
|
|
||||||
*
|
|
||||||
* @todo Handle negative dates
|
|
||||||
* @param dateToConvert The date object
|
|
||||||
* @returns How many days does it represent
|
|
||||||
*/
|
|
||||||
export function convertDateToDays(dateToConvert: LeimDate): number {
|
|
||||||
let numberOfDays: number = dateToConvert.day
|
|
||||||
|
|
||||||
numberOfDays = numberOfDays + dateToConvert.month * daysPerMonth
|
|
||||||
numberOfDays = numberOfDays + dateToConvert.year * daysPerYear
|
|
||||||
|
|
||||||
return numberOfDays
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* From two dates, get the difference in days between them
|
|
||||||
* @param baseDate The base date
|
|
||||||
* @param relativeDate The year to compare it to
|
|
||||||
* @returns The number of days separating the two dates (both positive and negative numbers)
|
|
||||||
*/
|
|
||||||
export function getDifferenceInDays(baseDate: LeimDate, relativeDate: LeimDate): number {
|
|
||||||
return convertDateToDays(relativeDate) - convertDateToDays(baseDate)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* From two dates, gives information on how many years, months and days it has been / will be between them
|
|
||||||
*
|
|
||||||
* @param baseDate The base date
|
|
||||||
* @param relativeDate The year to compare it to
|
|
||||||
* @returns A string with info on how the relative date differs to the base date
|
|
||||||
*/
|
|
||||||
export function getRelativeString(
|
|
||||||
baseDate: LeimDate,
|
|
||||||
relativeDate: LeimDate,
|
|
||||||
formatting: 'compact' | 'complex' = 'complex'
|
|
||||||
): string {
|
|
||||||
const differenceInDays: number = getDifferenceInDays(baseDate, relativeDate)
|
|
||||||
let output: string = ''
|
|
||||||
let direction: 'past' | 'present' | 'future' = 'present'
|
|
||||||
let directionPrefix: string = ''
|
|
||||||
|
|
||||||
// Check whether it's a past or future date
|
|
||||||
if (differenceInDays > 0) {
|
|
||||||
direction = 'future'
|
|
||||||
} else if (differenceInDays < 0) {
|
|
||||||
direction = 'past'
|
|
||||||
}
|
|
||||||
|
|
||||||
if (formatting === 'complex') {
|
|
||||||
// Handle if it's the same date
|
|
||||||
if (direction === 'present') {
|
|
||||||
return "Aujourd'hui"
|
|
||||||
}
|
|
||||||
if (differenceInDays === -2) {
|
|
||||||
return 'Avant-hier'
|
|
||||||
}
|
|
||||||
if (differenceInDays === -1) {
|
|
||||||
return 'Hier'
|
|
||||||
}
|
|
||||||
if (differenceInDays === 1) {
|
|
||||||
return 'Demain'
|
|
||||||
}
|
|
||||||
if (differenceInDays === 2) {
|
|
||||||
return 'Après-demain'
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get relevant prefix for the string
|
|
||||||
if (direction === 'future') {
|
|
||||||
directionPrefix = 'Dans '
|
|
||||||
} else if (direction === 'past') {
|
|
||||||
directionPrefix = 'Il y a '
|
|
||||||
}
|
|
||||||
|
|
||||||
output += directionPrefix
|
|
||||||
}
|
|
||||||
|
|
||||||
const yearPackets: number = Math.abs(Math.trunc(differenceInDays / daysPerYear))
|
|
||||||
const monthPackets: number = Math.abs(Math.trunc(differenceInDays / daysPerMonth) % monthsPerYear)
|
|
||||||
|
|
||||||
const remainingDays: number =
|
|
||||||
Math.abs(differenceInDays) - (yearPackets * daysPerYear + monthPackets * daysPerMonth)
|
|
||||||
|
|
||||||
// Assign year part
|
|
||||||
if (yearPackets) {
|
|
||||||
if (yearPackets === 1) {
|
|
||||||
output += `${yearPackets} an`
|
|
||||||
} else {
|
|
||||||
output += `${yearPackets} ans`
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Assign month part
|
|
||||||
if (monthPackets) {
|
|
||||||
// If there was a year packet(s), separate from them
|
|
||||||
if (yearPackets) {
|
|
||||||
output += ','
|
|
||||||
}
|
|
||||||
|
|
||||||
output += ` ${monthPackets} mois`
|
|
||||||
}
|
|
||||||
|
|
||||||
// Assign day part
|
|
||||||
if (remainingDays) {
|
|
||||||
// If there was a year OR month packet(s), separate from them
|
|
||||||
if (yearPackets || monthPackets) {
|
|
||||||
output += ' et'
|
|
||||||
}
|
|
||||||
|
|
||||||
if (remainingDays === 1) {
|
|
||||||
output += ` ${remainingDays} jour`
|
|
||||||
} else {
|
|
||||||
output += ` ${remainingDays} jours`
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return output
|
|
||||||
}
|
|
||||||
|
|
||||||
// export function getRelativeDate(baseDate: LeimDate, relativeDate: LeimDate) {
|
|
||||||
// let newDay: number
|
// let newDay: number
|
||||||
// let newMonth: number
|
// let newMonth: number
|
||||||
// let newYear: number
|
// let newYear: number
|
||||||
// let newPeriod: LeimPeriod
|
// let newPeriod: RPGPeriod
|
||||||
|
|
||||||
// const differenceInDays = getDifferenceInDays(baseDate, relativeDate)
|
// const differenceInDays = getDifferenceInDays(baseDate, relativeDate)
|
||||||
|
|
||||||
|
|||||||
@@ -1,39 +0,0 @@
|
|||||||
import type { LeimDate } from './Date'
|
|
||||||
|
|
||||||
export interface CalendarEvent {
|
|
||||||
title: string
|
|
||||||
startDate: LeimDate
|
|
||||||
endDate?: LeimDate
|
|
||||||
description?: string
|
|
||||||
category?: CalendarEventCategory
|
|
||||||
secondaryCategories?: CalendarEventCategory[]
|
|
||||||
hidden?: boolean
|
|
||||||
wiki?: string
|
|
||||||
}
|
|
||||||
|
|
||||||
export const calendarEventCategories = [
|
|
||||||
'naissance',
|
|
||||||
'mort',
|
|
||||||
'catastrophe',
|
|
||||||
'législation',
|
|
||||||
'catastrophe naturelle',
|
|
||||||
'inauguration',
|
|
||||||
'religion',
|
|
||||||
'invention',
|
|
||||||
'science',
|
|
||||||
'bénédiction',
|
|
||||||
'joueurs',
|
|
||||||
'découverte',
|
|
||||||
'exploration',
|
|
||||||
'construction',
|
|
||||||
'arcanologie',
|
|
||||||
'criminalité',
|
|
||||||
'scandale',
|
|
||||||
'commerce'
|
|
||||||
] as const
|
|
||||||
|
|
||||||
export type CalendarEventCategory = (typeof calendarEventCategories)[number]
|
|
||||||
|
|
||||||
export function isCalendarEvent(object: any): object is CalendarEvent {
|
|
||||||
return 'startDate' in object
|
|
||||||
}
|
|
||||||
7
models/World.ts
Normal file
7
models/World.ts
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
export interface World {
|
||||||
|
id: number
|
||||||
|
uuid: string
|
||||||
|
name: string
|
||||||
|
description?: string
|
||||||
|
color?: string
|
||||||
|
}
|
||||||
@@ -28,7 +28,8 @@
|
|||||||
"tailwind-merge": "^2.3.0",
|
"tailwind-merge": "^2.3.0",
|
||||||
"tailwindcss-animate": "^1.0.7",
|
"tailwindcss-animate": "^1.0.7",
|
||||||
"vue": "^3.4.27",
|
"vue": "^3.4.27",
|
||||||
"vue-router": "^4.3.2"
|
"vue-router": "^4.3.2",
|
||||||
|
"zod": "^3.23.8"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@nuxtjs/color-mode": "^3.4.1",
|
"@nuxtjs/color-mode": "^3.4.1",
|
||||||
|
|||||||
40
pages/calendar/[id].vue
Normal file
40
pages/calendar/[id].vue
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
<script lang="ts" setup>
|
||||||
|
import { PhMagnifyingGlass } from '@phosphor-icons/vue';
|
||||||
|
import type { MenuItem } from '~/components/global/SidebarProps';
|
||||||
|
|
||||||
|
useHead({
|
||||||
|
title: 'Calendrier'
|
||||||
|
})
|
||||||
|
definePageMeta({
|
||||||
|
middleware: ['auth-guard']
|
||||||
|
})
|
||||||
|
|
||||||
|
const user = useSupabaseUser()
|
||||||
|
// Redirect user back home when they log out on the page
|
||||||
|
watch(user, (n, _o) => {
|
||||||
|
if (!n) {
|
||||||
|
navigateTo('/')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const { revealAdvancedSearch } = useCalendar()
|
||||||
|
const { isAdvancedSearchOpen } = storeToRefs(useCalendar())
|
||||||
|
|
||||||
|
const sidebarMenu: MenuItem[] = [
|
||||||
|
{
|
||||||
|
phIcon: PhMagnifyingGlass,
|
||||||
|
tooltip: 'Recherche avancée',
|
||||||
|
clickHandler: revealAdvancedSearch
|
||||||
|
}
|
||||||
|
]
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="h-full grid grid-cols-[auto_1fr]">
|
||||||
|
<Sidebar :menu-items="sidebarMenu" />
|
||||||
|
|
||||||
|
<Calendar />
|
||||||
|
|
||||||
|
<CalendarSearch v-model:model-value="isAdvancedSearchOpen" />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
@@ -11,21 +11,5 @@ const sidebarMenu: MenuItem[] = []
|
|||||||
<template>
|
<template>
|
||||||
<main class="h-full grid grid-cols-[auto_1fr]">
|
<main class="h-full grid grid-cols-[auto_1fr]">
|
||||||
<Sidebar :menu-items="sidebarMenu" is-home />
|
<Sidebar :menu-items="sidebarMenu" is-home />
|
||||||
|
|
||||||
<div class="h-full grid place-items-center">
|
|
||||||
<UiCard class="w-1/3 min-w-72" link="/calendar">
|
|
||||||
<UiCardHeader>
|
|
||||||
<UiCardTitle>Calendrier</UiCardTitle>
|
|
||||||
<UiCardDescription>
|
|
||||||
<UiBadge class="mix-blend-luminosity font-bold bg-gray-600" variant="secondary">
|
|
||||||
chronologie
|
|
||||||
</UiBadge>
|
|
||||||
</UiCardDescription>
|
|
||||||
</UiCardHeader>
|
|
||||||
<UiCardContent>
|
|
||||||
Chronologie complète de Léïm, rassemblant les évènements et personnages clés du monde
|
|
||||||
</UiCardContent>
|
|
||||||
</UiCard>
|
|
||||||
</div>
|
|
||||||
</main>
|
</main>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -21,9 +21,9 @@ const sidebarMenu: MenuItem[] = []
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<main class="h-full grid grid-cols-[auto_1fr]">
|
<div class="h-full grid grid-cols-[auto_1fr]">
|
||||||
<Sidebar :menu-items="sidebarMenu" />
|
<Sidebar :menu-items="sidebarMenu" />
|
||||||
|
|
||||||
<ProfileLayout />
|
<ProfileDashboard />
|
||||||
</main>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
8
pnpm-lock.yaml
generated
8
pnpm-lock.yaml
generated
@@ -56,6 +56,9 @@ importers:
|
|||||||
vue-router:
|
vue-router:
|
||||||
specifier: ^4.3.2
|
specifier: ^4.3.2
|
||||||
version: 4.3.2(vue@3.4.27(typescript@5.4.5))
|
version: 4.3.2(vue@3.4.27(typescript@5.4.5))
|
||||||
|
zod:
|
||||||
|
specifier: ^3.23.8
|
||||||
|
version: 3.23.8
|
||||||
devDependencies:
|
devDependencies:
|
||||||
'@nuxtjs/color-mode':
|
'@nuxtjs/color-mode':
|
||||||
specifier: ^3.4.1
|
specifier: ^3.4.1
|
||||||
@@ -4734,6 +4737,9 @@ packages:
|
|||||||
resolution: {integrity: sha512-zK7YHHz4ZXpW89AHXUPbQVGKI7uvkd3hzusTdotCg1UxyaVtg0zFJSTfW/Dq5f7OBBVnq6cZIaC8Ti4hb6dtCA==}
|
resolution: {integrity: sha512-zK7YHHz4ZXpW89AHXUPbQVGKI7uvkd3hzusTdotCg1UxyaVtg0zFJSTfW/Dq5f7OBBVnq6cZIaC8Ti4hb6dtCA==}
|
||||||
engines: {node: '>= 14'}
|
engines: {node: '>= 14'}
|
||||||
|
|
||||||
|
zod@3.23.8:
|
||||||
|
resolution: {integrity: sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g==}
|
||||||
|
|
||||||
snapshots:
|
snapshots:
|
||||||
|
|
||||||
'@alloc/quick-lru@5.2.0': {}
|
'@alloc/quick-lru@5.2.0': {}
|
||||||
@@ -10202,3 +10208,5 @@ snapshots:
|
|||||||
archiver-utils: 5.0.2
|
archiver-utils: 5.0.2
|
||||||
compress-commons: 6.0.2
|
compress-commons: 6.0.2
|
||||||
readable-stream: 4.5.2
|
readable-stream: 4.5.2
|
||||||
|
|
||||||
|
zod@3.23.8: {}
|
||||||
|
|||||||
37
server/api/calendars/query.get.ts
Normal file
37
server/api/calendars/query.get.ts
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
import { serverSupabaseClient } from "#supabase/server";
|
||||||
|
import { z } from 'zod'
|
||||||
|
import type { Calendar } from "~/models/CalendarConfig";
|
||||||
|
|
||||||
|
const querySchema = z.object({
|
||||||
|
world_id: z.number({ coerce: true }).positive().int()
|
||||||
|
})
|
||||||
|
|
||||||
|
export default defineEventHandler(async (event) => {
|
||||||
|
const client = await serverSupabaseClient(event)
|
||||||
|
const query = await getValidatedQuery(event, querySchema.parse)
|
||||||
|
|
||||||
|
const output = client
|
||||||
|
.from('calendars')
|
||||||
|
.select(`
|
||||||
|
id,
|
||||||
|
name,
|
||||||
|
today,
|
||||||
|
months:calendar_months (*),
|
||||||
|
events:calendar_events (
|
||||||
|
id,
|
||||||
|
title,
|
||||||
|
description,
|
||||||
|
hidden,
|
||||||
|
startDate:start_date,
|
||||||
|
endDate:end_date,
|
||||||
|
wiki,
|
||||||
|
category:calendar_event_categories!calendar_events_category_fkey (*),
|
||||||
|
secondaryCategories:calendar_event_categories!calendar_event_categories_links (*)
|
||||||
|
)
|
||||||
|
`)
|
||||||
|
.eq('world_id', query.world_id)
|
||||||
|
.limit(1)
|
||||||
|
.single<Calendar>()
|
||||||
|
|
||||||
|
return output
|
||||||
|
})
|
||||||
@@ -1,252 +0,0 @@
|
|||||||
export default defineEventHandler(() => {
|
|
||||||
return [
|
|
||||||
/**
|
|
||||||
* Player characters
|
|
||||||
*/
|
|
||||||
// "Les Milles Cages"
|
|
||||||
{
|
|
||||||
name: 'Sulvan Trois-Barbes',
|
|
||||||
birth: { day: 20, month: 3, year: 3169 },
|
|
||||||
wiki: 'https://alexcreates.fr/leim/index.php/Sulvan_Trois-Barbes',
|
|
||||||
category: 'joueur',
|
|
||||||
secondaryCategories: ['criminel', 'étincelle']
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Vascylly',
|
|
||||||
birth: { day: 3, month: 5, year: 3181 },
|
|
||||||
wiki: 'https://alexcreates.fr/leim/index.php/Vascylly',
|
|
||||||
category: 'joueur',
|
|
||||||
secondaryCategories: ['mage']
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Tara Belyus',
|
|
||||||
birth: { day: 14, month: 9, year: 3186 },
|
|
||||||
category: 'joueur',
|
|
||||||
secondaryCategories: ['mage']
|
|
||||||
},
|
|
||||||
// "Les Cloches de Cantane"
|
|
||||||
{
|
|
||||||
name: 'Malik',
|
|
||||||
birth: { day: 22, month: 8, year: 3181 },
|
|
||||||
category: 'joueur',
|
|
||||||
secondaryCategories: ['scientifique']
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Elie',
|
|
||||||
birth: { day: 5, month: 6, year: 3192 },
|
|
||||||
category: 'joueur',
|
|
||||||
secondaryCategories: ['ecclésiastique']
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Clayron',
|
|
||||||
birth: { day: 3, month: 5, year: 3178 },
|
|
||||||
category: 'joueur',
|
|
||||||
secondaryCategories: ['sentinelle']
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* NPC
|
|
||||||
*/
|
|
||||||
// Counts of the Alliance
|
|
||||||
{
|
|
||||||
name: 'Alfrid de Lagarde',
|
|
||||||
birth: { day: 29, month: 7, year: 3193 },
|
|
||||||
wiki: 'https://alexcreates.fr/leim/index.php/Alfrid_de_Lagarde',
|
|
||||||
category: 'comte',
|
|
||||||
secondaryCategories: ['sentinelle']
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Alaric de Lagarde',
|
|
||||||
birth: { day: 23, month: 8, year: 3192 },
|
|
||||||
wiki: 'https://alexcreates.fr/leim/index.php/Alaric_de_Lagarde',
|
|
||||||
category: 'comte',
|
|
||||||
secondaryCategories: ['sentinelle']
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Anastael III de Quillon',
|
|
||||||
birth: { day: 1, month: 5, year: 3184 },
|
|
||||||
wiki: 'https://alexcreates.fr/leim/index.php/Anastael_III_de_Quillon',
|
|
||||||
category: 'comte',
|
|
||||||
secondaryCategories: ['sentinelle', 'buse blanche']
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Antoine de Mireloin',
|
|
||||||
birth: { day: 31, month: 5, year: 3190 },
|
|
||||||
wiki: 'https://alexcreates.fr/leim/index.php/Antoine_de_Mireloin',
|
|
||||||
category: 'comte'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Armance Ronchère',
|
|
||||||
birth: { day: 1, month: 1, year: 3132 },
|
|
||||||
wiki: 'https://alexcreates.fr/leim/index.php/Armance_Ronchère',
|
|
||||||
category: 'comte'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Baranne Rougefer',
|
|
||||||
birth: { day: 1, month: 0, year: 3175 },
|
|
||||||
wiki: 'https://alexcreates.fr/leim/index.php/Baranne_Rougefer',
|
|
||||||
category: 'comte',
|
|
||||||
secondaryCategories: ['sentinelle']
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Béatrice II de Grandlac',
|
|
||||||
birth: { day: 21, month: 4, year: 3158 },
|
|
||||||
wiki: 'https://alexcreates.fr/leim/index.php/Béatrice_II_de_Grandlac',
|
|
||||||
category: 'comte',
|
|
||||||
secondaryCategories: ['mage']
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Favio Asharos-Losantelle',
|
|
||||||
birth: { day: 17, month: 3, year: 3091 },
|
|
||||||
wiki: 'https://alexcreates.fr/leim/index.php/Favio_Asharos-Losantelle',
|
|
||||||
category: 'comte',
|
|
||||||
secondaryCategories: ['mage']
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Firmin de Montardieu',
|
|
||||||
birth: { day: 9, month: 2, year: 3203 },
|
|
||||||
wiki: 'https://alexcreates.fr/leim/index.php/Firmin_de_Montardieu',
|
|
||||||
category: 'comte'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Laura de Montardieu',
|
|
||||||
birth: { day: 32, month: 3, year: 3167 },
|
|
||||||
death: { day: 1, month: 4, year: 3217 },
|
|
||||||
hiddenDeath: true,
|
|
||||||
wiki: 'https://alexcreates.fr/leim/index.php/Laura_de_Montardieu',
|
|
||||||
category: 'comte'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Lazarus Tymos',
|
|
||||||
birth: { day: 29, month: 9, year: 3145 },
|
|
||||||
wiki: 'https://alexcreates.fr/leim/index.php/Lazarus_Tymos',
|
|
||||||
category: 'comte',
|
|
||||||
secondaryCategories: ['mage', 'buse blanche']
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Marion de Corambre',
|
|
||||||
birth: { day: 14, month: 7, year: 3190 },
|
|
||||||
wiki: 'https://alexcreates.fr/leim/index.php/Marion_de_Corambre',
|
|
||||||
category: 'comte',
|
|
||||||
secondaryCategories: ['scientifique', 'ecclésiastique']
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Relforg Pergaré',
|
|
||||||
birth: { day: 18, month: 9, year: 3182 },
|
|
||||||
wiki: 'https://alexcreates.fr/leim/index.php/Relforg_Pergaré',
|
|
||||||
category: 'comte'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Vilgarde de Ternâcre',
|
|
||||||
birth: { day: 3, month: 3, year: 2998 },
|
|
||||||
wiki: 'https://alexcreates.fr/leim/index.php/Vilgarde_de_Ternâcre',
|
|
||||||
category: 'comte'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Ysildy Milopée',
|
|
||||||
birth: { day: 3, month: 1, year: 3187 },
|
|
||||||
wiki: 'https://alexcreates.fr/leim/index.php/Ysildy_Milopée',
|
|
||||||
category: 'comte',
|
|
||||||
secondaryCategories: ['mage', 'scientifique', 'professeur']
|
|
||||||
},
|
|
||||||
|
|
||||||
// Sparks
|
|
||||||
{
|
|
||||||
name: 'Izàc Tymos',
|
|
||||||
birth: { day: 13, month: 6, year: 3192 },
|
|
||||||
wiki: 'https://alexcreates.fr/leim/index.php/Izàc_Tymos',
|
|
||||||
category: 'mage',
|
|
||||||
secondaryCategories: ['étincelle', 'criminel', 'professeur', 'scientifique']
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Tvernée',
|
|
||||||
birth: { day: 19, month: 2, year: 3205 },
|
|
||||||
wiki: 'https://alexcreates.fr/leim/index.php/Tvernée',
|
|
||||||
category: 'étincelle',
|
|
||||||
secondaryCategories: ['criminel']
|
|
||||||
},
|
|
||||||
|
|
||||||
// Pirates
|
|
||||||
{
|
|
||||||
name: 'Räzal',
|
|
||||||
birth: { day: 13, month: 8, year: 3178 },
|
|
||||||
wiki: 'https://alexcreates.fr/leim/index.php/Räzal'
|
|
||||||
},
|
|
||||||
|
|
||||||
// Legends
|
|
||||||
{
|
|
||||||
name: 'Jorhas Kirendre',
|
|
||||||
birth: { day: 2, month: 9, year: -452 },
|
|
||||||
death: { day: 2, month: 2, year: -419 },
|
|
||||||
category: 'sentinelle',
|
|
||||||
wiki: 'https://alexcreates.fr/leim/index.php/Jorhas_Kirendre'
|
|
||||||
},
|
|
||||||
|
|
||||||
// "Les Milles Cages"
|
|
||||||
{
|
|
||||||
name: 'Ernestin Pomel',
|
|
||||||
birth: { day: 11, month: 2, year: 3179 },
|
|
||||||
wiki: 'https://alexcreates.fr/leim/index.php/Ernestin_Pomel',
|
|
||||||
category: 'mage'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Quacille Lévios',
|
|
||||||
birth: { day: 3, month: 6, year: 3162 },
|
|
||||||
wiki: 'https://alexcreates.fr/leim/index.php/Quacille_Lévios',
|
|
||||||
category: 'professeur',
|
|
||||||
secondaryCategories: ['mage']
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Morel Lévios',
|
|
||||||
birth: { day: 26, month: 3, year: 3157 },
|
|
||||||
wiki: 'https://alexcreates.fr/leim/index.php/Morel_Lévios',
|
|
||||||
category: 'sentinelle',
|
|
||||||
secondaryCategories: ['mage', 'buse blanche']
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Anastael Simon',
|
|
||||||
birth: { day: 32, month: 2, year: 3166 },
|
|
||||||
wiki: 'https://alexcreates.fr/leim/index.php/Anastael_Simon',
|
|
||||||
category: 'étincelle',
|
|
||||||
secondaryCategories: ['mage']
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Grestain',
|
|
||||||
birth: { day: 9, month: 2, year: 3162 },
|
|
||||||
wiki: 'https://alexcreates.fr/leim/index.php/Grestain',
|
|
||||||
category: 'criminel',
|
|
||||||
secondaryCategories: ['mage']
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Lucien Malanth',
|
|
||||||
birth: { day: 31, month: 4, year: 3167 },
|
|
||||||
wiki: 'https://alexcreates.fr/leim/index.php/Lucien_Malanth',
|
|
||||||
category: 'criminel',
|
|
||||||
secondaryCategories: ['mage']
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Tivian Rodhus',
|
|
||||||
birth: { day: 13, month: 3, year: 3157 },
|
|
||||||
wiki: 'https://alexcreates.fr/leim/index.php/Tivian_Rodhus',
|
|
||||||
category: 'professeur',
|
|
||||||
secondaryCategories: ['mage', 'criminel']
|
|
||||||
},
|
|
||||||
|
|
||||||
// "Les Cloches de Cantane"
|
|
||||||
{
|
|
||||||
name: 'Bénédicte Vaht',
|
|
||||||
description: "Moine d'Ikami ayant entrepris la construction du Pilier Blanc de Cantane",
|
|
||||||
birth: { day: 28, month: 6, year: 3139 },
|
|
||||||
category: 'ecclésiastique'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Taleb Vaht',
|
|
||||||
description:
|
|
||||||
"Fils de Bénédicte, il s'est engagé auprès des Étincelles comme alchimiste artificier.",
|
|
||||||
birth: { day: 9, month: 1, year: 3180 },
|
|
||||||
death: { day: 28, month: 7, year: 3209 },
|
|
||||||
category: 'étincelle',
|
|
||||||
secondaryCategories: ['scientifique']
|
|
||||||
}
|
|
||||||
]
|
|
||||||
})
|
|
||||||
31
server/api/characters/query.get.ts
Normal file
31
server/api/characters/query.get.ts
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
import { serverSupabaseClient } from "#supabase/server";
|
||||||
|
import { z } from 'zod'
|
||||||
|
import type { Character } from "~/models/Characters";
|
||||||
|
|
||||||
|
const querySchema = z.object({
|
||||||
|
world_id: z.number({ coerce: true }).positive().int()
|
||||||
|
})
|
||||||
|
|
||||||
|
export default defineEventHandler(async (event) => {
|
||||||
|
const client = await serverSupabaseClient(event)
|
||||||
|
const query = await getValidatedQuery(event, querySchema.parse)
|
||||||
|
|
||||||
|
const output = client
|
||||||
|
.from('characters')
|
||||||
|
.select(`
|
||||||
|
id,
|
||||||
|
name,
|
||||||
|
description,
|
||||||
|
birth,
|
||||||
|
death,
|
||||||
|
wiki,
|
||||||
|
category:character_categories!characters_category_fkey (*),
|
||||||
|
secondaryCategories:character_categories!character_categories_links (*)
|
||||||
|
`)
|
||||||
|
|
||||||
|
if (query.world_id) {
|
||||||
|
output.eq('world_id', query.world_id)
|
||||||
|
}
|
||||||
|
|
||||||
|
return output.returns<Character[]>()
|
||||||
|
})
|
||||||
@@ -1,217 +0,0 @@
|
|||||||
export default defineEventHandler(() => {
|
|
||||||
return [
|
|
||||||
// Histoire Antique
|
|
||||||
{
|
|
||||||
title: "Laurdieu devient la première cité de l'empire de Kaliatos",
|
|
||||||
startDate: { day: 3, month: 4, year: -1932 },
|
|
||||||
description:
|
|
||||||
"L'empire de Kaliatos établi sa capitale dans la cité de Laurdieu, qui connaitra une prospérité nouvelle au sein d'Aldys.",
|
|
||||||
category: 'législation',
|
|
||||||
secondaryCategories: ['inauguration'],
|
|
||||||
wiki: 'https://alexcreates.fr/leim/index.php/Laurdieu',
|
|
||||||
hidden: true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "Apparition d'Asménys",
|
|
||||||
startDate: { day: 19, month: 7, year: -1358 },
|
|
||||||
description:
|
|
||||||
"La défunte chanteuse Asménys apparaît à un barde pendant son jeune public, démarrant la religion des Prêtresses d'Asménys.",
|
|
||||||
category: 'religion',
|
|
||||||
secondaryCategories: ['bénédiction'],
|
|
||||||
wiki: 'https://alexcreates.fr/leim/index.php/Pr%C3%AAtresses_d%27Asm%C3%A9nys',
|
|
||||||
hidden: true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'La Rupture',
|
|
||||||
startDate: { day: 26, month: 5, year: -756 },
|
|
||||||
endDate: { day: 4, month: 9, year: 29 },
|
|
||||||
description:
|
|
||||||
"Les Abysses se déversent à la surface de Léim, à travers plusieurs brèches. Plusieurs hordes de démons se rapprochent des villes, et ce qu'on appellera l'Âge des Abysses commencent alors sur la planète entière.",
|
|
||||||
category: 'catastrophe',
|
|
||||||
secondaryCategories: ['catastrophe naturelle'],
|
|
||||||
wiki: 'https://alexcreates.fr/leim/index.php/Seconde_Rupture',
|
|
||||||
hidden: true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Marche du sang',
|
|
||||||
startDate: { day: 18, month: 9, year: -420 },
|
|
||||||
endDate: { day: 27, month: 1, year: -419 },
|
|
||||||
description:
|
|
||||||
"L'empereur de Kaliatos ordonne personnellement la traque de Jorhas Kirendre pour connivence avec les démons. Plusieurs bataillons sont affectés à la chasse de Jorhas, qui se terminera par son incarcération ainsi que la mort de plusieurs centaines de soldats.",
|
|
||||||
category: 'criminalité',
|
|
||||||
wiki: 'https://alexcreates.fr/leim/index.php/Jorhas_Kirendre',
|
|
||||||
hidden: true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Exécution de Tyhos',
|
|
||||||
startDate: { day: 1, month: 0, year: 0 },
|
|
||||||
description:
|
|
||||||
"Le léviathan Tyhos rend l'âme après un combat de plusieurs années contre Lystos, le dieu du Soleil.",
|
|
||||||
category: 'bénédiction',
|
|
||||||
secondaryCategories: ['mort'],
|
|
||||||
wiki: 'https://alexcreates.fr/leim/index.php/Tyhos',
|
|
||||||
hidden: true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Traité de Kadel',
|
|
||||||
startDate: { day: 29, month: 4, year: 100 },
|
|
||||||
description: '',
|
|
||||||
category: 'inauguration',
|
|
||||||
secondaryCategories: ['législation'],
|
|
||||||
wiki: 'https://alexcreates.fr/leim/index.php/Alliance_Kald%C3%A9lienne#Trait%C3%A9_de_Kadel'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Découverte des Plaines de Poussières',
|
|
||||||
startDate: { day: 17, month: 7, year: 305 },
|
|
||||||
description:
|
|
||||||
"Les troupes de la reconquête aldienne explorent le littoral d'une immense étendue grise et inerte.",
|
|
||||||
category: 'découverte',
|
|
||||||
secondaryCategories: ['exploration'],
|
|
||||||
wiki: 'https://alexcreates.fr/leim/index.php/Plaines_de_poussi%C3%A8re',
|
|
||||||
hidden: true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Construction du Rempart de Laurdieu',
|
|
||||||
startDate: { day: 30, month: 2, year: 340 },
|
|
||||||
endDate: { day: 27, month: 9, year: 355 },
|
|
||||||
description:
|
|
||||||
"Le Grand Conseil Kaldélien ordonne la construction d'une muraille autour des Plaines de Poussières, afin de contenir les démons y sortant.",
|
|
||||||
category: 'construction',
|
|
||||||
wiki: 'https://alexcreates.fr/leim/index.php/Plaines_de_poussi%C3%A8re',
|
|
||||||
hidden: true
|
|
||||||
},
|
|
||||||
|
|
||||||
// Histoire Récente
|
|
||||||
{
|
|
||||||
title: "Inauguration de l'Académie Artistique Arcanique",
|
|
||||||
startDate: { day: 11, month: 6, year: 2545 },
|
|
||||||
description:
|
|
||||||
"Scäd Sceni ouvre son institut artistique dédié à l'apprentissage des arts arcaniques",
|
|
||||||
category: 'inauguration',
|
|
||||||
secondaryCategories: ['arcanologie'],
|
|
||||||
wiki: 'https://alexcreates.fr/leim/index.php/Buse_(arme)'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Création de la buse kaldélienne',
|
|
||||||
startDate: { day: 4, month: 2, year: 3113 },
|
|
||||||
description:
|
|
||||||
'Sophia de Rougefer invente la buse kaldélienne, une arme à feu souple à deux canons.',
|
|
||||||
category: 'invention',
|
|
||||||
secondaryCategories: ['science'],
|
|
||||||
wiki: 'https://alexcreates.fr/leim/index.php/Buse_(arme)'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Feux dans les champs de Bamast',
|
|
||||||
startDate: { day: 9, month: 5, year: 3200 },
|
|
||||||
description:
|
|
||||||
"Plusieurs incendies criminels se propagent à travers les champs de sérille des fermiers des littoraux de Bamast. Aucun suspect ni coupable ne sera trouvé et l'enquête sera baclée.",
|
|
||||||
category: 'catastrophe',
|
|
||||||
secondaryCategories: ['criminalité'],
|
|
||||||
wiki: 'https://alexcreates.fr/leim/index.php/Vascylly'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Meurtre de Darléon Typhos',
|
|
||||||
startDate: { day: 21, month: 6, year: 3200 },
|
|
||||||
description:
|
|
||||||
'Darléon Typhos surprend Vascylly fouillant sa demeure peu après la tombée de la nuit. Le majordome de la famille Typhos découvre le corps sans vie de son maître le lendemain.',
|
|
||||||
category: 'criminalité',
|
|
||||||
secondaryCategories: ['joueurs'],
|
|
||||||
wiki: 'https://alexcreates.fr/leim/index.php/Vascylly'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Scandale Rodhus',
|
|
||||||
startDate: { day: 25, month: 9, year: 3208 },
|
|
||||||
description:
|
|
||||||
"Tivian Rodhus, un professeur estimé de l'Académie Centrale Kaldélienne, est emprisonné pour corruption et aggression sexuelle. Le corps enseignant y est remanié sur ordre de Lazarus Tymos, comte de Nacride.",
|
|
||||||
category: 'criminalité',
|
|
||||||
secondaryCategories: ['scandale'],
|
|
||||||
wiki: 'https://alexcreates.fr/leim/index.php/Tivian_Rodhus'
|
|
||||||
},
|
|
||||||
|
|
||||||
// "Les Milles Cages"
|
|
||||||
{
|
|
||||||
title: "Arrivée d'aventuriers à Borélis",
|
|
||||||
startDate: { day: 12, month: 7, year: 3209 },
|
|
||||||
description:
|
|
||||||
'Tara Belyus, Vascylly et Adol Sulvan livrent 3 condamnés à Handany. Ils partent pour la mer durant la journée.',
|
|
||||||
category: 'joueurs'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "Naufrage de l'Éclipse",
|
|
||||||
description:
|
|
||||||
"L'Éclipse, le navire de la garde contenant des condamnés à destination des Cages Handaniennes, s'échoue au large des côtes montagneuses de la Lance d'Aldys.",
|
|
||||||
startDate: { day: 14, month: 7, year: 3209 },
|
|
||||||
category: 'catastrophe'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Emprisonnement de Tivian Rodhus',
|
|
||||||
description: "Celui qu'on surnomme la Bête d'Ambrose arrive à Handany, où il purgera sa peine.",
|
|
||||||
startDate: { day: 14, month: 7, year: 3209 },
|
|
||||||
category: 'législation'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Sulvan et Anastael atteignent Bamast',
|
|
||||||
startDate: { day: 19, month: 2, year: 3210 },
|
|
||||||
category: 'joueurs'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Jugement de Bormis Griloup',
|
|
||||||
description:
|
|
||||||
"Bromis Griloup est jugé coupable d'escroquerie et sabotage aux Cours d'Acier de Tourgrise. Il purgera une peine de 10 ans au sein des prisons royales.",
|
|
||||||
startDate: { day: 4, month: 8, year: 3209 },
|
|
||||||
category: 'législation'
|
|
||||||
},
|
|
||||||
|
|
||||||
// "Les Cloches de Cantane"
|
|
||||||
{
|
|
||||||
title: 'Inauguration de la Cloche du Pilier',
|
|
||||||
description: "Le Moine Premier inaugure la grande cloche d'argent au sommet du Pilier d'Ikami.",
|
|
||||||
startDate: { day: 29, month: 5, year: 3209 },
|
|
||||||
category: 'religion',
|
|
||||||
secondaryCategories: ['inauguration']
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: '1ère disparation à Cantane',
|
|
||||||
description: "Taleb Vaht décède dans une grotte à la suite d'une attaque d'ischiels enragées.",
|
|
||||||
startDate: { day: 28, month: 7, year: 3209 },
|
|
||||||
category: 'mort',
|
|
||||||
hidden: true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: '2ème disparation à Cantane',
|
|
||||||
description: 'Donovane le mineur kéturien disparait sans laisser de traces.',
|
|
||||||
startDate: { day: 32, month: 7, year: 3209 },
|
|
||||||
category: 'mort',
|
|
||||||
hidden: true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: '3ème disparation à Cantane',
|
|
||||||
description: 'Disparition de Sébastien, gredin sauride.',
|
|
||||||
startDate: { day: 10, month: 8, year: 3209 },
|
|
||||||
category: 'mort',
|
|
||||||
hidden: true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: '4ème disparation à Cantane',
|
|
||||||
description: 'Disparition de Thérence, patrouilleur sauride de la Vieille Garde.',
|
|
||||||
startDate: { day: 19, month: 8, year: 3209 },
|
|
||||||
category: 'mort',
|
|
||||||
hidden: true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: '5ème disparation à Cantane',
|
|
||||||
description: 'Disparition de Mathilda Boulais, vendeuse de pierres.',
|
|
||||||
startDate: { day: 22, month: 8, year: 3209 },
|
|
||||||
category: 'mort',
|
|
||||||
hidden: true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Grande Banque Minérale de Cantane',
|
|
||||||
description:
|
|
||||||
'Les artisans et mineurs de Rougefer se réunissent à Cantane pour vendre le fruit de leur dur labeur.',
|
|
||||||
startDate: { day: 23, month: 8, year: 3209 },
|
|
||||||
endDate: { day: 26, month: 8, year: 3209 },
|
|
||||||
category: 'commerce'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
})
|
|
||||||
27
server/api/events/query.get.ts
Normal file
27
server/api/events/query.get.ts
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
import { serverSupabaseClient } from "#supabase/server";
|
||||||
|
import { z } from 'zod'
|
||||||
|
import type { CalendarEvent } from "~/models/CalendarEvent";
|
||||||
|
|
||||||
|
const querySchema = z.object({
|
||||||
|
world_id: z.number({ coerce: true }).positive().int()
|
||||||
|
})
|
||||||
|
|
||||||
|
export default defineEventHandler(async (event) => {
|
||||||
|
const client = await serverSupabaseClient(event)
|
||||||
|
const query = await getValidatedQuery(event, querySchema.parse)
|
||||||
|
|
||||||
|
const output = client
|
||||||
|
.from('calendar_events')
|
||||||
|
.select(`
|
||||||
|
id,
|
||||||
|
title,
|
||||||
|
description,
|
||||||
|
world_calendars (id, world_id)
|
||||||
|
`)
|
||||||
|
|
||||||
|
if (query.world_id) {
|
||||||
|
output.eq('world_calendars.world_id', query.world_id)
|
||||||
|
}
|
||||||
|
|
||||||
|
return output.returns<CalendarEvent[]>()
|
||||||
|
})
|
||||||
10
server/api/worlds/index.get.ts
Normal file
10
server/api/worlds/index.get.ts
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
import { serverSupabaseClient } from "#supabase/server";
|
||||||
|
import type { World } from "~/models/World";
|
||||||
|
|
||||||
|
export default defineEventHandler(async (event) => {
|
||||||
|
const client = await serverSupabaseClient(event)
|
||||||
|
|
||||||
|
return client.from('worlds')
|
||||||
|
.select(`id, name, description, color`)
|
||||||
|
.returns<World[]>()
|
||||||
|
})
|
||||||
@@ -1,26 +1,14 @@
|
|||||||
import {
|
import {
|
||||||
monthsPerYear,
|
type RPGDate,
|
||||||
daysPerWeek,
|
type RPGDateOrder,
|
||||||
daysPerMonth,
|
|
||||||
daysPerYear,
|
|
||||||
type LeimDate,
|
|
||||||
type LeimPeriod,
|
|
||||||
type LeimPeriodShort
|
|
||||||
} from '@/models/Date'
|
} from '@/models/Date'
|
||||||
import { useLocalStorage, useUrlSearchParams } from '@vueuse/core'
|
import { useLocalStorage, useUrlSearchParams } from '@vueuse/core'
|
||||||
import { defineStore, skipHydrate } from 'pinia'
|
import { defineStore, skipHydrate } from 'pinia'
|
||||||
import { computed, ref, type ComputedRef, type Ref } from 'vue'
|
import { computed, ref, type ComputedRef, type Ref } from 'vue'
|
||||||
|
import type { CalendarMonth } from '~/models/CalendarMonth'
|
||||||
|
|
||||||
type CalendarViewType = 'month' | 'year' | 'decade' | 'century'
|
type CalendarViewType = 'month' | 'year' | 'decade' | 'century'
|
||||||
|
|
||||||
type CalendarStaticConfig = {
|
|
||||||
months: string[]
|
|
||||||
monthsPerYear: number
|
|
||||||
daysPerYear: number
|
|
||||||
daysPerMonth: number
|
|
||||||
daysPerWeek: number
|
|
||||||
}
|
|
||||||
|
|
||||||
type CalendarCurrentConfig = {
|
type CalendarCurrentConfig = {
|
||||||
viewType: CalendarViewType
|
viewType: CalendarViewType
|
||||||
}
|
}
|
||||||
@@ -30,8 +18,6 @@ type CalendarCurrentDate = {
|
|||||||
currentMonth: ComputedRef<number>
|
currentMonth: ComputedRef<number>
|
||||||
currentMonthName: ComputedRef<string>
|
currentMonthName: ComputedRef<string>
|
||||||
currentYear: ComputedRef<number>
|
currentYear: ComputedRef<number>
|
||||||
currentPeriod: Ref<LeimPeriod>
|
|
||||||
currentPeriodAbbr: Ref<LeimPeriodShort>
|
|
||||||
currentDateTitle: ComputedRef<string>
|
currentDateTitle: ComputedRef<string>
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -40,31 +26,6 @@ export const useCalendar = defineStore('calendar', () => {
|
|||||||
* Static calendar config
|
* Static calendar config
|
||||||
* This shouldn't change
|
* This shouldn't change
|
||||||
*/
|
*/
|
||||||
/**
|
|
||||||
* Month list
|
|
||||||
*/
|
|
||||||
const months: string[] = [
|
|
||||||
'Jalen',
|
|
||||||
'Malsen',
|
|
||||||
'Verlys',
|
|
||||||
'Nalys',
|
|
||||||
'Verdore',
|
|
||||||
'Sidore',
|
|
||||||
'Lyllion',
|
|
||||||
'Rion',
|
|
||||||
'Farene',
|
|
||||||
'Dalvene'
|
|
||||||
]
|
|
||||||
|
|
||||||
// Assign the static config
|
|
||||||
const staticConfig: CalendarStaticConfig = {
|
|
||||||
months,
|
|
||||||
monthsPerYear,
|
|
||||||
daysPerYear,
|
|
||||||
daysPerMonth,
|
|
||||||
daysPerWeek
|
|
||||||
}
|
|
||||||
|
|
||||||
const currentConfig: Ref<CalendarCurrentConfig> = ref({
|
const currentConfig: Ref<CalendarCurrentConfig> = ref({
|
||||||
viewType: 'month'
|
viewType: 'month'
|
||||||
})
|
})
|
||||||
@@ -75,15 +36,34 @@ export const useCalendar = defineStore('calendar', () => {
|
|||||||
'century'
|
'century'
|
||||||
])
|
])
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Month list (queried from API)
|
||||||
|
*/
|
||||||
|
const months: Ref<CalendarMonth[]> = ref<CalendarMonth[]>([])
|
||||||
|
|
||||||
|
function setMonths(data: CalendarMonth[]) {
|
||||||
|
months.value = data
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sorted month data using the raw months
|
||||||
|
*/
|
||||||
|
const sortedMonths = computed<CalendarMonth[]>(() => months.value.sort((a, b) => a.position - b.position))
|
||||||
|
const monthsPerYear = computed(() => months.value.length)
|
||||||
|
const daysPerYear = computed(() => months.value.reduce((acc, o) => acc + o.days, 0))
|
||||||
|
|
||||||
// Default date settings (current day in the world)
|
// Default date settings (current day in the world)
|
||||||
const defaultDay: number = 23
|
// The base setting is the first day / month of year 0
|
||||||
const defaultMonth: number = 8
|
const defaultDay: Ref<number> = ref<number>(1)
|
||||||
const defaultYear: number = 3209
|
const defaultMonth: Ref<number> = ref<number>(0)
|
||||||
const defaultDate: ComputedRef<LeimDate> = computed(() => {
|
const defaultYear: Ref<number> = ref<number>(0)
|
||||||
|
|
||||||
|
// Object representation
|
||||||
|
const defaultDate: ComputedRef<RPGDate> = computed(() => {
|
||||||
return {
|
return {
|
||||||
day: defaultDay,
|
day: defaultDay.value,
|
||||||
month: defaultMonth,
|
month: defaultMonth.value,
|
||||||
year: defaultYear
|
year: defaultYear.value
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -97,6 +77,24 @@ export const useCalendar = defineStore('calendar', () => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the new defaultDate (aka the "today" value from the calendar)
|
||||||
|
*
|
||||||
|
* @param date The new data to set as defaultDate
|
||||||
|
*/
|
||||||
|
function setDefaultDate(date: RPGDate) {
|
||||||
|
defaultDay.value = date.day
|
||||||
|
defaultMonth.value = date.month
|
||||||
|
defaultYear.value = date.year
|
||||||
|
}
|
||||||
|
|
||||||
|
// Everytime the defaultDate changes / is set, we should update the params in the URL
|
||||||
|
watch(defaultDate, () => {
|
||||||
|
params.day = String(defaultDate.value.day)
|
||||||
|
params.month = String(defaultDate.value.month)
|
||||||
|
params.year = String(defaultDate.value.year)
|
||||||
|
})
|
||||||
|
|
||||||
const currentDay = computed<number>(() => {
|
const currentDay = computed<number>(() => {
|
||||||
return Number(params.day)
|
return Number(params.day)
|
||||||
})
|
})
|
||||||
@@ -104,6 +102,9 @@ export const useCalendar = defineStore('calendar', () => {
|
|||||||
const currentMonth = computed<number>(() => {
|
const currentMonth = computed<number>(() => {
|
||||||
return Number(params.month)
|
return Number(params.month)
|
||||||
})
|
})
|
||||||
|
const currentMonthData = computed<CalendarMonth>(() => {
|
||||||
|
return sortedMonths.value[currentMonth.value]
|
||||||
|
})
|
||||||
// Gets the label from currentMonth index
|
// Gets the label from currentMonth index
|
||||||
const currentMonthName = computed<string>(() => getMonthName(currentMonth.value))
|
const currentMonthName = computed<string>(() => getMonthName(currentMonth.value))
|
||||||
|
|
||||||
@@ -111,12 +112,6 @@ export const useCalendar = defineStore('calendar', () => {
|
|||||||
return Number(params.year)
|
return Number(params.year)
|
||||||
})
|
})
|
||||||
|
|
||||||
// Get period from currentYear
|
|
||||||
const currentPeriod = computed<LeimPeriod>(() => getPeriodOfYear(currentYear.value).long)
|
|
||||||
const currentPeriodAbbr = computed<LeimPeriodShort>(
|
|
||||||
() => getPeriodOfYear(currentYear.value).short
|
|
||||||
)
|
|
||||||
|
|
||||||
const currentDateTitle = computed<string>(() => {
|
const currentDateTitle = computed<string>(() => {
|
||||||
switch (currentConfig.value.viewType) {
|
switch (currentConfig.value.viewType) {
|
||||||
case 'month':
|
case 'month':
|
||||||
@@ -124,17 +119,16 @@ export const useCalendar = defineStore('calendar', () => {
|
|||||||
day: currentDate.currentDay.value,
|
day: currentDate.currentDay.value,
|
||||||
month: currentDate.currentMonth.value,
|
month: currentDate.currentMonth.value,
|
||||||
year: currentDate.currentYear.value,
|
year: currentDate.currentYear.value,
|
||||||
period: currentDate.currentPeriod.value
|
|
||||||
})
|
})
|
||||||
|
|
||||||
case 'year':
|
case 'year':
|
||||||
return `Année ${currentYear.value} ${currentPeriodAbbr.value}`
|
return `Année ${currentYear.value}`
|
||||||
|
|
||||||
case 'decade':
|
case 'decade':
|
||||||
return `Années ${currentYear.value} ${getPeriodOfYear(currentYear.value).short} - ${currentYear.value + 10} ${getPeriodOfYear(currentYear.value + 10).short}`
|
return `Années ${currentYear.value} - ${currentYear.value + 10}`
|
||||||
|
|
||||||
case 'century':
|
case 'century':
|
||||||
return `Années ${currentYear.value} ${getPeriodOfYear(currentYear.value).short} - ${currentYear.value + 100} ${getPeriodOfYear(currentYear.value + 100).short}`
|
return `Années ${currentYear.value} - ${currentYear.value + 100}`
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return 'Date inconnue'
|
return 'Date inconnue'
|
||||||
@@ -147,21 +141,18 @@ export const useCalendar = defineStore('calendar', () => {
|
|||||||
currentMonth,
|
currentMonth,
|
||||||
currentMonthName,
|
currentMonthName,
|
||||||
currentYear,
|
currentYear,
|
||||||
currentPeriod,
|
|
||||||
currentPeriodAbbr,
|
|
||||||
currentDateTitle
|
currentDateTitle
|
||||||
}
|
}
|
||||||
|
|
||||||
const currentLeimDate = computed<LeimDate>(() => {
|
const currentRPGDate = computed<RPGDate>(() => {
|
||||||
return {
|
return {
|
||||||
day: currentDate.currentDay.value,
|
day: currentDate.currentDay.value,
|
||||||
month: currentDate.currentMonth.value,
|
month: currentDate.currentMonth.value,
|
||||||
year: currentDate.currentYear.value,
|
year: currentDate.currentYear.value,
|
||||||
period: currentDate.currentPeriod.value
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
const selectedDate = useLocalStorage<LeimDate>('selected-date', currentLeimDate.value, { deep: true })
|
const selectedDate = useLocalStorage<RPGDate>('selected-date', currentRPGDate.value, { deep: true })
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check whether the current viewType is active
|
* Check whether the current viewType is active
|
||||||
@@ -192,7 +183,7 @@ export const useCalendar = defineStore('calendar', () => {
|
|||||||
let newValue = Number(params.month) + 1
|
let newValue = Number(params.month) + 1
|
||||||
|
|
||||||
// If the new value would exceed the max number of month per year
|
// If the new value would exceed the max number of month per year
|
||||||
if (newValue >= staticConfig.monthsPerYear) {
|
if (newValue >= monthsPerYear.value) {
|
||||||
newValue = 0
|
newValue = 0
|
||||||
// Increment the year
|
// Increment the year
|
||||||
incrementYear()
|
incrementYear()
|
||||||
@@ -209,7 +200,7 @@ export const useCalendar = defineStore('calendar', () => {
|
|||||||
|
|
||||||
// If the new value would go below 0
|
// If the new value would go below 0
|
||||||
if (newValue < 0) {
|
if (newValue < 0) {
|
||||||
newValue = staticConfig.monthsPerYear - 1
|
newValue = monthsPerYear.value - 1
|
||||||
// Decrement the year
|
// Decrement the year
|
||||||
decrementYear()
|
decrementYear()
|
||||||
}
|
}
|
||||||
@@ -227,7 +218,7 @@ export const useCalendar = defineStore('calendar', () => {
|
|||||||
const target: number = monthNumber - 1
|
const target: number = monthNumber - 1
|
||||||
|
|
||||||
if (target < 0) {
|
if (target < 0) {
|
||||||
return monthsPerYear - 1
|
return monthsPerYear.value - 1
|
||||||
}
|
}
|
||||||
|
|
||||||
return target
|
return target
|
||||||
@@ -242,7 +233,7 @@ export const useCalendar = defineStore('calendar', () => {
|
|||||||
function getNextMonth(monthNumber: number): number {
|
function getNextMonth(monthNumber: number): number {
|
||||||
const target: number = monthNumber + 1
|
const target: number = monthNumber + 1
|
||||||
|
|
||||||
if (target + 1 >= monthsPerYear) {
|
if (target + 1 > monthsPerYear.value) {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -254,7 +245,7 @@ export const useCalendar = defineStore('calendar', () => {
|
|||||||
*/
|
*/
|
||||||
function setMonth(target: number): void {
|
function setMonth(target: number): void {
|
||||||
// If the target is outside the month bounds
|
// If the target is outside the month bounds
|
||||||
if (target < 0 || target >= staticConfig.monthsPerYear) {
|
if (target < 0 || target >= monthsPerYear.value) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -279,23 +270,6 @@ export const useCalendar = defineStore('calendar', () => {
|
|||||||
params.year = newValue.toString()
|
params.year = newValue.toString()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* From a given year, returns a set of LeimPeriod identifier
|
|
||||||
*
|
|
||||||
* This is used in range use-cases
|
|
||||||
*
|
|
||||||
* @param year The year to display
|
|
||||||
* @returns An object containing both short and long LeimPeriod
|
|
||||||
*/
|
|
||||||
function getPeriodOfYear(year: string | number): { long: LeimPeriod; short: LeimPeriodShort } {
|
|
||||||
const numYear = year as number
|
|
||||||
|
|
||||||
return {
|
|
||||||
long: numYear >= 0 ? 'nante' : 'ante',
|
|
||||||
short: numYear >= 0 ? 'N.R' : 'A.R'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the formatted month name given its index
|
* Get the formatted month name given its index
|
||||||
*
|
*
|
||||||
@@ -304,7 +278,23 @@ export const useCalendar = defineStore('calendar', () => {
|
|||||||
*/
|
*/
|
||||||
function getMonthName(monthNumber: number): string {
|
function getMonthName(monthNumber: number): string {
|
||||||
const index = Number(monthNumber)
|
const index = Number(monthNumber)
|
||||||
return staticConfig.months[index]
|
if (sortedMonths.value[index]) {
|
||||||
|
return sortedMonths.value[index].name
|
||||||
|
}
|
||||||
|
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* State for advanced search modal
|
||||||
|
*/
|
||||||
|
const isAdvancedSearchOpen: Ref<boolean> = ref<boolean>(false)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Opens the search modal
|
||||||
|
*/
|
||||||
|
function revealAdvancedSearch() {
|
||||||
|
isAdvancedSearchOpen.value = true
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -316,6 +306,9 @@ export const useCalendar = defineStore('calendar', () => {
|
|||||||
currentConfig.value.viewType = viewType
|
currentConfig.value.viewType = viewType
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* FORMATTING
|
||||||
|
*/
|
||||||
/**
|
/**
|
||||||
* Gets the formatted viewType title
|
* Gets the formatted viewType title
|
||||||
*
|
*
|
||||||
@@ -340,26 +333,29 @@ export const useCalendar = defineStore('calendar', () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* From a LeimDate, returns the legible date title
|
* From a RPGDate, returns the legible date title
|
||||||
*
|
*
|
||||||
* @param date Date target
|
* @param date Date target
|
||||||
* @param showNumber Should the date show the day number
|
* @param showNumber Should the date show the day number
|
||||||
* @returns Formatted date name
|
* @returns Formatted date name
|
||||||
*/
|
*/
|
||||||
function getFormattedDateTitle(date: LeimDate, showNumber?: boolean): string {
|
function getFormattedDateTitle(date: RPGDate, showNumber?: boolean): string {
|
||||||
if (showNumber) {
|
if (showNumber) {
|
||||||
return `${date.day} ${getMonthName(date.month)} ${date.year} ${getPeriodOfYear(date.year).short}`
|
return `${date.day} ${getMonthName(date.month)} ${date.year}`
|
||||||
}
|
}
|
||||||
|
|
||||||
return `${getMonthName(date.month)} ${date.year} ${getPeriodOfYear(date.year).short}`
|
return `${getMonthName(date.month)} ${date.year}`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DATE JUMPS & SELECTION
|
||||||
|
*/
|
||||||
/**
|
/**
|
||||||
* Jumps the calendar to the given date
|
* Jumps the calendar to the given date
|
||||||
*
|
*
|
||||||
* @param date Target date
|
* @param date Target date
|
||||||
*/
|
*/
|
||||||
function jumpToDate(date: LeimDate): void {
|
function jumpToDate(date: RPGDate): void {
|
||||||
params.day = date.day.toString()
|
params.day = date.day.toString()
|
||||||
params.month = date.month.toString()
|
params.month = date.month.toString()
|
||||||
params.year = date.year.toString()
|
params.year = date.year.toString()
|
||||||
@@ -376,27 +372,247 @@ export const useCalendar = defineStore('calendar', () => {
|
|||||||
/**
|
/**
|
||||||
* Jump the calendar to the default date
|
* Jump the calendar to the default date
|
||||||
*/
|
*/
|
||||||
function selectDate(date: LeimDate): void {
|
function selectDate(date: RPGDate): void {
|
||||||
selectedDate.value = date
|
selectedDate.value = date
|
||||||
}
|
}
|
||||||
|
|
||||||
const isAdvancedSearchOpen: Ref<boolean> = ref<boolean>(false)
|
/**
|
||||||
|
* DATE OPERATIONS
|
||||||
|
*
|
||||||
|
* Used to convert dates, sort them and compare them
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* Converts a RPGDate to its equivalent in days
|
||||||
|
*
|
||||||
|
* @param dateToConvert The date object
|
||||||
|
* @returns How many days does it represent
|
||||||
|
*/
|
||||||
|
function convertDateToDays(dateToConvert: RPGDate): number {
|
||||||
|
let numberOfDays: number = dateToConvert.day
|
||||||
|
|
||||||
function revealAdvancedSearch() {
|
// Get only the remaining months on the year
|
||||||
isAdvancedSearchOpen.value = true
|
const remainingMonths = sortedMonths.value.filter((m) => dateToConvert.month >= m.position)
|
||||||
|
// From remaining months, reduce their days value
|
||||||
|
const monthDaysToAdd = remainingMonths.reduce((a, b) => {
|
||||||
|
return a + b.days
|
||||||
|
}, 0)
|
||||||
|
|
||||||
|
numberOfDays = numberOfDays + monthDaysToAdd
|
||||||
|
numberOfDays = numberOfDays + dateToConvert.year * daysPerYear.value
|
||||||
|
|
||||||
|
return numberOfDays - 1
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* From two dates, get the difference in days between them
|
||||||
|
* @param baseDate The base date
|
||||||
|
* @param relativeDate The year to compare it to
|
||||||
|
* @returns The number of days separating the two dates (both positive and negative numbers)
|
||||||
|
*/
|
||||||
|
function getDifferenceInDays(baseDate: RPGDate, relativeDate: RPGDate): number {
|
||||||
|
return convertDateToDays(relativeDate) - convertDateToDays(baseDate)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check whether two dates are identical
|
||||||
|
*
|
||||||
|
* @param date1 First date
|
||||||
|
* @param date2 Second date
|
||||||
|
* @returns True if the dates are identical
|
||||||
|
*/
|
||||||
|
function areDatesIdentical(date1: RPGDate, date2: RPGDate): boolean {
|
||||||
|
return getDifferenceInDays({ ...date1 }, { ...date2 }) === 0
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compare dates (used for array sorting)
|
||||||
|
*
|
||||||
|
* @param date1 First date
|
||||||
|
* @param date2 Second date
|
||||||
|
* @returns 1 means the first date comes before the second, -1 means the second comes before the first, and 0 if they're identical
|
||||||
|
*/
|
||||||
|
function compareDates(a: RPGDate, b: RPGDate, order: RPGDateOrder = 'desc'): number {
|
||||||
|
// Reverses the order if specified
|
||||||
|
const orderFactor: number = order === 'desc' ? 1 : -1
|
||||||
|
|
||||||
|
// Compare years
|
||||||
|
if (a.year < b.year) return -1 * orderFactor
|
||||||
|
if (a.year > b.year) return 1 * orderFactor
|
||||||
|
|
||||||
|
// Compare months
|
||||||
|
if (a.month < b.month) return -1 * orderFactor
|
||||||
|
if (a.month > b.month) return 1 * orderFactor
|
||||||
|
|
||||||
|
// Compare days
|
||||||
|
if (a.day < b.day) return -1 * orderFactor
|
||||||
|
if (a.day > b.day) return 1 * orderFactor
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* From two dates, gives information on how many years, months and days it has been / will be between them
|
||||||
|
*
|
||||||
|
* @param baseDate The base date
|
||||||
|
* @param relativeDate The year to compare it to
|
||||||
|
* @returns A string with info on how the relative date differs to the base date
|
||||||
|
*/
|
||||||
|
function getRelativeString(
|
||||||
|
baseDate: RPGDate,
|
||||||
|
relativeDate: RPGDate,
|
||||||
|
formatting: 'compact' | 'complex' = 'complex'
|
||||||
|
): string {
|
||||||
|
const differenceInDays: number = getDifferenceInDays(baseDate, relativeDate)
|
||||||
|
let output: string = ''
|
||||||
|
let direction: 'past' | 'present' | 'future' = 'present'
|
||||||
|
let directionPrefix: string = ''
|
||||||
|
|
||||||
|
// Check whether it's a past or future date
|
||||||
|
if (differenceInDays > 0) {
|
||||||
|
direction = 'future'
|
||||||
|
} else if (differenceInDays < 0) {
|
||||||
|
direction = 'past'
|
||||||
|
}
|
||||||
|
|
||||||
|
if (formatting === 'complex') {
|
||||||
|
// Handle if it's the same date
|
||||||
|
if (direction === 'present') {
|
||||||
|
return "Aujourd'hui"
|
||||||
|
}
|
||||||
|
if (differenceInDays === -2) {
|
||||||
|
return 'Avant-hier'
|
||||||
|
}
|
||||||
|
if (differenceInDays === -1) {
|
||||||
|
return 'Hier'
|
||||||
|
}
|
||||||
|
if (differenceInDays === 1) {
|
||||||
|
return 'Demain'
|
||||||
|
}
|
||||||
|
if (differenceInDays === 2) {
|
||||||
|
return 'Après-demain'
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get relevant prefix for the string
|
||||||
|
if (direction === 'future') {
|
||||||
|
directionPrefix = 'Dans '
|
||||||
|
} else if (direction === 'past') {
|
||||||
|
directionPrefix = 'Il y a '
|
||||||
|
}
|
||||||
|
|
||||||
|
output += directionPrefix
|
||||||
|
}
|
||||||
|
|
||||||
|
const isSameMonth = baseDate.month === relativeDate.month
|
||||||
|
const isSameYear = baseDate.year === relativeDate.year
|
||||||
|
|
||||||
|
// At this point, we are beyond simple scenarios and must calculate the distance accurately
|
||||||
|
|
||||||
|
// Get which date should come first
|
||||||
|
let ancientDate: RPGDate
|
||||||
|
let futureDate: RPGDate
|
||||||
|
|
||||||
|
if (direction === "future") {
|
||||||
|
ancientDate = baseDate
|
||||||
|
futureDate = relativeDate
|
||||||
|
} else {
|
||||||
|
ancientDate = relativeDate
|
||||||
|
futureDate = baseDate
|
||||||
|
}
|
||||||
|
|
||||||
|
// The pivot point that will help proceed towards the relativeDate
|
||||||
|
const datePivot: RPGDate = { ...ancientDate }
|
||||||
|
// The accumulator that will hold the distance between the two dates
|
||||||
|
const dateAcc: RPGDate = { day: 0, month: 0, year: 0 }
|
||||||
|
|
||||||
|
// If we are on the same month / year during acceleration, just don't rev up
|
||||||
|
if (isSameMonth && isSameYear) {
|
||||||
|
dateAcc.day = futureDate.day - datePivot.day
|
||||||
|
|
||||||
|
if (dateAcc.day === 1) {
|
||||||
|
output += ` ${dateAcc.day} jour`
|
||||||
|
} else {
|
||||||
|
output += ` ${dateAcc.day} jours`
|
||||||
|
}
|
||||||
|
|
||||||
|
return output
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we are on the same year during acceleration, just don't rev up the next month, it might overflow to the next year
|
||||||
|
else if (isSameYear) {
|
||||||
|
dateAcc.month = futureDate.month - datePivot.month
|
||||||
|
|
||||||
|
output += ` ${dateAcc.month} mois`
|
||||||
|
|
||||||
|
return output
|
||||||
|
}
|
||||||
|
|
||||||
|
// Else, we need to accelerate and decelerate
|
||||||
|
else {
|
||||||
|
// First, get all the remaining days in the current month
|
||||||
|
const currentMonth = sortedMonths.value[datePivot.month]
|
||||||
|
dateAcc.day = currentMonth.days - datePivot.day
|
||||||
|
if (direction === 'future') {
|
||||||
|
datePivot.month = getNextMonth(datePivot.month)
|
||||||
|
} else {
|
||||||
|
datePivot.month = getPreviousMonth(datePivot.month)
|
||||||
|
}
|
||||||
|
datePivot.day = 1
|
||||||
|
|
||||||
|
// Then, get the remaining months in the year
|
||||||
|
const remainingMonthsStart = sortedMonths.value.filter((m) => datePivot.month < m.position )
|
||||||
|
if (direction === 'future') {
|
||||||
|
dateAcc.month = remainingMonthsStart.length + 1
|
||||||
|
} else {
|
||||||
|
dateAcc.month = remainingMonthsStart.length - 1
|
||||||
|
}
|
||||||
|
datePivot.month = 0
|
||||||
|
|
||||||
|
// Then, Accelerate through years
|
||||||
|
dateAcc.month = dateAcc.month + ((futureDate.year - datePivot.year) - 1) * monthsPerYear.value
|
||||||
|
datePivot.year = futureDate.year
|
||||||
|
|
||||||
|
// Once we reached the relativeYear, decelerate and get through the extra months
|
||||||
|
const remainingMonthsEnd = futureDate.month
|
||||||
|
dateAcc.month = dateAcc.month + remainingMonthsEnd
|
||||||
|
datePivot.month = futureDate.month
|
||||||
|
|
||||||
|
// Then at the destination month, decelerate to get the rest of the days
|
||||||
|
dateAcc.day = dateAcc.day + futureDate.day
|
||||||
|
datePivot.day = futureDate.day
|
||||||
|
|
||||||
|
const computedYear = Math.trunc(dateAcc.month / monthsPerYear.value)
|
||||||
|
const remainderMonths = dateAcc.month % monthsPerYear.value
|
||||||
|
|
||||||
|
if (computedYear >= 1 && remainderMonths) {
|
||||||
|
output += ` ${computedYear} an(s) et ${remainderMonths} mois`
|
||||||
|
}
|
||||||
|
else if (computedYear >= 1 && !remainderMonths) {
|
||||||
|
output += ` ${computedYear} an(s)`;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
output += ` ${remainderMonths} mois`
|
||||||
|
}
|
||||||
|
|
||||||
|
return output
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
staticConfig,
|
months,
|
||||||
|
setMonths,
|
||||||
|
sortedMonths,
|
||||||
|
daysPerYear,
|
||||||
|
monthsPerYear,
|
||||||
viewTypeOptions,
|
viewTypeOptions,
|
||||||
currentConfig,
|
currentConfig,
|
||||||
currentDate,
|
currentDate,
|
||||||
currentLeimDate,
|
currentRPGDate,
|
||||||
|
currentMonthData,
|
||||||
defaultDate,
|
defaultDate,
|
||||||
|
setDefaultDate,
|
||||||
selectedDate: skipHydrate(selectedDate),
|
selectedDate: skipHydrate(selectedDate),
|
||||||
selectDate,
|
selectDate,
|
||||||
params,
|
params,
|
||||||
getPeriodOfYear,
|
|
||||||
incrementMonth,
|
incrementMonth,
|
||||||
decrementMonth,
|
decrementMonth,
|
||||||
setMonth,
|
setMonth,
|
||||||
@@ -412,6 +628,11 @@ export const useCalendar = defineStore('calendar', () => {
|
|||||||
getViewTypeTitle,
|
getViewTypeTitle,
|
||||||
isCurrentScreenActive,
|
isCurrentScreenActive,
|
||||||
isAdvancedSearchOpen,
|
isAdvancedSearchOpen,
|
||||||
|
convertDateToDays,
|
||||||
|
getDifferenceInDays,
|
||||||
|
areDatesIdentical,
|
||||||
|
compareDates,
|
||||||
|
getRelativeString,
|
||||||
revealAdvancedSearch
|
revealAdvancedSearch
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -3,25 +3,10 @@ import { defineStore } from 'pinia'
|
|||||||
|
|
||||||
export const useCharacters = defineStore('characters', () => {
|
export const useCharacters = defineStore('characters', () => {
|
||||||
const characters = ref<Character[]>([])
|
const characters = ref<Character[]>([])
|
||||||
const charactersAreLoading = ref<boolean>(false)
|
|
||||||
const charactersLoaded = ref<boolean>(false)
|
|
||||||
|
|
||||||
async function fetchCharacters() {
|
async function setCharacters(data: Character[]) {
|
||||||
try {
|
characters.value = data
|
||||||
charactersAreLoading.value = true
|
|
||||||
const fetched = await useFetch<Character[]>('/api/characters')
|
|
||||||
|
|
||||||
if (fetched.data.value) {
|
|
||||||
charactersLoaded.value = true
|
|
||||||
characters.value = fetched.data.value
|
|
||||||
}
|
|
||||||
} catch (err) {
|
|
||||||
console.log(err)
|
|
||||||
} finally {
|
|
||||||
charactersAreLoading.value = false
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
fetchCharacters()
|
|
||||||
|
|
||||||
return { characters }
|
return { characters, setCharacters }
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,15 +1,17 @@
|
|||||||
import { compareDates, convertDateToDays, daysPerMonth, type LeimDate } from '@/models/Date'
|
import type { RPGDate } from '@/models/Date'
|
||||||
import type { CalendarEvent } from '@/models/Events'
|
import type { CalendarEvent } from '@/models/CalendarEvent'
|
||||||
import { defineStore } from 'pinia'
|
import { defineStore } from 'pinia'
|
||||||
import { ref, watch, type Ref } from 'vue'
|
import { ref, watch, type Ref } from 'vue'
|
||||||
import { useCalendar } from './CalendarStore'
|
import { useCalendar } from './CalendarStore'
|
||||||
|
|
||||||
export const useCalendarEvents = defineStore('calendar-events', () => {
|
export const useCalendarEvents = defineStore('calendar-events', () => {
|
||||||
const { currentDate, currentConfig } = useCalendar()
|
const { currentDate, currentConfig, convertDateToDays, compareDates } = useCalendar()
|
||||||
|
|
||||||
const baseEvents = ref<CalendarEvent[]>([])
|
const baseEvents = ref<CalendarEvent[]>([])
|
||||||
const eventsAreLoading = ref<boolean>(false)
|
|
||||||
const eventsLoaded = ref<boolean>(false)
|
function setEvents(data: CalendarEvent[]) {
|
||||||
|
baseEvents.value = data
|
||||||
|
}
|
||||||
|
|
||||||
const allEvents = computed(() => baseEvents.value.sort((a, b) => {
|
const allEvents = computed(() => baseEvents.value.sort((a, b) => {
|
||||||
return compareDates(a.startDate, b.startDate, 'desc')
|
return compareDates(a.startDate, b.startDate, 'desc')
|
||||||
@@ -23,22 +25,6 @@ export const useCalendarEvents = defineStore('calendar-events', () => {
|
|||||||
currentEvents.value = computeCurrentEvents()
|
currentEvents.value = computeCurrentEvents()
|
||||||
})
|
})
|
||||||
|
|
||||||
async function fetchEvents() {
|
|
||||||
try {
|
|
||||||
eventsAreLoading.value = true
|
|
||||||
const fetched = await useFetch<CalendarEvent[]>('/api/events')
|
|
||||||
|
|
||||||
if (fetched.data.value) {
|
|
||||||
eventsLoaded.value = true
|
|
||||||
baseEvents.value = fetched.data.value
|
|
||||||
}
|
|
||||||
} catch (err) {
|
|
||||||
console.log(err)
|
|
||||||
} finally {
|
|
||||||
eventsAreLoading.value = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determines if the event can appear in the front end
|
* Determines if the event can appear in the front end
|
||||||
*
|
*
|
||||||
@@ -48,8 +34,8 @@ export const useCalendarEvents = defineStore('calendar-events', () => {
|
|||||||
* @returns Whether the event should appear in the current view
|
* @returns Whether the event should appear in the current view
|
||||||
*/
|
*/
|
||||||
function shouldEventBeDisplayed(event: CalendarEvent): boolean {
|
function shouldEventBeDisplayed(event: CalendarEvent): boolean {
|
||||||
const eventStartDateToDays = convertDateToDays(event.startDate)
|
// const eventStartDateToDays = convertDateToDays(event.startDate)
|
||||||
const eventEndDateToDays: number = event.endDate ? convertDateToDays(event.endDate) : 0
|
// const eventEndDateToDays: number = event.endDate ? convertDateToDays(event.endDate) : 0
|
||||||
|
|
||||||
const isEventOnCurrentScreen =
|
const isEventOnCurrentScreen =
|
||||||
(event.startDate.year === currentDate.currentYear &&
|
(event.startDate.year === currentDate.currentYear &&
|
||||||
@@ -60,23 +46,26 @@ export const useCalendarEvents = defineStore('calendar-events', () => {
|
|||||||
|
|
||||||
// Check whether the event is on the last 8 tiles
|
// Check whether the event is on the last 8 tiles
|
||||||
// This is to allow leap events from appearing on the last 8 tiles
|
// This is to allow leap events from appearing on the last 8 tiles
|
||||||
const firstDayOfCurrentMonth = convertDateToDays({
|
//
|
||||||
day: 1,
|
// This is not used for now
|
||||||
month: currentDate.currentMonth,
|
//
|
||||||
year: currentDate.currentYear
|
// const firstDayOfCurrentMonth = convertDateToDays({
|
||||||
})
|
// day: 1,
|
||||||
const lastDayOfCurrentMonth = firstDayOfCurrentMonth + daysPerMonth
|
// month: currentDate.currentMonth,
|
||||||
const last8Tiles = lastDayOfCurrentMonth + 8
|
// year: currentDate.currentYear
|
||||||
|
// })
|
||||||
|
// const lastDayOfCurrentMonth = firstDayOfCurrentMonth + daysPerMonth
|
||||||
|
// const last8Tiles = lastDayOfCurrentMonth + 8
|
||||||
|
|
||||||
const isEventOnNext8Tiles =
|
// const isEventOnNext8Tiles =
|
||||||
(eventStartDateToDays <= last8Tiles && eventStartDateToDays >= lastDayOfCurrentMonth) ||
|
// (eventStartDateToDays <= last8Tiles && eventStartDateToDays >= lastDayOfCurrentMonth) ||
|
||||||
(Boolean(event.endDate) &&
|
// (Boolean(event.endDate) &&
|
||||||
eventEndDateToDays <= last8Tiles &&
|
// eventEndDateToDays <= last8Tiles &&
|
||||||
eventEndDateToDays >= lastDayOfCurrentMonth)
|
// eventEndDateToDays >= lastDayOfCurrentMonth)
|
||||||
|
|
||||||
switch (currentConfig.viewType) {
|
switch (currentConfig.viewType) {
|
||||||
case 'month':
|
case 'month':
|
||||||
return isEventOnCurrentScreen || isEventOnNext8Tiles
|
return isEventOnCurrentScreen!
|
||||||
|
|
||||||
case 'year':
|
case 'year':
|
||||||
return event.startDate.year === currentDate.currentYear
|
return event.startDate.year === currentDate.currentYear
|
||||||
@@ -119,8 +108,8 @@ export const useCalendarEvents = defineStore('calendar-events', () => {
|
|||||||
event: CalendarEvent,
|
event: CalendarEvent,
|
||||||
position: 'next' | 'prev' = 'next',
|
position: 'next' | 'prev' = 'next',
|
||||||
initialIsEnd: boolean = false
|
initialIsEnd: boolean = false
|
||||||
): { event: CalendarEvent; targetDate: LeimDate } {
|
): { event: CalendarEvent; targetDate: RPGDate } {
|
||||||
let dateToParse: LeimDate // Day value of the date that the user interacted with
|
let dateToParse: RPGDate // Day value of the date that the user interacted with
|
||||||
|
|
||||||
if (initialIsEnd && event.endDate) {
|
if (initialIsEnd && event.endDate) {
|
||||||
dateToParse = event.endDate
|
dateToParse = event.endDate
|
||||||
@@ -132,9 +121,9 @@ export const useCalendarEvents = defineStore('calendar-events', () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function getRelativeEventFromDate(
|
function getRelativeEventFromDate(
|
||||||
date: LeimDate,
|
date: RPGDate,
|
||||||
position: 'next' | 'prev' = 'next'
|
position: 'next' | 'prev' = 'next'
|
||||||
): { event: CalendarEvent; targetDate: LeimDate } {
|
): { event: CalendarEvent; targetDate: RPGDate } {
|
||||||
const pivotValue = convertDateToDays(date)
|
const pivotValue = convertDateToDays(date)
|
||||||
let t: { eventData: CalendarEvent; distance: number; targetKey: 'startDate' | 'endDate' }[] = []
|
let t: { eventData: CalendarEvent; distance: number; targetKey: 'startDate' | 'endDate' }[] = []
|
||||||
|
|
||||||
@@ -210,5 +199,5 @@ export const useCalendarEvents = defineStore('calendar-events', () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return { allEvents, eventsAreLoading, eventsLoaded, currentEvents, fetchEvents, getRelativeEventFromDate, getRelativeEventFromEvent }
|
return { allEvents, setEvents, currentEvents, getRelativeEventFromDate, getRelativeEventFromEvent }
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -4,9 +4,11 @@
|
|||||||
|
|
||||||
-- Custom types
|
-- Custom types
|
||||||
create type public.app_permission as enum ('events.see.hidden', 'users.ban');
|
create type public.app_permission as enum ('events.see.hidden', 'users.ban');
|
||||||
create type public.app_role as enum ('sa', 'gm');
|
create type public.app_role as enum ('sa', 'admin', 'moderator', 'user');
|
||||||
|
create type public.app_colors as enum ('red', 'orange', 'amber', 'yellow', 'lime', 'green', 'emerald', 'teal', 'cyan', 'sky', 'blue', 'indigo', 'violet', 'purple', 'fuchsia', 'pink', 'rose', 'black', 'white');
|
||||||
|
|
||||||
-- USERS
|
-- DATA STRUCTURES
|
||||||
|
-- Users
|
||||||
create table public.users (
|
create table public.users (
|
||||||
id uuid references auth.users not null primary key, -- UUID from auth.users
|
id uuid references auth.users not null primary key, -- UUID from auth.users
|
||||||
username text
|
username text
|
||||||
@@ -14,16 +16,16 @@ create table public.users (
|
|||||||
comment on table public.users is 'Profile data for each user.';
|
comment on table public.users is 'Profile data for each user.';
|
||||||
comment on column public.users.id is 'References the internal Supabase Auth user.';
|
comment on column public.users.id is 'References the internal Supabase Auth user.';
|
||||||
|
|
||||||
-- USER ROLES
|
-- Roles
|
||||||
create table public.user_roles (
|
create table public.user_roles (
|
||||||
id bigint generated by default as identity primary key,
|
id bigint generated by default as identity primary key,
|
||||||
user_id uuid references public.users on delete cascade not null,
|
|
||||||
role app_role not null,
|
role app_role not null,
|
||||||
|
user_id uuid references public.users on delete cascade not null,
|
||||||
unique (user_id, role)
|
unique (user_id, role)
|
||||||
);
|
);
|
||||||
comment on table public.user_roles is 'Application roles for each user.';
|
comment on table public.user_roles is 'Application roles for each user.';
|
||||||
|
|
||||||
-- ROLE PERMISSIONS
|
-- Permissions
|
||||||
create table public.role_permissions (
|
create table public.role_permissions (
|
||||||
id bigint generated by default as identity primary key,
|
id bigint generated by default as identity primary key,
|
||||||
role app_role not null,
|
role app_role not null,
|
||||||
@@ -32,6 +34,96 @@ create table public.role_permissions (
|
|||||||
);
|
);
|
||||||
comment on table public.role_permissions is 'Application permissions for each role.';
|
comment on table public.role_permissions is 'Application permissions for each role.';
|
||||||
|
|
||||||
|
-- Worlds
|
||||||
|
create table public.worlds (
|
||||||
|
id bigint generated by default as identity primary key,
|
||||||
|
name text not null,
|
||||||
|
description text,
|
||||||
|
color app_colors,
|
||||||
|
gm_id uuid references public.users on delete cascade
|
||||||
|
);
|
||||||
|
comment on table public.worlds is 'Worlds belonging to a single user ; a game master.';
|
||||||
|
|
||||||
|
-- World Calendars
|
||||||
|
create table public.calendars (
|
||||||
|
id bigint generated by default as identity primary key,
|
||||||
|
name text not null,
|
||||||
|
today json not null,
|
||||||
|
world_id bigint references public.worlds on delete cascade not null
|
||||||
|
);
|
||||||
|
comment on table public.calendars is 'Calendar settings and configuration attached to a single world.';
|
||||||
|
|
||||||
|
-- Calendar Months
|
||||||
|
create table public.calendar_months (
|
||||||
|
id bigint generated by default as identity primary key,
|
||||||
|
name text not null,
|
||||||
|
days int not null,
|
||||||
|
position int not null,
|
||||||
|
calendar_id bigint references public.calendars on delete cascade not null
|
||||||
|
);
|
||||||
|
comment on table public.calendar_months is 'A calendar month.';
|
||||||
|
|
||||||
|
-- Event categories
|
||||||
|
create table public.calendar_event_categories (
|
||||||
|
id bigint generated by default as identity primary key,
|
||||||
|
name text not null,
|
||||||
|
unique (name)
|
||||||
|
);
|
||||||
|
comment on table public.calendar_event_categories is 'Categories describing events.';
|
||||||
|
|
||||||
|
-- Events
|
||||||
|
create table public.calendar_events (
|
||||||
|
id bigint generated by default as identity primary key,
|
||||||
|
title text not null,
|
||||||
|
description text,
|
||||||
|
start_date json not null,
|
||||||
|
end_date json,
|
||||||
|
category bigint references public.calendar_event_categories on delete cascade,
|
||||||
|
hidden boolean,
|
||||||
|
wiki text,
|
||||||
|
calendar_id bigint references public.calendars on delete cascade not null
|
||||||
|
);
|
||||||
|
comment on table public.calendar_events is 'Events linked to a world';
|
||||||
|
|
||||||
|
-- Link table for events - categories
|
||||||
|
create table public.calendar_event_categories_links (
|
||||||
|
calendar_event_id bigint references public.calendar_events on delete cascade,
|
||||||
|
calendar_event_category_id bigint references public.calendar_event_categories on delete cascade,
|
||||||
|
primary key (calendar_event_id, calendar_event_category_id)
|
||||||
|
);
|
||||||
|
comment on table public.calendar_event_categories_links is 'Link tables for multiple event categories.';
|
||||||
|
|
||||||
|
-- Character categories
|
||||||
|
create table public.character_categories (
|
||||||
|
id bigint generated by default as identity primary key,
|
||||||
|
name text not null,
|
||||||
|
unique (name)
|
||||||
|
);
|
||||||
|
comment on table public.character_categories is 'Categories describing characters';
|
||||||
|
|
||||||
|
-- Characters
|
||||||
|
create table public.characters (
|
||||||
|
id bigint generated by default as identity primary key,
|
||||||
|
name text not null,
|
||||||
|
description text,
|
||||||
|
birth json not null,
|
||||||
|
death json,
|
||||||
|
category bigint references public.character_categories on delete cascade,
|
||||||
|
hidden_birth boolean,
|
||||||
|
hidden_death boolean,
|
||||||
|
wiki text,
|
||||||
|
world_id bigint references public.worlds on delete cascade not null
|
||||||
|
);
|
||||||
|
comment on table public.characters is 'Characters linked to a world';
|
||||||
|
|
||||||
|
-- Link table for events - categories
|
||||||
|
create table public.character_categories_links (
|
||||||
|
character_id bigint references public.characters on delete cascade,
|
||||||
|
character_category_id bigint references public.character_categories on delete cascade,
|
||||||
|
primary key (character_id, character_category_id)
|
||||||
|
);
|
||||||
|
comment on table public.character_categories_links is 'Link tables for multiple character categories.';
|
||||||
|
|
||||||
-- authorize with role-based access control (RBAC)
|
-- authorize with role-based access control (RBAC)
|
||||||
create function public.authorize(
|
create function public.authorize(
|
||||||
requested_permission app_permission
|
requested_permission app_permission
|
||||||
@@ -54,11 +146,114 @@ $$ language plpgsql security definer set search_path = public;
|
|||||||
alter table public.users enable row level security;
|
alter table public.users enable row level security;
|
||||||
alter table public.user_roles enable row level security;
|
alter table public.user_roles enable row level security;
|
||||||
alter table public.role_permissions enable row level security;
|
alter table public.role_permissions enable row level security;
|
||||||
|
alter table public.worlds enable row level security;
|
||||||
|
alter table public.character_categories enable row level security;
|
||||||
|
alter table public.character_categories_links enable row level security;
|
||||||
|
alter table public.characters enable row level security;
|
||||||
|
alter table public.calendars enable row level security;
|
||||||
|
alter table public.calendar_months enable row level security;
|
||||||
|
alter table public.calendar_events enable row level security;
|
||||||
|
alter table public.calendar_event_categories enable row level security;
|
||||||
|
alter table public.calendar_event_categories_links enable row level security;
|
||||||
|
|
||||||
|
-- User policies
|
||||||
create policy "Allow logged-in read access" on public.users for select using ( auth.role() = 'authenticated' );
|
create policy "Allow logged-in read access" on public.users for select using ( auth.role() = 'authenticated' );
|
||||||
create policy "Allow individual insert access" on public.users for insert with check ( auth.uid() = id );
|
create policy "Allow individual insert access" on public.users for insert with check ( auth.uid() = id );
|
||||||
create policy "Allow individual update access" on public.users for update using ( auth.uid() = id );
|
create policy "Allow individual update access" on public.users for update using ( auth.uid() = id );
|
||||||
create policy "Allow individual read access" on public.user_roles for select using ( auth.uid() = user_id );
|
create policy "Allow individual read access" on public.user_roles for select using ( auth.uid() = user_id );
|
||||||
|
|
||||||
|
-- World policies
|
||||||
|
create policy "Allow individual read access for GMs" on public.worlds for select using ( ( auth.uid() = gm_id ) );
|
||||||
|
create policy "Allow individual insert access for GMs" on public.worlds for insert with check ( auth.uid() = gm_id );
|
||||||
|
create policy "Allow individual update access for GMs" on public.worlds for update using ( auth.uid() = gm_id );
|
||||||
|
|
||||||
|
-- Calendar policies
|
||||||
|
create policy "Allow individual read access for GMs" on public.calendars for select using (
|
||||||
|
exists (
|
||||||
|
select 1 from worlds
|
||||||
|
where worlds.id = calendars.world_id
|
||||||
|
)
|
||||||
|
);
|
||||||
|
create policy "Allow individual insert access for GMs" on public.calendars for insert with check (
|
||||||
|
exists (
|
||||||
|
select 1 from worlds
|
||||||
|
where worlds.id = calendars.world_id
|
||||||
|
)
|
||||||
|
);
|
||||||
|
create policy "Allow individual update access for GMs" on public.calendars for update with check (
|
||||||
|
exists (
|
||||||
|
select 1 from worlds
|
||||||
|
where worlds.id = calendars.world_id
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
-- Month policies
|
||||||
|
create policy "Allow individual read access for GMs" on public.calendar_months for select using (
|
||||||
|
exists (
|
||||||
|
select 1 from calendars
|
||||||
|
where calendars.id = calendar_months.calendar_id
|
||||||
|
)
|
||||||
|
);
|
||||||
|
create policy "Allow individual insert access for GMs" on public.calendar_months for insert with check (
|
||||||
|
exists (
|
||||||
|
select 1 from calendars
|
||||||
|
where calendars.id = calendar_months.calendar_id
|
||||||
|
)
|
||||||
|
);
|
||||||
|
create policy "Allow individual update access for GMs" on public.calendar_months for update with check (
|
||||||
|
exists (
|
||||||
|
select 1 from calendars
|
||||||
|
where calendars.id = calendar_months.calendar_id
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
-- Event policies
|
||||||
|
create policy "Allow individual read access for GMs" on public.calendar_events for select using (
|
||||||
|
exists (
|
||||||
|
select 1 from calendars
|
||||||
|
where calendars.id = calendar_events.calendar_id
|
||||||
|
)
|
||||||
|
);
|
||||||
|
create policy "Allow individual insert access for GMs" on public.calendar_events for insert with check (
|
||||||
|
exists (
|
||||||
|
select 1 from calendars
|
||||||
|
where calendars.id = calendar_events.calendar_id
|
||||||
|
)
|
||||||
|
);
|
||||||
|
create policy "Allow individual update access for GMs" on public.calendar_events for update with check (
|
||||||
|
exists (
|
||||||
|
select 1 from calendars
|
||||||
|
where calendars.id = calendar_events.calendar_id
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
-- Character policies
|
||||||
|
create policy "Allow individual read access for GMs" on public.characters for select using (
|
||||||
|
exists (
|
||||||
|
select 1 from worlds
|
||||||
|
where worlds.id = characters.world_id
|
||||||
|
)
|
||||||
|
);
|
||||||
|
create policy "Allow individual insert access for GMs" on public.characters for insert with check (
|
||||||
|
exists (
|
||||||
|
select 1 from worlds
|
||||||
|
where worlds.id = characters.world_id
|
||||||
|
)
|
||||||
|
);
|
||||||
|
create policy "Allow individual update access for GMs" on public.characters for update with check (
|
||||||
|
exists (
|
||||||
|
select 1 from worlds
|
||||||
|
where worlds.id = characters.world_id
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
-- Categories are public to view but not to insert
|
||||||
|
-- Needs to be refactored maybe, if in the future we want a default set AND user defined ones
|
||||||
|
create policy "Allow logged-in read access" on public.calendar_event_categories for select using ( auth.role() = 'authenticated' );
|
||||||
|
create policy "Allow logged-in read access" on public.calendar_event_categories_links for select using ( auth.role() = 'authenticated' );
|
||||||
|
create policy "Allow logged-in read access" on public.character_categories for select using ( auth.role() = 'authenticated' );
|
||||||
|
create policy "Allow logged-in read access" on public.character_categories_links for select using ( auth.role() = 'authenticated' );
|
||||||
|
|
||||||
-- Send "previous data" on change
|
-- Send "previous data" on change
|
||||||
alter table public.users replica identity full;
|
alter table public.users replica identity full;
|
||||||
|
|
||||||
@@ -69,6 +264,8 @@ declare is_admin boolean;
|
|||||||
begin
|
begin
|
||||||
insert into public.users (id, username)
|
insert into public.users (id, username)
|
||||||
values (new.id, new.email);
|
values (new.id, new.email);
|
||||||
|
insert into public.user_roles (role, user_id)
|
||||||
|
values ('user', new.id);
|
||||||
|
|
||||||
return new;
|
return new;
|
||||||
end;
|
end;
|
||||||
|
|||||||
@@ -1,4 +1,301 @@
|
|||||||
insert into public.role_permissions (role, permission) values ('gm', 'events.see.hidden');
|
|
||||||
|
|
||||||
insert into public.role_permissions (role, permission) values ('sa', 'events.see.hidden');
|
insert into public.role_permissions (role, permission) values ('sa', 'events.see.hidden');
|
||||||
insert into public.role_permissions (role, permission) values ('sa', 'users.ban');
|
insert into public.role_permissions (role, permission) values ('sa', 'users.ban');
|
||||||
|
|
||||||
|
-- Event categories
|
||||||
|
insert into public.calendar_event_categories (name) values ('naissance');
|
||||||
|
insert into public.calendar_event_categories (name) values ('mort');
|
||||||
|
insert into public.calendar_event_categories (name) values ('catastrophe');
|
||||||
|
insert into public.calendar_event_categories (name) values ('catastrophe naturelle');
|
||||||
|
insert into public.calendar_event_categories (name) values ('inauguration');
|
||||||
|
insert into public.calendar_event_categories (name) values ('religion');
|
||||||
|
insert into public.calendar_event_categories (name) values ('invention');
|
||||||
|
insert into public.calendar_event_categories (name) values ('science');
|
||||||
|
insert into public.calendar_event_categories (name) values ('bénédiction');
|
||||||
|
insert into public.calendar_event_categories (name) values ('joueurs');
|
||||||
|
insert into public.calendar_event_categories (name) values ('découverte');
|
||||||
|
insert into public.calendar_event_categories (name) values ('exploration');
|
||||||
|
insert into public.calendar_event_categories (name) values ('construction');
|
||||||
|
insert into public.calendar_event_categories (name) values ('arcanologie');
|
||||||
|
insert into public.calendar_event_categories (name) values ('criminalité');
|
||||||
|
insert into public.calendar_event_categories (name) values ('scandale');
|
||||||
|
insert into public.calendar_event_categories (name) values ('commerce');
|
||||||
|
insert into public.calendar_event_categories (name) values ('législation');
|
||||||
|
|
||||||
|
-- Character categories
|
||||||
|
insert into public.character_categories (name) values ('joueur');
|
||||||
|
insert into public.character_categories (name) values ('comte');
|
||||||
|
insert into public.character_categories (name) values ('scientifique');
|
||||||
|
insert into public.character_categories (name) values ('mage');
|
||||||
|
insert into public.character_categories (name) values ('professeur');
|
||||||
|
insert into public.character_categories (name) values ('criminel');
|
||||||
|
insert into public.character_categories (name) values ('étincelle');
|
||||||
|
insert into public.character_categories (name) values ('buse blanche');
|
||||||
|
insert into public.character_categories (name) values ('ecclésiastique');
|
||||||
|
insert into public.character_categories (name) values ('militaire');
|
||||||
|
insert into public.character_categories (name) values ('activiste');
|
||||||
|
insert into public.character_categories (name) values ('commerçant');
|
||||||
|
|
||||||
|
-- Worlds
|
||||||
|
insert into public.worlds (name, description, color) values ('Léïm', 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis aliquet congue aliquet. Curabitur eu iaculis diam. Nunc iaculis nibh orci, eu semper nunc congue congue. Praesent euismod tortor eget metus tristique lobortis vel in risus. In volutpat ligula orci, id pharetra lectus egestas at.', 'black');
|
||||||
|
|
||||||
|
-- Worlds' calendars
|
||||||
|
insert into public.calendars (world_id, name, today) values (1, 'Calendrier solaire', '{ "day": 23, "month": 8, "year": 3209 }');
|
||||||
|
|
||||||
|
-- Calendar's months
|
||||||
|
insert into public.calendar_months (calendar_id, name, days, position) values (1, 'Jalen', 32, 1);
|
||||||
|
insert into public.calendar_months (calendar_id, name, days, position) values (1, 'Malsen', 32, 2);
|
||||||
|
insert into public.calendar_months (calendar_id, name, days, position) values (1, 'Verlys', 32, 3);
|
||||||
|
insert into public.calendar_months (calendar_id, name, days, position) values (1, 'Nalys', 32, 4);
|
||||||
|
insert into public.calendar_months (calendar_id, name, days, position) values (1, 'Verdore', 32, 5);
|
||||||
|
insert into public.calendar_months (calendar_id, name, days, position) values (1, 'Sidore', 32, 6);
|
||||||
|
insert into public.calendar_months (calendar_id, name, days, position) values (1, 'Lyllion', 32, 7);
|
||||||
|
insert into public.calendar_months (calendar_id, name, days, position) values (1, 'Rion', 32, 8);
|
||||||
|
insert into public.calendar_months (calendar_id, name, days, position) values (1, 'Farene', 32, 9);
|
||||||
|
insert into public.calendar_months (calendar_id, name, days, position) values (1, 'Dalvene', 32, 10);
|
||||||
|
|
||||||
|
-- Events
|
||||||
|
insert into public.calendar_events (title, description, start_date, category, hidden, wiki, calendar_id) values (
|
||||||
|
'Laurdieu devient la première cité de l''empire de Kaliatos',
|
||||||
|
'L''empire de Kaliatos établi sa capitale dans la cité de Laurdieu, qui connaitra une prospérité nouvelle au sein d''Aldys.',
|
||||||
|
'{ "day": 3, "month": 4, "year": -1932 }',
|
||||||
|
18,
|
||||||
|
true,
|
||||||
|
'https://alexcreates.fr/leim/index.php/Laurdieu',
|
||||||
|
1
|
||||||
|
);
|
||||||
|
insert into public.calendar_events (title, description, start_date, category, hidden, wiki, calendar_id) values (
|
||||||
|
'Apparition d''Asménys',
|
||||||
|
'La défunte chanteuse Asménys apparaît à un barde pendant son jeune public, démarrant la religion des Prêtresses d''Asménys.',
|
||||||
|
'{ "day": 19, "month": 7, "year": -1358 }',
|
||||||
|
6,
|
||||||
|
true,
|
||||||
|
'https://alexcreates.fr/leim/index.php/Pr%C3%AAtresses_d%27Asm%C3%A9nys',
|
||||||
|
1
|
||||||
|
);
|
||||||
|
insert into public.calendar_events (title, description, start_date, end_date, category, hidden, wiki, calendar_id) values (
|
||||||
|
'La Rupture',
|
||||||
|
'Les Abysses se déversent à la surface de Léim, à travers plusieurs brèches. Plusieurs hordes de démons se rapprochent des villes, et ce qu''on appellera l''Âge des Abysses commencent alors sur la planète entière.',
|
||||||
|
'{ "day": 26, "month": 5, "year": -756 }',
|
||||||
|
'{ "day": 4, "month": 9, "year": 29 }',
|
||||||
|
3,
|
||||||
|
true,
|
||||||
|
'https://alexcreates.fr/leim/index.php/Seconde_Rupture',
|
||||||
|
1
|
||||||
|
);
|
||||||
|
insert into public.calendar_events (title, description, start_date, end_date, category, hidden, wiki, calendar_id) values (
|
||||||
|
'Marche du sang',
|
||||||
|
'L''empereur de Kaliatos ordonne personnellement la traque de Jorhas Kirendre pour connivence avec les démons. Plusieurs bataillons sont affectés à la chasse de Jorhas, qui se terminera par son incarcération ainsi que la mort de plusieurs centaines de soldats.',
|
||||||
|
'{ "day": 18, "month": 9, "year": -420 }',
|
||||||
|
'{ "day": 27, "month": 1, "year": -419 }',
|
||||||
|
15,
|
||||||
|
true,
|
||||||
|
'https://alexcreates.fr/leim/index.php/Jorhas_Kirendre',
|
||||||
|
1
|
||||||
|
);
|
||||||
|
insert into public.calendar_events (title, description, start_date, category, hidden, wiki, calendar_id) values (
|
||||||
|
'Exécution de Tyhos',
|
||||||
|
'Le léviathan Tyhos rend l''âme après un combat de plusieurs années contre Lystos, le dieu du Soleil.',
|
||||||
|
'{ "day": 1, "month": 0, "year": 0 }',
|
||||||
|
9,
|
||||||
|
true,
|
||||||
|
'https://alexcreates.fr/leim/index.php/Tyhos',
|
||||||
|
1
|
||||||
|
);
|
||||||
|
insert into public.calendar_events (title, start_date, category, wiki, calendar_id) values (
|
||||||
|
'Traité de Kadel',
|
||||||
|
'{ "day": 29, "month": 4, "year": 100 }',
|
||||||
|
5,
|
||||||
|
'https://alexcreates.fr/leim/index.php/Alliance_Kald%C3%A9lienne#Trait%C3%A9_de_Kadel',
|
||||||
|
1
|
||||||
|
);
|
||||||
|
insert into public.calendar_events (title, description, start_date, category, hidden, wiki, calendar_id) values (
|
||||||
|
'Découverte des Plaines de Poussières',
|
||||||
|
'Les troupes de la reconquête aldienne explorent le littoral d''une immense étendue grise et inerte.',
|
||||||
|
'{ "day": 17, "month": 7, "year": 305 }',
|
||||||
|
11,
|
||||||
|
true,
|
||||||
|
'https://alexcreates.fr/leim/index.php/Plaines_de_poussi%C3%A8re',
|
||||||
|
1
|
||||||
|
);
|
||||||
|
insert into public.calendar_events (title, description, start_date, end_date, category, hidden, wiki, calendar_id) values (
|
||||||
|
'Construction du Rempart de Laurdieu',
|
||||||
|
'Le Grand Conseil Kaldélien ordonne la construction d''une muraille autour des Plaines de Poussières, afin de contenir les démons y sortant.',
|
||||||
|
'{ "day": 30, "month": 2, "year": 340 }',
|
||||||
|
'{ "day": 27, "month": 9, "year": 355 }',
|
||||||
|
13,
|
||||||
|
true,
|
||||||
|
'https://alexcreates.fr/leim/index.php/Plaines_de_poussi%C3%A8re',
|
||||||
|
1
|
||||||
|
);
|
||||||
|
insert into public.calendar_events (title, description, start_date, end_date, category, hidden, wiki, calendar_id) values (
|
||||||
|
'Inauguration de l''Académie Artistique Arcanique',
|
||||||
|
'Scäd Sceni ouvre son institut artistique dédié à l''apprentissage des arts arcaniques.',
|
||||||
|
'{ "day": 11, "month": 6, "year": 2545 }',
|
||||||
|
null,
|
||||||
|
5,
|
||||||
|
false,
|
||||||
|
'https://alexcreates.fr/leim/index.php/Acad%C3%A9mie_Artistique_Arcanique',
|
||||||
|
1
|
||||||
|
);
|
||||||
|
insert into public.calendar_events (title, description, start_date, end_date, category, hidden, wiki, calendar_id) values (
|
||||||
|
'Création de la buse kaldélienne',
|
||||||
|
'Sophia de Rougefer invente la buse kaldélienne, une arme à feu souple à deux canons.',
|
||||||
|
'{ "day": 4, "month": 2, "year": 3113 }',
|
||||||
|
null,
|
||||||
|
7,
|
||||||
|
false,
|
||||||
|
'https://alexcreates.fr/leim/index.php/Buse_(arme)',
|
||||||
|
1
|
||||||
|
);
|
||||||
|
insert into public.calendar_events (title, description, start_date, end_date, category, hidden, wiki, calendar_id) values (
|
||||||
|
'Feux dans les champs de Bamast',
|
||||||
|
'Plusieurs incendies criminels se propagent à travers les champs de sérille des fermiers des littoraux de Bamast. Aucun suspect ni coupable ne sera trouvé et l''enquête sera baclée.',
|
||||||
|
'{ "day": 9, "month": 5, "year": 3200 }',
|
||||||
|
null,
|
||||||
|
15,
|
||||||
|
false,
|
||||||
|
'https://alexcreates.fr/leim/index.php/Vascylly',
|
||||||
|
1
|
||||||
|
);
|
||||||
|
insert into public.calendar_events (title, description, start_date, end_date, category, hidden, wiki, calendar_id) values (
|
||||||
|
'Meurtre de Darléon Typhos',
|
||||||
|
'Darléon Typhos surprend Vascylly fouillant sa demeure peu après la tombée de la nuit. Le majordome de la famille Typhos découvre le corps sans vie de son maître le lendemain.',
|
||||||
|
'{ "day": 21, "month": 6, "year": 3200 }',
|
||||||
|
null,
|
||||||
|
15,
|
||||||
|
false,
|
||||||
|
'https://alexcreates.fr/leim/index.php/Vascylly',
|
||||||
|
1
|
||||||
|
);
|
||||||
|
insert into public.calendar_events (title, description, start_date, end_date, category, hidden, wiki, calendar_id) values (
|
||||||
|
'Scandale Rodhus',
|
||||||
|
'Tivian Rodhus, un professeur estimé de l''Académie Centrale Kaldélienne, est emprisonné pour corruption et aggression sexuelle. Le corps enseignant y est remanié sur ordre de Lazarus Tymos, comte de Nacride.',
|
||||||
|
'{ "day": 25, "month": 9, "year": 3208 }',
|
||||||
|
null,
|
||||||
|
15,
|
||||||
|
false,
|
||||||
|
'https://alexcreates.fr/leim/index.php/Tivian_Rodhus',
|
||||||
|
1
|
||||||
|
);
|
||||||
|
|
||||||
|
insert into public.calendar_events (title, description, start_date, end_date, category, hidden, wiki, calendar_id) values (
|
||||||
|
'Arrivée d''aventuriers à Borélis',
|
||||||
|
'Tara Belyus, Vascylly et Adol Sulvan livrent 3 condamnés à Handany. Ils partent pour la mer durant la journée.',
|
||||||
|
'{ "day": 12, "month": 7, "year": 3209 }',
|
||||||
|
null,
|
||||||
|
10,
|
||||||
|
false,
|
||||||
|
null,
|
||||||
|
1
|
||||||
|
);
|
||||||
|
insert into public.calendar_events (title, description, start_date, end_date, category, hidden, wiki, calendar_id) values (
|
||||||
|
'Naufrage de l''Éclipse',
|
||||||
|
'L''Éclipse, le navire de la garde contenant des condamnés à destination des Cages Handaniennes, s''échoue au large des côtes montagneuses de la Lance d''Aldys.',
|
||||||
|
'{ "day": 14, "month": 7, "year": 3209 }',
|
||||||
|
null,
|
||||||
|
3,
|
||||||
|
false,
|
||||||
|
null,
|
||||||
|
1
|
||||||
|
);
|
||||||
|
insert into public.calendar_events (title, description, start_date, end_date, category, hidden, wiki, calendar_id) values (
|
||||||
|
'Emprisonnement de Tivian Rodhus',
|
||||||
|
'Celui qu''on surnomme la Bête d''Ambrose arrive à Handany, où il purgera sa peine.',
|
||||||
|
'{ "day": 14, "month": 7, "year": 3209 }',
|
||||||
|
null,
|
||||||
|
18,
|
||||||
|
false,
|
||||||
|
'https://alexcreates.fr/leim/index.php/Tivian_Rodhus',
|
||||||
|
1
|
||||||
|
);
|
||||||
|
insert into public.calendar_events (title, description, start_date, end_date, category, hidden, wiki, calendar_id) values (
|
||||||
|
'Sulvan et Anastael atteignent Bamast',
|
||||||
|
null,
|
||||||
|
'{ "day": 19, "month": 2, "year": 3210 }',
|
||||||
|
null,
|
||||||
|
10,
|
||||||
|
false,
|
||||||
|
null,
|
||||||
|
1
|
||||||
|
);
|
||||||
|
insert into public.calendar_events (title, description, start_date, end_date, category, hidden, wiki, calendar_id) values (
|
||||||
|
'Jugement de Bormis Griloup',
|
||||||
|
'Bormis Griloup est jugé coupable d''escroquerie et sabotage aux Cours d''Acier de Tourgrise. Il purgera une peine de 10 ans au sein des prisons royales.',
|
||||||
|
'{ "day": 4, "month": 8, "year": 3209 }',
|
||||||
|
null,
|
||||||
|
18,
|
||||||
|
false,
|
||||||
|
null,
|
||||||
|
1
|
||||||
|
);
|
||||||
|
|
||||||
|
insert into public.calendar_events (title, description, start_date, end_date, category, hidden, wiki, calendar_id) values (
|
||||||
|
'Inauguration de la Cloche du Pilier',
|
||||||
|
'Le Moine Premier inaugure la grande cloche d''argent au sommet du Pilier d''Ikami.',
|
||||||
|
'{ "day": 29, "month": 5, "year": 3209 }',
|
||||||
|
null,
|
||||||
|
6,
|
||||||
|
false,
|
||||||
|
null,
|
||||||
|
1
|
||||||
|
);
|
||||||
|
insert into public.calendar_events (title, description, start_date, end_date, category, hidden, wiki, calendar_id) values (
|
||||||
|
'1ère disparation à Cantane',
|
||||||
|
'Taleb Vaht décède dans une grotte à la suite d''une attaque d''ischiels enragées.',
|
||||||
|
'{ "day": 28, "month": 7, "year": 3209 }',
|
||||||
|
null,
|
||||||
|
2,
|
||||||
|
true,
|
||||||
|
null,
|
||||||
|
1
|
||||||
|
);
|
||||||
|
insert into public.calendar_events (title, description, start_date, end_date, category, hidden, wiki, calendar_id) values (
|
||||||
|
'2ème disparation à Cantane',
|
||||||
|
'Donovane le mineur kéturien disparait sans laisser de traces.',
|
||||||
|
'{ "day": 32, "month": 7, "year": 3209 }',
|
||||||
|
null,
|
||||||
|
2,
|
||||||
|
true,
|
||||||
|
null,
|
||||||
|
1
|
||||||
|
);
|
||||||
|
insert into public.calendar_events (title, description, start_date, end_date, category, hidden, wiki, calendar_id) values (
|
||||||
|
'3ème disparation à Cantane',
|
||||||
|
'Disparition de Sébastien, gredin sauride.',
|
||||||
|
'{ "day": 10, "month": 8, "year": 3209 }',
|
||||||
|
null,
|
||||||
|
2,
|
||||||
|
true,
|
||||||
|
null,
|
||||||
|
1
|
||||||
|
);
|
||||||
|
insert into public.calendar_events (title, description, start_date, end_date, category, hidden, wiki, calendar_id) values (
|
||||||
|
'4ème disparation à Cantane',
|
||||||
|
'Disparition de Thérence, patrouilleur sauride de la Vieille Garde.',
|
||||||
|
'{ "day": 19, "month": 8, "year": 3209 }',
|
||||||
|
null,
|
||||||
|
2,
|
||||||
|
true,
|
||||||
|
null,
|
||||||
|
1
|
||||||
|
);
|
||||||
|
insert into public.calendar_events (title, description, start_date, end_date, category, hidden, wiki, calendar_id) values (
|
||||||
|
'5ème disparation à Cantane',
|
||||||
|
'Disparition de Mathilda Boulais, vendeuse de pierres.',
|
||||||
|
'{ "day": 22, "month": 8, "year": 3209 }',
|
||||||
|
null,
|
||||||
|
2,
|
||||||
|
true,
|
||||||
|
null,
|
||||||
|
1
|
||||||
|
);
|
||||||
|
insert into public.calendar_events (title, description, start_date, end_date, category, hidden, wiki, calendar_id) values (
|
||||||
|
'Grande Banque Minérale de Cantane',
|
||||||
|
'Les artisans et mineurs de Rougefer se réunissent à Cantane pour vendre le fruit de leur dur labeur.',
|
||||||
|
'{ "day": 23, "month": 8, "year": 3209 }',
|
||||||
|
'{ "day": 26, "month": 8, "year": 3209 }',
|
||||||
|
17,
|
||||||
|
false,
|
||||||
|
null,
|
||||||
|
1
|
||||||
|
);
|
||||||
|
|||||||
Reference in New Issue
Block a user