feat: add src/lib/store.ts
This commit is contained in:
parent
a35978ea0c
commit
a899b1b568
|
|
@ -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 },
|
||||
}))
|
||||
},
|
||||
}))
|
||||
Loading…
Reference in New Issue