PrimerLive.Theme (PrimerLive v0.2.6)
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
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. The solution is to use an Ajax request to our Phoenix app, which updates the session.
This setup involves 5 steps, but the provided helper functions make it a bit easier.
1-create-a-sessioncontroller
1. Create a SessionController
Create file controllers/session_controller.ex
:
defmodule MyAppWeb.SessionController do
use MyAppWeb, :controller
use PrimerLive.ThemeSessionController
end
PrimerLive.ThemeSessionController
will add the received theme request data to the session.
2-add-sessioncontroller-to-the-router-s-api
2. Add SessionController to the router's api
scope "/api", MyAppWeb do
pipe_through :api
post PrimerLive.Theme.session_route(), SessionController, :set
end
Optionally set the max_age
in endpoint.ex
:
@session_options [
...
# Over 300 years.
max_age: 9_999_999_999
]
3-add-thememenu-hook
3. Add ThemeMenu hook
In app.js
, import ThemeMenu
and add it to the liveSocket
hooks:
import { Prompt, ThemeMenu } from 'primer-live';
const hooks = {};
hooks.Prompt = Prompt;
hooks.ThemeMenu = ThemeMenu;
let liveSocket = new LiveSocket('/live', Socket, {
params: { _csrf_token: csrfToken },
hooks,
});
You may the hook anywhere, but only once for the entire application. If you have a single theme menu, add it there:
<.action_menu phx-hook="ThemeMenu" id="theme_menu">
...
</.action_menu>
4-initialise-the-theme-from-session-data
4. Initialise the theme from session data
In the LiveView's mount
, call add_to_socket
:
def mount(_params, session, socket) do
socket =
socket
|> PrimerLive.Theme.add_to_socket(session)
{:ok, socket}
end
This reads the theme state and adds it to the socket assigns.
Optionally set the default theme in the seconds argument:
PrimerLive.Theme.add_to_socket(session, %{
color_mode: "light",
light_theme: "light",
dark_theme: "dark"
})
5-handle-update-events
5. Handle update events
In the LiveView where the action menu resides, add:
use PrimerLive.ThemeEvent
This implements function handle_event
for "update_theme" (which is called by clicks on the menu's action_list
items). The function updates the socket and sends the event that is picked by by JavaScript (via the ThemeMenu
hook).
Link to this section Summary
Functions
Adds theme_state
and default_theme_state
to socket.assigns
.
Configures menu options from supplied params
Default label for a theme menu.
Default options for a theme menu.
Initial theme state.
Creates HTML (data) attributes from the supplied theme state to set a theme on a component or element directly
Compares the supplied state with the supplied default state.
Internal use. Reset link identifier to distinguish in update.
Generic key used for
Route for session api calls.
Theme data stored in the session.
Returns an updated theme state by putting the supplied data in the theme state. If key is the reset key, returns the default theme state.
Internal use. Update link identifier.
Link to this section Functions
add_to_socket(socket, session)
See add_to_socket/3
.
add_to_socket(socket, session, default_theme_state)
Adds theme_state
and default_theme_state
to socket.assigns
.
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:
<.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
Tests
iex> PrimerLive.Theme.html_attributes(
...> %{
...> color_mode: "light",
...> light_theme: "light_high_contrast",
...> dark_theme: "dark_high_contrast"
...> }
...> )
[data_color_mode: "light", data_light_theme: "light_high_contrast", data_dark_theme: "dark_high_contrast"]
iex> PrimerLive.Theme.html_attributes(
...> %{
...> },
...> %{
...> color_mode: "auto",
...> light_theme: "light",
...> dark_theme: "dark"
...> }
...> )
[data_color_mode: "auto", data_light_theme: "light", data_dark_theme: "dark"]
iex> PrimerLive.Theme.html_attributes(
...> %{
...> light_theme: "light_high_contrast",
...> },
...> %{
...> color_mode: "auto",
...> light_theme: "light",
...> dark_theme: "dark"
...> }
...> )
[data_color_mode: "auto", data_light_theme: "light_high_contrast", data_dark_theme: "dark"]
iex> PrimerLive.Theme.html_attributes(
...> %{
...> },
...> %{
...> color_mode: "auto",
...> }
...> )
[data_color_mode: "auto"]
is_default_theme(theme, default_theme_state)
Compares the supplied state with the supplied default state.
tests
Tests
iex> PrimerLive.Theme.is_default_theme(
...> %{
...> color_mode: "auto",
...> light_theme: "light",
...> dark_theme: "dark"
...> },
...> PrimerLive.Theme.default_theme_state()
...> )
true
iex> PrimerLive.Theme.is_default_theme(
...> %{
...> color_mode: "light",
...> light_theme: "light_high_contrast",
...> dark_theme: "dark_high_contrast"
...> },
...> PrimerLive.Theme.default_theme_state()
...> )
false
reset_key()
Internal use. Reset link identifier to distinguish in update.
session_key()
Generic key used for:
- session route
- JS event name ("phx:" prefix is assigned automatically)
session_route()
Route for session api calls.
For example:
scope "/api", MyAppWeb do
pipe_through :api
post PrimerLive.Theme.session_route(), SessionController, :set
end
session_theme_key()
Theme data stored in the session.
update(theme_state, map, default_theme_state)
Returns an updated theme state by putting the supplied data in the theme state. If key is the reset key, returns the default theme state.
update_theme_event_key()
Internal use. Update link identifier.