mirror of
https://github.com/nicoverbruggen/ebook-fonts-showcase.git
synced 2026-03-21 20:40:10 +01:00
239 lines
7.2 KiB
JavaScript
239 lines
7.2 KiB
JavaScript
const sizeRange = document.getElementById("sizeRange");
|
|
const lineHeightRange = document.getElementById("lineHeightRange");
|
|
const sampleArea = document.getElementById("sampleArea");
|
|
const fontSelect = document.getElementById("fontSelect");
|
|
const fontListCore = document.getElementById("fontListCore");
|
|
const fontListExtra = document.getElementById("fontListExtra");
|
|
const extraFonts = document.getElementById("extraFonts");
|
|
const darkModeToggle = document.getElementById("darkModeToggle");
|
|
const bezelToggle = document.getElementById("bezelToggle");
|
|
const ligatureDisableToggle = document.getElementById("ligaturesToggle");
|
|
const reader = document.querySelector(".reader");
|
|
const sizeValue = document.getElementById("sizeValue");
|
|
const lineHeightValue = document.getElementById("lineHeightValue");
|
|
|
|
const fonts = new Map();
|
|
const preferredOrder = [
|
|
"Readerly",
|
|
"Cartisse",
|
|
"NV Readerly",
|
|
"NV Cartisse",
|
|
"NV NinePoint",
|
|
"NV Charis",
|
|
"NV Garamond",
|
|
"NV Jost"
|
|
];
|
|
let sampleHtml = "";
|
|
let activeFamily = "";
|
|
|
|
function parseFont(file) {
|
|
const fileName = file.split("/").pop().replace(".ttf", "");
|
|
const parts = fileName.split("-");
|
|
const rawFamily = parts.slice(0, -1).join("-") || fileName;
|
|
const rawStyle = parts.length > 1 ? parts[parts.length - 1] : "Regular";
|
|
const family = rawFamily.replace(/_/g, " ");
|
|
const styleToken = rawStyle || "Regular";
|
|
const isBold = styleToken.includes("Bold");
|
|
const isItalic = styleToken.includes("Italic");
|
|
return {
|
|
file,
|
|
family,
|
|
weight: isBold ? 700 : 400,
|
|
style: isItalic ? "italic" : "normal",
|
|
collection: file.includes("/core/") ? "Core" : "Extra"
|
|
};
|
|
}
|
|
|
|
function buildFontFaces() {
|
|
const styleEl = document.createElement("style");
|
|
const rules = [];
|
|
|
|
fontFiles.forEach((file) => {
|
|
const info = parseFont(file);
|
|
if (!fonts.has(info.family)) {
|
|
fonts.set(info.family, {
|
|
family: info.family,
|
|
collection: info.collection,
|
|
files: []
|
|
});
|
|
}
|
|
fonts.get(info.family).files.push(info);
|
|
|
|
rules.push(
|
|
`@font-face {\n` +
|
|
` font-family: "${info.family}";\n` +
|
|
` src: url("./${info.file}") format("truetype");\n` +
|
|
` font-weight: ${info.weight};\n` +
|
|
` font-style: ${info.style};\n` +
|
|
` font-display: swap;\n` +
|
|
`}`
|
|
);
|
|
});
|
|
|
|
styleEl.textContent = rules.join("\n");
|
|
document.head.appendChild(styleEl);
|
|
}
|
|
|
|
function sortFonts() {
|
|
return [...fonts.values()].sort((a, b) => {
|
|
const aIndex = preferredOrder.indexOf(a.family);
|
|
const bIndex = preferredOrder.indexOf(b.family);
|
|
if (aIndex !== -1 || bIndex !== -1) {
|
|
if (aIndex === -1) return 1;
|
|
if (bIndex === -1) return -1;
|
|
return aIndex - bIndex;
|
|
}
|
|
return a.family.localeCompare(b.family);
|
|
});
|
|
}
|
|
|
|
function createFontCard(font) {
|
|
const card = document.createElement("button");
|
|
card.type = "button";
|
|
card.className = "font-card";
|
|
if (font.family === "NV NinePoint") card.classList.add("is-ninepoint");
|
|
if (font.family === "NV Charis") card.classList.add("is-charis");
|
|
card.style.fontFamily = `"${font.family}", serif`;
|
|
card.innerHTML = `<p>${font.family}</p>`;
|
|
card.addEventListener("click", () => setActiveFont(font.family));
|
|
return card;
|
|
}
|
|
|
|
function createFontOption(font) {
|
|
const option = document.createElement("option");
|
|
option.value = font.family;
|
|
option.textContent = font.family;
|
|
return option;
|
|
}
|
|
|
|
function updateFontList() {
|
|
fontListCore.innerHTML = "";
|
|
fontListExtra.innerHTML = "";
|
|
fontSelect.innerHTML = "";
|
|
|
|
const coreGroup = document.createElement("optgroup");
|
|
coreGroup.label = "Core Collection";
|
|
const extraGroup = document.createElement("optgroup");
|
|
extraGroup.label = "Extra Collection";
|
|
|
|
sortFonts().forEach((font) => {
|
|
const target = font.collection === "Core" ? fontListCore : fontListExtra;
|
|
target.appendChild(createFontCard(font));
|
|
|
|
const group = font.collection === "Core" ? coreGroup : extraGroup;
|
|
group.appendChild(createFontOption(font));
|
|
});
|
|
|
|
fontSelect.appendChild(coreGroup);
|
|
fontSelect.appendChild(extraGroup);
|
|
|
|
const scrollHint = document.createElement("div");
|
|
scrollHint.className = "scroll-hint";
|
|
scrollHint.textContent = "Scroll to see more fonts";
|
|
fontListExtra.appendChild(scrollHint);
|
|
}
|
|
|
|
function setActiveFont(family) {
|
|
activeFamily = family;
|
|
renderPreview();
|
|
document.querySelectorAll(".font-card").forEach((card) => {
|
|
card.classList.toggle("is-active", card.textContent.trim() === family);
|
|
});
|
|
if (fontSelect.value !== family) {
|
|
fontSelect.value = family;
|
|
}
|
|
}
|
|
|
|
function updateValueDisplays() {
|
|
sizeValue.textContent = `(${sizeRange.value}pt)`;
|
|
lineHeightValue.textContent = `(${lineHeightRange.value})`;
|
|
}
|
|
|
|
function renderPreview() {
|
|
sampleArea.style.fontFamily = `"${activeFamily}", serif`;
|
|
sampleArea.style.fontSize = `${sizeRange.value}px`;
|
|
sampleArea.style.lineHeight = lineHeightRange.value;
|
|
sampleArea.style.fontWeight = "400";
|
|
sampleArea.style.fontStyle = "normal";
|
|
sampleArea.style.fontVariantLigatures = ligatureDisableToggle.checked ? "none" : "common-ligatures";
|
|
updateValueDisplays();
|
|
|
|
if (sampleHtml) {
|
|
sampleArea.innerHTML = sampleHtml;
|
|
}
|
|
}
|
|
|
|
function loadSampleText() {
|
|
fetch("assets/sample.html")
|
|
.then((r) => r.text())
|
|
.then((html) => {
|
|
sampleHtml = html;
|
|
renderPreview();
|
|
});
|
|
}
|
|
|
|
function setupScrollFade(list) {
|
|
function update() {
|
|
const atBottom = list.scrollHeight - list.scrollTop - list.clientHeight < 2;
|
|
list.classList.toggle("is-overflowing", !atBottom);
|
|
}
|
|
list.addEventListener("scroll", update);
|
|
extraFonts.addEventListener("toggle", update);
|
|
update();
|
|
}
|
|
|
|
function setupInteractions() {
|
|
sizeRange.addEventListener("input", renderPreview);
|
|
lineHeightRange.addEventListener("input", renderPreview);
|
|
fontSelect.addEventListener("change", (e) => setActiveFont(e.target.value));
|
|
darkModeToggle.addEventListener("change", (e) => {
|
|
reader.classList.toggle("is-dark", e.target.checked);
|
|
updateScreenIcon();
|
|
});
|
|
bezelToggle.addEventListener("change", (e) => {
|
|
reader.classList.toggle("is-bezel-dark", !e.target.checked);
|
|
});
|
|
ligatureDisableToggle.addEventListener("change", renderPreview);
|
|
if (fontListExtra) {
|
|
setupScrollFade(fontListExtra);
|
|
}
|
|
}
|
|
|
|
function updateScreenIcon() {
|
|
const sun = document.querySelector(".screen-icon--sun");
|
|
const moon = document.querySelector(".screen-icon--moon");
|
|
sun.style.display = darkModeToggle.checked ? "none" : "inline-block";
|
|
moon.style.display = darkModeToggle.checked ? "inline-block" : "none";
|
|
}
|
|
|
|
function syncToggles() {
|
|
darkModeToggle.checked = reader.classList.contains("is-dark");
|
|
bezelToggle.checked = !reader.classList.contains("is-bezel-dark");
|
|
ligatureDisableToggle.checked = false;
|
|
updateScreenIcon();
|
|
}
|
|
|
|
function resetControls() {
|
|
const isDesktop = window.matchMedia("(min-width: 1051px)").matches;
|
|
sizeRange.value = isDesktop ? "22" : "20";
|
|
lineHeightRange.value = "1.45";
|
|
}
|
|
|
|
function init() {
|
|
buildFontFaces();
|
|
updateFontList();
|
|
activeFamily = preferredOrder.find((f) => fonts.has(f)) || fonts.keys().next().value;
|
|
setupInteractions();
|
|
resetControls();
|
|
syncToggles();
|
|
loadSampleText();
|
|
|
|
if (extraFonts) {
|
|
extraFonts.open = window.matchMedia("(max-width: 1050px)").matches;
|
|
}
|
|
|
|
setActiveFont(activeFamily);
|
|
}
|
|
|
|
init();
|