A tile grid: the shape of a stat or summary dashboard.
(props: { readonly next: () => number })
| 211 | |
| 212 | /** A tile grid: the shape of a stat or summary dashboard. */ |
| 213 | function TilesFigure(props: { readonly next: () => number }) { |
| 214 | const { next } = props; |
| 215 | const columns = 2; |
| 216 | const rows = 2; |
| 217 | const gap = 12; |
| 218 | const tileWidth = (WIDTH - PAD * 2 - gap * (columns - 1)) / columns; |
| 219 | const tileHeight = (HEIGHT - PAD - BODY_TOP - gap * (rows - 1)) / rows; |
| 220 | |
| 221 | return ( |
| 222 | <> |
| 223 | {Array.from({ length: columns * rows }, (_, index) => { |
| 224 | const column = index % columns; |
| 225 | const row = Math.floor(index / columns); |
| 226 | const x = PAD + column * (tileWidth + gap); |
| 227 | const y = BODY_TOP + row * (tileHeight + gap); |
| 228 | const valueWidth = between(next, 28, 54); |
| 229 | return ( |
| 230 | <g key={index}> |
| 231 | <rect |
| 232 | x={x} |
| 233 | y={y} |
| 234 | width={tileWidth} |
| 235 | height={tileHeight} |
| 236 | rx={4} |
| 237 | className="fill-transparent stroke-border" |
| 238 | strokeWidth={1} |
| 239 | /> |
| 240 | <Block x={x + 12} y={y + 14} width={between(next, 30, 46)} height={6} /> |
| 241 | <Block |
| 242 | x={x + 12} |
| 243 | y={y + 28} |
| 244 | width={valueWidth} |
| 245 | height={11} |
| 246 | className="fill-muted-foreground/35" |
| 247 | /> |
| 248 | </g> |
| 249 | ); |
| 250 | })} |
| 251 | </> |
| 252 | ); |
| 253 | } |
| 254 | |
| 255 | /** A list beside a panel: the shape of a detail or explorer artifact. */ |
| 256 | function SplitFigure(props: { readonly next: () => number }) { |