From 01e9c0b787867d52da37c36c09afe52698707b65 Mon Sep 17 00:00:00 2001 From: Regis Philibert Date: Thu, 1 Dec 2022 13:53:02 -0500 Subject: [PATCH 1/6] Partially refactors HUGE/Fonts Add `base`setting, improve `preload` logic and UX Fixes #80 --- core/fonts/private/GetFormat.html | 8 ++-- core/fonts/private/GetLocals.html | 39 +++++++-------- core/fonts/private/GetMediaType.html | 24 ++++++++++ core/fonts/private/GetPreloadTags.html | 40 +++++++++------- core/fonts/private/ParseFont.html | 56 +++++++++++++--------- core/fonts/private/ParseFontface.html | 33 ++----------- core/fonts/private/SanitizeProperties.html | 38 +++++++++++++++ 7 files changed, 146 insertions(+), 92 deletions(-) create mode 100644 core/fonts/private/GetMediaType.html create mode 100644 core/fonts/private/SanitizeProperties.html diff --git a/core/fonts/private/GetFormat.html b/core/fonts/private/GetFormat.html index 1c3d5ab..b77bb9c 100644 --- a/core/fonts/private/GetFormat.html +++ b/core/fonts/private/GetFormat.html @@ -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 }} \ No newline at end of file diff --git a/core/fonts/private/GetLocals.html b/core/fonts/private/GetLocals.html index cbb3679..b68d078 100644 --- a/core/fonts/private/GetLocals.html +++ b/core/fonts/private/GetLocals.html @@ -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 }} \ No newline at end of file + +{{ return $local_output }} \ No newline at end of file diff --git a/core/fonts/private/GetMediaType.html b/core/fonts/private/GetMediaType.html new file mode 100644 index 0000000..d603bf4 --- /dev/null +++ b/core/fonts/private/GetMediaType.html @@ -0,0 +1,24 @@ +{{/* + GetFormat + Retrieves the font format of a given resource + + @author @regisphilibert + + @context Resource (.) + + @access private + + @returns String + +*/}} +{{ $SubType := "woff2" }} +{{/* It appears CloudFlare produces an empty string when calling .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 }} +{{ $MainType := .MediaType.MainType }} + +{{ return printf "%s/%s" $MainType $SubType }} \ No newline at end of file diff --git a/core/fonts/private/GetPreloadTags.html b/core/fonts/private/GetPreloadTags.html index b3b69ef..90029e7 100644 --- a/core/fonts/private/GetPreloadTags.html +++ b/core/fonts/private/GetPreloadTags.html @@ -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 */}} - {{ range .resources }} +{{/* We want to print `` */}} +{{ 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 }} diff --git a/core/fonts/private/ParseFont.html b/core/fonts/private/ParseFont.html index 7aa2333..aae9f1b 100644 --- a/core/fonts/private/ParseFont.html +++ b/core/fonts/private/ParseFont.html @@ -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 @@ -9,50 +9,62 @@ @access private @return Map - String (.family) String (.file) Slice (.local) - Boolean (.preload) + Boolean | Slice of Strings (.preload) 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." .) }} {{ end }} {{ end }} -{{ with partialCached "huge/fonts/private/GetLocals" . . }} - {{ $font = merge $font (dict "local" .) }} +{{ $font := . }} +{{ with $config.base }} + {{ $font = merge . $font }} +{{ end }} + +{{ with partialCached "huge/fonts/private/GetLocals" $font $font }} + {{ $s.SetInMap "data" "local" . }} {{ end }} -{{/* We'll charge the parsed font with its `preload` preference. */}} -{{ $preload := false }} + +{{ with partialCached "huge/fonts/private/SanitizeProperties" $font $font }} + {{ $s.SetInMap "data" "properties" . }} +{{ end }} + +{{ $preload := true }} {{/* First we check for the global setting */}} -{{ $preload_setting := $config.preload | default "always" }} -{{ if partialCached "huge/env/When" $preload_setting $preload_setting }} - {{ $preload = . }} +{{ with $config }} + {{ if isset . "preload" }} + {{ $preload = .preload }} + {{ end }} {{ end }} {{/* if preload is set (can be `false`) on the declaration itself, it overwrites global's */}} -{{ if isset $ "preload" }} +{{ if isset $font "preload" }} {{ $preload = $.preload }} {{ end }} -{{ $font = merge $font (dict "preload" $preload) }} +{{ $s.SetInMap "data" "preload" $preload }} -{{ return $font }} \ No newline at end of file +{{ return $s.Get "data" }} \ No newline at end of file diff --git a/core/fonts/private/ParseFontface.html b/core/fonts/private/ParseFontface.html index 838123a..f050796 100644 --- a/core/fonts/private/ParseFontface.html +++ b/core/fonts/private/ParseFontface.html @@ -9,7 +9,7 @@ @access private @use - - huge/fonts/privateParseFont + - huge/fonts/private/ParseFont @return Map String (.font-family) @@ -41,37 +41,12 @@ {{ $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" }} \ No newline at end of file diff --git a/core/fonts/private/SanitizeProperties.html b/core/fonts/private/SanitizeProperties.html new file mode 100644 index 0000000..c74931d --- /dev/null +++ b/core/fonts/private/SanitizeProperties.html @@ -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" }} \ No newline at end of file From 0e6a2ff6a36d7f304c9e468f6e5ac23db518ae30 Mon Sep 17 00:00:00 2001 From: Regis Philibert Date: Thu, 1 Dec 2022 14:42:08 -0500 Subject: [PATCH 2/6] Fix mimetype issues when maintype/subtype is empty --- core/fonts/private/GetMediaType.html | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/core/fonts/private/GetMediaType.html b/core/fonts/private/GetMediaType.html index d603bf4..dccf608 100644 --- a/core/fonts/private/GetMediaType.html +++ b/core/fonts/private/GetMediaType.html @@ -11,14 +11,30 @@ @returns String */}} +{{ $MainType := "font" }} {{ $SubType := "woff2" }} -{{/* It appears CloudFlare produces an empty string when calling .MediaType.SubType on a 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 }} -{{ $MainType := .MediaType.MainType }} +{{ with .MediaType.MainType }} + {{ $MainType = . }} +{{ end }} + +{{ $MediaType := "%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 ` has an unsupported `type` value` warning on non-font "types". +*/}} +{{ $irregular := dict + "application/font-woff" "font/woff" +}} +{{ with index $irregular $format }} + {{ $format = . }} +{{ end }} {{ return printf "%s/%s" $MainType $SubType }} \ No newline at end of file From 1db8fb0dac17f1149bb346e6c4fcdd3fc264a6b6 Mon Sep 17 00:00:00 2001 From: Regis Philibert Date: Thu, 1 Dec 2022 15:01:02 -0500 Subject: [PATCH 3/6] Fix pesky formatting --- core/fonts/private/GetMediaType.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/fonts/private/GetMediaType.html b/core/fonts/private/GetMediaType.html index dccf608..c91e3e6 100644 --- a/core/fonts/private/GetMediaType.html +++ b/core/fonts/private/GetMediaType.html @@ -24,7 +24,7 @@ {{ $MainType = . }} {{ end }} -{{ $MediaType := "%s/%s" $MainType $SubType }} +{{ $format := printf "%s/%s" $MainType $SubType }} {{/* Another weirdness for some files depending on hosting plaftorm. Some woff file would return application/font-woff @@ -37,4 +37,4 @@ {{ $format = . }} {{ end }} -{{ return printf "%s/%s" $MainType $SubType }} \ No newline at end of file +{{ return $format }} \ No newline at end of file From f808cf3357b42e2601df7f851d594b9293449e55 Mon Sep 17 00:00:00 2001 From: Regis Philibert Date: Thu, 1 Dec 2022 15:14:43 -0500 Subject: [PATCH 4/6] Ensure not font-face at rule is printed if no files are found --- core/fonts/private/ParseFont.html | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/core/fonts/private/ParseFont.html b/core/fonts/private/ParseFont.html index aae9f1b..365b9e0 100644 --- a/core/fonts/private/ParseFont.html +++ b/core/fonts/private/ParseFont.html @@ -36,7 +36,7 @@ {{ $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 }} @@ -67,4 +67,8 @@ {{ end }} {{ $s.SetInMap "data" "preload" $preload }} +{{ if not ($s.Get "data").resources }} + {{ $s.Set "data" dict }} +{{ end }} + {{ return $s.Get "data" }} \ No newline at end of file From 5a8bb91bd5c04b2aef5b46dcee9d4ce373ef2fa3 Mon Sep 17 00:00:00 2001 From: Regis Philibert Date: Thu, 1 Dec 2022 16:49:59 -0500 Subject: [PATCH 5/6] Rename `base` setting to `cascade` Move `preload` setting to font (use cascade for global) --- core/fonts/private/ParseFont.html | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/core/fonts/private/ParseFont.html b/core/fonts/private/ParseFont.html index 365b9e0..b1b6b2a 100644 --- a/core/fonts/private/ParseFont.html +++ b/core/fonts/private/ParseFont.html @@ -41,7 +41,7 @@ {{ end }} {{ $font := . }} -{{ with $config.base }} +{{ with $config.cascade }} {{ $font = merge . $font }} {{ end }} @@ -55,16 +55,14 @@ {{ end }} {{ $preload := true }} -{{/* First we check for the global setting */}} -{{ with $config }} + +{{ with $font }} + {{/* Isset to ensure a falsy value is taken into account if set. */}} {{ if isset . "preload" }} {{ $preload = .preload }} {{ end }} {{ end }} -{{/* if preload is set (can be `false`) on the declaration itself, it overwrites global's */}} -{{ if isset $font "preload" }} - {{ $preload = $.preload }} -{{ end }} + {{ $s.SetInMap "data" "preload" $preload }} {{ if not ($s.Get "data").resources }} From 514f4685743128de72cdd3d422087064b14c1b1a Mon Sep 17 00:00:00 2001 From: Regis Philibert Date: Fri, 2 Dec 2022 10:46:08 -0500 Subject: [PATCH 6/6] Add "tech" font setting (variable fonts) --- core/fonts/private/ParseFont.html | 14 +++++++++----- core/fonts/private/ParseFontface.html | 6 +++++- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/core/fonts/private/ParseFont.html b/core/fonts/private/ParseFont.html index b1b6b2a..0536825 100644 --- a/core/fonts/private/ParseFont.html +++ b/core/fonts/private/ParseFont.html @@ -12,6 +12,7 @@ String (.file) Slice (.local) Boolean | Slice of Strings (.preload) + String (.tech) Resources (.resources) Map (.propertiers) String (.family) @@ -54,13 +55,16 @@ {{ $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 }} - {{/* Isset to ensure a falsy value is taken into account if set. */}} - {{ if isset . "preload" }} - {{ $preload = .preload }} - {{ end }} + +{{ with $font.tech }} + {{ $s.SetInMap "data" "tech" . }} {{ end }} {{ $s.SetInMap "data" "preload" $preload }} diff --git a/core/fonts/private/ParseFontface.html b/core/fonts/private/ParseFontface.html index f050796..ed1ae65 100644 --- a/core/fonts/private/ParseFontface.html +++ b/core/fonts/private/ParseFontface.html @@ -35,7 +35,11 @@ {{ 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") }}