Skip to content

Commit

Permalink
feat: add option to set default theme and hide toggle button (#146)
Browse files Browse the repository at this point in the history
resolves #135 

Light / dark theme can be configured via:

```yaml
  theme:
    # light | dark | system
    default: system
    displayToggle: true
```
  • Loading branch information
imfing authored Oct 21, 2023
1 parent 93cb788 commit 97e6945
Show file tree
Hide file tree
Showing 7 changed files with 113 additions and 57 deletions.
77 changes: 44 additions & 33 deletions assets/js/theme.js
Original file line number Diff line number Diff line change
@@ -1,40 +1,51 @@
// Dark theme toggle
// Light / Dark theme toggle
(function () {
const defaultTheme = '{{ site.Params.theme.default | default `system`}}'

const themeToggleButtons = document.querySelectorAll(".theme-toggle");
const themeToggleButtons = document.querySelectorAll(".theme-toggle");

// Change the icons inside the button based on previous settings
if (
localStorage.getItem("color-theme") === "dark" ||
(!("color-theme" in localStorage) && window.matchMedia("(prefers-color-scheme: dark)").matches)
) {
themeToggleButtons.forEach((el) => el.dataset.theme = "dark");
} else {
themeToggleButtons.forEach((el) => el.dataset.theme = "light");
}
// Change the icons of the buttons based on previous settings or system theme
if (
localStorage.getItem("color-theme") === "dark" ||
(!("color-theme" in localStorage) &&
((window.matchMedia("(prefers-color-scheme: dark)").matches && defaultTheme === "system") || defaultTheme === "dark"))
) {
themeToggleButtons.forEach((el) => el.dataset.theme = "dark");
} else {
themeToggleButtons.forEach((el) => el.dataset.theme = "light");
}

themeToggleButtons.forEach((el) => {
el.addEventListener("click", function () {
if (localStorage.getItem("color-theme")) {
if (localStorage.getItem("color-theme") === "light") {
document.documentElement.classList.add("dark");
document.documentElement.style.colorScheme = "dark";
localStorage.setItem("color-theme", "dark");
// Add click event handler to the buttons
themeToggleButtons.forEach((el) => {
el.addEventListener("click", function () {
if (localStorage.getItem("color-theme")) {
if (localStorage.getItem("color-theme") === "light") {
setDarkTheme();
localStorage.setItem("color-theme", "dark");
} else {
setLightTheme();
localStorage.setItem("color-theme", "light");
}
} else {
document.documentElement.classList.remove("dark");
document.documentElement.style.colorScheme = "light";
localStorage.setItem("color-theme", "light");
}
} else {
if (document.documentElement.classList.contains("dark")) {
document.documentElement.classList.remove("dark");
document.documentElement.style.colorScheme = "light";
localStorage.setItem("color-theme", "light");
} else {
document.documentElement.classList.add("dark");
document.documentElement.style.colorScheme = "dark";
localStorage.setItem("color-theme", "dark");
if (document.documentElement.classList.contains("dark")) {
setLightTheme();
localStorage.setItem("color-theme", "light");
} else {
setDarkTheme();
localStorage.setItem("color-theme", "dark");
}
}
el.dataset.theme = document.documentElement.classList.contains("dark") ? "dark" : "light";
});
});

// Listen for system theme changes
window.matchMedia("(prefers-color-scheme: dark)").addEventListener("change", (e) => {
if (defaultTheme === "system" && !("color-theme" in localStorage)) {
e.matches ? setDarkTheme() : setLightTheme();
themeToggleButtons.forEach((el) =>
el.dataset.theme = document.documentElement.classList.contains("dark") ? "dark" : "light"
);
}
el.dataset.theme = document.documentElement.classList.contains("dark") ? "dark" : "light";
});
});
})();
28 changes: 24 additions & 4 deletions exampleSite/content/docs/guide/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ weight: 2

Hugo reads its configuration from `hugo.yaml` in the root of your Hugo site.
The config file is where you can configure all aspects of your site.
You can find the config file for this site in `exampleSite/hugo.yaml` as a good starting point.
Check out the config file for this site [`exampleSite/hugo.yaml`](https://github.com/imfing/hextra/blob/main/exampleSite/hugo.yaml) on GitHub to get a comprehensive idea of available settings and best practices.

<!--more-->

Expand Down Expand Up @@ -181,6 +181,26 @@ Include both `favicon.ico` and `favicon.svg` files in your project to ensure you
While `favicon.ico` is generally for older browsers, `favicon.svg` is supported by modern ones. The optional `favicon-dark.svg` can be included for a tailored experience in dark mode.
Feel free to use tools like [favicon.io](https://favicon.io/) or [favycon](https://github.com/ruisaraiva19/favycon) to generate these icons.

### Theme Configuration

Use the `theme` setting to configure the default theme mode and toggle button, allowing visitors to switch between light or dark mode.

```yaml {filename="hugo.yaml"}
params:
theme:
# light | dark | system
default: system
displayToggle: true
```

Options for `theme.default`:

- `light` - always use light mode
- `dark` - always use dark mode
- `system` - sync with the operating system setting (default)

The `theme.displayToggle` parameter allows you to display a toggle button for changing themes.
When set to `true`, visitors can switch between light or dark mode, overriding the default setting.

### Page Width

Expand All @@ -193,8 +213,7 @@ params:
width: wide
```

There are three available options: `full`, `wide`, and `normal`.
By default, the page width is set to `normal`.
There are three available options: `full`, `wide`, and `normal`. By default, the page width is set to `normal`.

Similarly, the width of the navbar and footer can be customized by the `params.navbar.width` and `params.footer.width` parameters.

Expand All @@ -215,7 +234,8 @@ params:
index: content
```

available options for `flexsearch.index`:
Options for `flexsearch.index`:

- `content` - full content of the page (default)
- `summary` - summary of the page, see [Hugo Content Summaries](https://gohugo.io/content-management/summaries/) for more details
- `heading` - level 1 and level 2 headings
Expand Down
5 changes: 5 additions & 0 deletions exampleSite/hugo.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,11 @@ params:
# full (100%), wide (90rem), normal (1280px)
width: normal

theme:
# light | dark | system
default: system
displayToggle: true

footer:
displayCopyright: true
displayPoweredBy: true
Expand Down
16 changes: 10 additions & 6 deletions layouts/partials/footer.html
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{{- $enableFooterSwitches := .Scratch.Get "enableFooterSwitches" | default false -}}
{{- $displayThemeToggle := site.Params.theme.displayToggle | default true -}}

{{- $copyright := (T "copyright") | default "© 2023 Hextra." -}}

Expand All @@ -11,16 +12,19 @@
{{ end -}}
{{- end -}}


<footer class="hextra-footer bg-gray-100 pb-[env(safe-area-inset-bottom)] dark:bg-neutral-900 print:bg-transparent">
{{- if $enableFooterSwitches }}
<div class='mx-auto flex gap-2 py-2 px-4 {{ $footerWidth }}'>
{{- if $enableFooterSwitches -}}
<div class="mx-auto flex gap-2 py-2 px-4 {{ $footerWidth }}">
{{- partial "language-switch.html" (dict "context" .) -}}
{{- partial "theme-toggle.html" -}}
{{- with $displayThemeToggle }}{{ partial "theme-toggle.html" }}{{ end -}}
</div>
{{ end -}}
<hr class="dark:border-neutral-800" />
{{- if or site.IsMultiLingual $displayThemeToggle -}}
<hr class="dark:border-neutral-800" />
{{- end -}}
{{- end -}}
<div
class='{{ $footerWidth }} mx-auto flex justify-center py-12 pl-[max(env(safe-area-inset-left),1.5rem)] pr-[max(env(safe-area-inset-right),1.5rem)] text-gray-600 dark:text-gray-400 md:justify-start'
class="{{ $footerWidth }} mx-auto flex justify-center py-12 pl-[max(env(safe-area-inset-left),1.5rem)] pr-[max(env(safe-area-inset-right),1.5rem)] text-gray-600 dark:text-gray-400 md:justify-start"
>
<div class="flex w-full flex-col items-center sm:items-start">
{{- if (.Site.Params.footer.displayPoweredBy | default true) }}<div class="font-semibold">{{ template "theme-credit" . }}</div>{{ end }}
Expand Down
16 changes: 14 additions & 2 deletions layouts/partials/head.html
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,25 @@

<script>
/* Initialize light/dark mode */
if (localStorage.getItem("color-theme") === "dark" || (!("color-theme" in localStorage) && window.matchMedia("(prefers-color-scheme: dark)").matches)) {
const defaultTheme = '{{ site.Params.theme.default | default `system`}}';

const setDarkTheme = () => {
document.documentElement.classList.add("dark");
document.documentElement.style.colorScheme = "dark";
} else {
}
const setLightTheme = () => {
document.documentElement.classList.remove("dark");
document.documentElement.style.colorScheme = "light";
}

if ("color-theme" in localStorage) {
localStorage.getItem("color-theme") === "dark" ? setDarkTheme() : setLightTheme();
} else {
defaultTheme === "dark" ? setDarkTheme() : setLightTheme();
if (defaultTheme === "system") {
window.matchMedia("(prefers-color-scheme: dark)").matches ? setDarkTheme() : setLightTheme();
}
}
</script>

{{ partial "custom/head-end.html" . }}
Expand Down
2 changes: 1 addition & 1 deletion layouts/partials/scripts.html
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{{- $jsTheme := resources.Get "js/theme.js" -}}
{{- $jsTheme := resources.Get "js/theme.js" | resources.ExecuteAsTemplate "theme.js" . -}}
{{- $jsMenu := resources.Get "js/menu.js" -}}
{{- $jsTabs := resources.Get "js/tabs.js" -}}
{{- $jsLang := resources.Get "js/lang.js" -}}
Expand Down
26 changes: 15 additions & 11 deletions layouts/partials/sidebar.html
Original file line number Diff line number Diff line change
Expand Up @@ -34,17 +34,21 @@
{{ end -}}
</div>
{{/* Hide theme switch when sidebar is disabled */}}
{{ $switchesClass := cond $disableSidebar "md:hidden" "" }}
<div class="{{ $switchesClass }} {{ with site.IsMultiLingual }}justify-end{{ end }} sticky bottom-0 bg-white dark:bg-dark mx-4 py-4 shadow-[0_-12px_16px_#fff] flex items-center gap-2 dark:border-neutral-800 dark:shadow-[0_-12px_16px_#111] contrast-more:border-neutral-400 contrast-more:shadow-none contrast-more:dark:shadow-none border-t" data-toggle-animation="show">
{{- with site.IsMultiLingual }}
{{ partial "language-switch" (dict "context" $context "grow" true) }}
{{ partial "theme-toggle" (dict "hideLabel" true) }}
{{ else }}
<div class="flex grow flex-col">
{{ partial "theme-toggle" }}
</div>
{{ end -}}
</div>
{{ $switchesClass := cond $disableSidebar "md:hidden" "" -}}
{{ $displayThemeToggle := (site.Params.theme.displayToggle | default true) -}}

{{ if or site.IsMultiLingual $displayThemeToggle }}
<div class="{{ $switchesClass }} {{ with site.IsMultiLingual }}justify-end{{ end }} sticky bottom-0 bg-white dark:bg-dark mx-4 py-4 shadow-[0_-12px_16px_#fff] flex items-center gap-2 dark:border-neutral-800 dark:shadow-[0_-12px_16px_#111] contrast-more:border-neutral-400 contrast-more:shadow-none contrast-more:dark:shadow-none border-t" data-toggle-animation="show">
{{- with site.IsMultiLingual -}}
{{- partial "language-switch" (dict "context" $context "grow" true) -}}
{{- with $displayThemeToggle }}{{ partial "theme-toggle" (dict "hideLabel" true) }}{{ end -}}
{{- else -}}
{{- with $displayThemeToggle -}}
<div class="flex grow flex-col">{{ partial "theme-toggle" }}</div>
{{- end -}}
{{- end -}}
</div>
{{- end -}}
</aside>

{{- define "sidebar-main" -}}
Expand Down

0 comments on commit 97e6945

Please sign in to comment.