import gleam/int import gleam/option.{type Option} import lustre/attribute as attr import lustre/element import lustre/element/html import tom import website/style pub type Post(a) { Post( id: String, title: String, author: String, date_posted: tom.Date, summary: String, content: element.Element(a), ) } pub type Link { Link(title: String, url: String, img: String) } pub type Project(a) { Project( id: String, title: String, author: String, img: String, links: List(Link), archived: Bool, summary: String, content: element.Element(a), ) } pub type Anime { Anime(title: String, link: Option(String), thoughts: Option(String)) } pub fn wrapper( page: String, elements: List(element.Element(a)), ) -> element.Element(a) { html.html([attr.attribute("lang", "en"), style.background_color()], [ html.head([], [ html.meta([attr.attribute("charset", "UTF-8")]), html.title([], page <> " | Naomi Roberts"), html.link([attr.rel("preconnect"), attr.href("https://fonts.bunny.net")]), html.link([ attr.rel("stylesheet"), attr.href("https://fonts.bunny.net/css?family=almarai:400"), ]), ]), style.body_query(), html.body([attr.class("body-margin"), style.body_styles()], [ navbar(), html.div([attr.style("margin", "1em")], elements), ]), html.footer([style.footer()], [ html.hr([attr.style("color", "lightgrey")]), html.p([], [ html.text("The source code for this website is available "), link([], "here", "https://codeberg.org/naomi/website", True), html.text(" or "), link([], "here", "https://tangled.sh/@lesbian.skin/website", True), html.text(" under the "), link( [], "BSD 3 with Attribution", "https://spdx.org/licenses/BSD-3-Clause-Attribution", True, ), html.text(" license."), ]), html.p([], [ html.text("If you wish to get in contact, please send an email to "), link([], "mia@naomieow.xyz", "mailto:mia@naomieow.xyz", True), html.text(", or contact me on "), link([], "Discord", "https://chat.lesbian.skin", True), html.text("."), ]), ]), ]) } pub fn navbar() -> element.Element(a) { html.div([style.navbar()], [ navitem(name: "home", href: "/", external: False), navitem(name: "projects", href: "/projects", external: False), navitem(name: "posts", href: "/posts", external: False), navitem( name: "anime", href: "https://anilist.co/user/naomieow/", external: True, ), html.div([style.navbar_right()], [icon_link(Bluesky), icon_link(Tangled)]), ]) } fn navitem( name text: String, href href: String, external external: Bool, ) -> element.Element(a) { link([style.navitem()], text:, href:, external:) } pub type Icon { Bluesky Tangled } pub fn icon_link(icon icon: Icon) -> element.Element(a) { let #(href, img) = case icon { Bluesky -> #("https://bsky.app/profile/lesbian.skin", "/assets/bsky.svg") Tangled -> #("https://tangled.sh/@lesbian.skin", "/assets/git.svg") } html.a([attr.href(href), style.link_icon()], [ html.img([attr.src(img), style.icon_size()]), ]) } pub fn link( attributes attributes: List(attr.Attribute(a)), text text: String, href href: String, external external: Bool, ) -> element.Element(a) { let attrs = [attr.href(href), style.link(), ..attributes] html.a( case external { False -> attrs True -> [ attr.target("_blank"), attr.rel("noopener noreferrer"), attr.style("display", "inline-block"), ..attrs ] }, [ element.text(text), // Seems to cause some DOM issues? // in some places it appears `text

// but in other places it's `

text

` // case external { // True -> // html.p( // [ // attr.styles([ // #("display", "inline-block"), // #("font-size", "0.75em"), // #("margin", "0"), // #("vertical-align", "top"), // ]), // ], // [element.text("↗")], // ) // False -> element.none() // }, ], ) } pub fn raw_link( attributes attributes: List(attr.Attribute(a)), content content: List(element.Element(a)), href href: String, external external: Bool, ) -> element.Element(a) { let attrs = [attr.href(href), style.link(), ..attributes] html.a( case external { False -> attrs True -> [ attr.target("_blank"), attr.rel("noopener noreferrer"), attr.style("display", "inline-block"), ..attrs ] }, content, ) } pub fn warning(title: String, contents: String) -> element.Element(a) { html.div([], [ html.h3([], [element.text(title)]), html.p([], [element.text(contents)]), ]) } pub fn date_to_string(date: tom.Date) -> String { date.day |> int.to_string() <> "/" <> date.month |> int.to_string() <> "/" <> date.year |> int.to_string() }