windjammer_ui/components/generated/
section.rs1#![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}