Packages
petal_components
3.2.1
4.7.0
4.6.2
4.6.1
4.6.0
4.5.0
4.4.0
4.3.0
4.2.1
4.2.0
4.1.2
4.1.1
4.1.0
4.0.12
4.0.11
4.0.10
4.0.6
4.0.5
4.0.4
4.0.3
4.0.1
3.2.2
3.2.1
3.2.0
3.1.0
3.0.2
3.0.1
3.0.0
2.9.3
2.9.2
retired
2.9.1
retired
2.9.0
retired
2.8.4
2.8.3
2.8.2
2.8.1
2.8.0
2.7.4
2.7.3
2.7.2
2.7.1
2.7.0
2.6.1
2.6.0
2.5.2
2.5.1
2.5.0
2.4.3
2.4.2
2.4.1
2.4.0
2.3.0
2.2.1
2.2.0
2.1.2
2.1.1
2.1.0
2.0.6
2.0.5
2.0.4
2.0.3
2.0.2
2.0.1
2.0.0
1.9.3
1.9.2
1.9.1
1.9.0
1.8.0
1.7.1
1.7.0
1.6.2
1.6.1
1.6.0
1.5.5
1.5.4
1.5.3
1.5.2
1.5.1
1.5.0
1.4.9
1.4.8
1.4.7
1.4.6
1.4.5
1.4.4
1.4.3
1.4.2
1.4.1
1.4.0
1.3.0
1.2.14
1.2.13
1.2.12
1.2.11
1.2.10
1.2.9
1.2.8
1.2.7
1.2.6
1.2.5
1.2.4
1.2.3
1.2.2
1.2.1
1.2.0
1.1.6
1.1.5
1.1.4
1.1.3
1.1.2
1.1.1
1.1.0
1.0.8
1.0.7
1.0.6
1.0.5
1.0.4
1.0.3
1.0.2
1.0.1
1.0.0
0.19.10
0.19.9
0.19.8
0.19.7
0.19.6
0.19.5
0.19.4
0.19.3
0.19.2
0.19.1
0.19.0
0.18.5
0.18.4
0.18.3
0.18.2
0.18.1
0.18.0
0.17.7
0.17.6
0.17.5
0.17.4
0.17.3
0.17.2
0.17.1
0.17.0
0.16.0
0.15.0
0.14.1
0.14.0
0.13.7
0.13.6
0.13.5
0.13.4
0.13.3
0.13.2
0.13.1
0.13.0
0.12.0
0.11.4
0.11.3
0.11.2
0.11.1
0.11.0
0.10.8
0.10.7
0.10.6
0.10.5
0.10.4
0.10.3
0.10.2
0.10.1
0.10.0
0.9.3
0.9.2
0.9.1
0.9.0
0.8.0
0.7.0
0.6.1
0.6.0
0.5.1
0.5.0
0.4.0
0.3.2
0.3.1
0.3.0
0.2.2
0.2.1
0.2.0
0.1.0
Shadcn-style Phoenix LiveView components that AI assistants can actually use. Pair with the MCP server so AI coding tools can inspect the real component API.
Current section
Files
Jump to
Current section
Files
lib/petal_components/icon.ex
defmodule PetalComponents.Icon do
use Phoenix.Component
require Logger
deps_path = Mix.Project.deps_path()
heroicons_path = Path.join(deps_path, "heroicons/optimized")
# Heroicons aren't available when pushing to hex
if !File.dir?(heroicons_path) do
Logger.warning("""
Heroicons path "#{heroicons_path}" does not exist or is not a folder. Consider adding the following to your list of dependencies:
{:heroicons,
github: "tailwindlabs/heroicons",
tag: "v2.2.0",
app: false,
compile: false,
sparse: "optimized"}
See https://petal.build/components/heroicons for up-to-date instructions
""")
attr :rest, :global,
doc: "the arbitrary HTML attributes for the heroicon container",
include: ~w(role aria-hidden)
attr :name, :string, required: true
attr :class, :any, default: nil, doc: "class applied to heroicon container"
def icon(%{name: name}) when is_atom(name) do
raise ArgumentError,
message:
":#{name} is not a valid heroicon name. Please use a class name like \"hero-home\""
end
def icon(%{name: "hero-" <> _} = assigns) do
~H"""
<span class={[@name, @class]} {@rest} />
"""
end
end
# If heroicons are included as a dependency (either in :dev or in the
# calling application), then generate a function per heroicon variant
if File.dir?(heroicons_path) do
attr :rest, :global,
doc: "the arbitrary HTML attributes for the heroicon container",
include: ~w(role aria-hidden)
attr :name, :string, required: true
attr :class, :any, default: nil, doc: "class applied to heroicon container"
defp heroicon(assigns) do
~H"""
<span class={[@name, @class]} {@rest} />
"""
end
@icons [
{"", "/24/outline"},
{"-solid", "/24/solid"},
{"-mini", "/20/solid"},
{"-micro", "/16/solid"}
]
heroicon_names =
for {suffix, dir} <- @icons do
path =
Path.join(heroicons_path, dir)
|> Path.expand()
# Read folder
case File.ls(path) do
{:ok, file_names} ->
for file_name <- file_names, do: Path.rootname(file_name) <> suffix
{:error, _reason} ->
[]
end
end
|> Enum.flat_map(fn x -> x end)
quote do
attr :rest, :global,
doc: "the arbitrary HTML attributes for the svg container",
include: ~w(role aria-hidden)
attr :name, :string, required: true
attr :class, :any, default: nil, doc: "svg class"
end
def icon(%{name: name}) when is_atom(name) do
raise ArgumentError,
message:
":#{name} is not a valid heroicon name. Please use a class name like \"hero-home\""
end
for heroicon_name <- heroicon_names do
def icon(%{name: "hero-" <> unquote(heroicon_name)} = assigns), do: heroicon(assigns)
end
def icon(%{name: name}) do
raise ArgumentError,
message:
"\"#{name}\" is not a valid heroicon name. Please use a class name like \"hero-home\", \"hero-home-solid\", \"hero-home-mini\" or \"hero-home-micro\""
end
end
end