Packages
mdex
0.9.3
0.13.3
0.13.2
0.13.1
0.13.0
0.12.5
retired
0.12.4
0.12.3
0.12.2
0.12.1
0.12.0
0.11.7
0.11.6
0.11.5
0.11.4
0.11.3
0.11.2
0.11.1
0.11.0
0.10.0
0.9.4
0.9.3
0.9.2
0.9.1
0.9.0
0.8.6
0.8.5
0.8.4
0.8.3
0.8.2
0.8.1
0.8.0
0.7.5
0.7.4
0.7.3
0.7.2
0.7.1
0.7.0
0.6.2
0.6.1
0.6.0
0.5.0
0.4.3
0.4.2
0.4.1
0.4.0
0.3.3
0.3.2
0.3.1
0.3.0
0.2.0
0.1.18
0.1.17
0.1.16
0.1.15
0.1.14
0.1.13
0.1.12
0.1.11
0.1.10
0.1.9
0.1.8
0.1.7
0.1.6
0.1.5
0.1.4
0.1.3
0.1.2
0.1.1
0.1.0
Fast and extensible Markdown for Elixir
Security advisory:
This version has known vulnerabilities.
View advisories
Current section
Files
Jump to
Current section
Files
examples/nimble_publisher.livemd
<!-- livebook:{"persist_outputs":true} -->
# NimblePublisher
```elixir
Mix.install([
{:mdex, "~> 0.8"},
{:phoenix_live_view, "~> 1.0"},
{:phoenix_playground, "~> 0.1"},
{:nimble_publisher, "~> 1.1"},
{:phoenix_html, "~> 4.2"}
])
```
## Example
```elixir
defmodule MDEx.Posts.Post do
@enforce_keys [:id, :title, :date, :body]
defstruct [:id, :title, :date, :body]
def build(filepath, attrs, body) do
[year, month, day, id] =
filepath |> Path.rootname() |> Path.split() |> List.last() |> String.split("-", parts: 4)
id =
id
|> String.trim_trailing(".md")
|> String.downcase()
date = Date.from_iso8601!("#{year}-#{month}-#{day}")
struct!(__MODULE__, Map.merge(attrs, %{id: id, date: date, body: body}))
end
end
```
<!-- livebook:{"output":true} -->
```
{:module, MDEx.Posts.Post, <<70, 79, 82, 49, 0, 0, 18, ...>>, {:build, 3}}
```
```elixir
defmodule MDEx.Posts.Parser do
def parse(_path, contents) do
[header, markdown_body] = String.split(contents, "---\n", trim: true, parts: 2)
{%{} = attrs, _} = Code.eval_string(header, [])
html_body = markdown_to_html!(markdown_body)
{attrs, html_body}
end
defp markdown_to_html!(markdown_body) do
MDEx.to_html!(markdown_body,
syntax_highlight: [formatter: {:html_inline, theme: "github_dark"}],
extension: [
strikethrough: true,
underline: true,
tagfilter: true,
table: true,
autolink: true,
tasklist: true,
footnotes: true,
shortcodes: true
],
parse: [
smart: true,
relaxed_tasklist_matching: true,
relaxed_autolinks: true
],
render: [
github_pre_lang: true,
escape: true,
hardbreaks: true
]
)
end
end
```
<!-- livebook:{"output":true} -->
```
{:module, MDEx.Posts.Parser, <<70, 79, 82, 49, 0, 0, 11, ...>>, {:markdown_to_html!, 1}}
```
```elixir
defmodule MDEx.Posts.HTMLConverter do
# ⚠️ Important ⚠️
# You need to provide a custom converter, because otherwise NimblePublisher
# will apply their default markdown -> HTML conversion which will
# interfere with MDEx's conversion.
def convert(_extname, body, _attrs, _opts), do: body
end
```
<!-- livebook:{"output":true} -->
```
{:module, MDEx.Posts.HTMLConverter, <<70, 79, 82, 49, 0, 0, 7, ...>>, {:convert, 4}}
```
```elixir
defmodule MDEx.Posts do
use NimblePublisher,
# Update this filepath to your application
# and move the `posts` folder inside your `priv` folder.
#
# from: Application.app_dir(:my_app, "priv/posts/*.md"),
from: Path.join([Path.absname(__DIR__), "posts", "*.md"]),
build: MDEx.Posts.Post,
parser: MDEx.Posts.Parser,
html_converter: MDEx.Posts.HTMLConverter,
as: :posts,
highlighters: []
@posts Enum.sort_by(@posts, & &1.date, {:desc, Date})
def all_posts, do: @posts
defmodule NotFoundError do
defexception [:message, plug_status: 404]
end
def get_post_by_id!(id) do
Enum.find(all_posts(), &(&1.id == id)) ||
raise NotFoundError, "post with id=#{id} not found"
end
end
```
<!-- livebook:{"output":true} -->
```
{:module, MDEx.Posts, <<70, 79, 82, 49, 0, 0, 21, ...>>, {:get_post_by_id!, 1}}
```
```elixir
defmodule MDEx.DemoLive do
use Phoenix.LiveView
import Phoenix.HTML
def mount(%{"id" => post_id}, _session, socket) do
post = MDEx.Posts.get_post_by_id!(post_id)
{:ok, assign(socket, :post, post)}
end
# Show the first blog post by default.
# In your app, you'd show an overview of the blog posts instead.
def mount(_params, session, socket) do
mount(%{"id" => "example-post"}, session, socket)
end
def render(assigns) do
~H"""
<h1>{@post.title}</h1>
<h2>{@post.date}</h2>
<article>
{raw(@post.body)}
</article>
"""
end
end
```
<!-- livebook:{"output":true} -->
```
{:module, MDEx.DemoLive, <<70, 79, 82, 49, 0, 0, 24, ...>>, {:render, 1}}
```
```elixir
PhoenixPlayground.start(live: MDEx.DemoLive)
```
<!-- livebook:{"output":true} -->
```
19:29:52.699 [info] Running PhoenixPlayground.Endpoint with Bandit 1.7.0 at 127.0.0.1:4000 (http)
19:29:52.704 [info] Access PhoenixPlayground.Endpoint at http://localhost:4000
19:29:52.731 [info] CONNECTED TO Phoenix.LiveView.Socket in 16µs
Transport: :websocket
Serializer: Phoenix.Socket.V2.JSONSerializer
Parameters: %{"vsn" => "2.0.0"}
```
<!-- livebook:{"output":true} -->
```
{:ok, #PID<0.343.0>}
```
<!-- livebook:{"output":true} -->
```
19:29:52.781 [debug] MOUNT PhoenixPlayground.Router.DelegateLive
Parameters: %{}
Session: %{}
19:29:52.781 [debug] Replied in 115µs
19:29:52.783 [debug] HANDLE PARAMS in PhoenixPlayground.Router.DelegateLive
Parameters: %{}
19:29:52.783 [debug] Replied in 61µs
19:29:52.801 [info] GET /
19:29:52.805 [debug] Processing with PhoenixPlayground.Router.DelegateLive.index/2
Parameters: %{}
Pipelines: [:browser]
19:29:52.816 [info] Sent 200 in 15ms
19:29:52.843 [info] CONNECTED TO Phoenix.LiveView.Socket in 18µs
Transport: :websocket
Serializer: Phoenix.Socket.V2.JSONSerializer
Parameters: %{"vsn" => "2.0.0"}
19:29:52.844 [debug] MOUNT PhoenixPlayground.Router.DelegateLive
Parameters: %{}
Session: %{}
19:29:52.844 [debug] Replied in 101µs
19:29:52.844 [debug] HANDLE PARAMS in PhoenixPlayground.Router.DelegateLive
Parameters: %{}
19:29:52.844 [debug] Replied in 21µs
```