defmodule Phoenix.LiveEditable.Svg do @moduledoc """ Inline SVG utilities. FontAwesome-style SVG vector icons, embedded in your code. The workflow is: - download the SVG to `assets/static/svg` - customize the SVG with default size, color, etc. - use the inline SVG macros in your views and string functions This approach compiles the SVG into your binary. Fast, efficient and safe. Simpler to use than CDN or NPM approaches. To learn more, read the [Elixir Forum Thread][1] on embedded SVGs. [1]: https://elixirforum.com/t/svgs-eex-tags-inlining-from-external-file/25942 """ @doc """ Inline SVG for EEX tags. Usage Example: The file `MyIcon` must be located in `assets/static/svg/MyIcon.svg`. You'll have to `require` the SVG module in your view: defmodule MyappWeb.PageView do use MyappWeb, :view require Phoenix.LiveEditable.Svg end Then you can use the function in an EEX tag: <%= Phoenix.LiveEditable.Svg.inline_tag("MyIcon") %> """ defmacro inline_tag(file) do path = static_path(file) case File.read(path) do {:ok, text} -> quote do: {:safe, unquote(text)} {:error, _} -> raise "No SVG for #{path}" end end @doc """ Inline SVG for elixir functions. Returns the SVG text. Usage Example: The file `MyIcon` must be located in `assets/static/svg/MyIcon.svg`. You'll have to `require` the SVG module in your target code: defmodule MyappWeb.Mycode do require Phoenix.LiveEditable.Svg def my_svg(file) do Phoenix.LiveEditable.Svg.inline(file) end end Then you can use the function in your Elixir code: Myapp.Mycode.my_svg("MyIcon") """ defmacro inline(file) do path = static_path(file) case File.read(path) do {:ok, text} -> quote do: unquote(text) {:error, _} -> raise "No SVG for #{path}" end end defp static_path(file_name) do path = "#{__DIR__}/../../../assets/static/svg" [path, "#{file_name}.svg"] |> Path.join() |> Path.expand end end