from __future__ import annotations from typing import Any def render_card( title: str | None = None, body: str = "", subtitle: str | None = None, image_url: str | None = None, footer: str | None = None, accent_color: str = "#007AFF", ) -> str: parts = [] if title: parts.append(f"{_escape_html(title)}") if subtitle: parts.append(f"{_escape_html(subtitle)}") if image_url: parts.append(f'image') if body: parts.append(body) if footer: parts.append(f'{_escape_html(footer)}') return "\n".join(parts) def render_notification(title: str, body: str = "", level: str = "info") -> str: level_icons = {"info": "ℹ️", "warning": "⚠️", "error": "❌", "success": "✅"} icon = level_icons.get(level, "ℹ️") lines = [f"{icon} {_escape_html(title)}"] if body: lines.append(body) return "\n".join(lines) def render_items(items: list[dict[str, Any]], item_template: str = "{label}: {value}") -> str: lines = [] for item in items: line = item_template for key, val in item.items(): line = line.replace(f"{{{key}}}", str(val)) lines.append(f"• {line}") return "\n".join(lines) def render_button_row(buttons: list[dict[str, str]]) -> str: if not buttons: return "" links = [] for btn in buttons: label = btn.get("label", "") url = btn.get("url", "") if url: links.append(f'{_escape_html(label)}') else: links.append(f"[{_escape_html(label)}]") return " | ".join(links) def _escape_html(text: str) -> str: return text.replace("&", "&").replace("<", "<").replace(">", ">").replace('"', """)