coding_agent_search/html_export/mod.rs
1//! HTML export module for self-contained session exports.
2//!
3//! This module generates standalone HTML files from coding agent session transcripts.
4//! The exported files are:
5//! - **Self-contained**: All critical CSS/JS inlined for offline operation
6//! - **Progressive enhancement**: CDN resources enhance but don't break offline view
7//! - **Encrypted (optional)**: Web Crypto compatible encryption for sensitive content
8//! - **Accessible**: Semantic HTML with proper ARIA attributes
9//!
10//! # Architecture
11//!
12//! ```text
13//! html_export/
14//! ├── mod.rs # Module facade (this file)
15//! ├── template.rs # Core HTML template generation
16//! ├── styles.rs # CSS (critical inline + Tailwind CDN fallback)
17//! ├── scripts.rs # JS (decryption, search, theme toggle)
18//! ├── renderer.rs # Conversation -> HTML rendering
19//! ├── filename.rs # Smart filename generation
20//! └── encryption.rs # Web Crypto compatible encryption
21//! ```
22//!
23//! # Usage
24//!
25//! ```rust,ignore
26//! use cass::html_export::{HtmlExporter, ExportOptions};
27//!
28//! let exporter = HtmlExporter::new();
29//! let html = exporter.export_session(&session, ExportOptions::default())?;
30//! std::fs::write("session.html", html)?;
31//! ```
32
33mod encryption;
34mod filename;
35mod renderer;
36mod scripts;
37mod styles;
38mod template;
39
40// Re-export public API
41pub use encryption::{EncryptedContent, EncryptionError, EncryptionParams, encrypt_content};
42pub use filename::{
43 FilenameMetadata, FilenameOptions, agent_slug, datetime_slug, extract_topic, generate_filename,
44 generate_filepath, generate_full_filename, get_downloads_dir, is_valid_filename,
45 normalize_topic, unique_filename, workspace_slug,
46};
47pub use renderer::{
48 Message, MessageGroup, MessageGroupType, RenderError, RenderOptions, ToolCall,
49 ToolCallWithResult, ToolResult, ToolStatus, agent_css_class, agent_display_name,
50 render_message, render_message_groups,
51};
52pub use scripts::{ScriptBundle, generate_scripts};
53pub use styles::{StyleBundle, generate_styles};
54pub use template::{ExportOptions, HtmlExporter, HtmlTemplate, TemplateError, TemplateMetadata};
55
56/// Color palette matching TUI theme.rs for visual consistency.
57///
58/// These CSS custom properties are injected into the HTML template,
59/// ensuring exported files match the TUI aesthetics.
60pub mod colors {
61 /// Deep background - primary canvas color (#1a1b26)
62 pub const BG_DEEP: &str = "#1a1b26";
63
64 /// Elevated surface - cards, modals, popups (#24283b)
65 pub const BG_SURFACE: &str = "#24283b";
66
67 /// Subtle surface - hover states, selected items (#292e42)
68 pub const BG_HIGHLIGHT: &str = "#292e42";
69
70 /// Border color - subtle separators (#3b4261)
71 pub const BORDER: &str = "#3b4261";
72
73 /// Border accent - focused/active elements (#7d91c8)
74 pub const BORDER_FOCUS: &str = "#7d91c8";
75
76 /// Primary text - headings, important content (#c0caf5)
77 pub const TEXT_PRIMARY: &str = "#c0caf5";
78
79 /// Secondary text - body content (#a9b1d6)
80 pub const TEXT_SECONDARY: &str = "#a9b1d6";
81
82 /// Muted text - hints, placeholders, timestamps (#696e9e)
83 pub const TEXT_MUTED: &str = "#696e9e";
84
85 /// Disabled/inactive text (#444b6a)
86 pub const TEXT_DISABLED: &str = "#444b6a";
87
88 /// Primary accent - main actions, links (#7aa2f7)
89 pub const ACCENT_PRIMARY: &str = "#7aa2f7";
90
91 /// Secondary accent - complementary highlights (#bb9af7)
92 pub const ACCENT_SECONDARY: &str = "#bb9af7";
93
94 /// Tertiary accent - subtle highlights (#7dcfff)
95 pub const ACCENT_TERTIARY: &str = "#7dcfff";
96
97 /// User messages - soft sage green (#9ece6a)
98 pub const ROLE_USER: &str = "#9ece6a";
99
100 /// Agent/Assistant messages - primary accent (#7aa2f7)
101 pub const ROLE_AGENT: &str = "#7aa2f7";
102
103 /// Tool invocations - warm peach (#ff9e64)
104 pub const ROLE_TOOL: &str = "#ff9e64";
105
106 /// System messages - soft amber (#e0af68)
107 pub const ROLE_SYSTEM: &str = "#e0af68";
108
109 /// Success states (#73daca)
110 pub const STATUS_SUCCESS: &str = "#73daca";
111
112 /// Warning states (#e0af68)
113 pub const STATUS_WARNING: &str = "#e0af68";
114
115 /// Error states (#f7768e)
116 pub const STATUS_ERROR: &str = "#f7768e";
117
118 /// Info states (#7dcfff)
119 pub const STATUS_INFO: &str = "#7dcfff";
120
121 /// User message background tint (#1a201e)
122 pub const ROLE_USER_BG: &str = "#1a201e";
123
124 /// Agent message background tint (#1a1c24)
125 pub const ROLE_AGENT_BG: &str = "#1a1c24";
126
127 /// Tool invocation background tint (#201c1a)
128 pub const ROLE_TOOL_BG: &str = "#201c1a";
129
130 /// System message background tint (#201e1a)
131 pub const ROLE_SYSTEM_BG: &str = "#201e1a";
132}
133
134#[cfg(test)]
135mod tests {
136 use super::*;
137
138 #[test]
139 fn test_colors_are_valid_hex() {
140 // Verify all color constants are valid 7-char hex colors
141 let all_colors = [
142 // Backgrounds
143 colors::BG_DEEP,
144 colors::BG_SURFACE,
145 colors::BG_HIGHLIGHT,
146 // Borders
147 colors::BORDER,
148 colors::BORDER_FOCUS,
149 // Text
150 colors::TEXT_PRIMARY,
151 colors::TEXT_SECONDARY,
152 colors::TEXT_MUTED,
153 colors::TEXT_DISABLED,
154 // Accents
155 colors::ACCENT_PRIMARY,
156 colors::ACCENT_SECONDARY,
157 colors::ACCENT_TERTIARY,
158 // Roles
159 colors::ROLE_USER,
160 colors::ROLE_AGENT,
161 colors::ROLE_TOOL,
162 colors::ROLE_SYSTEM,
163 // Role backgrounds
164 colors::ROLE_USER_BG,
165 colors::ROLE_AGENT_BG,
166 colors::ROLE_TOOL_BG,
167 colors::ROLE_SYSTEM_BG,
168 // Status
169 colors::STATUS_SUCCESS,
170 colors::STATUS_WARNING,
171 colors::STATUS_ERROR,
172 colors::STATUS_INFO,
173 ];
174
175 for color in all_colors {
176 assert!(
177 color.starts_with('#') && color.len() == 7,
178 "Invalid color format: {}",
179 color
180 );
181 // Verify hex chars
182 assert!(
183 color[1..].chars().all(|c| c.is_ascii_hexdigit()),
184 "Invalid hex in color: {}",
185 color
186 );
187 }
188 }
189}