diff --git a/src/book-style.ts b/src/book-style.ts new file mode 100644 index 0000000..43f1afe --- /dev/null +++ b/src/book-style.ts @@ -0,0 +1,13 @@ +import { type BookFonts, fontStack } from "./model/fonts"; + +export function applyBookFonts(fonts: BookFonts): void { + const root = document.documentElement; + root.style.setProperty("--font-book", fontStack(fonts.body)); + root.style.setProperty("--font-heading", fontStack(fonts.heading)); +} + +export function resetBookFonts(): void { + const root = document.documentElement; + root.style.removeProperty("--font-book"); + root.style.removeProperty("--font-heading"); +} diff --git a/src/store/useBook.ts b/src/store/useBook.ts index 79414f5..05cb38c 100644 --- a/src/store/useBook.ts +++ b/src/store/useBook.ts @@ -14,6 +14,7 @@ import { } from "../model/book"; import { loadActiveChapter, saveActiveChapter } from "../editor/positions"; import { saveBook } from "../library"; +import { applyBookFonts, resetBookFonts } from "../book-style"; export const COVER_ID = "__cover__"; @@ -60,10 +61,12 @@ export const useBook = create((set, get) => ({ const saved = loadActiveChapter(normalized.id); const valid = saved === COVER_ID || normalized.chapters.some((c) => c.id === saved); const activeChapterId = valid ? (saved as string) : normalized.chapters[0]?.id ?? ""; + applyBookFonts(normalized.settings.fonts); set({ book: normalized, activeChapterId, dirty: false }); }, closeBook: () => { flushOutgoing(get().book, get().dirty); + resetBookFonts(); set({ book: null, activeChapterId: "", dirty: false }); }, setActiveChapter: (id) => set({ activeChapterId: id }), @@ -140,7 +143,12 @@ export const useBook = create((set, get) => ({ setMetadata: (patch) => set((s) => (s.book ? { dirty: true, book: { ...s.book, metadata: { ...s.book.metadata, ...patch } } } : {})), setSettings: (patch) => - set((s) => (s.book ? { dirty: true, book: { ...s.book, settings: { ...s.book.settings, ...patch } } } : {})), + set((s) => { + if (!s.book) return {}; + const book = { ...s.book, settings: { ...s.book.settings, ...patch } }; + if (patch.fonts) applyBookFonts(book.settings.fonts); + return { dirty: true, book }; + }), setCover: (patch) => set((s) => (s.book ? { dirty: true, book: { ...s.book, cover: { ...s.book.cover, ...patch } } } : {})), markSaved: () => set({ dirty: false }), diff --git a/src/styles/app.css b/src/styles/app.css index b4a1ae0..45ae0e3 100644 --- a/src/styles/app.css +++ b/src/styles/app.css @@ -427,6 +427,7 @@ body.resizing { } .chapter-title { + font-family: var(--font-heading); font-weight: 500; font-size: 31px; line-height: 1.16; @@ -434,6 +435,10 @@ body.resizing { margin: 15px 0 0; } +.prose :is(h1, h2, h3) { + font-family: var(--font-heading); +} + .prose p { font-size: 19px; line-height: 1.68; @@ -565,11 +570,15 @@ body.resizing { } .page .p-title { - font-family: var(--font-book); + font-family: var(--font-heading); font-size: 12px; margin-top: 5px; } +.page :is(h2, h3) { + font-family: var(--font-heading); +} + .page p { font-family: var(--font-book); font-size: 6.6px; @@ -620,7 +629,7 @@ body.resizing { border: 0; background: transparent; text-align: center; - font-family: var(--font-book); + font-family: var(--font-heading); font-weight: 500; font-size: 31px; line-height: 1.16; @@ -1432,7 +1441,7 @@ body.resizing { } .cover-title { - font-family: var(--font-book); + font-family: var(--font-heading); font-weight: 500; font-size: 9.5cqw; line-height: 1.08; @@ -2108,7 +2117,7 @@ body.resizing { } .device-title { - font-family: var(--font-book); + font-family: var(--font-heading); font-weight: 500; font-size: calc(24 * var(--dv-scale)); line-height: 1.2; @@ -2138,7 +2147,7 @@ body.resizing { .device-body h1, .device-body h2, .device-body h3 { - font-family: var(--font-book); + font-family: var(--font-heading); font-weight: 600; line-height: 1.25; margin: 1.2em 0 0.5em; diff --git a/src/styles/fonts.css b/src/styles/fonts.css index c92e953..eb5a191 100644 --- a/src/styles/fonts.css +++ b/src/styles/fonts.css @@ -29,3 +29,67 @@ font-style: italic; font-display: block; } + +@font-face { + font-family: "EB Garamond"; + src: url("/fonts/EBGaramond-VF.ttf") format("truetype-variations"); + font-weight: 400 800; + font-style: normal; + font-display: block; +} + +@font-face { + font-family: "EB Garamond"; + src: url("/fonts/EBGaramond-Italic-VF.ttf") format("truetype-variations"); + font-weight: 400 800; + font-style: italic; + font-display: block; +} + +@font-face { + font-family: "Lora"; + src: url("/fonts/Lora-VF.ttf") format("truetype-variations"); + font-weight: 400 700; + font-style: normal; + font-display: block; +} + +@font-face { + font-family: "Lora"; + src: url("/fonts/Lora-Italic-VF.ttf") format("truetype-variations"); + font-weight: 400 700; + font-style: italic; + font-display: block; +} + +@font-face { + font-family: "Source Serif 4"; + src: url("/fonts/SourceSerif4-VF.ttf") format("truetype-variations"); + font-weight: 200 900; + font-style: normal; + font-display: block; +} + +@font-face { + font-family: "Source Serif 4"; + src: url("/fonts/SourceSerif4-Italic-VF.ttf") format("truetype-variations"); + font-weight: 200 900; + font-style: italic; + font-display: block; +} + +@font-face { + font-family: "Fraunces"; + src: url("/fonts/Fraunces-VF.ttf") format("truetype-variations"); + font-weight: 100 900; + font-style: normal; + font-display: block; +} + +@font-face { + font-family: "Fraunces"; + src: url("/fonts/Fraunces-Italic-VF.ttf") format("truetype-variations"); + font-weight: 100 900; + font-style: italic; + font-display: block; +} diff --git a/src/styles/tokens.css b/src/styles/tokens.css index 409c3e6..d9e4a17 100644 --- a/src/styles/tokens.css +++ b/src/styles/tokens.css @@ -1,6 +1,7 @@ :root { --font-ui: "Hanken Grotesk", ui-sans-serif, system-ui, -apple-system, sans-serif; --font-book: "Literata", Georgia, "Times New Roman", serif; + --font-heading: "Literata", Georgia, "Times New Roman", serif; --r-sm: 5px; --r-md: 8px;