From f96dfd800263769eebb4d05b104fc40a6f50f013 Mon Sep 17 00:00:00 2001 From: cupadev-admin Date: Mon, 9 Mar 2026 12:59:23 +0000 Subject: [PATCH] feat: add src/store/useStore.ts --- src/store/useStore.ts | 391 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 391 insertions(+) create mode 100644 src/store/useStore.ts diff --git a/src/store/useStore.ts b/src/store/useStore.ts new file mode 100644 index 0000000..841ad9c --- /dev/null +++ b/src/store/useStore.ts @@ -0,0 +1,391 @@ +import { create } from 'zustand'; +import { persist } from 'zustand/middleware'; +import { v4 as uuidv4 } from 'uuid'; +import type { Page, Post, GalleryItem, NavItem, SiteSettings } from '@/types'; + +interface CMSState { + // Auth + isAuthenticated: boolean; + currentUser: { username: string; email: string; role: string } | null; + login: (username: string, password: string) => boolean; + logout: () => void; + + // Pages + pages: Page[]; + addPage: (page: Omit) => Page; + updatePage: (id: string, data: Partial) => void; + deletePage: (id: string) => void; + getPageBySlug: (slug: string) => Page | undefined; + getPageById: (id: string) => Page | undefined; + + // Posts + posts: Post[]; + addPost: (post: Omit) => Post; + updatePost: (id: string, data: Partial) => void; + deletePost: (id: string) => void; + getPostBySlug: (slug: string) => Post | undefined; + getPostById: (id: string) => Post | undefined; + + // Gallery + gallery: GalleryItem[]; + addGalleryItem: (item: Omit) => GalleryItem; + updateGalleryItem: (id: string, data: Partial) => void; + deleteGalleryItem: (id: string) => void; + reorderGallery: (items: GalleryItem[]) => void; + + // Navigation + navigation: NavItem[]; + addNavItem: (item: Omit) => void; + updateNavItem: (id: string, data: Partial) => void; + deleteNavItem: (id: string) => void; + reorderNav: (items: NavItem[]) => void; + + // Settings + settings: SiteSettings; + updateSettings: (data: Partial) => void; +} + +const defaultSettings: SiteSettings = { + siteName: 'Musée & Blog', + tagline: 'Art, Culture & Découvertes', + description: 'Un espace dédié à l\'art, à la culture et aux découvertes.', + primaryColor: '#1a1a2e', + accentColor: '#a08660', + footerText: '© 2024 Musée & Blog. Tous droits réservés.', + socialLinks: {}, + contactEmail: 'contact@musee-blog.fr', +}; + +const defaultPages: Page[] = [ + { + id: 'home', + title: 'Accueil', + slug: '', + content: '

Bienvenue au Musée & Blog

Explorez notre collection unique d\'œuvres d\'art et découvrez nos articles passionnants sur l\'art et la culture.

', + excerpt: 'Bienvenue sur notre site dédié à l\'art et à la culture.', + type: 'home', + status: 'published', + featuredImage: 'https://images.unsplash.com/photo-1518998053901-5348d3961a04?w=1200', + order: 0, + createdAt: new Date().toISOString(), + updatedAt: new Date().toISOString(), + }, + { + id: 'about', + title: 'À propos', + slug: 'a-propos', + content: '

Notre Mission

Nous sommes dédiés à la promotion de l\'art et de la culture à travers notre plateforme unique qui combine blog et musée virtuel.

Notre Histoire

Fondé en 2024, notre espace culturel numérique rassemble passionnés d\'art, artistes et curieux du monde entier.

', + excerpt: 'Découvrez notre mission et notre histoire.', + type: 'page', + status: 'published', + order: 1, + createdAt: new Date().toISOString(), + updatedAt: new Date().toISOString(), + }, + { + id: 'contact', + title: 'Contact', + slug: 'contact', + content: '

Contactez-nous

Pour toute question ou collaboration, n\'hésitez pas à nous contacter.

', + excerpt: 'Prenez contact avec nous.', + type: 'contact', + status: 'published', + order: 4, + createdAt: new Date().toISOString(), + updatedAt: new Date().toISOString(), + }, +]; + +const defaultPosts: Post[] = [ + { + id: 'post-1', + title: 'L\'impressionnisme : Une révolution artistique', + slug: 'impressionnisme-revolution-artistique', + content: '

L\'impressionnisme est un mouvement pictural né en France au XIXe siècle qui révolutionna la peinture traditionnelle...

Les Origines

Le mouvement impressionniste est né d\'un groupe de peintres parisiens dans les années 1860...

', + excerpt: 'Découvrez comment l\'impressionnisme a transformé le monde de l\'art au XIXe siècle.', + category: 'article', + tags: ['impressionnisme', 'peinture', 'histoire de l\'art'], + status: 'published', + featuredImage: 'https://images.unsplash.com/photo-1541367777708-7905fe3296c0?w=800', + author: 'Admin', + publishedAt: new Date().toISOString(), + createdAt: new Date().toISOString(), + updatedAt: new Date().toISOString(), + }, + { + id: 'post-2', + title: 'Exposition : Les Maîtres de la Lumière', + slug: 'exposition-maitres-lumiere', + content: '

Notre nouvelle exposition temporaire met en lumière les artistes qui ont su capturer et sublimer la lumière dans leurs œuvres...

', + excerpt: 'Une exposition exceptionnelle dédiée aux maîtres de la lumière dans l\'art.', + category: 'exhibit', + tags: ['exposition', 'lumière', 'peinture'], + status: 'published', + featuredImage: 'https://images.unsplash.com/photo-1578662996442-48f60103fc96?w=800', + author: 'Admin', + publishedAt: new Date().toISOString(), + createdAt: new Date().toISOString(), + updatedAt: new Date().toISOString(), + }, + { + id: 'post-3', + title: 'Vernissage : Art Contemporain 2024', + slug: 'vernissage-art-contemporain-2024', + content: '

Rejoignez-nous pour le vernissage de notre exposition d\'art contemporain qui réunit des artistes émergents et confirmés...

', + excerpt: 'Vernissage de notre exposition annuelle d\'art contemporain.', + category: 'event', + tags: ['vernissage', 'art contemporain', 'événement'], + status: 'published', + featuredImage: 'https://images.unsplash.com/photo-1531058020387-3be344556be6?w=800', + author: 'Admin', + publishedAt: new Date().toISOString(), + createdAt: new Date().toISOString(), + updatedAt: new Date().toISOString(), + }, +]; + +const defaultGallery: GalleryItem[] = [ + { + id: 'g-1', + title: 'Harmonie en Bleu', + description: 'Une œuvre abstraite explorant les nuances du bleu et la profondeur de l\'océan.', + imageUrl: 'https://images.unsplash.com/photo-1578301978693-85fa9c0320b9?w=800', + artist: 'Marie Dupont', + year: '2023', + medium: 'Huile sur toile', + dimensions: '120 × 90 cm', + category: 'Peinture', + tags: ['abstrait', 'bleu', 'contemporain'], + order: 0, + createdAt: new Date().toISOString(), + updatedAt: new Date().toISOString(), + }, + { + id: 'g-2', + title: 'Portrait d\'Automne', + description: 'Un portrait saisissant capturant la mélancolie de la saison automnale.', + imageUrl: 'https://images.unsplash.com/photo-1549490349-8643362247b5?w=800', + artist: 'Jean-Pierre Martin', + year: '2022', + medium: 'Aquarelle', + dimensions: '60 × 80 cm', + category: 'Peinture', + tags: ['portrait', 'automne', 'aquarelle'], + order: 1, + createdAt: new Date().toISOString(), + updatedAt: new Date().toISOString(), + }, + { + id: 'g-3', + title: 'Architecture Urbaine', + description: 'Photographie artistique explorant les lignes et formes de l\'architecture moderne.', + imageUrl: 'https://images.unsplash.com/photo-1486325212027-8081e485255e?w=800', + artist: 'Sophie Lambert', + year: '2024', + medium: 'Photographie numérique', + dimensions: '100 × 150 cm', + category: 'Photographie', + tags: ['architecture', 'urbain', 'photographie'], + order: 2, + createdAt: new Date().toISOString(), + updatedAt: new Date().toISOString(), + }, + { + id: 'g-4', + title: 'La Danse des Formes', + description: 'Sculpture abstraite jouant avec l\'équilibre et le mouvement.', + imageUrl: 'https://images.unsplash.com/photo-1561839561-b13bcfe95249?w=800', + artist: 'Pierre Moreau', + year: '2021', + medium: 'Bronze', + dimensions: '45 × 30 × 25 cm', + category: 'Sculpture', + tags: ['sculpture', 'abstrait', 'bronze'], + order: 3, + createdAt: new Date().toISOString(), + updatedAt: new Date().toISOString(), + }, + { + id: 'g-5', + title: 'Jardin Secret', + description: 'Une composition florale aux teintes pastel évoquant la sérénité d\'un jardin caché.', + imageUrl: 'https://images.unsplash.com/photo-1416879595882-3373a0480b5b?w=800', + artist: 'Isabelle Chen', + year: '2023', + medium: 'Acrylique sur toile', + dimensions: '80 × 80 cm', + category: 'Peinture', + tags: ['floral', 'pastel', 'jardin'], + order: 4, + createdAt: new Date().toISOString(), + updatedAt: new Date().toISOString(), + }, + { + id: 'g-6', + title: 'Lumière du Nord', + description: 'Paysage nordique baigné d\'une lumière spectrale et mystérieuse.', + imageUrl: 'https://images.unsplash.com/photo-1531366936337-7c912a4589a7?w=800', + artist: 'Erik Andersen', + year: '2024', + medium: 'Photographie', + dimensions: '120 × 80 cm', + category: 'Photographie', + tags: ['paysage', 'lumière', 'nord'], + order: 5, + createdAt: new Date().toISOString(), + updatedAt: new Date().toISOString(), + }, +]; + +const defaultNav: NavItem[] = [ + { id: 'nav-1', label: 'Accueil', url: '/', target: '_self', order: 0 }, + { id: 'nav-2', label: 'Musée', url: '/galerie', target: '_self', order: 1 }, + { id: 'nav-3', label: 'Blog', url: '/blog', target: '_self', order: 2 }, + { id: 'nav-4', label: 'À propos', url: '/a-propos', target: '_self', order: 3 }, + { id: 'nav-5', label: 'Contact', url: '/contact', target: '_self', order: 4 }, +]; + +export const useStore = create()( + persist( + (set, get) => ({ + isAuthenticated: false, + currentUser: null, + + login: (username, password) => { + if (username === 'admin' && password === 'admin123') { + set({ + isAuthenticated: true, + currentUser: { username: 'admin', email: 'admin@cms.fr', role: 'admin' }, + }); + return true; + } + return false; + }, + + logout: () => set({ isAuthenticated: false, currentUser: null }), + + pages: defaultPages, + + addPage: (pageData) => { + const now = new Date().toISOString(); + const page: Page = { + ...pageData, + id: uuidv4(), + createdAt: now, + updatedAt: now, + }; + set((state) => ({ pages: [...state.pages, page] })); + return page; + }, + + updatePage: (id, data) => { + set((state) => ({ + pages: state.pages.map((p) => + p.id === id ? { ...p, ...data, updatedAt: new Date().toISOString() } : p + ), + })); + }, + + deletePage: (id) => { + set((state) => ({ pages: state.pages.filter((p) => p.id !== id) })); + }, + + getPageBySlug: (slug) => get().pages.find((p) => p.slug === slug), + getPageById: (id) => get().pages.find((p) => p.id === id), + + posts: defaultPosts, + + addPost: (postData) => { + const now = new Date().toISOString(); + const post: Post = { + ...postData, + id: uuidv4(), + createdAt: now, + updatedAt: now, + }; + set((state) => ({ posts: [...state.posts, post] })); + return post; + }, + + updatePost: (id, data) => { + set((state) => ({ + posts: state.posts.map((p) => + p.id === id ? { ...p, ...data, updatedAt: new Date().toISOString() } : p + ), + })); + }, + + deletePost: (id) => { + set((state) => ({ posts: state.posts.filter((p) => p.id !== id) })); + }, + + getPostBySlug: (slug) => get().posts.find((p) => p.slug === slug), + getPostById: (id) => get().posts.find((p) => p.id === id), + + gallery: defaultGallery, + + addGalleryItem: (itemData) => { + const now = new Date().toISOString(); + const item: GalleryItem = { + ...itemData, + id: uuidv4(), + createdAt: now, + updatedAt: now, + }; + set((state) => ({ gallery: [...state.gallery, item] })); + return item; + }, + + updateGalleryItem: (id, data) => { + set((state) => ({ + gallery: state.gallery.map((g) => + g.id === id ? { ...g, ...data, updatedAt: new Date().toISOString() } : g + ), + })); + }, + + deleteGalleryItem: (id) => { + set((state) => ({ gallery: state.gallery.filter((g) => g.id !== id) })); + }, + + reorderGallery: (items) => set({ gallery: items }), + + navigation: defaultNav, + + addNavItem: (itemData) => { + const item: NavItem = { ...itemData, id: uuidv4() }; + set((state) => ({ navigation: [...state.navigation, item] })); + }, + + updateNavItem: (id, data) => { + set((state) => ({ + navigation: state.navigation.map((n) => (n.id === id ? { ...n, ...data } : n)), + })); + }, + + deleteNavItem: (id) => { + set((state) => ({ navigation: state.navigation.filter((n) => n.id !== id) })); + }, + + reorderNav: (items) => set({ navigation: items }), + + settings: defaultSettings, + + updateSettings: (data) => { + set((state) => ({ settings: { ...state.settings, ...data } })); + }, + }), + { + name: 'cms-storage', + partialize: (state) => ({ + pages: state.pages, + posts: state.posts, + gallery: state.gallery, + navigation: state.navigation, + settings: state.settings, + isAuthenticated: state.isAuthenticated, + currentUser: state.currentUser, + }), + } + ) +);