defmodule Next do import Phoenix.HTML import Phoenix.HTML.Tag def rev(tag, rev_opts, tag_opts, do: block) do content_tag(tag, merge_opts(rev_opts, tag_opts), do: block) end def rev(rev_opts, tag_opts, do: block) do {tag, rev_opts} = Keyword.pop_first(rev_opts, :tag, :div) rev(tag, rev_opts, tag_opts, do: block) end defp merge_opts(rev_opts, tag_opts) do {rev_class, rev_opts} = Keyword.pop_first(rev_opts, :class) {tag_class, tag_opts} = Keyword.pop_first(tag_opts, :class) class = rev_class || (tag_class && [rev_class, tag_class] |> Enum.filter(& &1) |> Enum.join(" ")) rev_opts |> Keyword.merge(tag_opts) |> Keyword.put(:class, class) end def suit(base_class, modifiers \\ []) do modifiers |> Enum.reduce("#{base_class}", fn {modifier, value}, class -> case modifier do :class -> "#{class} #{value}" _ -> case value do false -> class true -> "#{class} #{base_class}--#{modifier}" other -> "#{class} #{base_class}--#{modifier}#{other}" end end end) end def row(mods, x), do: rev(class: suit("rev-Row", mods), x) def row(x), do: row([], x) def col(mods, x), do: rev(class: suit("rev-Col", mods), x) def col(x), do: col([], x) def menu(mods, x), do: rev(tag: :ul, class: suit("rev-Menu", mods), x) do def menu(x), do: menu([], x) def menu_item(mods, x), do: rev(tag: :li, class: suit("rev-Menu-item", mods), x) def menu_item(x), do: menu([], x) end defmodule Next.Example do def example() do ~E""" <%= rev row() do %> <%= rev col(medium: 4), class: "extra classes" do %> <%= rev menu() do %> <%= rev menu_item() do %> Menu Item 1 <% end %> <% end %> <% end %> <% end %> """ end end