Some checks failed
🚀 Build & Deploy Image / Determine Build Necessity (push) Failing after 10m14s
🚀 Build & Deploy Image / Build Runtime Base Image (push) Has been skipped
🚀 Build & Deploy Image / Build Docker Image (push) Has been skipped
🚀 Build & Deploy Image / Run Tests & Quality Checks (push) Has been skipped
🚀 Build & Deploy Image / Auto-deploy to Staging (push) Has been skipped
🚀 Build & Deploy Image / Auto-deploy to Production (push) Has been skipped
Security Vulnerability Scan / Check for Dependency Changes (push) Failing after 11m25s
Security Vulnerability Scan / Composer Security Audit (push) Has been cancelled
- Remove middleware reference from Gitea Traefik labels (caused routing issues) - Optimize Gitea connection pool settings (MAX_IDLE_CONNS=30, authentication_timeout=180s) - Add explicit service reference in Traefik labels - Fix intermittent 504 timeouts by improving PostgreSQL connection handling Fixes Gitea unreachability via git.michaelschiemer.de
160 lines
4.3 KiB
PHP
160 lines
4.3 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Framework\Console\Layout;
|
|
|
|
use App\Framework\Console\Layout\Components\Footer;
|
|
use App\Framework\Console\Layout\Components\Header;
|
|
use App\Framework\Console\Layout\Components\Sidebar;
|
|
use App\Framework\Console\Layout\ValueObjects\LayoutOptions;
|
|
|
|
/**
|
|
* Page layout with header, main content, footer, and optional sidebar
|
|
*/
|
|
final class PageLayout extends LayoutContainer
|
|
{
|
|
private ?Header $header = null;
|
|
private ?Footer $footer = null;
|
|
private ?Sidebar $sidebar = null;
|
|
private array $sections = [];
|
|
private array $mainContent = [];
|
|
|
|
public function __construct(
|
|
?TerminalSize $customTerminalSize = null,
|
|
?LayoutOptions $options = null
|
|
) {
|
|
parent::__construct($customTerminalSize, $options);
|
|
}
|
|
|
|
/**
|
|
* Set header
|
|
*/
|
|
public function withHeader(string $title, ?string $subtitle = null, array $meta = []): self
|
|
{
|
|
$this->header = new Header($title, $subtitle, $this->theme, $meta);
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Set footer
|
|
*/
|
|
public function withFooter(string $content): self
|
|
{
|
|
$this->footer = new Footer($content, $this->theme);
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Set sidebar
|
|
*/
|
|
public function withSidebar(array $items, ?string $title = null): self
|
|
{
|
|
$this->sidebar = new Sidebar($items, $title, $this->theme);
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Add section to main content
|
|
*/
|
|
public function addSection(Section $section): self
|
|
{
|
|
$this->sections[] = $section;
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Add content line to main area
|
|
*/
|
|
public function addContent(string $content): self
|
|
{
|
|
$this->mainContent[] = $content;
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Render the page layout
|
|
*/
|
|
public function render(): string
|
|
{
|
|
$width = $this->getEffectiveWidth();
|
|
$output = [];
|
|
$hasSidebar = $this->sidebar !== null && $this->shouldShowSidebar();
|
|
|
|
// Header
|
|
if ($this->header !== null) {
|
|
$output[] = $this->header->render($width, $this->options->showBorders);
|
|
$output[] = '';
|
|
}
|
|
|
|
// Main content area
|
|
$mainContent = $this->renderMainContent($width, $hasSidebar);
|
|
|
|
if ($hasSidebar) {
|
|
// Split layout: sidebar + main content
|
|
$sidebarWidth = min(25, (int)($width * 0.25));
|
|
$mainWidth = $width - $sidebarWidth - 2; // Space between sidebar and main
|
|
|
|
$sidebarLines = explode("\n", $this->sidebar->render($sidebarWidth, $this->options->showBorders));
|
|
$mainLines = explode("\n", $mainContent);
|
|
|
|
$maxLines = max(count($sidebarLines), count($mainLines));
|
|
|
|
for ($i = 0; $i < $maxLines; $i++) {
|
|
$sidebarLine = $sidebarLines[$i] ?? str_repeat(' ', $sidebarWidth);
|
|
$mainLine = $mainLines[$i] ?? '';
|
|
$output[] = $sidebarLine . ' ' . $mainLine;
|
|
}
|
|
} else {
|
|
// Full width main content
|
|
$output[] = $mainContent;
|
|
}
|
|
|
|
// Footer
|
|
if ($this->footer !== null) {
|
|
$output[] = '';
|
|
$output[] = $this->footer->render($width, $this->options->showBorders);
|
|
}
|
|
|
|
return implode("\n", $output);
|
|
}
|
|
|
|
private function renderMainContent(int $width, bool $hasSidebar): string
|
|
{
|
|
$content = [];
|
|
|
|
// Render sections
|
|
foreach ($this->sections as $section) {
|
|
$content[] = $section->render($width, $this->options->showBorders);
|
|
$content[] = '';
|
|
}
|
|
|
|
// Render additional content
|
|
foreach ($this->mainContent as $line) {
|
|
$content[] = $line;
|
|
}
|
|
|
|
return implode("\n", $content);
|
|
}
|
|
|
|
private function shouldShowSidebar(): bool
|
|
{
|
|
if (!$this->isResponsive()) {
|
|
return true;
|
|
}
|
|
|
|
// Hide sidebar on small terminals
|
|
$breakpoint = $this->terminalSize->getBreakpoint();
|
|
return $breakpoint !== TerminalBreakpoint::EXTRA_SMALL && $breakpoint !== TerminalBreakpoint::SMALL;
|
|
}
|
|
|
|
/**
|
|
* Create page layout
|
|
*/
|
|
public static function create(?TerminalSize $terminalSize = null, ?LayoutOptions $options = null): self
|
|
{
|
|
return new self($terminalSize, $options);
|
|
}
|
|
}
|
|
|