ironhtml_bootstrap/
grid.rs

1//! Bootstrap grid system components.
2//!
3//! The grid system uses containers, rows, and columns to layout content.
4//!
5//! ## Example
6//!
7//! ```rust
8//! use ironhtml_bootstrap::grid::*;
9//! use ironhtml::typed::Element;
10//! use ironhtml_elements::Div;
11//!
12//! let layout = container(|c| {
13//!     c.child::<Div, _>(|_| {
14//!         row(|r| {
15//!             r.child::<Div, _>(|_| col(4, |c| c.text("Column 1")))
16//!              .child::<Div, _>(|_| col(4, |c| c.text("Column 2")))
17//!              .child::<Div, _>(|_| col(4, |c| c.text("Column 3")))
18//!         })
19//!     })
20//! });
21//!
22//! let html = layout.render();
23//! assert!(html.contains(r#"class="container"#));
24//! assert!(html.contains(r#"class="row"#));
25//! assert!(html.contains(r#"class="col-4"#));
26//! ```
27
28use crate::Breakpoint;
29use ironhtml::typed::Element;
30use ironhtml_elements::Div;
31
32/// Create a Bootstrap container.
33///
34/// Generates: `<div class="container">...</div>`
35///
36/// ## Example
37///
38/// ```rust
39/// use ironhtml_bootstrap::grid::container;
40///
41/// let c = container(|c| c.text("Content"));
42/// assert!(c.render().contains(r#"<div class="container">"#));
43/// ```
44#[must_use]
45pub fn container<F>(f: F) -> Element<Div>
46where
47    F: FnOnce(Element<Div>) -> Element<Div>,
48{
49    f(Element::<Div>::new().class("container"))
50}
51
52/// Create a fluid container (100% width).
53///
54/// Generates: `<div class="container-fluid">...</div>`
55#[must_use]
56pub fn container_fluid<F>(f: F) -> Element<Div>
57where
58    F: FnOnce(Element<Div>) -> Element<Div>,
59{
60    f(Element::<Div>::new().class("container-fluid"))
61}
62
63/// Create a responsive container.
64///
65/// Generates: `<div class="container-{breakpoint}">...</div>`
66///
67/// ## Example
68///
69/// ```rust
70/// use ironhtml_bootstrap::{grid::container_bp, Breakpoint};
71///
72/// let c = container_bp(Breakpoint::Md, |c| c.text("Content"));
73/// assert!(c.render().contains(r#"class="container-md"#));
74/// ```
75#[must_use]
76pub fn container_bp<F>(bp: Breakpoint, f: F) -> Element<Div>
77where
78    F: FnOnce(Element<Div>) -> Element<Div>,
79{
80    let class = alloc::format!("container-{}", bp.as_str());
81    f(Element::<Div>::new().class(&class))
82}
83
84/// Create a row.
85///
86/// Generates: `<div class="row">...</div>`
87#[must_use]
88pub fn row<F>(f: F) -> Element<Div>
89where
90    F: FnOnce(Element<Div>) -> Element<Div>,
91{
92    f(Element::<Div>::new().class("row"))
93}
94
95/// Create a row with custom gutter.
96///
97/// Generates: `<div class="row g-{gutter}">...</div>`
98#[must_use]
99pub fn row_gutter<F>(gutter: u8, f: F) -> Element<Div>
100where
101    F: FnOnce(Element<Div>) -> Element<Div>,
102{
103    let class = alloc::format!("row g-{gutter}");
104    f(Element::<Div>::new().class(&class))
105}
106
107/// Create an auto-width column.
108///
109/// Generates: `<div class="col">...</div>`
110#[must_use]
111pub fn col_auto<F>(f: F) -> Element<Div>
112where
113    F: FnOnce(Element<Div>) -> Element<Div>,
114{
115    f(Element::<Div>::new().class("col"))
116}
117
118/// Create a column with specific size (1-12).
119///
120/// Generates: `<div class="col-{size}">...</div>`
121///
122/// ## Example
123///
124/// ```rust
125/// use ironhtml_bootstrap::grid::col;
126///
127/// let c = col(6, |c| c.text("Half width"));
128/// assert!(c.render().contains(r#"class="col-6"#));
129/// ```
130#[must_use]
131pub fn col<F>(size: u8, f: F) -> Element<Div>
132where
133    F: FnOnce(Element<Div>) -> Element<Div>,
134{
135    let class = alloc::format!("col-{size}");
136    f(Element::<Div>::new().class(&class))
137}
138
139/// Create a responsive column.
140///
141/// Generates: `<div class="col-{breakpoint}-{size}">...</div>`
142///
143/// ## Example
144///
145/// ```rust
146/// use ironhtml_bootstrap::{grid::col_bp, Breakpoint};
147///
148/// let c = col_bp(Breakpoint::Md, 6, |c| c.text("Half on medium+"));
149/// assert!(c.render().contains(r#"class="col-md-6"#));
150/// ```
151#[must_use]
152pub fn col_bp<F>(bp: Breakpoint, size: u8, f: F) -> Element<Div>
153where
154    F: FnOnce(Element<Div>) -> Element<Div>,
155{
156    let class = alloc::format!("col-{}-{size}", bp.as_str());
157    f(Element::<Div>::new().class(&class))
158}
159
160extern crate alloc;
161
162#[cfg(test)]
163mod tests {
164    use super::*;
165
166    #[test]
167    fn test_container() {
168        let c = container(|c| c.text("Hello"));
169        assert!(c.render().contains(r#"<div class="container">"#));
170    }
171
172    #[test]
173    fn test_row_and_columns() {
174        let layout = row(|r| {
175            r.child::<Div, _>(|_| col(4, |c| c.text("A")))
176                .child::<Div, _>(|_| col(8, |c| c.text("B")))
177        });
178        let html = layout.render();
179        assert!(html.contains(r#"class="row"#));
180        assert!(html.contains(r#"class="col-4"#));
181        assert!(html.contains(r#"class="col-8"#));
182    }
183}