layoutcss_parser/components/
grid.rs1use indoc::formatdoc;
2use std::collections::HashSet;
3
4use crate::harmonic::get_harmonic;
5
6const GRID_STYLE: &str = r#"
7 grid-l{
8 display: grid;
9 }
10"#;
11
12fn grid_gap_style(value: &str, harmonic: String) -> String {
13 formatdoc!(
14 r#"
15 grid-l[layout~="gap:{value}"]{{
16 gap: {harmonic};
17 }}
18 "#,
19 )
20}
21
22fn grid_gap_x_style(value: &str, harmonic: String) -> String {
23 formatdoc!(
24 r#"
25 grid-l[layout~="gap-x:{value}"]{{
26 column-gap: {harmonic};
27 }}
28 "#,
29 )
30}
31
32fn grid_gap_y_style(value: &str, harmonic: String) -> String {
33 formatdoc!(
34 r#"
35 grid-l[layout~="gap-y:{value}"]{{
36 row-gap: {harmonic};
37 }}
38 "#,
39 )
40}
41
42fn grid_group_empty(min_cell_width: &str) -> String {
43 formatdoc!(
44 r#"
45 grid-l[layout*="min-cell-width:{min_cell_width}"] {{
46 grid-template-columns: repeat(auto-fit, minmax(min({min_cell_width}, 100%),1fr));
47 }}
48 "#,
49 )
50}
51
52fn grid_group_max_cols(min_cell_width: &str, max_cols: &str, gap_delta_max: &str) -> String {
53 formatdoc!(
54 r#"
55 grid-l[layout*="min-cell-width:{min_cell_width}"][layout*="max-cols:{max_cols}"]{{
56 grid-template-columns: repeat(auto-fit, minmax(min(100%, max({min_cell_width}, (100% / {max_cols} - {gap_delta_max}))),1fr));
57 }}
58 "#,
59 )
60}
61
62fn grid_group_min_cols(min_cell_width: &str, min_cols: &str, gap_delta_min: &str) -> String {
63 formatdoc!(
64 r#"
65 grid-l[layout*="min-cell-width:{min_cell_width}"][layout*="min-cols:{min_cols}"]:has(:nth-child({min_cols})){{
66 grid-template-columns: repeat(auto-fit, minmax(min((100% / {min_cols} - {gap_delta_min}), {min_cell_width}), 1fr));
67 }}
68 grid-l[layout*="min-cell-width:{min_cell_width}"][layout*="min-cols:{min_cols}"]{{
69 grid-template-columns: repeat({min_cols}, 1fr);
70 }}
71 "#,
72 )
73}
74
75fn grid_group_min_cols_max_cols(
76 min_cell_width: &str,
77 min_cols: &str,
78 max_cols: &str,
79 gap_delta_min: &str,
80 gap_delta_max: &str,
81 fr: f64,
82) -> String {
83 formatdoc!(
84 r#"
85 grid-l[layout*="min-cell-width:{min_cell_width}"][layout*="min-cols:{min_cols}"][layout*="max-cols:{max_cols}"]:has(:nth-child({min_cols})){{
86 grid-template-columns:
87 repeat(auto-fit,
88 minmax(
89 min(
90 (100% / {min_cols} - {gap_delta_min}),
91 max({min_cell_width}, (100% / {max_cols} - {gap_delta_max}))
92 ),
93 {fr}fr
94 )
95 )
96 }}
97 grid-l[layout*="min-cell-width:{min_cell_width}"][layout*="min-cols:{min_cols}"][layout*="max-cols:{max_cols}"]{{
98 grid-template-columns: repeat({min_cols}, 1fr);
99 }}
100 "#,
101 )
102}
103
104fn gap_delta(cols: &str, gap: Option<&str>, harmonic_ratio: f64) -> String {
105 if let Some(value) = gap {
106 match cols.parse::<f64>() {
107 Ok(cols_number) => {
108 let hr = get_harmonic(&value, harmonic_ratio);
109 format!("{hr} * ({cols_number} - 0.98) / {cols_number}").to_string()
110 },
112 Err(_) => "0px".to_string(),
113 }
114 } else {
115 "0px".to_string()
116 }
117}
118
119pub fn grid_css(
120 min_cell_width: Option<&str>,
121 min_cols: Option<&str>,
122 max_cols: Option<&str>,
123 gap: Option<&str>,
124 gap_x: Option<&str>,
125 gap_y: Option<&str>,
126 harmonic_ratio: f64,
127 set: &mut HashSet<String>,
128) {
129 set.insert(GRID_STYLE.to_string());
130 if let Some(ref value) = gap {
131 let harmonic_value = get_harmonic(value, harmonic_ratio);
132 set.insert(grid_gap_style(value, harmonic_value));
133 }
134 if let Some(ref value) = gap_x {
135 let harmonic_value = get_harmonic(value, harmonic_ratio);
136 set.insert(grid_gap_x_style(value, harmonic_value));
137 }
138 if let Some(ref value) = gap_y {
139 let harmonic_value = get_harmonic(value, harmonic_ratio);
140 set.insert(grid_gap_y_style(value, harmonic_value));
141 }
142 if let Some(min_cell_width) = min_cell_width {
143 match (min_cols, max_cols) {
144 (Some(min_cols), Some(max_cols)) => {
145
146 let gap_delta_min = gap_delta(min_cols, gap, harmonic_ratio);
147 let gap_delta_max = gap_delta(max_cols, gap, harmonic_ratio);
148 let fr = 1.0 / min_cols.parse::<f64>().unwrap_or(-1.0);
149 set.insert(grid_group_min_cols_max_cols(
150 min_cell_width,
151 min_cols,
152 max_cols,
153 &gap_delta_min,
154 &gap_delta_max,
155 fr,
156 ));
157 }
158 (Some(min_cols), None) => {
159 let gap_delta_min = gap_delta(min_cols, gap, harmonic_ratio);
160 set.insert(grid_group_min_cols(min_cell_width, min_cols, &gap_delta_min));
161 }
162 (None, Some(max_cols)) => {
163 let gap_delta_max = gap_delta(max_cols, gap, harmonic_ratio);
164 set.insert(grid_group_max_cols(min_cell_width, max_cols, &gap_delta_max));
165 }
166 _ => {
167 set.insert(grid_group_empty(min_cell_width));
168 }
169 }
170 }
171}
172
173