Rust library to generate static websites
at feat/prerender 288 lines 8.3 kB view raw
1use maudit::content::markdown::components::*; 2 3// Custom heading component that adds icons and anchor links 4pub struct CustomHeading; 5 6impl HeadingComponent for CustomHeading { 7 fn render_start(&self, level: u8, id: Option<&str>, classes: &[&str]) -> String { 8 let id_attr = id.map(|i| format!(" id=\"{}\"", i)).unwrap_or_default(); 9 let class_attr = if classes.is_empty() { 10 String::new() 11 } else { 12 format!(" class=\"{}\"", classes.join(" ")) 13 }; 14 let icon = match level { 15 1 => "🎯", 16 2 => "📌", 17 3 => "", 18 4 => "🔹", 19 5 => "🔸", 20 6 => "💎", 21 _ => "🔷", 22 }; 23 format!("<h{level}{id_attr}{class_attr}>{icon} ") 24 } 25 26 fn render_end(&self, level: u8) -> String { 27 format!("</h{level}>") 28 } 29} 30 31// Custom paragraph with fancy styling 32pub struct CustomParagraph; 33 34impl ParagraphComponent for CustomParagraph { 35 fn render_start(&self) -> String { 36 "<p class=\"prose\">".to_string() 37 } 38 39 fn render_end(&self) -> String { 40 "</p>".to_string() 41 } 42} 43 44// Custom link with external link detection 45pub struct CustomLink; 46 47impl LinkComponent for CustomLink { 48 fn render_start(&self, url: &str, title: Option<&str>, _link_type: LinkType) -> String { 49 let title_attr = title 50 .map(|t| format!(" title=\"{}\"", t)) 51 .unwrap_or_default(); 52 53 let class = if url.starts_with("http") { 54 "external-link" 55 } else { 56 "internal-link" 57 }; 58 59 format!("<a href=\"{}\" class=\"{}\"{}>", url, class, title_attr) 60 } 61 62 fn render_end(&self) -> String { 63 "</a>".to_string() 64 } 65} 66 67// Custom image with figure wrapper 68pub struct CustomImage; 69 70impl ImageComponent for CustomImage { 71 fn render(&self, url: &str, alt: &str, title: Option<&str>) -> String { 72 let title_attr = title 73 .map(|t| format!(" title=\"{}\"", t)) 74 .unwrap_or_default(); 75 76 format!( 77 "<figure class=\"image-wrapper\"><img src=\"{}\" alt=\"{}\" class=\"responsive-image\"{} /><figcaption>{}</figcaption></figure>", 78 url, 79 alt, 80 title_attr, 81 title.unwrap_or_default() 82 ) 83 } 84} 85 86// Custom strong with gradient text 87pub struct CustomStrong; 88 89impl StrongComponent for CustomStrong { 90 fn render_start(&self) -> String { 91 "<strong class=\"gradient-text\">".to_string() 92 } 93 94 fn render_end(&self) -> String { 95 "</strong>".to_string() 96 } 97} 98 99// Custom emphasis with italic styling 100pub struct CustomEmphasis; 101 102impl EmphasisComponent for CustomEmphasis { 103 fn render_start(&self) -> String { 104 "<em class=\"emphasis-text\">".to_string() 105 } 106 107 fn render_end(&self) -> String { 108 "</em>".to_string() 109 } 110} 111 112// Custom inline code with syntax highlighting 113pub struct CustomCode; 114 115impl CodeComponent for CustomCode { 116 fn render(&self, code: &str) -> String { 117 format!("<code class=\"inline-code\">{}</code>", code) 118 } 119} 120 121// Custom blockquote with different styles per type 122pub struct CustomBlockquote; 123 124impl BlockquoteComponent for CustomBlockquote { 125 fn render_start(&self, kind: Option<BlockQuoteKind>) -> String { 126 match kind { 127 Some(BlockQuoteKind::Note) => "<blockquote class=\"blockquote-note\"><div class=\"blockquote-icon\">ℹ️</div><div class=\"blockquote-content\">".to_string(), 128 Some(BlockQuoteKind::Tip) => "<blockquote class=\"blockquote-tip\"><div class=\"blockquote-icon\">💡</div><div class=\"blockquote-content\">".to_string(), 129 Some(BlockQuoteKind::Warning) => "<blockquote class=\"blockquote-warning\"><div class=\"blockquote-icon\">⚠️</div><div class=\"blockquote-content\">".to_string(), 130 Some(BlockQuoteKind::Important) => "<blockquote class=\"blockquote-important\"><div class=\"blockquote-icon\">❗</div><div class=\"blockquote-content\">".to_string(), 131 Some(BlockQuoteKind::Caution) => "<blockquote class=\"blockquote-caution\"><div class=\"blockquote-icon\">🚨</div><div class=\"blockquote-content\">".to_string(), 132 None => "<blockquote class=\"blockquote-default blockquote-content\">".to_string(), 133 } 134 } 135 136 fn render_end(&self, kind: Option<BlockQuoteKind>) -> String { 137 if kind.is_some() { 138 "</div></blockquote>".to_string() 139 } else { 140 "</blockquote>".to_string() 141 } 142 } 143} 144 145// Custom hard break 146pub struct CustomHardBreak; 147 148impl HardBreakComponent for CustomHardBreak { 149 fn render(&self) -> String { 150 "<br class=\"hard-break\" />".to_string() 151 } 152} 153 154// Custom horizontal rule 155pub struct CustomHorizontalRule; 156 157impl HorizontalRuleComponent for CustomHorizontalRule { 158 fn render(&self) -> String { 159 "<hr class=\"custom-hr\" />".to_string() 160 } 161} 162 163// Custom list with different styling 164pub struct CustomList; 165 166impl ListComponent for CustomList { 167 fn render_start(&self, list_type: ListType, start_number: Option<u64>) -> String { 168 match list_type { 169 ListType::Ordered => { 170 let start_attr = start_number 171 .map(|n| format!(" start=\"{}\"", n)) 172 .unwrap_or_default(); 173 format!("<ol class=\"custom-list\" style=\"list-style-type: decimal; list-style-position: inside;\"{}>", start_attr) 174 } 175 ListType::Unordered => { 176 "<ul class=\"custom-list\" style=\"list-style-type: disc; list-style-position: inside;\">".to_string() 177 } 178 } 179 } 180 181 fn render_end(&self, list_type: ListType) -> String { 182 match list_type { 183 ListType::Ordered => "</ol>".to_string(), 184 ListType::Unordered => "</ul>".to_string(), 185 } 186 } 187} 188 189// Custom list item 190pub struct CustomListItem; 191 192impl ListItemComponent for CustomListItem { 193 fn render_start(&self) -> String { 194 "<li>".to_string() 195 } 196 197 fn render_end(&self) -> String { 198 "</li>".to_string() 199 } 200} 201 202// Custom strikethrough 203pub struct CustomStrikethrough; 204 205impl StrikethroughComponent for CustomStrikethrough { 206 fn render_start(&self) -> String { 207 "<del class=\"strikethrough\">".to_string() 208 } 209 210 fn render_end(&self) -> String { 211 "</del>".to_string() 212 } 213} 214 215// Custom task list marker 216pub struct CustomTaskListMarker; 217 218impl TaskListMarkerComponent for CustomTaskListMarker { 219 fn render(&self, checked: bool) -> String { 220 if checked { 221 "<input type=\"checkbox\" checked disabled class=\"task-checkbox\" />".to_string() 222 } else { 223 "<input type=\"checkbox\" disabled class=\"task-checkbox\" />".to_string() 224 } 225 } 226} 227 228// Custom table 229pub struct CustomTable; 230 231impl TableComponent for CustomTable { 232 fn render_start(&self, _alignments: &[TableAlignment]) -> String { 233 "<table class=\"custom-table\">".to_string() 234 } 235 236 fn render_end(&self) -> String { 237 "</table>".to_string() 238 } 239} 240 241// Custom table head 242pub struct CustomTableHead; 243 244impl TableHeadComponent for CustomTableHead { 245 fn render_start(&self) -> String { 246 "<thead class=\"table-header\">".to_string() 247 } 248 249 fn render_end(&self) -> String { 250 "</thead>".to_string() 251 } 252} 253 254// Custom table row 255pub struct CustomTableRow; 256 257impl TableRowComponent for CustomTableRow { 258 fn render_start(&self) -> String { 259 "<tr class=\"table-row\">".to_string() 260 } 261 262 fn render_end(&self) -> String { 263 "</tr>".to_string() 264 } 265} 266 267// Custom table cell 268pub struct CustomTableCell; 269 270impl TableCellComponent for CustomTableCell { 271 fn render_start(&self, is_header: bool, alignment: Option<TableAlignment>) -> String { 272 let tag = if is_header { "th" } else { "td" }; 273 let mut class = "table-cell".to_string(); 274 275 match alignment { 276 Some(TableAlignment::Center) => class.push_str(" center"), 277 Some(TableAlignment::Right) => class.push_str(" right"), 278 _ => {} 279 }; 280 281 format!("<{} class=\"{}\">", tag, class) 282 } 283 284 fn render_end(&self, is_header: bool) -> String { 285 let tag = if is_header { "th" } else { "td" }; 286 format!("</{}>", tag) 287 } 288}