Add Neon and Meridian glass themes, bundled fonts, configurable recovery backup location, autosave and UI polish
This commit is contained in:
parent
aaa491424d
commit
b74cfe98ab
59 changed files with 1848 additions and 185 deletions
108
scripts/fetch-fonts.mjs
Normal file
108
scripts/fetch-fonts.mjs
Normal file
|
|
@ -0,0 +1,108 @@
|
|||
// One-time setup script: copy locally-bundled Google Fonts (.woff2) into
|
||||
// public/fonts and generate the offline @font-face CSS (src/renderer/fonts.css).
|
||||
//
|
||||
// Run ONCE while online (or with @fontsource packages already installed via npm):
|
||||
// node scripts/fetch-fonts.mjs
|
||||
//
|
||||
// After this, the app never requests fonts from the network at runtime.
|
||||
//
|
||||
// Fonts are sourced from the @fontsource packages (already in node_modules
|
||||
// after `npm i @fontsource/<font>`). If a package is missing, the script
|
||||
// falls back to downloading the file from the jsDelivr CDN.
|
||||
|
||||
import fs from "fs";
|
||||
import path from "path";
|
||||
import { fileURLToPath } from "url";
|
||||
|
||||
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
||||
const root = path.resolve(__dirname, "..");
|
||||
|
||||
// Each entry: display name, @fontsource package, file slug, CSS fallback.
|
||||
const FONTS = [
|
||||
{ name: "Inter", pkg: "inter", slug: "inter", fallback: "sans-serif" },
|
||||
{ name: "Roboto", pkg: "roboto", slug: "roboto", fallback: "sans-serif" },
|
||||
{ name: "Open Sans", pkg: "open-sans", slug: "open-sans", fallback: "sans-serif" },
|
||||
{ name: "Lato", pkg: "lato", slug: "lato", fallback: "sans-serif" },
|
||||
{ name: "Montserrat", pkg: "montserrat", slug: "montserrat", fallback: "sans-serif" },
|
||||
{ name: "Poppins", pkg: "poppins", slug: "poppins", fallback: "sans-serif" },
|
||||
{ name: "Oswald", pkg: "oswald", slug: "oswald", fallback: "sans-serif" },
|
||||
{ name: "Roboto Slab", pkg: "roboto-slab", slug: "roboto-slab", fallback: "serif" },
|
||||
{ name: "Merriweather", pkg: "merriweather", slug: "merriweather", fallback: "serif" },
|
||||
{ name: "Playfair Display", pkg: "playfair-display", slug: "playfair-display", fallback: "serif" },
|
||||
{ name: "Raleway", pkg: "raleway", slug: "raleway", fallback: "sans-serif" },
|
||||
{ name: "Nunito", pkg: "nunito", slug: "nunito", fallback: "sans-serif" },
|
||||
{ name: "Ubuntu", pkg: "ubuntu", slug: "ubuntu", fallback: "sans-serif" },
|
||||
{ name: "Source Sans 3", pkg: "source-sans-3", slug: "source-sans-3", fallback: "sans-serif" },
|
||||
{ name: "Noto Sans", pkg: "noto-sans", slug: "noto-sans", fallback: "sans-serif" },
|
||||
{ name: "PT Sans", pkg: "pt-sans", slug: "pt-sans", fallback: "sans-serif" },
|
||||
{ name: "Libre Baskerville", pkg: "libre-baskerville", slug: "libre-baskerville", fallback: "serif" },
|
||||
{ name: "DM Sans", pkg: "dm-sans", slug: "dm-sans", fallback: "sans-serif" },
|
||||
{ name: "Quicksand", pkg: "quicksand", slug: "quicksand", fallback: "sans-serif" },
|
||||
{ name: "Work Sans", pkg: "work-sans", slug: "work-sans", fallback: "sans-serif" },
|
||||
];
|
||||
|
||||
const publicFonts = path.join(root, "public", "fonts");
|
||||
fs.mkdirSync(publicFonts, { recursive: true });
|
||||
|
||||
async function copyOrDownload(srcRel, destFile, cdnUrl) {
|
||||
const src = path.join(root, srcRel);
|
||||
const dest = path.join(publicFonts, destFile);
|
||||
if (fs.existsSync(src)) {
|
||||
fs.copyFileSync(src, dest);
|
||||
return true;
|
||||
}
|
||||
// Fallback: download once from jsDelivr CDN.
|
||||
try {
|
||||
const res = await fetch(cdnUrl);
|
||||
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
||||
const buf = Buffer.from(await res.arrayBuffer());
|
||||
fs.writeFileSync(dest, buf);
|
||||
return true;
|
||||
} catch (err) {
|
||||
console.error(` ! failed: ${destFile} (${err.message})`);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
let css = "/* AUTO-GENERATED by scripts/fetch-fonts.mjs — do not edit by hand.\n" +
|
||||
" All fonts are bundled locally; no network requests at runtime. */\n\n";
|
||||
|
||||
let ok = 0;
|
||||
const report = [];
|
||||
for (const f of FONTS) {
|
||||
const regularDest = `${f.slug}-regular.woff2`;
|
||||
const boldDest = `${f.slug}-bold.woff2`;
|
||||
const rOk = await copyOrDownload(
|
||||
`node_modules/@fontsource/${f.pkg}/files/${f.slug}-latin-400-normal.woff2`,
|
||||
regularDest,
|
||||
`https://cdn.jsdelivr.net/npm/@fontsource/${f.pkg}/files/${f.slug}-latin-400-normal.woff2`
|
||||
);
|
||||
const bOk = await copyOrDownload(
|
||||
`node_modules/@fontsource/${f.pkg}/files/${f.slug}-latin-700-normal.woff2`,
|
||||
boldDest,
|
||||
`https://cdn.jsdelivr.net/npm/@fontsource/${f.pkg}/files/${f.slug}-latin-700-normal.woff2`
|
||||
);
|
||||
if (rOk && bOk) ok++;
|
||||
report.push(` ${f.name}: public/fonts/${regularDest} + public/fonts/${boldDest}`);
|
||||
css += `@font-face {\n` +
|
||||
` font-family: "${f.name}";\n` +
|
||||
` font-style: normal;\n` +
|
||||
` font-weight: 400;\n` +
|
||||
` font-display: swap;\n` +
|
||||
` src: url("./fonts/${regularDest}") format("woff2");\n` +
|
||||
`}\n` +
|
||||
`@font-face {\n` +
|
||||
` font-family: "${f.name}";\n` +
|
||||
` font-style: normal;\n` +
|
||||
` font-weight: 700;\n` +
|
||||
` font-display: swap;\n` +
|
||||
` src: url("./fonts/${boldDest}") format("woff2");\n` +
|
||||
`}\n\n`;
|
||||
}
|
||||
|
||||
fs.writeFileSync(path.join(root, "src", "renderer", "fonts.css"), css);
|
||||
|
||||
console.log(`Copied ${ok}/${FONTS.length} font families (2 files each).`);
|
||||
console.log("Files placed in public/fonts/:");
|
||||
console.log(report.join("\n"));
|
||||
console.log(`\nGenerated src/renderer/fonts.css (${ok * 2} @font-face rules).`);
|
||||
Loading…
Add table
Add a link
Reference in a new issue