Merge branch 'code/cleanup' into dev

This commit is contained in:
Alexis
2025-07-26 18:47:27 +02:00
42 changed files with 4076 additions and 2085 deletions

2
.gitignore vendored
View File

@@ -26,3 +26,5 @@ logs
# Supabase
.branches
.temp
.scannerwork/

View File

@@ -47,7 +47,7 @@ const { isSidebarOpened } = storeToRefs(useUiStore())
<Sidebar />
<div
class="wrapper max-h-screen transition-all"
class="wrapper max-h-screen transition-all overflow-y-auto"
>
<NuxtPage />
</div>

70
assets/_content.css Normal file
View File

@@ -0,0 +1,70 @@
.content {
> * + * {
margin-top: .5em;
@variant md {
margin-top: .75rem;
}
}
h1 {
font-size: var(--text-3xl);
font-weight: var(--font-weight-bold);
@variant md {
font-size: var(--text-4xl);
}
}
h2 {
font-size: var(--text-xl);
font-weight: var(--font-weight-bold);
@variant md {
font-size: var(--text-2xl);
}
}
h3 {
font-size: var(--text-lg);
font-weight: var(--font-weight-bold);
@variant md {
font-size: var(--text-xl);
}
}
h4 {
font-size: var(--text-md);
font-weight: var(--font-weight-bold);
@variant md {
font-size: var(--text-lg);
}
}
/* Normal link */
p a:not([class]) {
color: var(--color-sky-600);
text-underline-offset: .25rem;
&:hover {
color: var(--color-sky-500);
text-decoration: underline;
}
@variant dark {
color: var(--color-teal-500);
&:hover {
color: var(--color-teal-300);
}
}
}
ul {
list-style-type: square;
padding-inline-start: 1.5rem;
}
hr {
margin-block: 2rem;
}
}

View File

@@ -7,6 +7,8 @@
@import "./_colors.css" layer(theme);
@import "./_colors.css" layer(utilities);
@import "./_content.css";
/*
The default border color has changed to `currentcolor` in Tailwind CSS v4,
so we've added these compatibility styles to make sure everything still

View File

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

View File

@@ -13,7 +13,7 @@ const { category } = defineProps<{
}>()
const emit = defineEmits<{
(e: "on-delete-category", payload: Category): void
"on-delete-category": [payload: Category]
}>()
type RowMode = "edit" | "view"

View File

@@ -76,14 +76,6 @@ function handleClosing() {
</UiAlertDialogDescription>
<form @submit.prevent="handleAction">
<div class="grid grid-cols-2 gap-y-4">
<div class="text-red-500 ml-8">
<span class="text-sm">
<!-- {{ formErrors.message }} -->
</span>
</div>
</div>
<footer class="flex gap-2 justify-between">
<UiButton type="button" size="sm" variant="outline" @click="handleClosing">
{{ $t('ui.action.back') }}

View File

@@ -57,13 +57,11 @@ async function handleSubmit() {
}
/**
* === Watch for name changes to display above ===
* Watch for name changes to display above
*/
const emit = defineEmits<{
// eslint-disable-next-line no-unused-vars
(e: "on-changed-name", calendarName: string): void
// eslint-disable-next-line no-unused-vars
(e: "on-close"): void
"on-changed-name": [calendarName: string]
"on-close": []
}>()
/** Hook to emit a debounced event for the changed skeleton name */

View File

@@ -119,14 +119,6 @@ function handleCancel() {
</div>
</div>
<!-- <div class="col-span-2">
<div class="flex items-center gap-4">
<PhTag size="18" weight="fill" />
<CalendarInputEventCategories v-model="eventSkeleton.secondaryCategories" :placeholder="$t('entity.category.addSecondaries')" />
</div>
</div> -->
<div class="col-span-2 mb-2">
<div class="flex items-center gap-4">
<PhMapPinArea size="18" weight="fill" />

View File

@@ -53,13 +53,11 @@ async function handleSubmit() {
}
/**
* === Watch for name changes to display above ===
* Watch for name changes to display above
*/
const emit = defineEmits<{
// eslint-disable-next-line no-unused-vars
(e: "on-changed-name", calendarName: string): void
// eslint-disable-next-line no-unused-vars
(e: "on-close"): void
"on-changed-name": [calendarName: string]
"on-close": []
}>()
/** Hook to emit a debounced event for the changed skeleton name */
@@ -84,20 +82,6 @@ function handleFormCancel() {
{{ $t('entity.calendar.actionDialog.tabs.general.title') }}
</div>
</UiTabsTrigger>
<!-- <UiTabsTrigger value="months" class="font-bold">
<div class="flex items-center gap-1">
<PhCalendarDots size="18" weight="fill" />
{{ $t('entity.calendar.actionDialog.tabs.months.title') }}
</div>
</UiTabsTrigger>
<UiTabsTrigger value="today" class="font-bold">
<div class="flex items-center gap-1">
<PhAlarm size="18" weight="fill" />
{{ $t('entity.calendar.actionDialog.tabs.today.title') }}
</div>
</UiTabsTrigger> -->
</UiTabsList>
<UiTabsContent value="global" class="grid gap-4">
<input
@@ -127,12 +111,6 @@ function handleFormCancel() {
<InputColor id="new-calendar-color" v-model="calendarSkeleton.color" />
</div>
</UiTabsContent>
<!-- <UiTabsContent value="months">
<CalendarInputMonthList v-model:model-value="calendarSkeleton.months" />
</UiTabsContent>
<UiTabsContent value="today">
<CalendarInputTodaySelect v-model:model-value="calendarSkeleton.today" :available-months="calendarSkeleton.months"/>
</UiTabsContent> -->
</UiTabs>
<footer class="flex justify-end gap-2 mt-6">

View File

@@ -139,16 +139,6 @@ function handleCancel() {
</div>
</div>
<!-- <div class="col-span-2">
<div class="flex items-center gap-4">
<PhTag size="18" weight="fill" />
<div class="w-1/2">
<CalendarInputEventCategories v-model="eventSkeleton.secondaryCategories" placeholder="Ajouter des catégories secondaires" />
</div>
</div>
</div> -->
<div class="col-span-2 mb-2">
<div class="flex items-center gap-4">
<PhMapPinArea size="18" weight="fill" />

View File

@@ -35,6 +35,8 @@ const filteredCategories = computed(() =>
<UiButton
variant="outline"
role="combobox"
:aria-expanded="isPopoverOpen"
aria-controls="event-categories"
class="relative w-full max-w-full h-fit justify-between"
>
<template v-if="!model.length">
@@ -54,12 +56,13 @@ const filteredCategories = computed(() =>
</UiButton>
</UiPopoverTrigger>
<UiPopoverContent
id="event-categories"
align="start"
side="bottom"
:collision-padding="50"
class="w-fit h-[33vh] p-0"
>
<UiCommand v-model="modelBuffer" v-model:searchTerm="searchTerm" :multiple="true">
<UiCommand v-model="modelBuffer" v-model:search-term="searchTerm" :multiple="true">
<UiCommandInput :placeholder="$t('entity.category.search')" />
<UiCommandEmpty>{{ $t('entity.category.notFoundAny') }}</UiCommandEmpty>
<UiCommandList>

View File

@@ -34,6 +34,8 @@ const filteredCategories = computed(() =>
<UiButton
variant="outline"
role="combobox"
:aria-expanded="isPopoverOpen"
aria-controls="event-category"
class="w-full max-w-full justify-between"
>
<template v-if="!model">
@@ -52,6 +54,7 @@ const filteredCategories = computed(() =>
</UiButton>
</UiPopoverTrigger>
<UiPopoverContent
id="event-category"
align="start"
side="bottom"
:collision-padding="50"

View File

@@ -135,15 +135,6 @@ function handleValueReset() {
<UiInput v-model="model.year" type="number" />
<!-- <nav class="flex items-center justify-end gap-2">
<UiButton variant="outline" size="icon" class="w-8 h-8" @click="decrementModelMonth()">
<PhCaretLeft size="14" />
</UiButton>
<UiButton variant="outline" size="icon" class="w-8 h-8" @click="incrementModelMonth()">
<PhCaretRight size="14" />
</UiButton>
</nav> -->
<hr class="col-span-2" >
<div class="col-span-2">

View File

@@ -88,7 +88,7 @@ const searchResults = computed<(Character | CalendarEvent)[]>(() => {
results = dataToFilter.filter((item) => {
// Filter calendar events
if (isCalendarEvent(item)) {
const queryString = new String(searchQuery.value)
const queryString = (searchQuery.value as string)
.replace(searchUnifier, "")
.toLocaleLowerCase()
@@ -126,7 +126,7 @@ const searchResults = computed<(Character | CalendarEvent)[]>(() => {
// Filter characters
if (isCharacter(item)) {
const queryString = new String(searchQuery.value)
const queryString = (searchQuery.value as string)
.replace(searchUnifier, "")
.toLocaleLowerCase()
@@ -279,7 +279,6 @@ function handleCategoryUnselect(e: Category) {
</UiDialogDescription>
</VisuallyHidden>
<!-- UiDialog header -->
<div id="searchForm" class="grid gap-3">
<div class="relative w-full h-fit">
<UiInput
@@ -307,10 +306,6 @@ function handleCategoryUnselect(e: Category) {
<UiToggleGroupItem value="events" aria-label="Uniquement les évènements">
{{ $t('entity.calendar.event.namePlural') }}
</UiToggleGroupItem>
<!-- Not used for now -->
<!-- <UiToggleGroupItem value="characters" aria-label="Uniquement les personnages">
{{ $t('entity.character.namePlural') }}
</UiToggleGroupItem> -->
</UiToggleGroup>
</div>

View File

@@ -12,7 +12,7 @@ const props = defineProps<{
}>()
defineEmits<{
(e: "query:date-jump", payload: RPGDate): void
"query:date-jump": [payload: RPGDate]
}>()
const { getFormattedDateTitle } = useCalendar()

View File

@@ -10,7 +10,7 @@ const props = defineProps<{
}>()
defineEmits<{
(e: "query:date-jump", payload: RPGDate): void
"query:date-jump": [payload: RPGDate]
}>()
const { getRelativeString, defaultDate, getFormattedDateTitle } = useCalendar()

View File

@@ -13,7 +13,7 @@ const props = defineProps<{
}>()
const emit = defineEmits<{
(e: "on-open-create-dialog", date: RPGDate): void
"on-open-create-dialog": [date: RPGDate]
}>()
const calendarTile = ref()

View File

@@ -24,7 +24,7 @@ const moveCalendarRight = useThrottleFn(() => {
</script>
<template>
<div class="container mt-[10vh] mb-auto" @wheel="handleWheel">
<div class="container mx-auto mt-[10vh] mb-auto" @wheel="handleWheel">
<div class="grid grid-cols-5 gap-x-8 gap-y-16">
<CalendarStateYearlyMonthTile
v-for="month in months"

View File

@@ -1,5 +1,5 @@
<script lang="ts" setup>
import { PhCompass, PhGlobeHemisphereEast, PhHurricane, PhX } from "@phosphor-icons/vue"
import { PhCompass, PhGlobeHemisphereEast, PhHurricane, PhInfo, PhX } from "@phosphor-icons/vue"
import type { SidebarMenuActionType, SidebarMenuIcon } from "./SidebarProps";
import { cn } from "~/lib/utils";
import { breakpointsTailwind } from "@vueuse/core"
@@ -40,12 +40,12 @@ const breakpoints = useBreakpoints(
<nav
ref="sidebarRef"
:class="cn(
['md:relative md:isolate w-16 py-6 grid gap-4 grid-rows-[1fr_auto] justify-center transition-all'], // Base appearance
['md:relative md:isolate w-16 py-6 grid gap-4 grid-rows-[1fr_auto] justify-center md:transition-none'], // Base appearance
['after:opacity-50 after:contrast-125 dark:after:opacity-75 dark:after:contrast-175 after:-hue-rotate-60'], // After styling
['border-r-[1px] bg-indigo-700 dark:bg-black text-white border-r-indigo-700 dark:border-r-indigo-950 shadow-navbar-light dark:shadow-navbar-dark'], // Colours
['max-md:justify-stretch max-md:px-4 max-md:py-4 max-md:absolute max-md:left-0 max-md:inset-0 max-md:z-50 max-md:w-30 max-md:max-w-full'], // Responsive behaviours
['max-md:justify-stretch max-md:px-4 max-md:py-4 max-md:absolute max-md:left-0 max-md:inset-0 max-md:z-50 max-md:w-40 max-md:max-w-full max-md:transition-all'], // Responsive behaviours
{
'max-md:-translate-x-30': !isSidebarOpened,
'max-md:-translate-x-40': !isSidebarOpened,
'max-md:-translate-x-0 shadow-navbar-dark dark:bg-slate-950': isSidebarOpened
}
)"
@@ -96,6 +96,40 @@ const breakpoints = useBreakpoints(
</UiTooltipProvider>
</li>
<li class="max-md:self-start">
<UiTooltipProvider :delay-duration="50" :disabled="!breakpoints.md.value">
<UiTooltip>
<UiTooltipTrigger as-child>
<UiButton
variant="ghost"
size="icon"
class="rounded-full max-md:hidden"
as-child
>
<RouterLink to="/about">
<PhInfo size="24" weight="fill" />
</RouterLink>
</UiButton>
<RouterLink
to="/about"
class="md:hidden flex items-center gap-[.6ch] underline-offset-4 hover:underline"
>
<PhInfo size="22" weight="fill" />
<span class="text-[.9em]">
{{ $t('pages.about.menuLabel') }}
</span>
</RouterLink>
</UiTooltipTrigger>
<UiTooltipContent :side="'right'" :side-offset="6">
<p>
{{ $t('pages.about.menuLabel') }}
</p>
</UiTooltipContent>
</UiTooltip>
</UiTooltipProvider>
</li>
<ClientOnly>
<li v-for="(item, i) in currentMenu" :key="i">
<UiTooltipProvider :delay-duration="50">

View File

@@ -184,12 +184,6 @@ function pushRoute(to: AvailableRoutes) {
<UiDropdownMenuSeparator />
<template v-if="user">
<!-- <UiDropdownMenuItem class="flex gap-[.5ch] items-center rounded-none" @click="pushRoute('/my/settings')">
<PhGear size="20" weight="fill" />
<span>
{{ $t('ui.sidebarMenu.account') }}
</span>
</UiDropdownMenuItem> -->
<UiDropdownMenuItem class="flex gap-[.5ch] items-center rounded-none" @click="handleLogout">
<PhSignOut size="20" weight="fill" />
<span>

View File

@@ -10,7 +10,7 @@ const props = defineProps<{
}>()
const emits = defineEmits<{
(e: "update:modelValue", payload: string | number): void
"update:modelValue": [payload: string | number]
}>()
const modelValue = useVModel(props, "modelValue", emits, {

View File

@@ -34,5 +34,5 @@ type ToastVariants = VariantProps<typeof toastVariants>
export interface ToastProps extends ToastRootProps {
class?: HTMLAttributes["class"]
variant?: ToastVariants["variant"]
onOpenChange?: ((value: boolean) => void) | undefined
onOpenChange?: ((value: boolean) => void)
}

View File

@@ -76,14 +76,6 @@ function handleClosing() {
</UiAlertDialogDescription>
<form @submit.prevent="handleAction">
<div class="grid grid-cols-2 gap-y-4">
<div class="text-red-500 ml-8">
<span class="text-sm">
<!-- {{ formErrors.message }} -->
</span>
</div>
</div>
<footer class="flex gap-2 justify-between">
<UiButton type="button" size="sm" variant="outline" @click="handleClosing">
{{ $t('ui.action.back') }}

View File

@@ -42,10 +42,8 @@ async function handleSubmit() {
* === Watch for name changes to display above ===
*/
const emit = defineEmits<{
// eslint-disable-next-line no-unused-vars
(e: "on-changed-name", calendarName: string): void
// eslint-disable-next-line no-unused-vars
(e: "on-close"): void
"on-changed-name": [calendarName: string]
"on-close": []
}>()
/** Hook to emit a debounced event for the changed skeleton name */

View File

@@ -54,10 +54,8 @@ async function handleSubmit() {
* === Watch for name changes to display above ===
*/
const emit = defineEmits<{
// eslint-disable-next-line no-unused-vars
(e: "on-changed-name", calendarName: string): void
// eslint-disable-next-line no-unused-vars
(e: "on-close"): void
"on-changed-name": [calendarName: string]
"on-close": []
}>()
/** Hook to emit a debounced event for the changed skeleton name */

10
content.config.ts Normal file
View File

@@ -0,0 +1,10 @@
import { defineCollection, defineContentConfig } from "@nuxt/content"
export default defineContentConfig({
collections: {
sections: defineCollection({
type: "page",
source: "sections/**/*.md"
})
}
})

View File

@@ -0,0 +1,2 @@
## legal text
test

View File

@@ -0,0 +1,108 @@
## Mentions légales
### Propriétaire du site
Alexis Pelé
**Email** — contact@alexcreates.fr
**Email de support** — rpg@alexcreates.fr
### Hébergeur
Cloudflare US INC
**Adresse** — Townsend Street 101 San Francisco, Californie, États-Unis
-----
## Conditions Générales d'Utilisation
**Date d'entrée en vigueur : 5 mai 2025**
### 1. Acceptation des Conditions
En accédant à notre application de gestion d'univers de fiction (ci-après dénommée "l'Application"), vous acceptez d'être lié par les présentes Conditions Générales d'Utilisation. Si vous n'acceptez pas ces conditions, veuillez ne pas utiliser l'Application.
En utilisant notre Application, vous reconnaissez avoir lu, compris et accepté les présentes Conditions Générales d'Utilisation.
### 2. Description du Service
L'Application permet aux utilisateurs de créer, gérer et partager des calendriers et des univers de fiction. Les fonctionnalités incluent, sans s'y limiter :
- La création de comptes utilisateurs
- La conception de calendriers personnalisés
- La création et gestion d'univers de fiction
- Le partage de contenus avec d'autres utilisateurs
### 3. Inscription et Compte Utilisateur
Pour utiliser pleinement l'Application, vous devez créer un compte utilisateur. Vous vous engagez à fournir des informations exactes, complètes et à jour lors de votre inscription.
Vous êtes responsable du maintien de la confidentialité de vos identifiants de connexion et de toutes les activités qui se produisent sous votre compte. Vous devez nous informer immédiatement de toute utilisation non autorisée de votre compte.
### 4. Contenus de l'Utilisateur
#### 4.1 Propriété intellectuelle
Vous conservez tous vos droits de propriété intellectuelle sur les contenus que vous créez via l'Application. Cependant, vous nous accordez une licence mondiale, non exclusive, gratuite, transférable et pouvant faire l'objet d'une sous-licence pour utiliser, reproduire, adapter, publier et afficher ces contenus dans le cadre de la fourniture de l'Application et de ses services.
#### 4.2 Contenus prohibés
Vous vous engagez à ne pas créer ou partager de contenus qui :
- Violent les droits de propriété intellectuelle d'autrui
- Sont illégaux, diffamatoires, obscènes ou offensants
- Contiennent des virus ou autres codes malveillants
- Harcèlent, intimident ou discriminent d'autres utilisateurs
### 5. Utilisation de l'Application
#### 5.1 Utilisation autorisée
Vous vous engagez à utiliser l'Application conformément aux présentes conditions, aux lois applicables et aux bonnes pratiques en ligne.
#### 5.2 Restrictions
Il est interdit de :
- Utiliser l'Application d'une manière susceptible de l'endommager ou d'en altérer le fonctionnement
- Tenter d'accéder sans autorisation aux systèmes ou réseaux connectés à l'Application
- Utiliser l'Application pour distribuer des publicités non sollicitées ou du contenu malveillant
- Usurper l'identité d'une autre personne ou entité
### 6. Confidentialité et Données Personnelles
Le traitement de vos données personnelles est soumis à notre Politique de Confidentialité, disponible séparément. En utilisant l'Application, vous consentez à la collecte et au traitement de vos données conformément à cette politique.
### 7. Modification et Résiliation
#### 7.1 Modification du service
Nous nous réservons le droit de modifier, suspendre ou interrompre tout aspect de l'Application à tout moment, avec ou sans préavis.
#### 7.2 Résiliation
Nous pouvons résilier ou suspendre votre accès à l'Application immédiatement, sans préavis ni responsabilité, pour toute raison, y compris, sans limitation, si vous enfreignez les présentes conditions.
### 8. Limitation de Responsabilité
#### 8.1 Garantie
L'Application est fournie "telle quelle" et "selon disponibilité", sans garantie d'aucune sorte, expresse ou implicite.
#### 8.2 Responsabilité
Dans toute la mesure permise par la loi, nous déclinons toute responsabilité pour tout dommage indirect, consécutif, exemplaire, accessoire ou punitif, y compris la perte de profits, même si nous avons été avisés de la possibilité de tels dommages.
### 9. Dispositions Générales
Les présentes conditions sont régies par le droit français.
Tout litige relatif à l'interprétation, l'exécution ou la validité des présentes conditions sera soumis à la compétence exclusive des tribunaux français.
Ces conditions constituent l'intégralité de l'accord entre vous et nous concernant l'utilisation de l'Application et remplacent tous les accords antérieurs.
Si une disposition des présentes conditions est jugée invalide ou inapplicable, les autres dispositions resteront en vigueur.
Vous ne pouvez pas céder vos droits ou obligations en vertu des présentes conditions sans notre consentement écrit préalable.
Pour toute question concernant ces conditions d'utilisation, veuillez nous contacter à : rpg@alexcreates.fr
### 10. Cookies & informations personnelles
Lutilisateur est informé que lors de ses visites sur le site, un cookie peut sinstaller automatiquement sur son logiciel de navigation.
Le cookie est un bloc de données qui ne permet pas didentifier les utilisateurs mais sert à enregistrer des informations relatives à la navigation de celui-ci sur le site.
Le paramétrage du logiciel de navigation permet dinformer de la présence de cookie et éventuellement, de la refuser.
Lutilisateur dispose de lensemble des droits susvisés sagissant des données à caractère personnel communiquées par le biais des cookies dans les conditions indiquées ci-dessus.
Nous n'utilisons pas de cookie d'analyses, de tracking ou de régies publicitaires. Les cookies présents sur le site sont purement fonctionnels et ne sont pas partagés avec des tiers dans des buts commerciaux. Les cookies de l'application ne permettent pas de vous identifier.

View File

@@ -318,6 +318,11 @@ export default defineI18nConfig(() => ({
profile: {
title: "{user} — My universe",
metaTitle: "My universe",
},
about: {
title: "About this app",
metaTitle: "About this app",
menuLabel: "About",
}
},
breadcrumbs: {
@@ -647,6 +652,11 @@ export default defineI18nConfig(() => ({
profile: {
title: "{user} — Mon univers",
metaTitle: "Mon univers",
},
about: {
title: "À propos",
metaTitle: "À propos",
menuLabel: "À propos",
}
},
breadcrumbs: {

View File

@@ -12,7 +12,8 @@ export default defineNuxtConfig({
"@nuxt/eslint",
"shadcn-nuxt",
"@nuxtjs/i18n",
"@nuxthub/core"
"@nuxthub/core",
"@nuxt/content",
],
css: ["~/assets/main.css"],
@@ -48,7 +49,8 @@ export default defineNuxtConfig({
callback: "/my/",
exclude: [
"/calendars(/*)?",
"/explore(/*)?"
"/explore(/*)?",
"/about(/*)?"
]
}
},

View File

@@ -14,48 +14,50 @@
},
"dependencies": {
"@intlify/message-compiler": "^11.1.3",
"@nuxt/eslint": "^1.3.0",
"@nuxthub/core": "^0.8.24",
"@nuxtjs/i18n": "^9.5.3",
"@nuxt/content": "3.5.1",
"@nuxt/eslint": "^1.3.1",
"@nuxthub/core": "^0.8.27",
"@nuxtjs/i18n": "^9.5.4",
"@phosphor-icons/vue": "^2.2.1",
"@pinia/nuxt": "^0.11.0",
"@tailwindcss/vite": "^4.1.4",
"@tailwindcss/vite": "^4.1.6",
"@vueuse/core": "^13.1.0",
"@vueuse/integrations": "^13.1.0",
"@vueuse/nuxt": "^13.1.0",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"lucide-vue-next": "^0.503.0",
"lucide-vue-next": "^0.510.0",
"luxon": "^3.6.1",
"nuxt": "^3.16.2",
"nuxt": "^3.17.3",
"pinia": "^3.0.2",
"radix-vue": "^1.9.17",
"shadcn-nuxt": "^2.1.0",
"sortablejs": "^1.15.6",
"tailwind-merge": "^3.2.0",
"tailwind-merge": "^3.3.0",
"tailwindcss-animate": "^1.0.7",
"vue": "^3.5.13",
"vue-router": "^4.5.0",
"zod": "^3.24.3"
"vue-router": "^4.5.1",
"zod": "^3.24.4"
},
"devDependencies": {
"@nuxtjs/color-mode": "^3.5.2",
"@nuxtjs/supabase": "^1.5.0",
"@nuxtjs/tailwindcss": "^6.13.2",
"@nuxtjs/supabase": "^1.5.1",
"@nuxtjs/tailwindcss": "^6.14.0",
"@stylistic/eslint-plugin-js": "^4.2.0",
"@types/luxon": "^3.6.2",
"@typescript-eslint/eslint-plugin": "^8.31.0",
"@typescript-eslint/parser": "^8.31.0",
"eslint": "^9.25.1",
"eslint-config-prettier": "^10.1.2",
"eslint-plugin-prettier": "^5.2.6",
"eslint-plugin-vue": "^10.0.0",
"@typescript-eslint/eslint-plugin": "^8.32.1",
"@typescript-eslint/parser": "^8.32.1",
"eslint": "^9.26.0",
"eslint-config-prettier": "^10.1.5",
"eslint-plugin-prettier": "^5.4.0",
"eslint-plugin-vue": "^10.1.0",
"postcss": "^8.5.3",
"prettier": "^3.5.3",
"sass": "^1.87.0",
"tailwindcss": "^4.1.4",
"sass": "^1.88.0",
"supabase": "^2.30.4",
"tailwindcss": "^4.1.6",
"typescript": "^5.8.3",
"wrangler": "^4.12.0"
"wrangler": "^4.14.4"
},
"packageManager": "pnpm@9.1.0+sha1.217063ce3fcbf44f3051666f38b810f1ddefee4a"
"packageManager": "pnpm@10.10.0"
}

33
pages/about.vue Normal file
View File

@@ -0,0 +1,33 @@
<script lang="ts" setup>
const { locale } = useI18n()
const { data: page, refresh } = await useAsyncData(`about-content-${locale}`, () => {
return queryCollection("sections").path(`/sections/${locale.value}/legal`).first()
})
watch(locale, () => refresh())
</script>
<template>
<main class="py-8 px-5 md:px-8 overflow-y-auto">
<Head>
<Title>{{ $t("pages.about.title") }}</Title>
</Head>
<div class="container max-md:px-0">
<Spacing size="lg">
<div class="flex items-center gap-3">
<div class="md:hidden">
<SidebarToggle />
</div>
<Heading level="h1">
{{ $t("pages.about.title") }}
</Heading>
</div>
<ContentRenderer v-if="page" :value="page" class="content" />
</Spacing>
</div>
</main>
</template>

View File

@@ -17,9 +17,15 @@ const isLoading = computed(() => calendarStatus.value === "pending")
</Head>
<Spacing size="lg">
<div class="flex items-center gap-3">
<div class="md:hidden">
<SidebarToggle />
</div>
<Heading level="h1">
{{ $t("pages.explore.title") }}
</Heading>
</div>
<Spacing size="lg">
<Heading level="h2">

5657
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

10
pnpm-workspace.yaml Normal file
View File

@@ -0,0 +1,10 @@
onlyBuiltDependencies:
- '@parcel/watcher'
- '@tailwindcss/oxide'
- better-sqlite3
- esbuild
- sharp
- supabase
- unrs-resolver
- vue-demi
- workerd

View File

@@ -1,5 +1,4 @@
import { serverSupabaseClient } from "#supabase/server";
// import type { Calendar} from "~/models/CalendarConfig";
import type { Calendar} from "~/models/CalendarConfig";
import { postCalendarSchema } from "~/models/CalendarConfig";
@@ -63,7 +62,7 @@ export default defineEventHandler(async (event) => {
.insert(bodyData.months as never)
if (error) throw error
} catch (err) {
} catch {
// If we found an error, rollback the calendar
if (calendarId) {
await client
@@ -89,7 +88,7 @@ export default defineEventHandler(async (event) => {
.eq("id", calendarId)
.limit(1)
.single<Calendar>()
} catch (err) {
} catch {
throw createError({
cause: "Serveur",
fatal: false,

View File

@@ -1,5 +1,4 @@
import { serverSupabaseClient } from "#supabase/server";
// import type { Calendar} from "~/models/CalendarConfig";
import type { World } from "~/models/World";
import { postWorldSchema } from "~/models/World";
@@ -41,7 +40,7 @@ export default defineEventHandler(async (event) => {
if (error) throw error
return data
} catch (err) {
} catch {
throw createError({
cause: "Serveur",
status: 500,

View File

@@ -97,7 +97,7 @@ export const useCalendar = defineStore("calendar", () => {
/**
* Sorted month data using the raw months
*/
const sortedMonths = computed<CalendarMonth[]>(() => months.value.sort((a, b) => a.position - b.position))
const sortedMonths = computed<CalendarMonth[]>(() => months.value.toSorted((a, b) => a.position - b.position))
const monthsPerYear = computed<number>(() => months.value.length)
const daysPerYear = computed<number>(() => months.value.reduce((acc, o) => acc + o.days, 0))
@@ -520,7 +520,7 @@ export const useCalendar = defineStore("calendar", () => {
years: "xYearsAgoCompact",
yearsAndMonths: "xYearsAndMonthsAgoCompact",
}
let directionKeys: DateDirectionTranslationKeys = pastKeys
let directionKeys: DateDirectionTranslationKeys
// Check whether it's a past or future date
if (differenceInDays > 0) {
@@ -922,7 +922,6 @@ export const useCalendar = defineStore("calendar", () => {
})
}
// Watch for categories changes
watch(categories, (n) => {
updateAllEventsCategories(n)
})

View File

@@ -126,3 +126,6 @@ skip_nonce_check = false
[auth.hook.custom_access_token]
enabled = true
uri = "pg-functions://postgres/public/custom_access_token_hook"
[analytics]
enabled = false

View File

@@ -16,7 +16,6 @@ module.exports = {
theme: {
container: {
center: true,
padding: "2rem",
screens: {
"2xl": "1400px",

View File

@@ -5,7 +5,7 @@
* @returns Result of the test
*/
export function isDigit(str: string) {
return RegExp(/^\d{1}$/g).test(str)
return RegExp(/^\d$/g).test(str)
}
/**