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 std::io::{Read, Write};
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
|
@ -39,7 +41,14 @@ struct Page {
|
|||
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
|
||||
let mut config_file = std::fs::File::open("config.toml").unwrap();
|
||||
let mut contents = String::new();
|
||||
|
@ -58,22 +67,22 @@ pub fn render_pages() {
|
|||
|
||||
// Setup basic elements
|
||||
let nav_home = NavLink {
|
||||
href: config.index.href,
|
||||
href: config.index.href.clone(),
|
||||
text: config.index.label.clone(),
|
||||
active: AtomicBool::new(true),
|
||||
};
|
||||
let nav_about = NavLink {
|
||||
href: config.about.href,
|
||||
href: config.about.href.clone(),
|
||||
text: config.about.label.clone(),
|
||||
active: AtomicBool::new(false),
|
||||
};
|
||||
let nav_products = NavLink {
|
||||
href: config.products.href,
|
||||
href: config.products.href.clone(),
|
||||
text: config.products.label.clone(),
|
||||
active: AtomicBool::new(false),
|
||||
};
|
||||
let nav_contact = NavLink {
|
||||
href: config.contact.href,
|
||||
href: config.contact.href.clone(),
|
||||
text: config.contact.label.clone(),
|
||||
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 estrogens = NavLink {
|
||||
href: config.products.estrogens.href,
|
||||
href: config.products.estrogens.href.clone(),
|
||||
text: config.products.estrogens.label.clone(),
|
||||
active: AtomicBool::new(false),
|
||||
};
|
||||
let aa = NavLink {
|
||||
href: config.products.anti_androgens.href,
|
||||
href: config.products.anti_androgens.href.clone(),
|
||||
text: config.products.anti_androgens.label.clone(),
|
||||
active: AtomicBool::new(false),
|
||||
};
|
||||
let progestogens = NavLink {
|
||||
href: config.products.progestogens.href,
|
||||
href: config.products.progestogens.href.clone(),
|
||||
text: config.products.progestogens.label.clone(),
|
||||
active: AtomicBool::new(false),
|
||||
};
|
||||
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
|
||||
let index_render = RenderObject {
|
||||
url: "index.html".to_string(),
|
||||
tera: tera.clone(),
|
||||
subtitle: &config.index.title,
|
||||
active_page: &config.index.label,
|
||||
title: &config.title,
|
||||
description: &config.description,
|
||||
tera: base.tera.clone(),
|
||||
subtitle: &base.config.index.title,
|
||||
active_page: &base.config.index.label,
|
||||
title: &base.config.title,
|
||||
description: &base.config.description,
|
||||
products: None,
|
||||
};
|
||||
render_page(
|
||||
// Home
|
||||
index_render,
|
||||
&nav_elements,
|
||||
&product_classes,
|
||||
&base.nav_elements,
|
||||
&base.product_classes,
|
||||
);
|
||||
|
||||
let about_render = RenderObject {
|
||||
url: "about/index.html".to_string(),
|
||||
tera: tera.clone(),
|
||||
subtitle: &config.about.title,
|
||||
active_page: &config.about.label,
|
||||
title: &config.title,
|
||||
description: &config.description,
|
||||
tera: base.tera.clone(),
|
||||
subtitle: &base.config.about.title,
|
||||
active_page: &base.config.about.label,
|
||||
title: &base.config.title,
|
||||
description: &base.config.description,
|
||||
products: None,
|
||||
};
|
||||
render_page(
|
||||
// About
|
||||
about_render,
|
||||
&nav_elements,
|
||||
&product_classes,
|
||||
&base.nav_elements,
|
||||
&base.product_classes,
|
||||
);
|
||||
|
||||
let contact_render = RenderObject {
|
||||
url: "contact/index.html".to_string(),
|
||||
tera: tera.clone(),
|
||||
subtitle: &config.contact.title,
|
||||
active_page: &config.contact.label,
|
||||
title: &config.title,
|
||||
description: &config.description,
|
||||
tera: base.tera.clone(),
|
||||
subtitle: &base.config.contact.title,
|
||||
active_page: &base.config.contact.label,
|
||||
title: &base.config.title,
|
||||
description: &base.config.description,
|
||||
products: None,
|
||||
};
|
||||
render_page(
|
||||
// About
|
||||
contact_render,
|
||||
&nav_elements,
|
||||
&product_classes,
|
||||
&base.nav_elements,
|
||||
&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,
|
||||
title: &'a str,
|
||||
description: &'a str,
|
||||
products: Option<Vec<Product>>,
|
||||
}
|
||||
|
||||
fn render_page(data: RenderObject, nav_elements: &[NavLink], product_classes: &[NavLink]) {
|
||||
let mut output_file =
|
||||
std::fs::File::create(format!("static/{}", data.url)).expect("create failed");
|
||||
|
||||
// Change the active NavLink
|
||||
for i in nav_elements {
|
||||
if i.text == data.active_page {
|
||||
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();
|
||||
context.insert("title", data.title);
|
||||
context.insert("description", data.description);
|
||||
context.insert("subtitle", &data.subtitle);
|
||||
// Insert navigation elements
|
||||
for i in nav_elements {
|
||||
context.insert(&i.text.to_ascii_lowercase(), &i);
|
||||
}
|
||||
|
@ -178,7 +224,25 @@ fn render_page(data: RenderObject, nav_elements: &[NavLink], product_classes: &[
|
|||
} else {
|
||||
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
|
||||
.write_all(data.tera.render(&data.url, &context).unwrap().as_bytes())
|
||||
.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