Les images et les fichiers de contenu sont maintenant organisés par année (blog/2015/enigma/ au lieu de blog/enigma/) pour mieux s'y retrouver avec un volume croissant de posts. Le coverImage dans les frontmatters ne contient plus qu'un nom de fichier, résolu dynamiquement via import.meta.glob.
97 lines
No EOL
2.5 KiB
TypeScript
97 lines
No EOL
2.5 KiB
TypeScript
import { defineCollection, z } from "astro:content";
|
|
|
|
const formatDate = (date: Date, lang: string = 'fr') => {
|
|
const locales: Record<string, string> = { fr: 'fr-FR', en: 'en-US', ar: 'ar-SA' };
|
|
return date.toLocaleDateString(locales[lang] || 'fr-FR', {
|
|
year: 'numeric',
|
|
month: 'long',
|
|
day: 'numeric',
|
|
});
|
|
};
|
|
|
|
const blogCollection = defineCollection({
|
|
type: "content",
|
|
schema: z.object({
|
|
title: z.string(),
|
|
description: z.string(),
|
|
date: z.date(),
|
|
category: z.enum(['pro', 'comedy', 'photo']),
|
|
tags: z.array(z.string()).optional(),
|
|
image: z.string().optional(),
|
|
imageAlt: z.string().optional(),
|
|
draft: z.boolean().default(false),
|
|
lang: z.enum(['fr', 'en', 'ar']).default('fr'),
|
|
}).transform((data) => ({
|
|
...data,
|
|
dateFormatted: formatDate(data.date, data.lang),
|
|
})),
|
|
});
|
|
|
|
const projectsCollection = defineCollection({
|
|
type: "content",
|
|
schema: z.object({
|
|
title: z.string(),
|
|
description: z.string(),
|
|
date: z.date(),
|
|
dateFormatted: z.string(),
|
|
category: z.enum(['dev', 'comedy', 'photo']),
|
|
technologies: z.array(z.string()).optional(),
|
|
url: z.string().url().optional(),
|
|
github: z.string().url().optional(),
|
|
image: z.string().optional(),
|
|
imageAlt: z.string().optional(),
|
|
featured: z.boolean().default(false),
|
|
draft: z.boolean().default(false),
|
|
lang: z.enum(['fr', 'en', 'ar']).default('fr'),
|
|
}),
|
|
});
|
|
|
|
const talksCollection = defineCollection({
|
|
type: "content",
|
|
schema: z.object({
|
|
title: z.string(),
|
|
description: z.string(),
|
|
date: z.date(),
|
|
dateFormatted: z.string(),
|
|
event: z.string(),
|
|
location: z.string(),
|
|
slides: z.string().url().optional(),
|
|
video: z.string().url().optional(),
|
|
image: z.string().optional(),
|
|
imageAlt: z.string().optional(),
|
|
tags: z.array(z.string()).optional(),
|
|
draft: z.boolean().default(false),
|
|
lang: z.enum(['fr', 'en', 'ar']).default('fr'),
|
|
}),
|
|
});
|
|
|
|
const photoBlogPostsCollection = defineCollection({
|
|
type: "content",
|
|
schema: z.object({
|
|
title: z.string(),
|
|
description: z.string(),
|
|
date: z.date(),
|
|
coverImage: z.string(),
|
|
tags: z.array(z.string()).optional(),
|
|
featured: z.boolean().default(false),
|
|
draft: z.boolean().default(false),
|
|
lang: z.enum(['fr', 'en', 'ar']).default('fr'),
|
|
}),
|
|
});
|
|
|
|
const photoCategoriesCollection = defineCollection({
|
|
type: "data",
|
|
schema: z.object({
|
|
title: z.string(),
|
|
subtitle: z.string(),
|
|
order: z.number().optional(),
|
|
}),
|
|
});
|
|
|
|
export const collections = {
|
|
blog: blogCollection,
|
|
projects: projectsCollection,
|
|
talks: talksCollection,
|
|
photoBlogPosts: photoBlogPostsCollection,
|
|
photoCategories: photoCategoriesCollection,
|
|
}; |