pub fn col<F>(size: u8, f: F) -> Element<Div>Expand description
Create a column with specific size (1-12).
Generates: <div class="col-{size}">...</div>
§Example
use ironhtml_bootstrap::grid::col;
let c = col(6, |c| c.text("Half width"));
assert!(c.render().contains(r#"class="col-6"#));Examples found in repository?
examples/landing_page.rs (line 128)
113fn features_section(title: &str, subtitle: &str, features: &[Feature]) -> Element<Section> {
114 Element::<Section>::new()
115 .class("py-5")
116 .id("features")
117 .child::<Div, _>(|_| {
118 grid::container(|c| {
119 c.child::<Div, _>(|d| {
120 d.class("text-center mb-5")
121 .child::<H2, _>(|h| h.class("fw-bold").text(title))
122 .child::<P, _>(|p| p.class("text-muted").text(subtitle))
123 })
124 .child::<Div, _>(|_| {
125 grid::row_gutter(4, |r| {
126 features.iter().fold(r, |row, feature| {
127 row.child::<Div, _>(|_| {
128 grid::col(4, |col| col.child::<Div, _>(|_| feature_card(feature)))
129 })
130 })
131 })
132 })
133 })
134 })
135}
136
137/// Pricing card - reusable component
138fn pricing_card(tier: &PricingTier) -> Element<Div> {
139 let card_class = if tier.highlighted {
140 "card h-100 border-primary shadow"
141 } else {
142 "card h-100 shadow-sm"
143 };
144
145 Element::<Div>::new()
146 .class(card_class)
147 .child::<Div, _>(|body| {
148 let body = body.class("card-body d-flex flex-column");
149 let body = if tier.highlighted {
150 body.child::<Span, _>(|s| {
151 s.class("badge bg-primary text-white position-absolute")
152 .attr("style", "top: -10px; right: 10px;")
153 .text("Popular")
154 })
155 } else {
156 body
157 };
158
159 body.child::<H4, _>(|h| h.class("card-title text-center").text(tier.name))
160 .child::<Div, _>(|d| {
161 d.class("text-center mb-4")
162 .child::<Span, _>(|s| s.class("display-4 fw-bold").text(tier.price))
163 .child::<Span, _>(|s| s.class("text-muted").text(tier.period))
164 })
165 .child::<Ul, _>(|ul| {
166 tier.features
167 .iter()
168 .fold(ul.class("list-unstyled mb-4"), |ul, feature| {
169 ul.child::<Li, _>(|li| {
170 li.class("mb-2")
171 .child::<I, _>(|i| {
172 i.class("bi bi-check-circle-fill text-success me-2")
173 })
174 .text(*feature)
175 })
176 })
177 })
178 .child::<Div, _>(|d| {
179 d.class("mt-auto").child::<A, _>(|a| {
180 let class = alloc::format!(
181 "btn btn-{} w-100 py-2",
182 if tier.highlighted {
183 "primary"
184 } else {
185 "outline-primary"
186 }
187 );
188 a.class(&class).attr("href", "#signup").text(tier.cta)
189 })
190 })
191 })
192}
193
194/// Pricing section
195fn pricing_section(title: &str, tiers: &[PricingTier]) -> Element<Section> {
196 Element::<Section>::new()
197 .class("py-5 bg-light")
198 .id("pricing")
199 .child::<Div, _>(|_| {
200 grid::container(|c| {
201 c.child::<H2, _>(|h| h.class("text-center fw-bold mb-5").text(title))
202 .child::<Div, _>(|_| {
203 grid::row_gutter(4, |r| {
204 tiers.iter().fold(r, |row, tier| {
205 row.child::<Div, _>(|_| {
206 grid::col(4, |col| col.child::<Div, _>(|_| pricing_card(tier)))
207 })
208 })
209 })
210 })
211 })
212 })
213}
214
215/// Testimonial card - reusable component
216fn testimonial_card(testimonial: &Testimonial) -> Element<Div> {
217 cards::card(|body| {
218 body.class("h-100 border-0 shadow-sm")
219 .child::<Blockquote, _>(|bq| {
220 bq.class("blockquote mb-4")
221 .child::<P, _>(|p| {
222 p.child::<I, _>(|i| i.class("bi bi-quote text-primary me-2"))
223 .text(testimonial.quote)
224 })
225 })
226 .child::<Div, _>(|d| {
227 d.class("d-flex align-items-center")
228 .child::<Div, _>(|avatar| {
229 avatar
230 .class("rounded-circle bg-primary text-white d-flex align-items-center justify-content-center me-3")
231 .attr("style", "width: 48px; height: 48px;")
232 .text(testimonial.author.chars().next().unwrap().to_string())
233 })
234 .child::<Div, _>(|info| {
235 info.child::<Strong, _>(|s| s.text(testimonial.author))
236 .child::<Br, _>(|br| br)
237 .child::<Small, _>(|s| s.class("text-muted").text(testimonial.role))
238 })
239 })
240 })
241}
242
243/// Testimonials section
244fn testimonials_section(testimonials: &[Testimonial]) -> Element<Section> {
245 Element::<Section>::new()
246 .class("py-5")
247 .id("testimonials")
248 .child::<Div, _>(|_| {
249 grid::container(|c| {
250 c.child::<H2, _>(|h| {
251 h.class("text-center fw-bold mb-5")
252 .text("What Our Customers Say")
253 })
254 .child::<Div, _>(|_| {
255 grid::row_gutter(4, |r| {
256 testimonials.iter().fold(r, |row, t| {
257 row.child::<Div, _>(|_| {
258 grid::col(4, |col| col.child::<Div, _>(|_| testimonial_card(t)))
259 })
260 })
261 })
262 })
263 })
264 })
265}
266
267/// Footer component
268fn footer(company: &str, year: &str) -> Element<Footer> {
269 Element::<Footer>::new()
270 .class("bg-dark text-white py-4")
271 .child::<Div, _>(|_| {
272 grid::container(|c| {
273 c.child::<Div, _>(|_| {
274 grid::row(|r| {
275 r.child::<Div, _>(|_| {
276 grid::col(6, |col| {
277 col.child::<H5, _>(|h| h.text(company)).child::<P, _>(|p| {
278 p.class("text-muted")
279 .text("Building the future of web development.")
280 })
281 })
282 })
283 .child::<Div, _>(|_| {
284 grid::col(3, |col| {
285 col.child::<H6, _>(|h| h.text("Product"))
286 .child::<Ul, _>(|ul| {
287 ul.class("list-unstyled")
288 .child::<Li, _>(|li| {
289 li.child::<A, _>(|a| {
290 a.class("text-muted text-decoration-none")
291 .attr("href", "#")
292 .text("Features")
293 })
294 })
295 .child::<Li, _>(|li| {
296 li.child::<A, _>(|a| {
297 a.class("text-muted text-decoration-none")
298 .attr("href", "#")
299 .text("Pricing")
300 })
301 })
302 .child::<Li, _>(|li| {
303 li.child::<A, _>(|a| {
304 a.class("text-muted text-decoration-none")
305 .attr("href", "#")
306 .text("Documentation")
307 })
308 })
309 })
310 })
311 })
312 .child::<Div, _>(|_| {
313 grid::col(3, |col| {
314 col.child::<H6, _>(|h| h.text("Company"))
315 .child::<Ul, _>(|ul| {
316 ul.class("list-unstyled")
317 .child::<Li, _>(|li| {
318 li.child::<A, _>(|a| {
319 a.class("text-muted text-decoration-none")
320 .attr("href", "#")
321 .text("About")
322 })
323 })
324 .child::<Li, _>(|li| {
325 li.child::<A, _>(|a| {
326 a.class("text-muted text-decoration-none")
327 .attr("href", "#")
328 .text("Blog")
329 })
330 })
331 .child::<Li, _>(|li| {
332 li.child::<A, _>(|a| {
333 a.class("text-muted text-decoration-none")
334 .attr("href", "#")
335 .text("Contact")
336 })
337 })
338 })
339 })
340 })
341 })
342 })
343 .child::<Hr, _>(|hr| hr.class("my-4"))
344 .child::<P, _>(|p| {
345 let copyright = alloc::format!("© {year} {company}. All rights reserved.");
346 p.class("text-center text-muted mb-0").text(©right)
347 })
348 })
349 })
350}