diff --git a/templates/reader.templ b/templates/reader.templ index d5f7b99..4930444 100644 --- a/templates/reader.templ +++ b/templates/reader.templ @@ -258,6 +258,7 @@ templ ReaderSettingsPanel() { Noto Serif Charis SIL IBM Plex Serif + Playwrite NZ Guides (Test) diff --git a/templates/reader_templ.go b/templates/reader_templ.go index 7448e54..1f75ac2 100644 --- a/templates/reader_templ.go +++ b/templates/reader_templ.go @@ -189,7 +189,7 @@ func ReaderSettingsPanel() templ.Component { templ_7745c5c3_Var7 = templ.NopComponent } ctx = templ.ClearChildren(ctx) - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 13, "⚙️ Settings─DisplayChrome Behavior Auto Hide Always Visible Hide on Scroll Progress Mode Pages Chapter Percentage Time LeftReading Theme☀️Light Paper Sepia Parchment Warm Candlelight Azure Sky Arctic Frost Dusk Sunset Twilight Forest Moss Slate OLED SolarizedTypographyReading Font Literata (Default) Crimson Text Source Serif 4 EB Garamond Libertinus Serif Noto Serif Charis SIL IBM Plex Serif Font Size 18px Line Height 1.6Navigation Double Page SpreadDone") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 13, "⚙️ Settings─DisplayChrome Behavior Auto Hide Always Visible Hide on Scroll Progress Mode Pages Chapter Percentage Time LeftReading Theme☀️Light Paper Sepia Parchment Warm Candlelight Azure Sky Arctic Frost Dusk Sunset Twilight Forest Moss Slate OLED SolarizedTypographyReading Font Literata (Default) Crimson Text Source Serif 4 EB Garamond Libertinus Serif Noto Serif Charis SIL IBM Plex Serif Playwrite NZ Guides (Test) Font Size 18px Line Height 1.6Navigation Double Page SpreadDone") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -293,7 +293,7 @@ func ReaderBookmarksPanel(bookmarks []Bookmark) templ.Component { var templ_7745c5c3_Var11 string templ_7745c5c3_Var11, templ_7745c5c3_Err = templ.JoinStringErrs(bookmark.CfiPosition) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/reader.templ`, Line: 358, Col: 38} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/reader.templ`, Line: 359, Col: 38} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var11)) if templ_7745c5c3_Err != nil { @@ -306,7 +306,7 @@ func ReaderBookmarksPanel(bookmarks []Bookmark) templ.Component { var templ_7745c5c3_Var12 string templ_7745c5c3_Var12, templ_7745c5c3_Err = templ.JoinStringErrs(bookmark.Title) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/reader.templ`, Line: 361, Col: 49} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/reader.templ`, Line: 362, Col: 49} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var12)) if templ_7745c5c3_Err != nil { @@ -319,7 +319,7 @@ func ReaderBookmarksPanel(bookmarks []Bookmark) templ.Component { var templ_7745c5c3_Var13 string templ_7745c5c3_Var13, templ_7745c5c3_Err = templ.JoinStringErrs(bookmark.Position) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/reader.templ`, Line: 363, Col: 27} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/reader.templ`, Line: 364, Col: 27} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var13)) if templ_7745c5c3_Err != nil { diff --git a/web/src/reader/reader.ts b/web/src/reader/reader.ts index 2ae1738..cd72e64 100644 --- a/web/src/reader/reader.ts +++ b/web/src/reader/reader.ts @@ -12,142 +12,76 @@ const FONT_MAP: Record = { "noto-serif": '"Noto Serif"', "charis-sil": '"Charis SIL"', "ibm-plex": '"IBM Plex Serif"', + "playwrite": '"Playwrite NZ Guides"', }; -const FONT_FACE_RULES = ` -@font-face { - font-family: "Literata"; - src: url("/static/fonts/literata/Literata-Variable.woff2") format("woff2"); - font-weight: 100 900; - font-style: normal; +interface FontFile { + family: string; + url: string; + weight: string; + style: string; } -@font-face { - font-family: "Literata"; - src: url("/static/fonts/literata/Literata-Italic-Variable.woff2") format("woff2"); - font-weight: 100 900; - font-style: italic; + +const FONT_FILES: FontFile[] = [ + { family: '"Literata"', url: "/static/fonts/literata/Literata-Variable.woff2", weight: "100 900", style: "normal" }, + { family: '"Literata"', url: "/static/fonts/literata/Literata-Italic-Variable.woff2", weight: "100 900", style: "italic" }, + { family: '"Crimson Pro"', url: "/static/fonts/crimson/CrimsonPro-Variable.woff2", weight: "100 900", style: "normal" }, + { family: '"Crimson Pro"', url: "/static/fonts/crimson/CrimsonPro-Italic-Variable.woff2", weight: "100 900", style: "italic" }, + { family: '"Source Serif 4"', url: "/static/fonts/source-serif/SourceSerif4-Variable.woff2", weight: "100 900", style: "normal" }, + { family: '"Source Serif 4"', url: "/static/fonts/source-serif/SourceSerif4-Italic-Variable.woff2", weight: "100 900", style: "italic" }, + { family: '"EB Garamond"', url: "/static/fonts/eb-garamond/EBGaramond-Variable.woff2", weight: "100 900", style: "normal" }, + { family: '"EB Garamond"', url: "/static/fonts/eb-garamond/EBGaramond-Italic-Variable.woff2", weight: "100 900", style: "italic" }, + { family: '"Libertinus Serif"', url: "/static/fonts/libertinus/LibertinusSerif-Regular.woff2", weight: "400", style: "normal" }, + { family: '"Libertinus Serif"', url: "/static/fonts/libertinus/LibertinusSerif-Bold.woff2", weight: "700", style: "normal" }, + { family: '"Libertinus Serif"', url: "/static/fonts/libertinus/LibertinusSerif-Italic.woff2", weight: "400", style: "italic" }, + { family: '"Libertinus Serif"', url: "/static/fonts/libertinus/LibertinusSerif-BoldItalic.woff2", weight: "700", style: "italic" }, + { family: '"Noto Serif"', url: "/static/fonts/noto-serif/NotoSerif-Variable.woff2", weight: "100 900", style: "normal" }, + { family: '"Noto Serif"', url: "/static/fonts/noto-serif/NotoSerif-Italic-Variable.woff2", weight: "100 900", style: "italic" }, + { family: '"Charis SIL"', url: "/static/fonts/charis-sil/CharisSIL-Regular.woff2", weight: "400", style: "normal" }, + { family: '"Charis SIL"', url: "/static/fonts/charis-sil/CharisSIL-Bold.woff2", weight: "700", style: "normal" }, + { family: '"Charis SIL"', url: "/static/fonts/charis-sil/CharisSIL-Italic.woff2", weight: "400", style: "italic" }, + { family: '"Charis SIL"', url: "/static/fonts/charis-sil/CharisSIL-BoldItalic.woff2", weight: "700", style: "italic" }, + { family: '"IBM Plex Serif"', url: "/static/fonts/ibm-plex/IBMPlexSerif-Regular.woff2", weight: "400", style: "normal" }, + { family: '"IBM Plex Serif"', url: "/static/fonts/ibm-plex/IBMPlexSerif-Bold.woff2", weight: "700", style: "normal" }, + { family: '"IBM Plex Serif"', url: "/static/fonts/ibm-plex/IBMPlexSerif-Italic.woff2", weight: "400", style: "italic" }, + { family: '"IBM Plex Serif"', url: "/static/fonts/ibm-plex/IBMPlexSerif-BoldItalic.woff2", weight: "700", style: "italic" }, + { family: '"Playwrite NZ Guides"', url: "/static/fonts/Playwrite_NZ_Guides/PlaywriteNZGuides-Regular.woff2", weight: "400", style: "normal" }, +]; + +let fontBlobUrls: Record = {}; +let fontsLoaded = false; + +async function loadFontBlobUrls(): Promise { + if (fontsLoaded) return; + const entries = await Promise.all( + FONT_FILES.map(async (f) => { + try { + const resp = await fetch(f.url); + const blob = await resp.blob(); + const blobUrl = URL.createObjectURL(blob); + return { key: f.url, blobUrl }; + } catch (_e) { + return { key: f.url, blobUrl: f.url }; + } + }), + ); + for (const { key, blobUrl } of entries) { + fontBlobUrls[key] = blobUrl; + } + fontsLoaded = true; } -@font-face { - font-family: "Crimson Pro"; - src: url("/static/fonts/crimson/CrimsonPro-Variable.woff2") format("woff2"); - font-weight: 100 900; - font-style: normal; + +function buildFontFaceCSS(): string { + return FONT_FILES.map((f) => { + const src = fontBlobUrls[f.url] ?? f.url; + return `@font-face { + font-family: ${f.family}; + src: url("${src}") format("woff2"); + font-weight: ${f.weight}; + font-style: ${f.style}; +}`; + }).join("\n"); } -@font-face { - font-family: "Crimson Pro"; - src: url("/static/fonts/crimson/CrimsonPro-Italic-Variable.woff2") format("woff2"); - font-weight: 100 900; - font-style: italic; -} -@font-face { - font-family: "Source Serif 4"; - src: url("/static/fonts/source-serif/SourceSerif4-Variable.woff2") format("woff2"); - font-weight: 100 900; - font-style: normal; -} -@font-face { - font-family: "Source Serif 4"; - src: url("/static/fonts/source-serif/SourceSerif4-Italic-Variable.woff2") format("woff2"); - font-weight: 100 900; - font-style: italic; -} -@font-face { - font-family: "EB Garamond"; - src: url("/static/fonts/eb-garamond/EBGaramond-Variable.woff2") format("woff2"); - font-weight: 100 900; - font-style: normal; -} -@font-face { - font-family: "EB Garamond"; - src: url("/static/fonts/eb-garamond/EBGaramond-Italic-Variable.woff2") format("woff2"); - font-weight: 100 900; - font-style: italic; -} -@font-face { - font-family: "Libertinus Serif"; - src: url("/static/fonts/libertinus/LibertinusSerif-Regular.woff2") format("woff2"); - font-weight: 400; - font-style: normal; -} -@font-face { - font-family: "Libertinus Serif"; - src: url("/static/fonts/libertinus/LibertinusSerif-Bold.woff2") format("woff2"); - font-weight: 700; - font-style: normal; -} -@font-face { - font-family: "Libertinus Serif"; - src: url("/static/fonts/libertinus/LibertinusSerif-Italic.woff2") format("woff2"); - font-weight: 400; - font-style: italic; -} -@font-face { - font-family: "Libertinus Serif"; - src: url("/static/fonts/libertinus/LibertinusSerif-BoldItalic.woff2") format("woff2"); - font-weight: 700; - font-style: italic; -} -@font-face { - font-family: "Noto Serif"; - src: url("/static/fonts/noto-serif/NotoSerif-Variable.woff2") format("woff2"); - font-weight: 100 900; - font-style: normal; -} -@font-face { - font-family: "Noto Serif"; - src: url("/static/fonts/noto-serif/NotoSerif-Italic-Variable.woff2") format("woff2"); - font-weight: 100 900; - font-style: italic; -} -@font-face { - font-family: "Charis SIL"; - src: url("/static/fonts/charis-sil/CharisSIL-Regular.woff2") format("woff2"); - font-weight: 400; - font-style: normal; -} -@font-face { - font-family: "Charis SIL"; - src: url("/static/fonts/charis-sil/CharisSIL-Bold.woff2") format("woff2"); - font-weight: 700; - font-style: normal; -} -@font-face { - font-family: "Charis SIL"; - src: url("/static/fonts/charis-sil/CharisSIL-Italic.woff2") format("woff2"); - font-weight: 400; - font-style: italic; -} -@font-face { - font-family: "Charis SIL"; - src: url("/static/fonts/charis-sil/CharisSIL-BoldItalic.woff2") format("woff2"); - font-weight: 700; - font-style: italic; -} -@font-face { - font-family: "IBM Plex Serif"; - src: url("/static/fonts/ibm-plex/IBMPlexSerif-Regular.woff2") format("woff2"); - font-weight: 400; - font-style: normal; -} -@font-face { - font-family: "IBM Plex Serif"; - src: url("/static/fonts/ibm-plex/IBMPlexSerif-Bold.woff2") format("woff2"); - font-weight: 700; - font-style: normal; -} -@font-face { - font-family: "IBM Plex Serif"; - src: url("/static/fonts/ibm-plex/IBMPlexSerif-Italic.woff2") format("woff2"); - font-weight: 400; - font-style: italic; -} -@font-face { - font-family: "IBM Plex Serif"; - src: url("/static/fonts/ibm-plex/IBMPlexSerif-BoldItalic.woff2") format("woff2"); - font-weight: 700; - font-style: italic; -} -`; interface ThemeColors { fg: string; @@ -259,7 +193,7 @@ const getCSS = ({ }` : ""; return ` - ${FONT_FACE_RULES} + ${buildFontFaceCSS()} @namespace epub "http://www.idpf.org/2007/ops"; html { color-scheme: light dark; @@ -362,6 +296,7 @@ document.addEventListener("alpine:init", () => { const themeColors = this.readingMode === "dark" ? themeSet.dark : themeSet.light; viewport.style.backgroundColor = themeColors.bg; this.view = document.getElementById("reader-view") as any; + await loadFontBlobUrls(); const resp = await fetch(config.fileUrl, { headers: { Authorization: `Bearer ${getToken()}` }, }); diff --git a/web/static/reader-fonts.css b/web/static/reader-fonts.css index 257e7ea..eb5cb88 100644 --- a/web/static/reader-fonts.css +++ b/web/static/reader-fonts.css @@ -227,3 +227,11 @@ font-weight: 700; font-style: italic; } + +@font-face { + font-family: "Playwrite NZ Guides"; + src: url("/static/fonts/Playwrite_NZ_Guides/PlaywriteNZGuides-Regular.woff2") + format("woff2"); + font-weight: 400; + font-style: normal; +}