feat: add src/lib/store.ts

This commit is contained in:
cupadev-admin 2026-03-09 07:22:52 +00:00
parent a35978ea0c
commit a899b1b568
1 changed files with 333 additions and 0 deletions

333
src/lib/store.ts Normal file
View File

@ -0,0 +1,333 @@
import { create } from 'zustand'
import { v4 as uuidv4 } from 'uuid'
export type PostStatus = 'draft' | 'published'
export type PageStatus = 'draft' | 'published'
export type MediaType = 'image' | 'video'
export interface Post {
id: string
title: string
slug: string
content: string
excerpt: string
coverImage: string
category: string
tags: string[]
status: PostStatus
createdAt: string
updatedAt: string
author: string
}
export interface GalleryItem {
id: string
title: string
description: string
imageUrl: string
category: string
tags: string[]
createdAt: string
}
export interface Page {
id: string
title: string
slug: string
content: string
status: PageStatus
showInNav: boolean
navOrder: number
createdAt: string
updatedAt: string
}
export interface NavItem {
id: string
label: string
href: string
order: number
type: 'page' | 'custom'
}
export interface SiteSettings {
siteName: string
siteDescription: string
logo: string
favicon: string
primaryColor: string
footerText: string
socialLinks: {
facebook: string
instagram: string
twitter: string
youtube: string
linkedin: string
}
headerNavItems: NavItem[]
showSocialInHeader: boolean
showSocialInFooter: boolean
metaKeywords: string
metaDescription: string
}
export interface User {
id: string
username: string
email: string
role: 'admin' | 'editor'
avatar: string
}
interface CMSState {
// Auth
isAuthenticated: boolean
currentUser: User | null
login: (username: string, password: string) => boolean
logout: () => void
// Posts
posts: Post[]
addPost: (post: Omit<Post, 'id' | 'createdAt' | 'updatedAt'>) => void
updatePost: (id: string, post: Partial<Post>) => void
deletePost: (id: string) => void
getPost: (id: string) => Post | undefined
getPostBySlug: (slug: string) => Post | undefined
// Gallery
galleryItems: GalleryItem[]
addGalleryItem: (item: Omit<GalleryItem, 'id' | 'createdAt'>) => void
updateGalleryItem: (id: string, item: Partial<GalleryItem>) => void
deleteGalleryItem: (id: string) => void
// Pages
pages: Page[]
addPage: (page: Omit<Page, 'id' | 'createdAt' | 'updatedAt'>) => void
updatePage: (id: string, page: Partial<Page>) => void
deletePage: (id: string) => void
getPageBySlug: (slug: string) => Page | undefined
// Settings
settings: SiteSettings
updateSettings: (settings: Partial<SiteSettings>) => void
updateNavItems: (items: NavItem[]) => void
}
const defaultPosts: Post[] = [
{
id: '1',
title: 'Bienvenue sur mon blog',
slug: 'bienvenue-sur-mon-blog',
content: '<h2>Bonjour et bienvenue !</h2><p>Ceci est mon premier article de blog. Je suis ravi de partager mes pensées et créations avec vous.</p><p>Ce site est propulsé par mon CMS personnel que j\'ai créé pour exprimer ma créativité.</p>',
excerpt: 'Bienvenue sur mon blog personnel où je partage mes créations et réflexions.',
coverImage: 'https://images.unsplash.com/photo-1499750310107-5fef28a66643?w=800',
category: 'General',
tags: ['bienvenue', 'blog'],
status: 'published',
createdAt: new Date(Date.now() - 7 * 24 * 3600000).toISOString(),
updatedAt: new Date(Date.now() - 7 * 24 * 3600000).toISOString(),
author: 'Admin',
},
{
id: '2',
title: 'Exploration artistique',
slug: 'exploration-artistique',
content: '<h2>L\'art comme expression</h2><p>L\'art est une fenêtre sur l\'âme. Dans cet article, je vous emmène dans mon univers artistique.</p><p>Chaque œuvre raconte une histoire unique, une émotion capturée dans l\'instant.</p>',
excerpt: 'Un voyage au cœur de mes inspirations artistiques et créations.',
coverImage: 'https://images.unsplash.com/photo-1541367777708-7905fe3296c0?w=800',
category: 'Art',
tags: ['art', 'créativité', 'inspiration'],
status: 'published',
createdAt: new Date(Date.now() - 3 * 24 * 3600000).toISOString(),
updatedAt: new Date(Date.now() - 3 * 24 * 3600000).toISOString(),
author: 'Admin',
},
]
const defaultGallery: GalleryItem[] = [
{
id: '1',
title: 'Paysage Urbain',
description: 'Une exploration des contrastes de la ville moderne.',
imageUrl: 'https://images.unsplash.com/photo-1477959858617-67f85cf4f1df?w=600',
category: 'Photographie',
tags: ['urbain', 'ville'],
createdAt: new Date().toISOString(),
},
{
id: '2',
title: 'Nature Sauvage',
description: 'La beauté brute de la nature préservée.',
imageUrl: 'https://images.unsplash.com/photo-1441974231531-c6227db76b6e?w=600',
category: 'Nature',
tags: ['nature', 'forêt'],
createdAt: new Date().toISOString(),
},
{
id: '3',
title: 'Architecture Moderne',
description: 'Les lignes épurées de l\'architecture contemporaine.',
imageUrl: 'https://images.unsplash.com/photo-1486325212027-8081e485255e?w=600',
category: 'Architecture',
tags: ['architecture', 'design'],
createdAt: new Date().toISOString(),
},
{
id: '4',
title: 'Portrait Émotionnel',
description: 'Capturer l\'essence humaine dans un regard.',
imageUrl: 'https://images.unsplash.com/photo-1506794778202-cad84cf45f1d?w=600',
category: 'Portrait',
tags: ['portrait', 'humain'],
createdAt: new Date().toISOString(),
},
]
const defaultPages: Page[] = [
{
id: '1',
title: 'À Propos',
slug: 'a-propos',
content: '<h1>À Propos de Moi</h1><p>Bienvenue sur mon espace personnel. Je suis un artiste et créateur passionné.</p><p>Ce site est mon musée numérique où je partage mes œuvres, mes réflexions et mon univers créatif.</p>',
status: 'published',
showInNav: true,
navOrder: 1,
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
},
{
id: '2',
title: 'Contact',
slug: 'contact',
content: '<h1>Me Contacter</h1><p>N\'hésitez pas à me contacter pour toute collaboration ou question.</p><p>Email: contact@monsite.com</p>',
status: 'published',
showInNav: true,
navOrder: 2,
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
},
]
const defaultSettings: SiteSettings = {
siteName: 'Mon Musée Personnel',
siteDescription: 'Blog & Galerie d\'Art Personnel',
logo: '',
favicon: '',
primaryColor: '#0ea5e9',
footerText: '© 2024 Mon Musée Personnel. Tous droits réservés.',
socialLinks: {
facebook: 'https://facebook.com',
instagram: 'https://instagram.com',
twitter: '',
youtube: '',
linkedin: '',
},
headerNavItems: [
{ id: '1', label: 'Accueil', href: '/', order: 0, type: 'custom' },
{ id: '2', label: 'Blog', href: '/blog', order: 1, type: 'custom' },
{ id: '3', label: 'Galerie', href: '/galerie', order: 2, type: 'custom' },
{ id: '4', label: 'À Propos', href: '/pages/a-propos', order: 3, type: 'page' },
{ id: '5', label: 'Contact', href: '/pages/contact', order: 4, type: 'page' },
],
showSocialInHeader: true,
showSocialInFooter: true,
metaKeywords: 'blog, art, galerie, musée',
metaDescription: 'Mon espace créatif personnel',
}
export const useCMSStore = create<CMSState>((set, get) => ({
isAuthenticated: false,
currentUser: null,
login: (username: string, password: string) => {
if (username === 'admin' && password === 'admin123') {
const user: User = {
id: '1',
username: 'admin',
email: 'admin@cms.com',
role: 'admin',
avatar: 'https://ui-avatars.com/api/?name=Admin&background=0ea5e9&color=fff',
}
set({ isAuthenticated: true, currentUser: user })
return true
}
return false
},
logout: () => set({ isAuthenticated: false, currentUser: null }),
posts: defaultPosts,
addPost: (post) => {
const newPost: Post = {
...post,
id: uuidv4(),
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
}
set((state) => ({ posts: [newPost, ...state.posts] }))
},
updatePost: (id, post) => {
set((state) => ({
posts: state.posts.map((p) =>
p.id === id ? { ...p, ...post, updatedAt: new Date().toISOString() } : p
),
}))
},
deletePost: (id) => {
set((state) => ({ posts: state.posts.filter((p) => p.id !== id) }))
},
getPost: (id) => get().posts.find((p) => p.id === id),
getPostBySlug: (slug) => get().posts.find((p) => p.slug === slug),
galleryItems: defaultGallery,
addGalleryItem: (item) => {
const newItem: GalleryItem = {
...item,
id: uuidv4(),
createdAt: new Date().toISOString(),
}
set((state) => ({ galleryItems: [newItem, ...state.galleryItems] }))
},
updateGalleryItem: (id, item) => {
set((state) => ({
galleryItems: state.galleryItems.map((g) =>
g.id === id ? { ...g, ...item } : g
),
}))
},
deleteGalleryItem: (id) => {
set((state) => ({ galleryItems: state.galleryItems.filter((g) => g.id !== id) }))
},
pages: defaultPages,
addPage: (page) => {
const newPage: Page = {
...page,
id: uuidv4(),
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
}
set((state) => ({ pages: [newPage, ...state.pages] }))
},
updatePage: (id, page) => {
set((state) => ({
pages: state.pages.map((p) =>
p.id === id ? { ...p, ...page, 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),
settings: defaultSettings,
updateSettings: (settings) => {
set((state) => ({ settings: { ...state.settings, ...settings } }))
},
updateNavItems: (items) => {
set((state) => ({
settings: { ...state.settings, headerNavItems: items },
}))
},
}))