# HTML Compile
A template engine for generating HTML strings within Rust
for use with static websites.
HTML strings can be generated by inputting a concise syntax into provided macros or, alternatively, from Rust structs.
This engine prioritizes speed and should only be used with trusted HTML data.
## Generating HTML using Macros
A complete example is provided on GitHub in the directory [example](https://github.com/apburnie/html_compile/tree/main/example). The below provides an explanation of different aspects of the syntax.
The syntax used is inspired by [pug.js](https://pugjs.org) but has been adapted to better fit use within a Rust context.
### Creating a Text Element
#### Using a String Literal
```
html!(div (style = "border: 1px solid black;" class = "Hello") "Hello World");
```
Will create the following string of HTML that consists of a `div` with a `style` attribute that creates a black border, a `class` attribute set to `Hello` and text set to `"Hello World"`
```
"
Hello World
"
```
The first token (here `div`) specifies the name of the element.
The set of parentheses `()` contains the attributes for the element. The attribute name comes before the `=` and the attribute value after and is in double quotation marks. Different attributes are separated by whitespace.
The text in double quotation marks at the end of the content specifies the text content `"Hello World"`.
#### Using a Variable
The text can also be derived from a variable. In this case surround the variable with curly brackets `{}`
```
let example_text = "Hello World";
html!(div (style = "border: 1px solid black;" class = "Hello") {example_text});
```
gives the same result as before:
```
"div style=\"border: 1px solid black;\" class=\"Hello\">Hello World"
```
### Creating an Element with No Attributes or Content
Both `html!(div)` and `html!(div ())` will create a string of HTML consisting of an empty div with no styling
```
""
```
Void elements should not have end tags and this is handled accordingly. For example `html!(hr)` will return `"
"`
### Creating Elements that Contain other Elements
```
html!(ul () [el!(li () "First Sibling")] [el!(li () "Second Sibling")])
```
Will create the following string of HTML that consists of an unordered list with two items
```
"- First Sibling
- Second Sibling
"
```
In the browser this renders as
- First Sibling
- Second Sibling
Each child component is surrounded by square brackets `[]` and is inputted into the macro `el!` which creates the component. Multiple specified child components are treated as siblings.
The result from `el!(li () "Second Sibling")` could have been stored in a variable and the variable used instead as follows:
```
let second_sibling = el!(li () "Second Sibling");
let result = html!(ul()[el!(li () "First Sibling")][second_sibling]);
```
This would return the same HTML String.
### Where Child Elements are Specified through a Vector or an Array
```
let example_list = [
el!(li () "First Sibling"),
el!(li () "Second Sibling")
];
html!(ul () vec[example_list])
```
Will create the following string of HTML that consists of an unordered list with two items
```
"- First Sibling
- Second Sibling
"
```
In the browser this renders as
- First Sibling
- Second Sibling
Inserting the text `vec` before the square brackets `[]` tells the macro to expect a vector or array.
## Generating HTML using Rust structs
This library also provides tooling that enables generating HTML strings from Rust structs using the function `build_component()`.
```
use std::fs;
fn main() {
use html_compile::compile::*;
use html_compile::types::*;
let item_list: Vec = vec![1, 2, 3].iter().map(|x| format!("{}", x)).collect();
let item_components: Vec> = item_list
.iter()
.map(|item| {
Box::new(Component {
tag: "li",
meta: None,
child: Child::Text(item),
})
})
.collect();
let input_component = Component {
tag: "section",
meta: Some(vec![
Attribute {
label: "class",
value: "Example",
},
]),
child: Child::ComponentVec(vec![
Box::new(Component {
tag: "h2",
meta: None,
child: Child::Text("A List of Items"),
}),
Box::new(Component {
tag: "p",
meta: None,
child: Child::Text("The list begins after the following line"),
}),
Box::new(Component {
tag: "hr",
meta: None,
child: Child::NoChild,
}),
Box::new(Component {
tag: "ul",
meta: None,
child: Child::ComponentVec(item_components),
}),
]),
};
let output = build_component(&input_component);
let write_output_path = "./output.html";
fs::write(write_output_path, output).expect("Unable to write to file");
}
```
The file `output.html` looks like the following:
```
A List of Items
The list begins after the following line
```
This will render in the browser as follows:
A List of Items
The list begins after the following line
## Inserting HTML into existing HTML string
html_compile provides a macro `insert_html!` and function `insert_components` that searches for the placeholder string `{COMPONENT}` and switches this for the HTML string generated.
#### macro
```
insert_html!({test_contents}, div () "Hello World")
```
#### function
```
let test_component: Component = Component {
tag: "div",
meta: None,
child: Child::Text("Hello World"),
};
insert_components(test_contents, test_component)
```
Both search the `String` in the variable `test_contents` for the placeholder `{COMPONENT}` and swap the placeholder for `Hello World
`.
## Find in crates.io
* https://crates.io/crates/html_compile
## Find code on GitHub
* https://github.com/apburnie/html_compile
Note that in the code on GitHub there is a directory `example` that provides an example application using this library.