Skip to content

Commit

Permalink
More docs for layouts
Browse files Browse the repository at this point in the history
  • Loading branch information
akoutmos committed Apr 17, 2022
1 parent eb10a38 commit c806709
Show file tree
Hide file tree
Showing 5 changed files with 120 additions and 13 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

## [0.3.0] - 2021-04-18

### Added

- Ability to inject a template into a layout

## [0.2.0] - 2021-04-15

### Added
Expand Down
51 changes: 51 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,57 @@ And the following template:
Be sure to look at the `MjmlEEx.Component` for additional usage information as you can also pass options
to your template and use them when generating the partial string.

### Using Layouts

Often times, you'll want to create an Email skeleton or layout using MJML, and then inject your template into that
layout. MJML EEx supports this functionality which makes it really easy to have business branded emails application
wide without having to copy and paste the same boilerplate in every template.

To create a layout, define a layout module like so:

```elixir
defmodule BaseLayout do
use MjmlEEx.Layout, mjml_layout: "base_layout.mjml.eex"
end
```

And an accompanying layout like so:

```html
<mjml>
<mj-head>
<mj-title>Say hello to card</mj-title>
<mj-font name="Roboto" href="https://fonts.googleapis.com/css?family=Montserrat:300,400,500"></mj-font>
<mj-attributes>
<mj-all font-family="Montserrat, Helvetica, Arial, sans-serif"></mj-all>
<mj-text font-weight="400" font-size="16px" color="#000000" line-height="24px"></mj-text>
<mj-section padding="<%= @padding %>"></mj-section>
</mj-attributes>
</mj-head>

<%= @inner_content %>
</mjml>
```

As you can see, you can include assigns in your layout template (like `@padding`), but you also need to
include a mandatory `@inner_content` expression. That way, MJML EEx knowns where to inject your template
into the layout. With that in place, you just need to tell your template module what layout to use (if
you are using a layout that is):

```elixir
defmodule MyTemplate do
use MjmlEEx,
mjml_template: "my_template.mjml.eex",
layout: BaseLayout
end
```

And your template file can contain merely the parts that you need for that particular template:

```html
<mj-body> ... </mj-body>
```

## Attribution

- The logo for the project is an edited version of an SVG image from the [unDraw project](https://undraw.co/)
Expand Down
16 changes: 5 additions & 11 deletions lib/mjml_eex.ex
Original file line number Diff line number Diff line change
Expand Up @@ -96,17 +96,7 @@ defmodule MjmlEEx do
|> EEx.compile_file(engine: MjmlEEx.Engines.Mjml, line: 1, trim: true)
|> Code.eval_quoted()

mjml_document
|> Mjml.to_html()
|> case do
{:ok, email_html} ->
email_html

{:error, error} ->
raise "Failed to compile MJML template: #{inspect(error)}"
end
|> Utils.decode_eex_expressions()
|> EEx.compile_string(engine: Phoenix.HTML.Engine, line: 1)
compile_mjml_document(mjml_document)
end

defp compile_with_layout(template_path, layout_module) do
Expand All @@ -120,6 +110,10 @@ defmodule MjmlEEx do
|> EEx.compile_string(engine: MjmlEEx.Engines.Mjml, line: 1, trim: true)
|> Code.eval_quoted()

compile_mjml_document(mjml_document)
end

defp compile_mjml_document(mjml_document) do
mjml_document
|> Mjml.to_html()
|> case do
Expand Down
48 changes: 46 additions & 2 deletions test/mjml_eex_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,18 @@ defmodule MjmlEExTest do
layout: BaseLayout
end

defmodule AssignsLayout do
@moduledoc false

use MjmlEEx.Layout, mjml_layout: "test_layouts/assigns_layout.mjml.eex"
end

defmodule AssignsLayoutTemplate do
use MjmlEEx,
mjml_template: "test_templates/layout_template.mjml.eex",
layout: AssignsLayout
end

describe "BasicTemplate.render/1" do
test "should raise an error if no assigns are provided" do
assert_raise ArgumentError, ~r/assign @call_to_action_text not available in template/, fn ->
Expand Down Expand Up @@ -115,7 +127,19 @@ defmodule MjmlEExTest do
end
end

describe "InvalidLayoutTemplate" do
describe "AssignsTemplate.render/1" do
test "should raise an error if no assigns are provided" do
assert_raise ArgumentError, ~r/assign @padding not available in template/, fn ->
AssignsLayoutTemplate.render([])
end
end

test "should render the template using a layout" do
assert AssignsLayoutTemplate.render(call_to_action_text: "Click me please!", padding: "0px") =~ "Click me please!"
end
end

describe "InvalidLayout" do
test "should fail to compile since the layout contains no @inner_content expressions" do
assert_raise RuntimeError, ~r/The provided :mjml_layout must contain one <%= @inner_content %> expression./, fn ->
defmodule InvalidLayout do
Expand All @@ -125,7 +149,7 @@ defmodule MjmlEExTest do
end
end

describe "OtherInvalidLayoutTemplate" do
describe "OtherInvalidLayout" do
test "should fail to compile since the layout contains 2 @inner_content expressions" do
assert_raise RuntimeError,
~r/The provided :mjml_layout contains multiple <%= @inner_content %> expressions./,
Expand All @@ -136,4 +160,24 @@ defmodule MjmlEExTest do
end
end
end

describe "MissingOptionLayout" do
test "should fail to compile since the use statement is missing a required option" do
assert_raise RuntimeError, ~r/The :mjml_layout option is required./, fn ->
defmodule MissingOptionLayout do
use MjmlEEx.Layout
end
end
end
end

describe "MissingFileLayout" do
test "should fail to compile since the use statement is missing a required option" do
assert_raise RuntimeError, ~r/The provided :mjml_layout does not exist at/, fn ->
defmodule MissingFileLayout do
use MjmlEEx.Layout, mjml_layout: "invalid/path/to/layout.mjml.eex"
end
end
end
end
end
12 changes: 12 additions & 0 deletions test/test_layouts/assigns_layout.mjml.eex
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<mjml>
<mj-head>
<mj-title>Say hello to card</mj-title>
<mj-font name="Roboto" href="https://fonts.googleapis.com/css?family=Montserrat:300,400,500"></mj-font>
<mj-attributes>
<mj-all font-family="Montserrat, Helvetica, Arial, sans-serif"></mj-all>
<mj-text font-weight="400" font-size="16px" color="#000000" line-height="24px"></mj-text>
<mj-section padding="<%= @padding %>"></mj-section>
</mj-attributes>
</mj-head>
<%= @inner_content %>
</mjml>

0 comments on commit c806709

Please sign in to comment.