diff --git a/src/store/useStore.ts b/src/store/useStore.ts index 841ad9c..115e6b0 100644 --- a/src/store/useStore.ts +++ b/src/store/useStore.ts @@ -1,391 +1,161 @@ -import { create } from 'zustand'; -import { persist } from 'zustand/middleware'; -import { v4 as uuidv4 } from 'uuid'; -import type { Page, Post, GalleryItem, NavItem, SiteSettings } from '@/types'; +import { create } from 'zustand' +import { v4 as uuidv4 } from 'uuid' +import type { Post, Page, GalleryImage, 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; +const now = () => new Date().toISOString() - // 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[] = [ +const DEMO_POSTS: Post[] = [ { - 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', + id: '1', + title: 'Getting Started with Next.js 14', + slug: 'getting-started-nextjs-14', + excerpt: 'A comprehensive guide to building modern web applications with Next.js 14 and the App Router.', + content: '

Next.js 14 introduces groundbreaking features...

', status: 'published', - featuredImage: 'https://images.unsplash.com/photo-1518998053901-5348d3961a04?w=1200', - order: 0, - createdAt: new Date().toISOString(), - updatedAt: new Date().toISOString(), + tags: ['Next.js', 'React', 'Web Dev'], + createdAt: '2024-01-15T10:00:00Z', + updatedAt: '2024-01-15T10:00:00Z', }, { - 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', + id: '2', + title: 'Mastering Tailwind CSS', + slug: 'mastering-tailwind-css', + excerpt: 'Deep dive into advanced Tailwind CSS techniques for building beautiful UIs.', + content: '

Tailwind CSS has revolutionized how we write CSS...

', + status: 'published', + tags: ['CSS', 'Tailwind', 'Design'], + createdAt: '2024-01-20T10:00:00Z', + updatedAt: '2024-01-20T10:00:00Z', + }, + { + id: '3', + title: 'TypeScript Best Practices', + slug: 'typescript-best-practices', + excerpt: 'Essential TypeScript patterns and practices for scalable applications.', + content: '

TypeScript has become the standard for large-scale applications...

', + status: 'draft', + tags: ['TypeScript', 'JavaScript'], + createdAt: '2024-01-25T10:00:00Z', + updatedAt: '2024-01-25T10:00:00Z', + }, +] + +const DEMO_PAGES: Page[] = [ + { + id: '1', + title: 'About', + slug: 'about', + content: '

Welcome to my personal website...

', status: 'published', order: 1, - createdAt: new Date().toISOString(), - updatedAt: new Date().toISOString(), + createdAt: '2024-01-01T10:00:00Z', + updatedAt: '2024-01-01T10:00:00Z', }, { - id: 'contact', + id: '2', 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', + content: '

Get in touch with me...

', 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(), + createdAt: '2024-01-01T10:00:00Z', + updatedAt: '2024-01-01T10:00:00Z', }, - { - 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(), +] + +const DEMO_NAV: NavItem[] = [ + { id: '1', label: 'Home', href: '/', order: 1 }, + { id: '2', label: 'Blog', href: '/blog', order: 2 }, + { id: '3', label: 'About', href: '/about', order: 3 }, + { id: '4', label: 'Contact', href: '/contact', order: 4 }, +] + +const DEMO_GALLERY: GalleryImage[] = [ + { id: '1', url: 'https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=800', alt: 'Mountain landscape', caption: 'Alps at sunset', createdAt: now() }, + { id: '2', url: 'https://images.unsplash.com/photo-1469474968028-56623f02e42e?w=800', alt: 'Forest path', caption: 'Morning mist', createdAt: now() }, + { id: '3', url: 'https://images.unsplash.com/photo-1519681393784-d120267933ba?w=800', alt: 'Starry night', caption: 'Night sky', createdAt: now() }, +] + +interface StoreState { + posts: Post[] + pages: Page[] + gallery: GalleryImage[] + navItems: NavItem[] + settings: SiteSettings + + // Posts + addPost: (post: Omit) => Post + updatePost: (id: string, data: Partial) => void + deletePost: (id: string) => void + + // Pages + addPage: (page: Omit) => Page + updatePage: (id: string, data: Partial) => void + deletePage: (id: string) => void + + // 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 + + // Settings + updateSettings: (data: Partial) => void +} + +export const useStore = create((set, get) => ({ + posts: DEMO_POSTS, + pages: DEMO_PAGES, + gallery: DEMO_GALLERY, + navItems: DEMO_NAV, + settings: { + siteName: 'My Personal CMS', + siteDescription: 'A beautiful personal website built with Next.js', + socialLinks: {}, + seoDefaults: { title: 'My Site', description: 'Welcome to my personal site' }, + theme: { primaryColor: '#3b82f6', accentColor: '#8b5cf6', darkMode: false }, }, - { - 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(), + + addPost: (data) => { + const post: Post = { ...data, id: uuidv4(), createdAt: now(), updatedAt: now() } + set((s) => ({ posts: [post, ...s.posts] })) + return post }, - { - 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(), + 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) })), + + addPage: (data) => { + const page: Page = { ...data, 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) })), -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 }, -]; + addImage: (data) => + set((s) => ({ gallery: [{ ...data, id: uuidv4(), createdAt: now() }, ...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)) })), -export const useStore = create()( - persist( - (set, get) => ({ - isAuthenticated: false, - currentUser: null, + addNavItem: (data) => + set((s) => ({ navItems: [...s.navItems, { ...data, id: uuidv4() }] })), + updateNavItem: (id, data) => + set((s) => ({ navItems: s.navItems.map((n) => (n.id === id ? { ...n, ...data } : n)) })), + deleteNavItem: (id) => set((s) => ({ navItems: s.navItems.filter((n) => n.id !== id) })), + reorderNavItems: (items) => set({ navItems: items }), - 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, - }), - } - ) -); + updateSettings: (data) => + set((s) => ({ settings: { ...s.settings, ...data } })), +}))