Packages
petal_components
0.17.2
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/mix/tasks/heroicons/generate.ex
defmodule Mix.Tasks.Heroicons.Generate do
use Mix.Task
@shortdoc "Convert source SVG files into heex components. Run `git clone https://github.com/tailwindlabs/heroicons.git` first."
def run(_) do
Enum.each(["outline", "solid"], &loop_directory/1)
Mix.Task.run("format")
end
defp loop_directory(folder) do
src_path = "./heroicons/optimized/#{folder}/"
namespace = "Heroicons.#{String.capitalize(folder)}"
file_content = """
defmodule PetalComponents.#{namespace} do
@moduledoc \"\"\"
Icon name can be the function or passed in as a type eg.
<PetalComponents.Heroicons.Solid.home class="w-5 h-5" />
<PetalComponents.Heroicons.Solid.render icon="home" class="w-5 h-5" />
<PetalComponents.Heroicons.Outline.home class="w-6 h-6" />
<PetalComponents.Heroicons.Outline.render icon="home" class="w-6 h-6" />
\"\"\"
use Phoenix.Component
def render(%{icon: icon_name} = assigns) when is_atom(icon_name) do
apply(__MODULE__, icon_name, [assigns])
end
def render(%{icon: icon_name} = assigns) do
icon_name = String.to_existing_atom(icon_name)
apply(__MODULE__, icon_name, [assigns])
end
"""
functions_content =
src_path
|> File.ls!()
|> Enum.filter(&(Path.extname(&1) == ".svg"))
|> Enum.sort()
|> Enum.map(&create_component(src_path, &1, folder))
|> Enum.join("\n\n")
file_content =
file_content <>
functions_content <>
"""
end
"""
dest_path = "./lib/petal_components/icons/heroicons/#{folder}.ex"
unless File.exists?(dest_path) do
File.mkdir_p("./lib/petal_components/icons/heroicons")
end
File.write!(dest_path, file_content)
end
defp create_component(src_path, filename, type) do
svg_content =
File.read!(Path.join(src_path, filename))
|> String.trim()
|> String.replace(~r/<svg /, "<svg class={@class} {@rest} ")
|> String.replace(~r/<path/, " <path")
build_component(filename, svg_content, type)
end
defp function_name(current_filename) do
current_filename
|> Path.basename(".svg")
|> String.replace("-", "_")
end
defp build_component(filename, svg, type) do
class = class_for(type)
"""
def #{function_name(filename)}(assigns) do
assigns = assigns
|> assign_new(:class, fn -> "#{class}" end)
|> assign_new(:rest, fn ->
assigns_to_attributes(assigns, ~w(
class
)a)
end)
~H\"\"\"
#{svg}
\"\"\"
end
"""
end
defp class_for("outline"), do: "h-6 w-6"
defp class_for("solid"), do: "h-5 w-5"
end