299 lines
11 KiB
Rust
299 lines
11 KiB
Rust
|
|
/// Example: HTML Page Generation with Tera Templates
|
|||
|
|
///
|
|||
|
|
/// This example demonstrates how to use the HtmlRenderer to generate
|
|||
|
|
/// complete HTML pages with various layouts and components.
|
|||
|
|
use daemon_cli::rendering::{HtmlRenderer, RenderContext};
|
|||
|
|
use serde_json::json;
|
|||
|
|
|
|||
|
|
#[tokio::main]
|
|||
|
|
async fn main() {
|
|||
|
|
println!("═══════════════════════════════════════════════════════════");
|
|||
|
|
println!(" HTML Page Generation Examples with Tera Templates");
|
|||
|
|
println!("═══════════════════════════════════════════════════════════\n");
|
|||
|
|
|
|||
|
|
// Example 1: Basic Page
|
|||
|
|
example_basic_page().await;
|
|||
|
|
|
|||
|
|
// Example 2: Dashboard with Metrics
|
|||
|
|
example_dashboard().await;
|
|||
|
|
|
|||
|
|
// Example 3: Report with Table of Contents
|
|||
|
|
example_report().await;
|
|||
|
|
|
|||
|
|
// Example 4: Component with Loops
|
|||
|
|
example_components().await;
|
|||
|
|
|
|||
|
|
println!("\n═══════════════════════════════════════════════════════════");
|
|||
|
|
println!(" All examples completed successfully!");
|
|||
|
|
println!("═══════════════════════════════════════════════════════════");
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
async fn example_basic_page() {
|
|||
|
|
println!("\n1️⃣ BASIC PAGE EXAMPLE");
|
|||
|
|
println!("─────────────────────────────────────────────────────────\n");
|
|||
|
|
|
|||
|
|
let renderer = HtmlRenderer::new();
|
|||
|
|
|
|||
|
|
let template = r#"<!DOCTYPE html>
|
|||
|
|
<html lang="en">
|
|||
|
|
<head>
|
|||
|
|
<meta charset="UTF-8">
|
|||
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|||
|
|
<title>{{ page_title }}</title>
|
|||
|
|
<style>
|
|||
|
|
body { font-family: Arial, sans-serif; max-width: 800px; margin: 50px auto; }
|
|||
|
|
.header { background: #667eea; color: white; padding: 20px; border-radius: 5px; }
|
|||
|
|
.content { padding: 20px; }
|
|||
|
|
.footer { color: #666; border-top: 1px solid #ddd; padding-top: 10px; }
|
|||
|
|
</style>
|
|||
|
|
</head>
|
|||
|
|
<body>
|
|||
|
|
<div class="header">
|
|||
|
|
<h1>{{ page_title }}</h1>
|
|||
|
|
<p>{{ subtitle }}</p>
|
|||
|
|
</div>
|
|||
|
|
<div class="content">
|
|||
|
|
<p>Welcome {{ name }}!</p>
|
|||
|
|
<p>{{ message }}</p>
|
|||
|
|
</div>
|
|||
|
|
<div class="footer">
|
|||
|
|
<p>Generated: {{ _now }}</p>
|
|||
|
|
</div>
|
|||
|
|
</body>
|
|||
|
|
</html>"#;
|
|||
|
|
|
|||
|
|
let ctx = RenderContext::new()
|
|||
|
|
.with_variable("page_title", json!("Welcome Page"))
|
|||
|
|
.with_variable("subtitle", json!("A dynamically generated page"))
|
|||
|
|
.with_variable("name", json!("Alice"))
|
|||
|
|
.with_variable(
|
|||
|
|
"message",
|
|||
|
|
json!("This HTML was generated using Tera templates!"),
|
|||
|
|
);
|
|||
|
|
|
|||
|
|
let result = renderer.render_html(template, &ctx).await;
|
|||
|
|
|
|||
|
|
if result.success {
|
|||
|
|
println!("✅ Rendered in {}ms", result.duration_ms);
|
|||
|
|
println!("\nGenerated HTML (first 500 chars):");
|
|||
|
|
println!(
|
|||
|
|
"{}\n...",
|
|||
|
|
&result.output[..std::cmp::min(500, result.output.len())]
|
|||
|
|
);
|
|||
|
|
} else {
|
|||
|
|
eprintln!("❌ Error: {:?}", result.errors);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
async fn example_dashboard() {
|
|||
|
|
println!("\n2️⃣ DASHBOARD EXAMPLE");
|
|||
|
|
println!("─────────────────────────────────────────────────────────\n");
|
|||
|
|
|
|||
|
|
let renderer = HtmlRenderer::new();
|
|||
|
|
let template = HtmlRenderer::dashboard_template();
|
|||
|
|
|
|||
|
|
let metrics = json!([
|
|||
|
|
{ "label": "Total Requests", "value": "12,547" },
|
|||
|
|
{ "label": "Success Rate", "value": "99.8%" },
|
|||
|
|
{ "label": "Avg Response", "value": "45ms" },
|
|||
|
|
{ "label": "Errors", "value": "23" }
|
|||
|
|
]);
|
|||
|
|
|
|||
|
|
let sections = json!([
|
|||
|
|
{
|
|||
|
|
"title": "System Status",
|
|||
|
|
"content": "✅ All systems operational. No issues detected."
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
"title": "Recent Activity",
|
|||
|
|
"content": "📊 Processing 500+ requests per minute. Database performance optimal."
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
"title": "Deployments",
|
|||
|
|
"content": "🚀 Latest deployment: v2.5.1 (2 hours ago)"
|
|||
|
|
}
|
|||
|
|
]);
|
|||
|
|
|
|||
|
|
let ctx = RenderContext::new()
|
|||
|
|
.with_variable("dashboard_title", json!("System Dashboard"))
|
|||
|
|
.with_variable("dashboard_subtitle", json!("Real-time monitoring"))
|
|||
|
|
.with_variable("metrics", metrics)
|
|||
|
|
.with_variable("sections", sections);
|
|||
|
|
|
|||
|
|
let result = renderer.render_html(template, &ctx).await;
|
|||
|
|
|
|||
|
|
if result.success {
|
|||
|
|
println!("✅ Dashboard rendered in {}ms", result.duration_ms);
|
|||
|
|
println!("📊 Metrics displayed: 4");
|
|||
|
|
println!("📋 Sections displayed: 3");
|
|||
|
|
println!("💾 HTML size: {} bytes", result.output.len());
|
|||
|
|
} else {
|
|||
|
|
eprintln!("❌ Error: {:?}", result.errors);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
async fn example_report() {
|
|||
|
|
println!("\n3️⃣ REPORT EXAMPLE");
|
|||
|
|
println!("─────────────────────────────────────────────────────────\n");
|
|||
|
|
|
|||
|
|
let renderer = HtmlRenderer::new();
|
|||
|
|
let template = HtmlRenderer::report_template();
|
|||
|
|
|
|||
|
|
let toc = json!([
|
|||
|
|
{ "id": "executive", "title": "Executive Summary" },
|
|||
|
|
{ "id": "findings", "title": "Key Findings" },
|
|||
|
|
{ "id": "metrics", "title": "Metrics & Statistics" },
|
|||
|
|
{ "id": "conclusion", "title": "Conclusion" }
|
|||
|
|
]);
|
|||
|
|
|
|||
|
|
let sections = json!([
|
|||
|
|
{
|
|||
|
|
"id": "executive",
|
|||
|
|
"title": "Executive Summary",
|
|||
|
|
"content": "<p>This report provides a comprehensive analysis of system performance metrics over Q4 2024.</p>"
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
"id": "findings",
|
|||
|
|
"title": "Key Findings",
|
|||
|
|
"content": "<ul><li>✅ Performance improved by 35%</li><li>✅ Uptime reached 99.98%</li><li>⚠️ Database optimization needed</li></ul>"
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
"id": "metrics",
|
|||
|
|
"title": "Metrics & Statistics",
|
|||
|
|
"content": "<p><strong>Processed:</strong> 4.2M requests</p><p><strong>Average Response:</strong> 52ms</p><p><strong>Peak Load:</strong> 8,500 req/s</p>"
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
"id": "conclusion",
|
|||
|
|
"title": "Conclusion",
|
|||
|
|
"content": "<p>The system demonstrates excellent stability and performance characteristics. Recommended actions include database optimization and load balancing improvements.</p>"
|
|||
|
|
}
|
|||
|
|
]);
|
|||
|
|
|
|||
|
|
let ctx = RenderContext::new()
|
|||
|
|
.with_variable("report_title", json!("Q4 2024 Performance Report"))
|
|||
|
|
.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;
|
|||
|
|
|
|||
|
|
if result.success {
|
|||
|
|
println!("✅ Report generated in {}ms", result.duration_ms);
|
|||
|
|
println!("📄 Sections: 4");
|
|||
|
|
println!("📋 Table of Contents: 4 items");
|
|||
|
|
println!("💾 Report size: {} bytes", result.output.len());
|
|||
|
|
|
|||
|
|
// Save to file
|
|||
|
|
if let Err(e) = std::fs::write("example_report.html", &result.output) {
|
|||
|
|
eprintln!("⚠️ Could not save to file: {}", e);
|
|||
|
|
} else {
|
|||
|
|
println!("💾 Saved to: example_report.html");
|
|||
|
|
}
|
|||
|
|
} else {
|
|||
|
|
eprintln!("❌ Error: {:?}", result.errors);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
async fn example_components() {
|
|||
|
|
println!("\n4️⃣ COMPONENTS WITH LOOPS AND CONDITIONALS");
|
|||
|
|
println!("─────────────────────────────────────────────────────────\n");
|
|||
|
|
|
|||
|
|
let renderer = HtmlRenderer::new();
|
|||
|
|
|
|||
|
|
let template = r#"<!DOCTYPE html>
|
|||
|
|
<html>
|
|||
|
|
<head>
|
|||
|
|
<title>Product List</title>
|
|||
|
|
<style>
|
|||
|
|
body { font-family: Arial; margin: 20px; }
|
|||
|
|
.product { border: 1px solid #ddd; padding: 15px; margin: 10px 0; border-radius: 5px; }
|
|||
|
|
.product.featured { background: #fffacd; border-left: 4px solid #ffd700; }
|
|||
|
|
.price { font-size: 1.2em; color: #667eea; font-weight: bold; }
|
|||
|
|
.status { padding: 5px 10px; border-radius: 3px; font-size: 0.9em; }
|
|||
|
|
.status.in-stock { background: #90EE90; color: #2d5016; }
|
|||
|
|
.status.low-stock { background: #FFB6C1; color: #8b1538; }
|
|||
|
|
.status.out-of-stock { background: #DCDCDC; color: #555; }
|
|||
|
|
</style>
|
|||
|
|
</head>
|
|||
|
|
<body>
|
|||
|
|
<h1>{{ catalog_title }}</h1>
|
|||
|
|
<p>Total products: {{ products | length }}</p>
|
|||
|
|
|
|||
|
|
{% for product in products %}
|
|||
|
|
<div class="product {% if product.featured %}featured{% endif %}">
|
|||
|
|
<h3>{{ product.name }}</h3>
|
|||
|
|
<p>{{ product.description }}</p>
|
|||
|
|
|
|||
|
|
<div class="price">${{ product.price }}</div>
|
|||
|
|
|
|||
|
|
{% if product.stock > 0 %}
|
|||
|
|
{% if product.stock > 10 %}
|
|||
|
|
<span class="status in-stock">✅ In Stock ({{ product.stock }} units)</span>
|
|||
|
|
{% else %}
|
|||
|
|
<span class="status low-stock">⚠️ Low Stock ({{ product.stock }} units)</span>
|
|||
|
|
{% endif %}
|
|||
|
|
{% else %}
|
|||
|
|
<span class="status out-of-stock">❌ Out of Stock</span>
|
|||
|
|
{% endif %}
|
|||
|
|
|
|||
|
|
{% if product.featured %}
|
|||
|
|
<p><strong>⭐ Featured Item</strong></p>
|
|||
|
|
{% endif %}
|
|||
|
|
</div>
|
|||
|
|
{% endfor %}
|
|||
|
|
</body>
|
|||
|
|
</html>"#;
|
|||
|
|
|
|||
|
|
let products = json!([
|
|||
|
|
{
|
|||
|
|
"name": "Laptop Pro",
|
|||
|
|
"description": "High-performance laptop for professionals",
|
|||
|
|
"price": 1299,
|
|||
|
|
"stock": 5,
|
|||
|
|
"featured": true
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
"name": "Wireless Mouse",
|
|||
|
|
"description": "Ergonomic wireless mouse with long battery life",
|
|||
|
|
"price": 29,
|
|||
|
|
"stock": 25,
|
|||
|
|
"featured": false
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
"name": "USB-C Hub",
|
|||
|
|
"description": "7-in-1 USB-C hub with multiple ports",
|
|||
|
|
"price": 49,
|
|||
|
|
"stock": 2,
|
|||
|
|
"featured": false
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
"name": "Monitor Stand",
|
|||
|
|
"description": "Adjustable monitor stand",
|
|||
|
|
"price": 79,
|
|||
|
|
"stock": 0,
|
|||
|
|
"featured": false
|
|||
|
|
}
|
|||
|
|
]);
|
|||
|
|
|
|||
|
|
let ctx = RenderContext::new()
|
|||
|
|
.with_variable("catalog_title", json!("Product Catalog"))
|
|||
|
|
.with_variable("products", products);
|
|||
|
|
|
|||
|
|
let result = renderer.render_html(template, &ctx).await;
|
|||
|
|
|
|||
|
|
if result.success {
|
|||
|
|
println!("✅ Catalog rendered in {}ms", result.duration_ms);
|
|||
|
|
println!("📦 Products displayed: 4");
|
|||
|
|
println!("🌟 Featured items: 1");
|
|||
|
|
|
|||
|
|
if let Err(e) = std::fs::write("example_catalog.html", &result.output) {
|
|||
|
|
eprintln!("⚠️ Could not save to file: {}", e);
|
|||
|
|
} else {
|
|||
|
|
println!("💾 Saved to: example_catalog.html");
|
|||
|
|
}
|
|||
|
|
} else {
|
|||
|
|
eprintln!("❌ Error: {:?}", result.errors);
|
|||
|
|
}
|
|||
|
|
}
|