# Terrazzo client
Template library to generate dynamic HTML documents.
The template library is usually used in tandem with the `terrazzo-macro` crate.
# The `#[html]` macro
## Basic usage
This macro us used to generate dynamic HTML nodes.
```
# use terrazzo_client::prelude::*;
# use terrazzo_macro::html;
#[html]
fn sample() -> XElement {
div(
h1("Section 1"),
ul(li("Firstly"), li("Secondly")),
h1("Section 2"),
ol(li("One"), li("Two"), li("Three")),
)
}
```
This function generates:
```html
<div>
<h1> Section 1 </h1>
<ul>
<li> Firstly </li>
<li> Secondly </li>
</ul>
<h1> Section 2 </h1>
<ol>
<li> One </li>
<li> Two </li>
<li> Three </li>
</ol>
</div>
```
## List of nodes
List of nodes can be generated from iterators
```
# use terrazzo_client::prelude::*;
# use terrazzo_macro::html;
#[html]
fn sample() -> XElement {
let list = [1, 2, 3].map(|i| li("{i}"));
div(h1("Title"), ul(list..))
}
```
This function generates:
```html
<div>
<h1> Title </h1>
<ul>
<li> 1 </li>
<li> 2 </li>
<li> 3 </li>
</ul>
</div>
```
## Attributes
```
# use terrazzo_client::prelude::*;
# use terrazzo_macro::html;
#[html]
fn sample() -> XElement {
div(
class = "my-css-class",
style = format!("width: {}%", 100),
"Content",
)
}
```
## Optional attributes
This can be useful when a function generates a node and an attribute may or may not have a value.
```
# use terrazzo_client::prelude::*;
# use terrazzo_macro::html;
#[html]
fn sample(class: Option<String>) -> XElement {
div(
class |= class,
style = format!("width: {}%", 100),
"Content",
)
}
```
## Style properties
Style properties can be set individually.
```
# use terrazzo_client::prelude::*;
# use terrazzo_macro::html;
#[html]
fn sample(width: i32) -> XElement {
div(
style::width = format!("{}%", width),
"Content",
)
}
```
## Special attributes
`key`, `before-render` and `after-render` are special attributes.
See [XKey](crate::prelude::XKey) and [OnRenderCallback](crate::prelude::OnRenderCallback) for details.
# The `#[template]` macro
This macro can be used to create dynamic nodes.
## Simple case.
The tag and key have to be defined at the call site.
The node gets updated every time to `content` signal is updated.
```
# use terrazzo_client::prelude::*;
# use terrazzo_macro::html;
# use terrazzo_macro::template;
#[template]
#[html]
fn inner(name: String, #[signal] content: String) -> XElement {
p("id={name}", "Content={content}")
}
#[html]
pub fn outer() -> XElement {
let name = "Section 1".to_owned();
let content = XSignal::new("content", "Hello, World!".to_owned());
div(
h1("Title"),
p(key = name.clone(), move |t| {
inner(t, name.clone(), content.clone())
}),
)
}
```
## With tag and key defined in the attribute
When the tag is defined on the attribute itself, the key should be defined on the `#[template]` attribute at well.
```
# use terrazzo_client::prelude::*;
# use terrazzo_macro::html;
# use terrazzo_macro::template;
#[template(tag = p, key = name.clone())]
#[html]
fn inner(name: String, #[signal] content: String) -> XElement {
tag("id={name}", "Content={content}")
}
#[html]
pub fn outer() -> XElement {
let name = "Section 1".to_owned();
let content = XSignal::new("content", "Hello, World!".to_owned());
div(h1("Title"), inner(name, content))
}
```
## Dynamic attributes
Attributes can be generated by signals that depend on dynamic signals.
Updating the signal will recompute and update the attribute or style property.
```
# use terrazzo_client::prelude::*;
# use terrazzo_macro::html;
# use terrazzo_macro::template;
#[html]
pub fn sample(suffix: XSignal<&'static str>, width: XSignal<i32>) -> XElement {
div(
class %= move |t| make_class(t, suffix.clone()),
style::width %= move |t| make_width(t, width.clone()),
"Content",
)
}
#[template]
fn make_class(#[signal] suffix: &'static str) -> XAttributeValue {
format!("class-{suffix}")
}
#[template]
fn make_width(#[signal] width: i32) -> XAttributeValue {
format!("{}px", width)
}
```
# Debugging
## At runtime
The [tracing](https://docs.rs/tracing) crate is used to log events and add debugging information.
## At compile time
To debug code-generation, add `debug = true` to the `html` and `template` macros,
e.g.
- `#[html(debug = true)]`, and
- `#[template(debug = true)]`.