PrimerLive.Theme (PrimerLive v0.7.2)
Primer CSS contains styles for light/dark color modes and themes, with support for color blindness.
PrimerLive provides components and functions to work with themes:
theme/1
- wrapper to set the theme on child elementstheme_menu_options/1
- contents for a theme menuhtml_attributes/2
- HTML attributes to set a theme on a component or element directly
Persistency
There is no easy way to save persistent session data in LiveView because LiveView's state is stored in a process that ends when the page is left.
Session for theme state has been removed
Using the session to store the theme state (for example using a AJAX call roundtrip) does not work as expected: when navigating to another LiveView page, the updated session data is not refetched and only becomes available after a page refresh. This means that the previous offered solution with PrimerLive.ThemeSessionController
is no longer recommended and in fact removed.
Alternatives: database or cache
If you already have a database set up for storing data by session ID, it's a small step to integrate the theme state with it.
On the other hand, for a lightweight solution you may find caching simpler to start with. For example Cachex (which I've selected for primer-live.org).
Handling user selection
Assuming you are providing a theme menu on the website, the option the user selects must be stored in persistent storage.
Here we're setting event callback "store_theme" in the theme menu:
# Some app component
<.action_menu>
<:toggle class="btn btn-invisible">
<.octicon name="sun-16" />
</:toggle>
<.theme_menu_options
theme_state={@theme_state}
update_theme_event="store_theme"
/>
</.action_menu>
The callback is invoked whenever a theme menu option is clicked. See attr update_theme_event
for documentation of the arguments.
# App LiveView
def handle_event(
"store_theme",
%{"data" => data, "key" => key, "value" => _},
socket
) do
# Persist new theme state ...
{:noreply, socket}
end
Summary
Functions
Configures menu options from supplied params
Default label for a theme menu.
Default options for a theme menu.
Compares the supplied state with the supplied default state.
Initial theme state.
Creates HTML (data) attributes from the supplied theme state to set a theme on a component or element directly. This is useful to "theme" specific page parts regardless of the user selected theme, for example a dark page header.
Default reset link identifier for the handle_event
update callback.
Default event name for the handle_event
update callback.
Functions
default_theme?(theme, default_theme_state)
Compares the supplied state with the supplied default state.
Tests
iex> PrimerLive.Theme.default_theme?(
...> %{
...> color_mode: "auto",
...> light_theme: "light",
...> dark_theme: "dark"
...> },
...> PrimerLive.Theme.default_theme_state()
...> )
true
iex> PrimerLive.Theme.default_theme?(
...> %{
...> color_mode: "light",
...> light_theme: "light_high_contrast",
...> dark_theme: "dark_high_contrast"
...> },
...> PrimerLive.Theme.default_theme_state()
...> )
false
default_theme_state()
Initial theme state.
html_attributes(theme_state)
See html_attributes/2
.
html_attributes(theme_state, default_theme_state)
Creates HTML (data) attributes from the supplied theme state to set a theme on a component or element directly. This is useful to "theme" specific page parts regardless of the user selected theme, for example a dark page header.
<.button
{PrimerLive.Theme.html_attributes([color_mode: "dark", dark_theme: "dark_high_contrast"])}
>Button</.button>
<.octicon name="sun-24"
{PrimerLive.Theme.html_attributes(%{color_mode: "dark", dark_theme: "dark_dimmed"})}
/>
Tests
iex> PrimerLive.Theme.html_attributes(
...> %{
...> color_mode: "light",
...> light_theme: "light_high_contrast",
...> dark_theme: "dark_high_contrast"
...> }
...> )
[{:"data-color-mode", "light"}, {:"data-dark-theme", "dark_high_contrast"}, {:"data-light-theme", "light_high_contrast"}]
iex> PrimerLive.Theme.html_attributes(
...> %{
...> },
...> %{
...> color_mode: "auto",
...> light_theme: "light",
...> dark_theme: "dark"
...> }
...> )
[{:"data-color-mode", "auto"}, {:"data-dark-theme", "dark"}, {:"data-light-theme", "light"}]
iex> PrimerLive.Theme.html_attributes(
...> %{
...> light_theme: "light_high_contrast",
...> },
...> %{
...> color_mode: "auto",
...> light_theme: "light",
...> dark_theme: "dark"
...> }
...> )
[{:"data-color-mode", "auto"}, {:"data-dark-theme", "dark"}, {:"data-light-theme", "light_high_contrast"}]
iex> PrimerLive.Theme.html_attributes(
...> %{
...> },
...> %{
...> color_mode: "auto",
...> }
...> )
["data-color-mode": "auto"]
reset_key()
Default reset link identifier for the handle_event
update callback.
update_theme_event_key()
Default event name for the handle_event
update callback.
This value can be overridden in theme_menu_options
with update_theme_event
:
<.theme_menu_options
theme_state={@theme_state}
update_theme_event="store_theme"
/>