InfraGuard

Светлая / тёмная тема

Переключение консоли между светлым и тёмным оформлением — единственный атрибут data-theme на корневом элементе, сохранение в localStorage (infr-theme), кнопка в верхней панели и все цвета в виде токенов CSS-переменных --infr-*.

Обзор — что делает

Консоль InfraGuard поставляется с двумя темами: тёмной (по умолчанию) и светлой. Тема переключается единственным атрибутом на корневом элементе документа (<html>) — data-theme, значение которого подменяет весь набор токенов CSS-переменных --infr-*, определённых в SCSS. Все компоненты используют токены var(--infr-*), а не жёстко заданные шестнадцатеричные значения, поэтому смена одного слова (dark ↔ light) мгновенно перекрашивает весь интерфейс.

По умолчанию используется тёмная тема: как консоль NOC (центра управления сетью) она применяет глубокий сине-чёрный фон с бирюзовыми сигнальными акцентами, чтобы цвета критичности (crit / warn / good) чётко читались на тёмном поле.

<html data-theme="dark">   ← по умолчанию, тёмная тема NOC
<html data-theme="light">  ← светлая (ярко освещённые офисы)

Тема — это исключительно клиентская настройка. Она никогда не сохраняется на сервере и никак не связана с вашей учётной записью или базой данных: она живёт только в localStorage браузера. Она переживает выход из системы, а если кто-то войдёт под той же учётной записью на другом устройстве, это устройство будет следовать собственной настройке.


Когда использовать

После выбора настройка сохраняется в этом браузере, поэтому обычно её задают лишь один раз.


Структура экрана

Кнопка переключения в верхней панели

И оболочка консоли (layouts/app.blade.php), и экран входа (layouts/simple.blade.php) размещают кнопку смены темы справа в верхней панели.

Элемент Значение
Точка привязки в разметке <button data-theme-toggle>
Значок mdi-theme-light-dark (полумесяц)
aria-label msg.action.theme (локализовано)
Действие Щелчок переключает тёмную ↔ светлую
Расположение Область действий верхней панели (рядом с переключателем языка, слева от меню пользователя)

На экране до входа (гостевом) есть та же кнопка, поэтому сменить тему можно без аутентификации.

Группы цветовых токенов

Файл resources/scss/_variables.scss определяет одни и те же имена токенов с разными значениями в двух блоках: :root[data-theme="dark"] и :root[data-theme="light"]. Показательные токены:

Токен Назначение dark light
--infr-bg Фон страницы #0b1220 #f6f8fb
--infr-surface Поверхность панели / карточки #111b2c #ffffff
--infr-fg Основной текст #e9eff8 #111a28
--infr-fg-muted Второстепенный текст #8493ac #63728b
--infr-border Границы #1e2c43 #dbe2ec
--infr-accent Акцент (бирюзовый) #2dd4bf #0d9488
--infr-crit Критическая важность #fb7185 #e11d48
--infr-warn Предупреждение #fbbf24 #b45309
--infr-good Нормальное состояние #34d399 #0f9d6a
--infr-info Информация #38bdf8 #0369a1

Помимо них каждая тема определяет также --infr-surface-2/hi, --infr-border-2, --infr-accent-soft/ink, --infr-on-accent (текст кнопки на акцентном фоне), цвета состояний TCP (--infr-state-*), цвета диаграмм (--infr-chart-2), тень и свечение (--infr-shadow / --infr-glow), а также стекло верхней панели (--infr-topbar-*). Каждый блок дополнительно объявляет color-scheme: dark|light, чтобы системные элементы форм и полосы прокрутки соответствовали теме.

Палитра SSH-терминала — исключение. Токены --infr-term-* остаются глубоко тёмными и «погружающими» независимо от data-theme. Даже в светлой теме SSH-консоль сохраняет тёмный терминал.


Как пользоваться

Переключение

  1. Нажмите значок полумесяца (Сменить тему) справа в верхней панели.
  2. Тёмная ↔ светлая меняются немедленно, а выбор сохраняется автоматически.
  3. При следующем посещении или перезагрузке страницы восстанавливается ваш последний выбор.

Как это устроено (справка для разработчика)

Клиентская часть подключается в resources/js/app.js. Основная логика:

const THEME_KEY = 'infr-theme';                 // ключ localStorage
const get_theme = () => localStorage.getItem(THEME_KEY) || 'dark';   // по умолчанию тёмная
const set_theme = (t) => {
    document.documentElement.setAttribute('data-theme', t);   // атрибут корневого элемента
    localStorage.setItem(THEME_KEY, t);                        // сохранить
    window.dispatchEvent(new CustomEvent('infr:theme', { detail: t })); // перекрасить диаграммы
};
// подключить кнопку переключения
document.querySelectorAll('[data-theme-toggle]')
    .forEach(btn => btn.addEventListener('click',
        () => set_theme(get_theme() === 'dark' ? 'light' : 'dark')));

Сводка поведения:

Шаг Что
Ключ хранения localStorage['infr-theme'] = "dark" | "light"
Применяется к атрибуту data-theme на document.documentElement (то есть на <html>)
По умолчанию dark (когда localStorage пуст или недоступен для чтения)
Событие Каждое переключение порождает CustomEvent infr:theme на window (detail = текущая тема)
Синхронизация между вкладками Слушает событие storage → другие вкладки того же браузера синхронизируются автоматически

Предотвращение мелькания нестилизованного содержимого (FOUC) — скрипт до отрисовки

Крошечный встроенный скрипт в самом начале <head> (общий для app.blade.php и simple.blade.php, до загрузки CSS через @vite) устанавливает data-theme раньше, чем применится любая таблица стилей. Это устраняет «мелькание тёмное→светлое» при перезагрузке.

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

Даже там, где localStorage заблокирован (режим инкогнито, блокировка стороннего хранилища и т. п.), блок catch безопасно откатывается к тёмной теме.

Диаграммы и редакторы следуют теме

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

Источники данных

У темы вообще нет хранения ни в БД, ни на сервере. Используются только:

Расположение Содержимое
localStorage['infr-theme'] Выбор пользователя в каждом браузере (dark/light)
<html data-theme> Состояние, применённое во время выполнения
resources/scss/_variables.scss Фактические значения токенов --infr-* для каждой темы (собираются в CSS)
resources/js/app.js Переключение / сохранение / подключение событий

Приложение C (токены светлой/тёмной темы) в CLAUDE.md — источник истины для оформления палитры.


Доступ

Тема — это настройка интерфейса, не связанная с аутентификацией и авторизацией.


Устранение неполадок и часто задаваемые вопросы

В. Тема сбрасывается при перезагрузке. Если браузер блокирует localStorage (режим инкогнито, строгие настройки конфиденциальности, блокировка стороннего хранилища), выбор невозможно сохранить и он каждый раз возвращается к тёмной теме по умолчанию. Разрешите сайту доступ к хранилищу.

В. Я изменил тему в одной вкладке, но другая вкладка не обновилась. Переключение распространяется на другие вкладки того же браузера через событие storage. Если оно не отражается сразу, эта вкладка, возможно, ещё не загрузила подключение обработчика (app.js) — перезагрузите её. Разные устройства и браузеры имеют отдельные хранилища и не синхронизируются (так задумано).

В. Я переключился на светлую тему, но SSH-терминал остаётся тёмным. Это ожидаемое поведение. Терминал использует выделенную палитру --infr-term-*, которая остаётся глубоко тёмной независимо от темы приложения (ради читаемости и погружения).

В. Один компонент выглядит неправильно (тема на него не действует). В этом компоненте вместо токенов жёстко заданы шестнадцатеричные значения. По соглашению компоненты обязаны использовать только токены var(--infr-*). Проверьте наличие прямых шестнадцатеричных значений в resources/scss/pages регрессионным grep:

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

В. Я хочу, чтобы тема следовала тёмному режиму моей операционной системы. Текущая реализация не следует системной настройке (prefers-color-scheme). Начальное значение всегда dark, и запоминается только то, что пользователь явно выбрал кнопкой. Интеграция с ОС — пункт дорожной карты.


Связанные материалы

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