defmodule PhoenixKitWeb.Components.ThemeControllerScript do @moduledoc """ The one theme-controller script — the behavior behind every element the `PhoenixKitWeb.Components.Core.ThemeController` picker renders. Before this module the same behavior existed three times: a hand-written script in the dashboard layout, a near-copy inside the admin layout wrapper, and the deleted static `phoenix_kit_themes.js`. They drifted — the dashboard copy carried its own hardcoded base map that missed newer themes and could never know host-defined ones, and both resolved `"system"` to hardcoded `phoenix-*` names, wrong for any host whose configured pair uses other names (see `PhoenixKit.ThemeConfig.system_pair/0`). Everything data-shaped is generated from `PhoenixKit.ThemeConfig` at render time, so host `:theme_definitions` flow through with zero JS changes. The script is idempotent per page (`window.__pkThemeController` guard) and every DOM hook is optional — a page with no label element or no toggle simply skips those branches. Event contract: picker elements dispatch `phx:set-theme` themselves (a `JS.dispatch` bubbling to `window`), so hosts hear each selection exactly once whether or not this script is present. The script CONSUMES that event to persist and reflect; it re-announces only changes that did not arrive as a window event (the legacy `phx:set-admin-theme` translation). Renders at the end of `
`; the pre-paint half of the story is `PhoenixKitWeb.Components.ThemeBootstrap` in ``. """ use Phoenix.Component alias PhoenixKit.ThemeConfig @doc """ The shared theme controller. Render once, at the end of ``. """ def theme_controller_script(assigns) do {light, dark} = ThemeConfig.system_pair() # :html_safe turns < and > into \\u003C/\\u003E so no config- or # translation-derived string can close this """ end end