├── test ├── test_helper.exs └── phoenix_mjml_test.exs ├── lib ├── phoenix_mjml.ex └── phoenix_mjml │ └── engine.ex ├── .formatter.exs ├── .gitignore ├── mix.exs ├── LICENSE ├── config └── config.exs ├── README.md ├── .github └── workflows │ └── elixir.yml └── mix.lock /test/test_helper.exs: -------------------------------------------------------------------------------- 1 | ExUnit.start() 2 | -------------------------------------------------------------------------------- /lib/phoenix_mjml.ex: -------------------------------------------------------------------------------- 1 | defmodule Mjml do 2 | end 3 | -------------------------------------------------------------------------------- /.formatter.exs: -------------------------------------------------------------------------------- 1 | [ 2 | inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"] 3 | ] 4 | -------------------------------------------------------------------------------- /test/phoenix_mjml_test.exs: -------------------------------------------------------------------------------- 1 | defmodule PhoenixMjmlTest do 2 | use ExUnit.Case 3 | doctest PhoenixMjml 4 | 5 | test "the truth" do 6 | assert 1 + 1 == 2 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # The directory Mix will write compiled artifacts to. 2 | /_build 3 | 4 | # If you run "mix test --cover", coverage assets end up here. 5 | /cover 6 | 7 | # The directory Mix downloads your dependencies sources to. 8 | /deps 9 | 10 | # Where 3rd-party dependencies like ExDoc output generated docs. 11 | /doc 12 | 13 | # Ignore .fetch files in case you like to edit your project deps locally. 14 | /.fetch 15 | 16 | # If the VM crashes, it generates a dump, let's ignore it too. 17 | erl_crash.dump 18 | 19 | # Also ignore archive artifacts (built via "mix archive.build"). 20 | *.ez 21 | *.swp 22 | *.swo 23 | -------------------------------------------------------------------------------- /lib/phoenix_mjml/engine.ex: -------------------------------------------------------------------------------- 1 | defmodule PhoenixMjml.Engine do 2 | @behaviour Phoenix.Template.Engine 3 | 4 | def compile(path, _name) do 5 | os_type = :os.type() 6 | 7 | case do_compile_with(os_type, path) do 8 | {html, 0} -> EEx.compile_string(html, engine: Phoenix.HTML.Engine, line: 0) 9 | _ -> raise "Error MJML exited with non zero status" 10 | end 11 | end 12 | 13 | defp do_compile_with({:unix, _osname}, path) do 14 | System.cmd("mjml", [path, "-s"]) 15 | end 16 | 17 | defp do_compile_with({:win32, _osname}, path) do 18 | System.cmd("cmd.exe", ["/c", "mjml", path, "-s"]) 19 | end 20 | end 21 | -------------------------------------------------------------------------------- /mix.exs: -------------------------------------------------------------------------------- 1 | defmodule PhoenixMjml.Mixfile do 2 | use Mix.Project 3 | 4 | def project do 5 | [ 6 | app: :phoenix_mjml, 7 | version: "0.2.1", 8 | elixir: "~> 1.4", 9 | deps: deps(), 10 | package: package(), 11 | description: description() 12 | ] 13 | end 14 | 15 | def application do 16 | [applications: [:phoenix, :uuid]] 17 | end 18 | 19 | defp deps do 20 | [ 21 | {:phoenix, "~> 1.2"}, 22 | {:phoenix_html, "~> 2.6 or ~> 3.0"}, 23 | {:uuid, "~> 1.1"}, 24 | {:ex_doc, "~> 0.18", only: :dev, runtime: false} 25 | ] 26 | end 27 | 28 | defp description do 29 | """ 30 | Phoenix Template Engine for Mjml 31 | """ 32 | end 33 | 34 | defp package do 35 | [ 36 | name: :phoenix_mjml, 37 | maintainers: ["MQuy"], 38 | licenses: ["MIT"], 39 | links: %{github: "https://github.com/MQuy/phoenix_mjml"} 40 | ] 41 | end 42 | end 43 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) MQuy 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /config/config.exs: -------------------------------------------------------------------------------- 1 | # This file is responsible for configuring your application 2 | # and its dependencies with the aid of the Mix.Config module. 3 | use Mix.Config 4 | 5 | # This configuration is loaded before any dependency and is restricted 6 | # to this project. If another project depends on this project, this 7 | # file won't be loaded nor affect the parent project. For this reason, 8 | # if you want to provide default values for your application for 9 | # 3rd-party users, it should be done in your "mix.exs" file. 10 | 11 | # You can configure for your application as: 12 | # 13 | # config :phoenix_mjml, key: :value 14 | # 15 | # And access this configuration in your application as: 16 | # 17 | # Application.get_env(:phoenix_mjml, :key) 18 | # 19 | # Or configure a 3rd-party app: 20 | # 21 | # config :logger, level: :info 22 | # 23 | 24 | # It is also possible to import configuration files, relative to this 25 | # directory. For example, you can emulate configuration per environment 26 | # by uncommenting the line below and defining dev.exs, test.exs and such. 27 | # Configuration from the imported file will override the ones defined 28 | # here (which is why it is important to import them last). 29 | # 30 | # import_config "#{Mix.env}.exs" 31 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Phoenix Template Engine for Mjml 2 | 3 | [![License][deps-img]][deps] 4 | [![License][license-img]][license] 5 | 6 | > Powered by [Mjml](https://mjml.io/) 7 | 8 | 9 | ## Usage 10 | 11 | 1. Add `{:phoenix_mjml, "~> 0.2.1"}` to your deps in `mix.exs`. 12 | If you generated your app from the Phoenix master branch, 13 | add phoenix_mjml's master branch to your deps instead. 14 | `{:phoenix_mjml, github: "chrismccord/phoenix_mjml"}` 15 | 2. Add the following to your Phoenix `config/config.exs` 16 | 17 | ```elixir 18 | config :phoenix, :template_engines, 19 | mjml: PhoenixMjml.Engine 20 | ``` 21 | 3. Use the `.html.mjml` extensions for your templates. 22 | 23 | ## Optional 24 | 25 | Add mjml extension to Phoenix live reload in `config/dev.exs` 26 | 27 | ```elixir 28 | config :hello_phoenix, HelloPhoenix.Endpoint, 29 | live_reload: [ 30 | patterns: [ 31 | ~r{priv/static/.*(js|css|png|jpeg|jpg|gif|svg)$}, 32 | ~r{web/views/.*(ex)$}, 33 | ~r{web/templates/.*(eex|mjml)$} 34 | ] 35 | ] 36 | ``` 37 | 38 | ## License 39 | 40 | MIT license. Please see [LICENSE][license] for details. 41 | 42 | [deps-img]: https://beta.hexfaktor.org/badge/all/github/dailydrip/firestorm.svg 43 | [deps]: https://beta.hexfaktor.org/github/dailydrip/firestorm 44 | [license-img]: http://img.shields.io/badge/license-MIT-brightgreen.svg 45 | [license]: http://opensource.org/licenses/MIT 46 | [LICENSE]: https://github.com/MQuy/phoenix_mjml 47 | -------------------------------------------------------------------------------- /.github/workflows/elixir.yml: -------------------------------------------------------------------------------- 1 | name: Elixir 2 | on: push 3 | 4 | env: 5 | MIX_ENV: test 6 | 7 | # https://github.com/elixir-lang/elixir/blob/master/lib/elixir/pages/compatibility-and-deprecations.md 8 | jobs: 9 | elixir_1_12: 10 | runs-on: ubuntu-20.04 11 | name: OTP ${{matrix.otp}} / Elixir ${{matrix.elixir}} 12 | strategy: 13 | matrix: 14 | otp: [22.x, 23.x, 24.x] 15 | elixir: [1.12.x] 16 | steps: 17 | - uses: actions/checkout@v2 18 | - uses: erlef/setup-beam@v1 19 | with: 20 | otp-version: ${{matrix.otp}} 21 | elixir-version: ${{matrix.elixir}} 22 | - run: mix do deps.get, compile --warnings-as-errors 23 | - run: mix format --dry-run --check-formatted 24 | - run: mix test 25 | 26 | elixir_1_11: 27 | runs-on: ubuntu-20.04 28 | name: OTP ${{matrix.otp}} / Elixir ${{matrix.elixir}} 29 | strategy: 30 | matrix: 31 | otp: [21.x, 22.x, 23.x, 24.x] 32 | elixir: [1.11.x] 33 | steps: 34 | - uses: actions/checkout@v2 35 | - uses: erlef/setup-beam@v1 36 | with: 37 | otp-version: ${{matrix.otp}} 38 | elixir-version: ${{matrix.elixir}} 39 | - run: mix do deps.get, compile --warnings-as-errors 40 | - run: mix format --dry-run --check-formatted 41 | - run: mix test 42 | 43 | elixir_1_10: 44 | runs-on: ubuntu-20.04 45 | name: OTP ${{matrix.otp}} / Elixir ${{matrix.elixir}} 46 | strategy: 47 | matrix: 48 | otp: [21.x, 22.x, 23.x] 49 | elixir: [1.10.x] 50 | steps: 51 | - uses: actions/checkout@v2 52 | - uses: erlef/setup-beam@v1 53 | with: 54 | otp-version: ${{matrix.otp}} 55 | elixir-version: ${{matrix.elixir}} 56 | - run: mix do deps.get, compile --warnings-as-errors 57 | - run: mix format --dry-run --check-formatted 58 | - run: mix test -------------------------------------------------------------------------------- /mix.lock: -------------------------------------------------------------------------------- 1 | %{ 2 | "earmark": {:hex, :earmark, "1.2.6", "b6da42b3831458d3ecc57314dff3051b080b9b2be88c2e5aa41cd642a5b044ed", [:mix], [], "hexpm", "b42a23e9bd92d65d16db2f75553982e58519054095356a418bb8320bbacb58b1"}, 3 | "ex_doc": {:hex, :ex_doc, "0.19.1", "519bb9c19526ca51d326c060cb1778d4a9056b190086a8c6c115828eaccea6cf", [:mix], [{:earmark, "~> 1.1", [hex: :earmark, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.7", [hex: :makeup_elixir, repo: "hexpm", optional: false]}], "hexpm", "dc87f778d8260da0189a622f62790f6202af72f2f3dee6e78d91a18dd2fcd137"}, 4 | "makeup": {:hex, :makeup, "0.5.1", "966c5c2296da272d42f1de178c1d135e432662eca795d6dc12e5e8787514edf7", [:mix], [{:nimble_parsec, "~> 0.2.2", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "259748a45dfcf5f49765a7c29c9594791c82de23e22d7a3e6e59533fe8e8935b"}, 5 | "makeup_elixir": {:hex, :makeup_elixir, "0.8.0", "1204a2f5b4f181775a0e456154830524cf2207cf4f9112215c05e0b76e4eca8b", [:mix], [{:makeup, "~> 0.5.0", [hex: :makeup, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 0.2.2", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "393d17c5a648e3b30522b2a4743bd1dc3533e1227c8c2823ebe8c3a8e5be5913"}, 6 | "mime": {:hex, :mime, "1.1.0", "01c1d6f4083d8aa5c7b8c246ade95139620ef8effb009edde934e0ec3b28090a", [:mix], [], "hexpm", "33dd09e615daab5668c15cc3a33829892728fdbed910ab0c0a0edb06b45fc54d"}, 7 | "nimble_parsec": {:hex, :nimble_parsec, "0.2.2", "d526b23bdceb04c7ad15b33c57c4526bf5f50aaa70c7c141b4b4624555c68259", [:mix], [], "hexpm", "4ababf5c44164f161872704e1cfbecab3935fdebec66c72905abaad0e6e5cef6"}, 8 | "phoenix": {:hex, :phoenix, "1.2.5", "dbc45a5f8fb522aaa815b003f2d5598bc45e23102ae3e265768848ab23eafcb7", [:mix], [{:cowboy, "~> 1.0", [hex: :cowboy, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 1.0", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:plug, "~> 1.3.3 or ~> 1.2.4 or ~> 1.1.8 or ~> 1.0.5", [hex: :plug, repo: "hexpm", optional: false]}, {:poison, "~> 1.5 or ~> 2.0", [hex: :poison, repo: "hexpm", optional: false]}], "hexpm", "53141e3226ccc4abbf141961699aeefb7048fb129c64825215e4ceb18c03e938"}, 9 | "phoenix_html": {:hex, :phoenix_html, "2.9.3", "1b5a2122cbf743aa242f54dced8a4f1cc778b8bd304f4b4c0043a6250c58e258", [:mix], [{:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "f090e3a75de4efd72ae2b9b016909fe673512ef04e6b72d7bf039031a64d4a52"}, 10 | "phoenix_pubsub": {:hex, :phoenix_pubsub, "1.0.2", "bfa7fd52788b5eaa09cb51ff9fcad1d9edfeb68251add458523f839392f034c1", [:mix], [], "hexpm", "6f9193364c5de86b85e8d3a80294a134aecf6c5618adcbae668608749e00a7f7"}, 11 | "plug": {:hex, :plug, "1.3.5", "7503bfcd7091df2a9761ef8cecea666d1f2cc454cbbaf0afa0b6e259203b7031", [:mix], [{:cowboy, "~> 1.0.1 or ~> 1.1", [hex: :cowboy, repo: "hexpm", optional: true]}, {:mime, "~> 1.0", [hex: :mime, repo: "hexpm", optional: false]}], "hexpm", "141058cca1fa800128391ece7f442f71a7b42a7411e6eaa56dc8f85283c8dde7"}, 12 | "poison": {:hex, :poison, "2.2.0", "4763b69a8a77bd77d26f477d196428b741261a761257ff1cf92753a0d4d24a63", [:mix], [], "hexpm", "519bc209e4433961284174c497c8524c001e285b79bdf80212b47a1f898084cc"}, 13 | "uuid": {:hex, :uuid, "1.1.6", "4927232f244e69c6e255643014c2d639dad5b8313dc2a6976ee1c3724e6ca60d", [:mix], [], "hexpm", "717e93d768e2e393308a65ab23b65e55c2a15d6dc83b6a2c08854cf4b23b3e0a"}, 14 | } 15 | --------------------------------------------------------------------------------