freedive/lib/liliform/icon.ex

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