mhmmcontent/TEMPLATE_FEATURE.md
2026-01-28 20:56:35 +01:00

6.5 KiB

Template/Layout Feature Implementation

Overview

Successfully implemented a flexible template/layout system that allows loading custom HTML templates from the working directory's ./layout folder.

Key Features

Template Loading from Filesystem

  • Custom Template Support: Loads templates from ./layout/{template_name}.hbs
  • Handlebars Integration: Uses the handlebars crate for powerful templating
  • Fallback Mechanism: Gracefully falls back to built-in default template if custom template not found
  • Runtime Configuration: Template name configurable via --template flag (default: "default")

Template Variables

  • {{title}} - Page title derived from Markdown filename
  • {{content}} - Rendered HTML content from Markdown
  • {{path}} - Current URL path

Error Handling

  • File Not Found: Falls back to built-in template if custom template doesn't exist
  • Parse Errors: Falls back to simple HTML if template rendering fails
  • Directory Creation: Automatically handles missing layout directories

User Experience

  • Clear Logging: Shows which template is being used on startup
  • Help Documentation: Updated --help shows template option
  • Flexible Configuration: Easy to switch between different templates

Implementation Details

Template Loading Logic

fn load_template(workdir: &PathBuf, template_name: &str) -> Handlebars<'static> {
    // 1. Try to load from ./layout/{template_name}.hbs
    // 2. If found and valid, use it
    // 3. Otherwise, use built-in default template
}

Template Rendering

let template_data = json!({
    "title": title,
    "content": html_output,
    "path": path.into_inner(),
});

match data.template_engine.render("layout", &template_data) {
    Ok(rendered) => /* Use rendered template */,
    Err(_) => /* Fallback to simple HTML */
}

File Structure

mhmmcontent/
├── layout/                    # Template directory
│   ├── default.hbs           # Custom default template
│   ├── minimal.hbs           # Minimal template example
│   └── *.hbs                 # Additional custom templates
├── content/                  # Markdown content
│   └── *.md                  # Markdown files
└── src/main.rs               # Server implementation

Usage Examples

Default Template (Built-in)

./mhmmcontent
# Uses built-in default template

Custom Template from Filesystem

./mhmmcontent --template default
# Loads from ./layout/default.hbs if it exists

Different Custom Template

./mhmmcontent --template minimal
# Loads from ./layout/minimal.hbs

Non-existent Template (Error)

./mhmmcontent --template nonexistent
# Fails with clear error message indicating missing template file

Template Examples

Basic Template (layout/basic.hbs)

<!DOCTYPE html>
<html>
<head>
    <title>{{title}}</title>
    <style>
        body { font-family: Arial, sans-serif; max-width: 800px; margin: 0 auto; padding: 20px; }
        pre { background: #f0f0f0; padding: 10px; overflow-x: auto; }
    </style>
</head>
<body>
    <h1>{{title}}</h1>
    <div>{{{content}}}</div>
    <footer><small>Path: {{path}}</small></footer>
</body>
</html>

Advanced Template (layout/advanced.hbs)

<!DOCTYPE html>
<html>
<head>
    <title>{{title}} | My Site</title>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <style>
        :root {
            --primary: #2c3e50;
            --secondary: #3498db;
        }
        body {
            font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
            line-height: 1.6;
            color: #333;
            max-width: 1000px;
            margin: 0 auto;
            padding: 20px;
        }
        header {
            background: var(--primary);
            color: white;
            padding: 1rem;
            margin-bottom: 2rem;
            border-radius: 5px;
        }
        nav {
            display: flex;
            gap: 1rem;
            margin: 1rem 0;
        }
        nav a {
            color: white;
            text-decoration: none;
        }
        main {
            min-height: 300px;
        }
        footer {
            margin-top: 2rem;
            padding-top: 1rem;
            border-top: 1px solid #eee;
            color: #666;
            font-size: 0.9rem;
        }
    </style>
</head>
<body>
    <header>
        <h1>My Site</h1>
        <nav>
            <a href="/">Home</a>
            <a href="/about">About</a>
            <a href="/contact">Contact</a>
        </nav>
        <div style="font-size: 0.9rem; opacity: 0.8;">
            Current page: {{path}}
        </div>
    </header>
    <main>
        <h2>{{title}}</h2>
        {{{content}}}
    </main>
    <footer>
        &copy; 2023 My Site. Powered by Rust Markdown Server.
    </footer>
</body>
</html>

Benefits

For Users

  • Custom Branding: Easy to add logos, colors, and branding
  • Consistent Layout: Maintain consistent header/footer across all pages
  • Navigation: Add navigation menus to all pages automatically
  • Responsive Design: Create mobile-friendly layouts

For Developers

  • Separation of Concerns: Content (Markdown) separate from presentation (HTML)
  • Easy Customization: No need to modify server code to change appearance
  • Multiple Themes: Support different templates for different use cases
  • Fallback Safety: Server continues to work even if templates are missing

Technical Implementation

Dependencies Added

[dependencies]
handlebars = "4.0"      # Templating engine

Key Functions

  • load_template(): Loads and registers templates
  • serve_markdown(): Renders content using templates
  • Template fallback mechanism for robustness

Error Handling

  • File system errors: Clear error messages for missing template files
  • Template parsing errors: Detailed error messages for invalid template syntax
  • Rendering errors: Fallback to simple HTML if template rendering fails
  • Strict Requirements: Server fails fast if required template is missing

Performance

  • Fast Template Loading: Templates loaded once at startup
  • Efficient Rendering: Handlebars provides fast template rendering
  • Minimal Overhead: Template processing adds negligible latency
  • Memory Efficient: Templates stored in memory after initial load

The template feature makes the Markdown server highly customizable while maintaining robustness and ease of use.