Skip to content

Commit 0a7381f

Browse files
michael-borckclaude
andcommitted
Complete export system with batch processing and branding (sub-tasks 5.7-5.8)
Implemented comprehensive batch export and template customization system: Sub-task 5.7 - Template Customization with Branding: - Added BrandingOptions with colors, fonts, and institution settings - Dynamic CSS injection for HTML exports with brand colors - PowerPoint theme customization with branded color schemes - PDF title page branding with institution names - Cross-format consistency and graceful fallbacks Sub-task 5.8 - Batch Export for Multiple Content Types: - BatchExportManager for orchestrating multiple export jobs - Multi-session and multi-format processing capabilities - Parallel execution with configurable concurrency limits - Progress tracking with real-time feedback system - Flexible naming strategies (session-based, content-based, sequential, custom) - Error resilience with continue-on-error options - Manifest generation for detailed operation reports - Enhanced SessionManager with multi-session content retrieval Export System Features (Section 5.0 COMPLETE): - Multiple formats: Markdown, HTML, PDF, PowerPoint, Quarto - Professional templates with branding customization - Batch processing with parallel execution - Progress tracking and error handling - Comprehensive documentation and examples 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
1 parent 38b0dc6 commit 0a7381f

File tree

15 files changed

+7717
-21
lines changed

15 files changed

+7717
-21
lines changed

src-tauri/docs/batch-export-system.md

Lines changed: 592 additions & 0 deletions
Large diffs are not rendered by default.

src-tauri/docs/branding-customization.md

Lines changed: 449 additions & 0 deletions
Large diffs are not rendered by default.

src-tauri/examples/batch_export.rs

Lines changed: 434 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 374 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,374 @@
1+
//! Branding Customization Example
2+
//!
3+
//! This example demonstrates how to use the template customization system
4+
//! with branding options (colors, logos, fonts) in the Curriculum Curator.
5+
6+
use curriculum_curator::export::{ExportFormat, ExportOptions, ExportManager, BrandingOptions, BrandColors, BrandFonts};
7+
use curriculum_curator::content::{ContentType, GeneratedContent};
8+
use curriculum_curator::content::generator::ContentMetadata;
9+
use std::path::PathBuf;
10+
11+
#[tokio::main]
12+
async fn main() -> Result<(), Box<dyn std::error::Error>> {
13+
println!("🎨 Template Customization with Branding Options");
14+
println!("==============================================\n");
15+
16+
// Create sample educational content
17+
let sample_content = create_sample_content();
18+
19+
// Create different branding configurations
20+
let university_branding = create_university_branding();
21+
let corporate_branding = create_corporate_branding();
22+
let k12_branding = create_k12_branding();
23+
24+
// Export with different brandings
25+
let export_manager = ExportManager::new();
26+
27+
// Test 1: University Branding
28+
println!("🎓 Testing University Branding...");
29+
test_branding_export(&export_manager, &sample_content, &university_branding, "university").await?;
30+
31+
// Test 2: Corporate Branding
32+
println!("🏢 Testing Corporate Branding...");
33+
test_branding_export(&export_manager, &sample_content, &corporate_branding, "corporate").await?;
34+
35+
// Test 3: K-12 School Branding
36+
println!("🏫 Testing K-12 School Branding...");
37+
test_branding_export(&export_manager, &sample_content, &k12_branding, "k12").await?;
38+
39+
// Test 4: No Branding (Default)
40+
println!("⚪ Testing Default (No Branding)...");
41+
test_default_export(&export_manager, &sample_content).await?;
42+
43+
println!("\n🎉 Branding customization demonstration complete!");
44+
println!("\nBranding Features Demonstrated:");
45+
println!("• 🎨 Custom color schemes (primary, secondary, accent)");
46+
println!("• 🔤 Custom fonts (heading and body typography)");
47+
println!("• 🏛️ Institution name integration");
48+
println!("• 📄 Cross-format consistency (HTML, PDF, PowerPoint)");
49+
println!("• 🎯 Template-specific optimizations");
50+
51+
println!("\nGenerated Files:");
52+
println!("• ./examples/output/university_branded.html");
53+
println!("• ./examples/output/university_branded.pdf");
54+
println!("• ./examples/output/university_branded.pptx");
55+
println!("• ./examples/output/corporate_branded.html");
56+
println!("• ./examples/output/k12_branded.html");
57+
println!("• ./examples/output/default_export.html");
58+
59+
Ok(())
60+
}
61+
62+
async fn test_branding_export(
63+
manager: &ExportManager,
64+
content: &GeneratedContent,
65+
branding: &BrandingOptions,
66+
prefix: &str
67+
) -> Result<(), Box<dyn std::error::Error>> {
68+
// Test HTML export with branding
69+
let html_path = PathBuf::from(format!("./examples/output/{}_branded.html", prefix));
70+
test_format_with_branding(manager, content, branding, ExportFormat::Html, html_path).await?;
71+
72+
// Test PDF export with branding
73+
let pdf_path = PathBuf::from(format!("./examples/output/{}_branded.pdf", prefix));
74+
test_format_with_branding(manager, content, branding, ExportFormat::Pdf, pdf_path).await?;
75+
76+
// Test PowerPoint export with branding
77+
let pptx_path = PathBuf::from(format!("./examples/output/{}_branded.pptx", prefix));
78+
test_format_with_branding(manager, content, branding, ExportFormat::PowerPoint, pptx_path).await?;
79+
80+
Ok(())
81+
}
82+
83+
async fn test_format_with_branding(
84+
manager: &ExportManager,
85+
content: &GeneratedContent,
86+
branding: &BrandingOptions,
87+
format: ExportFormat,
88+
output_path: PathBuf
89+
) -> Result<(), Box<dyn std::error::Error>> {
90+
// Ensure output directory exists
91+
if let Some(parent) = output_path.parent() {
92+
std::fs::create_dir_all(parent)?;
93+
}
94+
95+
let options = ExportOptions {
96+
format: format.clone(),
97+
output_path: output_path.clone(),
98+
template_name: Some("professional".to_string()),
99+
include_metadata: true,
100+
branding_options: Some(branding.clone()),
101+
};
102+
103+
match manager.export_content(&[content.clone()], &options).await {
104+
Ok(result) => {
105+
if result.success {
106+
println!(" ✅ {:?} export successful: {}", format, result.output_path.display());
107+
if let Some(size) = result.file_size {
108+
println!(" 📊 File size: {} bytes", size);
109+
}
110+
} else {
111+
println!(" ❌ {:?} export failed: {}", format,
112+
result.error_message.unwrap_or_else(|| "Unknown error".to_string()));
113+
}
114+
},
115+
Err(e) => {
116+
println!(" ❌ {:?} export error: {}", format, e);
117+
}
118+
}
119+
120+
Ok(())
121+
}
122+
123+
async fn test_default_export(
124+
manager: &ExportManager,
125+
content: &GeneratedContent
126+
) -> Result<(), Box<dyn std::error::Error>> {
127+
let output_path = PathBuf::from("./examples/output/default_export.html");
128+
129+
// Ensure output directory exists
130+
if let Some(parent) = output_path.parent() {
131+
std::fs::create_dir_all(parent)?;
132+
}
133+
134+
let options = ExportOptions {
135+
format: ExportFormat::Html,
136+
output_path: output_path.clone(),
137+
template_name: Some("default".to_string()),
138+
include_metadata: true,
139+
branding_options: None, // No branding
140+
};
141+
142+
match manager.export_content(&[content.clone()], &options).await {
143+
Ok(result) => {
144+
if result.success {
145+
println!(" ✅ Default export successful: {}", result.output_path.display());
146+
} else {
147+
println!(" ❌ Default export failed: {}",
148+
result.error_message.unwrap_or_else(|| "Unknown error".to_string()));
149+
}
150+
},
151+
Err(e) => {
152+
println!(" ❌ Default export error: {}", e);
153+
}
154+
}
155+
156+
Ok(())
157+
}
158+
159+
fn create_university_branding() -> BrandingOptions {
160+
BrandingOptions {
161+
institution_name: Some("State University".to_string()),
162+
logo_path: None, // Would typically be a path to university logo
163+
colors: BrandColors {
164+
primary: "#003366".to_string(), // Navy blue
165+
secondary: "#0066CC".to_string(), // Royal blue
166+
accent: "#FFD700".to_string(), // Gold
167+
},
168+
fonts: BrandFonts {
169+
heading: "Garamond, serif".to_string(),
170+
body: "Times New Roman, serif".to_string(),
171+
},
172+
}
173+
}
174+
175+
fn create_corporate_branding() -> BrandingOptions {
176+
BrandingOptions {
177+
institution_name: Some("TechCorp Training Division".to_string()),
178+
logo_path: None, // Would typically be a path to company logo
179+
colors: BrandColors {
180+
primary: "#1E88E5".to_string(), // Corporate blue
181+
secondary: "#424242".to_string(), // Dark gray
182+
accent: "#FF9800".to_string(), // Orange
183+
},
184+
fonts: BrandFonts {
185+
heading: "Helvetica Neue, sans-serif".to_string(),
186+
body: "Arial, sans-serif".to_string(),
187+
},
188+
}
189+
}
190+
191+
fn create_k12_branding() -> BrandingOptions {
192+
BrandingOptions {
193+
institution_name: Some("Sunshine Elementary School".to_string()),
194+
logo_path: None, // Would typically be a path to school logo
195+
colors: BrandColors {
196+
primary: "#4CAF50".to_string(), // Green
197+
secondary: "#2196F3".to_string(), // Blue
198+
accent: "#FFC107".to_string(), // Amber
199+
},
200+
fonts: BrandFonts {
201+
heading: "Comic Sans MS, cursive".to_string(),
202+
body: "Verdana, sans-serif".to_string(),
203+
},
204+
}
205+
}
206+
207+
fn create_sample_content() -> GeneratedContent {
208+
GeneratedContent {
209+
content_type: ContentType::Slides,
210+
title: "Introduction to Scientific Method".to_string(),
211+
content: r#"
212+
---SLIDE---
213+
# The Scientific Method
214+
215+
## Learning Objectives
216+
By the end of this lesson, students will be able to:
217+
- Define the scientific method
218+
- Identify the steps of scientific inquiry
219+
- Apply the scientific method to real-world problems
220+
- Distinguish between observation and inference
221+
222+
---SLIDE---
223+
# What is Science?
224+
225+
## Definition
226+
Science is a systematic way of learning about the natural world through:
227+
- **Observation**: Using our senses to gather information
228+
- **Investigation**: Asking questions and seeking answers
229+
- **Experimentation**: Testing ideas in controlled conditions
230+
- **Analysis**: Making sense of data and evidence
231+
232+
> "Science is not only a disciple of reason but also one of romance and passion." - Stephen Hawking
233+
234+
SPEAKER_NOTES:
235+
Start by asking students what they think science is. Many will think of test tubes and lab coats, but science is much broader. Emphasize that science is a way of thinking and understanding the world around us.
236+
237+
---SLIDE---
238+
# The Scientific Method Steps
239+
240+
## 1. Make an Observation
241+
- Notice something interesting in the natural world
242+
- Ask "What's happening here?"
243+
244+
## 2. Ask a Question
245+
- Form a specific, testable question
246+
- Example: "Why do plants grow toward light?"
247+
248+
## 3. Form a Hypothesis
249+
- Make an educated guess based on prior knowledge
250+
- Must be testable and falsifiable
251+
252+
## 4. Design and Conduct an Experiment
253+
- Control variables
254+
- Collect data systematically
255+
256+
## 5. Analyze Results and Draw Conclusions
257+
- Look for patterns in the data
258+
- Accept, reject, or modify your hypothesis
259+
260+
SPEAKER_NOTES:
261+
Emphasize that this is not always a linear process. Scientists often go back and forth between steps, and new observations can lead to new questions at any point.
262+
263+
---SLIDE---
264+
# Types of Scientific Investigation
265+
266+
## Controlled Experiments
267+
- Test one variable at a time
268+
- Use control groups
269+
- Example: Testing plant growth with different fertilizers
270+
271+
## Observational Studies
272+
- Watch and record natural phenomena
273+
- Cannot control variables
274+
- Example: Studying animal behavior in the wild
275+
276+
## Comparative Studies
277+
- Compare different groups or conditions
278+
- Look for correlations
279+
- Example: Comparing student performance across different teaching methods
280+
281+
SPEAKER_NOTES:
282+
Not all science happens in a laboratory. Field studies, surveys, and observational research are equally important to advancing scientific knowledge.
283+
284+
---SLIDE---
285+
# Designing Good Experiments
286+
287+
## Key Principles
288+
289+
### Variables
290+
- **Independent Variable**: What you change
291+
- **Dependent Variable**: What you measure
292+
- **Control Variables**: What you keep the same
293+
294+
### Controls
295+
- **Positive Control**: Expected to show the effect
296+
- **Negative Control**: Expected to show no effect
297+
- **Control Group**: Receives no treatment
298+
299+
### Sample Size
300+
- Larger samples give more reliable results
301+
- Reduces the impact of individual variation
302+
303+
SPEAKER_NOTES:
304+
Use concrete examples from student experience. For instance, if testing which brand of paper airplane flies farthest, the independent variable is the paper brand, the dependent variable is flight distance, and control variables include throwing force, launch angle, and environmental conditions.
305+
306+
---SLIDE---
307+
# Activity: Design Your Own Experiment
308+
309+
## Question: "Which type of music helps students concentrate better?"
310+
311+
Working in groups, design an experiment to test this question:
312+
313+
1. **Hypothesis**: What do you predict and why?
314+
2. **Variables**: What will you change, measure, and control?
315+
3. **Procedure**: How will you conduct the test?
316+
4. **Data Collection**: What will you record?
317+
5. **Sample Size**: How many people will you test?
318+
319+
**Time**: 15 minutes to plan, 5 minutes to present
320+
321+
SPEAKER_NOTES:
322+
Walk around and guide groups toward good experimental design. Common issues will be controlling variables (same task, same time of day, same volume level) and defining "concentration" (test scores, time to complete task, etc.).
323+
324+
---SLIDE---
325+
# Scientific Thinking in Everyday Life
326+
327+
## Examples of Daily Science
328+
329+
### Weather Prediction
330+
- Observation: Clouds gathering
331+
- Hypothesis: It might rain
332+
- Test: Check weather forecast and barometric pressure
333+
334+
### Cooking
335+
- Observation: Cake didn't rise properly
336+
- Question: What went wrong?
337+
- Hypothesis: Too much/little baking powder
338+
- Test: Try different amounts in next batch
339+
340+
### Problem Solving
341+
- Identify the problem (observation)
342+
- Brainstorm solutions (hypotheses)
343+
- Test the best option (experiment)
344+
- Evaluate results (analysis)
345+
346+
SPEAKER_NOTES:
347+
Help students see that they already use scientific thinking in their daily lives. The formal scientific method just makes this process more systematic and rigorous.
348+
349+
---SLIDE---
350+
# Review and Assessment
351+
352+
## Key Takeaways
353+
1. Science is a way of understanding the natural world
354+
2. The scientific method provides a systematic approach to investigation
355+
3. Good experiments control variables and use appropriate sample sizes
356+
4. Scientific thinking applies to everyday problem-solving
357+
358+
## Next Class
359+
- Applying the scientific method to a real research project
360+
- Introduction to data analysis and interpretation
361+
- Guest speaker: Local scientist discussing their research
362+
363+
**Homework**: Choose a question about the natural world and design an experiment to test it. Use the scientific method steps we learned today.
364+
365+
SPEAKER_NOTES:
366+
Review the main concepts and check for understanding. Assign students to bring their experimental designs to the next class where they'll peer-review each other's work before conducting their investigations.
367+
"#.to_string(),
368+
metadata: ContentMetadata {
369+
word_count: 847,
370+
estimated_duration: "45 minutes".to_string(),
371+
difficulty_level: "Intermediate".to_string(),
372+
},
373+
}
374+
}

0 commit comments

Comments
 (0)