windjammer_ui/components/generated/
section.rs

1#![allow(clippy::all)]
2#![allow(noop_method_call)]
3use super::traits::Renderable;
4
5#[derive(Debug, Clone, PartialEq, Eq, Default)]
6pub struct Section {
7    pub icon: String,
8    pub title: String,
9    pub children: Vec<String>,
10    pub collapsed: bool,
11    pub accent_color: String,
12    pub removable: bool,
13    pub on_remove: String,
14}
15
16impl Section {
17    #[inline]
18    pub fn new(title: String) -> Section {
19        Section {
20            icon: "".to_string(),
21            title,
22            children: Vec::new(),
23            collapsed: false,
24            accent_color: "".to_string(),
25            removable: false,
26            on_remove: "".to_string(),
27        }
28    }
29    #[inline]
30    pub fn icon(mut self, icon: String) -> Section {
31        self.icon = icon;
32        self
33    }
34    #[inline]
35    pub fn child(mut self, child: String) -> Section {
36        self.children.push(child);
37        self
38    }
39    #[inline]
40    pub fn children(mut self, children: Vec<String>) -> Section {
41        self.children = children;
42        self
43    }
44    #[inline]
45    pub fn collapsed(mut self, collapsed: bool) -> Section {
46        self.collapsed = collapsed;
47        self
48    }
49    #[inline]
50    pub fn accent(mut self, color: String) -> Section {
51        self.accent_color = color;
52        self
53    }
54    #[inline]
55    pub fn removable(mut self, on_remove: String) -> Section {
56        self.removable = true;
57        self.on_remove = on_remove;
58        self
59    }
60}
61
62impl Renderable for Section {
63    #[inline]
64    fn render(self) -> String {
65        let collapse_icon = {
66            if self.collapsed {
67                "▶".to_string()
68            } else {
69                "▼".to_string()
70            }
71        };
72        let content_class = {
73            if self.collapsed {
74                "section-content collapsed".to_string()
75            } else {
76                "section-content".to_string()
77            }
78        };
79        let icon_html = {
80            if self.icon != "" {
81                format!("<span class='section-icon'>{}</span>", self.icon)
82            } else {
83                "".to_string()
84            }
85        };
86        let accent_style = {
87            if self.accent_color != "" {
88                format!(" style='border-left: 3px solid {}'", self.accent_color)
89            } else {
90                "".to_string()
91            }
92        };
93        let remove_btn = {
94            if self.removable {
95                format!(
96                    "<button class='section-remove' onclick='{}'>×</button>",
97                    self.on_remove
98                )
99            } else {
100                "".to_string()
101            }
102        };
103        let children_html = self.children.join(
104            "
105",
106        );
107        format!(
108            "
109            <div class='wj-section'{}>
110                <div class='section-header'>
111                    <span class='collapse-arrow'>{}</span>
112                    {}
113                    <span class='section-title'>{}</span>
114                    {}
115                </div>
116                <div class='{}'>
117                    {}
118                </div>
119            </div>
120        ",
121            accent_style,
122            collapse_icon,
123            icon_html,
124            self.title,
125            remove_btn,
126            content_class,
127            children_html
128        )
129    }
130}
131
132#[derive(Debug, Clone, PartialEq, Default)]
133pub struct SectionGroup {
134    pub sections: Vec<Section>,
135    pub accordion: bool,
136}
137
138impl SectionGroup {
139    #[inline]
140    pub fn new() -> SectionGroup {
141        SectionGroup {
142            sections: Vec::new(),
143            accordion: false,
144        }
145    }
146    #[inline]
147    pub fn section(mut self, section: Section) -> SectionGroup {
148        self.sections.push(section);
149        self
150    }
151    #[inline]
152    pub fn accordion(mut self, accordion: bool) -> SectionGroup {
153        self.accordion = accordion;
154        self
155    }
156}
157
158impl Renderable for SectionGroup {
159    #[inline]
160    fn render(self) -> String {
161        let mut sections_html = "".to_string();
162        for s in &self.sections {
163            sections_html = format!(
164                "{}{}{}",
165                sections_html,
166                s.clone().render().as_str(),
167                "
168"
169            );
170        }
171        let class = {
172            if self.accordion {
173                "section-group accordion".to_string()
174            } else {
175                "section-group".to_string()
176            }
177        };
178        format!("<div class='{}'>{}</div>", class, sections_html)
179    }
180}
181
182#[inline]
183pub fn section_styles() -> String {
184    "
185    .wj-section {
186        background: #16213e;
187        border-radius: 8px;
188        margin-bottom: 8px;
189        overflow: hidden;
190        border-left: 3px solid transparent;
191    }
192    
193    .section-header {
194        display: flex;
195        align-items: center;
196        gap: 8px;
197        padding: 12px 16px;
198        cursor: pointer;
199        user-select: none;
200        transition: background 0.15s;
201    }
202    
203    .section-header:hover {
204        background: rgba(255,255,255,0.05);
205    }
206    
207    .collapse-arrow {
208        font-size: 10px;
209        color: #666;
210        width: 12px;
211        transition: transform 0.2s;
212    }
213    
214    .section-icon {
215        font-size: 16px;
216    }
217    
218    .section-title {
219        flex: 1;
220        font-weight: 500;
221        font-size: 13px;
222        color: #e0e0e0;
223    }
224    
225    .section-remove {
226        width: 20px;
227        height: 20px;
228        border: none;
229        background: transparent;
230        color: #666;
231        font-size: 16px;
232        cursor: pointer;
233        border-radius: 4px;
234        display: flex;
235        align-items: center;
236        justify-content: center;
237    }
238    
239    .section-remove:hover {
240        background: #e94560;
241        color: white;
242    }
243    
244    .section-content {
245        padding: 0 16px 16px 16px;
246        animation: section-expand 0.2s ease-out;
247    }
248    
249    .section-content.collapsed {
250        display: none;
251    }
252    
253    @keyframes section-expand {
254        from {
255            opacity: 0;
256            transform: translateY(-10px);
257        }
258        to {
259            opacity: 1;
260            transform: translateY(0);
261        }
262    }
263    
264    .section-group {
265        display: flex;
266        flex-direction: column;
267    }
268    
269    .section-group.accordion .wj-section:not(:first-child) {
270        margin-top: -1px;
271        border-radius: 0;
272    }
273    
274    .section-group.accordion .wj-section:first-child {
275        border-radius: 8px 8px 0 0;
276    }
277    
278    .section-group.accordion .wj-section:last-child {
279        border-radius: 0 0 8px 8px;
280    }
281    "
282    .to_string()
283}