6.5 KiB
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
handlebarscrate for powerful templating - Fallback Mechanism: Gracefully falls back to built-in default template if custom template not found
- Runtime Configuration: Template name configurable via
--templateflag (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
--helpshows 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>
© 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 templatesserve_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.