fix: apply designer agent improvements to src/store/useStore.ts

This commit is contained in:
cupadev-admin 2026-03-09 19:01:00 +00:00
parent a755ed776d
commit e2501b3004
1 changed files with 140 additions and 370 deletions

View File

@ -1,391 +1,161 @@
import { create } from 'zustand'; import { create } from 'zustand'
import { persist } from 'zustand/middleware'; import { v4 as uuidv4 } from 'uuid'
import { v4 as uuidv4 } from 'uuid'; import type { Post, Page, GalleryImage, NavItem, SiteSettings } from '@/types'
import type { Page, Post, GalleryItem, NavItem, SiteSettings } from '@/types';
interface CMSState { const now = () => new Date().toISOString()
// Auth
isAuthenticated: boolean;
currentUser: { username: string; email: string; role: string } | null;
login: (username: string, password: string) => boolean;
logout: () => void;
// Pages const DEMO_POSTS: Post[] = [
pages: Page[];
addPage: (page: Omit<Page, 'id' | 'createdAt' | 'updatedAt'>) => Page;
updatePage: (id: string, data: Partial<Page>) => void;
deletePage: (id: string) => void;
getPageBySlug: (slug: string) => Page | undefined;
getPageById: (id: string) => Page | undefined;
// Posts
posts: Post[];
addPost: (post: Omit<Post, 'id' | 'createdAt' | 'updatedAt'>) => Post;
updatePost: (id: string, data: Partial<Post>) => void;
deletePost: (id: string) => void;
getPostBySlug: (slug: string) => Post | undefined;
getPostById: (id: string) => Post | undefined;
// Gallery
gallery: GalleryItem[];
addGalleryItem: (item: Omit<GalleryItem, 'id' | 'createdAt' | 'updatedAt'>) => GalleryItem;
updateGalleryItem: (id: string, data: Partial<GalleryItem>) => void;
deleteGalleryItem: (id: string) => void;
reorderGallery: (items: GalleryItem[]) => void;
// Navigation
navigation: NavItem[];
addNavItem: (item: Omit<NavItem, 'id'>) => void;
updateNavItem: (id: string, data: Partial<NavItem>) => void;
deleteNavItem: (id: string) => void;
reorderNav: (items: NavItem[]) => void;
// Settings
settings: SiteSettings;
updateSettings: (data: Partial<SiteSettings>) => 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', id: '1',
title: 'Accueil', title: 'Getting Started with Next.js 14',
slug: '', slug: 'getting-started-nextjs-14',
content: '<h1>Bienvenue au Musée & Blog</h1><p>Explorez notre collection unique d\'œuvres d\'art et découvrez nos articles passionnants sur l\'art et la culture.</p>', excerpt: 'A comprehensive guide to building modern web applications with Next.js 14 and the App Router.',
excerpt: 'Bienvenue sur notre site dédié à l\'art et à la culture.', content: '<p>Next.js 14 introduces groundbreaking features...</p>',
type: 'home',
status: 'published', status: 'published',
featuredImage: 'https://images.unsplash.com/photo-1518998053901-5348d3961a04?w=1200', tags: ['Next.js', 'React', 'Web Dev'],
order: 0, createdAt: '2024-01-15T10:00:00Z',
createdAt: new Date().toISOString(), updatedAt: '2024-01-15T10:00:00Z',
updatedAt: new Date().toISOString(),
}, },
{ {
id: 'about', id: '2',
title: 'À propos', title: 'Mastering Tailwind CSS',
slug: 'a-propos', slug: 'mastering-tailwind-css',
content: '<h2>Notre Mission</h2><p>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.</p><h2>Notre Histoire</h2><p>Fondé en 2024, notre espace culturel numérique rassemble passionnés d\'art, artistes et curieux du monde entier.</p>', excerpt: 'Deep dive into advanced Tailwind CSS techniques for building beautiful UIs.',
excerpt: 'Découvrez notre mission et notre histoire.', content: '<p>Tailwind CSS has revolutionized how we write CSS...</p>',
type: 'page', 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: '<p>TypeScript has become the standard for large-scale applications...</p>',
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: '<p>Welcome to my personal website...</p>',
status: 'published', status: 'published',
order: 1, order: 1,
createdAt: new Date().toISOString(), createdAt: '2024-01-01T10:00:00Z',
updatedAt: new Date().toISOString(), updatedAt: '2024-01-01T10:00:00Z',
}, },
{ {
id: 'contact', id: '2',
title: 'Contact', title: 'Contact',
slug: 'contact', slug: 'contact',
content: '<h2>Contactez-nous</h2><p>Pour toute question ou collaboration, n\'hésitez pas à nous contacter.</p>', content: '<p>Get in touch with me...</p>',
excerpt: 'Prenez contact avec nous.',
type: 'contact',
status: 'published', 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: '<p>L\'impressionnisme est un mouvement pictural né en France au XIXe siècle qui révolutionna la peinture traditionnelle...</p><h2>Les Origines</h2><p>Le mouvement impressionniste est né d\'un groupe de peintres parisiens dans les années 1860...</p>',
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: '<p>Notre nouvelle exposition temporaire met en lumière les artistes qui ont su capturer et sublimer la lumière dans leurs œuvres...</p>',
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: '<p>Rejoignez-nous pour le vernissage de notre exposition d\'art contemporain qui réunit des artistes émergents et confirmés...</p>',
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, order: 2,
createdAt: new Date().toISOString(), createdAt: '2024-01-01T10:00:00Z',
updatedAt: new Date().toISOString(), updatedAt: '2024-01-01T10:00:00Z',
}, },
{ ]
id: 'g-4',
title: 'La Danse des Formes', const DEMO_NAV: NavItem[] = [
description: 'Sculpture abstraite jouant avec l\'équilibre et le mouvement.', { id: '1', label: 'Home', href: '/', order: 1 },
imageUrl: 'https://images.unsplash.com/photo-1561839561-b13bcfe95249?w=800', { id: '2', label: 'Blog', href: '/blog', order: 2 },
artist: 'Pierre Moreau', { id: '3', label: 'About', href: '/about', order: 3 },
year: '2021', { id: '4', label: 'Contact', href: '/contact', order: 4 },
medium: 'Bronze', ]
dimensions: '45 × 30 × 25 cm',
category: 'Sculpture', const DEMO_GALLERY: GalleryImage[] = [
tags: ['sculpture', 'abstrait', 'bronze'], { id: '1', url: 'https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=800', alt: 'Mountain landscape', caption: 'Alps at sunset', createdAt: now() },
order: 3, { id: '2', url: 'https://images.unsplash.com/photo-1469474968028-56623f02e42e?w=800', alt: 'Forest path', caption: 'Morning mist', createdAt: now() },
createdAt: new Date().toISOString(), { id: '3', url: 'https://images.unsplash.com/photo-1519681393784-d120267933ba?w=800', alt: 'Starry night', caption: 'Night sky', createdAt: now() },
updatedAt: new Date().toISOString(), ]
interface StoreState {
posts: Post[]
pages: Page[]
gallery: GalleryImage[]
navItems: NavItem[]
settings: SiteSettings
// Posts
addPost: (post: Omit<Post, 'id' | 'createdAt' | 'updatedAt'>) => Post
updatePost: (id: string, data: Partial<Post>) => void
deletePost: (id: string) => void
// Pages
addPage: (page: Omit<Page, 'id' | 'createdAt' | 'updatedAt'>) => Page
updatePage: (id: string, data: Partial<Page>) => void
deletePage: (id: string) => void
// Gallery
addImage: (image: Omit<GalleryImage, 'id' | 'createdAt'>) => void
deleteImage: (id: string) => void
updateImage: (id: string, data: Partial<GalleryImage>) => void
// Navigation
addNavItem: (item: Omit<NavItem, 'id'>) => void
updateNavItem: (id: string, data: Partial<NavItem>) => void
deleteNavItem: (id: string) => void
reorderNavItems: (items: NavItem[]) => void
// Settings
updateSettings: (data: Partial<SiteSettings>) => void
}
export const useStore = create<StoreState>((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', addPost: (data) => {
title: 'Jardin Secret', const post: Post = { ...data, id: uuidv4(), createdAt: now(), updatedAt: now() }
description: 'Une composition florale aux teintes pastel évoquant la sérénité d\'un jardin caché.', set((s) => ({ posts: [post, ...s.posts] }))
imageUrl: 'https://images.unsplash.com/photo-1416879595882-3373a0480b5b?w=800', return post
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(),
}, },
{ updatePost: (id, data) =>
id: 'g-6', set((s) => ({
title: 'Lumière du Nord', posts: s.posts.map((p) => (p.id === id ? { ...p, ...data, updatedAt: now() } : p)),
description: 'Paysage nordique baigné d\'une lumière spectrale et mystérieuse.', })),
imageUrl: 'https://images.unsplash.com/photo-1531366936337-7c912a4589a7?w=800', deletePost: (id) => set((s) => ({ posts: s.posts.filter((p) => p.id !== id) })),
artist: 'Erik Andersen',
year: '2024', addPage: (data) => {
medium: 'Photographie', const page: Page = { ...data, id: uuidv4(), createdAt: now(), updatedAt: now() }
dimensions: '120 × 80 cm', set((s) => ({ pages: [page, ...s.pages] }))
category: 'Photographie', return page
tags: ['paysage', 'lumière', 'nord'],
order: 5,
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
}, },
]; 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[] = [ addImage: (data) =>
{ id: 'nav-1', label: 'Accueil', url: '/', target: '_self', order: 0 }, set((s) => ({ gallery: [{ ...data, id: uuidv4(), createdAt: now() }, ...s.gallery] })),
{ id: 'nav-2', label: 'Musée', url: '/galerie', target: '_self', order: 1 }, deleteImage: (id) => set((s) => ({ gallery: s.gallery.filter((i) => i.id !== id) })),
{ id: 'nav-3', label: 'Blog', url: '/blog', target: '_self', order: 2 }, updateImage: (id, data) =>
{ id: 'nav-4', label: 'À propos', url: '/a-propos', target: '_self', order: 3 }, set((s) => ({ gallery: s.gallery.map((i) => (i.id === id ? { ...i, ...data } : i)) })),
{ id: 'nav-5', label: 'Contact', url: '/contact', target: '_self', order: 4 },
];
export const useStore = create<CMSState>()( addNavItem: (data) =>
persist( set((s) => ({ navItems: [...s.navItems, { ...data, id: uuidv4() }] })),
(set, get) => ({ updateNavItem: (id, data) =>
isAuthenticated: false, set((s) => ({ navItems: s.navItems.map((n) => (n.id === id ? { ...n, ...data } : n)) })),
currentUser: null, deleteNavItem: (id) => set((s) => ({ navItems: s.navItems.filter((n) => n.id !== id) })),
reorderNavItems: (items) => set({ navItems: items }),
login: (username, password) => { updateSettings: (data) =>
if (username === 'admin' && password === 'admin123') { set((s) => ({ settings: { ...s.settings, ...data } })),
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,
}),
}
)
);