diff options
author | Jean-Nicolas Veigel <art.jnveigel@gmail.com> | 2024-03-16 03:50:59 +0100 |
---|---|---|
committer | Louis Pilfold <louis@lpil.uk> | 2024-03-26 10:31:25 +0000 |
commit | c041d47e3befea07f7fedba7b2bb1aa29f5755e0 (patch) | |
tree | d8e10e6016798cb7c78189e7ad61276ba7eda0f8 | |
parent | 1f31579405c73589d5375ad66934dbc3d466077a (diff) | |
download | tour-c041d47e3befea07f7fedba7b2bb1aa29f5755e0.tar.gz tour-c041d47e3befea07f7fedba7b2bb1aa29f5755e0.zip |
chore: move global components to their own module
-rw-r--r-- | src/tour.gleam | 297 | ||||
-rw-r--r-- | src/tour/components.gleam | 40 | ||||
-rw-r--r-- | src/tour/document.gleam | 18 | ||||
-rw-r--r-- | src/tour/page.gleam | 47 | ||||
-rw-r--r-- | src/tour/styles.gleam | 35 |
5 files changed, 176 insertions, 261 deletions
diff --git a/src/tour.gleam b/src/tour.gleam index a5e04ea..4834c9b 100644 --- a/src/tour.gleam +++ b/src/tour.gleam @@ -8,9 +8,9 @@ import gleam/string_builder import htmb.{h, text} import simplifile import snag -import tour/widgets import tour/document -import tour/page +import tour/page.{PageConfig, ScriptConfig} +import tour/styles const static = "static" @@ -611,71 +611,49 @@ fn everything_html(chapters: List(Chapter)) -> String { ) }) - let render_next = True - - case render_next { - True -> - page.html( - page.PageConfig( - path: "everything", - title: "Everything!", - scripts: page.ScriptConfig(head: [], body: [ - document.script( - "/highlight/highlight.core.min.js", - document.ScriptOptions(module: True, defer: True), - [], - ), - document.script( - "/highlight/highlight-gleam.js", - document.ScriptOptions(module: True, defer: True), - [], - ), - ]), - stylesheets: ["/highlight/highlight.css"], - content: [ - h("main", [#("id", "everything")], [ - h( - "aside", - [#("id", "everything-contents"), #("class", "dim-bg")], - table_of_contents, - ), - h("section", [#("id", "everything-lessons")], chapter_lessons), - ]), - ], - ), - ) - |> page.render - _ -> - page_html( - at: "everything", - titled: "Everything!!!", - containing: [ - h("main", [#("id", "everything")], [ - h( - "aside", - [#("id", "everything-contents"), #("class", "dim-bg")], - table_of_contents, - ), - h("section", [#("id", "everything-lessons")], chapter_lessons), - ]), - h( - "script", - [#("src", "/highlight/highlight.core.min.js"), #("type", "module")], + // TODO: use proper values for location and such + page.html( + page.PageConfig( + path: "everything", + title: "Everything!", + scripts: page.ScriptConfig( + head: [ + document.script( + "/js/highlight/highlight.core.min.js", + document.ScriptOptions(module: True, defer: False), [], ), - h( - "script", - [#("src", "/highlight/highlight-gleam.js"), #("type", "module")], + document.script( + "/js/highlight/regexes.js", + document.ScriptOptions(module: True, defer: True), [], ), ], - with_styles: ["/highlight/highlight.css"], - ) - } - // TODO: use proper values for location and such + body: [ + document.script( + "/js/highlight/highlight-gleam.js", + document.ScriptOptions(module: True, defer: True), + [], + ), + ], + ), + stylesheets: [styles.page, ..styles.defaults_code], + content: [ + h("main", [#("id", "everything")], [ + h( + "aside", + [#("id", "everything-contents"), #("class", "dim-bg")], + table_of_contents, + ), + h("section", [#("id", "everything-lessons")], chapter_lessons), + ]), + ], + ), + ) + |> page.render } -fn lesson_html(page: Lesson) -> String { +fn lesson_html(lesson: Lesson) -> String { let navlink = fn(name, link) { case link { None -> h("span", [], [text(name)]) @@ -683,38 +661,52 @@ fn lesson_html(page: Lesson) -> String { } } - page_html( - at: page.path, - titled: page.name, - containing: [ - h("article", [#("id", "playground")], [ - h("section", [#("id", "left")], [ - h("h2", [], [text(page.name)]), - htmb.dangerous_unescaped_fragment(string_builder.from_string( - page.text, - )), - h("nav", [#("class", "prev-next")], [ - navlink("Back", page.previous), - text(" — "), - h("a", [#("href", path_table_of_contents)], [text("Contents")]), - text(" — "), - navlink("Next", page.next), + page.html( + PageConfig( + path: lesson.path, + title: lesson.name, + content: [ + h("article", [#("id", "playground")], [ + h("section", [#("id", "left")], [ + h("h2", [], [text(lesson.name)]), + htmb.dangerous_unescaped_fragment(string_builder.from_string( + lesson.text, + )), + h("nav", [#("class", "prev-next")], [ + navlink("Back", lesson.previous), + text(" — "), + h("a", [#("href", path_table_of_contents)], [text("Contents")]), + text(" — "), + navlink("Next", lesson.next), + ]), ]), - ]), - h("section", [#("id", "right")], [ - h("section", [#("id", "editor")], [ - h("div", [#("id", "editor-target")], []), + h("section", [#("id", "right")], [ + h("section", [#("id", "editor")], [ + h("div", [#("id", "editor-target")], []), + ]), + h("aside", [#("id", "output")], []), ]), - h("aside", [#("id", "output")], []), ]), - ]), - h("script", [#("type", "gleam"), #("id", "code")], [ - htmb.dangerous_unescaped_fragment(string_builder.from_string(page.code)), - ]), - h("script", [#("type", "module"), #("src", "/index.js")], []), - ], - with_styles: [], + ], + scripts: ScriptConfig( + body: [ + h("script", [#("type", "gleam"), #("id", "code")], [ + htmb.dangerous_unescaped_fragment(string_builder.from_string( + lesson.code, + )), + ]), + document.script( + "/index.js", + document.ScriptOptions(module: True, defer: False), + [], + ), + ], + head: [], + ), + stylesheets: [styles.page, ..styles.defaults_code], + ), ) + |> page.render } type Link { @@ -726,132 +718,3 @@ fn link_html(for link: Link, attributes attributes: List(#(String, String))) { h("a", link_attributes, [text(link.label)]) } - -/// Renders the tour's navbar as html -fn page_navbar( - titled title: String, - links additional_links: List(Link), -) -> htmb.Html { - let links = { - [Link(label: "gleam.run", to: "http://gleam.run"), ..additional_links] - |> list.map(fn(l) { link_html(l, [#("class", "link")]) }) - } - let nav_right_items = list.flatten([links, [widgets.theme_picker()]]) - - h("nav", [#("class", "navbar")], [ - h("a", [#("href", "/"), #("class", "logo")], [ - h( - "img", - [ - #("src", "https://gleam.run/images/lucy/lucy.svg"), - #("alt", "Lucy the star, Gleam's mascot"), - ], - [], - ), - text(title), - ]), - h("div", [#("class", "nav-right")], nav_right_items), - ]) -} - -/// Renders the page head as HTML -fn page_head( - at path: String, - titled title: String, - with_styles styles: List(String), -) -> htmb.Html { - let metaprop = fn(property, content) { - h("meta", [#("property", property), #("content", content)], []) - } - let link = fn(rel, href) { h("link", [#("rel", rel), #("href", href)], []) } - - let stylesheet = fn(src: String) { link("stylesheet", src) } - let title = title <> " - The Gleam Language Tour" - let description = - "An interactive introduction and reference to the Gleam programming language. Learn Gleam in your browser!" - let metaprops = [ - metaprop("og:type", "website"), - metaprop("og:title", title), - metaprop("og:description", description), - metaprop("og:url", "https://tour.gleam.run/" <> path), - metaprop("og:image", "https://gleam.run/images/og-image.png"), - metaprop("twitter:card", "summary_large_image"), - metaprop("twitter:url", "https://tour.gleam.run/" <> path), - metaprop("twitter:title", title), - metaprop("twitter:description", description), - metaprop("twitter:image", "https://gleam.run/images/og-image.png"), - ] - - let metadata = [ - h("meta", [#("charset", "utf-8")], []), - h( - "meta", - [ - #("name", "viewport"), - #("content", "width=device-width, initial-scale=1"), - ], - [], - ), - h("title", [], [text(title)]), - h("meta", [#("name", "description"), #("content", description)], []), - ..metaprops - ] - - let links = [ - link("shortcut icon", "https://gleam.run/images/lucy/lucy.svg"), - link("stylesheet", "/common.css"), - link("stylesheet", "/style.css"), - ..list.map(styles, stylesheet) - ] - - let scripts = [ - h( - "script", - [ - #("defer", ""), - #("data-domain", "tour.gleam.run"), - #("src", "https://plausible.io/js/script.js"), - ], - [], - ), - h("script", [#("type", "module")], [ - htmb.dangerous_unescaped_fragment(string_builder.from_string( - widgets.theme_picker_js, - )), - ]), - ] - - let head_content = { - let parts = [metadata, links, scripts] - parts - |> list.concat - } - - h("head", [], head_content) -} - -fn page_html( - at path: String, - titled title: String, - containing content: List(htmb.Html), - with_styles styles: List(String), -) -> String { - let head = { - let static_styles = ["/common.css", "/styles.css"] - let head_styles = - [static_styles, styles] - |> list.concat() - - page_head(at: path, titled: title, with_styles: head_styles) - } - - h("html", [#("lang", "en-gb"), #("class", "theme-light")], [ - head, - h("body", [], [ - page_navbar(titled: "Gleam Language Tour", links: []), - ..content - ]), - ]) - |> htmb.render_page("html") - |> string_builder.to_string -} diff --git a/src/tour/components.gleam b/src/tour/components.gleam new file mode 100644 index 0000000..98d7590 --- /dev/null +++ b/src/tour/components.gleam @@ -0,0 +1,40 @@ +import gleam/list +import htmb.{type Html, h, text} +import tour/document.{type HtmlAttribute} +import tour/widgets + +pub type Link { + Link(label: String, to: String) +} + +/// Renders a styled text link +pub fn text_link( + for link: Link, + attributes attributes: List(HtmlAttribute), +) -> Html { + let link_attributes = [#("class", "link"), ..attributes] + + document.anchor(link.to, link_attributes, [text(link.label)]) +} + +/// Renders the tour's navbar as html +pub fn navbar(titled title: String, links links: List(Link)) -> Html { + let links = list.map(links, fn(l) { text_link(l, [#("class", "link")]) }) + + let nav_right_items = list.flatten([links, [widgets.theme_picker()]]) + + h("nav", [#("class", "navbar")], [ + document.anchor("/", [#("class", "logo")], [ + h( + "img", + [ + #("src", "https://gleam.run/images/lucy/lucy.svg"), + #("alt", "Lucy the star, Gleam's mascot"), + ], + [], + ), + text(title), + ]), + h("div", [#("class", "nav-right")], nav_right_items), + ]) +} diff --git a/src/tour/document.gleam b/src/tour/document.gleam index 892148d..6921950 100644 --- a/src/tour/document.gleam +++ b/src/tour/document.gleam @@ -31,10 +31,7 @@ pub fn script( ) -> Html { let attrs = { let src_attr = #("src", source) - let base_attrs: List(HtmlAttribute) = [ - src_attr, - ..script_common_attributes(attributes) - ] + let base_attrs = [src_attr, ..script_common_attributes(attributes)] list.flatten([base_attrs, additional_attributes]) } h("script", attrs, []) @@ -129,6 +126,19 @@ pub fn head(with config: HeadConfig) -> htmb.Html { h("head", [], head_content) } +pub type Link { + Link(label: String, to: String) +} + +/// Renders an HTML anchor tag +pub fn anchor( + to href: String, + attrs attributes: List(HtmlAttribute), + with content: List(Html), +) { + h("a", [#("href", href), ..attributes], content) +} + pub type BodyConfig { BodyConfig( content: List(Html), diff --git a/src/tour/page.gleam b/src/tour/page.gleam index 557668b..b2093bc 100644 --- a/src/tour/page.gleam +++ b/src/tour/page.gleam @@ -1,44 +1,11 @@ -import gleam/list import gleam/string import gleam/string_builder -import htmb.{type Html, h, text} -import tour/document.{ - type HtmlAttribute, BodyConfig, HeadConfig, HtmlConfig, ScriptOptions, -} +import gleam/list +import htmb.{type Html} +import tour/document.{BodyConfig, HeadConfig, HtmlConfig, ScriptOptions} +import tour/components.{Link} import tour/widgets - -pub type Link { - Link(label: String, to: String) -} - -/// Renders an HTML anchor tag -pub fn link(for link: Link, attributes attributes: List(HtmlAttribute)) -> Html { - let link_attributes = [#("href", link.to), ..attributes] - - h("a", link_attributes, [text(link.label)]) -} - -/// Renders the tour's navbar as html -pub fn navbar(titled title: String, links links: List(Link)) -> Html { - let links = list.map(links, fn(l) { link(l, [#("class", "link")]) }) - - let nav_right_items = list.flatten([links, [widgets.theme_picker()]]) - - h("nav", [#("class", "navbar")], [ - h("a", [#("href", "/"), #("class", "logo")], [ - h( - "img", - [ - #("src", "https://gleam.run/images/lucy/lucy.svg"), - #("alt", "Lucy the star, Gleam's mascot"), - ], - [], - ), - text(title), - ]), - h("div", [#("class", "nav-right")], nav_right_items), - ]) -} +import tour/styles pub type ScriptConfig { ScriptConfig(head: List(Html), body: List(Html)) @@ -68,7 +35,7 @@ pub fn html(page config: PageConfig) -> Html { url: "https://tour.gleam.run/" <> config.path, path: config.path, meta: [], - stylesheets: ["/common.css", "/style.css", ..config.stylesheets], + stylesheets: list.flatten([styles.defaults_page, config.stylesheets]), scripts: [ document.script( "https://plausible.io/js/script.js", @@ -89,7 +56,7 @@ pub fn html(page config: PageConfig) -> Html { attributes: [body_class], scripts: config.scripts.body, static_content: [ - navbar(titled: "Gleam Language Tour", links: [ + components.navbar(titled: "Gleam Language Tour", links: [ Link(label: "gleam.run", to: "http://gleam.run"), ]), ], diff --git a/src/tour/styles.gleam b/src/tour/styles.gleam new file mode 100644 index 0000000..7660393 --- /dev/null +++ b/src/tour/styles.gleam @@ -0,0 +1,35 @@ +//// A list of valid paths to static css files +//// We use these to pick and choose what style sheets to include per page + +/// Inherited from code Gleam projects +pub const common = "/common.css" + +/// Loads fonts and defines font sizes +pub const fonts = "/css/fonts.css" + +/// Derives app colors for both dark & light themes from common.css variables +pub const theme = "/css/theme.css" + +/// Defines layout unit variables +pub const layout = "/css/layout.css" + +/// Common stylesheet for all tour pages +/// TODO: split into one file per page +pub const page = "/style.css" + +/// Sensitive defaults for any page +pub const defaults_page = [theme, fonts, common, layout] + +// Defines code syntax highlighting for highlightJS & CodeFlash +// based on dark / light mode and the currenly loaded color scheme +pub const syntax_highlight = "/css/code/syntax-highlight.css" + +// Color schemes +// TODO: add more color schemes + +/// Atom One Dark & Atom One Light colors +pub const scheme_atom_one = "/css/code/color-schemes/atom-one.css" + +/// Sensitive defaults for any page needing to display Gleam code +/// To be used alonside defaults_page +pub const defaults_code = [syntax_highlight, scheme_atom_one] |