1use std::collections::{HashMap, HashSet};
2use std::str::FromStr;
3
4use crate::classes::LayoutClass;
5use crate::components::Component;
6use crate::media_query::MediaQuery;
7
8#[derive(Hash, PartialEq, Eq, Debug)]
9pub enum LayoutElement<'a> {
10 LayoutComponent(Component<'a>, Option<MediaQuery>),
11 LayoutUtility(LayoutClass<'a>, Option<MediaQuery>),
12}
13
14impl<'a> LayoutElement<'a> {
15 pub fn insert_css(
20 self,
21 harmonic_ratio: f64,
22 set: &mut HashSet<String>,
23 media_queries_rules: &mut HashMap<MediaQuery, HashSet<String>>,
24 ) {
25 match self {
28 Self::LayoutComponent(component, None) => component.insert_css(harmonic_ratio, set),
29 Self::LayoutComponent(component, Some(mq)) => {
31 let val = media_queries_rules.entry(mq).or_insert_with(HashSet::new);
32 component.insert_css(harmonic_ratio, val);
33 }
34 Self::LayoutUtility(class, None) => class.insert_css(harmonic_ratio, set),
35 Self::LayoutUtility(class, Some(mq)) => {
37 let val = media_queries_rules.entry(mq).or_insert_with(HashSet::new);
38 class.insert_css(harmonic_ratio, val);
39 }
40 }
41 }
42}
43
44pub fn generate<'a>(
45 tag_name: &'a str,
46 layout_attribute: Option<&'a str>,
47 media_query: Option<MediaQuery>,
48 set: &mut HashSet<LayoutElement<'a>>,
49) {
50 let mut component = Component::from_str(tag_name);
51 if let Some(layout_attribute) = layout_attribute {
52 for class in layout_attribute.split_whitespace() {
53 let layout_class = LayoutClass::try_from(class);
54
55 if let Ok(current_class) = layout_class {
57 if let Ok(comp) = &mut component {
62 match current_class {
63 LayoutClass::MaxWidth(v) => {
64 match comp {
65 Component::Box { max_width, .. } => *max_width = Some(v),
66 Component::Center { max_width, .. } => *max_width = Some(v),
67 _ => {}
68 };
69 }
70 LayoutClass::MinCellWidth(v) => {
71 match comp {
72 Component::Grid { min_cell_width, .. } => *min_cell_width = Some(v),
73 _ => {}
74 };
75 }
76 LayoutClass::MinCols(v) => {
77 match comp {
78 Component::Grid { min_cols, .. } => *min_cols = Some(v),
79 _ => {}
80 };
81 }
82 LayoutClass::MaxCols(v) => {
83 match comp {
84 Component::Grid { max_cols, .. } => *max_cols = Some(v),
85 _ => {}
86 };
87 }
88 LayoutClass::Recursive => {
89 match comp {
90 Component::Stack { recursive, .. } => *recursive = true,
91 Component::Center { recursive, .. } => *recursive = true,
92 _ => {}
93 };
94 }
95 LayoutClass::Reverse => {
96 match comp {
97 Component::Switcher { reverse, .. } => *reverse = true,
98 Component::Sidebar { reverse, .. } => *reverse = true,
99 _ => {}
100 };
101 }
102 LayoutClass::Screen => {
103 match comp {
104 Component::Extender { screen, .. } => *screen = true,
105 _ => {}
106 };
107 }
108 LayoutClass::TwinWidth => {
109 match comp {
110 Component::Row { twin_width, .. } => *twin_width = true,
111 _ => {}
112 };
113 }
114 LayoutClass::NoWrap => {
115 match comp {
116 Component::Row { nowrap, .. } => *nowrap = true,
117 _ => {}
118 };
119 }
120 LayoutClass::HideBar => {
121 match comp {
122 Component::Slider { hide_bar, .. } => *hide_bar = true,
123 _ => {}
124 };
125 }
126 LayoutClass::Grow => {
127 match comp {
128 Component::Box { grow, .. } => *grow = true,
129 _ => {}
130 };
131 }
132 LayoutClass::Template(v) => {
133 match comp {
134 Component::Area { template, .. } => *template = Some(v),
135 _ => {}
136 };
137 }
138 LayoutClass::Row(v) => {
139 match comp {
140 Component::Area { rows, .. } => rows.push(v),
141 _ => {}
142 };
143 }
144 LayoutClass::Col(v) => {
145 match comp {
146 Component::Area { cols, .. } => cols.push(v),
147 _ => {}
148 };
149 }
150 LayoutClass::Gap(v) => {
151 match comp {
152 Component::Area { gap, .. } => *gap = Some(v),
153 Component::Grid { gap, .. } => *gap = Some(v),
154 Component::Icon { gap, .. } => *gap = Some(v),
155 Component::Row { gap, .. } => *gap = Some(v),
156 Component::Rack { gap, .. } => *gap = Some(v),
157 Component::Sidebar { gap, .. } => *gap = Some(v),
158 Component::Slider { gap, .. } => *gap = Some(v),
159 Component::Stack { gap, .. } => *gap = Some(v),
160 Component::Switcher { gap, .. } => *gap = Some(v),
161 _ => {}
162 };
163 }
164 LayoutClass::GapX(v) => {
165 match comp {
166 Component::Area { gap_x, .. } => *gap_x = Some(v),
167 Component::Grid { gap_x, .. } => *gap_x = Some(v),
168 Component::Row { gap_x, .. } => *gap_x = Some(v),
169 Component::Sidebar { gap_x, .. } => *gap_x = Some(v),
170 Component::Switcher { gap_x, .. } => *gap_x = Some(v),
171 _ => {}
172 };
173 }
174 LayoutClass::GapY(v) => {
175 match comp {
176 Component::Area { gap_y, .. } => *gap_y = Some(v),
177 Component::Grid { gap_y, .. } => *gap_y = Some(v),
178 Component::Row { gap_y, .. } => *gap_y = Some(v),
179 Component::Sidebar { gap_y, .. } => *gap_y = Some(v),
180 Component::Switcher { gap_y, .. } => *gap_y = Some(v),
181 _ => {}
182 };
183 }
184 LayoutClass::GapDir(v) => {
185 match comp {
186 Component::Icon { gap_dir, .. } => *gap_dir = Some(v),
187 _ => {}
188 };
189 }
190 LayoutClass::Scale(v) => {
191 match comp {
192 Component::Icon { scale, .. } => *scale = Some(v),
193 _ => {}
194 };
195 }
196 LayoutClass::Align(v) => {
197 match comp {
198 Component::Icon { align, .. } => *align = Some(v),
199 Component::Row { align, .. } => *align = Some(v),
200 _ => {}
201 };
202 }
203 LayoutClass::Justify(v) => {
204 match comp {
205 Component::Row { justify, .. } => *justify = Some(v),
206 _ => {}
207 };
208 }
209
210 LayoutClass::Position(v) => {
211 match comp {
212 Component::Outsider { position, .. } => *position = Some(v),
213 _ => {}
214 };
215 }
216 LayoutClass::Top(v) => {
217 match comp {
218 Component::Outsider { top, .. } => *top = Some(v),
219 _ => {}
220 };
221 }
222 LayoutClass::Bottom(v) => {
223 match comp {
224 Component::Outsider { bottom, .. } => *bottom = Some(v),
225 _ => {}
226 };
227 }
228 LayoutClass::Left(v) => {
229 match comp {
230 Component::Outsider { left, .. } => *left = Some(v),
231 _ => {}
232 };
233 }
234 LayoutClass::Right(v) => {
235 match comp {
236 Component::Outsider { right, .. } => *right = Some(v),
237 _ => {}
238 };
239 }
240
241 LayoutClass::Height(v) => {
242 match comp {
243 Component::Rack { height, .. } => *height = Some(v),
244 Component::Slider { height, .. } => *height = Some(v),
245 _ => {}
246 };
247 }
248 LayoutClass::ItemWidth(v) => {
249 match comp {
250 Component::Slider { item_width, .. } => *item_width = Some(v),
251 _ => {}
252 };
253 }
254 LayoutClass::MinHeight(v) => {
255 match comp {
256 Component::Rack { min_height, .. } => *min_height = Some(v),
257 _ => {}
258 };
259 }
260 LayoutClass::MaxHeight(v) => {
261 match comp {
262 Component::Rack { max_height, .. } => *max_height = Some(v),
263 _ => {}
264 };
265 }
266 LayoutClass::SideWidth(v) => {
267 match comp {
268 Component::Sidebar { side_width, .. } => *side_width = Some(v),
269 _ => {}
270 };
271 }
272 LayoutClass::Side(v) => {
273 match comp {
274 Component::Sidebar { side, .. } => *side = Some(v),
275 _ => {}
276 };
277 }
278 LayoutClass::ContentMin(v) => {
279 match comp {
280 Component::Sidebar { content_min, .. } => *content_min = Some(v),
281 _ => {}
282 };
283 }
284 LayoutClass::Threshold(v) => {
285 match comp {
286 Component::Switcher { threshold, .. } => *threshold = Some(v),
287 _ => {}
288 };
289 }
290 LayoutClass::Limit(v) => {
291 match comp {
292 Component::Switcher { limit, .. } => *limit = Some(v),
293 _ => {}
294 };
295 }
296 LayoutClass::KeepP => {
297 match comp {
298 Component::Extender { keep_p, .. } => *keep_p = true,
299 _ => {}
300 };
301 }
302 LayoutClass::KeepPL => {
303 match comp {
304 Component::Extender { keep_pl, .. } => *keep_pl = true,
305 _ => {}
306 };
307 }
308 LayoutClass::KeepPR => {
309 match comp {
310 Component::Extender { keep_pr, .. } => *keep_pr = true,
311 _ => {}
312 };
313 }
314 LayoutClass::KeepCenter => {
315 match comp {
316 Component::Extender { keep_center, .. } => *keep_center = true,
317 _ => {}
318 };
319 }
320 LayoutClass::Shrink => {
321 match comp {
322 Component::Sidebar { shrink, .. } => *shrink = true,
323 _ => {}
324 };
325 }
326 LayoutClass::AndText => {
327 match comp {
328 Component::Center { and_text, .. } => *and_text = true,
329 _ => {}
330 };
331 }
332 _ => {
333 let final_mq = match media_query {
336 Some(MediaQuery::SuperiorTo(_, _)) => None,
337 Some(MediaQuery::InferiorOrEqualTo(_)) => media_query.clone(),
338 _ => None,
339 };
340 set.insert(LayoutElement::LayoutUtility(current_class, final_mq));
341 }
342 };
343 } else {
344 let final_mq = match media_query {
347 Some(MediaQuery::SuperiorTo(_, _)) => None,
348 Some(MediaQuery::InferiorOrEqualTo(_)) => media_query.clone(),
349 _ => None,
350 };
351 set.insert(LayoutElement::LayoutUtility(current_class, final_mq));
352 }
353 }
354 }
355 }
356 if let Ok(cc) = component {
357 set.insert(LayoutElement::LayoutComponent(cc, media_query));
359 }
360}
361
362#[cfg(test)]
363mod tests {
364 use super::*;
365
366
367 #[test]
368 fn media_queries_are_generated() {
369 let mut set: HashSet<String> = HashSet::new();
370 let mut mq_set: HashMap<MediaQuery, HashSet<String>> = HashMap::new();
371 let el = LayoutElement::LayoutComponent(
372 Component::Box {
373 max_width: Some("800px"),
374 grow: false,
375 },
376 Some(MediaQuery::SuperiorTo(
377 800,
378 "p:2 max-width:400px".to_string(),
379 )),
380 );
381 let el2 = LayoutElement::LayoutComponent(
382 Component::Box {
383 max_width: Some("1200px"),
384 grow: false,
385 },
386 Some(MediaQuery::SuperiorTo(
387 800,
388 "p:2 max-width:400px".to_string(),
389 )),
390 );
391
392 el.insert_css(1.618, &mut set, &mut mq_set);
393 el2.insert_css(1.618, &mut set, &mut mq_set);
394 println!("{:?}oooooooooooo", mq_set);
395 assert_eq!(4, 4)
396 }
397
398 #[test]
399 fn attribute_layout_with_component_and_utilities_append_hashset_correctly() {
400 let mut set: HashSet<LayoutElement> = HashSet::new();
401 generate(
402 "box-l",
403 Some("max-width:440px max-width:440px grow p:2 p:4 p:2"),
404 None,
405 &mut set,
406 );
407 println!("{:?}oooooooooooo", set);
408 assert_eq!(4, 4)
409 }
410}