# HTML Rendering Guide
## Overview
The daemon-cli crate now includes **HTML page generation** capabilities using Tera templates. This allows you to:
- Generate complete HTML5 pages with styled layouts
- Create reusable HTML components
- Build dashboards with metrics and sections
- Generate professional reports
- Render dynamic pages from templates and context data
---
## Quick Start
### Basic HTML Page
```rust
use daemon_cli::rendering::{HtmlRenderer, RenderContext};
use serde_json::json;
#[tokio::main]
async fn main() {
let renderer = HtmlRenderer::new();
let template = r#"
{{ page_title }}
Welcome {{ name }}!
{{ message }}
"#;
let ctx = RenderContext::new()
.with_variable("page_title", json!("My Page"))
.with_variable("name", json!("Alice"))
.with_variable("message", json!("This is dynamically rendered HTML"));
let result = renderer.render_html(template, &ctx).await;
if result.success {
println!("{}", result.output);
// Save to file
std::fs::write("output.html", &result.output).unwrap();
}
}
```
---
## Built-in Templates
### 1. Basic Page Template
Use the basic page template for simple HTML pages:
```rust
let renderer = HtmlRenderer::new();
let template = HtmlRenderer::basic_page_template();
let ctx = RenderContext::new()
.with_variable("page_title", json!("My App"))
.with_variable("content", json!("
Hello World
"));
let result = renderer.render_html(template, &ctx).await;
```
**Features**:
- Responsive CSS included
- Clean typography
- Mobile-friendly viewport settings
- Dark/light friendly colors
- Footer with generation timestamp
---
### 2. Dashboard Template
Create interactive dashboards with metrics:
```rust
let renderer = HtmlRenderer::new();
let template = HtmlRenderer::dashboard_template();
let metrics = json!([
{ "label": "Total Users", "value": "1,234" },
{ "label": "Active Sessions", "value": "567" },
{ "label": "Revenue", "value": "$12,345" }
]);
let sections = json!([
{
"title": "System Status",
"content": "All systems operational"
},
{
"title": "Recent Activity",
"content": "3 new users signed up today"
}
]);
let ctx = RenderContext::new()
.with_variable("dashboard_title", json!("Operations Dashboard"))
.with_variable("dashboard_subtitle", json!("Real-time metrics"))
.with_variable("metrics", metrics)
.with_variable("sections", sections);
let result = renderer.render_html(template, &ctx).await;
```
**Features**:
- Gradient header with purple theme
- Metric cards in responsive grid
- Section cards for content
- Color-coded metric values
- Last updated timestamp
---
### 3. Report Template
Generate professional reports:
```rust
let renderer = HtmlRenderer::new();
let template = HtmlRenderer::report_template();
let toc = json!([
{ "id": "intro", "title": "Introduction" },
{ "id": "findings", "title": "Findings" },
{ "id": "conclusion", "title": "Conclusion" }
]);
let sections = json!([
{
"id": "intro",
"title": "Introduction",
"content": "
This is the introduction section with details about the report.
"
}
]);
let ctx = RenderContext::new()
.with_variable("report_title", json!("Annual Report 2024"))
.with_variable("report_author", json!("Operations Team"))
.with_variable("toc", toc)
.with_variable("sections", sections)
.with_variable("footer_text", json!("Confidential - Internal Use Only"));
let result = renderer.render_html(template, &ctx).await;
```
**Features**:
- Table of Contents with anchor links
- Professional typography (Georgia serif)
- Print-friendly layout
- Page break handling
- Automatic section numbering
- Confidential footer
---
## Advanced Features
### HTML Components
Create reusable HTML components:
```rust
let renderer = HtmlRenderer::new();
// Define a card component
let card_component = r#"
{{ card_title }}
{{ card_content }}
{% if card_footer %}{% endif %}
"#;
let ctx = RenderContext::new()
.with_variable("card_title", json!("Featured Item"))
.with_variable("card_content", json!("This is a reusable card component"))
.with_variable("card_footer", json!("Click for details"));
let result = renderer.render_component(card_component, &ctx).await;
```
### Dynamic Lists
Generate HTML lists from arrays:
```rust
let template = r#"
{% for item in items %}
{{ item.name }} - {{ item.value }}
{% endfor %}
"#;
let items = json!([
{ "name": "Item 1", "value": "100" },
{ "name": "Item 2", "value": "200" },
{ "name": "Item 3", "value": "300" }
]);
let ctx = RenderContext::new()
.with_variable("items", items);
let result = renderer.render_html(template, &ctx).await;
```
### Conditional Content
Show/hide sections based on data:
```rust
let template = r#"
Status Report
{% if status == "error" %}
Error: {{ error_message }}
{% elif status == "warning" %}
Warning: {{ warning_message }}
{% else %}
Success: All systems operational
{% endif %}
"#;
let ctx = RenderContext::new()
.with_variable("status", json!("error"))
.with_variable("error_message", json!("Database connection failed"));
let result = renderer.render_html(template, &ctx).await;
```
### Using Filters
Apply Tera filters to format data:
```rust
let template = r#"
{{ title | upper }}
Items: {{ items | length }}
Truncated: {{ long_text | truncate(length=50) }}
"#;
let ctx = RenderContext::new()
.with_variable("title", json!("hello world"))
.with_variable("items", json!(["a", "b", "c"]))
.with_variable("long_text", json!("This is a very long text that should be truncated"));
let result = renderer.render_html(template, &ctx).await;
```
---
## Rendering Methods
### `render_html(template, context)`
Simple HTML rendering with validation.
```rust
let result = renderer.render_html(template, &context).await;
if result.success {
println!("Rendered in {}ms", result.duration_ms);
println!("{}", result.output);
} else {
eprintln!("Errors: {:?}", result.errors);
}
```
### `render_page(title, template, context)`
Render a page with automatic title handling.
```rust
let result = renderer.render_page(
"Dashboard",
template,
&context
).await;
```
### `render_component(template, context)`
Render reusable HTML components.
```rust
let result = renderer.render_component(component, &context).await;
```
### `validate_html(template)`
Validate HTML template syntax before rendering.
```rust
let validation = renderer.validate_html(template).await;
if validation.is_ok() {
// Template is valid, safe to render
}
```
---
## Performance
- **Rendering Time**: <5ms for typical pages
- **Validation Time**: <1ms
- **Memory Usage**: Minimal (RefCell-based Tera wrapper)
- **Supports**: Thousands of concurrent renders
---
## Real-World Examples
### Generate a Project Status Page
```rust
let renderer = HtmlRenderer::new();
let template = HtmlRenderer::dashboard_template();
let metrics = json!([
{ "label": "Build Status", "value": "✅ Passing" },
{ "label": "Test Coverage", "value": "98%" },
{ "label": "Deployment", "value": "🟢 Live" }
]);
let sections = json!([
{
"title": "Latest Build",
"content": "Build #1234 completed successfully in 2m 34s"
},
{
"title": "Recent Commits",
"content": "5 commits merged to main branch"
}
]);
let ctx = RenderContext::new()
.with_variable("dashboard_title", json!("Project Status"))
.with_variable("metrics", metrics)
.with_variable("sections", sections);
let result = renderer.render_html(template, &ctx).await;
std::fs::write("status.html", result.output).unwrap();
```
### Generate a Security Report
```rust
let renderer = HtmlRenderer::new();
let template = HtmlRenderer::report_template();
let findings = json!([
{
"id": "findings",
"title": "Security Findings",
"content": r#"
The following vulnerabilities were identified:
CVE
Severity
Status
CVE-2024-001
High
Patched
CVE-2024-002
Medium
In Progress
"#
}
]);
let ctx = RenderContext::new()
.with_variable("report_title", json!("Security Audit Report"))
.with_variable("report_author", json!("Security Team"))
.with_variable("sections", findings)
.with_variable("footer_text", json!("CONFIDENTIAL"));
let result = renderer.render_html(template, &ctx).await;
```
---
## Integration with Daemon API
You can expose HTML rendering through the HTTP API:
```rust
// Handler for /api/v1/render endpoint
async fn render_html_handler(
State(state): State,
Json(payload): Json,
) -> impl IntoResponse {
let renderer = HtmlRenderer::new();
let ctx = RenderContext::new()
.with_variable("data", json!(payload.data));
match renderer.render_html(&payload.template, &ctx).await {
result if result.success => {
(StatusCode::OK, result.output)
}
result => {
(StatusCode::BAD_REQUEST, format!("Error: {:?}", result.errors))
}
}
}
```
---
## Best Practices
1. **Validate Templates First**
```rust
renderer.validate_html(template).await?;
renderer.render_html(template, &ctx).await;
```
2. **Sanitize User Input**
- Always escape user-provided data in templates
- Use Tera's `escape_html` filter for user content
3. **Reuse Templates**
```rust
let template = HtmlRenderer::basic_page_template();
// Render multiple pages with different contexts
```
4. **Performance**
- Cache template definitions
- Render heavy pages asynchronously
- Profile with `duration_ms` metric
5. **Accessibility**
- Include ARIA labels
- Use semantic HTML (``, `