diff --git a/lib/heroicons.ex b/lib/heroicons.ex index 6fdda4d..be21dab 100644 --- a/lib/heroicons.ex +++ b/lib/heroicons.ex @@ -8,42 +8,51 @@ defmodule Heroicons do @doc false defmacro __before_compile__(%Macro.Env{module: module}) do - unless Module.has_attribute?(module, :icon_path) do - raise CompileError, description: "@icon_path attrubute is required" + unless Module.has_attribute?(module, :icon_dir) do + raise CompileError, description: "@icon_dir attrubute is required" end + icon_dir = Module.get_attribute(module, :icon_dir) + icon_paths = - Module.get_attribute(module, :icon_path) + Path.absname(icon_dir, :code.priv_dir(:heroicons)) |> Path.join("*.svg") |> Path.wildcard() for path <- icon_paths do - name = - Path.basename(path, ".svg") - |> String.replace("-", "_") - |> String.to_atom() + generate_function(path) + end + end - quote do - @doc """ - ![](#{unquote(path)}) {: width=24px} + @doc false + def generate_function(path) do + name = + Path.basename(path, ".svg") + |> String.replace("-", "_") + |> String.to_atom() - ## Examples - iex> #{unquote(name)}() - iex> #{unquote(name)}(class: "h-6 w-6 text-gray-500") - """ - @spec unquote(name)(keyword(binary)) :: binary - def unquote(name)(opts \\ []) do - icon = File.read!(unquote(path)) - {i, _} = :binary.match(icon, ">") + doc = """ + ![](assets/#{Path.relative_to(path, :code.priv_dir(:heroicons))}) {: width=24px} - {head, tail} = String.split_at(icon, i) + ## Examples + iex> #{name}() + iex> #{name}(class: "h-6 w-6 text-gray-500") + """ - attrs = - opts - |> Enum.map_join(fn {k, v} -> ~s( #{k}="#{v}") end) + quote do + @doc unquote(doc) + @spec unquote(name)(keyword(binary)) :: binary + def unquote(name)(opts \\ []) do + icon = File.read!(unquote(path)) + {i, _} = :binary.match(icon, ">") - head <> attrs <> tail - end + {head, tail} = String.split_at(icon, i) + + attrs = + opts + |> Enum.map_join(fn {k, v} -> ~s( #{k}="#{v}") end) + + head <> attrs <> tail end end end diff --git a/lib/heroicons/outline.ex b/lib/heroicons/outline.ex index 16c4e62..f9868c2 100644 --- a/lib/heroicons/outline.ex +++ b/lib/heroicons/outline.ex @@ -4,6 +4,6 @@ defmodule Heroicons.Outline do For primary navigation and marketing sections, designed to be rendered at 24x24. """ - @icon_path "#{:code.priv_dir(:heroicons)}/outline/" + @icon_dir "outline/" @before_compile Heroicons end diff --git a/lib/heroicons/solid.ex b/lib/heroicons/solid.ex index d2cd93a..74d7ece 100644 --- a/lib/heroicons/solid.ex +++ b/lib/heroicons/solid.ex @@ -5,6 +5,6 @@ defmodule Heroicons.Solid do For buttons, form elements, and to support text, designed to be rendered at 20x20. """ - @icon_path "#{:code.priv_dir(:heroicons)}/solid/" + @icon_dir "solid/" @before_compile Heroicons end diff --git a/mix.exs b/mix.exs index a911ff9..a78dd74 100644 --- a/mix.exs +++ b/mix.exs @@ -7,7 +7,13 @@ defmodule HeroiconsElixir.MixProject do version: "0.1.0", elixir: "~> 1.11", start_permanent: Mix.env() == :prod, - deps: deps() + deps: deps(), + + # Docs + name: "Heroicons Elixir", + source_url: "https://github.com/mveytsman/heroicons_elixir", + description: "Include Heroicons as SVG-strings in your Elixir/Phoenix project!", + docs: docs() ] end @@ -26,4 +32,10 @@ defmodule HeroiconsElixir.MixProject do {:ex_doc, "~> 0.23", only: :dev, runtime: false} ] end + + defp docs do + [ + assets: "priv/" + ] + end end diff --git a/test/heroicons_test.exs b/test/heroicons_test.exs index 457b04b..6b1c7dc 100644 --- a/test/heroicons_test.exs +++ b/test/heroicons_test.exs @@ -1,4 +1,28 @@ defmodule HeroiconsTest do use ExUnit.Case, async: true - doctest Heroicons.Solid + + @icon """ + + + + """ + + @tag :tmp_dir + test "generated function", %{tmp_dir: tmp_dir} do + Path.join(tmp_dir, "academic_cap.svg") + |> File.write(@icon) + + quote do + defmodule TestIcons do + @icon_dir unquote(Path.absname(tmp_dir)) + @before_compile Heroicons + end + end + |> Code.compile_quoted() + + assert TestIcons.academic_cap() == @icon + + assert TestIcons.academic_cap(class: "h-6 w-6 text-gray-500") =~ + ~s(class="h-6 w-6 text-gray-500") + end end