mirror of
https://gitlab.com/upRootNutrition/website.git
synced 2025-06-16 12:25:12 -05:00
314 lines
9.2 KiB
Elm
314 lines
9.2 KiB
Elm
![]() |
module Config.Helpers.Markdown exposing (..)
|
||
|
|
||
|
import Browser
|
||
|
import Config.Helpers.Format
|
||
|
exposing
|
||
|
( headerFontSizeBig
|
||
|
, headerFontSizeMedium
|
||
|
, headerFontSizeSmall
|
||
|
, paragraphFontSize
|
||
|
)
|
||
|
import Config.Helpers.Response exposing (pageList)
|
||
|
import Config.Style.Colour exposing (colourTheme)
|
||
|
import Config.Style.Transitions
|
||
|
exposing
|
||
|
( hoverFontDarkOrange
|
||
|
, hoverFontLightOrange
|
||
|
, transitionStyleFast
|
||
|
, transitionStyleMedium
|
||
|
)
|
||
|
import Element as E exposing (..)
|
||
|
import Element.Background as B
|
||
|
import Element.Border as D
|
||
|
import Element.Font as F
|
||
|
import Element.Input as Input
|
||
|
import Element.Region as Region
|
||
|
import Html exposing (Attribute, Html)
|
||
|
import Html.Attributes
|
||
|
import Markdown.Block as Block exposing (Block, Inline, ListItem(..), Task(..))
|
||
|
import Markdown.Html
|
||
|
import Markdown.Parser
|
||
|
import Markdown.Renderer
|
||
|
|
||
|
|
||
|
articleImage : String -> Element msg
|
||
|
articleImage pic =
|
||
|
el
|
||
|
[ centerX
|
||
|
, width fill
|
||
|
]
|
||
|
<|
|
||
|
image
|
||
|
[ width fill
|
||
|
]
|
||
|
{ src = "/blog/" ++ pic ++ ".png", description = "" }
|
||
|
|
||
|
|
||
|
renderDeviceMarkdown : String -> Element msg
|
||
|
renderDeviceMarkdown markdown =
|
||
|
case renderMarkdown markdown of
|
||
|
Ok renderedMarkdown ->
|
||
|
column
|
||
|
[ width fill
|
||
|
, centerX
|
||
|
, spacing 8
|
||
|
, paddingEach
|
||
|
{ top = 10
|
||
|
, bottom = 0
|
||
|
, left = 0
|
||
|
, right = 0
|
||
|
}
|
||
|
]
|
||
|
renderedMarkdown
|
||
|
|
||
|
Err error ->
|
||
|
E.text error
|
||
|
|
||
|
|
||
|
renderMarkdown : String -> Result String (List (Element msg))
|
||
|
renderMarkdown markdown =
|
||
|
markdown
|
||
|
|> Markdown.Parser.parse
|
||
|
|> Result.mapError (\error -> error |> List.map Markdown.Parser.deadEndToString |> String.join "\n")
|
||
|
|> Result.andThen (Markdown.Renderer.render elmUiRenderer)
|
||
|
|
||
|
|
||
|
elmUiRenderer : Markdown.Renderer.Renderer (Element msg)
|
||
|
elmUiRenderer =
|
||
|
{ heading = heading
|
||
|
, paragraph =
|
||
|
E.paragraph
|
||
|
[ E.spacing 3
|
||
|
, paragraphFontSize
|
||
|
, F.alignLeft
|
||
|
, width fill
|
||
|
]
|
||
|
, thematicBreak = E.none
|
||
|
, text = E.text
|
||
|
, strong =
|
||
|
\content ->
|
||
|
E.row
|
||
|
[ F.bold
|
||
|
]
|
||
|
content
|
||
|
, emphasis =
|
||
|
\content ->
|
||
|
E.row
|
||
|
[ F.italic
|
||
|
]
|
||
|
content
|
||
|
, strikethrough =
|
||
|
\content ->
|
||
|
E.row
|
||
|
[ F.strike
|
||
|
]
|
||
|
content
|
||
|
, codeSpan = code
|
||
|
, link =
|
||
|
\{ title, destination } body ->
|
||
|
E.newTabLink
|
||
|
[ width fill ]
|
||
|
{ url = destination
|
||
|
, label =
|
||
|
E.paragraph
|
||
|
[ F.color colourTheme.textLightOrange
|
||
|
, paragraphFontSize
|
||
|
, transitionStyleFast
|
||
|
, hoverFontDarkOrange
|
||
|
]
|
||
|
body
|
||
|
}
|
||
|
, hardLineBreak = Html.br [] [] |> E.html
|
||
|
, image =
|
||
|
\image ->
|
||
|
case image.title of
|
||
|
Just title ->
|
||
|
el [ centerX ] <|
|
||
|
E.image
|
||
|
[ E.width <| E.px 300 ]
|
||
|
{ src = image.src
|
||
|
, description = image.alt
|
||
|
}
|
||
|
|
||
|
Nothing ->
|
||
|
el [ centerX ] <|
|
||
|
E.image
|
||
|
[ E.width <| E.px 300
|
||
|
]
|
||
|
{ src = image.src
|
||
|
, description = image.alt
|
||
|
}
|
||
|
, blockQuote =
|
||
|
\children ->
|
||
|
E.column
|
||
|
[ D.widthEach
|
||
|
{ top = 0
|
||
|
, right = 0
|
||
|
, bottom = 0
|
||
|
, left = 5
|
||
|
}
|
||
|
, D.rounded 10
|
||
|
, E.paddingEach
|
||
|
{ top = 13
|
||
|
, bottom = 10
|
||
|
, left = 10
|
||
|
, right = 10
|
||
|
}
|
||
|
, D.color colourTheme.textLightOrange
|
||
|
, B.color colourTheme.backgroundLightGrey
|
||
|
, paragraphFontSize
|
||
|
, width fill
|
||
|
]
|
||
|
children
|
||
|
, unorderedList =
|
||
|
\items ->
|
||
|
E.column
|
||
|
[ E.spacing 3
|
||
|
, paragraphFontSize
|
||
|
]
|
||
|
(items
|
||
|
|> List.map
|
||
|
(\(ListItem task children) ->
|
||
|
E.row
|
||
|
[ E.width fill
|
||
|
]
|
||
|
[ E.el
|
||
|
[ E.width <| E.px 20
|
||
|
, E.alignTop
|
||
|
, alignRight
|
||
|
]
|
||
|
(case task of
|
||
|
IncompleteTask ->
|
||
|
Input.defaultCheckbox False
|
||
|
|
||
|
CompletedTask ->
|
||
|
Input.defaultCheckbox True
|
||
|
|
||
|
NoTask ->
|
||
|
E.text "•"
|
||
|
)
|
||
|
, E.column
|
||
|
[ E.width fill, F.alignLeft ]
|
||
|
children
|
||
|
]
|
||
|
)
|
||
|
)
|
||
|
, orderedList =
|
||
|
\startingIndex items ->
|
||
|
E.column
|
||
|
[ E.spacing 3
|
||
|
, paragraphFontSize
|
||
|
, E.width fill
|
||
|
]
|
||
|
(items
|
||
|
|> List.indexedMap
|
||
|
(\index itemBlocks ->
|
||
|
E.row
|
||
|
[ E.width fill
|
||
|
|
||
|
]
|
||
|
[ E.el
|
||
|
[ E.alignTop
|
||
|
, width <| px 25
|
||
|
, F.bold
|
||
|
, alignRight
|
||
|
]
|
||
|
(E.text (String.fromInt (index + startingIndex) ++ "."))
|
||
|
, E.column
|
||
|
[ alignLeft
|
||
|
, E.width fill
|
||
|
]
|
||
|
itemBlocks
|
||
|
]
|
||
|
)
|
||
|
)
|
||
|
, codeBlock = codeBlock
|
||
|
, html = Markdown.Html.oneOf []
|
||
|
, table = E.column [ width fill ]
|
||
|
, tableHeader = E.column [ width fill ]
|
||
|
, tableBody = E.column [ width fill ]
|
||
|
, tableRow = E.row [ width fill ]
|
||
|
, tableHeaderCell =
|
||
|
\maybeAlignment children ->
|
||
|
E.paragraph [ width fill ] children
|
||
|
, tableCell =
|
||
|
\maybeAlignment children ->
|
||
|
E.paragraph [ width fill ] children
|
||
|
}
|
||
|
|
||
|
|
||
|
code : String -> Element msg
|
||
|
code snippet =
|
||
|
E.el
|
||
|
[ B.color colourTheme.backgroundLightGrey
|
||
|
, D.rounded 2
|
||
|
, E.paddingXY 5 3
|
||
|
, width fill
|
||
|
, F.family
|
||
|
[ F.external
|
||
|
{ url = "https://fonts.googleapis.com/css?family=Source+Code+Pro"
|
||
|
, name = "Source Code Pro"
|
||
|
}
|
||
|
]
|
||
|
]
|
||
|
(E.text snippet)
|
||
|
|
||
|
|
||
|
codeBlock : { body : String, language : Maybe String } -> Element msg
|
||
|
codeBlock details =
|
||
|
E.el
|
||
|
[ B.color colourTheme.backgroundLightGrey
|
||
|
, E.htmlAttribute (Html.Attributes.style "white-space" "pre")
|
||
|
, width fill
|
||
|
, E.paddingEach
|
||
|
{ top = 23
|
||
|
, bottom = 20
|
||
|
, left = 20
|
||
|
, right = 20
|
||
|
}
|
||
|
, paragraphFontSize
|
||
|
, F.family
|
||
|
[ F.external
|
||
|
{ url = "https://fonts.googleapis.com/css?family=Source+Code+Pro"
|
||
|
, name = "Source Code Pro"
|
||
|
}
|
||
|
]
|
||
|
]
|
||
|
(E.text details.body)
|
||
|
|
||
|
|
||
|
heading : { level : Block.HeadingLevel, rawText : String, children : List (Element msg) } -> Element msg
|
||
|
heading { level, rawText, children } =
|
||
|
E.paragraph
|
||
|
[ F.size
|
||
|
(case level of
|
||
|
Block.H1 ->
|
||
|
headerFontSizeBig
|
||
|
|
||
|
Block.H2 ->
|
||
|
headerFontSizeMedium
|
||
|
|
||
|
_ ->
|
||
|
headerFontSizeSmall
|
||
|
)
|
||
|
, F.bold
|
||
|
, F.center
|
||
|
, width fill
|
||
|
, F.color colourTheme.textLightOrange
|
||
|
, Region.heading (Block.headingLevelToInt level)
|
||
|
, E.htmlAttribute
|
||
|
(Html.Attributes.attribute "name" (rawTextToId rawText))
|
||
|
, E.htmlAttribute
|
||
|
(Html.Attributes.id (rawTextToId rawText))
|
||
|
]
|
||
|
children
|
||
|
|
||
|
|
||
|
rawTextToId rawText =
|
||
|
rawText
|
||
|
|> String.split " "
|
||
|
|> Debug.log "split"
|
||
|
|> String.join "-"
|
||
|
|> Debug.log "joined"
|
||
|
|> String.toLower
|