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…