InfraGuard

Tema claro / oscuro

Alterna la consola entre claro y oscuro: un único atributo data-theme en la raíz, persistido en localStorage (infr-theme), un botón en la cabecera y todos los colores como tokens de variable CSS --infr-*.

Resumen — qué hace

La consola de InfraGuard se entrega con dos temas: oscuro (predeterminado) y claro. El tema se cambia mediante un único atributo en la raíz del documento (<html>), data-theme, cuyo valor intercambia todo el conjunto de tokens de variable CSS --infr-* definidos en SCSS. Todos los componentes usan tokens var(--infr-*) en lugar de valores hexadecimales fijos, así que cambiar una sola palabra (dark ↔ light) vuelve a pintar al instante toda la interfaz.

El valor predeterminado es oscuro: al tratarse de una consola de NOC (centro de operaciones de red), usa un fondo azul-negro profundo con acentos de señal en verde azulado, de modo que los colores de gravedad (crit / warn / good) se lean con nitidez sobre un campo oscuro.

<html data-theme="dark">   ← predeterminado, oscuro de NOC
<html data-theme="light">  ← claro (entornos de oficina luminosos)

El tema es una preferencia puramente de front-end. Nunca se almacena en el servidor y no tiene nada que ver con su cuenta ni con la base de datos: vive únicamente en el localStorage del navegador. Sobrevive al cierre de sesión y, si otra persona inicia sesión con la misma cuenta en otro dispositivo, ese dispositivo sigue su propio ajuste.


Cuándo utilizarlo

Una vez elegido persiste en ese navegador, de modo que normalmente solo se configura una vez.


Disposición

Botón de conmutación en la cabecera

Tanto el armazón de la consola (layouts/app.blade.php) como la pantalla de acceso (layouts/simple.blade.php) colocan un botón de cambio de tema a la derecha de la barra superior.

Elemento Valor
Punto de anclaje en el marcado <button data-theme-toggle>
Icono mdi-theme-light-dark (media luna)
aria-label msg.action.theme (localizado)
Acción Al hacer clic alterna oscuro ↔ claro
Posición Área de acciones de la barra superior (junto al selector de idioma, a la izquierda del menú de usuario)

La pantalla previa al acceso (invitado) lleva el mismo botón, de modo que puede cambiar de tema sin autenticarse.

Grupos de tokens de color

resources/scss/_variables.scss define los mismos nombres de token con valores distintos en dos bloques: :root[data-theme="dark"] y :root[data-theme="light"]. Tokens representativos:

Token Finalidad dark light
--infr-bg Fondo de la página #0b1220 #f6f8fb
--infr-surface Superficie de panel / tarjeta #111b2c #ffffff
--infr-fg Texto del cuerpo #e9eff8 #111a28
--infr-fg-muted Texto secundario #8493ac #63728b
--infr-border Bordes #1e2c43 #dbe2ec
--infr-accent Acento (verde azulado) #2dd4bf #0d9488
--infr-crit Gravedad crítica #fb7185 #e11d48
--infr-warn Gravedad de advertencia #fbbf24 #b45309
--infr-good Gravedad saludable #34d399 #0f9d6a
--infr-info Información #38bdf8 #0369a1

Más allá de estos, cada tema define además --infr-surface-2/hi, --infr-border-2, --infr-accent-soft/ink, --infr-on-accent (texto de botón sobre el acento), colores de estado TCP (--infr-state-*), colores de gráfico (--infr-chart-2), sombra/resplandor (--infr-shadow / --infr-glow) y el cristal de la barra superior (--infr-topbar-*). Cada bloque declara también color-scheme: dark|light, de modo que los controles de formulario nativos y las barras de desplazamiento coincidan con el tema.

La paleta del terminal SSH es una excepción. Los tokens --infr-term-* permanecen en un oscuro profundo e inmersivo con independencia de data-theme. Incluso con el tema claro, la consola SSH mantiene un terminal oscuro.


Cómo utilizarlo

Cambiar de tema

  1. Haga clic en el icono de media luna (Cambiar tema) a la derecha de la barra superior.
  2. Alterna oscuro ↔ claro de inmediato y la elección se guarda automáticamente.
  3. En la siguiente visita o al recargar la página se restaura su última elección.

Bajo el capó (referencia para desarrolladores)

El front-end se conecta en resources/js/app.js. Lógica principal:

const THEME_KEY = 'infr-theme';                 // clave de localStorage
const get_theme = () => localStorage.getItem(THEME_KEY) || 'dark';   // oscuro por defecto
const set_theme = (t) => {
    document.documentElement.setAttribute('data-theme', t);   // atributo de la raíz
    localStorage.setItem(THEME_KEY, t);                        // persistir
    window.dispatchEvent(new CustomEvent('infr:theme', { detail: t })); // repintar los gráficos
};
// conectar el botón de conmutación
document.querySelectorAll('[data-theme-toggle]')
    .forEach(btn => btn.addEventListener('click',
        () => set_theme(get_theme() === 'dark' ? 'light' : 'dark')));

Resumen del comportamiento:

Paso Qué
Clave de almacenamiento localStorage['infr-theme'] = "dark" | "light"
Se aplica a atributo data-theme en document.documentElement (el <html>)
Predeterminado dark (cuando localStorage está vacío o no se puede leer)
Evento Cada cambio dispara un CustomEvent infr:theme en window (detail = tema actual)
Sincronización entre pestañas Escucha el evento storage → las demás pestañas del mismo navegador se sincronizan automáticamente

Prevención del destello de contenido sin estilo (FOUC) — script previo al pintado

Un pequeño script en línea situado al principio de <head> (compartido por app.blade.php y simple.blade.php, antes de la carga de CSS con @vite) fija data-theme antes de que se aplique ninguna hoja de estilo. Esto elimina el "destello oscuro→claro" al recargar.

<script>
  (function () {
    try { document.documentElement.setAttribute('data-theme',
            localStorage.getItem('infr-theme') || 'dark'); }
    catch (e) { document.documentElement.setAttribute('data-theme', 'dark'); }
  })();
</script>

Incluso donde localStorage está bloqueado (modo incógnito, almacenamiento de terceros bloqueado, etc.), el catch recurre de forma segura a oscuro.

Los gráficos y los editores siguen al tema

<cm-editor v-model="script.body" lang="bash" :dark="is_dark_mode"></cm-editor>

Fuentes de datos

El tema no tiene absolutamente ningún almacenamiento en base de datos ni en el servidor. Solo utiliza:

Ubicación Contenido
localStorage['infr-theme'] Elección del usuario por navegador (dark/light)
<html data-theme> Estado aplicado en tiempo de ejecución
resources/scss/_variables.scss Valores reales de los tokens --infr-* para cada tema (compilados en el CSS)
resources/js/app.js Conmutación / persistencia / conexión de eventos

El apéndice C (tokens del tema claro/oscuro) de CLAUDE.md es la fuente de verdad del diseño de la paleta.


Acceso

El tema es una preferencia de interfaz ajena a la autenticación y a la autorización.


Resolución de problemas y preguntas frecuentes

P. El tema se reinicia al recargar. Si el navegador bloquea localStorage (modo incógnito, ajustes estrictos de privacidad, bloqueo del almacenamiento de terceros), la elección no puede guardarse y vuelve cada vez al valor predeterminado oscuro. Conceda acceso al almacenamiento para el sitio.

P. Lo cambié en una pestaña, pero otra pestaña no se actualizó. El cambio se propaga a las demás pestañas del mismo navegador mediante el evento storage. Si no se refleja de inmediato, puede que esa pestaña todavía no haya cargado la conexión del escuchador (app.js): recárguela. Los dispositivos/navegadores distintos tienen almacenamientos separados y no se sincronizan (así está diseñado).

P. Cambié a claro, pero el terminal SSH sigue oscuro. Es lo esperado. El terminal usa una paleta dedicada --infr-term-* que permanece muy oscura con independencia del tema de la aplicación (legibilidad / inmersión).

P. Un componente se ve mal (el tema no se le aplica). Ese componente fijó valores hexadecimales en lugar de tokens. Por convención, los componentes deben usar únicamente tokens var(--infr-*). Busque valores hexadecimales directos en resources/scss/pages con el grep de regresión:

rg -n "#[0-9a-fA-F]{3,6}" resources/scss/pages

P. Quiero que siga el modo oscuro de mi sistema operativo. La implementación actual no sigue la preferencia del sistema operativo (prefers-color-scheme). El valor inicial es siempre dark y solo recuerda lo que el usuario eligió explícitamente con el botón. La integración con el sistema operativo es un elemento de la hoja de ruta.


Relacionado

상단바 오른쪽의 테마 · 언어 전환
상단바 오른쪽의 테마 · 언어 전환