zen_rs/layouts/html/
container.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
//! This module contains the `container_html` function for rendering a `Container`
//! component into an HTML string with specified styles and content.
//!
//! The `container_html` function takes a `Container` component, extracts its properties
//! (such as background color, size, border, gap, padding, alignment, and direction),
//! and generates an HTML `<div>` element. The function applies appropriate CSS styles
//! for the container layout (including flexbox styles) and recursively renders
//! its child components into the container.

use super::HtmlBuilder;
use crate::components::container::Container;

/// Renders a `Container` component into an HTML string with the specified styles
/// such as background color, size, border, padding, alignment, and flexbox layout.
///
/// # Arguments
/// * `component` - A reference to a `Container` component containing the properties
///   such as background color, dimensions, border, padding, and alignment.
///   It may also include nested components that are rendered inside the container.
///
/// # Returns
/// A string representing the HTML `<div>` element with the specified properties,
/// styles, and content (child components).
pub fn container_html(component: &Container) -> String {
    // data
    let (bg_red, bg_green, bg_blue, bg_alpha) = component.get_background_color();
    let w = component.get_width();
    let h = component.get_height();
    let (b_size, (b_red, b_green, b_blue, b_alpha), b_radius) = component.get_border();
    let gap = component.get_gap();
    let padding = component.get_padding();
    let align = component.get_align_content();

    // local state
    let mut is_col = false;

    // content
    let content = {
        let mut out = String::new();
        let components = component.get_components();
        for component in components {
            let component = HtmlBuilder::render_component(component);
            out.push_str(&component);
        }
        out
    };

    // css

    let padding = format!("padding: {padding}px;");
    let gap = format!("gap: {gap}px;");
    let flex = if *component.get_flex() {
        "display: flex;"
    } else {
        "display: block;"
    };
    let direction = {
        let dn = match component.get_direction() {
            crate::aspects::Order::TopToBottom => {
                is_col = !is_col;
                "column"
            }
            crate::aspects::Order::BottomToTop => "column-reverse",
            crate::aspects::Order::LefToRight => "row",
            crate::aspects::Order::RightToLeft => "row-reverse",
        };
        format!("flex-direction: {dn};")
    };
    let align_content = {
        let a = match align {
            crate::aspects::Align::Left => "flex-left",
            crate::aspects::Align::Center => "center",
            crate::aspects::Align::Right => "flex-end",
            crate::aspects::Align::SpaceBetween => "space-between",
        };
        if is_col {
            format!("align-items: {a};")
        } else {
            format!("justify-content: {a};")
        }
    };
    let align_items = {
        let a = match align {
            crate::aspects::Align::Left => "flex-left",
            crate::aspects::Align::Center => "center",
            crate::aspects::Align::Right => "flex-end",
            crate::aspects::Align::SpaceBetween => "space-between",
        };
        if is_col {
            format!("justify-content: {a};")
        } else {
            format!("align-items: {a};")
        }
    };
    let size = {
        let mut out = String::new();
        if *component.get_width_full() {
            out.push_str("width: 100%;");
        } else if *w != 0 {
            out.push_str(&format!("width: {w};"));
        }
        if *component.get_height_full() {
            out.push_str("height: 100%;");
        } else if *h != 0 {
            out.push_str(&format!("height: {h};"));
        }

        out
    };
    let bg_color = format!("background-color: rgba({bg_red}, {bg_green}, {bg_blue}, {bg_alpha});");
    let border = format!("border: {b_size}px solid rgba({b_red}, {b_green}, {b_blue}, {b_alpha}); border-radius: {b_radius}px;");
    // css build
    let style = format!(
        r#"style="{flex} {align_content} {align_items} {size} {gap} {direction} {padding} {bg_color} {border}""#
    );

    // out data
    let out = format!("<div {style}>{content}</div>");
    out
}