79 lines
2.1 KiB
PHP
79 lines
2.1 KiB
PHP
|
|
<?php
|
||
|
|
|
||
|
|
namespace Reservair\Layout;
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Fluent builder for multi-column admin page layouts.
|
||
|
|
*
|
||
|
|
* Lets a page declare the shape it wants (e.g. a two-column split) without
|
||
|
|
* committing to any markup or styling. Each column's content is supplied as a
|
||
|
|
* callable that echoes — inline HTML and <script> blocks work as usual.
|
||
|
|
*
|
||
|
|
* Usage:
|
||
|
|
* RsvColumnLayout::split('1:2')
|
||
|
|
* ->column(function () { ?>
|
||
|
|
* <h2>Add timetable</h2>
|
||
|
|
* ...
|
||
|
|
* <?php })
|
||
|
|
* ->column(function () { ?>
|
||
|
|
* <div id="availability_table"></div>
|
||
|
|
* ...
|
||
|
|
* <?php })
|
||
|
|
* ->output();
|
||
|
|
*/
|
||
|
|
class RsvColumnLayout
|
||
|
|
{
|
||
|
|
/** @var list<callable():void> Column content, in left-to-right order. */
|
||
|
|
private array $columns = [];
|
||
|
|
|
||
|
|
/** @var list<int> 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 .= '<div class="rsv-col" style="--rsv-col-grow:' . (int) $grow . '">'
|
||
|
|
. $this->capture($render)
|
||
|
|
. '</div>';
|
||
|
|
}
|
||
|
|
return '<div class="rsv-cols">' . $cols . '</div>';
|
||
|
|
}
|
||
|
|
|
||
|
|
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();
|
||
|
|
}
|
||
|
|
}
|