Skip to main content

bootstrap_docs/
bootstrap_docs.rs

1//! Bootstrap Documentation Site Example
2//!
3//! This example replicates the structure of the Bootstrap documentation website,
4//! focusing on the Components section. It demonstrates how to build a complete
5//! documentation site using ironhtml-bootstrap.
6//!
7//! Run with: `cargo run --example bootstrap_docs`
8
9use ironhtml::typed::{Document, Element};
10use ironhtml_bootstrap::{
11    accordion, alerts, badge, breadcrumb, buttons, cards, carousel, close_button, collapse,
12    dropdown, list_group, modal, navbar, offcanvas, pagination, placeholder, progress, spinner,
13    toast, tooltip, Color, NavbarExpand, Size,
14};
15use ironhtml_elements::{
16    Body, Br, Button, Div, Form, Head, Html, Input, Li, Link, Main, Meta, Nav, Ol, Script, Section,
17    Span, Style, Title, Ul, A, H1, H2, H4, H5, P,
18};
19
20extern crate alloc;
21use alloc::vec;
22
23// ============================================================
24// DATA STRUCTURES
25// ============================================================
26
27/// Sidebar navigation item
28struct SidebarItem {
29    href: &'static str,
30    label: &'static str,
31    active: bool,
32}
33
34impl SidebarItem {
35    const fn new(href: &'static str, label: &'static str) -> Self {
36        Self {
37            href,
38            label,
39            active: false,
40        }
41    }
42
43    const fn active(mut self) -> Self {
44        self.active = true;
45        self
46    }
47}
48
49// ============================================================
50// LAYOUT COMPONENTS
51// ============================================================
52
53/// Create the docs page header/navbar
54fn docs_navbar() -> Element<Nav> {
55    Element::<Nav>::new()
56        .class("navbar navbar-expand-lg bg-dark navbar-dark sticky-top")
57        .child::<Div, _>(|d| {
58            d.class("container-fluid")
59                .child::<A, _>(|a| {
60                    a.class("navbar-brand")
61                        .attr("href", "/")
62                        .child::<Span, _>(|s| s.class("me-2").text("📘"))
63                        .text("Bootstrap Docs")
64                })
65                .child::<Button, _>(|b| {
66                    b.class("navbar-toggler")
67                        .attr("type", "button")
68                        .attr("data-bs-toggle", "collapse")
69                        .attr("data-bs-target", "#navbarSearch")
70                        .child::<Span, _>(|s| s.class("navbar-toggler-icon"))
71                })
72                .child::<Div, _>(|d| {
73                    d.class("collapse navbar-collapse")
74                        .attr("id", "navbarSearch")
75                        .child::<Ul, _>(|ul| {
76                            ul.class("navbar-nav me-auto")
77                                .child::<Li, _>(|li| {
78                                    li.class("nav-item").child::<A, _>(|a| {
79                                        a.class("nav-link")
80                                            .attr("href", "#")
81                                            .text("Getting Started")
82                                    })
83                                })
84                                .child::<Li, _>(|li| {
85                                    li.class("nav-item").child::<A, _>(|a| {
86                                        a.class("nav-link active")
87                                            .attr("href", "#")
88                                            .text("Components")
89                                    })
90                                })
91                                .child::<Li, _>(|li| {
92                                    li.class("nav-item").child::<A, _>(|a| {
93                                        a.class("nav-link").attr("href", "#").text("Utilities")
94                                    })
95                                })
96                        })
97                        .child::<Form, _>(|f| {
98                            f.class("d-flex")
99                                .attr("role", "search")
100                                .child::<Input, _>(|i| {
101                                    i.class("form-control me-2")
102                                        .attr("type", "search")
103                                        .attr("placeholder", "Search...")
104                                })
105                        })
106                })
107        })
108}
109
110/// Create the sidebar navigation
111fn docs_sidebar(items: &[SidebarItem]) -> Element<Nav> {
112    Element::<Nav>::new()
113        .class("sidebar bg-body-tertiary p-3")
114        .attr("style", "width: 280px; min-height: 100vh;")
115        .child::<H5, _>(|h| h.class("mb-3 text-muted").text("Components"))
116        .child::<Ul, _>(|ul| {
117            items
118                .iter()
119                .fold(ul.class("nav nav-pills flex-column"), |ul, item| {
120                    ul.child::<Li, _>(|li| {
121                        let link_class = if item.active {
122                            "nav-link active"
123                        } else {
124                            "nav-link text-dark"
125                        };
126                        li.class("nav-item").child::<A, _>(|a| {
127                            a.class(link_class).attr("href", item.href).text(item.label)
128                        })
129                    })
130                })
131        })
132}
133
134// ============================================================
135// COMPONENT DOCUMENTATION SECTIONS
136// ============================================================
137
138/// Accordion documentation section
139fn accordion_section() -> Element<Section> {
140    Element::<Section>::new()
141        .attr("id", "accordion")
142        .class("mb-5")
143        .child::<H2, _>(|h| h.class("border-bottom pb-2").text("Accordion"))
144        .child::<P, _>(|p| {
145            p.class("lead").text(
146                "Build vertically collapsing accordions in combination with our Collapse JavaScript plugin.",
147            )
148        })
149        // Basic example
150        .child::<H4, _>(|h| h.class("mt-4").text("Basic Example"))
151        .child::<Div, _>(|d| {
152            d.class("bd-example mb-3").child::<Div, _>(|_| {
153                let items = vec![
154                    accordion::AccordionItem {
155                        id: "one".into(),
156                        header: "Accordion Item #1".into(),
157                        content: "This is the first item's accordion body.".into(),
158                        expanded: true,
159                    },
160                    accordion::AccordionItem {
161                        id: "two".into(),
162                        header: "Accordion Item #2".into(),
163                        content: "This is the second item's accordion body.".into(),
164                        expanded: false,
165                    },
166                    accordion::AccordionItem {
167                        id: "three".into(),
168                        header: "Accordion Item #3".into(),
169                        content: "This is the third item's accordion body.".into(),
170                        expanded: false,
171                    },
172                ];
173                accordion::accordion("accordionExample", &items)
174            })
175        })
176        // Flush variant
177        .child::<H4, _>(|h| h.class("mt-4").text("Flush"))
178        .child::<P, _>(|p| {
179            p.text("Add .accordion-flush to remove borders and rounded corners.")
180        })
181        .child::<Div, _>(|d| {
182            d.class("bd-example mb-3").child::<Div, _>(|_| {
183                let items = vec![
184                    accordion::AccordionItem {
185                        id: "f1".into(),
186                        header: "Accordion Item #1".into(),
187                        content: "Flush accordion content here.".into(),
188                        expanded: false,
189                    },
190                    accordion::AccordionItem {
191                        id: "f2".into(),
192                        header: "Accordion Item #2".into(),
193                        content: "More flush accordion content.".into(),
194                        expanded: false,
195                    },
196                ];
197                accordion::accordion_flush("accordionFlush", &items)
198            })
199        })
200}
201
202/// Alerts documentation section
203fn alerts_section() -> Element<Section> {
204    Element::<Section>::new()
205        .attr("id", "alerts")
206        .class("mb-5")
207        .child::<H2, _>(|h| h.class("border-bottom pb-2").text("Alerts"))
208        .child::<P, _>(|p| {
209            p.class("lead")
210                .text("Provide contextual feedback messages for typical user actions.")
211        })
212        // All color variants
213        .child::<H4, _>(|h| h.class("mt-4").text("Examples"))
214        .child::<Div, _>(|d| {
215            d.class("bd-example mb-3")
216                .child::<Div, _>(|_| alerts::alert(Color::Primary, "A simple primary alert!"))
217                .child::<Div, _>(|_| alerts::alert(Color::Secondary, "A simple secondary alert!"))
218                .child::<Div, _>(|_| alerts::alert(Color::Success, "A simple success alert!"))
219                .child::<Div, _>(|_| alerts::alert(Color::Danger, "A simple danger alert!"))
220                .child::<Div, _>(|_| alerts::alert(Color::Warning, "A simple warning alert!"))
221                .child::<Div, _>(|_| alerts::alert(Color::Info, "A simple info alert!"))
222        })
223        // Dismissible
224        .child::<H4, _>(|h| h.class("mt-4").text("Dismissing"))
225        .child::<P, _>(|p| p.text("Add a dismiss button and the .alert-dismissible class."))
226        .child::<Div, _>(|d| {
227            d.class("bd-example mb-3").child::<Div, _>(|_| {
228                alerts::alert_dismissible(Color::Warning, "Holy guacamole! You should check this.")
229            })
230        })
231        // With heading
232        .child::<H4, _>(|h| h.class("mt-4").text("Additional Content"))
233        .child::<Div, _>(|d| {
234            d.class("bd-example mb-3").child::<Div, _>(|_| {
235                alerts::alert_with_heading(
236                    Color::Success,
237                    "Well done!",
238                    "You successfully read this important alert message.",
239                    "",
240                )
241            })
242        })
243}
244
245/// Badges documentation section
246fn badges_section() -> Element<Section> {
247    Element::<Section>::new()
248        .attr("id", "badges")
249        .class("mb-5")
250        .child::<H2, _>(|h| h.class("border-bottom pb-2").text("Badges"))
251        .child::<P, _>(|p| p.class("lead").text("Small count and labeling component."))
252        // Color variants
253        .child::<H4, _>(|h| h.class("mt-4").text("Background Colors"))
254        .child::<Div, _>(|d| {
255            d.class("bd-example mb-3")
256                .child::<Span, _>(|_| badge::badge(Color::Primary, "Primary"))
257                .text(" ")
258                .child::<Span, _>(|_| badge::badge(Color::Secondary, "Secondary"))
259                .text(" ")
260                .child::<Span, _>(|_| badge::badge(Color::Success, "Success"))
261                .text(" ")
262                .child::<Span, _>(|_| badge::badge(Color::Danger, "Danger"))
263                .text(" ")
264                .child::<Span, _>(|_| badge::badge(Color::Warning, "Warning"))
265                .text(" ")
266                .child::<Span, _>(|_| badge::badge(Color::Info, "Info"))
267        })
268        // Pill badges
269        .child::<H4, _>(|h| h.class("mt-4").text("Pill Badges"))
270        .child::<Div, _>(|d| {
271            d.class("bd-example mb-3")
272                .child::<Span, _>(|_| badge::badge_pill(Color::Primary, "Primary"))
273                .text(" ")
274                .child::<Span, _>(|_| badge::badge_pill(Color::Success, "Success"))
275                .text(" ")
276                .child::<Span, _>(|_| badge::badge_pill(Color::Danger, "99+"))
277        })
278}
279
280/// Breadcrumb documentation section
281fn breadcrumb_section() -> Element<Section> {
282    Element::<Section>::new()
283        .attr("id", "breadcrumb")
284        .class("mb-5")
285        .child::<H2, _>(|h| h.class("border-bottom pb-2").text("Breadcrumb"))
286        .child::<P, _>(|p| {
287            p.class("lead")
288                .text("Indicate the current page's location within a navigational hierarchy.")
289        })
290        .child::<H4, _>(|h| h.class("mt-4").text("Example"))
291        .child::<Div, _>(|d| {
292            d.class("bd-example mb-3").child::<Nav, _>(|_| {
293                let items = vec![
294                    breadcrumb::BreadcrumbItem::link("Home", "/"),
295                    breadcrumb::BreadcrumbItem::link("Library", "/library"),
296                    breadcrumb::BreadcrumbItem::active("Data"),
297                ];
298                breadcrumb::breadcrumb(&items)
299            })
300        })
301        .child::<Div, _>(|d| {
302            d.class("bd-example mb-3").child::<Nav, _>(|_| {
303                let items = vec![breadcrumb::BreadcrumbItem::active("Home")];
304                breadcrumb::breadcrumb(&items)
305            })
306        })
307}
308
309/// Buttons documentation section
310fn buttons_section() -> Element<Section> {
311    Element::<Section>::new()
312        .attr("id", "buttons")
313        .class("mb-5")
314        .child::<H2, _>(|h| h.class("border-bottom pb-2").text("Buttons"))
315        .child::<P, _>(|p| {
316            p.class("lead").text(
317                "Use Bootstrap's custom button styles for actions in forms, dialogs, and more.",
318            )
319        })
320        // Base styles
321        .child::<H4, _>(|h| h.class("mt-4").text("Base Class"))
322        .child::<Div, _>(|d| {
323            d.class("bd-example mb-3")
324                .child::<Button, _>(|_| buttons::btn(Color::Primary, "Primary"))
325                .text(" ")
326                .child::<Button, _>(|_| buttons::btn(Color::Secondary, "Secondary"))
327                .text(" ")
328                .child::<Button, _>(|_| buttons::btn(Color::Success, "Success"))
329                .text(" ")
330                .child::<Button, _>(|_| buttons::btn(Color::Danger, "Danger"))
331                .text(" ")
332                .child::<Button, _>(|_| buttons::btn(Color::Warning, "Warning"))
333                .text(" ")
334                .child::<Button, _>(|_| buttons::btn(Color::Info, "Info"))
335                .text(" ")
336                .child::<Button, _>(|_| buttons::btn(Color::Light, "Light"))
337                .text(" ")
338                .child::<Button, _>(|_| buttons::btn(Color::Dark, "Dark"))
339        })
340        // Outline buttons
341        .child::<H4, _>(|h| h.class("mt-4").text("Outline Buttons"))
342        .child::<Div, _>(|d| {
343            d.class("bd-example mb-3")
344                .child::<Button, _>(|_| buttons::btn_outline(Color::Primary, "Primary"))
345                .text(" ")
346                .child::<Button, _>(|_| buttons::btn_outline(Color::Secondary, "Secondary"))
347                .text(" ")
348                .child::<Button, _>(|_| buttons::btn_outline(Color::Success, "Success"))
349                .text(" ")
350                .child::<Button, _>(|_| buttons::btn_outline(Color::Danger, "Danger"))
351        })
352        // Sizes
353        .child::<H4, _>(|h| h.class("mt-4").text("Sizes"))
354        .child::<Div, _>(|d| {
355            d.class("bd-example mb-3")
356                .child::<Button, _>(|_| buttons::btn_sized(Color::Primary, Size::Large, "Large"))
357                .text(" ")
358                .child::<Button, _>(|_| buttons::btn(Color::Primary, "Default"))
359                .text(" ")
360                .child::<Button, _>(|_| buttons::btn_sized(Color::Primary, Size::Small, "Small"))
361        })
362        // Disabled
363        .child::<H4, _>(|h| h.class("mt-4").text("Disabled State"))
364        .child::<Div, _>(|d| {
365            d.class("bd-example mb-3")
366                .child::<Button, _>(|_| buttons::btn_disabled(Color::Primary, "Disabled"))
367                .text(" ")
368                .child::<Button, _>(|_| buttons::btn_disabled(Color::Secondary, "Disabled"))
369        })
370}
371
372/// Cards documentation section
373fn cards_section() -> Element<Section> {
374    Element::<Section>::new()
375        .attr("id", "cards")
376        .class("mb-5")
377        .child::<H2, _>(|h| h.class("border-bottom pb-2").text("Cards"))
378        .child::<P, _>(|p| {
379            p.class("lead").text(
380                "Bootstrap's cards provide a flexible and extensible content container.",
381            )
382        })
383        // Basic card
384        .child::<H4, _>(|h| h.class("mt-4").text("Example"))
385        .child::<Div, _>(|d| {
386            d.class("bd-example mb-3")
387                .attr("style", "max-width: 18rem;")
388                .child::<Div, _>(|_| {
389                    cards::card_simple(
390                        "Card title",
391                        "Some quick example text to build on the card title and make up the bulk of the card's content.",
392                        "Go somewhere",
393                        "#",
394                    )
395                })
396        })
397        // Card with image
398        .child::<H4, _>(|h| h.class("mt-4").text("Image Caps"))
399        .child::<Div, _>(|d| {
400            d.class("bd-example mb-3")
401                .attr("style", "max-width: 18rem;")
402                .child::<Div, _>(|_| {
403                    cards::card_with_image(
404                        "https://via.placeholder.com/286x180",
405                        "Card image cap",
406                        "Card title",
407                        "This is a wider card with supporting text below.",
408                    )
409                })
410        })
411        // Card with header/footer
412        .child::<H4, _>(|h| h.class("mt-4").text("Header and Footer"))
413        .child::<Div, _>(|d| {
414            d.class("bd-example mb-3")
415                .attr("style", "max-width: 18rem;")
416                .child::<Div, _>(|_| {
417                    cards::card_with_header_footer("Featured", "Footer text", |body| {
418                        body.child::<H5, _>(|h| h.class("card-title").text("Special title treatment"))
419                            .child::<P, _>(|p| {
420                                p.class("card-text").text(
421                                    "With supporting text below as a natural lead-in to additional content.",
422                                )
423                            })
424                    })
425                })
426        })
427}
428
429/// List Group documentation section
430fn list_group_section() -> Element<Section> {
431    Element::<Section>::new()
432        .attr("id", "list-group")
433        .class("mb-5")
434        .child::<H2, _>(|h| h.class("border-bottom pb-2").text("List Group"))
435        .child::<P, _>(|p| {
436            p.class("lead")
437                .text("List groups are a flexible and powerful component for displaying lists.")
438        })
439        // Basic example
440        .child::<H4, _>(|h| h.class("mt-4").text("Basic Example"))
441        .child::<Div, _>(|d| {
442            d.class("bd-example mb-3")
443                .attr("style", "max-width: 400px;")
444                .child::<Ul, _>(|_| {
445                    list_group::list_group(&["An item", "A second item", "A third item"])
446                })
447        })
448        // With links
449        .child::<H4, _>(|h| h.class("mt-4").text("Links and Buttons"))
450        .child::<Div, _>(|d| {
451            d.class("bd-example mb-3")
452                .attr("style", "max-width: 400px;")
453                .child::<Div, _>(|_| {
454                    let items = vec![
455                        list_group::ListGroupLink::new("The current link item", "#").active(),
456                        list_group::ListGroupLink::new("A second link item", "#"),
457                        list_group::ListGroupLink::new("A third link item", "#"),
458                        list_group::ListGroupLink::new("A disabled link item", "#").disabled(),
459                    ];
460                    list_group::list_group_links(&items)
461                })
462        })
463        // Flush
464        .child::<H4, _>(|h| h.class("mt-4").text("Flush"))
465        .child::<Div, _>(|d| {
466            d.class("bd-example mb-3")
467                .attr("style", "max-width: 400px;")
468                .child::<Ul, _>(|_| {
469                    list_group::list_group_flush(&["An item", "A second item", "A third item"])
470                })
471        })
472        // Numbered
473        .child::<H4, _>(|h| h.class("mt-4").text("Numbered"))
474        .child::<Div, _>(|d| {
475            d.class("bd-example mb-3")
476                .attr("style", "max-width: 400px;")
477                .child::<Ol, _>(|_| {
478                    list_group::list_group_numbered(&["A list item", "A list item", "A list item"])
479                })
480        })
481}
482
483/// Progress documentation section
484fn progress_section() -> Element<Section> {
485    Element::<Section>::new()
486        .attr("id", "progress")
487        .class("mb-5")
488        .child::<H2, _>(|h| h.class("border-bottom pb-2").text("Progress"))
489        .child::<P, _>(|p| {
490            p.class("lead")
491                .text("Documentation and examples for using Bootstrap custom progress bars.")
492        })
493        // Basic example
494        .child::<H4, _>(|h| h.class("mt-4").text("Example"))
495        .child::<Div, _>(|d| {
496            d.class("bd-example mb-3")
497                .child::<Div, _>(|d| d.class("mb-2").child::<Div, _>(|_| progress::progress(0)))
498                .child::<Div, _>(|d| d.class("mb-2").child::<Div, _>(|_| progress::progress(25)))
499                .child::<Div, _>(|d| d.class("mb-2").child::<Div, _>(|_| progress::progress(50)))
500                .child::<Div, _>(|d| d.class("mb-2").child::<Div, _>(|_| progress::progress(75)))
501                .child::<Div, _>(|d| d.class("mb-2").child::<Div, _>(|_| progress::progress(100)))
502        })
503        // Colored
504        .child::<H4, _>(|h| h.class("mt-4").text("Backgrounds"))
505        .child::<Div, _>(|d| {
506            d.class("bd-example mb-3")
507                .child::<Div, _>(|d| {
508                    d.class("mb-2")
509                        .child::<Div, _>(|_| progress::progress_colored(25, Color::Success))
510                })
511                .child::<Div, _>(|d| {
512                    d.class("mb-2")
513                        .child::<Div, _>(|_| progress::progress_colored(50, Color::Info))
514                })
515                .child::<Div, _>(|d| {
516                    d.class("mb-2")
517                        .child::<Div, _>(|_| progress::progress_colored(75, Color::Warning))
518                })
519                .child::<Div, _>(|d| {
520                    d.class("mb-2")
521                        .child::<Div, _>(|_| progress::progress_colored(100, Color::Danger))
522                })
523        })
524        // Striped
525        .child::<H4, _>(|h| h.class("mt-4").text("Striped"))
526        .child::<Div, _>(|d| {
527            d.class("bd-example mb-3")
528                .child::<Div, _>(|d| {
529                    d.class("mb-2")
530                        .child::<Div, _>(|_| progress::progress_striped(25, Color::Primary))
531                })
532                .child::<Div, _>(|d| {
533                    d.class("mb-2")
534                        .child::<Div, _>(|_| progress::progress_striped(50, Color::Success))
535                })
536        })
537        // Animated
538        .child::<H4, _>(|h| h.class("mt-4").text("Animated Stripes"))
539        .child::<Div, _>(|d| {
540            d.class("bd-example mb-3")
541                .child::<Div, _>(|_| progress::progress_animated(75, Color::Primary))
542        })
543}
544
545/// Spinners documentation section
546fn spinners_section() -> Element<Section> {
547    Element::<Section>::new()
548        .attr("id", "spinners")
549        .class("mb-5")
550        .child::<H2, _>(|h| h.class("border-bottom pb-2").text("Spinners"))
551        .child::<P, _>(|p| {
552            p.class("lead")
553                .text("Indicate the loading state of a component or page with Bootstrap spinners.")
554        })
555        // Border spinner
556        .child::<H4, _>(|h| h.class("mt-4").text("Border Spinner"))
557        .child::<Div, _>(|d| {
558            d.class("bd-example mb-3")
559                .child::<Div, _>(|_| spinner::spinner())
560        })
561        // Colors
562        .child::<H4, _>(|h| h.class("mt-4").text("Colors"))
563        .child::<Div, _>(|d| {
564            d.class("bd-example mb-3")
565                .child::<Div, _>(|d| {
566                    d.class("d-inline-block me-2")
567                        .child::<Div, _>(|_| spinner::spinner_colored(Color::Primary))
568                })
569                .child::<Div, _>(|d| {
570                    d.class("d-inline-block me-2")
571                        .child::<Div, _>(|_| spinner::spinner_colored(Color::Secondary))
572                })
573                .child::<Div, _>(|d| {
574                    d.class("d-inline-block me-2")
575                        .child::<Div, _>(|_| spinner::spinner_colored(Color::Success))
576                })
577                .child::<Div, _>(|d| {
578                    d.class("d-inline-block me-2")
579                        .child::<Div, _>(|_| spinner::spinner_colored(Color::Danger))
580                })
581                .child::<Div, _>(|d| {
582                    d.class("d-inline-block me-2")
583                        .child::<Div, _>(|_| spinner::spinner_colored(Color::Warning))
584                })
585                .child::<Div, _>(|d| {
586                    d.class("d-inline-block me-2")
587                        .child::<Div, _>(|_| spinner::spinner_colored(Color::Info))
588                })
589        })
590        // Growing spinner
591        .child::<H4, _>(|h| h.class("mt-4").text("Growing Spinner"))
592        .child::<Div, _>(|d| {
593            d.class("bd-example mb-3")
594                .child::<Div, _>(|_| spinner::spinner_grow())
595        })
596        // Small spinners
597        .child::<H4, _>(|h| h.class("mt-4").text("Size"))
598        .child::<Div, _>(|d| {
599            d.class("bd-example mb-3")
600                .child::<Span, _>(|s| s.class("me-2").child::<Span, _>(|_| spinner::spinner_sm()))
601                .child::<Span, _>(|_| spinner::spinner_grow_sm())
602        })
603        // Button with spinner
604        .child::<H4, _>(|h| h.class("mt-4").text("Buttons"))
605        .child::<Div, _>(|d| {
606            d.class("bd-example mb-3")
607                .child::<Button, _>(|_| buttons::btn_loading(Color::Primary, "Loading..."))
608                .text(" ")
609                .child::<Button, _>(|_| buttons::btn_loading_grow(Color::Primary, "Loading..."))
610        })
611}
612
613/// Navbar documentation section
614fn navbar_section() -> Element<Section> {
615    Element::<Section>::new()
616        .attr("id", "navbar")
617        .class("mb-5")
618        .child::<H2, _>(|h| h.class("border-bottom pb-2").text("Navbar"))
619        .child::<P, _>(|p| {
620            p.class("lead").text(
621                "Documentation and examples for Bootstrap's powerful, responsive navigation header.",
622            )
623        })
624        .child::<H4, _>(|h| h.class("mt-4").text("Example"))
625        .child::<Div, _>(|d| {
626            d.class("bd-example mb-3").child::<Nav, _>(|_| {
627                navbar::navbar("Navbar", NavbarExpand::Lg, "navbarExample", |ul| {
628                    ul.child::<Li, _>(|_| navbar::nav_item("/", "Home", true))
629                        .child::<Li, _>(|_| navbar::nav_item("/features", "Features", false))
630                        .child::<Li, _>(|_| navbar::nav_item("/pricing", "Pricing", false))
631                        .child::<Li, _>(|_| navbar::nav_item_disabled("Disabled"))
632                })
633            })
634        })
635}
636
637/// Carousel documentation section
638fn carousel_section() -> Element<Section> {
639    Element::<Section>::new()
640        .attr("id", "carousel")
641        .class("mb-5")
642        .child::<H2, _>(|h| h.class("border-bottom pb-2").text("Carousel"))
643        .child::<P, _>(|p| {
644            p.class("lead")
645                .text("A slideshow component for cycling through elements.")
646        })
647        .child::<H4, _>(|h| h.class("mt-4").text("Basic Example"))
648        .child::<Div, _>(|d| {
649            d.class("bd-example mb-3").child::<Div, _>(|_| {
650                let items = vec![
651                    carousel::CarouselItem::new(
652                        "https://via.placeholder.com/800x400/007bff/ffffff?text=First+Slide",
653                        "First slide",
654                    )
655                    .active()
656                    .caption(
657                        "First slide label",
658                        "Some representative placeholder content.",
659                    ),
660                    carousel::CarouselItem::new(
661                        "https://via.placeholder.com/800x400/6c757d/ffffff?text=Second+Slide",
662                        "Second slide",
663                    )
664                    .caption("Second slide label", "Some more placeholder content."),
665                    carousel::CarouselItem::new(
666                        "https://via.placeholder.com/800x400/28a745/ffffff?text=Third+Slide",
667                        "Third slide",
668                    )
669                    .caption("Third slide label", "Even more placeholder content."),
670                ];
671                carousel::carousel_with_indicators("carouselExample", &items)
672            })
673        })
674}
675
676/// Close Button documentation section
677fn close_button_section() -> Element<Section> {
678    Element::<Section>::new()
679        .attr("id", "close-button")
680        .class("mb-5")
681        .child::<H2, _>(|h| h.class("border-bottom pb-2").text("Close Button"))
682        .child::<P, _>(|p| {
683            p.class("lead")
684                .text("A generic close button for dismissing content like modals and alerts.")
685        })
686        .child::<H4, _>(|h| h.class("mt-4").text("Examples"))
687        .child::<Div, _>(|d| {
688            d.class("bd-example mb-3")
689                .child::<Button, _>(|_| close_button::close_button())
690        })
691        .child::<H4, _>(|h| h.class("mt-4").text("Disabled"))
692        .child::<Div, _>(|d| {
693            d.class("bd-example mb-3")
694                .child::<Button, _>(|_| close_button::close_button_disabled())
695        })
696        .child::<H4, _>(|h| h.class("mt-4").text("Dark Variant"))
697        .child::<Div, _>(|d| {
698            d.class("bd-example mb-3 bg-dark p-3")
699                .child::<Button, _>(|_| close_button::close_button_white())
700        })
701}
702
703/// Collapse documentation section
704fn collapse_section() -> Element<Section> {
705    Element::<Section>::new()
706        .attr("id", "collapse")
707        .class("mb-5")
708        .child::<H2, _>(|h| h.class("border-bottom pb-2").text("Collapse"))
709        .child::<P, _>(|p| {
710            p.class("lead")
711                .text("Toggle the visibility of content with a few classes and JavaScript plugins.")
712        })
713        .child::<H4, _>(|h| h.class("mt-4").text("Example"))
714        .child::<Div, _>(|d| {
715            d.class("bd-example mb-3")
716                .child::<P, _>(|p| {
717                    p.child::<Button, _>(|_| {
718                        collapse::collapse_button("collapseExample", "Toggle content")
719                    })
720                    .text(" ")
721                    .child::<A, _>(|_| collapse::collapse_link("collapseExample", "Link"))
722                })
723                .child::<Div, _>(|_| {
724                    collapse::collapse_content("collapseExample", |div| {
725                        div.child::<Div, _>(|d| {
726                            d.class("card card-body")
727                                .text("Some placeholder content for the collapse component.")
728                        })
729                    })
730                })
731        })
732}
733
734/// Dropdown documentation section
735fn dropdown_section() -> Element<Section> {
736    Element::<Section>::new()
737        .attr("id", "dropdowns")
738        .class("mb-5")
739        .child::<H2, _>(|h| h.class("border-bottom pb-2").text("Dropdowns"))
740        .child::<P, _>(|p| {
741            p.class("lead")
742                .text("Toggle contextual overlays for displaying lists of links and more.")
743        })
744        .child::<H4, _>(|h| h.class("mt-4").text("Single Button"))
745        .child::<Div, _>(|d| {
746            d.class("bd-example mb-3").child::<Div, _>(|_| {
747                let items = vec![
748                    dropdown::DropdownItem::link("Action", "#"),
749                    dropdown::DropdownItem::link("Another action", "#"),
750                    dropdown::DropdownItem::divider(),
751                    dropdown::DropdownItem::link("Separated link", "#"),
752                ];
753                dropdown::dropdown(Color::Primary, "Dropdown button", &items)
754            })
755        })
756        .child::<H4, _>(|h| h.class("mt-4").text("Split Button"))
757        .child::<Div, _>(|d| {
758            d.class("bd-example mb-3").child::<Div, _>(|_| {
759                let items = vec![
760                    dropdown::DropdownItem::link("Action", "#"),
761                    dropdown::DropdownItem::link("Another action", "#"),
762                    dropdown::DropdownItem::divider(),
763                    dropdown::DropdownItem::link("Separated link", "#"),
764                ];
765                dropdown::dropdown_split(Color::Success, "Action", "#", &items)
766            })
767        })
768        .child::<H4, _>(|h| h.class("mt-4").text("Directions"))
769        .child::<Div, _>(|d| {
770            let items = vec![dropdown::DropdownItem::link("Action", "#")];
771            d.class("bd-example mb-3")
772                .child::<Div, _>(|d| {
773                    d.class("d-inline-block me-2")
774                        .child::<Div, _>(|_| dropdown::dropup(Color::Secondary, "Dropup", &items))
775                })
776                .child::<Div, _>(|d| {
777                    d.class("d-inline-block me-2")
778                        .child::<Div, _>(|_| dropdown::dropend(Color::Secondary, "Dropend", &items))
779                })
780                .child::<Div, _>(|d| {
781                    d.class("d-inline-block").child::<Div, _>(|_| {
782                        dropdown::dropstart(Color::Secondary, "Dropstart", &items)
783                    })
784                })
785        })
786}
787
788/// Modal documentation section
789fn modal_section() -> Element<Section> {
790    Element::<Section>::new()
791        .attr("id", "modal")
792        .class("mb-5")
793        .child::<H2, _>(|h| h.class("border-bottom pb-2").text("Modal"))
794        .child::<P, _>(|p| {
795            p.class("lead")
796                .text("Add dialogs to your site for lightboxes, notifications, or custom content.")
797        })
798        .child::<H4, _>(|h| h.class("mt-4").text("Live Demo"))
799        .child::<Div, _>(|d| {
800            d.class("bd-example mb-3")
801                .child::<Button, _>(|_| {
802                    modal::modal_button("exampleModal", Color::Primary, "Launch demo modal")
803                })
804                .child::<Div, _>(|_| {
805                    modal::modal_with_footer(
806                        "exampleModal",
807                        modal::ModalSize::Default,
808                        "Modal title",
809                        |body| body.text("This is modal body content."),
810                        "Save changes",
811                    )
812                })
813        })
814        .child::<H4, _>(|h| h.class("mt-4").text("Sizes"))
815        .child::<P, _>(|p| {
816            p.text("Modals come in small, default, large, extra-large, and fullscreen sizes.")
817        })
818        .child::<Div, _>(|d| {
819            d.class("bd-example mb-3")
820                .child::<Button, _>(|_| {
821                    modal::modal_button("smallModal", Color::Primary, "Small modal")
822                })
823                .text(" ")
824                .child::<Button, _>(|_| {
825                    modal::modal_button("largeModal", Color::Primary, "Large modal")
826                })
827                .text(" ")
828                .child::<Button, _>(|_| {
829                    modal::modal_button("xlModal", Color::Primary, "Extra large modal")
830                })
831        })
832}
833
834/// Offcanvas documentation section
835fn offcanvas_section() -> Element<Section> {
836    Element::<Section>::new()
837        .attr("id", "offcanvas")
838        .class("mb-5")
839        .child::<H2, _>(|h| h.class("border-bottom pb-2").text("Offcanvas"))
840        .child::<P, _>(|p| {
841            p.class("lead")
842                .text("Build hidden sidebars into your project for navigation and more.")
843        })
844        .child::<H4, _>(|h| h.class("mt-4").text("Example"))
845        .child::<Div, _>(|d| {
846            d.class("bd-example mb-3")
847                .child::<Button, _>(|_| {
848                    offcanvas::offcanvas_button("offcanvasExample", Color::Primary, "Toggle offcanvas")
849                })
850                .child::<Div, _>(|_| {
851                    offcanvas::offcanvas(
852                        "offcanvasExample",
853                        offcanvas::OffcanvasPlacement::Start,
854                        "Offcanvas",
855                        |body| {
856                            body.text("Some text as placeholder. In real life you can have elements here.")
857                        },
858                    )
859                })
860        })
861        .child::<H4, _>(|h| h.class("mt-4").text("Placement"))
862        .child::<P, _>(|p| {
863            p.text("Offcanvas can be placed on the start, end, top, or bottom of the viewport.")
864        })
865}
866
867/// Pagination documentation section
868fn pagination_section() -> Element<Section> {
869    Element::<Section>::new()
870        .attr("id", "pagination")
871        .class("mb-5")
872        .child::<H2, _>(|h| h.class("border-bottom pb-2").text("Pagination"))
873        .child::<P, _>(|p| {
874            p.class("lead")
875                .text("Indicate a series of related content exists across multiple pages.")
876        })
877        .child::<H4, _>(|h| h.class("mt-4").text("Basic Example"))
878        .child::<Div, _>(|d| {
879            d.class("bd-example mb-3").child::<Nav, _>(|_| {
880                let items = vec![
881                    pagination::PageItem::page(1, "#").active(),
882                    pagination::PageItem::page(2, "#"),
883                    pagination::PageItem::page(3, "#"),
884                ];
885                pagination::pagination(&items)
886            })
887        })
888        .child::<H4, _>(|h| h.class("mt-4").text("With Icons"))
889        .child::<Div, _>(|d| {
890            d.class("bd-example mb-3").child::<Nav, _>(|_| {
891                let items = vec![
892                    pagination::PageItem::page(1, "#").active(),
893                    pagination::PageItem::page(2, "#"),
894                    pagination::PageItem::page(3, "#"),
895                ];
896                pagination::pagination_with_arrows(&items, Some("#"), Some("#"))
897            })
898        })
899        .child::<H4, _>(|h| h.class("mt-4").text("Sizes"))
900        .child::<Div, _>(|d| {
901            let items = vec![
902                pagination::PageItem::page(1, "#").active(),
903                pagination::PageItem::page(2, "#"),
904                pagination::PageItem::page(3, "#"),
905            ];
906            d.class("bd-example mb-3")
907                .child::<Nav, _>(|_| {
908                    pagination::pagination_sized(&items, pagination::PaginationSize::Large)
909                })
910                .child::<Nav, _>(|_| {
911                    pagination::pagination_sized(&items, pagination::PaginationSize::Small)
912                })
913        })
914}
915
916/// Placeholder documentation section
917fn placeholder_section() -> Element<Section> {
918    Element::<Section>::new()
919        .attr("id", "placeholders")
920        .class("mb-5")
921        .child::<H2, _>(|h| h.class("border-bottom pb-2").text("Placeholders"))
922        .child::<P, _>(|p| {
923            p.class("lead")
924                .text("Use loading placeholders for your components or pages to indicate content is loading.")
925        })
926        .child::<H4, _>(|h| h.class("mt-4").text("Example"))
927        .child::<Div, _>(|d| {
928            d.class("bd-example mb-3")
929                .attr("style", "max-width: 18rem;")
930                .child::<Div, _>(|_| placeholder::placeholder_card())
931        })
932        .child::<H4, _>(|h| h.class("mt-4").text("Width"))
933        .child::<Div, _>(|d| {
934            d.class("bd-example mb-3")
935                .child::<Span, _>(|_| placeholder::placeholder(placeholder::PlaceholderWidth::Col6))
936                .child::<Br, _>(|b| b)
937                .child::<Span, _>(|_| placeholder::placeholder(placeholder::PlaceholderWidth::Col4))
938                .child::<Br, _>(|b| b)
939                .child::<Span, _>(|_| placeholder::placeholder(placeholder::PlaceholderWidth::Col8))
940        })
941        .child::<H4, _>(|h| h.class("mt-4").text("Color"))
942        .child::<Div, _>(|d| {
943            d.class("bd-example mb-3")
944                .child::<Span, _>(|_| {
945                    placeholder::placeholder_colored(placeholder::PlaceholderWidth::Col12, Color::Primary)
946                })
947                .child::<Br, _>(|b| b)
948                .child::<Span, _>(|_| {
949                    placeholder::placeholder_colored(placeholder::PlaceholderWidth::Col12, Color::Success)
950                })
951                .child::<Br, _>(|b| b)
952                .child::<Span, _>(|_| {
953                    placeholder::placeholder_colored(placeholder::PlaceholderWidth::Col12, Color::Danger)
954                })
955        })
956}
957
958/// Toast documentation section
959fn toast_section() -> Element<Section> {
960    Element::<Section>::new()
961        .attr("id", "toasts")
962        .class("mb-5")
963        .child::<H2, _>(|h| h.class("border-bottom pb-2").text("Toasts"))
964        .child::<P, _>(|p| {
965            p.class("lead")
966                .text("Push notifications to your visitors with a toast, a lightweight and customizable alert message.")
967        })
968        .child::<H4, _>(|h| h.class("mt-4").text("Basic"))
969        .child::<Div, _>(|d| {
970            d.class("bd-example mb-3")
971                .child::<Div, _>(|_| toast::toast_show("Hello, world! This is a toast message.", "11 mins ago"))
972        })
973        .child::<H4, _>(|h| h.class("mt-4").text("Color Schemes"))
974        .child::<Div, _>(|d| {
975            d.class("bd-example mb-3")
976                .child::<Div, _>(|d| {
977                    d.class("mb-2")
978                        .child::<Div, _>(|_| toast::toast_colored(Color::Primary, "Primary toast message."))
979                })
980                .child::<Div, _>(|d| {
981                    d.class("mb-2")
982                        .child::<Div, _>(|_| toast::toast_colored(Color::Success, "Success toast message."))
983                })
984                .child::<Div, _>(|d| {
985                    d.class("mb-2")
986                        .child::<Div, _>(|_| toast::toast_colored(Color::Danger, "Danger toast message."))
987                })
988        })
989}
990
991/// Tooltip documentation section
992fn tooltip_section() -> Element<Section> {
993    Element::<Section>::new()
994        .attr("id", "tooltips")
995        .class("mb-5")
996        .child::<H2, _>(|h| h.class("border-bottom pb-2").text("Tooltips"))
997        .child::<P, _>(|p| {
998            p.class("lead")
999                .text("Tooltips and popovers powered by CSS and JavaScript.")
1000        })
1001        .child::<H4, _>(|h| h.class("mt-4").text("Tooltips"))
1002        .child::<Div, _>(|d| {
1003            d.class("bd-example mb-3")
1004                .child::<Button, _>(|_| {
1005                    tooltip::tooltip_button(
1006                        Color::Secondary,
1007                        "Tooltip on top",
1008                        "Tooltip on top",
1009                        tooltip::Placement::Top,
1010                    )
1011                })
1012                .text(" ")
1013                .child::<Button, _>(|_| {
1014                    tooltip::tooltip_button(
1015                        Color::Secondary,
1016                        "Tooltip on right",
1017                        "Tooltip on right",
1018                        tooltip::Placement::Right,
1019                    )
1020                })
1021                .text(" ")
1022                .child::<Button, _>(|_| {
1023                    tooltip::tooltip_button(
1024                        Color::Secondary,
1025                        "Tooltip on bottom",
1026                        "Tooltip on bottom",
1027                        tooltip::Placement::Bottom,
1028                    )
1029                })
1030                .text(" ")
1031                .child::<Button, _>(|_| {
1032                    tooltip::tooltip_button(
1033                        Color::Secondary,
1034                        "Tooltip on left",
1035                        "Tooltip on left",
1036                        tooltip::Placement::Left,
1037                    )
1038                })
1039        })
1040        .child::<H4, _>(|h| h.class("mt-4").text("Popovers"))
1041        .child::<Div, _>(|d| {
1042            d.class("bd-example mb-3").child::<Button, _>(|_| {
1043                tooltip::popover_button(
1044                    Color::Danger,
1045                    "Click to toggle popover",
1046                    "Popover title",
1047                    "And here's some amazing content. It's very engaging.",
1048                    tooltip::Placement::Right,
1049                )
1050            })
1051        })
1052}
1053
1054// ============================================================
1055// PAGE COMPOSITION
1056// ============================================================
1057
1058/// Sidebar navigation items for the docs page
1059fn sidebar_items() -> alloc::vec::Vec<SidebarItem> {
1060    alloc::vec![
1061        SidebarItem::new("#accordion", "Accordion"),
1062        SidebarItem::new("#alerts", "Alerts").active(),
1063        SidebarItem::new("#badges", "Badges"),
1064        SidebarItem::new("#breadcrumb", "Breadcrumb"),
1065        SidebarItem::new("#buttons", "Buttons"),
1066        SidebarItem::new("#cards", "Cards"),
1067        SidebarItem::new("#carousel", "Carousel"),
1068        SidebarItem::new("#close-button", "Close Button"),
1069        SidebarItem::new("#collapse", "Collapse"),
1070        SidebarItem::new("#dropdowns", "Dropdowns"),
1071        SidebarItem::new("#list-group", "List Group"),
1072        SidebarItem::new("#modal", "Modal"),
1073        SidebarItem::new("#navbar", "Navbar"),
1074        SidebarItem::new("#offcanvas", "Offcanvas"),
1075        SidebarItem::new("#pagination", "Pagination"),
1076        SidebarItem::new("#placeholders", "Placeholders"),
1077        SidebarItem::new("#progress", "Progress"),
1078        SidebarItem::new("#spinners", "Spinners"),
1079        SidebarItem::new("#toasts", "Toasts"),
1080        SidebarItem::new("#tooltips", "Tooltips"),
1081    ]
1082}
1083
1084/// Build the complete documentation page
1085fn build_docs_page() -> Document {
1086    let sidebar_items = sidebar_items();
1087
1088    Document::new()
1089        .doctype()
1090        .root::<Html, _>(|html| {
1091            html.attr("lang", "en")
1092                .attr("data-bs-theme", "light")
1093                .child::<Head, _>(|h| {
1094                    h.child::<Meta, _>(|m| m.attr("charset", "UTF-8"))
1095                        .child::<Meta, _>(|m| {
1096                            m.attr("name", "viewport")
1097                                .attr("content", "width=device-width, initial-scale=1")
1098                        })
1099                        .child::<Title, _>(|t| t.text("Bootstrap Components - Documentation"))
1100                        .child::<Link, _>(|l| {
1101                            l.attr(
1102                                "href",
1103                                "https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css",
1104                            )
1105                            .attr("rel", "stylesheet")
1106                        })
1107                        .child::<Style, _>(|s| {
1108                            s.text(
1109                                r"
1110                            .bd-example {
1111                                padding: 1.5rem;
1112                                border: 1px solid #dee2e6;
1113                                border-radius: 0.375rem;
1114                                background-color: #fff;
1115                            }
1116                            .sidebar {
1117                                position: sticky;
1118                                top: 56px;
1119                                height: calc(100vh - 56px);
1120                                overflow-y: auto;
1121                            }
1122                            section {
1123                                scroll-margin-top: 70px;
1124                            }
1125                        ",
1126                            )
1127                        })
1128                })
1129                .child::<Body, _>(|body| {
1130                    body.child::<Nav, _>(|_| docs_navbar())
1131                        .child::<Div, _>(|d| {
1132                            d.class("d-flex")
1133                                // Sidebar
1134                                .child::<Nav, _>(|_| docs_sidebar(&sidebar_items))
1135                                // Main content
1136                                .child::<Main, _>(|m| {
1137                                    m.class("flex-grow-1 p-4")
1138                                        .child::<Div, _>(|d| {
1139                                            d.class("container-fluid")
1140                                                .child::<H1, _>(|h| {
1141                                                    h.class("display-5 mb-4").text("Components")
1142                                                })
1143                                                .child::<P, _>(|p| {
1144                                                    p.class("lead text-muted mb-5").text(
1145                                                    "Dozens of reusable components built on top of Bootstrap.",
1146                                                )
1147                                                })
1148                                                // Component sections
1149                                                .child::<Section, _>(|_| accordion_section())
1150                                                .child::<Section, _>(|_| alerts_section())
1151                                                .child::<Section, _>(|_| badges_section())
1152                                                .child::<Section, _>(|_| breadcrumb_section())
1153                                                .child::<Section, _>(|_| buttons_section())
1154                                                .child::<Section, _>(|_| cards_section())
1155                                                .child::<Section, _>(|_| carousel_section())
1156                                                .child::<Section, _>(|_| close_button_section())
1157                                                .child::<Section, _>(|_| collapse_section())
1158                                                .child::<Section, _>(|_| dropdown_section())
1159                                                .child::<Section, _>(|_| list_group_section())
1160                                                .child::<Section, _>(|_| modal_section())
1161                                                .child::<Section, _>(|_| navbar_section())
1162                                                .child::<Section, _>(|_| offcanvas_section())
1163                                                .child::<Section, _>(|_| pagination_section())
1164                                                .child::<Section, _>(|_| placeholder_section())
1165                                                .child::<Section, _>(|_| progress_section())
1166                                                .child::<Section, _>(|_| spinners_section())
1167                                                .child::<Section, _>(|_| toast_section())
1168                                                .child::<Section, _>(|_| tooltip_section())
1169                                        })
1170                                })
1171                        })
1172                        // Bootstrap JS
1173                        .child::<Script, _>(|s| {
1174                            s.attr(
1175                                "src",
1176                                "https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js",
1177                            )
1178                        })
1179                })
1180        })
1181}
1182
1183fn main() {
1184    let doc = build_docs_page();
1185    let html = doc.render();
1186
1187    println!("{html}");
1188
1189    // Calculate stats
1190    let component_count = 20; // Number of documented components
1191    let example_count = 50; // Approximate number of examples
1192
1193    eprintln!("\n=== Bootstrap Documentation Site ===");
1194    eprintln!("Components documented: {component_count}");
1195    eprintln!("Examples rendered: {example_count}");
1196    eprintln!("HTML size: {} bytes", html.len());
1197    eprintln!("\nThis example demonstrates building a complete documentation site");
1198    eprintln!("similar to getbootstrap.com using ironhtml-bootstrap.");
1199}