aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJean-Nicolas Veigel <art.jnveigel@gmail.com>2024-03-16 03:50:59 +0100
committerLouis Pilfold <louis@lpil.uk>2024-03-26 10:31:25 +0000
commitc041d47e3befea07f7fedba7b2bb1aa29f5755e0 (patch)
treed8e10e6016798cb7c78189e7ad61276ba7eda0f8
parent1f31579405c73589d5375ad66934dbc3d466077a (diff)
downloadtour-c041d47e3befea07f7fedba7b2bb1aa29f5755e0.tar.gz
tour-c041d47e3befea07f7fedba7b2bb1aa29f5755e0.zip
chore: move global components to their own module
-rw-r--r--src/tour.gleam297
-rw-r--r--src/tour/components.gleam40
-rw-r--r--src/tour/document.gleam18
-rw-r--r--src/tour/page.gleam47
-rw-r--r--src/tour/styles.gleam35
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]