defmodule Legendary.CoreWeb.EmailHelpers do
@moduledoc """
HTML helpers for emails.
"""
import Phoenix.Component, only: [sigil_H: 2]
import ShorterMaps
def framework_styles do
%{
background: %{
color: "#222222"
},
body: %{
font_family: "sans-serif",
font_size: "15px",
line_height: "20px",
text_color: "#555555"
},
button: %{
border_radius: "4px",
border: "1px solid #000000",
background: "#222222",
color: "#ffffff",
font_family: "sans-serif",
font_size: "15px",
line_height: "15px",
text_decoration: "none",
padding: "13px 17px",
display: "block"
},
column: %{
background: "#FFFFFF",
padding: "0 10px 40px 10px"
},
footer: %{
padding: "20px",
font_family: "sans-serif",
font_size: "12px",
line_height: "15px",
text_align: "center",
color: "#ffffff"
},
global: %{
width: 600
},
h1: %{
margin: "0 0 10px 0",
font_family: "sans-serif",
font_size: "25px",
line_height: "30px",
color: "#333333",
font_weight: "normal"
},
h2: %{
margin: "0 0 10px 0",
font_family: "sans-serif",
font_size: "18px",
line_height: "22px",
color: "#333333",
font_weight: "bold"
},
header: %{
padding: "20px 0",
text_align: "center"
},
hero_image: %{
background: "#dddddd",
display: "block",
margin: "auto"
},
inner_column: %{
padding: "10px 10px 0"
},
li: %{
margin: "0 0 0 10px"
},
last_li: %{
margin: "0 0 10px 30px"
},
spacer: %{
height: "40",
font_size: "0px",
line_height: "0px"
},
ul: %{
margin: "0 0 10px 0",
padding: "0"
}
}
end
def framework_styles(group) do
Map.get(framework_styles(), group, %{})
end
def application_styles(group) do
styles = Application.get_env(:core, :email, %{}) |> Map.get(:styles, %{})
Map.get(styles, group, %{})
end
def effective_styles(group, overrides \\ %{}) do
group
|> framework_styles()
|> Legendary.Core.MapUtils.deep_merge(application_styles(group))
|> Map.merge(overrides)
end
def preview(do: content) do
assigns = ~M{content}
~H"""
<div style="max-height:0; overflow:hidden; mso-hide:all;" aria-hidden="true">
<!-- Visually Hidden Preheader Text -->
<%= @content %>
</div>
<div style="display: none; font-size: 1px; line-height: 1px; max-height: 0px; max-width: 0px; opacity: 0; overflow: hidden; mso-hide: all; font-family: sans-serif;">
<!-- Create white space after the desired preview text so email clients don't pull other distracting text into the inbox preview. Extend as necessary. -->
‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌
‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌
‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌
‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌
‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌
‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌
</div>
"""
end
def header(do: content) do
assigns = ~M{content}
~H"""
<tr>
<td style={map_style(effective_styles(:header))}>
<%= content %>
</td>
</tr>
"""
end
def spacer do
style = effective_styles(:spacer)
assigns = ~M{style}
~H"""
<tr>
<td aria-hidden="true" height={style[:height]} style={map_style(style)}>
</td>
</tr>
"""
end
def row(do: content) do
assigns = ~M{content}
~H"""
<table role="presentation" cellspacing="0" cellpadding="0" border="0" width="100%">
<tr>
<%= content %>
</tr>
</table>
"""
end
@spec col(number, keyword, [{:do, any}, ...]) :: {:safe, [...]}
def col(n, opts, do: content) do
{of, _opts} = Keyword.pop!(opts, :of)
width = n * 100.0 / of
assigns = ~M{of, width, content}
~H"""
<td valign="top" width={"#{width}%"} style={map_style(effective_styles(:column))}>
<table role="presentation" cellspacing="0" cellpadding="0" border="0" width="100%">
<tr>
<td style={
map_style(effective_styles(:body)) <> " " <> map_style(effective_styles(:inner_column))
}>
<%= content %>
</td>
</tr>
</table>
</td>
"""
end
def hero_image(opts) do
{src, _rest_opts} = Keyword.pop!(opts, :src)
assigns = ~M{src}
~H"""
<%= row do %>
<%= col 1, of: 1 do %>
<img
src={src}
width={effective_styles(:global)[:width]}
height="auto"
alt="alt_text"
border="0"
style={
"#{map_style(effective_styles(:body))} width: 100%; max-width: #{effective_styles(:global)[:width]}; height: auto; #{map_style(effective_styles(:hero_image))}"
}
class="g-img"
/>
<% end %>
<% end %>
"""
end
def h1(do: content) do
assigns = ~M{content}
~H"""
<h1 style={map_style(effective_styles(:h1))}>
<%= content %>
</h1>
"""
end
def h2(do: content) do
assigns = ~M{content}
~H"""
<h2 style={map_style(effective_styles(:h2))}>
<%= content %>
</h2>
"""
end
def p(do: content) do
assigns = ~M{content}
~H"""
<p style={map_style(effective_styles(:body))}>
<%= content %>
</p>
"""
end
def styled_button(opts, do: content), do: button(opts, do: content)
def button(opts, do: content) do
{overrides, opts_without_style} = Keyword.pop(opts, :style, %{})
{href, _rest_opts} = Keyword.pop!(opts_without_style, :href)
style = effective_styles(:button, overrides)
cell_style = style |> Map.take([:border_radius, :background])
assigns = ~M{cell_style, content, href, style}
~H"""
<%= wrapper do %>
<td class="button-td button-td-primary" style={map_style(cell_style)}>
<a class="button-a button-a-primary" href={href} style={map_style(style)}>
<%= content %>
</a>
</td>
<% end %>
"""
end
def ul(opts) do
{items, _rest_opts} = Keyword.pop!(opts, :items)
item_count = Enum.count(items)
item_tags =
items
|> Enum.with_index()
|> Enum.map(fn {item, index} ->
li_for_ul(index, item_count, item)
end)
assigns = ~M{item_tags}
~H"""
<ul style={map_style(effective_styles(:ul))}>
<%= for li <- item_tags do %>
<%= li %>
<% end %>
</ul>
"""
end
def footer do
assigns = %{}
~H"""
<%= wrapper do %>
<td style={map_style(effective_styles(:footer))}>
<%= Legendary.I18n.t!("en", "email.company.name") %><br />
<span class="unstyle-auto-detected-links">
<%= Legendary.I18n.t!("en", "email.company.address") %><br />
<%= Legendary.I18n.t!("en", "email.company.phone") %>
</span>
<br /><br />
</td>
<% end %>
"""
end
defp li_for_ul(index, list_length, content) do
style_type = if index == list_length - 1, do: :last_li, else: :li
assigns = ~M{content, style_type}
~H"""
<li style={map_style(effective_styles(style_type))}>
<%= content %>
</li>
"""
end
defp wrapper(do: content) do
assigns = ~M{content}
~H"""
<table
align="center"
role="presentation"
cellspacing="0"
cellpadding="0"
border="0"
style="margin: auto;"
>
<tr>
<%= content %>
</tr>
</table>
"""
end
defp map_style(map) do
map
|> Enum.map_join("\n", fn {key, value} ->
new_key =
key
|> Atom.to_string()
|> String.replace("_", "-")
"#{new_key}: #{value};"
end)
end
end