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 @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 :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} height={@size} width={@size} color={icon_color(assigns)} /> <%= if @inner_block != [] do %> <%= render_slot(@inner_block) %> <% end %> """ 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 case assigns.color do nil -> "" "auto" -> Colorhash.hsl(assigns.for) color -> color 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 lucide_name -> String.to_atom(lucide_name) end end end