forked from drowl87/hextra_mirror
		
	feat: add option to set default theme and hide toggle button (#146)
resolves #135 Light / dark theme can be configured via: ```yaml theme: # light | dark | system default: system displayToggle: true ```
This commit is contained in:
		| @@ -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 |   // Change the icons of the buttons based on previous settings or system theme | ||||||
| if ( |   if ( | ||||||
|   localStorage.getItem("color-theme") === "dark" || |     localStorage.getItem("color-theme") === "dark" || | ||||||
|   (!("color-theme" in localStorage) && window.matchMedia("(prefers-color-scheme: dark)").matches) |     (!("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 = "dark"); | ||||||
|   themeToggleButtons.forEach((el) => el.dataset.theme = "light"); |   } else { | ||||||
| } |     themeToggleButtons.forEach((el) => el.dataset.theme = "light"); | ||||||
|  |   } | ||||||
|  |  | ||||||
| themeToggleButtons.forEach((el) => { |   // Add click event handler to the buttons | ||||||
|   el.addEventListener("click", function () { |   themeToggleButtons.forEach((el) => { | ||||||
|     if (localStorage.getItem("color-theme")) { |     el.addEventListener("click", function () { | ||||||
|       if (localStorage.getItem("color-theme") === "light") { |       if (localStorage.getItem("color-theme")) { | ||||||
|         document.documentElement.classList.add("dark"); |         if (localStorage.getItem("color-theme") === "light") { | ||||||
|         document.documentElement.style.colorScheme = "dark"; |           setDarkTheme(); | ||||||
|         localStorage.setItem("color-theme", "dark"); |           localStorage.setItem("color-theme", "dark"); | ||||||
|  |         } else { | ||||||
|  |           setLightTheme(); | ||||||
|  |           localStorage.setItem("color-theme", "light"); | ||||||
|  |         } | ||||||
|       } else { |       } else { | ||||||
|         document.documentElement.classList.remove("dark"); |         if (document.documentElement.classList.contains("dark")) { | ||||||
|         document.documentElement.style.colorScheme = "light"; |           setLightTheme(); | ||||||
|         localStorage.setItem("color-theme", "light"); |           localStorage.setItem("color-theme", "light"); | ||||||
|  |         } else { | ||||||
|  |           setDarkTheme(); | ||||||
|  |           localStorage.setItem("color-theme", "dark"); | ||||||
|  |         } | ||||||
|       } |       } | ||||||
|     } else { |       el.dataset.theme = document.documentElement.classList.contains("dark") ? "dark" : "light"; | ||||||
|       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"); |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
|     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" | ||||||
|  |       ); | ||||||
|  |     } | ||||||
|  |   }); | ||||||
|  | })(); | ||||||
|   | |||||||
| @@ -5,7 +5,7 @@ weight: 2 | |||||||
|  |  | ||||||
| Hugo reads its configuration from `hugo.yaml` in the root of your Hugo site. | 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. | 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--> | <!--more--> | ||||||
|  |  | ||||||
| @@ -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. | 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. | 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 | ### Page Width | ||||||
|  |  | ||||||
| @@ -193,8 +213,7 @@ params: | |||||||
|     width: wide |     width: wide | ||||||
| ``` | ``` | ||||||
|  |  | ||||||
| There are three available options: `full`, `wide`, and `normal`. | There are three available options: `full`, `wide`, and `normal`. By default, the page width is set to `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. | Similarly, the width of the navbar and footer can be customized by the `params.navbar.width` and `params.footer.width` parameters. | ||||||
|  |  | ||||||
| @@ -215,7 +234,8 @@ params: | |||||||
|       index: content |       index: content | ||||||
| ``` | ``` | ||||||
|  |  | ||||||
| available options for `flexsearch.index`: | Options for `flexsearch.index`: | ||||||
|  |  | ||||||
| - `content` - full content of the page (default) | - `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 | - `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 | - `heading` - level 1 and level 2 headings | ||||||
|   | |||||||
| @@ -109,6 +109,11 @@ params: | |||||||
|     # full (100%), wide (90rem), normal (1280px) |     # full (100%), wide (90rem), normal (1280px) | ||||||
|     width: normal |     width: normal | ||||||
|  |  | ||||||
|  |   theme: | ||||||
|  |     # light | dark | system | ||||||
|  |     default: system | ||||||
|  |     displayToggle: true | ||||||
|  |  | ||||||
|   footer: |   footer: | ||||||
|     displayCopyright: true |     displayCopyright: true | ||||||
|     displayPoweredBy: true |     displayPoweredBy: true | ||||||
|   | |||||||
| @@ -1,4 +1,5 @@ | |||||||
| {{- $enableFooterSwitches := .Scratch.Get "enableFooterSwitches" | default false -}} | {{- $enableFooterSwitches := .Scratch.Get "enableFooterSwitches" | default false -}} | ||||||
|  | {{- $displayThemeToggle := site.Params.theme.displayToggle | default true -}} | ||||||
|  |  | ||||||
| {{- $copyright := (T "copyright") | default "© 2023 Hextra." -}} | {{- $copyright := (T "copyright") | default "© 2023 Hextra." -}} | ||||||
|  |  | ||||||
| @@ -11,16 +12,19 @@ | |||||||
|   {{ end -}} |   {{ end -}} | ||||||
| {{- end -}} | {{- end -}} | ||||||
|  |  | ||||||
|  |  | ||||||
| <footer class="hextra-footer bg-gray-100 pb-[env(safe-area-inset-bottom)] dark:bg-neutral-900 print:bg-transparent"> | <footer class="hextra-footer bg-gray-100 pb-[env(safe-area-inset-bottom)] dark:bg-neutral-900 print:bg-transparent"> | ||||||
|   {{- if $enableFooterSwitches }} |   {{- if $enableFooterSwitches -}} | ||||||
|     <div class='mx-auto flex gap-2 py-2 px-4 {{ $footerWidth }}'> |     <div class="mx-auto flex gap-2 py-2 px-4 {{ $footerWidth }}"> | ||||||
|       {{- partial "language-switch.html" (dict "context" .) -}} |       {{- partial "language-switch.html" (dict "context" .) -}} | ||||||
|       {{- partial "theme-toggle.html" -}} |       {{- with $displayThemeToggle }}{{ partial "theme-toggle.html" }}{{ end -}} | ||||||
|     </div> |     </div> | ||||||
|   {{ end -}} |     {{- if or site.IsMultiLingual $displayThemeToggle -}} | ||||||
|   <hr class="dark:border-neutral-800" /> |       <hr class="dark:border-neutral-800" /> | ||||||
|  |     {{- end -}} | ||||||
|  |   {{- end -}} | ||||||
|   <div |   <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"> |     <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 }} |       {{- if (.Site.Params.footer.displayPoweredBy | default true) }}<div class="font-semibold">{{ template "theme-credit" . }}</div>{{ end }} | ||||||
|   | |||||||
| @@ -33,13 +33,25 @@ | |||||||
|  |  | ||||||
|   <script> |   <script> | ||||||
|     /* Initialize light/dark mode */ |     /* 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.classList.add("dark"); | ||||||
|       document.documentElement.style.colorScheme = "dark"; |       document.documentElement.style.colorScheme = "dark"; | ||||||
|     } else { |     } | ||||||
|  |     const setLightTheme = () => { | ||||||
|       document.documentElement.classList.remove("dark"); |       document.documentElement.classList.remove("dark"); | ||||||
|       document.documentElement.style.colorScheme = "light"; |       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> |   </script> | ||||||
|  |  | ||||||
|   {{ partial "custom/head-end.html" . }} |   {{ partial "custom/head-end.html" . }} | ||||||
|   | |||||||
| @@ -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" -}} | {{- $jsMenu := resources.Get "js/menu.js" -}} | ||||||
| {{- $jsTabs := resources.Get "js/tabs.js" -}} | {{- $jsTabs := resources.Get "js/tabs.js" -}} | ||||||
| {{- $jsLang := resources.Get "js/lang.js" -}} | {{- $jsLang := resources.Get "js/lang.js" -}} | ||||||
|   | |||||||
| @@ -34,17 +34,21 @@ | |||||||
|     {{ end -}} |     {{ end -}} | ||||||
|   </div> |   </div> | ||||||
|   {{/* Hide theme switch when sidebar is disabled */}} |   {{/* Hide theme switch when sidebar is disabled */}} | ||||||
|   {{ $switchesClass := cond $disableSidebar "md:hidden" "" }} |   {{ $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"> |   {{ $displayThemeToggle := (site.Params.theme.displayToggle | default true) -}} | ||||||
|     {{- with site.IsMultiLingual }} |  | ||||||
|       {{ partial "language-switch" (dict "context" $context "grow" true) }} |   {{ if or site.IsMultiLingual $displayThemeToggle }} | ||||||
|       {{ partial "theme-toggle" (dict "hideLabel" true) }} |     <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"> | ||||||
|     {{ else }} |       {{- with site.IsMultiLingual -}} | ||||||
|       <div class="flex grow flex-col"> |         {{- partial "language-switch" (dict "context" $context "grow" true) -}} | ||||||
|         {{ partial "theme-toggle" }} |         {{- with $displayThemeToggle }}{{ partial "theme-toggle" (dict "hideLabel" true) }}{{ end -}} | ||||||
|       </div> |       {{- else -}} | ||||||
|     {{ end -}} |         {{- with $displayThemeToggle -}} | ||||||
|   </div> |           <div class="flex grow flex-col">{{ partial "theme-toggle" }}</div> | ||||||
|  |         {{- end -}} | ||||||
|  |       {{- end -}} | ||||||
|  |     </div> | ||||||
|  |   {{- end -}} | ||||||
| </aside> | </aside> | ||||||
|  |  | ||||||
| {{- define "sidebar-main" -}} | {{- define "sidebar-main" -}} | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Xin
					Xin