Обзор — что делает
Консоль 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браузера. Она переживает выход из системы, а если кто-то войдёт под той же учётной записью на другом устройстве, это устройство будет следовать собственной настройке.
Когда использовать
- Ночные смены / настенные панели NOC → тёмная (меньше бликов, выше контраст цветов критичности).
- Светлые офисы, проекторы, снимки экрана для документации → светлая.
- Личные предпочтения по контрасту или цветовосприятию — переключается для каждого пользователя.
После выбора настройка сохраняется в этом браузере, поэтому обычно её задают лишь один раз.
Структура экрана
Кнопка переключения в верхней панели
И оболочка консоли (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-консоль сохраняет тёмный терминал.
Как пользоваться
Переключение
- Нажмите значок полумесяца (Сменить тему) справа в верхней панели.
- Тёмная ↔ светлая меняются немедленно, а выбор сохраняется автоматически.
- При следующем посещении или перезагрузке страницы восстанавливается ваш последний выбор.
Как это устроено (справка для разработчика)
Клиентская часть подключается в 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безопасно откатывается к тёмной теме.
Диаграммы и редакторы следуют теме
- ECharts (
<metric-chart>/ echarts-kit): читает токены--infr-*черезgetComputedStyle, чтобы построить цвета диаграммы, оси и подсказки, и перекрашивается по событиюinfr:theme. Проверкаis_dark()выглядит какdata-theme !== 'light'(тёмная тема — значение по умолчанию). См. Временные ряды серверов. - CodeMirror (
<cm-editor>): свойство:darkпереключает междуoneDark(тёмная) и светлой темой. Страницы Vue вычисляютis_dark_mode = document.documentElement.dataset.theme === 'dark', передают его как:dark="is_dark_mode"и обновляют по событиюinfr:theme. См. Конструктор скриптов резервного копирования.
<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 — источник истины для оформления палитры.
Доступ
Тема — это настройка интерфейса, не связанная с аутентификацией и авторизацией.
- Любой пользователь, включая гостей (до входа), может свободно её переключать — без ограничений по уровню.
- Поведение одинаково при demo=1 / staff=5 / admin=10.
- Поскольку на сервере ничего не записывается, она никогда не появляется в журнале аудита (
infr_audit_log).
Устранение неполадок и часто задаваемые вопросы
В. Тема сбрасывается при перезагрузке.
Если браузер блокирует 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, и запоминается только то, что пользователь явно выбрал кнопкой. Интеграция с ОС — пункт дорожной карты.
Связанные материалы
- Навигация и компоновка — область действий верхней панели (тема / язык / меню пользователя)
- Язык · локаль — вторая клиентская настройка наряду с темой
- Поиск по этому руководству — поиск и структура /manual
- Временные ряды серверов и MetricChart — диаграммы, перекрашиваемые по токенам темы
- Конструктор скриптов резервного копирования — привязка
:darkв CodeMirror - SSH-консоль — терминал, постоянно тёмный и независимый от темы приложения
