freedive/lib/liliform/icon.ex

119 lines
2.9 KiB
Elixir

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"""
<span class="icon-text">
<span class={["icon", @class]} {@rest}>
<.icon_svg for={@for} height={@size} width={@size} color={icon_color(assigns)} />
</span>
<%= if @inner_block != [] do %>
<span>
<%= render_slot(@inner_block) %>
</span>
<% end %>
</span>
"""
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