lib/fluint_ui/theme.ex

defmodule FlintUI.Theme do
  @moduledoc """
  Theme and helpers.
  """

  @enforce_keys [:name, :ui]
  defstruct [:name, :ui]

  ## Variants

  @doc """
  Returns the list of the theme size variants (e.g. for
  width, height, radius, etc).
  """
  def size_variants, do: FlintUI.Theme.Default.size_variants()

  def size_variants(exclude_list) when is_list(exclude_list) do
    size_variants() -- exclude_list
  end

  @doc """
  Returns the list of the theme radius variants.
  """
  def radius_variants, do: FlintUI.Theme.Default.radius() |> Map.keys()

  def radius_variants(exclude_list) when is_list(exclude_list) do
    radius_variants() -- exclude_list
  end

  def semantic_colors, do: FlintUI.Theme.Default.semantic_colors()
  def shade_colors, do: FlintUI.Theme.Default.shade_colors()

  ## Theme

  def theme do
    if Application.get_env(:flint_ui, :config)[:dev],
      do: merge_theme(),
      else: Memoize.resolve(:theme, fn -> merge_theme() end)
  end

  def theme(component) when is_atom(component) do
    get_theme_component(component)
  end

  def theme(component) when is_binary(component) do
    String.to_atom(component) |> get_theme_component()
  end

  @doc """
  Returns the theme component by name (e.g. `:badge`).
  If the component is not found, it returns nil.
  """
  def get_theme_component(component) do
    theme().ui[component] || nil
  end

  def get_in_theme(component, keys) do
    get_in(theme(component), keys)
  end

  def user_config do
    Application.get_env(:flint_ui, :config, %{})
    |> Map.get(:overrides, %{})
    |> Map.new()
  end

  # Merge default theme with the user theme
  defp merge_theme do
    default_theme = FlintUI.Theme.Default.values()
    theme = DeepMerge.deep_merge(default_theme, user_config())
    struct(__MODULE__, theme)
  end
end