Skip to content

主题定制 ​

AI Chat UI 使用 CSS Variables 实现主题定制,不依赖任何 CSS 框架。所有变量以 --ai-chat- 为前缀。

想可视化地调整主题?请打开 主题配置器 —— 所有三层令牌均可在线编辑、实时预览,并支持导出 CSS 覆盖文件。

三层令牌结构 ​

主题系统采用 原始 → 语义 → 组件 的三层令牌结构。三层各司其职,改一层不会波及其余:

层职责是否随主题翻转示例
原始 Primitive主题无关的原材料(色阶、圆角、字体、尺寸)否(不进 [data-theme])--ai-chat-color-accent-500、--ai-chat-neutral-100
语义 Semantic按用途命名的颜色,亮色在 :root、暗色在 [data-theme='dark'] 翻转是--ai-chat-color-bg-primary、--ai-chat-color-text-primary
组件 Component组件级映射,引用语义层否(引用而非取色)--ai-chat-bubble-radius

核心原则:组件只引用语义层,语义层引用原始层。换主题时只翻转语义层,原始层不动;换品牌色时只改原始层 accent 色阶,语义层自动跟随。

三档配置方式 ​

从高到低三种方式,可叠加使用,优先级递增:

1. Props 声明式(组件级,推荐起步方式) ​

通过 Conversation 的三个 Props 直接声明,作用于容器内部,不影响全局:

vue
<Conversation theme="purple" :custom-theme="{ '--ai-chat-color-accent-500': '#8b5cf6' }" dark-mode="dark">
  <!-- ... -->
</Conversation>
  • theme:内置预设名(default / purple / green / warm),只改原始层 accent 色阶。
  • custom-theme:自定义 CSS 变量键值对象,覆盖任意层令牌。
  • dark-mode:true / false 强制本容器明暗;'auto'(默认)跟随全局。

Props 以 inline style 应用到容器根元素,优先级最高,适合隔离的多实例场景。

2. useTheme 运行时切换(全局) ​

通过 useTheme composable 在运行时切换全局明暗,默认写入 document.documentElement 的 data-theme 并持久化到 localStorage。两个选项可改变这一行为:

  • target: 'html'(默认):data-theme 写宿主 <html>,整页生效。
  • target: 'component':data-theme 只写到组件根元素,暗色变量仅作用于组件子树,不碰宿主主题系统。
  • persist: false:关闭 localStorage 读写,主题不跨会话保留。
ts
// 组件内明暗切换,不影响宿主页面、不落 localStorage
const { resolvedTheme, toggleTheme } = useTheme({ target: 'component', persist: false })

基本用法:

vue
<script setup lang="ts">
import { useTheme } from '@toimc/vue'

const { theme, resolvedTheme, setTheme, toggleTheme } = useTheme()
// theme: 'light' | 'dark' | 'system'
// resolvedTheme: 实际解析后的 'light' | 'dark'
</script>

<template>
  <button @click="toggleTheme">
    当前:{{ resolvedTheme }}
  </button>
</template>

useTheme 是模块级单例,多个组件共享同一份状态。完整 API(返回值、类型、SSR 注意事项)见 useTheme 文档;预设与自定义变量的容器级应用见 useThemePreset 文档。

3. CSS 覆盖(宿主零 JS) ​

直接在自己的 CSS 里重定义变量,组件会自动跟随。适合全站统一定制:

css
:root {
  --ai-chat-color-accent-500: #7c3aed; /* 改原始层,语义层自动跟随 */
}

样式隔离与宿主覆盖(@layer) ​

组件库的全部样式都收在 CSS 级联层(@layer)内,层顺序在 tokens.css 顶部声明一次:

css
@layer ai-chat-base, ai-chat-tokens, ai-chat-components, ai-chat-animations;
/*      基础重置      令牌变量        组件样式           动画 keyframes */

这带来两个直接收益:

  1. 覆盖库样式无需 !important:CSS 规范中层内样式优先级低于任何未分层样式——宿主应用(通常不使用 @layer)的一行普通 CSS 天然覆盖组件库任意对应规则:

    css
    /* 宿主里的一行普通 CSS,直接生效,不需要 !important */
    .ai-chat-conversation { border-radius: 16px; }
  2. 库样式不会反向污染宿主:组件库自己写的规则永远压不过宿主样式;同时全局 * box-sizing reset 已收敛为只作用于组件库根子树(ai-chat-base 层内以 .ai-chat-conversation 为根的作用域选择器),宿主文档中除聊天窗口外没有任何元素被组件库规则命中。

何时用 @layer 覆盖、何时用变量?

调颜色/圆角等令牌时优先覆盖 CSS 变量;需要改结构型样式(边框、间距、布局)时直接写未分层 CSS 规则覆盖即可,两者都不需要 !important。

内置预设 ​

内置四套预设,只覆盖原始层 accent 色阶,暗色与亮色天然兼容:

预设 key名称主色
default默认靛蓝#6366f1
purple优雅紫#8b5cf6
green自然绿#059669
warm暖橙#ea580c
ts
import { presets, type PresetKey } from '@toimc/vue'

const purple = presets.purple // { name: '优雅紫', vars: {...} }

常用语义变量参考 ​

下表列出最常用的语义层变量(完整目录见 主题配置器,73 个令牌均可视化编辑)。

强调色 ​

变量名亮色默认说明
--ai-chat-color-accentvar(--ai-chat-color-accent-500)主色
--ai-chat-color-accent-hover#818cf8主色悬停
--ai-chat-color-text-on-accent#ffffff主色上的文字(发送按钮等)
--ai-chat-color-accent-dimrgba(99,102,241,0.15)主色淡底

背景 ​

变量名亮色默认暗色默认说明
--ai-chat-color-bg-primary#ffffff#171717主背景
--ai-chat-color-bg-secondary#f9fafb#262626次背景
--ai-chat-color-bg-chat#ffffff#171717聊天区背景
--ai-chat-color-bg-sidebar#f9fafb#171717侧边栏背景

文本 ​

变量名亮色默认暗色默认说明
--ai-chat-color-text-primary#171717#f9fafb主文本
--ai-chat-color-text-secondary#4b5563#a1a1aa次文本
--ai-chat-color-text-muted#9ca3af#71717a弱文本

边框与输入 ​

变量名亮色默认暗色默认说明
--ai-chat-color-border#e5e7eb#2e2e2e边框
--ai-chat-color-input-bg#f3f4f6#2f2f2f输入框背景
--ai-chat-color-input-border#d1d5db#404040输入框边框

消息 ​

变量名亮色默认暗色默认说明
--ai-chat-color-msg-user-bg#f3f4f6#2f2f2f用户消息背景
--ai-chat-color-msg-assistant-bgtransparenttransparentAI 消息背景

状态色 ​

变量名亮色默认暗色默认说明
--ai-chat-color-status-error#ef4444#f87171错误
--ai-chat-color-status-warning#f59e0b#fbbf24警告
--ai-chat-color-status-success#10b981#34d399成功

组件 ​

变量名默认值说明
--ai-chat-bubble-radiusvar(--ai-chat-radius-lg)气泡圆角(引用原始层)

布局与响应式 ​

变量名默认值说明
--ai-chat-content-max-width768px消息区标准限宽
--ai-chat-content-max-width-wide1024px宽屏(容器 ≥1100px)消息区限宽
--ai-chat-message-max-width480pxim 模式单条消息气泡限宽
--ai-chat-input-max-height200px输入框最大高度(桌面端)
--ai-chat-input-max-height-mobile120px输入框最大高度(移动端)
--ai-chat-breakpoint-sm480px小屏断点 sm(语义参考)
--ai-chat-breakpoint-md640px中屏断点 md:输入紧凑、对比卡堆叠(CSS 容器查询为字面量 640px)
--ai-chat-breakpoint-lg1024px大屏断点 lg(语义参考)
--ai-chat-breakpoint-xl1280px超大屏断点 xl:消息区放宽(容器查询为字面量 1280px)
--ai-chat-z-toast1000Toast 弹层层级
--ai-chat-z-popup1000灯箱等全屏弹层层级

使用方式 ​

全局覆盖 ​

在根样式中重定义变量:

css
:root {
  --ai-chat-color-accent-500: #7c3aed; /* 改原始层主色,语义层自动跟随 */
}

组件级覆盖 ​

通过父容器限定作用域,只影响该容器内的组件:

css
.my-chat {
  --ai-chat-color-bg-chat: #ecfdf5;
  --ai-chat-color-msg-user-bg: #d1fae5;
}
vue
<Conversation class="my-chat">
  <!-- ... -->
</Conversation>

暗色模式 ​

默认亮色(:root),暗色通过 [data-theme='dark'] 翻转语义层:

css
[data-theme='dark'] {
  --ai-chat-color-bg-primary: #0a0a0a;
  --ai-chat-color-text-primary: #f9fafb;
}

通常无需手写——组件库已内置完整的暗色语义层,调用 toggleTheme() 或在 <html> 上设 data-theme="dark" 即可。