15 gebündelte Open-Source-Schriften statt Systemfonts

Text-Werkzeug nutzte bisher OS-abhängige Systemfonts (Helvetica/Arial/
Times/Georgia/Courier) — Darstellung und PDF-Export waren damit nicht
plattformunabhängig deterministisch. Jetzt 15 kuratierte SIL-OFL-
Schriften lokal als WOFF2 gebündelt (je mit OFL.txt-Lizenz):
Inter, Work Sans, IBM Plex Sans/Mono, Source Sans 3, Space Grotesk,
Manrope, Outfit, DM Sans, Public Sans, Karla, Rubik, Jost, Archivo,
Source Serif 4. Ein späterer Einstellungen-Dialog kann weitere
Schriften nachladen.
This commit is contained in:
2026-07-04 05:19:53 +02:00
parent 7e8764b21b
commit 8b6b9291a1
72 changed files with 1860 additions and 7 deletions
+1
View File
@@ -5,6 +5,7 @@ import { ErrorBoundary } from "./ui/ErrorBoundary";
import { getLanguage, setLanguage } from "./i18n";
import type { Language } from "./i18n";
import "./styles.css";
import "./text/fonts.css";
// Sprach-Naht für Werkzeuge/Tests (und einen späteren Umschalter): die i18n-
// Steuerung am window verfügbar machen. Identifier englisch; Werte übersetzbar.
+441
View File
@@ -0,0 +1,441 @@
/*
* Lokal gebuendelte Open-Source-Schriften (SIL Open Font License) fuer das
* Text-Werkzeug (Raumstempel/Text-Objekte). Damit ist die Schriftdarstellung
* unabhaengig vom Betriebssystem und der PDF-Export deterministisch.
*
* Jede Schrift bringt ihre OFL.txt unter public/fonts/<slug>/OFL.txt mit.
* Herkunft: Google Fonts (css2-API), WOFF2, Subset "latin".
*/
@font-face {
font-family: "Inter";
font-style: normal;
font-weight: 400;
font-display: swap;
src: url("/fonts/inter/inter-400-normal.woff2") format("woff2");
}
@font-face {
font-family: "Inter";
font-style: normal;
font-weight: 700;
font-display: swap;
src: url("/fonts/inter/inter-700-normal.woff2") format("woff2");
}
@font-face {
font-family: "Inter";
font-style: italic;
font-weight: 400;
font-display: swap;
src: url("/fonts/inter/inter-400-italic.woff2") format("woff2");
}
@font-face {
font-family: "Inter";
font-style: italic;
font-weight: 700;
font-display: swap;
src: url("/fonts/inter/inter-700-italic.woff2") format("woff2");
}
@font-face {
font-family: "Work Sans";
font-style: normal;
font-weight: 400;
font-display: swap;
src: url("/fonts/work-sans/work-sans-400-normal.woff2") format("woff2");
}
@font-face {
font-family: "Work Sans";
font-style: normal;
font-weight: 700;
font-display: swap;
src: url("/fonts/work-sans/work-sans-700-normal.woff2") format("woff2");
}
@font-face {
font-family: "Work Sans";
font-style: italic;
font-weight: 400;
font-display: swap;
src: url("/fonts/work-sans/work-sans-400-italic.woff2") format("woff2");
}
@font-face {
font-family: "Work Sans";
font-style: italic;
font-weight: 700;
font-display: swap;
src: url("/fonts/work-sans/work-sans-700-italic.woff2") format("woff2");
}
@font-face {
font-family: "IBM Plex Sans";
font-style: normal;
font-weight: 400;
font-display: swap;
src: url("/fonts/ibm-plex-sans/ibm-plex-sans-400-normal.woff2") format("woff2");
}
@font-face {
font-family: "IBM Plex Sans";
font-style: normal;
font-weight: 700;
font-display: swap;
src: url("/fonts/ibm-plex-sans/ibm-plex-sans-700-normal.woff2") format("woff2");
}
@font-face {
font-family: "IBM Plex Sans";
font-style: italic;
font-weight: 400;
font-display: swap;
src: url("/fonts/ibm-plex-sans/ibm-plex-sans-400-italic.woff2") format("woff2");
}
@font-face {
font-family: "IBM Plex Sans";
font-style: italic;
font-weight: 700;
font-display: swap;
src: url("/fonts/ibm-plex-sans/ibm-plex-sans-700-italic.woff2") format("woff2");
}
@font-face {
font-family: "IBM Plex Mono";
font-style: normal;
font-weight: 400;
font-display: swap;
src: url("/fonts/ibm-plex-mono/ibm-plex-mono-400-normal.woff2") format("woff2");
}
@font-face {
font-family: "IBM Plex Mono";
font-style: normal;
font-weight: 700;
font-display: swap;
src: url("/fonts/ibm-plex-mono/ibm-plex-mono-700-normal.woff2") format("woff2");
}
@font-face {
font-family: "IBM Plex Mono";
font-style: italic;
font-weight: 400;
font-display: swap;
src: url("/fonts/ibm-plex-mono/ibm-plex-mono-400-italic.woff2") format("woff2");
}
@font-face {
font-family: "IBM Plex Mono";
font-style: italic;
font-weight: 700;
font-display: swap;
src: url("/fonts/ibm-plex-mono/ibm-plex-mono-700-italic.woff2") format("woff2");
}
@font-face {
font-family: "Source Sans 3";
font-style: normal;
font-weight: 400;
font-display: swap;
src: url("/fonts/source-sans-3/source-sans-3-400-normal.woff2") format("woff2");
}
@font-face {
font-family: "Source Sans 3";
font-style: normal;
font-weight: 700;
font-display: swap;
src: url("/fonts/source-sans-3/source-sans-3-700-normal.woff2") format("woff2");
}
@font-face {
font-family: "Source Sans 3";
font-style: italic;
font-weight: 400;
font-display: swap;
src: url("/fonts/source-sans-3/source-sans-3-400-italic.woff2") format("woff2");
}
@font-face {
font-family: "Source Sans 3";
font-style: italic;
font-weight: 700;
font-display: swap;
src: url("/fonts/source-sans-3/source-sans-3-700-italic.woff2") format("woff2");
}
@font-face {
font-family: "Space Grotesk";
font-style: normal;
font-weight: 400;
font-display: swap;
src: url("/fonts/space-grotesk/space-grotesk-400-normal.woff2") format("woff2");
}
@font-face {
font-family: "Space Grotesk";
font-style: normal;
font-weight: 700;
font-display: swap;
src: url("/fonts/space-grotesk/space-grotesk-700-normal.woff2") format("woff2");
}
@font-face {
font-family: "Manrope";
font-style: normal;
font-weight: 400;
font-display: swap;
src: url("/fonts/manrope/manrope-400-normal.woff2") format("woff2");
}
@font-face {
font-family: "Manrope";
font-style: normal;
font-weight: 700;
font-display: swap;
src: url("/fonts/manrope/manrope-700-normal.woff2") format("woff2");
}
@font-face {
font-family: "Outfit";
font-style: normal;
font-weight: 400;
font-display: swap;
src: url("/fonts/outfit/outfit-400-normal.woff2") format("woff2");
}
@font-face {
font-family: "Outfit";
font-style: normal;
font-weight: 700;
font-display: swap;
src: url("/fonts/outfit/outfit-700-normal.woff2") format("woff2");
}
@font-face {
font-family: "DM Sans";
font-style: normal;
font-weight: 400;
font-display: swap;
src: url("/fonts/dm-sans/dm-sans-400-normal.woff2") format("woff2");
}
@font-face {
font-family: "DM Sans";
font-style: normal;
font-weight: 700;
font-display: swap;
src: url("/fonts/dm-sans/dm-sans-700-normal.woff2") format("woff2");
}
@font-face {
font-family: "DM Sans";
font-style: italic;
font-weight: 400;
font-display: swap;
src: url("/fonts/dm-sans/dm-sans-400-italic.woff2") format("woff2");
}
@font-face {
font-family: "DM Sans";
font-style: italic;
font-weight: 700;
font-display: swap;
src: url("/fonts/dm-sans/dm-sans-700-italic.woff2") format("woff2");
}
@font-face {
font-family: "Public Sans";
font-style: normal;
font-weight: 400;
font-display: swap;
src: url("/fonts/public-sans/public-sans-400-normal.woff2") format("woff2");
}
@font-face {
font-family: "Public Sans";
font-style: normal;
font-weight: 700;
font-display: swap;
src: url("/fonts/public-sans/public-sans-700-normal.woff2") format("woff2");
}
@font-face {
font-family: "Public Sans";
font-style: italic;
font-weight: 400;
font-display: swap;
src: url("/fonts/public-sans/public-sans-400-italic.woff2") format("woff2");
}
@font-face {
font-family: "Public Sans";
font-style: italic;
font-weight: 700;
font-display: swap;
src: url("/fonts/public-sans/public-sans-700-italic.woff2") format("woff2");
}
@font-face {
font-family: "Karla";
font-style: normal;
font-weight: 400;
font-display: swap;
src: url("/fonts/karla/karla-400-normal.woff2") format("woff2");
}
@font-face {
font-family: "Karla";
font-style: normal;
font-weight: 700;
font-display: swap;
src: url("/fonts/karla/karla-700-normal.woff2") format("woff2");
}
@font-face {
font-family: "Karla";
font-style: italic;
font-weight: 400;
font-display: swap;
src: url("/fonts/karla/karla-400-italic.woff2") format("woff2");
}
@font-face {
font-family: "Karla";
font-style: italic;
font-weight: 700;
font-display: swap;
src: url("/fonts/karla/karla-700-italic.woff2") format("woff2");
}
@font-face {
font-family: "Rubik";
font-style: normal;
font-weight: 400;
font-display: swap;
src: url("/fonts/rubik/rubik-400-normal.woff2") format("woff2");
}
@font-face {
font-family: "Rubik";
font-style: normal;
font-weight: 700;
font-display: swap;
src: url("/fonts/rubik/rubik-700-normal.woff2") format("woff2");
}
@font-face {
font-family: "Rubik";
font-style: italic;
font-weight: 400;
font-display: swap;
src: url("/fonts/rubik/rubik-400-italic.woff2") format("woff2");
}
@font-face {
font-family: "Rubik";
font-style: italic;
font-weight: 700;
font-display: swap;
src: url("/fonts/rubik/rubik-700-italic.woff2") format("woff2");
}
@font-face {
font-family: "Jost";
font-style: normal;
font-weight: 400;
font-display: swap;
src: url("/fonts/jost/jost-400-normal.woff2") format("woff2");
}
@font-face {
font-family: "Jost";
font-style: normal;
font-weight: 700;
font-display: swap;
src: url("/fonts/jost/jost-700-normal.woff2") format("woff2");
}
@font-face {
font-family: "Jost";
font-style: italic;
font-weight: 400;
font-display: swap;
src: url("/fonts/jost/jost-400-italic.woff2") format("woff2");
}
@font-face {
font-family: "Jost";
font-style: italic;
font-weight: 700;
font-display: swap;
src: url("/fonts/jost/jost-700-italic.woff2") format("woff2");
}
@font-face {
font-family: "Archivo";
font-style: normal;
font-weight: 400;
font-display: swap;
src: url("/fonts/archivo/archivo-400-normal.woff2") format("woff2");
}
@font-face {
font-family: "Archivo";
font-style: normal;
font-weight: 700;
font-display: swap;
src: url("/fonts/archivo/archivo-700-normal.woff2") format("woff2");
}
@font-face {
font-family: "Archivo";
font-style: italic;
font-weight: 400;
font-display: swap;
src: url("/fonts/archivo/archivo-400-italic.woff2") format("woff2");
}
@font-face {
font-family: "Archivo";
font-style: italic;
font-weight: 700;
font-display: swap;
src: url("/fonts/archivo/archivo-700-italic.woff2") format("woff2");
}
@font-face {
font-family: "Source Serif 4";
font-style: normal;
font-weight: 400;
font-display: swap;
src: url("/fonts/source-serif-4/source-serif-4-400-normal.woff2") format("woff2");
}
@font-face {
font-family: "Source Serif 4";
font-style: normal;
font-weight: 700;
font-display: swap;
src: url("/fonts/source-serif-4/source-serif-4-700-normal.woff2") format("woff2");
}
@font-face {
font-family: "Source Serif 4";
font-style: italic;
font-weight: 400;
font-display: swap;
src: url("/fonts/source-serif-4/source-serif-4-400-italic.woff2") format("woff2");
}
@font-face {
font-family: "Source Serif 4";
font-style: italic;
font-weight: 700;
font-display: swap;
src: url("/fonts/source-serif-4/source-serif-4-700-italic.woff2") format("woff2");
}
+23 -7
View File
@@ -519,14 +519,30 @@ function Segment({
);
}
/** Systemfont-Auswahl der Text-Gruppe. */
/**
* Schriftauswahl der Text-Gruppe: 15 kuratierte, lokal gebuendelte
* Open-Source-Schriften (SIL Open Font License, siehe `src/text/fonts.css`
* und `public/fonts/<slug>/OFL.txt`). Bewusst KEINE Systemfonts mehr — die
* Darstellung soll unabhaengig vom Betriebssystem und der PDF-Export
* deterministisch sein. Ein spaeterer Einstellungen-Dialog kann weitere
* Schriften nachladen; das hier ist die Standardliste.
*/
const TEXT_FONTS: string[] = [
"Helvetica",
"Arial",
"Inter",
"Times New Roman",
"Georgia",
"Courier New",
"Work Sans",
"IBM Plex Sans",
"IBM Plex Mono",
"Source Sans 3",
"Space Grotesk",
"Manrope",
"Outfit",
"DM Sans",
"Public Sans",
"Karla",
"Rubik",
"Jost",
"Archivo",
"Source Serif 4",
];
/** Grössen-Presets (pt) der Text-Gruppe. */
@@ -547,7 +563,7 @@ function TextGroup({
}) {
// Defaults für neuen Text, solange nichts Text-artiges selektiert ist. Bei
// aktivem Ziel spiegeln die Controls die gemeinsamen Werte des Ziels wider.
const [defFont, setDefFont] = useState<string>("Helvetica");
const [defFont, setDefFont] = useState<string>("Inter");
const [defSize, setDefSize] = useState<number>(12);
const [defAlign, setDefAlign] = useState<Align>("left");
const [defBold, setDefBold] = useState(false);