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); } }