diff --git a/src/store/cmsStore.ts b/src/store/cmsStore.ts new file mode 100644 index 0000000..a5be28f --- /dev/null +++ b/src/store/cmsStore.ts @@ -0,0 +1,251 @@ +import { create } from 'zustand' +import { persist } from 'zustand/middleware' +import { v4 as uuidv4 } from 'uuid' +import { Post, Page, GalleryImage, NavItem, SiteSettings, Category } from '@/types' + +interface CMSState { + posts: Post[] + pages: Page[] + gallery: GalleryImage[] + navItems: NavItem[] + categories: Category[] + settings: SiteSettings + + // Posts + addPost: (post: Omit) => Post + updatePost: (id: string, data: Partial) => void + deletePost: (id: string) => void + getPost: (id: string) => Post | undefined + + // Pages + addPage: (page: Omit) => Page + updatePage: (id: string, data: Partial) => void + deletePage: (id: string) => void + getPage: (id: string) => Page | undefined + + // Gallery + addImage: (image: Omit) => void + deleteImage: (id: string) => void + updateImage: (id: string, data: Partial) => void + + // Navigation + addNavItem: (item: Omit) => void + updateNavItem: (id: string, data: Partial) => void + deleteNavItem: (id: string) => void + reorderNavItems: (items: NavItem[]) => void + + // Categories + addCategory: (cat: Omit) => void + updateCategory: (id: string, data: Partial) => void + deleteCategory: (id: string) => void + + // Settings + updateSettings: (data: Partial) => void +} + +const now = () => new Date().toISOString() + +const DEMO_POSTS: Post[] = [ + { + id: '1', + title: 'Bienvenue sur mon blog', + slug: 'bienvenue-sur-mon-blog', + content: '

Bonjour tout le monde !

Ceci est mon premier article de blog. Je suis ravi de partager mes pensées et expériences avec vous.

Ce CMS vous permet de gérer facilement vos articles, pages, galerie et navigation.

', + excerpt: 'Mon premier article de blog pour inaugurer ce CMS personnel.', + status: 'published', + category: 'Général', + tags: ['bienvenue', 'premier article'], + author: 'admin', + createdAt: new Date(Date.now() - 7 * 24 * 3600 * 1000).toISOString(), + updatedAt: new Date(Date.now() - 7 * 24 * 3600 * 1000).toISOString(), + publishedAt: new Date(Date.now() - 7 * 24 * 3600 * 1000).toISOString(), + views: 142, + }, + { + id: '2', + title: 'Guide de démarrage rapide', + slug: 'guide-demarrage-rapide', + content: '

Premiers pas avec le CMS

Ce guide vous explique comment utiliser toutes les fonctionnalités du CMS.

  • Créer des articles
  • Gérer les pages
  • Organiser la galerie
  • Configurer la navigation
', + excerpt: 'Apprenez à utiliser toutes les fonctionnalités du CMS en quelques minutes.', + status: 'published', + category: 'Tutoriel', + tags: ['guide', 'démarrage', 'tutoriel'], + author: 'admin', + createdAt: new Date(Date.now() - 3 * 24 * 3600 * 1000).toISOString(), + updatedAt: new Date(Date.now() - 3 * 24 * 3600 * 1000).toISOString(), + publishedAt: new Date(Date.now() - 3 * 24 * 3600 * 1000).toISOString(), + views: 89, + }, + { + id: '3', + title: 'Article en brouillon', + slug: 'article-en-brouillon', + content: '

Cet article est en cours de rédaction...

', + excerpt: 'Un article non publié.', + status: 'draft', + category: 'Général', + tags: ['brouillon'], + author: 'editor', + createdAt: new Date(Date.now() - 1 * 24 * 3600 * 1000).toISOString(), + updatedAt: new Date(Date.now() - 1 * 24 * 3600 * 1000).toISOString(), + views: 0, + }, +] + +const DEMO_PAGES: Page[] = [ + { + id: '1', + title: 'À propos', + slug: 'a-propos', + content: '

Qui suis-je ?

Bienvenue sur ma page à propos. Je suis un développeur passionné par les nouvelles technologies.

', + status: 'published', + template: 'default', + createdAt: new Date(Date.now() - 14 * 24 * 3600 * 1000).toISOString(), + updatedAt: new Date(Date.now() - 14 * 24 * 3600 * 1000).toISOString(), + }, + { + id: '2', + title: 'Contact', + slug: 'contact', + content: '

Me contacter

N\'hésitez pas à me contacter pour toute question.

', + status: 'published', + template: 'default', + createdAt: new Date(Date.now() - 10 * 24 * 3600 * 1000).toISOString(), + updatedAt: new Date(Date.now() - 10 * 24 * 3600 * 1000).toISOString(), + }, +] + +const DEMO_NAV: NavItem[] = [ + { id: '1', label: 'Accueil', href: '/', order: 0, isExternal: false }, + { id: '2', label: 'Blog', href: '/blog', order: 1, isExternal: false }, + { id: '3', label: 'À propos', href: '/a-propos', order: 2, isExternal: false }, + { id: '4', label: 'Contact', href: '/contact', order: 3, isExternal: false }, +] + +const DEMO_CATEGORIES: Category[] = [ + { id: '1', name: 'Général', slug: 'general', color: '#6366f1' }, + { id: '2', name: 'Tutoriel', slug: 'tutoriel', color: '#10b981' }, + { id: '3', name: 'Actualité', slug: 'actualite', color: '#f59e0b' }, + { id: '4', name: 'Projet', slug: 'projet', color: '#ef4444' }, +] + +const DEFAULT_SETTINGS: SiteSettings = { + siteName: 'Mon Blog', + siteDescription: 'Un blog personnel propulsé par le CMS', + siteUrl: 'https://monblog.com', + primaryColor: '#6366f1', + postsPerPage: 10, + allowComments: true, + maintenanceMode: false, + socialLinks: { + twitter: '', + github: '', + linkedin: '', + }, +} + +export const useCMSStore = create()( + persist( + (set, get) => ({ + posts: DEMO_POSTS, + pages: DEMO_PAGES, + gallery: [], + navItems: DEMO_NAV, + categories: DEMO_CATEGORIES, + settings: DEFAULT_SETTINGS, + + // Posts + addPost: (postData) => { + const post: Post = { + ...postData, + id: uuidv4(), + createdAt: now(), + updatedAt: now(), + views: 0, + } + set((s) => ({ posts: [post, ...s.posts] })) + return post + }, + updatePost: (id, data) => + set((s) => ({ + posts: s.posts.map((p) => + p.id === id ? { ...p, ...data, updatedAt: now() } : p + ), + })), + deletePost: (id) => + set((s) => ({ posts: s.posts.filter((p) => p.id !== id) })), + getPost: (id) => get().posts.find((p) => p.id === id), + + // Pages + addPage: (pageData) => { + const page: Page = { + ...pageData, + id: uuidv4(), + createdAt: now(), + updatedAt: now(), + } + set((s) => ({ pages: [page, ...s.pages] })) + return page + }, + updatePage: (id, data) => + set((s) => ({ + pages: s.pages.map((p) => + p.id === id ? { ...p, ...data, updatedAt: now() } : p + ), + })), + deletePage: (id) => + set((s) => ({ pages: s.pages.filter((p) => p.id !== id) })), + getPage: (id) => get().pages.find((p) => p.id === id), + + // Gallery + addImage: (imgData) => { + const image: GalleryImage = { + ...imgData, + id: uuidv4(), + uploadedAt: now(), + } + set((s) => ({ gallery: [image, ...s.gallery] })) + }, + deleteImage: (id) => + set((s) => ({ gallery: s.gallery.filter((i) => i.id !== id) })), + updateImage: (id, data) => + set((s) => ({ + gallery: s.gallery.map((i) => (i.id === id ? { ...i, ...data } : i)), + })), + + // Navigation + addNavItem: (itemData) => { + const item: NavItem = { ...itemData, id: uuidv4() } + set((s) => ({ navItems: [...s.navItems, item] })) + }, + updateNavItem: (id, data) => + set((s) => ({ + navItems: s.navItems.map((i) => (i.id === id ? { ...i, ...data } : i)), + })), + deleteNavItem: (id) => + set((s) => ({ navItems: s.navItems.filter((i) => i.id !== id) })), + reorderNavItems: (items) => set({ navItems: items }), + + // Categories + addCategory: (catData) => { + const cat: Category = { ...catData, id: uuidv4() } + set((s) => ({ categories: [...s.categories, cat] })) + }, + updateCategory: (id, data) => + set((s) => ({ + categories: s.categories.map((c) => + c.id === id ? { ...c, ...data } : c + ), + })), + deleteCategory: (id) => + set((s) => ({ categories: s.categories.filter((c) => c.id !== id) })), + + // Settings + updateSettings: (data) => + set((s) => ({ settings: { ...s.settings, ...data } })), + }), + { + name: 'cms-data', + } + ) +)