diff --git a/client/public/index.html b/client/public/index.html index 806aa39..e7f6664 100644 --- a/client/public/index.html +++ b/client/public/index.html @@ -12,6 +12,17 @@ /> Palette Switcher + diff --git a/client/src/App.tsx b/client/src/App.tsx index 2db5f4a..6dfe672 100644 --- a/client/src/App.tsx +++ b/client/src/App.tsx @@ -33,7 +33,7 @@ function App() { }; return ( -
+
diff --git a/client/src/Header.tsx b/client/src/Header.tsx index 83c2559..0634bc9 100644 --- a/client/src/Header.tsx +++ b/client/src/Header.tsx @@ -1,6 +1,7 @@ import { faGithub } from "@fortawesome/free-brands-svg-icons"; import { faIgloo } from "@fortawesome/free-solid-svg-icons"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import ThemeToggler from "./ThemeToggler"; function Header() { return ( @@ -37,6 +38,9 @@ function Header() { . Visit using your own node ! + + +
); } diff --git a/client/src/ThemeToggler.tsx b/client/src/ThemeToggler.tsx new file mode 100644 index 0000000..39bfcbb --- /dev/null +++ b/client/src/ThemeToggler.tsx @@ -0,0 +1,78 @@ +import { + faMoon, + faSun, + IconDefinition, +} from "@fortawesome/free-solid-svg-icons"; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import { useEffect, useState } from "react"; + +type Theme = "light" | "dark"; + +function ThemeToggler() { + const userPrefersDarkMode = (): boolean => { + return ( + localStorage.theme === "dark" || + (!("theme" in localStorage) && + window.matchMedia("(prefers-color-scheme: dark)").matches) + ); + }; + + const getCurrentTheme = (): Theme => { + // We have a theme set + if ("theme" in localStorage) { + const theme = localStorage.getItem("theme"); + // Is it valid ? + if (theme === "dark" || theme === "light") { + return theme; + } else { + // Invalid theme, remove it and return default + localStorage.removeItem("theme"); + return userPrefersDarkMode() ? "dark" : "light"; + } + } else { + return userPrefersDarkMode() ? "dark" : "light"; + } + }; + + const [theme, setTheme] = useState(getCurrentTheme()); + + const rotateTheme = () => { + switch (theme) { + case "light": + setTheme("dark"); + break; + case "dark": + setTheme("light"); + break; + } + }; + + const getIcon = (): IconDefinition => { + switch (theme) { + case "light": + return faMoon; + case "dark": + return faSun; + } + }; + + useEffect(() => { + localStorage.theme = theme; + + if (theme === "dark") { + document.documentElement.classList.add("dark"); + } else if (theme === "light") { + document.documentElement.classList.remove("dark"); + } + }, [theme]); + + return ( + + ); +} + +export default ThemeToggler; diff --git a/client/tailwind.config.js b/client/tailwind.config.js index 2143195..56d0af0 100644 --- a/client/tailwind.config.js +++ b/client/tailwind.config.js @@ -1,5 +1,6 @@ module.exports = { content: ["./src/**/*.{ts,tsx}", "./public/index.html}"], + darkMode: "class", theme: { extend: { colors: {