refactor(store): nullable open book with open/close for library nav

This commit is contained in:
pj committed 2026-06-20 15:09:13 -04:00
1 parent 4896e10aba
commit a6404847d1
1 file changed
+26 -37
+26 -37
View File
@@ -1,61 +1,50 @@
import { create } from "zustand";
import type { JSONContent } from "@tiptap/core";
import { type Book, type BookMetadata, type BookSettings, createChapter, starterBook } from "../model/book";
import { type Book, type BookMetadata, type BookSettings, createChapter } from "../model/book";
interface BookState {
book: Book;
book: Book | null;
activeChapterId: string;
path: string | null;
dirty: boolean;
openBook: (book: Book) => void;
closeBook: () => void;
setActiveChapter: (id: string) => void;
setChapterContent: (id: string, content: JSONContent) => void;
setChapterTitle: (id: string, title: string) => void;
addChapter: () => void;
setMetadata: (patch: Partial<BookMetadata>) => void;
setSettings: (patch: Partial<BookSettings>) => void;
replaceBook: (book: Book, path: string) => void;
markSaved: (path: string) => void;
markSaved: () => void;
}
export const useBook = create<BookState>((set) => {
const book = starterBook();
return {
book,
activeChapterId: book.chapters[0].id,
path: null,
export const useBook = create<BookState>((set) => ({
book: null,
activeChapterId: "",
dirty: false,
openBook: (book) => set({ book, activeChapterId: book.chapters[0]?.id ?? "", dirty: false }),
closeBook: () => set({ book: null, activeChapterId: "", dirty: false }),
setActiveChapter: (id) => set({ activeChapterId: id }),
setChapterContent: (id, content) =>
set((s) => ({
dirty: true,
book: {
...s.book,
chapters: s.book.chapters.map((c) => (c.id === id ? { ...c, content } : c)),
},
})),
set((s) =>
s.book
? { dirty: true, book: { ...s.book, chapters: s.book.chapters.map((c) => (c.id === id ? { ...c, content } : c)) } }
: {}
),
setChapterTitle: (id, title) =>
set((s) => ({
dirty: true,
book: {
...s.book,
chapters: s.book.chapters.map((c) => (c.id === id ? { ...c, title } : c)),
},
})),
set((s) =>
s.book
? { dirty: true, book: { ...s.book, chapters: s.book.chapters.map((c) => (c.id === id ? { ...c, title } : c)) } }
: {}
),
addChapter: () =>
set((s) => {
if (!s.book) return {};
const chapter = createChapter();
return {
activeChapterId: chapter.id,
dirty: true,
book: { ...s.book, chapters: [...s.book.chapters, chapter] },
};
return { activeChapterId: chapter.id, dirty: true, book: { ...s.book, chapters: [...s.book.chapters, chapter] } };
}),
setMetadata: (patch) =>
set((s) => ({ dirty: true, book: { ...s.book, metadata: { ...s.book.metadata, ...patch } } })),
set((s) => (s.book ? { dirty: true, book: { ...s.book, metadata: { ...s.book.metadata, ...patch } } } : {})),
setSettings: (patch) =>
set((s) => ({ dirty: true, book: { ...s.book, settings: { ...s.book.settings, ...patch } } })),
replaceBook: (book, path) =>
set({ book, activeChapterId: book.chapters[0]?.id ?? "", path, dirty: false }),
markSaved: (path) => set({ path, dirty: false }),
};
});
set((s) => (s.book ? { dirty: true, book: { ...s.book, settings: { ...s.book.settings, ...patch } } } : {})),
markSaved: () => set({ dirty: false }),
}));