Refactored project to use Builder pattern.
This commit is contained in:
199
src/html/pages.rs
Normal file
199
src/html/pages.rs
Normal file
@@ -0,0 +1,199 @@
|
||||
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 buttons = Division::builder()
|
||||
.classes(vec!["nav-buttons"])
|
||||
.elements(boxed_vec![home, projects])
|
||||
.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 }
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user