128 lines
3.6 KiB
Elm
128 lines
3.6 KiB
Elm
module MParser exposing (ezmd)
|
|
|
|
import Element exposing (..)
|
|
import Element.Background
|
|
import Element.Border
|
|
import Element.Font as Font
|
|
import Html.Attributes
|
|
import Markdown.Html
|
|
import Markdown.Parser
|
|
import SiteComponents exposing (..)
|
|
|
|
|
|
ezmd input =
|
|
case markdownView input of
|
|
Ok rendered ->
|
|
Element.column [ Element.spacing 30 ] rendered
|
|
|
|
Err errors ->
|
|
Element.text errors
|
|
|
|
|
|
markdownView : String -> Result String (List (Element msg))
|
|
markdownView markdown =
|
|
markdown
|
|
|> Markdown.Parser.parse
|
|
|> Result.mapError (\error -> error |> List.map Markdown.Parser.deadEndToString |> String.join "\n")
|
|
|> Result.andThen (Markdown.Parser.render renderer)
|
|
|
|
|
|
renderer : Markdown.Parser.Renderer (Element msg)
|
|
renderer =
|
|
{ heading = heading
|
|
, raw = Element.paragraph [ Element.spacing 15 ]
|
|
, thematicBreak = Element.none
|
|
, plain = Element.text
|
|
, bold = \content -> Element.row [ Font.bold ] [ Element.text content ]
|
|
, italic = \content -> Element.row [ Font.italic ] [ Element.text content ]
|
|
, code = code
|
|
, link =
|
|
\{ destination } body ->
|
|
(if List.member (String.left 1 destination) [ "#", "/" ] then
|
|
Element.link
|
|
|
|
else
|
|
Element.newTabLink
|
|
)
|
|
[ Element.htmlAttribute (Html.Attributes.style "display" "inline-flex") ]
|
|
{ url = destination
|
|
, label = Element.paragraph [ Font.color basedGreen, Font.underline ] body
|
|
}
|
|
|> Ok
|
|
, image =
|
|
\image body ->
|
|
Element.image [ Element.width (Element.maximum 700 Element.fill) ] { src = image.src, description = body }
|
|
|> Ok
|
|
, list =
|
|
\items ->
|
|
Element.column [ Element.spacing 15 ]
|
|
(items
|
|
|> List.map
|
|
(\itemBlocks ->
|
|
Element.row [ Element.spacing 5 ]
|
|
[ Element.el
|
|
[ Element.alignTop ]
|
|
(Element.text "•")
|
|
, itemBlocks
|
|
]
|
|
)
|
|
)
|
|
, codeBlock = codeBlock
|
|
, html = Markdown.Html.oneOf []
|
|
}
|
|
|
|
|
|
rawTextToId rawText =
|
|
rawText
|
|
|> String.toLower
|
|
|> String.replace " " "-"
|
|
|
|
|
|
heading : { level : Int, rawText : String, children : List (Element msg) } -> Element msg
|
|
heading { level, rawText, children } =
|
|
let
|
|
fontSize =
|
|
case level of
|
|
1 ->
|
|
36
|
|
|
|
2 ->
|
|
24
|
|
|
|
_ ->
|
|
20
|
|
in
|
|
paragraph
|
|
[ Element.htmlAttribute (Html.Attributes.attribute "name" (rawTextToId rawText))
|
|
, Element.htmlAttribute (Html.Attributes.id (rawTextToId rawText))
|
|
, width fill
|
|
, height shrink
|
|
, padding 10
|
|
, greenLines
|
|
, Font.size fontSize
|
|
]
|
|
children
|
|
|
|
|
|
code : String -> Element msg
|
|
code snippet =
|
|
Element.el
|
|
[ Element.Background.color (Element.rgba 0 0 0 0.04)
|
|
, scrollbars
|
|
, Element.Border.rounded 2
|
|
, Element.paddingXY 5 3
|
|
]
|
|
(Element.text snippet)
|
|
|
|
|
|
codeBlock : { body : String, language : Maybe String } -> Element msg
|
|
codeBlock details =
|
|
Element.el
|
|
[ Element.Background.color (Element.rgba 0 0 0 0.03)
|
|
, scrollbars
|
|
, Element.htmlAttribute (Html.Attributes.style "white-space" "pre")
|
|
, Element.padding 20
|
|
, Element.width Element.fill
|
|
]
|
|
(Element.text details.body)
|