Render products page
This commit is contained in:
parent
3928f50be5
commit
1a1a5a3451
122
src/html.rs
122
src/html.rs
|
@ -1,3 +1,5 @@
|
||||||
|
use crate::database::read_all_products;
|
||||||
|
use crate::structures::{Product, ProductClass};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::io::{Read, Write};
|
use std::io::{Read, Write};
|
||||||
use std::sync::atomic::{AtomicBool, Ordering};
|
use std::sync::atomic::{AtomicBool, Ordering};
|
||||||
|
@ -39,7 +41,14 @@ struct Page {
|
||||||
title: String,
|
title: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn render_pages() {
|
struct PageBase {
|
||||||
|
config: Config,
|
||||||
|
tera: Tera,
|
||||||
|
nav_elements: Vec<NavLink>,
|
||||||
|
product_classes: Vec<NavLink>,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn build_base() -> PageBase {
|
||||||
// Read in TOML
|
// Read in TOML
|
||||||
let mut config_file = std::fs::File::open("config.toml").unwrap();
|
let mut config_file = std::fs::File::open("config.toml").unwrap();
|
||||||
let mut contents = String::new();
|
let mut contents = String::new();
|
||||||
|
@ -58,22 +67,22 @@ pub fn render_pages() {
|
||||||
|
|
||||||
// Setup basic elements
|
// Setup basic elements
|
||||||
let nav_home = NavLink {
|
let nav_home = NavLink {
|
||||||
href: config.index.href,
|
href: config.index.href.clone(),
|
||||||
text: config.index.label.clone(),
|
text: config.index.label.clone(),
|
||||||
active: AtomicBool::new(true),
|
active: AtomicBool::new(true),
|
||||||
};
|
};
|
||||||
let nav_about = NavLink {
|
let nav_about = NavLink {
|
||||||
href: config.about.href,
|
href: config.about.href.clone(),
|
||||||
text: config.about.label.clone(),
|
text: config.about.label.clone(),
|
||||||
active: AtomicBool::new(false),
|
active: AtomicBool::new(false),
|
||||||
};
|
};
|
||||||
let nav_products = NavLink {
|
let nav_products = NavLink {
|
||||||
href: config.products.href,
|
href: config.products.href.clone(),
|
||||||
text: config.products.label.clone(),
|
text: config.products.label.clone(),
|
||||||
active: AtomicBool::new(false),
|
active: AtomicBool::new(false),
|
||||||
};
|
};
|
||||||
let nav_contact = NavLink {
|
let nav_contact = NavLink {
|
||||||
href: config.contact.href,
|
href: config.contact.href.clone(),
|
||||||
text: config.contact.label.clone(),
|
text: config.contact.label.clone(),
|
||||||
active: AtomicBool::new(false),
|
active: AtomicBool::new(false),
|
||||||
};
|
};
|
||||||
|
@ -81,66 +90,99 @@ pub fn render_pages() {
|
||||||
let nav_elements = vec![nav_home, nav_about, nav_products, nav_contact];
|
let nav_elements = vec![nav_home, nav_about, nav_products, nav_contact];
|
||||||
|
|
||||||
let estrogens = NavLink {
|
let estrogens = NavLink {
|
||||||
href: config.products.estrogens.href,
|
href: config.products.estrogens.href.clone(),
|
||||||
text: config.products.estrogens.label.clone(),
|
text: config.products.estrogens.label.clone(),
|
||||||
active: AtomicBool::new(false),
|
active: AtomicBool::new(false),
|
||||||
};
|
};
|
||||||
let aa = NavLink {
|
let aa = NavLink {
|
||||||
href: config.products.anti_androgens.href,
|
href: config.products.anti_androgens.href.clone(),
|
||||||
text: config.products.anti_androgens.label.clone(),
|
text: config.products.anti_androgens.label.clone(),
|
||||||
active: AtomicBool::new(false),
|
active: AtomicBool::new(false),
|
||||||
};
|
};
|
||||||
let progestogens = NavLink {
|
let progestogens = NavLink {
|
||||||
href: config.products.progestogens.href,
|
href: config.products.progestogens.href.clone(),
|
||||||
text: config.products.progestogens.label.clone(),
|
text: config.products.progestogens.label.clone(),
|
||||||
active: AtomicBool::new(false),
|
active: AtomicBool::new(false),
|
||||||
};
|
};
|
||||||
let product_classes = vec![estrogens, aa, progestogens];
|
let product_classes = vec![estrogens, aa, progestogens];
|
||||||
|
|
||||||
|
return PageBase {
|
||||||
|
config,
|
||||||
|
tera,
|
||||||
|
nav_elements,
|
||||||
|
product_classes,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
pub fn render_pages() {
|
||||||
|
let base = build_base();
|
||||||
// Render pages
|
// Render pages
|
||||||
let index_render = RenderObject {
|
let index_render = RenderObject {
|
||||||
url: "index.html".to_string(),
|
url: "index.html".to_string(),
|
||||||
tera: tera.clone(),
|
tera: base.tera.clone(),
|
||||||
subtitle: &config.index.title,
|
subtitle: &base.config.index.title,
|
||||||
active_page: &config.index.label,
|
active_page: &base.config.index.label,
|
||||||
title: &config.title,
|
title: &base.config.title,
|
||||||
description: &config.description,
|
description: &base.config.description,
|
||||||
|
products: None,
|
||||||
};
|
};
|
||||||
render_page(
|
render_page(
|
||||||
// Home
|
// Home
|
||||||
index_render,
|
index_render,
|
||||||
&nav_elements,
|
&base.nav_elements,
|
||||||
&product_classes,
|
&base.product_classes,
|
||||||
);
|
);
|
||||||
|
|
||||||
let about_render = RenderObject {
|
let about_render = RenderObject {
|
||||||
url: "about/index.html".to_string(),
|
url: "about/index.html".to_string(),
|
||||||
tera: tera.clone(),
|
tera: base.tera.clone(),
|
||||||
subtitle: &config.about.title,
|
subtitle: &base.config.about.title,
|
||||||
active_page: &config.about.label,
|
active_page: &base.config.about.label,
|
||||||
title: &config.title,
|
title: &base.config.title,
|
||||||
description: &config.description,
|
description: &base.config.description,
|
||||||
|
products: None,
|
||||||
};
|
};
|
||||||
render_page(
|
render_page(
|
||||||
// About
|
// About
|
||||||
about_render,
|
about_render,
|
||||||
&nav_elements,
|
&base.nav_elements,
|
||||||
&product_classes,
|
&base.product_classes,
|
||||||
);
|
);
|
||||||
|
|
||||||
let contact_render = RenderObject {
|
let contact_render = RenderObject {
|
||||||
url: "contact/index.html".to_string(),
|
url: "contact/index.html".to_string(),
|
||||||
tera: tera.clone(),
|
tera: base.tera.clone(),
|
||||||
subtitle: &config.contact.title,
|
subtitle: &base.config.contact.title,
|
||||||
active_page: &config.contact.label,
|
active_page: &base.config.contact.label,
|
||||||
title: &config.title,
|
title: &base.config.title,
|
||||||
description: &config.description,
|
description: &base.config.description,
|
||||||
|
products: None,
|
||||||
};
|
};
|
||||||
render_page(
|
render_page(
|
||||||
// About
|
// About
|
||||||
contact_render,
|
contact_render,
|
||||||
&nav_elements,
|
&base.nav_elements,
|
||||||
&product_classes,
|
&base.product_classes,
|
||||||
|
);
|
||||||
|
|
||||||
|
let products_vec: Option<Vec<Product>>;
|
||||||
|
match read_all_products() {
|
||||||
|
Ok(prods) => products_vec = Some(prods),
|
||||||
|
Err(err) => products_vec = None,
|
||||||
|
}
|
||||||
|
let products_render = RenderObject {
|
||||||
|
url: "products/index.html".to_string(),
|
||||||
|
tera: base.tera.clone(),
|
||||||
|
subtitle: &base.config.products.title,
|
||||||
|
active_page: &base.config.products.label,
|
||||||
|
title: &base.config.title,
|
||||||
|
description: &base.config.description,
|
||||||
|
products: products_vec,
|
||||||
|
};
|
||||||
|
render_page(
|
||||||
|
// Products
|
||||||
|
products_render,
|
||||||
|
&base.nav_elements,
|
||||||
|
&base.product_classes,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -151,12 +193,14 @@ struct RenderObject<'a> {
|
||||||
active_page: &'a str,
|
active_page: &'a str,
|
||||||
title: &'a str,
|
title: &'a str,
|
||||||
description: &'a str,
|
description: &'a str,
|
||||||
|
products: Option<Vec<Product>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render_page(data: RenderObject, nav_elements: &[NavLink], product_classes: &[NavLink]) {
|
fn render_page(data: RenderObject, nav_elements: &[NavLink], product_classes: &[NavLink]) {
|
||||||
let mut output_file =
|
let mut output_file =
|
||||||
std::fs::File::create(format!("static/{}", data.url)).expect("create failed");
|
std::fs::File::create(format!("static/{}", data.url)).expect("create failed");
|
||||||
|
|
||||||
|
// Change the active NavLink
|
||||||
for i in nav_elements {
|
for i in nav_elements {
|
||||||
if i.text == data.active_page {
|
if i.text == data.active_page {
|
||||||
i.active.store(true, Ordering::Relaxed);
|
i.active.store(true, Ordering::Relaxed);
|
||||||
|
@ -165,10 +209,12 @@ fn render_page(data: RenderObject, nav_elements: &[NavLink], product_classes: &[
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Create the context
|
||||||
let mut context = Context::new();
|
let mut context = Context::new();
|
||||||
context.insert("title", data.title);
|
context.insert("title", data.title);
|
||||||
context.insert("description", data.description);
|
context.insert("description", data.description);
|
||||||
context.insert("subtitle", &data.subtitle);
|
context.insert("subtitle", &data.subtitle);
|
||||||
|
// Insert navigation elements
|
||||||
for i in nav_elements {
|
for i in nav_elements {
|
||||||
context.insert(&i.text.to_ascii_lowercase(), &i);
|
context.insert(&i.text.to_ascii_lowercase(), &i);
|
||||||
}
|
}
|
||||||
|
@ -178,7 +224,25 @@ fn render_page(data: RenderObject, nav_elements: &[NavLink], product_classes: &[
|
||||||
} else {
|
} else {
|
||||||
context.insert("is_contact", &false);
|
context.insert("is_contact", &false);
|
||||||
}
|
}
|
||||||
|
// Fill out products page
|
||||||
|
match data.products {
|
||||||
|
None => info!("no product"),
|
||||||
|
Some(p) => {
|
||||||
|
let mut estrogens = Vec::new();
|
||||||
|
let mut anti_androgens = Vec::new();
|
||||||
|
for i in p {
|
||||||
|
match i.class {
|
||||||
|
ProductClass::Estrogens => estrogens.push(i),
|
||||||
|
ProductClass::AntiAndrogens => anti_androgens.push(i),
|
||||||
|
ProductClass::Progestogens => todo!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
context.insert("estrogens", &estrogens);
|
||||||
|
context.insert("anti_androgens", &anti_androgens);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write it to the file
|
||||||
output_file
|
output_file
|
||||||
.write_all(data.tera.render(&data.url, &context).unwrap().as_bytes())
|
.write_all(data.tera.render(&data.url, &context).unwrap().as_bytes())
|
||||||
.expect("write failed");
|
.expect("write failed");
|
||||||
|
|
|
@ -0,0 +1,76 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
{# head content #}
|
||||||
|
<title>{{ title }}</title>
|
||||||
|
|
||||||
|
<!-- css style -->
|
||||||
|
<link rel="preload" href="/style.css" as="style">
|
||||||
|
<link rel="stylesheet" href="/style.css">
|
||||||
|
|
||||||
|
<!-- metadata -->
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="description" content="{{ description }}">
|
||||||
|
|
||||||
|
<!-- link preview card -->
|
||||||
|
<meta name="og:title" content="{{ title }}">
|
||||||
|
<meta name="twitter:title" content="{{ title }}">
|
||||||
|
|
||||||
|
<meta name="og:description" content="{{ description }}">
|
||||||
|
<meta name="twitter:description" content="{{ description }}">
|
||||||
|
|
||||||
|
<!-- display settings & favicon -->
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<link rel="icon" href="/assets/pill.svg">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>{{ title }}</h1>
|
||||||
|
|
||||||
|
{# Navigation #}
|
||||||
|
<nav class="menu">
|
||||||
|
<ul>
|
||||||
|
<li><a {% if home.active %}class="active"{% endif %} href="{{ home.href }}">{{ home.text }}</a></li>
|
||||||
|
<li><a {% if about.active %}class="active"{% endif %} href="{{ about.href }}">{{ about.text }}</a></li>
|
||||||
|
<li class="dropdown">
|
||||||
|
<a {% if products.active %}class="active"{% endif %} href="{{ products.href }}" class="dropbtn">{{ products.text }}</a>
|
||||||
|
<div class="dropdown-content">
|
||||||
|
{% for product in product_classes %}
|
||||||
|
<a href="{{product.href}}">{{product.text}}</a>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
<li><a {% if contact.active %}class="active"{% endif %} href="{{ contact.href }}">{{ contact.text }}</a></li>
|
||||||
|
</ul>
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
<h2>{{ subtitle }}</h2>
|
||||||
|
|
||||||
|
{# articles #}
|
||||||
|
{% if estrogens %}
|
||||||
|
<h3 id="estrogens">Estrogens</h3>
|
||||||
|
<div class="images">
|
||||||
|
{% for product in estrogens %}
|
||||||
|
<div class="gallery">
|
||||||
|
<a target="_blank" href="/products/{{product.short_name}}">
|
||||||
|
<img src="/assets/products/{{product.short_name}}.webp" width="600" height="400">
|
||||||
|
</a>
|
||||||
|
<div class="desc">{{ product.full_name }}</div>
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if anti_androgens %}
|
||||||
|
<h3 id="anti_androgens">Anti-Androgens</h3>
|
||||||
|
<div class="images">
|
||||||
|
{% for product in anti_androgens %}
|
||||||
|
<div class="gallery">
|
||||||
|
<a target="_blank" href="/products/{{product.short_name}}">
|
||||||
|
<img src="/assets/products/{{product.short_name}}.webp" width="600" height="400">
|
||||||
|
</a>
|
||||||
|
<div class="desc">{{ product.full_name }}</div>
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
</html>
|
Loading…
Reference in New Issue