, Bootstrap, sidebar y abre
. * Layout::close() cierra
, agrega scripts y . */ class Layout { // ─── Apertura ──────────────────────────────────────────────────────────── /** * Emite el HTML inicial de la página (head + sidebar + apertura de main). * * @param string $title Título de la pestaña y del encabezado. * @param string $icon Clase FontAwesome del ícono (ej. 'fas fa-ticket-alt'). */ public static function open(string $title = 'Panel', string $icon = 'fas fa-th-large'): void { $appName = defined('APP_NAME') ? APP_NAME : 'ERP System'; $safeTitle = htmlspecialchars($title, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8'); $safeIcon = htmlspecialchars($icon, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8'); // Exponer variables para sidebar.php $GLOBALS['_LAYOUT_TITLE'] = $title; $GLOBALS['_LAYOUT_ICON'] = $icon; // Color de marca desde BD $brandColor = '#1565c0'; try { $row = Database::getInstance()->fetch("SELECT valor FROM lab_config WHERE clave = 'doc_color'"); if ($row && preg_match('/^#[0-9a-fA-F]{3,8}$/', $row['valor'])) { $brandColor = $row['valor']; } } catch (\Throwable $_) {} // Derivar color oscuro para gradiente $hex = ltrim($brandColor, '#'); $brandDark = sprintf('#%02x%02x%02x', max(0, hexdec(substr($hex,0,2)) - 40), max(0, hexdec(substr($hex,2,2)) - 40), max(0, hexdec(substr($hex,4,2)) - 40) ); // Detectar base URL (para assets relativos) $base = defined('APP_URL') ? rtrim(APP_URL, '/') : ''; ?> <?= $safeTitle ?> — <?= htmlspecialchars($appName, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8') ?>