Files
aindustries.be/src/html/pages.rs

216 lines
5.2 KiB
Rust

use crate::html::Render;
use crate::html::boxed_vec;
use crate::html::elements::{Anchor, Image, Link, Paragraph};
use crate::html::layouts::Division;
pub(crate) struct Page {
title: String,
head: Vec<Box<dyn Render>>,
body: Vec<Box<dyn Render>>,
}
impl Render for Page {
fn render(&self) -> String {
format!(
"\
<!DOCTYPE html>
<html lang=\"en\">
<head>
<meta charset=\"UTF-8\">
<title>{}</title>
<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />
{}
</head>
<body>
{}
</body>
</html>",
self.title,
self.head.render(),
self.body.render()
)
}
}
impl Page {
pub(crate) fn builder() -> PageBuilder {
PageBuilder::new()
}
pub(crate) fn append_element_to_body(&mut self, element: impl Render + 'static) {
self.body.push(Box::new(element));
}
pub(crate) fn append_element_to_head(&mut self, element: impl Render + 'static) {
self.head.push(Box::new(element));
}
}
pub(crate) struct PageBuilder {
title: Option<String>,
head: Option<Vec<Box<dyn Render>>>,
body: Option<Vec<Box<dyn Render>>>,
}
impl PageBuilder {
pub(crate) fn new() -> Self {
Self {
title: None,
head: None,
body: None,
}
}
pub(crate) fn title<T>(self, title: T) -> Self
where
T: Into<String>,
{
Self {
title: Some(title.into()),
..self
}
}
pub(crate) fn head(self, head: Vec<Box<dyn Render>>) -> Self {
Self {
head: Some(head),
..self
}
}
pub(crate) fn body(self, body: Vec<Box<dyn Render>>) -> Self {
Self {
body: Some(body),
..self
}
}
pub(crate) fn build(self) -> Page {
let title = self.title.unwrap_or(String::new());
let head = self.head.unwrap_or(Vec::new());
let body = self.body.unwrap_or(Vec::new());
Page { title, head, body }
}
}
pub(crate) struct BasePage {
page: Page,
}
impl BasePage {
pub(crate) fn builder() -> BasePageBuilder {
BasePageBuilder::new()
}
pub(crate) fn append_element_to_head(&mut self, element: impl Render + 'static) {
self.page.append_element_to_head(element);
}
pub(crate) fn append_element_to_body(&mut self, element: impl Render + 'static) {
self.page.append_element_to_body(element);
}
}
impl Render for BasePage {
fn render(&self) -> String {
self.page.render()
}
}
pub(crate) struct BasePageBuilder {
title: Option<String>,
head: Option<Vec<Box<dyn Render>>>,
body: Option<Vec<Box<dyn Render>>>,
}
impl BasePageBuilder {
pub(crate) fn new() -> Self {
Self {
title: None,
head: None,
body: None,
}
}
pub(crate) fn title<T>(self, title: T) -> Self
where
T: Into<String>,
{
Self {
title: Some(title.into()),
..self
}
}
pub(crate) fn head(self, head: Vec<Box<dyn Render>>) -> Self {
Self {
head: Some(head),
..self
}
}
pub(crate) fn body(self, body: Vec<Box<dyn Render>>) -> Self {
Self {
body: Some(body),
..self
}
}
pub(crate) fn build(self) -> BasePage {
let title = self.title.unwrap_or(String::new());
let head = self.head.unwrap_or(Vec::new());
let body = self.body.unwrap_or(Vec::new());
let name = Paragraph::builder()
.id("name")
.classes(vec!["name"])
.text("AINDUSTRIES")
.build();
let home = Anchor::builder()
.id("home")
.classes(vec!["nav-button"])
.href("/")
.text("Home")
.build();
let projects = Anchor::builder()
.id("projects")
.classes(vec!["nav-button"])
.href("/projects")
.text("Projects")
.build();
let music = Anchor::builder()
.id("music")
.classes(vec!["nav-button"])
.href("/music")
.text("Music")
.build();
let buttons = Division::builder()
.classes(vec!["nav-buttons"])
.elements(boxed_vec![home, projects, music])
.build();
let header = Division::builder()
.id("header")
.classes(vec!["header"])
.elements(boxed_vec![name, buttons])
.build();
// background
let image = Image::builder()
.id("background")
.classes(vec!["background"])
.src("/static/img/background.png")
.build();
// css
let base = Link::builder()
.rel("stylesheet")
.href("/static/css/base.css")
.build();
let mut final_head = boxed_vec![base];
final_head.extend(head);
let mut final_body = boxed_vec![image, header];
final_body.extend(body);
let page = Page::builder()
.title(title)
.head(final_head)
.body(final_body)
.build();
BasePage { page }
}
}