186 lines
4.3 KiB
TypeScript
186 lines
4.3 KiB
TypeScript
import { create } from 'zustand';
|
|
|
|
export interface Chapter {
|
|
number: number;
|
|
title: string;
|
|
summary: string;
|
|
content: string;
|
|
isGenerated: boolean;
|
|
}
|
|
|
|
export interface BookOutline {
|
|
title: string;
|
|
genre: string;
|
|
logline: string;
|
|
chapters: Chapter[];
|
|
}
|
|
|
|
export interface Character {
|
|
name: string;
|
|
role: string;
|
|
traits: string[];
|
|
motivation: string;
|
|
backstory: string;
|
|
}
|
|
|
|
export interface Book {
|
|
id: string;
|
|
title: string;
|
|
genre: string;
|
|
idea: string;
|
|
outline: BookOutline | null;
|
|
characters: Character[];
|
|
currentChapter: number;
|
|
coverId?: string;
|
|
createdAt: Date;
|
|
updatedAt: Date;
|
|
}
|
|
|
|
interface BookState {
|
|
books: Book[];
|
|
activeBook: Book | null;
|
|
isGenerating: boolean;
|
|
generationProgress: number;
|
|
|
|
// Actions
|
|
addBook: (book: Book) => void;
|
|
updateBook: (id: string, updates: Partial<Book>) => void;
|
|
deleteBook: (id: string) => void;
|
|
setActiveBook: (book: Book | null) => void;
|
|
setOutline: (outline: BookOutline) => void;
|
|
addCharacter: (character: Character) => void;
|
|
updateChapterContent: (chapterNumber: number, content: string) => void;
|
|
setCurrentChapter: (chapterNumber: number) => void;
|
|
setCoverForBook: (coverId: string) => void;
|
|
setIsGenerating: (isGenerating: boolean) => void;
|
|
setGenerationProgress: (progress: number) => void;
|
|
}
|
|
|
|
export const useBookStore = create<BookState>((set) => ({
|
|
books: [],
|
|
activeBook: null,
|
|
isGenerating: false,
|
|
generationProgress: 0,
|
|
|
|
addBook: (book) =>
|
|
set((state) => ({
|
|
books: [book, ...state.books],
|
|
activeBook: book,
|
|
})),
|
|
|
|
updateBook: (id, updates) =>
|
|
set((state) => ({
|
|
books: state.books.map((b) =>
|
|
b.id === id ? { ...b, ...updates, updatedAt: new Date() } : b
|
|
),
|
|
activeBook: state.activeBook?.id === id
|
|
? { ...state.activeBook, ...updates, updatedAt: new Date() }
|
|
: state.activeBook,
|
|
})),
|
|
|
|
deleteBook: (id) =>
|
|
set((state) => ({
|
|
books: state.books.filter((b) => b.id !== id),
|
|
activeBook: state.activeBook?.id === id ? null : state.activeBook,
|
|
})),
|
|
|
|
setActiveBook: (book) => set({ activeBook: book }),
|
|
|
|
setOutline: (outline) =>
|
|
set((state) => {
|
|
if (!state.activeBook) return state;
|
|
|
|
const updatedBook = {
|
|
...state.activeBook,
|
|
outline,
|
|
updatedAt: new Date(),
|
|
};
|
|
|
|
return {
|
|
activeBook: updatedBook,
|
|
books: state.books.map((b) =>
|
|
b.id === state.activeBook!.id ? updatedBook : b
|
|
),
|
|
};
|
|
}),
|
|
|
|
addCharacter: (character) =>
|
|
set((state) => {
|
|
if (!state.activeBook) return state;
|
|
|
|
const updatedBook = {
|
|
...state.activeBook,
|
|
characters: [...state.activeBook.characters, character],
|
|
updatedAt: new Date(),
|
|
};
|
|
|
|
return {
|
|
activeBook: updatedBook,
|
|
books: state.books.map((b) =>
|
|
b.id === state.activeBook!.id ? updatedBook : b
|
|
),
|
|
};
|
|
}),
|
|
|
|
updateChapterContent: (chapterNumber, content) =>
|
|
set((state) => {
|
|
if (!state.activeBook || !state.activeBook.outline) return state;
|
|
|
|
const updatedOutline = {
|
|
...state.activeBook.outline,
|
|
chapters: state.activeBook.outline.chapters.map((chapter) =>
|
|
chapter.number === chapterNumber
|
|
? { ...chapter, content, isGenerated: true }
|
|
: chapter
|
|
),
|
|
};
|
|
|
|
const updatedBook = {
|
|
...state.activeBook,
|
|
outline: updatedOutline,
|
|
updatedAt: new Date(),
|
|
};
|
|
|
|
return {
|
|
activeBook: updatedBook,
|
|
books: state.books.map((b) =>
|
|
b.id === state.activeBook!.id ? updatedBook : b
|
|
),
|
|
};
|
|
}),
|
|
|
|
setCurrentChapter: (chapterNumber) =>
|
|
set((state) => {
|
|
if (!state.activeBook) return state;
|
|
|
|
return {
|
|
activeBook: {
|
|
...state.activeBook,
|
|
currentChapter: chapterNumber,
|
|
},
|
|
};
|
|
}),
|
|
|
|
setCoverForBook: (coverId) =>
|
|
set((state) => {
|
|
if (!state.activeBook) return state;
|
|
|
|
const updatedBook = {
|
|
...state.activeBook,
|
|
coverId,
|
|
updatedAt: new Date(),
|
|
};
|
|
|
|
return {
|
|
activeBook: updatedBook,
|
|
books: state.books.map((b) =>
|
|
b.id === state.activeBook!.id ? updatedBook : b
|
|
),
|
|
};
|
|
}),
|
|
|
|
setIsGenerating: (isGenerating) => set({ isGenerating }),
|
|
|
|
setGenerationProgress: (progress) => set({ generationProgress: progress }),
|
|
}));
|