InfraGuard

浅色 / 深色主题

在浅色与深色之间切换控制台 — 根元素上的单个 data-theme 属性、保存在 localStorage(infr-theme)中的偏好、页眉的切换按钮,以及全部以 --infr-* CSS 变量令牌表达的颜色。

概述 — 这个功能做什么

InfraGuard 控制台内置两套主题:深色(默认) 和 浅色。主题通过文档根元素(<html>)上的单个属性 data-theme 切换,其取值会整体替换 SCSS 中定义的 --infr-* CSS 变量令牌 集合。所有组件都使用 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 严重程度 critical #fb7185 #e11d48
--infr-warn 严重程度 warning #fbbf24 #b45309
--infr-good 严重程度 healthy #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"
应用到 document.documentElement(即 <html>)上的 data-theme 属性
默认值 dark(当 localStorage 为空或不可读时)
事件 每次切换都会在 window 上触发 infr:theme CustomEvent(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 切换 / 持久化 / 事件绑定

CLAUDE.md 的 附录 C(浅色 / 深色主题令牌) 是调色板设计的权威依据。


访问权限

主题是 与认证或授权无关的界面偏好。


排障与常见问题

Q. 刷新后主题被重置了。 如果浏览器阻止了 localStorage(无痕模式、严格隐私设置、第三方存储拦截),则无法保存选择,每次都会退回默认的 深色。请为该站点授予存储访问权限。

Q. 我在一个标签页里改了,另一个标签页没有更新。 切换会通过 storage 事件传播到 同一浏览器的其他标签页。如果没有立即生效,可能是该标签页尚未加载监听器绑定(app.js)— 请刷新它。不同 设备/浏览器 的存储彼此独立,不会同步(这是设计如此)。

Q. 我切换到了浅色,但 SSH 终端仍然是深色。 这是预期行为。终端使用专门的 --infr-term-* 调色板,无论应用主题如何都保持深邃的深色(为了可读性 / 沉浸感)。

Q. 某个组件显示不正常(主题对它不生效)。 那个组件硬编码了十六进制色值而不是使用令牌。按照约定,组件只能使用 var(--infr-*) 令牌。请用回归检查的 grep 确认 resources/scss/pages 中没有直接写死的十六进制色值:

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

Q. 我希望它跟随操作系统的深色模式。 当前实现 不会 跟随操作系统偏好(prefers-color-scheme)。初始值始终是 dark,并且只记住用户通过切换按钮显式选择的值。操作系统集成是路线图中的项目。


相关内容

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