mhmmcontent/TEMPLATE_FEATURE.md

229 lines
6.5 KiB
Markdown
Raw Normal View History

2026-01-28 20:56:35 +01:00
# 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
```rust
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
```rust
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)
```bash
./mhmmcontent
# Uses built-in default template
```
### Custom Template from Filesystem
```bash
./mhmmcontent --template default
# Loads from ./layout/default.hbs if it exists
```
### Different Custom Template
```bash
./mhmmcontent --template minimal
# Loads from ./layout/minimal.hbs
```
### Non-existent Template (Error)
```bash
./mhmmcontent --template nonexistent
# Fails with clear error message indicating missing template file
```
## Template Examples
### Basic Template (`layout/basic.hbs`)
```html
<!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`)
```html
<!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
```toml
[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.