defmodule Liliform.Icon do @moduledoc """ Bulma icon element. The icon element is a container for any type of icon font. Because the icons can take a few seconds to load, and because you want control over the space the icons will take, you can use the icon class as a reliable square container that will prevent the page to "jump" on page load. By default, the icon container will take up exactly 1.5rem x 1.5rem. The icon itself is sized accordingly to the icon library you're using. For example, Font Awesome 5 icons will inherit the font size. """ use Liliform.Component alias Liliform.Colorhash alias Freedive.Features @doc """ Renders an icon. ## For The icon name is set using the `for` attribute. ## Color Set color to `auto` to automatically choose/generate color based on the icon name. You can also set the color to any valid CSS color value. ## Size The icon size can be set using the `size` attribute. By default, the size is set to `1.5rem`. Example: <.icon for="home" /> <.icon for="info" color="auto" /> <.icon for="alert" color="#f44" /> <.icon for="settings" color="blue" /> <.icon for="error" color="hsl(0, 100%, 50%)" /> <.icon for="info" size="2rem" /> """ attr :for, :string, required: true, doc: "icon name" attr :title, :string, default: nil, doc: "icon title" attr :size, :string, default: nil, doc: "size of icon" attr :color, :string, default: nil, doc: "color of icon" attr :class, :string, default: "", doc: "additional classes" attr :rest, :global slot :inner_block, required: false def icon(assigns) do assigns = assigns |> set_bulma_classes() assigns = if assigns.size != nil do Map.put(assigns, :style, "width: #{assigns.size}; height: #{assigns.size};") else assigns end ~H""" <.icon_svg for={@for} title={@title} height={@size} width={@size} {icon_color(assigns)} {@rest} /> <%= if @inner_block != [] do %> <%= render_slot(@inner_block) %> <% end %> """ end @doc """ Renders an icon without the icon-text wrapper. """ attr :for, :string, required: true, doc: "icon name" attr :title, :string, default: nil, doc: "icon title" attr :size, :string, default: nil, doc: "size of icon" attr :color, :string, default: nil, doc: "color of icon" attr :rest, :global def icon_raw(assigns) do assigns = assigns |> set_bulma_classes() ~H""" <.icon_svg for={@for} title={@title} height={@size} width={@size} {icon_color(assigns)} {@rest} /> """ end defp icon_svg(assigns) do base_assigns = assigns |> Map.reject(fn {k, _} -> k in [:for, :size, :rest] end) |> Map.reject(fn {k, v} -> k in [:color] and v == "" end) apply(Lucideicons, icon_name(assigns), [base_assigns]) end defp icon_color(assigns) do if Features.enabled?(:colorhash) do case assigns.color do nil -> [] clr -> case String.downcase(clr) do "auto" -> case String.downcase(assigns.for) do "alert" -> [class: "has-text-danger"] "info" -> [class: "has-text-info"] "success" -> [class: "has-text-success"] "warning" -> [class: "has-text-warning"] "error" -> [class: "has-text-danger"] "all" -> [color: "magenta"] "compute" -> [color: "blue"] "storage" -> [color: "green"] "network" -> [color: "orange"] "system" -> [color: "purple"] "account" -> [color: "darkblue"] "running" -> [color: "lime"] "stopped" -> [color: "gray"] "enabled" -> [color: "blue"] "disabled" -> [color: "gray"] _ -> [color: Colorhash.hsl(assigns.for)] end _ -> [color: assigns.color] end end else [class: "has-text-dark"] end end defp icon_name(assigns) do name = assigns.for |> String.trim() |> String.downcase() |> String.replace("-", "_") case name do "alert" -> :triangle_alert "compute" -> :binary "storage" -> :hard_drive "network" -> :earth "system" -> :bot "account" -> :user "all" -> :infinity "running" -> :circle_play "stopped" -> :circle_stop "enabled" -> :circle_check "disabled" -> :circle_x lucide_name -> String.to_atom(lucide_name) end end end