1use super::units::Length;
6
7#[derive(Clone, Debug)]
9pub struct GridTemplate {
10 columns: Vec<GridTrack>,
11 rows: Vec<GridTrack>,
12 areas: Option<Vec<Vec<String>>>,
13}
14
15#[derive(Clone, Debug)]
17pub enum GridTrack {
18 Fixed(Length),
20 Flexible(f32),
22 MinMax(Length, Length),
24 Repeat(u32, Vec<GridTrack>),
26 Auto,
28 Named(String),
30}
31
32impl GridTrack {
33 pub fn to_css(&self) -> String {
35 match self {
36 GridTrack::Fixed(len) => len.to_css(),
37 GridTrack::Flexible(fr) => format!("{}fr", fr),
38 GridTrack::MinMax(min, max) => format!("minmax({}, {})", min.to_css(), max.to_css()),
39 GridTrack::Repeat(count, tracks) => {
40 let tracks_str = tracks
41 .iter()
42 .map(|t| t.to_css())
43 .collect::<Vec<_>>()
44 .join(" ");
45 format!("repeat({}, {})", count, tracks_str)
46 }
47 GridTrack::Auto => "auto".to_string(),
48 GridTrack::Named(name) => format!("[{}]", name),
49 }
50 }
51}
52
53impl GridTemplate {
54 pub fn new() -> Self {
56 Self {
57 columns: Vec::new(),
58 rows: Vec::new(),
59 areas: None,
60 }
61 }
62
63 pub fn columns(mut self, cols: Vec<GridTrack>) -> Self {
65 self.columns = cols;
66 self
67 }
68
69 pub fn rows(mut self, rows: Vec<GridTrack>) -> Self {
71 self.rows = rows;
72 self
73 }
74
75 pub fn areas(mut self, areas: Vec<Vec<String>>) -> Self {
77 self.areas = Some(areas);
78 self
79 }
80
81 pub fn to_css(&self) -> String {
83 let mut css = String::new();
84
85 if !self.columns.is_empty() {
86 let cols_str = self
87 .columns
88 .iter()
89 .map(|t| t.to_css())
90 .collect::<Vec<_>>()
91 .join(" ");
92 css.push_str(&format!("grid-template-columns: {}; ", cols_str));
93 }
94
95 if !self.rows.is_empty() {
96 let rows_str = self
97 .rows
98 .iter()
99 .map(|t| t.to_css())
100 .collect::<Vec<_>>()
101 .join(" ");
102 css.push_str(&format!("grid-template-rows: {}; ", rows_str));
103 }
104
105 if let Some(ref areas) = self.areas {
106 let areas_str = areas
107 .iter()
108 .map(|row| format!("\"{}\"", row.join(" ")))
109 .collect::<Vec<_>>()
110 .join(" ");
111 css.push_str(&format!("grid-template-areas: {}; ", areas_str));
112 }
113
114 css
115 }
116}
117
118impl Default for GridTemplate {
119 fn default() -> Self {
120 Self::new()
121 }
122}
123
124#[derive(Clone, Debug)]
126pub struct GridArea {
127 pub name: String,
128 pub row_start: Option<String>,
129 pub column_start: Option<String>,
130 pub row_end: Option<String>,
131 pub column_end: Option<String>,
132}
133
134impl GridArea {
135 pub fn new(name: &str) -> Self {
137 Self {
138 name: name.to_string(),
139 row_start: None,
140 column_start: None,
141 row_end: None,
142 column_end: None,
143 }
144 }
145
146 pub fn row_start(mut self, start: &str) -> Self {
148 self.row_start = Some(start.to_string());
149 self
150 }
151
152 pub fn column_start(mut self, start: &str) -> Self {
154 self.column_start = Some(start.to_string());
155 self
156 }
157
158 pub fn row_end(mut self, end: &str) -> Self {
160 self.row_end = Some(end.to_string());
161 self
162 }
163
164 pub fn column_end(mut self, end: &str) -> Self {
166 self.column_end = Some(end.to_string());
167 self
168 }
169
170 pub fn to_css(&self) -> String {
172 let mut props = Vec::new();
173
174 props.push(format!("grid-area: {};", self.name));
175
176 if let Some(ref start) = self.row_start {
177 props.push(format!("grid-row-start: {};", start));
178 }
179
180 if let Some(ref start) = self.column_start {
181 props.push(format!("grid-column-start: {};", start));
182 }
183
184 if let Some(ref end) = self.row_end {
185 props.push(format!("grid-row-end: {};", end));
186 }
187
188 if let Some(ref end) = self.column_end {
189 props.push(format!("grid-column-end: {};", end));
190 }
191
192 props.join(" ")
193 }
194}
195
196#[derive(Clone, Debug)]
198pub struct Subgrid {
199 pub columns: bool,
200 pub rows: bool,
201}
202
203impl Subgrid {
204 pub fn both() -> Self {
206 Self {
207 columns: true,
208 rows: true,
209 }
210 }
211
212 pub fn columns() -> Self {
214 Self {
215 columns: true,
216 rows: false,
217 }
218 }
219
220 pub fn rows() -> Self {
222 Self {
223 columns: false,
224 rows: true,
225 }
226 }
227
228 pub fn to_css(&self) -> String {
230 match (self.columns, self.rows) {
231 (true, true) => "subgrid".to_string(),
232 (true, false) => "subgrid / none".to_string(),
233 (false, true) => "none / subgrid".to_string(),
234 (false, false) => "none".to_string(),
235 }
236 }
237}