;; This Source Code Form is subject to the terms of the Mozilla Public ;; License, v. 2.0. If a copy of the MPL was not distributed with this ;; file, You can obtain one at http://mozilla.org/MPL/2.0/. ;; ;; Copyright (c) KALEIDOS SUBSIDIARY SL (ns app.util.theme (:require [app.common.data :as d] [app.util.globals :as globals] [beicon.v2.core :as rx] [rumext.v2 :as mf])) (defonce ^:private color-scheme-media-query (.matchMedia globals/window "(prefers-color-scheme: dark)")) (defonce ^:private color-scheme-listeners* (atom #{})) (def ^:const default "dark") (defn get-system-theme [] (if ^boolean (.-matches color-scheme-media-query) "dark" "light")) (defn- notify-color-scheme-listeners! [] (doseq [f @color-scheme-listeners*] (f))) (defn add-color-scheme-listener! "Registers `f` to run after each `body` color-scheme update in `use-initialize` (profile theme or OS preference). Returns a dispose fn." [f] (swap! color-scheme-listeners* conj f) (fn [] (swap! color-scheme-listeners* disj f))) (defn- set-color-scheme [^string color] (let [node (.querySelector js/document "body") class (if (= color "dark") "default" "light")] (.removeAttribute node "class") (.add ^js (.-classList ^js node) class))) (defn resolve-theme "Resolves the profile's theme setting to the effective UI theme ('dark' or 'light'): 'system' follows the given system theme, 'default' and an unset theme mean dark, and any other value is taken as-is. Single source of truth for the app's own theme and the theme reported to plugins." [profile-theme system-theme] (cond (= profile-theme "system") system-theme (= profile-theme "default") "dark" :else (d/nilv profile-theme "dark"))) (defn use-initialize [{profile-theme :theme}] (let [system-theme* (mf/use-state get-system-theme) system-theme (deref system-theme*)] (mf/with-effect [] (let [s (->> (rx/from-event color-scheme-media-query "change") (rx/map #(if (.-matches %) "dark" "light")) (rx/subs! #(reset! system-theme* %)))] (fn [] (rx/dispose! s)))) (mf/with-effect [system-theme profile-theme] (set-color-scheme (resolve-theme profile-theme system-theme)) (notify-color-scheme-listeners!))))