diff --git a/admin/lib/fonts.js b/admin/lib/fonts.js index ca8838b..3af8810 100644 --- a/admin/lib/fonts.js +++ b/admin/lib/fonts.js @@ -10,6 +10,7 @@ const FONT_OPTIONS = [ { name: 'Merriweather', fallback: "Georgia, 'Times New Roman', serif" }, { name: 'Libre Baskerville', fallback: "Georgia, 'Times New Roman', serif" }, { name: 'DM Serif Display', fallback: "Georgia, 'Times New Roman', serif" }, + { name: 'Newsreader', fallback: "Georgia, 'Times New Roman', serif" }, { name: 'Georgia (Systemschrift)', fallback: "Georgia, 'Times New Roman', serif" }, { name: 'Inter', fallback: "system-ui, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif" }, { name: 'Roboto', fallback: "system-ui, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif" }, @@ -19,6 +20,7 @@ const FONT_OPTIONS = [ { name: 'Nunito', fallback: "system-ui, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif" }, { name: 'Work Sans', fallback: "system-ui, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif" }, { name: 'Source Sans 3', fallback: "system-ui, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif" }, + { name: 'Schibsted Grotesk', fallback: "system-ui, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif" }, { name: 'System UI (Systemschrift)', fallback: "system-ui, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif" }, ]; diff --git a/admin/public/app.js b/admin/public/app.js index da1a5fd..fdd44a3 100644 --- a/admin/public/app.js +++ b/admin/public/app.js @@ -64,7 +64,7 @@ .flatMap(([name, list]) => list.map( (face) => - `@font-face { font-family: '${name}'; font-weight: ${face.weight}; font-display: swap; ` + + `@font-face { font-family: '${name}'; font-style: ${face.style || 'normal'}; font-weight: ${face.weight}; font-display: swap; ` + `src: url('/admin${face.file}') format('woff2'); unicode-range: ${face.unicodeRange}; }`, ), ) diff --git a/content/theme.json b/content/theme.json index 74bb8c4..7896c0f 100644 --- a/content/theme.json +++ b/content/theme.json @@ -1,7 +1,7 @@ { "fonts": { - "heading": "Playfair Display", - "body": "Inter" + "heading": "Newsreader", + "body": "Schibsted Grotesk" }, "fontSizes": { "sm": "0.875rem", @@ -20,9 +20,9 @@ "a": 1 }, "bgAlt": { - "r": 244, + "r": 233, "g": 239, - "b": 228, + "b": 234, "a": 1 }, "surface": { @@ -32,57 +32,57 @@ "a": 1 }, "text": { - "r": 28, - "g": 24, - "b": 19, + "r": 26, + "g": 38, + "b": 34, "a": 1 }, "textMuted": { - "r": 107, - "g": 97, - "b": 84, + "r": 78, + "g": 93, + "b": 87, "a": 1 }, "border": { - "r": 220, - "g": 207, - "b": 182, + "r": 185, + "g": 198, + "b": 190, "a": 1 }, "primary": { - "r": 122, - "g": 93, - "b": 31, + "r": 44, + "g": 74, + "b": 66, "a": 1 }, "primaryDark": { - "r": 94, - "g": 71, - "b": 22, + "r": 31, + "g": 53, + "b": 48, "a": 1 }, "primaryContrast": { - "r": 255, - "g": 253, - "b": 248, + "r": 252, + "g": 250, + "b": 246, "a": 1 }, "accent": { - "r": 122, - "g": 93, - "b": 31, + "r": 142, + "g": 79, + "b": 63, "a": 1 }, "accentDark": { - "r": 94, - "g": 71, - "b": 22, + "r": 115, + "g": 62, + "b": 49, "a": 1 }, "success": { - "r": 79, + "r": 63, "g": 107, - "b": 66, + "b": 85, "a": 1 }, "danger": { @@ -101,7 +101,7 @@ "r": 138, "g": 59, "b": 34, - "a": 0.1 + "a": 1 }, "googleBlue": { "r": 26, diff --git a/public/fonts/newsreader/newsreader-latin-1.woff2 b/public/fonts/newsreader/newsreader-latin-1.woff2 new file mode 100644 index 0000000..11a48ec Binary files /dev/null and b/public/fonts/newsreader/newsreader-latin-1.woff2 differ diff --git a/public/fonts/newsreader/newsreader-latin-3.woff2 b/public/fonts/newsreader/newsreader-latin-3.woff2 new file mode 100644 index 0000000..816261a Binary files /dev/null and b/public/fonts/newsreader/newsreader-latin-3.woff2 differ diff --git a/public/fonts/newsreader/newsreader-latin-ext-0.woff2 b/public/fonts/newsreader/newsreader-latin-ext-0.woff2 new file mode 100644 index 0000000..7a7ae44 Binary files /dev/null and b/public/fonts/newsreader/newsreader-latin-ext-0.woff2 differ diff --git a/public/fonts/newsreader/newsreader-latin-ext-2.woff2 b/public/fonts/newsreader/newsreader-latin-ext-2.woff2 new file mode 100644 index 0000000..06116f4 Binary files /dev/null and b/public/fonts/newsreader/newsreader-latin-ext-2.woff2 differ diff --git a/public/fonts/schibsted-grotesk/schibsted-grotesk-latin-1.woff2 b/public/fonts/schibsted-grotesk/schibsted-grotesk-latin-1.woff2 new file mode 100644 index 0000000..ea0f36f Binary files /dev/null and b/public/fonts/schibsted-grotesk/schibsted-grotesk-latin-1.woff2 differ diff --git a/public/fonts/schibsted-grotesk/schibsted-grotesk-latin-ext-0.woff2 b/public/fonts/schibsted-grotesk/schibsted-grotesk-latin-ext-0.woff2 new file mode 100644 index 0000000..041da55 Binary files /dev/null and b/public/fonts/schibsted-grotesk/schibsted-grotesk-latin-ext-0.woff2 differ diff --git a/public/form/fleck-maske.svg b/public/form/fleck-maske.svg new file mode 100644 index 0000000..c317153 --- /dev/null +++ b/public/form/fleck-maske.svg @@ -0,0 +1 @@ + diff --git a/public/form/fleck.svg b/public/form/fleck.svg new file mode 100644 index 0000000..9c1a34f --- /dev/null +++ b/public/form/fleck.svg @@ -0,0 +1 @@ + diff --git a/public/form/pille.svg b/public/form/pille.svg new file mode 100644 index 0000000..ff9d512 --- /dev/null +++ b/public/form/pille.svg @@ -0,0 +1 @@ + diff --git a/scripts/fonts-holen.py b/scripts/fonts-holen.py index 2d2bd59..d24b29e 100644 --- a/scripts/fonts-holen.py +++ b/scripts/fonts-holen.py @@ -1,30 +1,41 @@ -import re, json, urllib.request, urllib.error, pathlib +# Aufruf: python scripts/fonts-holen.py -> alle Schriften neu holen +# python scripts/fonts-holen.py "Name" ... -> nur diese, Manifest wird ergänzt +import re, json, sys, urllib.request, urllib.error, pathlib UA = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0 Safari/537.36" -FAMS = ['Playfair Display','Lora','Merriweather','Libre Baskerville','DM Serif Display','Inter','Roboto','Open Sans','Poppins','Montserrat','Nunito','Work Sans','Source Sans 3'] +FAMS = ['Playfair Display','Lora','Merriweather','Libre Baskerville','DM Serif Display','Inter','Roboto','Open Sans','Poppins','Montserrat','Nunito','Work Sans','Source Sans 3','Newsreader','Schibsted Grotesk'] +# Diese Schriften auch kursiv holen (echte Kursive statt schräg gerechneter) +ITAL = {'Newsreader'} +manifest_path = pathlib.Path('src/lib/font-faces.json') +if sys.argv[1:]: + FAMS = sys.argv[1:] out_dir = pathlib.Path('public/fonts'); out_dir.mkdir(parents=True, exist_ok=True) -manifest = {} +manifest = json.load(open(manifest_path, encoding='utf8')) if sys.argv[1:] else {} def get(url): return urllib.request.urlopen(urllib.request.Request(url, headers={'User-Agent': UA})).read() for fam in FAMS: css = None for w in ['400;500;600;700', '400;700', '400']: + axis = 'wght' + if fam in ITAL: + axis = 'ital,wght'; w = ';'.join([f'0,{x}' for x in w.split(';')] + [f'1,{x}' for x in w.split(';')]) try: - css = get(f"https://fonts.googleapis.com/css2?family={fam.replace(' ','+')}:wght@{w}&display=swap").decode(); break + css = get(f"https://fonts.googleapis.com/css2?family={fam.replace(' ','+')}:{axis}@{w}&display=swap").decode(); break except urllib.error.HTTPError: pass slug = fam.lower().replace(' ', '-'); d = out_dir / slug; d.mkdir(exist_ok=True) faces = []; seen = {} for subset, body in re.findall(r'/\* ([\w-]+) \*/\s*@font-face \{(.*?)\}', css, re.S): if subset not in ('latin', 'latin-ext'): continue weight = re.search(r'font-weight: (\d+)', body).group(1) + style = re.search(r'font-style: (\w+)', body).group(1) url = re.search(r'url\((.*?)\)', body).group(1) rng = re.search(r'unicode-range: (.*?);', body).group(1) if url not in seen: fn = f"{slug}-{subset}-{len(seen)}.woff2"; (d / fn).write_bytes(get(url)); seen[url] = fn - faces.append({'weight': int(weight), 'subset': subset, 'file': f"/fonts/{slug}/{seen[url]}", 'unicodeRange': rng}) + faces.append({'weight': int(weight), 'style': style, 'subset': subset, 'file': f"/fonts/{slug}/{seen[url]}", 'unicodeRange': rng}) # gleiche Datei fuer mehrere Gewichte (variable Schrift) -> eine Regel mit Gewichtsbereich merged = {} for f in faces: - k = (f['file'], f['subset']); merged.setdefault(k, dict(f, weights=[]))['weights'].append(f['weight']) - manifest[fam] = [{'file': v['file'], 'weight': f"{min(v['weights'])} {max(v['weights'])}" if len(v['weights']) > 1 else str(v['weights'][0]), 'unicodeRange': v['unicodeRange']} for v in merged.values()] + k = (f['file'], f['subset'], f['style']); merged.setdefault(k, dict(f, weights=[]))['weights'].append(f['weight']) + manifest[fam] = [dict({'file': v['file'], 'weight': f"{min(v['weights'])} {max(v['weights'])}" if len(v['weights']) > 1 else str(v['weights'][0]), 'unicodeRange': v['unicodeRange']}, **({'style': 'italic'} if v['style'] == 'italic' else {})) for v in merged.values()] print(fam, len(manifest[fam]), 'Regeln', len(seen), 'Dateien') -json.dump(manifest, open('src/lib/font-faces.json', 'w', encoding='utf8'), indent=2) +json.dump(manifest, open(manifest_path, 'w', encoding='utf8'), indent=2) diff --git a/src/components/Kicker.astro b/src/components/Kicker.astro new file mode 100644 index 0000000..81c3920 --- /dev/null +++ b/src/components/Kicker.astro @@ -0,0 +1,22 @@ +--- +/** + * Abschnittskennung als Randnotiz: "02 · Was uns unterscheidet" wird zu + * großer Ziffer im Fleck plus kleiner Zeile darunter. Ohne Ziffer am Anfang + * bleibt es eine einfache Zeile. + */ +interface Props { + text: string; +} + +const { text } = Astro.props; +const match = text.match(/^(\d+)\s*·\s*(.+)$/); +--- + +{match ? ( +
+ {match[1]} + {match[2]} +
+) : ( +{text}
+)} diff --git a/src/lib/font-faces.json b/src/lib/font-faces.json index ffbf9f1..293e6d0 100644 --- a/src/lib/font-faces.json +++ b/src/lib/font-faces.json @@ -184,5 +184,41 @@ "weight": "400 700", "unicodeRange": "U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD" } + ], + "Newsreader": [ + { + "file": "/fonts/newsreader/newsreader-latin-ext-0.woff2", + "weight": "400 700", + "unicodeRange": "U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C4, U+2113, U+2C60-2C7F, U+A720-A7FF", + "style": "italic" + }, + { + "file": "/fonts/newsreader/newsreader-latin-1.woff2", + "weight": "400 700", + "unicodeRange": "U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD", + "style": "italic" + }, + { + "file": "/fonts/newsreader/newsreader-latin-ext-2.woff2", + "weight": "400 700", + "unicodeRange": "U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C4, U+2113, U+2C60-2C7F, U+A720-A7FF" + }, + { + "file": "/fonts/newsreader/newsreader-latin-3.woff2", + "weight": "400 700", + "unicodeRange": "U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD" + } + ], + "Schibsted Grotesk": [ + { + "file": "/fonts/schibsted-grotesk/schibsted-grotesk-latin-ext-0.woff2", + "weight": "400 700", + "unicodeRange": "U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C4, U+2113, U+2C60-2C7F, U+A720-A7FF" + }, + { + "file": "/fonts/schibsted-grotesk/schibsted-grotesk-latin-1.woff2", + "weight": "400 700", + "unicodeRange": "U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD" + } ] } \ No newline at end of file diff --git a/src/lib/fonts.ts b/src/lib/fonts.ts index ad46191..51f140d 100644 --- a/src/lib/fonts.ts +++ b/src/lib/fonts.ts @@ -18,6 +18,7 @@ export const FONT_OPTIONS: FontOption[] = [ { name: 'Merriweather', category: 'serif', google: true, fallback: "Georgia, 'Times New Roman', serif" }, { name: 'Libre Baskerville', category: 'serif', google: true, fallback: "Georgia, 'Times New Roman', serif" }, { name: 'DM Serif Display', category: 'serif', google: true, fallback: "Georgia, 'Times New Roman', serif" }, + { name: 'Newsreader', category: 'serif', google: true, fallback: "Georgia, 'Times New Roman', serif" }, { name: 'Georgia (Systemschrift)', category: 'serif', google: false, fallback: "Georgia, 'Times New Roman', serif" }, { name: 'Inter', category: 'sans', google: true, fallback: "system-ui, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif" }, { name: 'Roboto', category: 'sans', google: true, fallback: "system-ui, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif" }, @@ -27,6 +28,7 @@ export const FONT_OPTIONS: FontOption[] = [ { name: 'Nunito', category: 'sans', google: true, fallback: "system-ui, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif" }, { name: 'Work Sans', category: 'sans', google: true, fallback: "system-ui, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif" }, { name: 'Source Sans 3', category: 'sans', google: true, fallback: "system-ui, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif" }, + { name: 'Schibsted Grotesk', category: 'sans', google: true, fallback: "system-ui, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif" }, { name: 'System UI (Systemschrift)', category: 'sans', google: false, fallback: "system-ui, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif" }, ]; @@ -43,7 +45,7 @@ export function fontFamilyCss(name: string): string { * public/fonts (see font-faces.json). The fonts are served from our own * server so a page view never contacts Google. System fonts are skipped. */ export function localFontFacesCss(fontNames: string[]): string { - const faces = fontFaces as Record{hero.eyebrow}
+{preis.eyebrow}
+{preis.amount} {preis.amountNote}
@@ -78,9 +80,9 @@ const findItem = (src: string) => -{warum.eyebrow}
+{leistungen.eyebrow}
+— {text}
+{text}
))}{mappe.eyebrow}
+{ablauf.eyebrow}
+{about.eyebrow}
+{about.quote}
+{about.paragraphs.map((paragraph) => ( @@ -240,8 +242,8 @@ const findItem = (src: string) =>{about.quote}
{faq.eyebrow}
+{kontakt.eyebrow}
+