Pour tout problème contactez-nous par mail : support@froggit.fr | La FAQ :grey_question: | Rejoignez-nous sur le Chat :speech_balloon:

Skip to content
Snippets Groups Projects
Commit 2e57f968 authored by peterrabbit's avatar peterrabbit
Browse files

website build pages

parent 515b638a
No related branches found
No related tags found
No related merge requests found
......@@ -7,7 +7,8 @@
"image": "https://pijar.com/static/images/pijar_pic.png",
"css": [],
"js": [],
"url_slug": ""
"url_slug": "",
"lang": "en"
},
"body": [
{
......
use super::page::Page;
use regex::{Captures, Regex};
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
pub const CSS_LINK_FRAGMENT: &'static str = "<link rel='stylesheet' href='{url}'>";
pub const SCRIPT_FRAGMENT: &'static str = "<script src='{url}'></script>";
const HTML_DOC_TEMPLATE: &'static str = "
<html lang='{lang}'>
<head>
<meta charset='UTF-8'>
<meta http-equiv='X-UA-Compatible' content='IE=edge'>
<meta name='viewport' content='width=device-width, initial-scale=1.0'>
<meta name='description' content='{description}'>
<title>{title}</title>
{css}
</head>
<body>
{body}
</body>
{js}
</html>
";
pub fn replace_placeholders(template: &str, map: HashMap<String, String>) -> String {
let re = Regex::new(r#"\{[a-z]+\}"#).unwrap();
let def = String::new();
re.replace_all(template, |captures: &Captures| {
let placeholder = captures.iter().next().unwrap().unwrap().as_str();
let placeholder = placeholder[1..placeholder.len() - 1].to_owned(); // strip the brackets
match map.get(&placeholder) {
Some(s) => s,
None => &def,
}
})
.to_string()
}
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct HtmlDoc(String);
impl HtmlDoc {
pub fn from_page(page: &Page) -> Self {
HtmlDoc(replace_placeholders(HTML_DOC_TEMPLATE, page.to_map()))
}
pub fn new() -> Self {
HtmlDoc(String::new())
}
}
impl std::fmt::Display for HtmlDoc {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "{}", self.0)
}
}
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct HtmlAttributes(pub HashMap<String, String>);
......@@ -48,7 +106,7 @@ impl std::fmt::Display for HtmlElement {
let body = match &self.contents {
Some(contents) => contents
.iter()
.map(|item| item.to_string())
.map(|el| el.to_string())
.collect::<Vec<String>>()
.join(""),
None => match &self.text {
......@@ -62,39 +120,39 @@ impl std::fmt::Display for HtmlElement {
}
#[cfg(test)]
mod test_items {
mod test_html_elements {
use super::*;
#[test]
fn text_item_content_to_string() {
let item_content = HtmlElement {
fn text_html_element_to_string() {
let html_el = HtmlElement {
tag: String::from("p"),
text: Some(String::from("Hello")),
contents: None,
attrs: HtmlAttributes::new(),
};
assert_eq!(item_content.to_string(), "<p>Hello</p>")
assert_eq!(html_el.to_string(), "<p>Hello</p>")
}
#[test]
fn item_content_with_attrs_to_string() {
fn html_el_with_attrs_to_string() {
let mut attrs = HtmlAttributes::new();
attrs.0.insert(String::from("id"), String::from("some-id"));
let item_content = HtmlElement {
let html_el = HtmlElement {
tag: String::from("p"),
text: Some(String::from("Hello")),
contents: None,
attrs: attrs.clone(),
};
assert_eq!(item_content.to_string(), "<p id=\"some-id\">Hello</p>");
assert_eq!(html_el.to_string(), "<p id=\"some-id\">Hello</p>");
}
#[test]
fn complex_item_content_to_string() {
let item_content = HtmlElement {
fn complex_html_el_to_string() {
let html_el = HtmlElement {
tag: String::from("p"),
text: None,
attrs: HtmlAttributes::new(),
......@@ -115,7 +173,7 @@ mod test_items {
};
assert_eq!(
item_content.to_string(),
html_el.to_string(),
"<p><span>Hello </span><b>World</b></p>"
)
}
......
use super::page::Page;
use regex::{Captures, Regex};
use serde::{Deserialize, Serialize};
// const CSS_LINK_FRAGMENT: &'static str = "<link rel='stylesheet' href='{url}'>";
// const SCRIPT_FRAGMENT: &'static str = "<script src='{url}'></script>";
const HTML_DOC_TEMPLATE: &'static str = "
<html lang='{lang}'>
<head>
<meta charset='UTF-8'>
<meta http-equiv='X-UA-Compatible' content='IE=edge'>
<meta name='viewport' content='width=device-width, initial-scale=1.0'>
<meta name='description' content='{description}'>
<title>{title}</title>
{css}
</head>
<body>
{body}
</body>
{js}
</html>
";
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct HtmlDoc(String);
impl HtmlDoc {
pub fn from_page(page: &Page) -> Self {
let re = Regex::new(r#"\{[a-z]+\}"#).unwrap();
let html = re
.replace_all(HTML_DOC_TEMPLATE, |captures: &Captures| {
let placeholder = captures.iter().next().unwrap().unwrap().as_str();
let placeholder = placeholder[1..placeholder.len() - 1].to_owned(); // strip the brackets
page.text_from_key(placeholder)
})
.to_string();
HtmlDoc(html)
}
pub fn new() -> Self {
HtmlDoc(String::new())
}
}
impl std::fmt::Display for HtmlDoc {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "{}", self.0)
}
}
mod css;
mod html_doc;
mod item;
mod html;
mod page;
mod website;
......
use super::css::StyleSheet;
use super::html_doc::HtmlDoc;
use super::item::*;
use super::html::{replace_placeholders, HtmlDoc, HtmlElement, CSS_LINK_FRAGMENT, SCRIPT_FRAGMENT};
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct Page {
......@@ -46,8 +46,66 @@ pub struct PageMetadata {
pub lang: String,
pub description: String,
pub url_slug: String,
pub css: Vec<String>,
pub js: Vec<String>,
#[serde(default = "CSSLinks::new")]
pub css: CSSLinks,
#[serde(default = "JSLinks::new")]
pub js: JSLinks,
}
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct CSSLinks(Vec<String>);
impl CSSLinks {
pub fn new() -> Self {
CSSLinks(vec!["/static/default/style.css".to_owned()])
}
}
impl std::fmt::Display for CSSLinks {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(
f,
"{}",
&self
.0
.iter()
.map(|url| replace_placeholders(CSS_LINK_FRAGMENT, {
let mut map = HashMap::new();
map.insert("url".to_string(), url.to_owned());
map
}))
.collect::<Vec<String>>()
.join("")
)
}
}
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct JSLinks(Vec<String>);
impl JSLinks {
pub fn new() -> Self {
JSLinks(vec!["/static/default/script.js".to_owned()])
}
}
impl std::fmt::Display for JSLinks {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(
f,
"{}",
&self
.0
.iter()
.map(|url| replace_placeholders(SCRIPT_FRAGMENT, {
let mut map = HashMap::new();
map.insert("url".to_string(), url.to_owned());
map
}))
.collect::<Vec<String>>()
.join("")
)
}
}
impl Page {
......@@ -56,28 +114,35 @@ impl Page {
}
pub fn build_body_template(&mut self, template: PageTemplate) {
let mut body = template.clone();
let mut complete_body = template.clone();
self.template = Some(template);
let err = "Couldn't find page-body placeholder";
body.contents
// Insert page body inside the template page-body container.
// Then replace the page body by the complete template
complete_body
.contents
.iter_mut()
.find(|el| el.attrs.get("id").unwrap_or(&String::new()).eq("page-body"))
.expect(err)
.set_contents(self.body.0.clone());
self.body.0 = body.contents;
self.body.0 = complete_body.contents;
}
pub fn text_from_key(&self, key: String) -> String {
match &key[..] {
"title" => self.metadata.title.to_owned(),
"lang" => self.metadata.lang.to_owned(),
"description" => self.metadata.description.to_owned(),
"slug" => self.metadata.url_slug.to_owned(),
"body" => self.body.to_string(),
// "css" => self.css.as_ref().unwrap_or(&String::new()).to_owned(),
// "js" => self.js.as_ref().unwrap_or(&String::new()).to_owned(),
_ => String::new(),
}
pub fn to_map(&self) -> HashMap<String, String> {
let mut map = HashMap::new();
map.insert("title".to_string(), self.metadata.title.to_owned());
map.insert("lang".to_string(), self.metadata.lang.to_owned());
map.insert(
"description".to_string(),
self.metadata.description.to_owned(),
);
map.insert("slug".to_string(), self.metadata.url_slug.to_owned());
map.insert("body".to_string(), self.body.to_string());
map.insert("css".to_string(), self.metadata.css.to_string());
map.insert("js".to_string(), self.metadata.js.to_string());
map
}
}
......@@ -7,6 +7,7 @@ use std::path::PathBuf;
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct WebSite {
root_page: Page,
#[serde(default = "AssetsIndex::new")]
assets_index: AssetsIndex,
templates: Vec<PageTemplate>,
#[serde(default = "HashMap::new")]
......@@ -22,12 +23,22 @@ pub struct AssetsIndex {
pub source_code: Vec<String>,
}
impl AssetsIndex {
pub fn new() -> Self {
AssetsIndex {
images: Vec::new(),
sounds: Vec::new(),
videos: Vec::new(),
docs: Vec::new(),
source_code: Vec::new(),
}
}
}
impl WebSite {
pub fn from_json(json: &str) -> Self {
let mut obj: Self = serde_json::from_str(json).unwrap();
obj.build_assets_index();
obj.build_pages_index(obj.root_page.clone(), PathBuf::from("/"));
obj.root_page.build_html();
let mut obj: WebSite = serde_json::from_str(json).unwrap();
obj.root_page.build_body_template(
obj.templates
.iter()
......@@ -35,8 +46,10 @@ impl WebSite {
.expect("Page template not found")
.clone(),
);
obj.root_page.build_html();
for p in obj.root_page.sub_pages.iter_mut() {
p.build_html();
p.build_body_template(
obj.templates
.iter()
......@@ -44,7 +57,12 @@ impl WebSite {
.expect("Page template not found")
.clone(),
);
p.build_html();
}
obj.build_assets_index();
obj.build_pages_index(obj.root_page.clone(), PathBuf::from("/"));
obj
}
......
......@@ -5,9 +5,8 @@
"title": "New Website",
"description": "A new website",
"image": "",
"css": [],
"js": [],
"url_slug": ""
"url_slug": "",
"lang": "en"
},
"body": [
{
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment