11import {
22 DEFAULT_THEME_SETTINGS ,
3+ Font ,
34 getGoogleFontName ,
45 getRelatedFont ,
6+ normalizeCustomFontDefinition ,
7+ type CustomFont ,
8+ type CustomFontDefinition ,
9+ type FontVariant ,
510 type ThemeSettings ,
611} from '@/theme-settings' ;
712import { withoutUndefined } from '@/utils' ;
@@ -13,14 +18,98 @@ interface Props {
1318 settings : Partial < ThemeSettings > ;
1419}
1520
16- export function BrandingSettings ( { settings } : Props ) {
17- const compiledSettings : ThemeSettings = {
18- ...DEFAULT_THEME_SETTINGS ,
19- ...withoutUndefined ( settings ) ,
20- } ;
21+ function getGoogleFontsUrl ( families : string [ ] ) : string {
22+ return `https://fonts.googleapis.com/css2?display=swap&${ families
23+ . map ( ( family ) => `family=${ family } ` )
24+ . join ( '&' ) } `;
25+ }
26+
27+ function getFontFaceStyle ( definition : CustomFontDefinition ) : string {
28+ return `@font-face { font-family: '${ definition . family } '; src: url('${ definition . url } '); font-display: swap; }` ;
29+ }
2130
22- const primaryGoogleFontName = getGoogleFontName ( compiledSettings . font ) . replace ( ' ' , '+' ) ;
23- const relatedFont = getRelatedFont ( compiledSettings . font ) ;
31+ function getFontFaceStyleFromVariant ( family : string , variant : FontVariant ) : string {
32+ return `@font-face { font-family: '${ family } '; src: url('${ variant . src } '); font-weight: ${ variant . weight } ; font-style: ${ variant . style } ; font-display: swap; }` ;
33+ }
34+
35+ function collectCustomFontSlot (
36+ slot : CustomFontDefinition ,
37+ weights : string ,
38+ googleFamilies : string [ ] ,
39+ cssLinkUrls : string [ ] ,
40+ fontFaceStyles : string [ ] ,
41+ ) {
42+ const normalized = normalizeCustomFontDefinition ( slot ) ;
43+
44+ switch ( normalized . source ) {
45+ case 'google' :
46+ googleFamilies . push ( `${ normalized . family . replace ( / / g, '+' ) } :wght@${ weights } ` ) ;
47+ break ;
48+ case 'typekit' :
49+ if ( normalized . url ) {
50+ cssLinkUrls . push ( normalized . url ) ;
51+ }
52+ break ;
53+ case 'upload' :
54+ if ( normalized . variants ?. length ) {
55+ for ( const v of normalized . variants ) {
56+ fontFaceStyles . push ( getFontFaceStyleFromVariant ( normalized . family , v ) ) ;
57+ }
58+ } else if ( normalized . url ) {
59+ fontFaceStyles . push ( getFontFaceStyle ( normalized ) ) ;
60+ }
61+ break ;
62+ case 'link' :
63+ if ( normalized . variants ?. length ) {
64+ for ( const v of normalized . variants ) {
65+ fontFaceStyles . push ( getFontFaceStyleFromVariant ( normalized . family , v ) ) ;
66+ }
67+ } else if ( normalized . url ) {
68+ fontFaceStyles . push ( getFontFaceStyle ( normalized ) ) ;
69+ }
70+ break ;
71+ }
72+ }
73+
74+ function renderCustomFontElements ( customFont : CustomFont ) {
75+ const googleFamilies : string [ ] = [ ] ;
76+ const cssLinkUrls : string [ ] = [ ] ;
77+ const fontFaceStyles : string [ ] = [ ] ;
78+
79+ collectCustomFontSlot (
80+ customFont . heading ,
81+ '400;600;700' ,
82+ googleFamilies ,
83+ cssLinkUrls ,
84+ fontFaceStyles ,
85+ ) ;
86+ collectCustomFontSlot (
87+ customFont . paragraph ,
88+ '400;500;600;700;900' ,
89+ googleFamilies ,
90+ cssLinkUrls ,
91+ fontFaceStyles ,
92+ ) ;
93+
94+ return (
95+ < >
96+ { googleFamilies . length > 0 && (
97+ < link href = { getGoogleFontsUrl ( googleFamilies ) } rel = "stylesheet" />
98+ ) }
99+ { [ ...new Set ( cssLinkUrls ) ] . map ( ( url ) => (
100+ < link key = { url } href = { url } rel = "stylesheet" />
101+ ) ) }
102+ { fontFaceStyles . length > 0 && (
103+ // biome-ignore lint/security/noDangerouslySetInnerHtml: Font-face CSS from trusted backend data
104+ < style dangerouslySetInnerHTML = { { __html : fontFaceStyles . join ( '\n' ) } } />
105+ ) }
106+ </ >
107+ ) ;
108+ }
109+
110+ function renderPresetFontElements ( font : Font ) {
111+ const primaryGoogleFontName = getGoogleFontName ( font ) . replace ( ' ' , '+' ) ;
112+ const relatedFont = getRelatedFont ( font ) ;
24113
25114 let families = [ ] ;
26115 if ( relatedFont ) {
@@ -34,14 +123,21 @@ export function BrandingSettings({ settings }: Props) {
34123 families = [ `${ primaryGoogleFontName } :wght@400;500;600;700;900` ] ;
35124 }
36125
126+ return < link href = { getGoogleFontsUrl ( families ) } rel = "stylesheet" /> ;
127+ }
128+
129+ export function BrandingSettings ( { settings } : Props ) {
130+ const compiledSettings : ThemeSettings = {
131+ ...DEFAULT_THEME_SETTINGS ,
132+ ...withoutUndefined ( settings ) ,
133+ } ;
134+
135+ const { font, custom_font } = compiledSettings ;
136+ const isCustomFont = font === Font . CUSTOM && custom_font !== null ;
137+
37138 return (
38139 < >
39- < link
40- href = { `https://fonts.googleapis.com/css2?display=swap&${ families
41- . map ( ( family ) => `family=${ family } ` )
42- . join ( '&' ) } `}
43- rel = "stylesheet"
44- />
140+ { isCustomFont ? renderCustomFontElements ( custom_font ) : renderPresetFontElements ( font ) }
45141
46142 < InjectCssVariables variables = { getCssVariables ( compiledSettings ) } />
47143 </ >
0 commit comments