Current section

Files

Jump to
scriptorium src scriptorium rendering views base.gleam
Raw

src/scriptorium/rendering/views/base.gleam

import gleam/dict
import gleam/list
import gleam/option
import kielet.{gettext as g_}
import lustre/attribute.{attribute, href, id, name, rel, role, type_}
import lustre/element.{type Element, text}
import lustre/element/html.{
a, body, footer, h1, head, header, html, li, link, main, meta, nav, p, section,
title, ul,
}
import scriptorium/config.{type Configuration}
import scriptorium/models/database.{type Database}
import scriptorium/models/menu.{type MenuItem}
import scriptorium/rendering/views/archives
import scriptorium/rendering/views/tags
/// The base view pre-renders some content once, so that it can be reused for every render.
pub type PreRendered {
PreRendered(tags: Element(Nil), archives: Element(Nil))
}
pub fn generate(db: Database, config: Configuration) {
let pre_rendered = pre_render(db, config, tags.view, archives.view)
fn(inner: Element(Nil), extra_meta: List(Element(Nil)), title_prefix: String) {
view(db, config, pre_rendered, inner, extra_meta, title_prefix)
}
}
/// Pre-render the tag and archive elements using the given tags and archives
/// components.
pub fn pre_render(
db: Database,
config: Configuration,
tags: fn(Database, Configuration) -> Element(Nil),
archives: fn(Database, Configuration) -> Element(Nil),
) -> PreRendered {
PreRendered(tags: tags(db, config), archives: archives(db, config))
}
fn view(
db: Database,
config: Configuration,
pre_rendered: PreRendered,
inner: Element(Nil),
extra_meta: List(Element(Nil)),
title_prefix: String,
) {
let title_text = case title_prefix {
"" -> config.blog_name
prefix -> prefix <> " · " <> config.blog_name
}
html([attribute("lang", config.l10n.language)], [
head([], [
meta([attribute("charset", "utf-8")]),
meta([
name("viewport"),
attribute("content", "width=device-width, initial-scale=1"),
]),
title([], title_text),
link([href(config.paths.root <> "/css/normalize.css"), rel("stylesheet")]),
link([href(config.paths.root <> "/css/magick.css"), rel("stylesheet")]),
link([href(config.paths.root <> "/css/custom.css"), rel("stylesheet")]),
link([
href(config.paths.root <> config.paths.feed),
rel("alternate"),
type_("application/atom+xml"),
]),
case config.author.url {
option.Some(url) -> link([rel("me"), href(url)])
_ -> element.none()
},
..extra_meta
]),
body([], [
header([id("title"), role("banner")], [
h1([], [
a([href(config.paths.html(config.paths.root <> config.paths.index))], [
text(config.blog_name),
]),
]),
case database.menu(db) {
[] -> element.none()
m -> menu(m)
},
]),
main([], [inner]),
section([id("sidebar")], [
case dict.size(database.tags(db)) {
0 -> element.none()
_ ->
nav(
[
id("tags"),
attribute("aria-label", g_(config.l10n.context, "Tags")),
],
[pre_rendered.tags],
)
},
nav(
[
id("archives"),
attribute("aria-label", g_(config.l10n.context, "Archives")),
],
[pre_rendered.archives],
),
]),
footer([], [
p([], [
text(config.rendering.copyright),
text(" · "),
text("Powered by: "),
a([href("https://gleam.run/")], [text("Gleam")]),
text(", "),
a([href("https://hexdocs.pm/lustre")], [text("Lustre")]),
text(", "),
a([href("https://gitlab.com/Nicd/scriptorium")], [text("Scriptorium")]),
]),
]),
]),
])
}
fn menu(menu: List(MenuItem)) {
nav([], [
ul(
[],
list.map(menu, fn(item) {
li([], [a([href(item.url)], [text(item.name)])])
}),
),
])
}