11"""Sphinx extension for self-hosted fonts via Fontsource CDN.
22
3- Downloads font files at build time, caches them locally, and generates
4- CSS with @font-face declarations and CSS variable overrides .
3+ Downloads font files at build time, caches them locally, and passes
4+ structured font data to the template context for inline @font-face CSS.
55"""
66
77from __future__ import annotations
@@ -66,37 +66,6 @@ def _download_font(url: str, dest: pathlib.Path) -> bool:
6666 return True
6767
6868
69- def _generate_css (
70- fonts : list [dict [str , t .Any ]],
71- variables : dict [str , str ],
72- ) -> str :
73- lines : list [str ] = []
74- for font in fonts :
75- family = font ["family" ]
76- font_id = font ["package" ].split ("/" )[- 1 ]
77- subset = font .get ("subset" , "latin" )
78- for weight in font ["weights" ]:
79- for style in font ["styles" ]:
80- filename = f"{ font_id } -{ subset } -{ weight } -{ style } .woff2"
81- lines .append ("@font-face {" )
82- lines .append (f' font-family: "{ family } ";' )
83- lines .append (f" font-style: { style } ;" )
84- lines .append (f" font-weight: { weight } ;" )
85- lines .append (" font-display: swap;" )
86- lines .append (f' src: url("../fonts/{ filename } ") format("woff2");' )
87- lines .append ("}" )
88- lines .append ("" )
89-
90- if variables :
91- lines .append ("body {" )
92- for var , value in variables .items ():
93- lines .append (f" { var } : { value } ;" )
94- lines .append ("}" )
95- lines .append ("" )
96-
97- return "\n " .join (lines )
98-
99-
10069def _on_builder_inited (app : Sphinx ) -> None :
10170 if app .builder .format != "html" :
10271 return
@@ -109,10 +78,9 @@ def _on_builder_inited(app: Sphinx) -> None:
10978 cache = _cache_dir ()
11079 static_dir = pathlib .Path (app .outdir ) / "_static"
11180 fonts_dir = static_dir / "fonts"
112- css_dir = static_dir / "css"
11381 fonts_dir .mkdir (parents = True , exist_ok = True )
114- css_dir .mkdir (parents = True , exist_ok = True )
11582
83+ font_faces : list [dict [str , str ]] = []
11684 for font in fonts :
11785 font_id = font ["package" ].split ("/" )[- 1 ]
11886 version = font ["version" ]
@@ -125,10 +93,14 @@ def _on_builder_inited(app: Sphinx) -> None:
12593 url = _cdn_url (package , version , font_id , subset , weight , style )
12694 if _download_font (url , cached ):
12795 shutil .copy2 (cached , fonts_dir / filename )
128-
129- css_content = _generate_css (fonts , variables )
130- (css_dir / "fonts.css" ).write_text (css_content , encoding = "utf-8" )
131- logger .info ("generated fonts.css with %d font families" , len (fonts ))
96+ font_faces .append (
97+ {
98+ "family" : font ["family" ],
99+ "style" : style ,
100+ "weight" : str (weight ),
101+ "filename" : filename ,
102+ }
103+ )
132104
133105 preload_hrefs : list [str ] = []
134106 preload_specs : list [tuple [str , int , str ]] = app .config .sphinx_font_preload
@@ -140,9 +112,13 @@ def _on_builder_inited(app: Sphinx) -> None:
140112 filename = f"{ font_id } -{ subset } -{ weight } -{ style } .woff2"
141113 preload_hrefs .append (filename )
142114 break
143- app ._font_preload_hrefs = preload_hrefs # type: ignore[attr-defined]
144115
145- app .add_css_file ("css/fonts.css" )
116+ fallbacks : list [dict [str , str ]] = app .config .sphinx_font_fallbacks
117+
118+ app ._font_preload_hrefs = preload_hrefs # type: ignore[attr-defined]
119+ app ._font_faces = font_faces # type: ignore[attr-defined]
120+ app ._font_fallbacks = fallbacks # type: ignore[attr-defined]
121+ app ._font_css_variables = variables # type: ignore[attr-defined]
146122
147123
148124def _on_html_page_context (
@@ -153,10 +129,14 @@ def _on_html_page_context(
153129 doctree : t .Any ,
154130) -> None :
155131 context ["font_preload_hrefs" ] = getattr (app , "_font_preload_hrefs" , [])
132+ context ["font_faces" ] = getattr (app , "_font_faces" , [])
133+ context ["font_fallbacks" ] = getattr (app , "_font_fallbacks" , [])
134+ context ["font_css_variables" ] = getattr (app , "_font_css_variables" , {})
156135
157136
158137def setup (app : Sphinx ) -> SetupDict :
159138 app .add_config_value ("sphinx_fonts" , [], "html" )
139+ app .add_config_value ("sphinx_font_fallbacks" , [], "html" )
160140 app .add_config_value ("sphinx_font_css_variables" , {}, "html" )
161141 app .add_config_value ("sphinx_font_preload" , [], "html" )
162142 app .connect ("builder-inited" , _on_builder_inited )
0 commit comments