Skip to content

Commit

Permalink
Partially refactors HUGE/Fonts (#81)
Browse files Browse the repository at this point in the history
* Partially refactors HUGE/Fonts

Add `base`setting, improve `preload` logic and UX

Fixes #80

* Fix mimetype issues when maintype/subtype is empty

* Fix pesky formatting

* Ensure not font-face at rule is printed if no files are found

* Rename `base` setting to `cascade`
Move `preload` setting to font (use cascade for global)

* Add "tech" font setting (variable fonts)
  • Loading branch information
regisphilibert authored Dec 2, 2022
1 parent 33b64c8 commit e3ed7df
Show file tree
Hide file tree
Showing 7 changed files with 177 additions and 97 deletions.
8 changes: 4 additions & 4 deletions core/fonts/private/GetFormat.html
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,12 @@
{{ $irregular := dict
"vnd.ms-fontobject" "embedded-opentype"
"font-woff" "woff"
"ttf" "truetype"
"font-sfnt" "truetype"
"otf" "opentype"
"font-sfnt" "opentype"
"ttf" "truetype"
"otf" "opentype"
"svgz" "svg"
}}
{{ with index $irregular $format }}
{{ $format = . }}
{{ end }}

{{ return $format }}
39 changes: 20 additions & 19 deletions core/fonts/private/GetLocals.html
Original file line number Diff line number Diff line change
Expand Up @@ -10,31 +10,32 @@

@return Slice of strings
*/}}
{{ $local := slice }}
{{ $local_output := slice }}

{{ $config := partialCached "huge/config/Get" "fonts" "fonts" }}

{{/* We add local */}}
{{/* 1. Font local setting is ommited */}}
{{ $add_local := not (isset . "local") }}
{{/* 2. OR font local setting is not `false` */}}
{{ $add_local = $add_local | or (ne .local false) }}
{{/* 2. AND fonts global setting `disable_local` is not true */}}
{{ $add_local = $add_local | and (not $config.disable_local) }}

{{ if $add_local }}
{{ with .local }}
{{/* This safely append the value of .local (a string or a slice) to the $local slice */}}
{{ $local = $local | append . }}
{{ else }}
{{/* If local is not set, we'll build it ourselves based on the font family name */}}
{{ with .family }}
{{ $local = $local | append . }}
{{/* Default is always true, meaning we built it ourselves */}}
{{ $local := true }}

{{ if isset $ "local" }}
{{ $local = $.local }}
{{ end }}
{{/* If local is neither true nor false, it means it is a string or a slice */}}
{{ if not (in (slice true false) $local) }}
{{/* This safely append the value of .local (a string or a slice) to the $local slice */}}
{{ $local_output = $local_output | append $local }}
{{ else }}
{{/* Only if it's true... */}}
{{ if $local }}
{{ with $.family }}
{{ $local_output = $local_output | append . }}
{{/* If a whitespace is in the family name, we can add a local with dash in place of ws */}}
{{ if in . " " }}
{{ $local = $local | append (replace . " " "-") }}
{{ $local_output = $local_output | append (replace . " " "-") }}
{{ end }}
{{ end }}
{{ end }}

{{ end }}
{{ return $local }}

{{ return $local_output }}
40 changes: 40 additions & 0 deletions core/fonts/private/GetMediaType.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
{{/*
GetFormat
Retrieves the font format of a given resource

@author @regisphilibert

@context Resource (.)

@access private

@returns String

*/}}
{{ $MainType := "font" }}
{{ $SubType := "woff2" }}
{{/* It appears CloudFlare produces an empty string when calling .MediaType.MainType or .MediaType.SubType on a woff2...
As this is by far the best font format these days in terms of support and optimization,
making it default to ensure it is not botched by cloudflare is "ok".
*/}}
{{ with .MediaType.SubType }}
{{ $SubType = . }}
{{ end }}
{{ with .MediaType.MainType }}
{{ $MainType = . }}
{{ end }}

{{ $format := printf "%s/%s" $MainType $SubType }}

{{/* Another weirdness for some files depending on hosting plaftorm.
Some woff file would return application/font-woff
But Chrome will print a `<link rel=preload> has an unsupported `type` value` warning on non-font "types".
*/}}
{{ $irregular := dict
"application/font-woff" "font/woff"
}}
{{ with index $irregular $format }}
{{ $format = . }}
{{ end }}

{{ return $format }}
40 changes: 22 additions & 18 deletions core/fonts/private/GetPreloadTags.html
Original file line number Diff line number Diff line change
Expand Up @@ -16,26 +16,30 @@
*/}}
{{ $tags := slice }}
{{/* We list all the fonts in order to produce the data for the "prefetch" tags on all its required files */}}
{{ range partialCached "huge/fonts/private/GetFonts" "GetFonts" }}
{{ if .preload }}
{{/* We want to print <link rel="preload" href="font.woff2" as="font" type="font/woff2" crossorigin> */}}
{{ range .resources }}
{{/* We want to print `<link rel="preload" href="font.woff2" as="font" type="font/woff2" crossorigin="anonymous">` */}}
{{ range $font := partialCached "huge/fonts/private/GetFonts" "GetFonts" }}
{{ with $preload := .preload }}
{{ range $font.resources }}
{{ $format := partialCached "huge/fonts/private/GetFormat" . .MediaType.SubType }}
{{/* For now it makes sens to restrict preload to the most supported file format.
Future release will allow other file formats to be preloaded.
*/}}
{{ if eq $format "woff2" }}
{{ $tag := dict
"name" "link"
"attr" (dict
"href" .RelPermalink
"as" "font"
"type" "font/woff2"
"rel" "preload"
"crossorigin" "anonymous"
)}}
{{ $tags = $tags | append $tag }}
{{/* If user resrticts preloading by format */}}
{{ if reflect.IsSlice $preload }}
{{/* If said font format not in the preload format list, we skip this resource */}}
{{ if not (in $preload $format) }}
{{ continue }}
{{ end }}
{{ end }}
{{/* Test above failed, we can proceeed */}}
{{ $tag := dict
"name" "link"
"attr" (dict
"href" .RelPermalink
"as" "font"
"type" (partialCached "huge/fonts/private/GetMediaType" . .)
"rel" "preload"
"crossorigin" "anonymous"
)
}}
{{ $tags = $tags | append $tag }}
{{ end }}
{{ end }}
{{ end }}
Expand Down
70 changes: 44 additions & 26 deletions core/fonts/private/ParseFont.html
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{{/*
ParseFont
Parse data from Module's settings font declaration. For now it only adds a .resources containing the font files assets.
Parse data from Module's settings font declaration and base declarations

@author @regisphilibert

Expand All @@ -9,50 +9,68 @@
@access private

@return Map
String (.family)
String (.file)
Slice (.local)
Boolean (.preload)
Boolean | Slice of Strings (.preload)
String (.tech)
Resources (.resources)
String (.family)?
String (.weight)?
String (.style)?
String (.display)?
String (.variant)?
String (.feature-settings)?
String (.variation-settings)?
Map (.propertiers)
String (.family)
String (.weight)?
String (.style)?
String (.display)?
String (.variant)?
String (.feature-settings)?
String (.variation-settings)?


*/}}
{{ $font := . }}
{{ $s := newScratch }}
{{ $s.Set "data" dict }}

{{ $config := partialCached "huge/config/Get" "fonts" "fonts" }}

{{ with .file }}
{{ with resources.Match (print "/" . ".*") }}
{{/* This ensures woff2 and woff are declared first, it seems we can't realy rely on SubType (cloufflare as '' for woff2...) */}}
{{ with sort . "Name" "desc" }}
{{ $font = merge $font (dict "resources" (sort . "Name" "desc")) }}
{{ $s.SetInMap "data" "resources" (sort . "Name" "desc") }}
{{ end }}
{{ else }}
{{ partial "huge/console/warn" (printf "We did not find matching font files for basename `%s`.\nFont files should be added to the project's `assets` directory and match the relative path set in the font's settings." .) }}
{{ partial "huge/console/warn" (printf "We did not find matching font files for basename `/%s`.\nAs a result no @font-face CSS at-rule will be printed for this font. \nFont files should be added to the project's `assets` directory and match the relative path set in the font's settings." .) }}
{{ end }}
{{ end }}

{{ with partialCached "huge/fonts/private/GetLocals" . . }}
{{ $font = merge $font (dict "local" .) }}
{{ $font := . }}
{{ with $config.cascade }}
{{ $font = merge . $font }}
{{ end }}

{{/* We'll charge the parsed font with its `preload` preference. */}}
{{ $preload := false }}
{{/* First we check for the global setting */}}
{{ $preload_setting := $config.preload | default "always" }}
{{ if partialCached "huge/env/When" $preload_setting $preload_setting }}
{{ $preload = . }}
{{ with partialCached "huge/fonts/private/GetLocals" $font $font }}
{{ $s.SetInMap "data" "local" . }}
{{ end }}
{{/* if preload is set (can be `false`) on the declaration itself, it overwrites global's */}}
{{ if isset $ "preload" }}
{{ $preload = $.preload }}


{{ with partialCached "huge/fonts/private/SanitizeProperties" $font $font }}
{{ $s.SetInMap "data" "properties" . }}
{{ end }}

{{/* We preload by default */}}
{{ $preload := true }}
{{/* We use `isset` to ensure a falsy value is taken into account if set. */}}
{{ if isset $font "preload" }}
{{ $preload = $font.preload }}
{{ end }}


{{ with $font.tech }}
{{ $s.SetInMap "data" "tech" . }}
{{ end }}

{{ $s.SetInMap "data" "preload" $preload }}

{{ if not ($s.Get "data").resources }}
{{ $s.Set "data" dict }}
{{ end }}
{{ $font = merge $font (dict "preload" $preload) }}

{{ return $font }}
{{ return $s.Get "data" }}
39 changes: 9 additions & 30 deletions core/fonts/private/ParseFontface.html
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
@access private

@use
- huge/fonts/privateParseFont
- huge/fonts/private/ParseFont

@return Map
String (.font-family)
Expand All @@ -35,43 +35,22 @@

{{ range . }}
{{ $format := partialCached "huge/fonts/private/GetFormat" . .MediaType.SubType }}
{{ $css_srcs = $css_srcs | append (printf `url("%s") format("%s")` .RelPermalink $format) }}
{{ $src := printf `url("%s") format("%s")` .RelPermalink $format }}
{{ with $font.tech }}
{{ $src = printf `%s tech("%s")` $src . }}
{{ end }}
{{ $css_srcs = $css_srcs | append $src }}
{{ end }}
{{ with $css_srcs }}
{{ $s.SetInMap "font" "src" (delimit . ",\n") }}
{{ end }}
{{ end }}
{{ end }}

{{ $properties := slice
"family"
"weight"
"style"
"display"
"variant"
"feature-settings"
"variation-settings"
"stretch"
}}
{{/* In order to tolerate if user uses `font-{property}: value` in the settings instead of `{property}: value`,
we add font-{property} to the valid properties */}}
{{ range $properties }}
{{ $properties = $properties | append (print "font-" .) }}
{{ end }}

{{ range $property := $properties }}
{{ with index $ . }}
{{ $key := $property }}
{{/* If missing font- we prepend the property */}}
{{ if not (in $key "font-") }}
{{ $key = print "font-" $property }}
{{ with .properties }}
{{ range $key, $v := . }}
{{ $s.SetInMap "font" (print "font-" $key) . }}
{{ end }}
{{ $s.SetInMap "font" $key . }}
{{ end }}
{{ end }}

{{ if not (index ($s.Get "font") "font-display") }}
{{ $s.SetInMap "font" "font-display" "swap" }}
{{ end }}

{{ return $s.Get "font" }}
38 changes: 38 additions & 0 deletions core/fonts/private/SanitizeProperties.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
{{/*
SanitizeProperties
Eliminate any property which is not a font property to be used in @font-face declaration.
Also clean the key (font-display > display)

@author @regisphilibert

@context Map (.)

@access private

@returns Map

*/}}
{{ $s := newScratch }}
{{ $s.Set "data" dict }}

{{ $property_keys := slice
"family"
"weight"
"style"
"display"
"variant"
"feature-settings"
"variation-settings"
"stretch"
}}
{{ range $key := $property_keys }}
{{ with index $ $key }}
{{ $s.SetInMap "data" $key . }}
{{ else }}
{{ with index $ (printf "font-" $key) }}
{{ $s.SetInMap "data" $key . }}
{{ end }}
{{ end }}
{{ end }}

{{ return $s.Get "data" }}

0 comments on commit e3ed7df

Please sign in to comment.