Skip to content

Commit e9d1b05

Browse files
implement @font-face for file-based brand.yml fonts
fixes #12501
1 parent ec1c554 commit e9d1b05

File tree

11 files changed

+130
-13
lines changed

11 files changed

+130
-13
lines changed

src/core/sass/brand.ts

Lines changed: 62 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,15 @@ import {
1818
BrandFont,
1919
// BrandFontBunny,
2020
BrandFontCommon,
21+
BrandFontFile,
2122
BrandFontGoogle,
2223
BrandFontWeight,
2324
Zod,
2425
} from "../../resources/types/zod/schema-types.ts";
2526
import { Brand } from "../brand/brand.ts";
2627
import { darkModeDefault } from "../../format/html/format-html-info.ts";
2728
import { kBrandMode } from "../../config/constants.ts";
29+
import { join, relative } from "../../deno_ral/path.ts";
2830

2931
const defaultColorNameMap: Record<string, string> = {
3032
"link-color": "link",
@@ -149,6 +151,28 @@ const googleFontImportString = (description: BrandFontGoogle) => {
149151
}:${styleString}wght@${weights}&display=${display}');`;
150152
};
151153

154+
const fileFontImportString = (brand: Brand, description: BrandFontFile) => {
155+
const pathPrefix = relative(brand.projectDir, brand.brandDir);
156+
const parts = [];
157+
for (const file of description.files) {
158+
let path, weight, style;
159+
if (typeof file === "string") {
160+
path = file;
161+
} else {
162+
path = file.path;
163+
weight = file.weight;
164+
style = file.style;
165+
}
166+
parts.push(`@font-face {
167+
font-family: '${description.family}';
168+
src: url('${join(pathPrefix, path).replace(/\\/g, '/')}');
169+
font-weight: ${weight || "normal"};
170+
font-style: ${style || "normal"};
171+
}\n`);
172+
}
173+
return parts.join("\n");
174+
};
175+
152176
const brandColorLayer = (
153177
brand: Brand,
154178
nameMap: Record<string, string>,
@@ -352,7 +376,7 @@ const brandTypographyLayer = (
352376
const resolveBunnyFontFamily = (
353377
font: BrandFont[],
354378
): string | undefined => {
355-
let googleFamily = "";
379+
let bunnyFamily = "";
356380
for (const _resolvedFont of font) {
357381
const safeResolvedFont = Zod.BrandFontBunny.safeParse(_resolvedFont);
358382
if (!safeResolvedFont.success) {
@@ -367,19 +391,49 @@ const brandTypographyLayer = (
367391
if (!thisFamily) {
368392
continue;
369393
}
370-
if (googleFamily === "") {
371-
googleFamily = thisFamily;
372-
} else if (googleFamily !== thisFamily) {
394+
if (bunnyFamily === "") {
395+
bunnyFamily = thisFamily;
396+
} else if (bunnyFamily !== thisFamily) {
373397
throw new Error(
374-
`Inconsistent Google font families found: ${googleFamily} and ${thisFamily}`,
398+
`Inconsistent Bunny font families found: ${bunnyFamily} and ${thisFamily}`,
375399
);
376400
}
377401
typographyImports.add(bunnyFontImportString(resolvedFont));
378402
}
379-
if (googleFamily === "") {
403+
if (bunnyFamily === "") {
380404
return undefined;
381405
}
382-
return googleFamily;
406+
return bunnyFamily;
407+
};
408+
409+
const resolveFileFontFamily = (
410+
brand: Brand,
411+
font: BrandFont[],
412+
): string | undefined => {
413+
let fileFamily = "";
414+
for (const _resolvedFont of font) {
415+
const safeResolvedFont = Zod.BrandFontFile.safeParse(_resolvedFont);
416+
if (!safeResolvedFont.success) {
417+
return undefined;
418+
}
419+
const resolvedFont = safeResolvedFont.data;
420+
const thisFamily = resolvedFont.family;
421+
if (!thisFamily) {
422+
continue;
423+
}
424+
if (fileFamily === "") {
425+
fileFamily = thisFamily;
426+
} else if (fileFamily !== thisFamily) {
427+
throw new Error(
428+
`Inconsistent Files font families found: ${fileFamily} and ${thisFamily}`,
429+
);
430+
}
431+
typographyImports.add(fileFontImportString(brand, resolvedFont));
432+
}
433+
if (fileFamily === "") {
434+
return undefined;
435+
}
436+
return fileFamily;
383437
};
384438

385439
type HTMLFontInformation = { [key: string]: unknown };
@@ -410,7 +464,7 @@ const brandTypographyLayer = (
410464
const font = getFontFamilies(family);
411465
result.family = resolveGoogleFontFamily(font) ??
412466
resolveBunnyFontFamily(font) ??
413-
// resolveFilesFontFamily(font) ??
467+
resolveFileFontFamily(brand, font) ??
414468
family;
415469
for (
416470
const entry of [
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
*.html
2+
*_files/
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
typography:
2+
fonts:
3+
- family: "Source Sans Pro"
4+
source: file
5+
files:
6+
- fonts/source-sans-pro/source-sans-pro-regular.woff
7+
- path: fonts/source-sans-pro/source-sans-pro-italic.woff
8+
style: italic
9+
- path: fonts/source-sans-pro/source-sans-pro-semibold.woff
10+
weight: 600
11+
- path: fonts/source-sans-pro/source-sans-pro-semibolditalic.woff
12+
style: italic
13+
weight: 600
14+
base:
15+
family: Source Sans Pro
16+
line-height: 1.25
17+
size: 1rem
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
typography:
2+
fonts:
3+
- family: "Source Sans Pro"
4+
source: file
5+
files:
6+
- path: fonts/source-sans-pro/source-sans-pro-regular.woff
7+
8+
- family: "Fira Code"
9+
source: file
10+
files:
11+
- fonts/firacode/FiraCode-VF.ttf
12+
- family: "Roboto Slab"
13+
source: file
14+
files:
15+
- path: fonts/robotoslab/RobotoSlab-VariableFont_wght.ttf
16+
weight: 600
17+
style: normal
18+
base:
19+
family: Source Sans Pro
20+
line-height: 1.25
21+
size: 1rem
22+
headings:
23+
family: Roboto Slab
24+
color: primary
25+
weight: 600
26+
monospace:
27+
family: Fira Code
28+
size: 0.9em
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
---
2+
title: Source Sans Pro
3+
---
4+
5+
This text **should be** in Source Sans Pro, _and_ some ***variants***.
6+
7+
{{< lipsum 1 >}}
8+
9+
**{{< lipsum 1 >}}**
10+
11+
*{{< lipsum 1 >}}*
12+
13+
***{{< lipsum 1 >}}***
14+

tests/docs/smoke-all/typst/brand-yaml/typography/relative-path/brand-typography.qmd

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
---
22
title: title is `#context text.font`{=typst} `#context text.weight`{=typst} `#context text.style`{=typst} `#context text.size`{=typst}
3-
format: typst
3+
format:
4+
typst:
5+
include-in-header:
6+
text: |
7+
#set text(fallback: false)
8+
html: default
49
brand: branding/brand.yml
5-
include-in-header:
6-
text: |
7-
#set text(fallback: false)
810
_quarto:
911
tests:
1012
typst:

0 commit comments

Comments
 (0)