fix: dark mode completamente reescrito con Bootstrap 5.3 data-bs-theme

- Agrega script inline en <head> de Layout.php, lugar.php y recepcion.php
  que detecta prefers-color-scheme y activa data-bs-theme="dark" en <html>
  antes del primer paint (evita flash de contenido blanco)
- sidebar.php: script de fallback para páginas con head propio no actualizado
- Layout.php: corrige background hardcodeado #f8f9fa en .main-content y
  reemplaza bg-white por bg-body-tertiary en barra de título
- styles.css: elimina bloque @media duplicado y contradictorio; nuevo bloque
  unificado cubre @media (fallback sin JS) + [data-bs-theme="dark"] para
  elementos custom (sidebar, chat); Bootstrap maneja el resto automáticamente
- Bump styles.css a v=15 en los tres templates

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Lizandro Guarnizo
2026-07-09 20:42:39 -05:00
co-authored by Claude Sonnet 4.6
parent fdc04d615c
commit 55bccae0ad
5 changed files with 132 additions and 127 deletions
+117 -122
View File
@@ -935,32 +935,6 @@ body {
#sidebar-toggle { display: none !important; }
}
/* Dark Mode Support */
@media (prefers-color-scheme: dark) {
:root {
--light-bg: #1f2937;
--text-primary: #f9fafb;
--text-secondary: #d1d5db;
--border-color: #374151;
}
body {
background-color: var(--dark-bg);
color: var(--text-primary);
}
.card {
background: #374151;
}
.card-header {
background: #4b5563;
}
.table th {
background: #4b5563;
}
}
/* Utility Classes */
.text-center { text-align: center; }
@@ -1483,104 +1457,125 @@ body {
border: 1px solid rgba(255, 255, 255, 0.5);
}
/* ===== Ajustes para modo nocturno (dark mode) ===== */
/* ─────────────────────────────────────────────────────────────────────────
MODO OSCURO
Activación dual:
1) @media (prefers-color-scheme: dark) — OS sin JS
2) [data-bs-theme="dark"] en <html> — Bootstrap 5.3 via script inline
Bootstrap 5.3 maneja automáticamente (cuando data-bs-theme está activo):
card, modal, table, form-control, form-select, dropdown, badge, alert,
list-group, nav, pagination, offcanvas, toast, popover, etc.
Aquí solo cubrimos variables custom y elementos no-Bootstrap.
───────────────────────────────────────────────────────────────────────── */
/* ── Variables custom para elementos no-Bootstrap ── */
@media (prefers-color-scheme: dark) {
:root {
--light-bg: #071322;
--text-primary: #e6eef1;
--dm-body: #0a1628;
--dm-surf: #071322;
--dm-surf2: #0b1c32;
--dm-bdr: #163240;
--dm-txt: #e6eef1;
--dm-muted: #9ca3af;
--dm-link: #a6f3c9;
/* Alias compatibilidad con código que usa estas vars */
--light-bg: #071322;
--text-primary: #e6eef1;
--text-secondary: #9ca3af;
--border-color: #163240;
--border-color: #163240;
}
body {
background-color: var(--light-bg);
color: var(--text-primary);
}
/* Encabezados y títulos */
.content-header h1,
.card-header h5,
.sidebar-header h4,
.status-text,
.status-indicator,
.conversation-empty {
color: var(--text-primary) !important;
}
/* Contenedores */
.content-header,
.card,
.chat-container {
background: #071322;
color: var(--text-primary);
border-color: var(--border-color);
box-shadow: none;
}
.card-header {
background: transparent;
border-bottom-color: rgba(255,255,255,0.04);
}
/* Formularios y botones */
.form-control {
background: #072033;
color: var(--text-primary);
border-color: #163240;
}
.btn {
color: inherit;
}
/* Sidebar */
.sidebar {
background: linear-gradient(135deg,#08131a,#0b2221);
color: #e6eef1;
}
.conversation-actions .btn {
background: #0b1220;
border-color: #1f2937;
color: var(--text-secondary);
}
/* Chat específico */
.chat-header {
background: linear-gradient(135deg, #1f5a3f 0%, #0f513e 100%);
color: #fff;
}
.message-bubble {
color: #e6eef1;
}
.message-incoming {
background: #0b1220;
color: #e6eef1;
box-shadow: none;
}
.message-outgoing {
background: #0f513e;
color: #fff;
}
.message-document,
.media-preview {
background: rgba(255,255,255,0.03);
color: var(--text-primary);
}
.conversation-search {
background: rgba(255,255,255,0.04);
color: var(--text-primary);
}
a, .nav-link {
color: #a6f3c9;
}
/* Placeholders visibles */
::placeholder { color: #9ca3af !important; opacity: 1; }
}
[data-bs-theme="dark"] {
--dm-body: #0a1628;
--dm-surf: #071322;
--dm-surf2: #0b1c32;
--dm-bdr: #163240;
--dm-txt: #e6eef1;
--dm-muted: #9ca3af;
--dm-link: #a6f3c9;
--light-bg: #071322;
--text-primary: #e6eef1;
--text-secondary: #9ca3af;
--border-color: #163240;
}
/* ── Reglas para modo OS sin JS (fallback) ── */
@media (prefers-color-scheme: dark) {
body { background-color: var(--dm-body); color: var(--dm-txt); }
/* Fondo principal */
.main-content { background-color: var(--dm-body) !important; }
/* Bootstrap no cambia bg-white — forzamos adaptación */
.bg-white { background-color: var(--dm-surf) !important; color: var(--dm-txt) !important; }
/* Encabezados y texto */
.content-header { background: var(--dm-surf); border-color: var(--dm-bdr) !important; color: var(--dm-txt); }
.content-header h1, .card-header h5, .sidebar-header h4,
.status-text, .status-indicator, .conversation-empty { color: var(--dm-txt) !important; }
/* Componentes Bootstrap (fallback sin data-bs-theme) */
.card { background: var(--dm-surf); color: var(--dm-txt); border-color: var(--dm-bdr); box-shadow: none; }
.card-header { background: transparent; border-color: rgba(255,255,255,.06); }
.form-control, .form-select {
background: var(--dm-surf2);
color: var(--dm-txt);
border-color: var(--dm-bdr);
}
.form-control:focus, .form-select:focus {
background: var(--dm-surf2);
color: var(--dm-txt);
border-color: #2d6a8a;
box-shadow: 0 0 0 .2rem rgba(45,106,138,.25);
}
.table { color: var(--dm-txt); border-color: var(--dm-bdr); }
.table th { background: var(--dm-surf2); color: var(--dm-txt); }
.modal-content { background: var(--dm-surf); color: var(--dm-txt); }
.modal-header, .modal-footer { border-color: var(--dm-bdr); }
.dropdown-menu { background: var(--dm-surf); border-color: var(--dm-bdr); }
.dropdown-item { color: var(--dm-txt); }
.dropdown-item:hover { background: var(--dm-surf2); color: var(--dm-txt); }
.list-group-item { background: var(--dm-surf); color: var(--dm-txt); border-color: var(--dm-bdr); }
.input-group-text { background: var(--dm-surf2); color: var(--dm-txt); border-color: var(--dm-bdr); }
.nav-tabs .nav-link { color: var(--dm-muted); }
.nav-tabs .nav-link.active { background: var(--dm-surf); color: var(--dm-txt); border-color: var(--dm-bdr); }
/* Sidebar custom */
.sidebar { background: linear-gradient(135deg, #08131a, #0b2221); color: #e6eef1; }
/* Chat */
.chat-container { background: var(--dm-surf); color: var(--dm-txt); border-color: var(--dm-bdr); }
.chat-header { background: linear-gradient(135deg, #1f5a3f, #0f513e); color: #fff; }
.message-bubble { color: var(--dm-txt); }
.message-incoming { background: var(--dm-surf2); color: var(--dm-txt); box-shadow: none; }
.message-outgoing { background: #0f513e; color: #fff; }
.message-document, .media-preview { background: rgba(255,255,255,.03); color: var(--dm-txt); }
.conversation-search { background: rgba(255,255,255,.04); color: var(--dm-txt); }
.conversation-actions .btn { background: #0b1220; border-color: #1f2937; color: var(--dm-muted); }
/* Links */
a:not(.btn):not(.badge), .nav-link { color: var(--dm-link); }
/* Placeholders */
::placeholder { color: var(--dm-muted) !important; opacity: 1; }
}
/* ── Reglas para Bootstrap dark mode activo (data-bs-theme="dark") ── */
/* Bootstrap ya maneja card, modal, table, form, dropdown, badge, alert, etc. */
/* Solo corregimos lo que Bootstrap no toca: elementos custom y clases forzadas */
[data-bs-theme="dark"] .main-content { background-color: var(--dm-body, #0a1628) !important; }
[data-bs-theme="dark"] .bg-white { background-color: var(--bs-body-bg) !important; color: var(--bs-body-color) !important; }
[data-bs-theme="dark"] .sidebar { background: linear-gradient(135deg, #08131a, #0b2221) !important; color: #e6eef1; }
[data-bs-theme="dark"] .chat-container { background: var(--dm-surf, #071322); border-color: var(--dm-bdr, #163240); }
[data-bs-theme="dark"] .chat-header { background: linear-gradient(135deg, #1f5a3f, #0f513e); color: #fff; }
[data-bs-theme="dark"] .message-bubble { color: var(--dm-txt, #e6eef1); }
[data-bs-theme="dark"] .message-incoming { background: var(--dm-surf2, #0b1c32); color: var(--dm-txt, #e6eef1); box-shadow: none; }
[data-bs-theme="dark"] .message-outgoing { background: #0f513e; color: #fff; }
[data-bs-theme="dark"] .message-document,
[data-bs-theme="dark"] .media-preview { background: rgba(255,255,255,.03); color: var(--dm-txt, #e6eef1); }
[data-bs-theme="dark"] .conversation-search { background: rgba(255,255,255,.04); color: var(--dm-txt, #e6eef1); }
[data-bs-theme="dark"] .conversation-actions .btn { background: #0b1220; border-color: #1f2937; color: var(--dm-muted, #9ca3af); }
[data-bs-theme="dark"] a:not(.btn):not(.badge) { color: var(--dm-link, #a6f3c9); }
[data-bs-theme="dark"] ::placeholder { color: var(--dm-muted, #9ca3af) !important; opacity: 1; }
+6 -3
View File
@@ -60,12 +60,15 @@ class Layout
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title><?= $safeTitle ?> — <?= htmlspecialchars($appName, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8') ?></title>
<!-- Dark mode: aplica data-bs-theme antes del primer paint para evitar flash -->
<script>(function(){try{var m=window.matchMedia('(prefers-color-scheme: dark)');function a(d){document.documentElement.setAttribute('data-bs-theme',d?'dark':'light');}a(m.matches);m.addEventListener('change',function(e){a(e.matches);});}catch(e){}})();</script>
<!-- Bootstrap 5 -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
<!-- Font Awesome 6 -->
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css" rel="stylesheet">
<!-- Estilos del sistema -->
<link href="<?= $base ?>/assets/css/styles.css?v=14" rel="stylesheet">
<link href="<?= $base ?>/assets/css/styles.css?v=15" rel="stylesheet">
<style>
:root {
@@ -77,7 +80,7 @@ class Layout
.main-content {
margin-left: var(--sidebar-width);
min-height: 100vh;
background: #f8f9fa;
background: var(--bs-body-bg, #f8f9fa);
}
@media (max-width: 991.98px) {
.main-content { margin-left: 0; }
@@ -108,7 +111,7 @@ class Layout
<!-- Contenido principal -->
<main class="main-content">
<!-- Barra de título de módulo -->
<div class="bg-white border-bottom px-4 py-3 d-flex align-items-center justify-content-between">
<div class="bg-body-tertiary border-bottom px-4 py-3 d-flex align-items-center justify-content-between">
<h5 class="mb-0 fw-semibold">
<i class="<?= $safeIcon ?> me-2 text-primary"></i><?= $safeTitle ?>
</h5>
+2 -1
View File
@@ -89,9 +89,10 @@ try {
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title><?= htmlspecialchars($lugarNombre) ?> — Turnero</title>
<script>(function(){try{var m=window.matchMedia('(prefers-color-scheme: dark)');function a(d){document.documentElement.setAttribute('data-bs-theme',d?'dark':'light');}a(m.matches);m.addEventListener('change',function(e){a(e.matches);});}catch(e){}})();</script>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css" rel="stylesheet">
<link href="<?= BASE_URL ?>assets/css/styles.css?v=12" rel="stylesheet">
<link href="<?= BASE_URL ?>assets/css/styles.css?v=15" rel="stylesheet">
<style>
/* ── Layout ─────────────────────────────────────────────── */
.lugar-layout {
+2 -1
View File
@@ -134,9 +134,10 @@ $adminNombre = $_SESSION['admin_user']['full_name'] ?? $_SESSION['admin_user']['
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title><?= htmlspecialchars($deskNombre ?? 'Recepción') ?> — Turnero</title>
<script>(function(){try{var m=window.matchMedia('(prefers-color-scheme: dark)');function a(d){document.documentElement.setAttribute('data-bs-theme',d?'dark':'light');}a(m.matches);m.addEventListener('change',function(e){a(e.matches);});}catch(e){}})();</script>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css" rel="stylesheet">
<link href="<?= BASE_URL ?>assets/css/styles.css?v=12" rel="stylesheet">
<link href="<?= BASE_URL ?>assets/css/styles.css?v=15" rel="stylesheet">
<link href="https://cdn.jsdelivr.net/npm/tom-select@2.4.3/dist/css/tom-select.bootstrap5.min.css" rel="stylesheet">
<script src="https://cdn.jsdelivr.net/npm/tom-select@2.4.3/dist/js/tom-select.complete.min.js"></script>
<style>
+5
View File
@@ -56,6 +56,11 @@ if (!defined('_SIDEBAR_BRAND_INJECTED')) {
}
} catch (\Throwable $_) {}
echo "<style>:root{--brand:{$_sb_brand};--brand-dark:{$_sb_brand_dark}}</style>\n";
// Dark mode: activa Bootstrap 5.3 data-bs-theme si el head de la página no lo hizo ya
if (!defined('_DM_SCRIPT_INJECTED')) {
define('_DM_SCRIPT_INJECTED', true);
echo '<script>(function(){if(document.documentElement.hasAttribute("data-bs-theme"))return;try{var m=window.matchMedia("(prefers-color-scheme: dark)");function a(d){document.documentElement.setAttribute("data-bs-theme",d?"dark":"light");}a(m.matches);m.addEventListener("change",function(e){a(e.matches);});}catch(e){}})();</script>' . "\n";
}
}
// Ruta del script que está siendo cargado actualmente