at main 3.1 kB view raw
1import gleam/dict 2import gleam/list 3import gleam/option 4import gleam/regexp 5import gleam/string 6import jot 7import lustre/attribute as attr 8import lustre/element 9import lustre/element/html 10import lustre/ssg/djot 11import website/common 12import website/style 13 14pub fn renderer() -> djot.Renderer(element.Element(msg)) { 15 let to_attributes = fn(attrs) { 16 use attrs, key, val <- dict.fold(attrs, []) 17 [attr.attribute(key, val), ..attrs] 18 } 19 20 djot.Renderer( 21 codeblock: fn(attrs, lang, code) { 22 let lang = option.unwrap(lang, "text") 23 html.pre([style.code_block(), ..to_attributes(attrs)], [ 24 html.code([attr.attribute("data-lang", lang), style.monospaced()], [ 25 html.text(code), 26 ]), 27 ]) 28 }, 29 emphasis: fn(content) { html.em([], content) }, 30 heading: fn(attrs, level, content) { 31 case level { 32 1 -> html.h1(to_attributes(attrs), content) 33 2 -> html.h2(to_attributes(attrs), content) 34 3 -> html.h3(to_attributes(attrs), content) 35 4 -> html.h4(to_attributes(attrs), content) 36 5 -> html.h5(to_attributes(attrs), content) 37 6 -> html.h6(to_attributes(attrs), content) 38 _ -> html.p(to_attributes(attrs), content) 39 } 40 }, 41 link: fn(destination, references, content) { 42 case destination { 43 jot.Reference(ref) -> 44 case dict.get(references, ref) { 45 Ok(url) -> 46 common.raw_link( 47 attributes: [], 48 content:, 49 href: url, 50 external: False, 51 ) 52 Error(_) -> 53 common.raw_link( 54 attributes: [attr.id(linkify("back-to-" <> ref))], 55 content:, 56 href: "#" <> linkify(ref), 57 external: False, 58 ) 59 } 60 jot.Url(url) -> 61 common.raw_link(attributes: [], content:, href: url, external: False) 62 } 63 }, 64 paragraph: fn(attrs, content) { html.p(to_attributes(attrs), content) }, 65 bullet_list: fn(layout, style, items) { 66 let list_style_type = 67 attr.style("list-style-type", case style { 68 "-" -> "'-'" 69 "*" -> "disc" 70 _ -> "circle" 71 }) 72 73 html.ul([list_style_type], { 74 list.map(items, fn(item) { 75 case layout { 76 jot.Tight -> html.li([], item) 77 jot.Loose -> html.li([], [html.p([], item)]) 78 } 79 }) 80 }) 81 }, 82 raw_html: fn(content) { element.unsafe_raw_html("", "div", [], content) }, 83 strong: fn(content) { html.strong([], content) }, 84 text: fn(text) { html.text(text) }, 85 code: fn(content) { html.code([style.monospaced()], [html.text(content)]) }, 86 image: fn(destination, alt) { 87 case destination { 88 jot.Reference(ref) -> 89 html.img([attr.src("#" <> linkify(ref)), attr.alt(alt)]) 90 jot.Url(url) -> html.img([attr.src(url), attr.alt(alt)]) 91 } 92 }, 93 linebreak: html.br([]), 94 thematicbreak: html.hr([]), 95 ) 96} 97 98fn linkify(text: String) -> String { 99 let assert Ok(re) = regexp.from_string(" +") 100 101 text 102 |> regexp.split(re, _) 103 |> string.join("-") 104}