|
1 | 1 | import { |
2 | 2 | Box, |
3 | 3 | Button, |
| 4 | + Checkbox, |
4 | 5 | Dialog, |
5 | 6 | DialogActionButton, |
6 | 7 | DialogActions, |
7 | 8 | DialogCancelButton, |
8 | 9 | DialogContent, |
9 | 10 | DialogDescription, |
10 | 11 | DialogHeader, |
| 12 | + InlineLabel, |
11 | 13 | ScrollArea, |
12 | 14 | Text, |
13 | 15 | TextInput, |
@@ -203,6 +205,30 @@ export function ImportSlicesFromLibraryModal( |
203 | 205 | selectedSliceIds.has(slice.model.id), |
204 | 206 | ); |
205 | 207 |
|
| 208 | + const allSelected = |
| 209 | + slices.length > 0 && selectedSliceIds.size === slices.length; |
| 210 | + const someSelected = |
| 211 | + selectedSliceIds.size > 0 && selectedSliceIds.size < slices.length; |
| 212 | + |
| 213 | + const handleSelectAll = (selected: boolean) => { |
| 214 | + if (selected) { |
| 215 | + const allSliceIds = new Set<string>(); |
| 216 | + for (const slice of slices) { |
| 217 | + allSliceIds.add(slice.model.id); |
| 218 | + } |
| 219 | + setSelectedSliceIds(allSliceIds); |
| 220 | + } else { |
| 221 | + setSelectedSliceIds(new Set()); |
| 222 | + } |
| 223 | + }; |
| 224 | + |
| 225 | + let selectAllLabel = "Select all slices"; |
| 226 | + if (allSelected) { |
| 227 | + selectAllLabel = `Selected all slices (${selectedSliceIds.size})`; |
| 228 | + } else if (someSelected) { |
| 229 | + selectAllLabel = `${selectedSliceIds.size} of ${slices.length} selected`; |
| 230 | + } |
| 231 | + |
206 | 232 | return ( |
207 | 233 | <Dialog open={open} onOpenChange={onOpenChange}> |
208 | 234 | <DialogHeader title="Import slices from library" /> |
@@ -239,40 +265,59 @@ export function ImportSlicesFromLibraryModal( |
239 | 265 | </Box> |
240 | 266 | </Box> |
241 | 267 | ) : ( |
242 | | - <ScrollArea stableScrollbar={false}> |
| 268 | + <> |
243 | 269 | <Box |
244 | | - display="grid" |
245 | | - gridTemplateColumns="1fr 1fr 1fr" |
246 | | - gap={16} |
| 270 | + display="flex" |
| 271 | + alignItems="center" |
| 272 | + justifyContent="space-between" |
247 | 273 | padding={16} |
| 274 | + border={{ bottom: true }} |
248 | 275 | > |
249 | | - {slices.map((slice) => { |
250 | | - return ( |
251 | | - <SliceCard |
252 | | - model={slice.model} |
253 | | - thumbnailUrl={slice.thumbnailUrl} |
254 | | - key={slice.model.id} |
255 | | - selected={selectedSliceIds.has(slice.model.id)} |
256 | | - onSelectedChange={(selected) => { |
257 | | - if (selected) { |
258 | | - setSelectedSliceIds((prev) => { |
259 | | - const next = new Set(prev); |
260 | | - next.add(slice.model.id); |
261 | | - return next; |
262 | | - }); |
263 | | - } else { |
264 | | - setSelectedSliceIds((prev) => { |
265 | | - const next = new Set(prev); |
266 | | - next.delete(slice.model.id); |
267 | | - return next; |
268 | | - }); |
269 | | - } |
270 | | - }} |
| 276 | + <Box display="flex" alignItems="center" gap={8}> |
| 277 | + <InlineLabel value={selectAllLabel}> |
| 278 | + <Checkbox |
| 279 | + checked={allSelected} |
| 280 | + indeterminate={someSelected} |
| 281 | + onCheckedChange={handleSelectAll} |
271 | 282 | /> |
272 | | - ); |
273 | | - })} |
| 283 | + </InlineLabel> |
| 284 | + </Box> |
274 | 285 | </Box> |
275 | | - </ScrollArea> |
| 286 | + <ScrollArea stableScrollbar={false}> |
| 287 | + <Box |
| 288 | + display="grid" |
| 289 | + gridTemplateColumns="1fr 1fr 1fr" |
| 290 | + gap={16} |
| 291 | + padding={16} |
| 292 | + > |
| 293 | + {slices.map((slice) => { |
| 294 | + return ( |
| 295 | + <SliceCard |
| 296 | + model={slice.model} |
| 297 | + thumbnailUrl={slice.thumbnailUrl} |
| 298 | + key={slice.model.id} |
| 299 | + selected={selectedSliceIds.has(slice.model.id)} |
| 300 | + onSelectedChange={(selected) => { |
| 301 | + if (selected) { |
| 302 | + setSelectedSliceIds((prev) => { |
| 303 | + const next = new Set(prev); |
| 304 | + next.add(slice.model.id); |
| 305 | + return next; |
| 306 | + }); |
| 307 | + } else { |
| 308 | + setSelectedSliceIds((prev) => { |
| 309 | + const next = new Set(prev); |
| 310 | + next.delete(slice.model.id); |
| 311 | + return next; |
| 312 | + }); |
| 313 | + } |
| 314 | + }} |
| 315 | + /> |
| 316 | + ); |
| 317 | + })} |
| 318 | + </Box> |
| 319 | + </ScrollArea> |
| 320 | + </> |
276 | 321 | )} |
277 | 322 |
|
278 | 323 | <DialogActions> |
|
0 commit comments