use blocks::{
block::{ButtonStyle, CalloutType},
Block, BlockType, ConversionFormat, Convertible, Document, JsonSerializable,
};
fn main() -> Result<(), Box<dyn std::error::Error>> {
println!("🔌 Blocks Library - JSON API for Editor Backends\n");
println!("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
println!("1. PARSING BLOCKS FROM FRONTEND JSON");
println!("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n");
let block_json = r#"{
"id": "550e8400-e29b-41d4-a716-446655440000",
"block_type": { "Header": { "level": 2 } },
"content": "Welcome to My Blog",
"metadata": {},
"created_at": 1703001600,
"updated_at": 1703001600
}"#;
println!("Received JSON from frontend:");
println!("{}\n", block_json);
let block = Block::from_json(block_json)?;
println!("Parsed block: {:?}", block.block_type);
println!("Content: {}\n", block.content);
println!("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
println!("2. PARSING FULL DOCUMENT FROM FRONTEND");
println!("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n");
let doc_json = r#"{
"id": "550e8400-e29b-41d4-a716-446655440001",
"title": "My Blog Post",
"blocks": [
{
"id": "550e8400-e29b-41d4-a716-446655440002",
"block_type": { "Header": { "level": 1 } },
"content": "Introduction",
"metadata": {},
"created_at": 1703001600,
"updated_at": 1703001600
},
{
"id": "550e8400-e29b-41d4-a716-446655440003",
"block_type": "Text",
"content": "This is the first paragraph of my blog post.",
"metadata": {},
"created_at": 1703001600,
"updated_at": 1703001600
},
{
"id": "550e8400-e29b-41d4-a716-446655440004",
"block_type": { "List": { "list_type": "Unordered" } },
"content": "Point one\nPoint two\nPoint three",
"metadata": {},
"created_at": 1703001600,
"updated_at": 1703001600
}
],
"metadata": { "author": "John Doe" },
"created_at": 1703001600,
"updated_at": 1703001600
}"#;
let doc = Document::from_json(doc_json)?;
println!("Parsed document: '{}'", doc.title);
println!("Blocks: {}", doc.blocks.len());
for (i, block) in doc.blocks.iter().enumerate() {
println!(
" {}. {:?} - '{}'",
i + 1,
block.block_type,
truncate(&block.content, 30)
);
}
println!();
println!("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
println!("3. CREATING DOCUMENT → SENDING JSON TO FRONTEND");
println!("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n");
let mut new_doc = Document::with_title("New Article".to_string());
new_doc.add_block(Block::new(
BlockType::Header { level: 1 },
"Getting Started with Rust".to_string(),
));
new_doc.add_block(Block::new(
BlockType::Text,
"Rust is a systems programming language focused on safety.".to_string(),
));
new_doc.add_block(Block::new(
BlockType::Code {
language: Some("rust".to_string()),
},
"fn main() {\n println!(\"Hello, world!\");\n}".to_string(),
));
new_doc.add_block(Block::new(
BlockType::Callout {
callout_type: CalloutType::Info,
title: Some("Note".to_string()),
},
"Rust requires cargo to manage dependencies.".to_string(),
));
let json_response = new_doc.to_json_pretty()?;
println!("JSON response for frontend (first 500 chars):");
println!("{}\n", truncate(&json_response, 500));
println!("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
println!("4. BACKEND CONVERSIONS (JSON → Markdown/HTML)");
println!("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n");
let markdown = new_doc.to_markdown()?;
let html = new_doc.to_html()?;
let plain = new_doc.to_plain_text()?;
println!("📝 Markdown output:");
println!("{}\n", truncate(&markdown, 300));
println!("🌐 HTML output:");
println!("{}\n", truncate(&html, 300));
println!("📄 Plain text output:");
println!("{}\n", truncate(&plain, 200));
println!("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
println!("5. SINGLE BLOCK OPERATIONS");
println!("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n");
let button = Block::new(
BlockType::Button {
text: "Subscribe".to_string(),
url: "https://newsletter.example.com".to_string(),
style: ButtonStyle::Primary,
},
String::new(),
);
let block_json = button.to_json()?;
println!("Block as JSON: {}\n", truncate(&block_json, 200));
let block_html = button.to_format(ConversionFormat::Html)?;
let block_md = button.to_format(ConversionFormat::Markdown)?;
println!("Block as HTML: {}", block_html.trim());
println!("Block as Markdown: {}\n", block_md.trim());
println!("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
println!("6. BATCH BLOCK OPERATIONS");
println!("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n");
let blocks_json = r#"[
{"id":"550e8400-e29b-41d4-a716-446655440010","block_type":"Text","content":"First","metadata":{},"created_at":0,"updated_at":0},
{"id":"550e8400-e29b-41d4-a716-446655440011","block_type":"Text","content":"Second","metadata":{},"created_at":0,"updated_at":0},
{"id":"550e8400-e29b-41d4-a716-446655440012","block_type":"Text","content":"Third","metadata":{},"created_at":0,"updated_at":0}
]"#;
let blocks = blocks::Converter::blocks_from_json(blocks_json)?;
println!("Parsed {} blocks from JSON array", blocks.len());
let batch_json = blocks.to_json()?;
println!("Batch JSON (compact): {}\n", truncate(&batch_json, 100));
println!("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
println!("7. IMPORT FROM MARKDOWN/HTML (User Paste)");
println!("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n");
let pasted_markdown = r#"# Pasted Title
Some pasted content with **bold** text.
- List item 1
- List item 2
"#;
let imported_doc = Document::from_markdown(pasted_markdown)?;
let import_json = imported_doc.to_json()?;
println!("User pasted markdown, returning JSON:");
println!(" Blocks imported: {}", imported_doc.blocks.len());
println!(" JSON size: {} bytes\n", import_json.len());
println!("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
println!("8. TYPICAL API RESPONSES");
println!("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n");
println!("GET /documents/123 →");
println!(" Content-Type: application/json");
println!(" Body: {}\n", truncate(&new_doc.to_json()?, 80));
println!("POST /documents/123/export?format=markdown →");
println!(" Content-Type: text/markdown");
println!(" Body: {}\n", truncate(&new_doc.to_markdown()?, 80));
println!("POST /documents/123/export?format=html →");
println!(" Content-Type: text/html");
println!(" Body: {}\n", truncate(&new_doc.to_html()?, 80));
println!("✅ JSON API examples completed!");
Ok(())
}
fn truncate(s: &str, max: usize) -> String {
if s.len() <= max {
s.to_string()
} else {
format!("{}...", &s[..max])
}
}