blocks work as usual.
*
* Usage:
* RsvColumnLayout::split('1:2')
* ->column(function () { ?>
*
Add timetable
* ...
* column(function () { ?>
*
* ...
* output();
*/
class RsvColumnLayout
{
/** @var list Column content, in left-to-right order. */
private array $columns = [];
/** @var list Relative column weights, parsed from the ratio. */
private array $weights;
private function __construct(string $ratio)
{
$this->weights = array_map('intval', explode(':', $ratio));
}
/**
* Side-by-side columns that stack on narrow screens.
*
* @param string $ratio Relative column widths, e.g. '1:1', '1:2'.
*/
public static function split(string $ratio = '1:1'): static
{
return new static($ratio);
}
/** Adds the next column. $render echoes the column's content. */
public function column(callable $render): static
{
$this->columns[] = $render;
return $this;
}
public function render(): string
{
$cols = '';
foreach ($this->columns as $i => $render) {
$grow = $this->weights[$i] ?? end($this->weights) ?: 1;
$cols .= ''
. $this->capture($render)
. '
';
}
return '' . $cols . '
';
}
public function output(): void
{
echo $this->render();
}
/** Runs an echoing callable and returns what it printed. */
private function capture(callable $render): string
{
ob_start();
$render();
return ob_get_clean();
}
}