import { defineCollection, z } from "astro:content"; import { glob } from "astro/loaders"; /** Préserve les points dans les IDs (ex: "portraits.en.json" → "portraits.en") */ const stripExtension = (ext: string) => ({ generateId: ({ entry }: { entry: string }) => entry.replace(new RegExp(`\\.${ext}$`), '') }); const formatDate = (date: Date, lang: string = 'fr') => { const locales: Record = { 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({ loader: glob({ pattern: "**/*.md", base: "./src/content/blog" }), 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({ loader: glob({ pattern: "**/*.md", base: "./src/content/projects", ...stripExtension('md') }), schema: z.object({ title: z.string(), description: z.string(), date: z.date(), 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'), }).transform((data) => ({ ...data, dateFormatted: formatDate(data.date, data.lang), })), }); const experiencesCollection = defineCollection({ loader: glob({ pattern: "**/*.md", base: "./src/content/experiences", ...stripExtension('md') }), schema: z.object({ role: z.string(), company: z.string(), companyUrl: z.string().url().optional(), location: z.string().optional(), startDate: z.string(), endDate: z.string().optional(), technologies: z.array(z.string()).optional(), type: z.enum(['employment', 'freelance', 'teaching', 'community', 'entrepreneurship']), featured: z.boolean().default(false), draft: z.boolean().default(false), lang: z.enum(['fr', 'en', 'ar']).default('fr'), }), }); const recommendationsCollection = defineCollection({ loader: glob({ pattern: "**/*.md", base: "./src/content/recommendations" }), schema: ({ image }) => z.object({ author: z.string(), authorRole: z.string(), company: z.string(), avatar: image().optional(), date: z.date(), relationship: z.string().optional(), lang: z.enum(['fr', 'en']).default('fr'), }), }); const talksCollection = defineCollection({ loader: glob({ pattern: "**/*.md", base: "./src/content/talks" }), 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({ loader: glob({ pattern: "**/*.md", base: "./src/content/photoBlogPosts", ...stripExtension('md') }), 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({ loader: glob({ pattern: "**/*.json", base: "./src/content/photoCategories", ...stripExtension('json') }), schema: z.object({ title: z.string(), subtitle: z.string(), order: z.number().optional(), lang: z.enum(['fr', 'en', 'ar']).default('fr'), }), }); export const collections = { blog: blogCollection, projects: projectsCollection, experiences: experiencesCollection, recommendations: recommendationsCollection, talks: talksCollection, photoBlogPosts: photoBlogPostsCollection, photoCategories: photoCategoriesCollection, };