marschro
Style formatting for nested elements with earmark or earmark_parser
Hello,
so I started to integrate markdown editing in my app and I ended up integrating earmark, which works fine for me.
Currently I have a utility function that I can call everywhere in my LiveViews in order to generate html from markdown.
Here how his looks ( I reuse styles, defined in my CoreComponents):
@doc """
parse markdown to styled html
"""
def markdown(nil), do: nil
def markdown(content) do
case Earmark.Parser.as_ast(content) do
{:ok, ast, _warnings} ->
ast
|> parse_ast()
|> Earmark.Transform.transform()
{:error, _ast, warnings} ->
{:warning, _id, msg} = List.first(warnings)
"Invalid markup: #{msg}"
end
end
defp parse_ast(ast) do
ast
|> Earmark.Transform.map_ast(fn node -> parse_node(node) end, ignore_strings: true)
|> List.flatten()
end
defp parse_node({_tag, _attrs, _children_or_content, _meta} = node) do
add = fn class_list ->
fn node -> Earmark.AstTools.merge_atts_in_node(node, class: Enum.join(class_list, " ")) end
end
processors = [
{"h1", add.(PortalWeb.CoreComponents.typography(:h1))},
{"h2", add.(PortalWeb.CoreComponents.typography(:h2))},
{"h3", add.(PortalWeb.CoreComponents.typography(:h3))},
{"h4", add.(PortalWeb.CoreComponents.typography(:h4))},
{"p", add.(PortalWeb.CoreComponents.typography(:p))},
{"ul", add.(PortalWeb.CoreComponents.typography(:ul))},
{"ol", add.(PortalWeb.CoreComponents.typography(:ol))},
{"li", add.(PortalWeb.CoreComponents.typography(:li))},
{"a", add.(PortalWeb.CoreComponents.typography(:a))},
{"strong", add.(PortalWeb.CoreComponents.typography(:strong))},
{"em", add.(PortalWeb.CoreComponents.typography(:em))},
{"u", add.(PortalWeb.CoreComponents.typography(:u))},
{"img", add.(PortalWeb.CoreComponents.typography(:img))},
{"blockquote", add.(PortalWeb.CoreComponents.typography(:blockquote))},
{"hr", add.(PortalWeb.CoreComponents.typography(:hr))},
{"code", add.(PortalWeb.CoreComponents.typography(:code))},
{"pre", add.(PortalWeb.CoreComponents.typography(:pre))}
]
postprocessor =
Earmark.Options.make_options!(registered_processors: processors)
|> Earmark.Transform.make_postprocessor()
postprocessor.(node)
end
No I have two questions:
- I ran into the thing, that earmark_parser was extracted from earmark. So if I only use earmark_parser - how do I generate html markup from the generated ast ? With floki? How is that done.
- Also I struggle with styling nested elements like lists in list. Has anyone a good example how that can be achieved? Currently I only can add classes to every
- element but cannot differntiate if this is a list of 1st or second level… (don’t want to do that via css but with tailwind classes…)
Any advice appreciated ![]()
… also how is such a cool editor done like this one I am typing in…
Most Liked
RobertDober
There is no built in way to do this easily as far as I remember, the idea is that you need to transform the ast yourself, here is a draft of how this should work
defp add_level_att(tag, atts, inner, meta, level) do
{
tag,
Keyword.put(atts, :class, "list-level-#{level}"),
recursive_map(inner, level+1),
meta
}
end
defp recursive_map(ast, level)
defp recursive_map(list, level) when is_list(list), do: Enum.map(list, &recursive_map(&1, level))
defp recursive_map(leaf, _) when is_binary(leaf), do: leaf
defp recursive_map({"ol", atts, inner, meta}, level), do: add_level_att("ol", atts, inner, meta, level)
defp recursive_map({"ul", atts, inner, meta}, level), do: add_level_att("ul", atts, inner, meta, level)
defp recursive_map({tag, atts, inner, meta}, level), do: {tag, atts, recursive_map(inner, level), meta}
1
Popular in Questions
Hi guys, i’m new in the Elixir world, and i have to say, that i love it!
i’m having some problem to understand anonymous functions with ...
New
Original source of discussion: This topic on the Pragmatic Programmers’ Functional Web Development with Elixir, OTP, and Phoenix forum.
...
New
Hi. I’ve noticed that Windows Powershell has it’s own IEX command and you cannot access Elixir’s IEX due to the conflict. This isn’t a cr...
New
About me? ( if you have nothing better to do than reading about some random guy in the internet :stuck_out_tongue: )
Hello all, this is ...
New
What is the idiomatic way of matching for not nil in Elixir?
E.g.,
First way:
defp halt_if_not_signed_in(conn, signed_in_account) when...
New
If I have a string “1000 cfu/ml” . I want to remove the characters and / and space . So the string is like this
"1000"
What is the ...
New
I’m not a pro in using Regex and can’t figure out why the following behaviour happens, especially if we take into account the difference ...
New
Good day to you all.
I have been struggling to get a query involving like and ilike to work.
Can anyone assist me on this, please?
pro...
New
Hi all,
Trying to get some more clarity over utc_datetime and naive_datetime for Ecto:
The documentation above suggests that while ...
New
Hello everyone,
I try to use an Javascript Event Handler in my root.html.leex file.
Therefore I created a function in the app.js file: ...
New
Other popular topics
Hello, how can I check the Phoenix version ?
Thanks !
New
I’m brand new to Phoenix and I have stripped one of the demo applications to the bone. I just want to get an svg up on the screen. Here i...
New
I’ve read in another post that it may be possible with a router helper - but I couldn’t find an appropriate one, and tbh, I’m still just ...
New
TL;DR: I’ve just released an implementation of Microsoft’s IDE-independent Language Server Protocol for Elixir. It adds language support ...
New
I believe there are people here who are dealing with CSV files import on the daily basis, and since Excel is a really popular tool there ...
New
I am using Ecto timestamps with postgres, I can see the timestamps() use the :naive_dateime but for my use case I wanted to store the ti...
New
Why is it that the mnesia database isn’t the most preferred database for use in Elixir/Phoenix?
New
Surface is an experimental library built on top of Phoenix LiveView and its new LiveComponent API that aims to provide a more declarative...
New
Hello everyone,
Long time lurker first time poster here. I’ve recently begun working on Elixir full-time again! :raised_hands: It’s been...
New
Hello everyone,
I try to use an Javascript Event Handler in my root.html.leex file.
Therefore I created a function in the app.js file: ...
New
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #deployment
- #library
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #channels
- #elixirconf
- #exunit
- #discussion
- #code-sync
- #javascript
- #podcasts
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixir-ls
- #phoenix_html
- #iex
- #blog-post
- #graphql
- #genstage
- #ai
- #websockets
- #supervisor
- #advent-of-code
- #elixirconf-us
- #distillery
- #processes
- #forms
- #api
- #metaprogramming
- #security
- #performance








