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
* Increase the minimum version required to v0.95.0 due to using much of the new features found on the release.
* Clean the layouts.
* 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].
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.
* 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

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.
* 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[]
* Create more custom color schemes easily with https://github.com/chriskempson/base16[Base16 color schemes] without touching any CSS!
* Link your social media platforms with icons from the entire set from https://simpleicons.org/[Simple Icons] featuring more than 1000 icons!
* 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 2000 icons!
* With most of the features retained from the original theme (except fancier).
This is mainly for personal blogs running a one-man show.
@ -278,14 +278,10 @@ base0E: "ba8baf"
base0F: "a16946"
----
You can also use https://github.com/chriskempson/base16#scheme-repositories[any of the existing color schemes] as a starting point.
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).
CAUTION: Setting the default theme through `_index` is deprecated.
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.
By default, this theme enforces setting system themes with a light and a dark theme.
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).
If neither system themes are given, the theme will use the fallback system themes.
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 }}
// This is a template for a colorscheme based from a Base16 data file from https://github.com/chriskempson/base16.
@mixin createColorScheme($invert: false) {
{{ $data := newScratch }}
@use "sass:color";
{{/*
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 }}
{{- $hex := upper (printf "%02x" $i) }}
{{- $key := printf "base%s" $hex }}
@if $invert {
--{{ $key }}: #{invert(#{{ index $scheme $key }}, 100%)};
} @else {
--{{ $key }}: #{{ index $scheme $key }};
}
// TODO: Make a better way to interpolate the color strings.
{{/* We're just taking advantage the fact that the SASS color functions
returns the colors in the same format we needed. */}}
{{- $color := printf "#%s" (index $scheme $key) }}
--{{ $key }}: {{ $color }};
{{- end }}
}
{{- if (or (eq $name "_light_fallback") (eq $name "_dark_fallback")) }}
{{ continue }}
{{- end }}
{{- if eq $name "_light" }}
@media (prefers-color-scheme: light) {
:root {

View File

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

View File

@ -16,4 +16,3 @@ base0C: "86c1b9"
base0D: "7cafc2"
base0E: "ba8baf"
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 }}
{{- /*
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.
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 }}