Add system theme fallback capability

The Hugo theme will also generate a counterpart system theme if there's
only one system theme given. Though, it isn't perfect so the release
will not happen for a while. I'll look into generating a color palette
with HSLuv to see if it can be improved.
This commit is contained in:
Gabriel Arazas 2022-04-30 15:45:17 +08:00
parent 1d9de2264d
commit cc4547437d
8 changed files with 211 additions and 86 deletions

View File

@ -21,15 +21,28 @@ and this project adheres to https://semver.org/spec/v2.0.0.html[Semantic Version
=== Changed === Changed
* Increase the minimum version required to v0.95.0 due to using much of the new features found on the release.
* Clean the layouts. * Clean the layouts.
* Change the style of the horizontal rule with colors. * Change the style of the horizontal rule with colors.
* The theme button is placed in the site header instead of the top-rightmost side of the viewport.
* Update the link:https://github.com/foo-dogsquared/hugo-mod-simple-icons[Simple Icons module]. * Update the link:https://github.com/foo-dogsquared/hugo-mod-simple-icons[Simple Icons module].
For reference, it is from link:https://github.com/simple-icons/simple-icons/commit/6f83d1dd85662360353c73d42c6b6b4ca75d6e14[this commit]. For reference, it is from link:https://github.com/simple-icons/simple-icons/commit/6f83d1dd85662360353c73d42c6b6b4ca75d6e14[this commit].
* Improve the list template to be more considerable to easy eyeing of the posts. * Improve the list template to be more considerable to easy eyeing of the posts.
* Fallback themes are now enforced to be implemented into two themes: one for light and one for dark theme.
This is changed from a single `_index` Base16 scheme to `_{dark,light}` Base16 scheme.
The Hugo theme also has fallbacks for certain cases.
** If the user gives only one system theme, the Hugo theme will generate the appropriate counterpart theme.
E.g., if there is only `_dark`, the Hugo theme will generate the light theme.
** If given neither, fallback themes will be used.
=== Fixed === Fixed

View File

@ -32,8 +32,8 @@ The following features highlights the differences from the original.
* Clean(er) reader mode interface for a nice reading experience for your readers. * Clean(er) reader mode interface for a nice reading experience for your readers.
* Uses https://sass-lang.com/[SCSS] instead of CSS for more concise formatting. footnote:needs-hugo-extended[It needs Hugo extended version.] * Uses https://sass-lang.com/[SCSS] instead of CSS for more concise formatting. footnote:needs-hugo-extended[It needs Hugo extended version.]
* More colors with a http://chriskempson.com/projects/base16/[base-16]-based color scheme. footnote:needs-hugo-extended[] * More colors with a http://chriskempson.com/projects/base16/[base-16]-based color scheme. footnote:needs-hugo-extended[]
* Create more custom color schemes easily with https://github.com/chriskempson/base16[Base16 color schemes] without touching any CSS! * Create more custom color schemes easily with https://github.com/chriskempson/base16[Base16 color schemes] without touching any CSS! footnote:needs-hugo-extended[]
* Link your social media platforms with icons from the entire set from https://simpleicons.org/[Simple Icons] featuring more than 1000 icons! * Link your social media platforms with icons from the entire set from https://simpleicons.org/[Simple Icons] featuring more than 2000 icons!
* With most of the features retained from the original theme (except fancier). * With most of the features retained from the original theme (except fancier).
This is mainly for personal blogs running a one-man show. This is mainly for personal blogs running a one-man show.
@ -278,14 +278,10 @@ base0E: "ba8baf"
base0F: "a16946" base0F: "a16946"
---- ----
You can also use https://github.com/chriskempson/base16#scheme-repositories[any of the existing color schemes] as a starting point. By default, this theme enforces setting system themes with a light and a dark theme.
If you want to override the default scheme, you can place the file as `_index.{json,toml,yaml}` (of whatever appropriate data format of your choice). You can set the custom themes for both system light and dark theme for your website by naming them `_light.{json,toml,yaml}` and `_dark.{json,toml,yaml}`, respectively.
If either theme is missing, the theme will generate one for you with the assumption that the user-given theme is set correctly (e.g., `_dark` is a dark theme and the theme will generate a light theme).
CAUTION: Setting the default theme through `_index` is deprecated. If neither system themes are given, the theme will use the fallback system themes.
Please set them through the dark/light theme instead.
You can also set the light and dark theme for your website by naming them `_light.{json,toml,yaml}` and `_dark.{json,toml,yaml}`, respectively.
This will add certain options in the theme selection button as well as the ability to set the OS default.
The schemes are pressed against a template (i.e., link:./assets/templates/theme.scss[`./assets/templates/theme.scss`]) then added to the resulting stylesheet. The schemes are pressed against a template (i.e., link:./assets/templates/theme.scss[`./assets/templates/theme.scss`]) then added to the resulting stylesheet.

View File

@ -1,17 +1,95 @@
{{- range $name, $scheme := (index $.Site.Data "more-contentful").themes }} {{ $data := newScratch }}
// This is a template for a colorscheme based from a Base16 data file from https://github.com/chriskempson/base16. @use "sass:color";
@mixin createColorScheme($invert: false) {
{{/*
Create an automatic way of generating system color schemes, if set by the user.
* If either only one is set, generate an appropriate color scheme with the given color scheme.
For example, if there is only a given dark theme, the theme will generate a light color scheme.
* If given neither, go with the fallback themes.
*/}}
{{ $themes := (index $.Site.Data "more-contentful").themes }}
{{ $hasLight := $themes._light }}
{{ $hasDark := $themes._dark }}
{{ $hasSystemTheme := or $hasLight $hasDark }}
{{/*
Take note how the other half get its colors. It's not exactly a color
string but it is a SASS expression to be evaluated and put into string
interpolation in SASS.
*/}}
{{ if (and $hasLight (not $hasDark)) }}
{{- warnf "No given dark theme. Generating one from the light theme..." }}
{{ $darkTheme := dict
"scheme" (printf "%s (light)" $hasLight.scheme)
"base00" $hasLight.base07
"base01" $hasLight.base06
"base02" $hasLight.base05
"base03" $hasLight.base04
"base04" $hasLight.base03
"base05" $hasLight.base02
"base06" $hasLight.base01
"base07" $hasLight.base00
"base08" (print "{lighten(saturate(#" $hasLight.base08 ", 10%), 15%)}")
"base09" (print "{lighten(saturate(#" $hasLight.base09 ", 10%), 15%)}")
"base0A" (print "{lighten(saturate(#" $hasLight.base0A ", 10%), 15%)}")
"base0B" (print "{lighten(saturate(#" $hasLight.base0B ", 10%), 15%)}")
"base0C" (print "{lighten(saturate(#" $hasLight.base0C ", 10%), 15%)}")
"base0D" (print "{lighten(saturate(#" $hasLight.base0D ", 10%), 15%)}")
"base0E" (print "{lighten(saturate(#" $hasLight.base0E ", 10%), 15%)}")
"base0F" (print "{lighten(saturate(#" $hasLight.base0F ", 10%), 15%)}")
}}
{{ $themes = merge $themes (dict "_dark" $darkTheme) }}
{{ else if (and $hasDark (not $hasLight)) }}
{{- warnf "No given light theme. Generating one from the dark theme..." }}
{{ $lightTheme := dict
"scheme" (printf "%s (light)" $hasDark.scheme)
"base00" $hasDark.base07
"base01" $hasDark.base06
"base02" $hasDark.base05
"base03" $hasDark.base04
"base04" $hasDark.base03
"base05" $hasDark.base02
"base06" $hasDark.base01
"base07" $hasDark.base00
"base08" (print "{darken(saturate(#" $hasDark.base08 ", 10%), 15%)}")
"base09" (print "{darken(saturate(#" $hasDark.base09 ", 10%), 15%)}")
"base0A" (print "{darken(saturate(#" $hasDark.base0A ", 10%), 15%)}")
"base0B" (print "{darken(saturate(#" $hasDark.base0B ", 10%), 15%)}")
"base0C" (print "{darken(saturate(#" $hasDark.base0C ", 10%), 15%)}")
"base0D" (print "{darken(saturate(#" $hasDark.base0D ", 10%), 15%)}")
"base0E" (print "{darken(saturate(#" $hasDark.base0E ", 10%), 15%)}")
"base0F" (print "{darken(saturate(#" $hasDark.base0F ", 10%), 15%)}")
}}
{{ $themes = merge $themes (dict "_light" $lightTheme) }}
{{ else if not $hasSystemTheme }}
{{ $systemThemes := dict
"_dark" $themes._dark_fallback
"_light" $themes._light_fallback
}}
{{ $themes = merge $systemThemes $themes }}
{{ end }}
{{- range $name, $scheme := $themes }}
// This is a template for a colorscheme based from a Base16 data file from
// https://github.com/chriskempson/base16.
@mixin createColorScheme {
{{- range $i := seq 0 15 }} {{- range $i := seq 0 15 }}
{{- $hex := upper (printf "%02x" $i) }} {{- $hex := upper (printf "%02x" $i) }}
{{- $key := printf "base%s" $hex }} {{- $key := printf "base%s" $hex }}
@if $invert {
--{{ $key }}: #{invert(#{{ index $scheme $key }}, 100%)}; // TODO: Make a better way to interpolate the color strings.
} @else { {{/* We're just taking advantage the fact that the SASS color functions
--{{ $key }}: #{{ index $scheme $key }}; returns the colors in the same format we needed. */}}
} {{- $color := printf "#%s" (index $scheme $key) }}
--{{ $key }}: {{ $color }};
{{- end }} {{- end }}
} }
{{- if (or (eq $name "_light_fallback") (eq $name "_dark_fallback")) }}
{{ continue }}
{{- end }}
{{- if eq $name "_light" }} {{- if eq $name "_light" }}
@media (prefers-color-scheme: light) { @media (prefers-color-scheme: light) {
:root { :root {

View File

@ -1,7 +1,7 @@
[module] [module]
[module.hugoVersion] [module.hugoVersion]
extended = true extended = true
min = "0.74.0" min = "0.95.0"
[[module.imports]] [[module.imports]]
path = "github.com/foo-dogsquared/hugo-theme-contentful" path = "github.com/foo-dogsquared/hugo-theme-contentful"

View File

@ -15,5 +15,4 @@ base0B: "a1b56c"
base0C: "86c1b9" base0C: "86c1b9"
base0D: "7cafc2" base0D: "7cafc2"
base0E: "ba8baf" base0E: "ba8baf"
base0F: "a16946" base0F: "a16946"

View File

@ -0,0 +1,18 @@
scheme: "Default Light"
author: "Chris Kempson (http://chriskempson.com)"
base00: "f8f8f8"
base01: "e8e8e8"
base02: "d8d8d8"
base03: "b8b8b8"
base04: "585858"
base05: "383838"
base06: "282828"
base07: "181818"
base08: "ab4642"
base09: "dc9656"
base0A: "f7ca88"
base0B: "a1b56c"
base0C: "86c1b9"
base0D: "7cafc2"
base0E: "ba8baf"
base0F: "a16946"

View File

@ -34,69 +34,6 @@
{{ end }} {{ end }}
{{- /*
The theme button in its own bed.
Take note this component already has conditional rendering so a conditional is unnecessary.
*/ -}}
{{- define "partials/components/theme-button.html" }}
{{- if gt (len (index $.Site.Data "more-contentful").themes) 1 }}
<div class="site__theme-btn" aria-label="Theme toggle">
{{ partial "components/heroicon.html" "color-swatch" }}
<div class="site__theme-dropdown">
<div class="site__theme-dropdown-list">
{{- range $filename, $scheme := (index $.Site.Data "more-contentful").themes }}
{{- $isLight := false }}
{{- $isDark := false }}
{{- $name := cond (eq $filename "_index") (printf "%s (default)" .scheme) .scheme }}
{{- if eq $filename "_light" }}
{{- $name = i18n "theme_light" }}
{{- $isLight = true }}
{{- else if eq $filename "_dark" }}
{{- $name = i18n "theme_dark" }}
{{- $isDark = true }}
{{- end }}
{{- $hasSystemTheme := (or $isDark $isLight) }}
{{ if $hasSystemTheme }}
{{ .Scratch.Set "has-system-theme" $hasSystemTheme }}
{{ end }}
<div class="site__theme-item"
data-theme="{{ .scheme }}"
{{ if $isDark }}data-theme-dark{{ end }}
{{ if $isLight }}data-theme-light{{ end }}
>{{ $name }}</div>
{{- end }}
{{ .Scratch.Get "has-system-theme" }}
<div class="site__theme-item" data-theme-system>
{{ i18n "theme_os_default" }}
</div>
</div>
</div>
</div>
</div>
<script defer>
const themeDropdown = document.querySelector('.site__theme-btn');
themeDropdown.addEventListener('click', (event) => {
const { target } = event;
if (target.classList.contains("site__theme-item")) {
if (target.dataset.theme) {
theme = target.dataset.theme;
window.localStorage.setItem("theme", theme);
document.documentElement.dataset.theme = theme;
} else {
window.localStorage.removeItem("theme");
delete document.documentElement.dataset.theme;
}
}
});
</script>
{{- end }}
{{- end }}
{{- /* {{- /*
The component where it will display the metadata of the post. The component where it will display the metadata of the post.
This is used on list templates but feel free to change that. This is used on list templates but feel free to change that.

View File

@ -0,0 +1,84 @@
{{- /*
The theme button in its own bed.
Take note this component already has conditional rendering so a conditional is unnecessary.
*/ -}}
{{- if gt (len (index $.Site.Data "more-contentful").themes) 1 }}
<div class="site__theme-btn" aria-label="Theme toggle">
{{ partial "components/heroicon.html" "color-swatch" }}
<div class="site__theme-dropdown">
<div class="site__theme-dropdown-list">
{{ $themes := (index $.Site.Data "more-contentful").themes }}
{{ $hasLight := $themes._light }}
{{ $hasDark := $themes._dark }}
{{ $hasSystemTheme := or $hasLight $hasDark }}
{{/* This list should only need the scheme name of the themes. */}}
{{ if (and $hasLight (not $hasDark)) }}
{{ $darkTheme := dict
"scheme" (printf "%s (dark)" $hasLight.scheme)
}}
{{ $themes = merge $themes (dict "_dark" $darkTheme) }}
{{ else if (and $hasDark (not $hasLight)) }}
{{ $lightTheme := dict
"scheme" (printf "%s (light)" $hasDark.scheme)
}}
{{ $themes = merge $themes (dict "_light" $lightTheme) }}
{{ else if not $hasSystemTheme }}
{{ $systemThemes := dict
"_dark" $themes._dark_fallback
"_light" $themes._light_fallback
}}
{{ $themes = merge $themes $systemThemes }}
{{ end }}
{{- range $filename, $scheme := $themes }}
{{- if (or (eq $filename "_light_fallback") (eq $filename "_dark_fallback")) }}
{{ continue }}
{{- end }}
{{- $isLight := false }}
{{- $isDark := false }}
{{- $name := cond (eq $filename "_index") (printf "%s (default)" .scheme) .scheme }}
{{- if eq $filename "_light" }}
{{- $name = i18n "theme_light" }}
{{- $isLight = true }}
{{- else if eq $filename "_dark" }}
{{- $name = i18n "theme_dark" }}
{{- $isDark = true }}
{{- end }}
{{- $hasSystemTheme := (or $isDark $isLight) }}
{{ if $hasSystemTheme }}
{{ .Scratch.Set "has-system-theme" $hasSystemTheme }}
{{ end }}
<div class="site__theme-item"
data-theme="{{ .scheme }}"
{{ if $isDark }}data-theme-dark{{ end }}
{{ if $isLight }}data-theme-light{{ end }}
>{{ $name }}</div>
{{- end }}
<div class="site__theme-item" data-theme-system>
{{ i18n "theme_os_default" }}
</div>
</div>
</div>
</div>
<script defer>
const themeDropdown = document.querySelector('.site__theme-btn');
themeDropdown.addEventListener('click', (event) => {
const { target } = event;
if (target.classList.contains("site__theme-item")) {
if (target.dataset.theme) {
theme = target.dataset.theme;
window.localStorage.setItem("theme", theme);
document.documentElement.dataset.theme = theme;
} else {
window.localStorage.removeItem("theme");
delete document.documentElement.dataset.theme;
}
}
});
</script>
{{- end }}