Rust library to generate static websites
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}