mirror of
https://github.com/priyanshujain/margin.git
synced 2026-10-02 11:07:04 +00:00
feat(model): add document model and book store
This commit is contained in:
1 parent
03a05b7e8f
commit
c76e5b0a5f
2 files changed
+129
No files matched your search
@@ -0,0 +1,81 @@
|
||||
import type { JSONContent } from "@tiptap/core";
|
||||
|
||||
export type TrimSize = "6x9" | "5.5x8.5" | "5x8" | "a5";
|
||||
export type FigurePlacement = "inline" | "full-width" | "full-page" | "float-top";
|
||||
|
||||
export interface BookMetadata {
|
||||
title: string;
|
||||
subtitle: string;
|
||||
author: string;
|
||||
isbn: string;
|
||||
language: string;
|
||||
}
|
||||
|
||||
export interface BookSettings {
|
||||
trim: TrimSize;
|
||||
bleed: boolean;
|
||||
}
|
||||
|
||||
export interface Chapter {
|
||||
id: string;
|
||||
title: string;
|
||||
content: JSONContent;
|
||||
}
|
||||
|
||||
export interface Book {
|
||||
schema: "margin/1";
|
||||
metadata: BookMetadata;
|
||||
theme: string;
|
||||
settings: BookSettings;
|
||||
chapters: Chapter[];
|
||||
}
|
||||
|
||||
function paragraph(text: string): JSONContent {
|
||||
return { type: "paragraph", content: [{ type: "text", text }] };
|
||||
}
|
||||
|
||||
function emptyDoc(): JSONContent {
|
||||
return { type: "doc", content: [{ type: "paragraph" }] };
|
||||
}
|
||||
|
||||
export function createChapter(title = "Untitled chapter"): Chapter {
|
||||
return { id: crypto.randomUUID(), title, content: emptyDoc() };
|
||||
}
|
||||
|
||||
export function createBook(): Book {
|
||||
return {
|
||||
schema: "margin/1",
|
||||
metadata: { title: "Untitled", subtitle: "", author: "", isbn: "", language: "en" },
|
||||
theme: "quiet-press",
|
||||
settings: { trim: "6x9", bleed: true },
|
||||
chapters: [createChapter("Chapter One")],
|
||||
};
|
||||
}
|
||||
|
||||
export function starterBook(): Book {
|
||||
const book = createBook();
|
||||
book.chapters = [
|
||||
{
|
||||
id: crypto.randomUUID(),
|
||||
title: "The Lighthouse",
|
||||
content: {
|
||||
type: "doc",
|
||||
content: [
|
||||
paragraph(
|
||||
"The lamp had not been lit in thirty years, and yet the islanders still set their clocks by a light that no longer came. Mara climbed the iron stair each evening out of a habit older than memory, and each evening she found the same dark glass waiting, patient as the sea."
|
||||
),
|
||||
paragraph(
|
||||
"Her grandfather had kept the flame. Her mother had let it die. Between those two facts lay the whole of the family's quarrel with the water, and Mara had inherited both the quarrel and the key that opened the lantern room."
|
||||
),
|
||||
{ type: "horizontalRule" },
|
||||
paragraph(
|
||||
"Morning came the color of pewter. The tide had left its usual accounting along the shingle, and Mara walked the length of it without hurry, naming each thing as her grandfather had named them to her."
|
||||
),
|
||||
],
|
||||
},
|
||||
},
|
||||
createChapter("Salt and Iron"),
|
||||
createChapter("What the Tide Left"),
|
||||
];
|
||||
return book;
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
import { create } from "zustand";
|
||||
import type { JSONContent } from "@tiptap/core";
|
||||
import { type Book, createChapter, starterBook } from "../model/book";
|
||||
|
||||
interface BookState {
|
||||
book: Book;
|
||||
activeChapterId: string;
|
||||
dirty: boolean;
|
||||
setActiveChapter: (id: string) => void;
|
||||
setChapterContent: (id: string, content: JSONContent) => void;
|
||||
setChapterTitle: (id: string, title: string) => void;
|
||||
addChapter: () => void;
|
||||
}
|
||||
|
||||
export const useBook = create<BookState>((set) => {
|
||||
const book = starterBook();
|
||||
return {
|
||||
book,
|
||||
activeChapterId: book.chapters[0].id,
|
||||
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)),
|
||||
},
|
||||
})),
|
||||
setChapterTitle: (id, title) =>
|
||||
set((s) => ({
|
||||
dirty: true,
|
||||
book: {
|
||||
...s.book,
|
||||
chapters: s.book.chapters.map((c) => (c.id === id ? { ...c, title } : c)),
|
||||
},
|
||||
})),
|
||||
addChapter: () =>
|
||||
set((s) => {
|
||||
const chapter = createChapter();
|
||||
return {
|
||||
activeChapterId: chapter.id,
|
||||
dirty: true,
|
||||
book: { ...s.book, chapters: [...s.book.chapters, chapter] },
|
||||
};
|
||||
}),
|
||||
};
|
||||
});
|
||||
Reference in new issue
Block a user