diff --git a/assets/js/app.js b/assets/js/app.js index d5e278a..7e5779f 100644 --- a/assets/js/app.js +++ b/assets/js/app.js @@ -16,29 +16,35 @@ // // Include phoenix_html to handle method=PUT/DELETE in forms and buttons. -import "phoenix_html" +import "phoenix_html"; // Establish Phoenix Socket and LiveView configuration. -import {Socket} from "phoenix" -import {LiveSocket} from "phoenix_live_view" -import topbar from "../vendor/topbar" +import { Socket } from "phoenix"; +import { LiveSocket } from "phoenix_live_view"; +import topbar from "../vendor/topbar"; -let csrfToken = document.querySelector("meta[name='csrf-token']").getAttribute("content") +import darkModeHook from "../vendor/dark_mode"; +let Hooks = {}; +Hooks.DarkThemeToggle = darkModeHook; + +let csrfToken = document + .querySelector("meta[name='csrf-token']") + .getAttribute("content"); let liveSocket = new LiveSocket("/live", Socket, { - longPollFallbackMs: 2500, - params: {_csrf_token: csrfToken} -}) + longPollFallbackMs: 2500, + params: { _csrf_token: csrfToken }, + hooks: Hooks, +}); // Show progress bar on live navigation and form submits -topbar.config({barColors: {0: "#29d"}, shadowColor: "rgba(0, 0, 0, .3)"}) -window.addEventListener("phx:page-loading-start", _info => topbar.show(300)) -window.addEventListener("phx:page-loading-stop", _info => topbar.hide()) +topbar.config({ barColors: { 0: "#29d" }, shadowColor: "rgba(0, 0, 0, .3)" }); +window.addEventListener("phx:page-loading-start", (_info) => topbar.show(300)); +window.addEventListener("phx:page-loading-stop", (_info) => topbar.hide()); // connect if there are any LiveViews on the page -liveSocket.connect() +liveSocket.connect(); // expose liveSocket on window for web console debug logs and latency simulation: // >> liveSocket.enableDebug() // >> liveSocket.enableLatencySim(1000) // enabled for duration of browser session // >> liveSocket.disableLatencySim() -window.liveSocket = liveSocket - +window.liveSocket = liveSocket; diff --git a/assets/tailwind.config.js b/assets/tailwind.config.js index 2e6b547..749f87c 100644 --- a/assets/tailwind.config.js +++ b/assets/tailwind.config.js @@ -7,6 +7,7 @@ const path = require("path"); module.exports = { content: ["./js/**/*.js", "../lib/exmr_web.ex", "../lib/exmr_web/**/*.*ex"], + darkMode: "class", theme: { extend: { colors: { diff --git a/assets/vendor/dark_mode.js b/assets/vendor/dark_mode.js new file mode 100644 index 0000000..da02a50 --- /dev/null +++ b/assets/vendor/dark_mode.js @@ -0,0 +1,46 @@ +const localStorageKey = "theme"; + +const isDark = () => { + if (localStorage.getItem(localStorageKey) === "dark") return true; + if (localStorage.getItem(localStorageKey) === "light") return false; + return window.matchMedia("(prefers-color-scheme: dark)").matches; +}; + +const setupThemeToggle = () => { + toggleVisibility = (dark) => { + const themeToggleDarkIcon = document.getElementById( + "theme-toggle-dark-icon", + ); + const themeToggleLightIcon = document.getElementById( + "theme-toggle-light-icon", + ); + if (themeToggleDarkIcon == null || themeToggleLightIcon == null) return; + const show = dark ? themeToggleDarkIcon : themeToggleLightIcon; + const hide = dark ? themeToggleLightIcon : themeToggleDarkIcon; + show.classList.remove("hidden", "text-transparent"); + hide.classList.add("hidden", "text-transparent"); + if (dark) { + document.documentElement.classList.add("dark"); + } else { + document.documentElement.classList.remove("dark"); + } + try { + localStorage.setItem(localStorageKey, dark ? "dark" : "light"); + } catch (_err) { } + }; + toggleVisibility(isDark()); + document + .getElementById("theme-toggle") + .addEventListener("click", function() { + toggleVisibility(!isDark()); + }); +}; + +const darkModeHook = { + mounted() { + setupThemeToggle(); + }, + updated() { }, +}; + +export default darkModeHook; diff --git a/lib/exmr_web/components/core_components.ex b/lib/exmr_web/components/core_components.ex index 113ccbf..9dc1df1 100644 --- a/lib/exmr_web/components/core_components.ex +++ b/lib/exmr_web/components/core_components.ex @@ -232,7 +232,7 @@ defmodule ExmrWeb.CoreComponents do type={@type} class={[ "phx-submit-loading:opacity-75 rounded-lg bg-zinc-900 hover:bg-zinc-700 py-2 px-3", - "text-sm font-semibold leading-6 text-white active:text-white/80", + "text-sm font-semibold leading-6", @class ]} {@rest} @@ -429,10 +429,10 @@ defmodule ExmrWeb.CoreComponents do ~H"""
-

+

<%= render_slot(@inner_block) %>

-

+

<%= render_slot(@subtitle) %>

diff --git a/lib/exmr_web/components/dark_mode.ex b/lib/exmr_web/components/dark_mode.ex new file mode 100644 index 0000000..537e0be --- /dev/null +++ b/lib/exmr_web/components/dark_mode.ex @@ -0,0 +1,57 @@ +defmodule DarkMode do + @moduledoc """ + A component to toggle dark mode. + """ + + use Phoenix.Component + + def button(assigns) do + ~H""" + + + + """ + end +end diff --git a/lib/exmr_web/components/layouts/root.html.heex b/lib/exmr_web/components/layouts/root.html.heex index 30c1caa..520a812 100644 --- a/lib/exmr_web/components/layouts/root.html.heex +++ b/lib/exmr_web/components/layouts/root.html.heex @@ -8,19 +8,27 @@ <%= assigns[:page_title] || "Exmr" %> + - +