diff options
author | Jean-Nicolas Veigel <art.jnveigel@gmail.com> | 2024-03-17 18:50:14 +0100 |
---|---|---|
committer | Louis Pilfold <louis@lpil.uk> | 2024-03-26 10:31:25 +0000 |
commit | 68b72402d90414c84a7db38c25b916b3080a4043 (patch) | |
tree | b09c33935ec52bd8265a9b6de7cfef6ba0e75f77 /src | |
parent | bf5e64da6c7f2e79d853b956d1842a1c45dae91b (diff) | |
download | tour-68b72402d90414c84a7db38c25b916b3080a4043.tar.gz tour-68b72402d90414c84a7db38c25b916b3080a4043.zip |
chore: delete render module
Diffstat (limited to 'src')
-rw-r--r-- | src/tour.gleam | 266 | ||||
-rw-r--r-- | src/tour/render.gleam | 223 | ||||
-rw-r--r-- | src/tour/widgets.gleam | 9 |
3 files changed, 246 insertions, 252 deletions
diff --git a/src/tour.gleam b/src/tour.gleam index 1001252..4c35344 100644 --- a/src/tour.gleam +++ b/src/tour.gleam @@ -8,7 +8,6 @@ import gleam/string_builder import htmb.{type Html, h, text} import simplifile import snag -import tour/render.{PageConfig, ScriptConfig} import tour/widgets.{Link} const static = "static" @@ -310,7 +309,7 @@ fn contents_list_html(chapter: Chapter) -> String { ]) } -fn render_html(html: htmb.Html) -> String { +fn render_html(html: Html) -> String { html |> htmb.render |> string_builder.to_string @@ -557,7 +556,7 @@ fn file_error( // Page renders /// Renders the navbar with common links -fn navbar_render() -> Html { +fn render_navbar() -> Html { widgets.navbar(titled: "Gleam Language Tour", links: [ // TODO: find better label Link(label: "Tour index", to: path_everything), @@ -565,6 +564,16 @@ fn navbar_render() -> Html { ]) } +/// Renders the script that that contains the code +/// needed for the light/dark theme picker to work +pub fn theme_picker_script() -> Html { + html_dangerous_inline_script( + widgets.theme_picker_js, + ScriptOptions(module: True, defer: False), + [], + ) +} + /// Renders a Lesson's page /// Complete with title, lesson, editor and output fn lesson_page_render(lesson: Lesson) -> String { @@ -575,7 +584,7 @@ fn lesson_page_render(lesson: Lesson) -> String { } } - render.render(PageConfig( + render_page(PageConfig( path: lesson.path, title: lesson.name, stylesheets: list.flatten([ @@ -583,7 +592,7 @@ fn lesson_page_render(lesson: Lesson) -> String { css_defaults_code, [css_page_common], ]), - static_content: [navbar_render()], + static_content: [render_navbar()], content: [ h("article", [#("id", "playground")], [ h("section", [#("id", "left")], [ @@ -609,17 +618,13 @@ fn lesson_page_render(lesson: Lesson) -> String { ], scripts: ScriptConfig( body: [ - widgets.theme_picker_script(), + theme_picker_script(), h("script", [#("type", "gleam"), #("id", "code")], [ htmb.dangerous_unescaped_fragment(string_builder.from_string( lesson.code, )), ]), - render.script( - "/index.js", - render.ScriptOptions(module: True, defer: False), - [], - ), + html_script("/index.js", ScriptOptions(module: True, defer: False), []), ], head: [], ), @@ -739,7 +744,7 @@ const css_everything_page = "/css/pages/everything.css" /// Renders the /everything page to a string pub fn everything_page_render(chapters: List(Chapter)) -> String { // TODO: use proper values for location and such - render.render(PageConfig( + render_page(PageConfig( path: path_everything, title: "Everything!", stylesheets: list.flatten([ @@ -747,29 +752,250 @@ pub fn everything_page_render(chapters: List(Chapter)) -> String { css_defaults_code, [css_page_common, css_everything_page], ]), - static_content: [navbar_render()], + static_content: [render_navbar()], content: [everything_page_html(chapters)], scripts: ScriptConfig( head: [ - render.script( + html_script( "/js/highlight/highlight.core.min.js", - render.ScriptOptions(module: True, defer: False), + ScriptOptions(module: True, defer: False), [], ), - render.script( + html_script( "/js/highlight/regexes.js", - render.ScriptOptions(module: True, defer: True), + ScriptOptions(module: True, defer: True), [], ), ], body: [ - widgets.theme_picker_script(), - render.script( + theme_picker_script(), + html_script( "/js/highlight/highlight-gleam.js", - render.ScriptOptions(module: True, defer: True), + ScriptOptions(module: True, defer: True), [], ), ], ), )) } + +/// Generic HTML rendering utils +pub type HtmlAttribute = + #(String, String) + +pub type ScriptOptions { + ScriptOptions(module: Bool, defer: Bool) +} + +/// Formats js script options into usage html attributes +fn html_script_common_attributes( + attributes: ScriptOptions, +) -> List(HtmlAttribute) { + let type_attr = #("type", case attributes.module { + True -> "module" + _ -> "text/javascript" + }) + let defer_attr = #("defer", "") + + case attributes.defer { + True -> [defer_attr, type_attr] + _ -> [type_attr] + } +} + +/// Renders an HTML script tag +pub fn html_script( + src source: String, + options attributes: ScriptOptions, + attributes additional_attributes: List(HtmlAttribute), +) -> Html { + let attrs = { + let src_attr = #("src", source) + let base_attrs = [src_attr, ..html_script_common_attributes(attributes)] + list.flatten([base_attrs, additional_attributes]) + } + h("script", attrs, []) +} + +/// Renders an inline HTML script tag +pub fn html_dangerous_inline_script( + script content: String, + options attributes: ScriptOptions, + attributes additional_attributes: List(HtmlAttribute), +) -> Html { + let attrs = { + list.flatten([ + html_script_common_attributes(attributes), + additional_attributes, + ]) + } + h("script", attrs, [ + htmb.dangerous_unescaped_fragment(string_builder.from_string(content)), + ]) +} + +/// Renders an HTML meta tag +pub fn html_meta(data attributes: List(HtmlAttribute)) -> Html { + h("meta", attributes, []) +} + +/// Renders an HTML meta property tag +pub fn html_meta_prop(property: String, content: String) -> Html { + html_meta([#("property", property), #("content", content)]) +} + +/// Renders an HTML link tag +pub fn html_link(rel: String, href: String) -> Html { + h("link", [#("rel", rel), #("href", href)], []) +} + +/// Renders a stylesheet link tag +pub fn html_stylesheet(src: String) -> Html { + html_link("stylesheet", src) +} + +/// Renders an HTML title tag +pub fn html_title(title: String) -> Html { + h("title", [], [text(title)]) +} + +pub type HeadConfig { + HeadConfig( + path: String, + title: String, + description: String, + url: String, + image: String, + meta: List(Html), + stylesheets: List(String), + scripts: List(Html), + ) +} + +/// Renders the page head as HTML +fn head(with config: HeadConfig) -> htmb.Html { + let meta_tags = [ + html_meta_prop("og:type", "website"), + html_meta_prop("og:title", config.title), + html_meta_prop("og:description", config.description), + html_meta_prop("og:url", config.url), + html_meta_prop("og:image", config.image), + html_meta_prop("twitter:card", "summary_large_image"), + html_meta_prop("twitter:url", config.url), + html_meta_prop("twitter:title", config.title), + html_meta_prop("twitter:description", config.description), + html_meta_prop("twitter:image", config.image), + ..config.meta + ] + + let head_meta = [ + html_meta([#("charset", "utf-8")]), + html_meta([ + #("name", "viewport"), + #("content", "width=device-width, initial-scale=1"), + ]), + html_title(config.title), + html_meta([#("name", "description"), #("content", config.description)]), + ..meta_tags + ] + + let head_links = [ + html_link("shortcut icon", "https://gleam.run/images/lucy/lucy.svg"), + ..list.map(config.stylesheets, html_stylesheet) + ] + + let head_content = list.concat([head_meta, head_links, config.scripts]) + + h("head", [], head_content) +} + +pub type BodyConfig { + BodyConfig( + content: List(Html), + static_content: List(Html), + scripts: List(Html), + attributes: List(HtmlAttribute), + ) +} + +/// Renders an Html body tag +fn html_body(with config: BodyConfig) -> Html { + let content = + list.flatten([config.static_content, config.content, config.scripts]) + + h("body", config.attributes, content) +} + +pub type HtmlConfig { + HtmlConfig( + attributes: List(HtmlAttribute), + lang: String, + head: HeadConfig, + body: BodyConfig, + ) +} + +/// Renders an HTML tag and its children +fn html(with config: HtmlConfig) -> Html { + let attributes = [#("lang", config.lang), ..config.attributes] + + h("html", attributes, [head(config.head), html_body(config.body)]) +} + +pub type ScriptConfig { + ScriptConfig(head: List(Html), body: List(Html)) +} + +pub type PageConfig { + PageConfig( + path: String, + title: String, + content: List(Html), + static_content: List(Html), + stylesheets: List(String), + scripts: ScriptConfig, + ) +} + +/// Renders a page in the language tour +pub fn render_page_html(page config: PageConfig) -> Html { + // add path-specific class to body to make styling easier + let body_class = #("id", "page" <> string.replace(config.path, "/", "-")) + + // render html + html(HtmlConfig( + head: HeadConfig( + description: "An interactive introduction and reference to the Gleam programming language. Learn Gleam in your browser!", + image: "https://gleam.run/images/og-image.png", + title: config.title <> " - The Gleam Language Tour", + url: "https://tour.gleam.run/" <> config.path, + path: config.path, + meta: [], + stylesheets: config.stylesheets, + scripts: [ + html_script( + "https://plausible.io/js/script.js", + ScriptOptions(defer: True, module: False), + [#("data-domain", "tour.gleam.run")], + ), + ..config.scripts.head + ], + ), + lang: "en-GB", + attributes: [#("class", "theme-light theme-init")], + body: BodyConfig( + attributes: [body_class], + scripts: config.scripts.body, + static_content: config.static_content, + content: config.content, + ), + )) +} + +/// Renders an HTML document in String form from a PageConfig +pub fn render_page(page config: PageConfig) -> String { + config + |> render_page_html + |> htmb.render_page("html") + |> string_builder.to_string +} diff --git a/src/tour/render.gleam b/src/tour/render.gleam deleted file mode 100644 index 3502f6e..0000000 --- a/src/tour/render.gleam +++ /dev/null @@ -1,223 +0,0 @@ -import htmb.{type Html, h, text} -import gleam/list -import gleam/string -import gleam/string_builder - -pub type HtmlAttribute = - #(String, String) - -pub type ScriptOptions { - ScriptOptions(module: Bool, defer: Bool) -} - -/// Formats js script options into usage html attributes -fn script_common_attributes(attributes: ScriptOptions) -> List(HtmlAttribute) { - let type_attr = #("type", case attributes.module { - True -> "module" - _ -> "text/javascript" - }) - let defer_attr = #("defer", "") - - case attributes.defer { - True -> [defer_attr, type_attr] - _ -> [type_attr] - } -} - -/// Renders an HTML script tag -pub fn script( - src source: String, - options attributes: ScriptOptions, - attributes additional_attributes: List(HtmlAttribute), -) -> Html { - let attrs = { - let src_attr = #("src", source) - let base_attrs = [src_attr, ..script_common_attributes(attributes)] - list.flatten([base_attrs, additional_attributes]) - } - h("script", attrs, []) -} - -/// Renders an inline HTML script tag -pub fn dangerous_inline_script( - script content: String, - options attributes: ScriptOptions, - attributes additional_attributes: List(HtmlAttribute), -) -> Html { - let attrs = { - list.flatten([script_common_attributes(attributes), additional_attributes]) - } - h("script", attrs, [ - htmb.dangerous_unescaped_fragment(string_builder.from_string(content)), - ]) -} - -/// Renders an HTML meta tag -pub fn meta(data attributes: List(HtmlAttribute)) -> Html { - h("meta", attributes, []) -} - -/// Renders an HTML meta property tag -pub fn meta_prop(property: String, content: String) -> Html { - meta([#("property", property), #("content", content)]) -} - -/// Renders an HTML link tag -pub fn link(rel: String, href: String) -> Html { - h("link", [#("rel", rel), #("href", href)], []) -} - -/// Renders a stylesheet link tag -pub fn stylesheet(src: String) -> Html { - link("stylesheet", src) -} - -/// Renders an HTML title tag -pub fn title(title: String) -> Html { - h("title", [], [text(title)]) -} - -pub type HeadConfig { - HeadConfig( - path: String, - title: String, - description: String, - url: String, - image: String, - meta: List(Html), - stylesheets: List(String), - scripts: List(Html), - ) -} - -/// Renders the page head as HTML -fn head(with config: HeadConfig) -> htmb.Html { - let meta_tags = [ - meta_prop("og:type", "website"), - meta_prop("og:title", config.title), - meta_prop("og:description", config.description), - meta_prop("og:url", config.url), - meta_prop("og:image", config.image), - meta_prop("twitter:card", "summary_large_image"), - meta_prop("twitter:url", config.url), - meta_prop("twitter:title", config.title), - meta_prop("twitter:description", config.description), - meta_prop("twitter:image", config.image), - ..config.meta - ] - - let head_meta = [ - meta([#("charset", "utf-8")]), - meta([ - #("name", "viewport"), - #("content", "width=device-width, initial-scale=1"), - ]), - title(config.title), - meta([#("name", "description"), #("content", config.description)]), - ..meta_tags - ] - - let head_links = [ - link("shortcut icon", "https://gleam.run/images/lucy/lucy.svg"), - ..list.map(config.stylesheets, stylesheet) - ] - - let head_content = list.concat([head_meta, head_links, config.scripts]) - - h("head", [], head_content) -} - -pub type BodyConfig { - BodyConfig( - content: List(Html), - static_content: List(Html), - scripts: List(Html), - attributes: List(HtmlAttribute), - ) -} - -/// Renders an Html body tag -fn body(with config: BodyConfig) -> Html { - let content = - list.flatten([config.static_content, config.content, config.scripts]) - - h("body", config.attributes, content) -} - -pub type HtmlConfig { - HtmlConfig( - attributes: List(HtmlAttribute), - lang: String, - head: HeadConfig, - body: BodyConfig, - ) -} - -/// Renders an HTML tag and its children -fn html(with config: HtmlConfig) -> Html { - let attributes = [#("lang", config.lang), ..config.attributes] - - h("html", attributes, [head(config.head), body(config.body)]) -} - -pub type ScriptConfig { - ScriptConfig(head: List(Html), body: List(Html)) -} - -pub type PageConfig { - PageConfig( - path: String, - title: String, - content: List(Html), - static_content: List(Html), - stylesheets: List(String), - scripts: ScriptConfig, - ) -} - -/// Renders a page in the language tour -pub fn render_html(page config: PageConfig) -> Html { - // add path-specific class to body to make styling easier - let body_class = #("id", "page" <> string.replace(config.path, "/", "-")) - - // render html - html(HtmlConfig( - head: HeadConfig( - description: "An interactive introduction and reference to the Gleam programming language. Learn Gleam in your browser!", - image: "https://gleam.run/images/og-image.png", - title: config.title <> " - The Gleam Language Tour", - url: "https://tour.gleam.run/" <> config.path, - path: config.path, - meta: [], - stylesheets: config.stylesheets, - scripts: [ - script( - "https://plausible.io/js/script.js", - ScriptOptions(defer: True, module: False), - [#("data-domain", "tour.gleam.run")], - ), - ..config.scripts.head - ], - ), - lang: "en-GB", - attributes: [#("class", "theme-light theme-init")], - body: BodyConfig( - attributes: [body_class], - scripts: config.scripts.body, - static_content: config.static_content, - content: config.content, - ), - )) -} - -pub fn render_string(page page_html: Html) -> String { - page_html - |> htmb.render_page("html") - |> string_builder.to_string -} - -pub fn render(page config: PageConfig) -> String { - config - |> render_html - |> render_string -} diff --git a/src/tour/widgets.gleam b/src/tour/widgets.gleam index c475a03..3a6f0a0 100644 --- a/src/tour/widgets.gleam +++ b/src/tour/widgets.gleam @@ -1,6 +1,5 @@ import gleam/list import htmb.{type Html, h, text} -import tour/render pub fn icon_moon() -> Html { h("svg", [#("id", "icon-moon"), #("viewBox", "0 0 24 24")], [ @@ -173,14 +172,6 @@ function initTheme() { initTheme(); " -pub fn theme_picker_script() -> Html { - render.dangerous_inline_script( - theme_picker_js, - render.ScriptOptions(module: True, defer: False), - [], - ) -} - /// Renders an HTML anhor tag pub fn anchor( to href: String, |