Update font files with simplified naming and add reader font CSS

- Rename font files from VariableFont_wght/opsz,wght to Variable format
- Add reader-fonts.css with @font-face definitions for 10 serif fonts
- Fonts: Crimson Pro, EB Garamond, Literata, Noto Serif, Source Serif 4
- Each font includes regular and italic variants
This commit is contained in:
2026-04-04 01:00:13 -04:00
parent c1bc9dceb5
commit d52937e578
12 changed files with 289 additions and 24 deletions
+60 -24
View File
@@ -2,33 +2,72 @@
// Procedural style: Functions, not classes
interface TypographyConfig {
readingFont:
| "literata"
| "crimson"
| "source-serif"
| "eb-garamond"
| "libertinus"
| "noto-serif"
| "charis-sil"
| "ibm-plex"; // Bundled libre fonts
fontSize: number;
lineHeight: number;
textAlign: "left" | "justify";
marginTop: number;
marginBottom: number;
marginLeft: number;
marginRight: number;
textAlign: "left" | "right" | "center" | "justify";
textIndent: number;
hyphenate: boolean;
ligatures: boolean;
fontSmoothing: "auto" | "grayscale";
fontSmoothing: "auto" | "antialiased" | "subpixel-antialiased";
}
export function applyTypographyConfig(
element: HTMLElement,
function applyTypography(
container: HTMLElement,
config: TypographyConfig,
): void {
// Enable/disable ligatures
setLigatures(element, config.ligatures);
const content = container.querySelector(".ebook-content");
if (!content) return;
const fontStack = getFontStack(config.readingFont);
content.setAttribute(
"style",
`
font-family: ${fontStack};
font-size: ${config.fontSize}px;
line-height: ${config.lineHeight};
text-align: ${config.textAlign};
margin-top: ${config.marginTop}px;
margin-bottom: ${config.marginBottom}px;
margin-left: ${config.marginLeft}px;
margin-right: ${config.marginRight}px;
text-indent: ${config.textIndent}px;
-webkit-font-smoothing: ${config.fontSmoothing};
-moz-osx-font-smoothing: ${config.fontSmoothing === "grayscale" ? "grayscale" : "auto"};
`,
);
// Enable/disable hyphenation
if (config.hyphenate) {
enableHyphenation(element);
enableHyphenation(container, content as HTMLElement);
}
// Apply justification settings
setLigatures(content as HTMLElement, config.ligatures);
if (config.textAlign === "justify") {
enableJustification(element);
enableJustification(content as HTMLElement);
}
}
// Apply font smoothing
element.style.fontSmooth = config.fontSmoothing;
function enableHyphenation(container: HTMLElement, element: HTMLElement): void {
element.style.hyphens = "auto";
element.style.hyphenateLimitChars = "6 3 3";
const lang =
container.closest("[data-language]")?.getAttribute("data-language") || "en";
element.setAttribute("lang", lang);
}
function setLigatures(element: HTMLElement, enabled: boolean): void {
@@ -41,16 +80,6 @@ function setLigatures(element: HTMLElement, enabled: boolean): void {
}
}
function enableHyphenation(element: HTMLElement): void {
element.style.hyphens = "auto";
element.style.hyphenateLimitChars = "6 3 3";
// Add language attribute from EPUB metadata
const lang =
element.closest("[data-language]")?.getAttribute("data-language") || "en";
element.setAttribute("lang", lang);
}
function enableJustification(element: HTMLElement): void {
element.style.wordBreak = "normal";
element.style.overflowWrap = "break-word";
@@ -58,7 +87,14 @@ function enableJustification(element: HTMLElement): void {
element.style.letterSpacing = "0.01em";
}
export function measureReadingTime(
function updateTypographyConfig(
currentConfig: TypographyConfig,
newConfig: Partial<TypographyConfig>,
): TypographyConfig {
return { ...currentConfig, ...newConfig };
}
function measureReadingTime(
container: HTMLElement,
wordsPerMinute: number = 250,
): number {
@@ -72,7 +108,7 @@ export function measureReadingTime(
return Math.ceil(minutes);
}
export function getWordCount(container: HTMLElement): number {
function getWordCount(container: HTMLElement): number {
const content = container.querySelector(".ebook-content");
if (!content) return 0;
+229
View File
@@ -0,0 +1,229 @@
/* Libre reading fonts for Bookhoard ebook reader */
/* Literata - Designed for Google Play Books */
@font-face {
font-family: "Literata";
src: url("/static/fonts/literata/Literata-Variable.woff2") format("woff2");
font-weight: 400;
font-style: normal;
}
@font-face {
font-family: "Literata";
src: url("/static/fonts/literata/Literata-Variable.woff2") format("woff2");
font-weight: 700;
font-style: normal;
}
@font-face {
font-family: "Literata";
src: url("/static/fonts/literata/Literata-Italic-Variable.woff2")
format("woff2");
font-weight: 400;
font-style: italic;
}
@font-face {
font-family: "Literata";
src: url("/static/fonts/literata/Literata-Italic-Variable.woff2")
format("woff2");
font-weight: 700;
font-style: italic;
}
/* Crimson Text - Optimized for screen reading */
@font-face {
font-family: "Crimson Pro";
src: url("/static/fonts/crimson/CrimsonPro-Variable.woff2") format("woff2");
font-weight: 400;
font-style: normal;
}
@font-face {
font-family: "Crimson Pro";
src: url("/static/fonts/crimson/CrimsonPro-Variable.woff2") format("woff2");
font-weight: 700;
font-style: normal;
}
@font-face {
font-family: "Crimson Pro";
src: url("/static/fonts/crimson/CrimsonPro-Italic-Variable.woff2")
format("woff2");
font-weight: 400;
font-style: italic;
}
@font-face {
font-family: "Crimson Pro";
src: url("/static/fonts/crimson/CrimsonPro-Italic-Variable.woff2")
format("woff2");
font-weight: 700;
font-style: italic;
}
/* Source Serif 4 - Adobe professional quality */
@font-face {
font-family: "Source Serif 4";
src: url("/static/fonts/source-serif/SourceSerif4-Variable.woff2")
format("woff2");
font-weight: 400;
font-style: normal;
}
@font-face {
font-family: "Source Serif 4";
src: url("/static/fonts/source-serif/SourceSerif4-Variable.woff2")
format("woff2");
font-weight: 700;
font-style: normal;
}
@font-face {
font-family: "Source Serif 4";
src: url("/static/fonts/source-serif/SourceSerif4-Italic-Variable.woff2")
format("woff2");
font-weight: 400;
font-style: italic;
}
@font-face {
font-family: "Source Serif 4";
src: url("/static/fonts/source-serif/SourceSerif4-Italic-Variable.woff2")
format("woff2");
font-weight: 700;
font-style: italic;
}
/* EB Garamond - Classic elegance */
@font-face {
font-family: "EB Garamond";
src: url("/static/fonts/eb-garamond/EBGaramond-Variable.woff2")
format("woff2");
font-weight: 400;
font-style: normal;
}
@font-face {
font-family: "EB Garamond";
src: url("/static/fonts/eb-garamond/EBGaramond-Variable.woff2")
format("woff2");
font-weight: 700;
font-style: normal;
}
@font-face {
font-family: "EB Garamond";
src: url("/static/fonts/eb-garamond/EBGaramond-Italic-Variable.woff2")
format("woff2");
font-weight: 400;
font-style: italic;
}
@font-face {
font-family: "EB Garamond";
src: url("/static/fonts/eb-garamond/EBGaramond-Italic-Variable.woff2")
format("woff2");
font-weight: 700;
font-style: italic;
}
/* Libertinus Serif - Academic/technical */
@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-style: normal;
font-weight: 700;
}
@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;
}
/* Noto Serif - Maximum language support */
@font-face {
font-family: "Noto Serif";
src: url("/static/fonts/noto-serif/NotoSerif-Variable.woff2") format("woff2");
font-weight: 400;
font-style: normal;
}
@font-face {
font-family: "Noto Serif";
src: url("/static/fonts/noto-serif/NotoSerif-Variable.woff2") format("woff2");
font-weight: 700;
font-style: normal;
}
@font-face {
font-family: "Noto Serif";
src: url("/static/fonts/noto-serif/NotoSerif-Italic-Variable.woff2")
format("woff2");
font-weight: 400;
font-style: italic;
}
@font-face {
font-family: "Noto Serif";
src: url("/static/fonts/noto-serif/NotoSerif-Italic-Variable.woff2")
format("woff2");
font-weight: 700;
font-style: italic;
}
/* Charis SIL - Multilingual specialist */
@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;
}
/* IBM Plex Serif - Modern & versatile */
@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;
}