Packages

Typed Phosphor icons for Phoenix LiveView with compile-time SVG components and dynamic helpers.

Current section

Files

Jump to
phosphor_live_view lib phosphor generated builder.exs
Raw

lib/phosphor/generated/builder.exs

defmodule Phosphor.Generated.Builder do
@moduledoc false
alias Phosphor.Generated.Manifest
@weights Manifest.weights()
defmacro __using__(_opts) do
icons = Manifest.icons()
icon_modules =
for icon <- icons do
build_icon_module(icon)
end
function_components =
for icon <- icons do
build_function_component(icon)
end
quote do
unquote_splicing(icon_modules)
unquote_splicing(function_components)
end
end
defp build_icon_module(icon) do
name = Map.fetch!(icon, :name)
module = icon_module(name)
weights = ordered_weights(icon)
default_weight = icon_default_weight(icon, weights)
weight_defs =
for weight <- weights do
svg =
icon
|> Map.fetch!(:svgs)
|> Map.fetch!(weight)
svg_ast = Macro.escape(svg)
weight_fun = weight
quote do
@doc false
def unquote(weight_fun)(assigns) do
Phosphor.__render_svg__(assigns, unquote(svg_ast), [:weight, :name])
end
end
end
weights_ast = Macro.escape(weights)
default_ast = Macro.escape(default_weight)
quote do
defmodule unquote(module) do
use Phoenix.Component
@moduledoc false
@weights unquote(weights_ast)
@default_weight unquote(default_ast)
def icon(assigns) do
assigns = Phosphor.__ensure_assigns__(assigns)
requested = Map.get(assigns, :weight)
weight = Phosphor.__resolve_weight__(requested, @weights, @default_weight)
apply(__MODULE__, weight, [assigns])
end
@doc false
def weights, do: @weights
unquote_splicing(weight_defs)
end
end
end
defp build_function_component(icon) do
name = Map.fetch!(icon, :name)
module = icon_module(name)
function_name = icon_function(name)
quote do
@doc false
def unquote(function_name)(assigns) do
unquote(module).icon(assigns)
end
end
end
defp icon_module(name) do
camel =
name
|> String.replace("-", "_")
|> Macro.camelize()
Module.concat(Phosphor, camel)
end
defp icon_function(name) do
name
|> String.replace("-", "_")
|> String.to_atom()
end
defp ordered_weights(icon) do
icon_weights =
icon
|> Map.fetch!(:svgs)
|> Map.keys()
|> MapSet.new()
@weights
|> Enum.filter(&MapSet.member?(icon_weights, &1))
end
defp icon_default_weight(icon, []), do: Map.get(icon, :default_weight, :regular)
defp icon_default_weight(icon, weights) do
case Map.get(icon, :default_weight) do
nil ->
Enum.find(weights, fn weight -> weight == :regular end) || hd(weights)
weight ->
if weight in weights do
weight
else
Enum.find(weights, fn candidate -> candidate == :regular end) || hd(weights)
end
end
end
end