aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJean-Nicolas Veigel <art.jnveigel@gmail.com>2024-03-17 18:50:14 +0100
committerLouis Pilfold <louis@lpil.uk>2024-03-26 10:31:25 +0000
commit68b72402d90414c84a7db38c25b916b3080a4043 (patch)
treeb09c33935ec52bd8265a9b6de7cfef6ba0e75f77
parentbf5e64da6c7f2e79d853b956d1842a1c45dae91b (diff)
downloadtour-68b72402d90414c84a7db38c25b916b3080a4043.tar.gz
tour-68b72402d90414c84a7db38c25b916b3080a4043.zip
chore: delete render module
-rw-r--r--src/tour.gleam266
-rw-r--r--src/tour/render.gleam223
-rw-r--r--src/tour/widgets.gleam9
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,