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
@@ -68,37 +68,6 @@ def _download_font(url: str, dest: pathlib.Path) -> bool:
6868 return True
6969
7070
71- def _generate_css (
72- fonts : list [dict [str , t .Any ]],
73- variables : dict [str , str ],
74- ) -> str :
75- lines : list [str ] = []
76- for font in fonts :
77- family = font ["family" ]
78- font_id = font ["package" ].split ("/" )[- 1 ]
79- subset = font .get ("subset" , "latin" )
80- for weight in font ["weights" ]:
81- for style in font ["styles" ]:
82- filename = f"{ font_id } -{ subset } -{ weight } -{ style } .woff2"
83- lines .append ("@font-face {" )
84- lines .append (f' font-family: "{ family } ";' )
85- lines .append (f" font-style: { style } ;" )
86- lines .append (f" font-weight: { weight } ;" )
87- lines .append (" font-display: swap;" )
88- lines .append (f' src: url("../fonts/{ filename } ") format("woff2");' )
89- lines .append ("}" )
90- lines .append ("" )
91-
92- if variables :
93- lines .append ("body {" )
94- for var , value in variables .items ():
95- lines .append (f" { var } : { value } ;" )
96- lines .append ("}" )
97- lines .append ("" )
98-
99- return "\n " .join (lines )
100-
101-
10271def _on_builder_inited (app : Sphinx ) -> None :
10372 if app .builder .format != "html" :
10473 return
@@ -111,10 +80,9 @@ def _on_builder_inited(app: Sphinx) -> None:
11180 cache = _cache_dir ()
11281 static_dir = pathlib .Path (app .outdir ) / "_static"
11382 fonts_dir = static_dir / "fonts"
114- css_dir = static_dir / "css"
11583 fonts_dir .mkdir (parents = True , exist_ok = True )
116- css_dir .mkdir (parents = True , exist_ok = True )
11784
85+ font_faces : list [dict [str , str ]] = []
11886 for font in fonts :
11987 font_id = font ["package" ].split ("/" )[- 1 ]
12088 version = font ["version" ]
@@ -127,10 +95,14 @@ def _on_builder_inited(app: Sphinx) -> None:
12795 url = _cdn_url (package , version , font_id , subset , weight , style )
12896 if _download_font (url , cached ):
12997 shutil .copy2 (cached , fonts_dir / filename )
130-
131- css_content = _generate_css (fonts , variables )
132- (css_dir / "fonts.css" ).write_text (css_content , encoding = "utf-8" )
133- logger .info ("generated fonts.css with %d font families" , len (fonts ))
98+ font_faces .append (
99+ {
100+ "family" : font ["family" ],
101+ "style" : style ,
102+ "weight" : str (weight ),
103+ "filename" : filename ,
104+ }
105+ )
134106
135107 preload_hrefs : list [str ] = []
136108 preload_specs : list [tuple [str , int , str ]] = app .config .sphinx_font_preload
@@ -142,9 +114,13 @@ def _on_builder_inited(app: Sphinx) -> None:
142114 filename = f"{ font_id } -{ subset } -{ weight } -{ style } .woff2"
143115 preload_hrefs .append (filename )
144116 break
145- app ._font_preload_hrefs = preload_hrefs # type: ignore[attr-defined]
146117
147- app .add_css_file ("css/fonts.css" )
118+ fallbacks : list [dict [str , str ]] = app .config .sphinx_font_fallbacks
119+
120+ app ._font_preload_hrefs = preload_hrefs # type: ignore[attr-defined]
121+ app ._font_faces = font_faces # type: ignore[attr-defined]
122+ app ._font_fallbacks = fallbacks # type: ignore[attr-defined]
123+ app ._font_css_variables = variables # type: ignore[attr-defined]
148124
149125
150126def _on_html_page_context (
@@ -155,10 +131,14 @@ def _on_html_page_context(
155131 doctree : t .Any ,
156132) -> None :
157133 context ["font_preload_hrefs" ] = getattr (app , "_font_preload_hrefs" , [])
134+ context ["font_faces" ] = getattr (app , "_font_faces" , [])
135+ context ["font_fallbacks" ] = getattr (app , "_font_fallbacks" , [])
136+ context ["font_css_variables" ] = getattr (app , "_font_css_variables" , {})
158137
159138
160139def setup (app : Sphinx ) -> SetupDict :
161140 app .add_config_value ("sphinx_fonts" , [], "html" )
141+ app .add_config_value ("sphinx_font_fallbacks" , [], "html" )
162142 app .add_config_value ("sphinx_font_css_variables" , {}, "html" )
163143 app .add_config_value ("sphinx_font_preload" , [], "html" )
164144 app .connect ("builder-inited" , _on_builder_inited )
0 commit comments