pub mod compose;
pub mod context;
pub mod helpers;
pub mod post_process;
use crate::registry::TemplateRegistry;
use crate::template::{ComposeSection, RenderResponse};
use anyhow::{Context, bail};
use serde_json::Value;
pub fn render_preset(
registry: &TemplateRegistry,
preset_name: &str,
theme_name: Option<&str>,
data: &Value,
) -> anyhow::Result<RenderResponse> {
let _preset = registry
.get_preset(preset_name)
.with_context(|| format!("preset '{}' not found", preset_name))?;
let theme = registry.get_theme(theme_name)?;
let context = context::build_context(data, &theme);
let rendered = registry
.handlebars
.render(preset_name, &context)
.with_context(|| format!("handlebars render failed for '{}'", preset_name))?;
let card = post_process::finalize(&rendered)?;
Ok(RenderResponse {
card,
host_config: theme.host_config.clone(),
preset: preset_name.to_string(),
theme: theme.name.clone(),
})
}
pub fn render_compose(
registry: &TemplateRegistry,
sections: &[ComposeSection],
theme_name: Option<&str>,
) -> anyhow::Result<RenderResponse> {
if sections.is_empty() {
bail!("compose mode requires at least one section");
}
let theme = registry.get_theme(theme_name)?;
let card = compose::render_sections(®istry.handlebars, sections, &theme)?;
Ok(RenderResponse {
card,
host_config: theme.host_config.clone(),
preset: "compose".to_string(),
theme: theme.name.clone(),
})
}
pub fn validate_theme_exists(registry: &TemplateRegistry, theme_name: &str) -> anyhow::Result<()> {
registry.themes.get(theme_name).map(|_| ()).ok_or_else(|| {
let available = registry.themes.names().join(", ");
anyhow::anyhow!("theme '{}' not found. Available: {}", theme_name, available)
})
}