主题与 UI 样式
@ydesign/react-editor 的界面由 内置 shadcn 组件 + 语义 CSS 变量 驱动。接入时引入一份样式,即可用内置主题 API 切换明暗与主色,或覆盖 CSS 变量做品牌定制。
样式栈一览
| 层级 | 技术选型 | 用途 |
|---|---|---|
| 组件 | 内置 shadcn(Button、Dialog、Select、Tooltip…) | 编辑器全部表单 / 反馈 UI |
| 主题令牌 | 语义 CSS 变量(--primary、--background…) | 颜色、圆角、边框;明暗与预设都写在这些变量上 |
| 原子类 | Tailwind CSS v4(已编译进 style.css) | 布局、间距、dark: 变体 |
| 布局容器 | styled-components | DesignEditorContainer / SidePanelWrap / WorkspaceWrap 等 |
| 主题 API | @ydesign/react-editor/theme | useTheme / setTheme / ThemeSwitcher |
| 画布引擎 | @ydesign/core | 无 UI 样式依赖 |
消费方不必再安装 Tailwind、shadcn 或独立 token 包;一行样式即可:
import '@ydesign/react-editor/style.css';
1. 快速接入:内置主题切换
Demo / 脚手架已提供完整开关,业务 Topbar 可直接挂上:
import '@ydesign/react-editor/style.css';
import { ThemeSwitcher } from '@ydesign/react-editor/theme';
export function Topbar() {
return (
<header>
{/* 明暗三段切换 + 主色预设圆点 */}
<ThemeSwitcher />
</header>
);
}
也可拆开用:
import { ModeToggle, PresetPicker } from '@ydesign/react-editor/theme';
<ModeToggle /> {/* light / dark / system */}
<PresetPicker /> {/* 主色预设 */}
状态是模块级单例,持久化到 localStorage(key:ydl-theme)。ThemeProvider 可选,仅用于挂载时写入默认值:
import { ThemeProvider } from '@ydesign/react-editor/theme';
<ThemeProvider defaultMode="system" defaultPreset="blue">
<App />
</ThemeProvider>
2. 主题如何工作
setTheme({ mode, preset })
│
▼
document.documentElement
├─ classList.toggle('dark', isDark) ← Tailwind / shadcn 暗色
└─ style.setProperty('--primary', …) ← 当前预设主色
style.setProperty('--primary-foreground', …)
style.setProperty('--sidebar-primary', …)
…
| 维度 | 取值 | 效果 |
|---|---|---|
mode | 'light' | 'dark' | 'system' | 控制 <html> 是否带 .dark;system 跟随 prefers-color-scheme |
preset | 'neutral' | 'blue' | 'orange' | … | 覆盖 --primary / --sidebar-primary 等(亮暗各有一套色值) |
resolvedMode | 'light' | 'dark' | system 解析后的实际明暗,只读 |
内置预设见 PRESETS(neutral、amber、blue、cyan、emerald、fuchsia、green、indigo、lime、orange、pink、purple、red、rose、sky、teal、violet、yellow 等)。默认:mode: 'light',preset: 'neutral'。
底层变量定义在包内 globals.css 的 :root / .dark;Tailwind 通过 @custom-variant dark (&:is(.dark *)) 识别暗色。
3. 编程式控制
3.1 React:useTheme
import { useTheme } from '@ydesign/react-editor/theme';
function BrandBar() {
const { mode, resolvedMode, preset, color, setMode, setPreset, toggleMode } = useTheme();
return (
<div>
<span>当前:{resolvedMode} / {preset}</span>
<button type="button" onClick={() => setMode('dark')}>深色</button>
<button type="button" onClick={() => setPreset('orange')}>橙色品牌</button>
<button type="button" onClick={toggleMode}>轮换 light → dark → system</button>
<span style={{ color }}>主色预览</span>
</div>
);
}
3.2 非 React / 启动时:setTheme
import { setTheme, getTheme, subscribeTheme } from '@ydesign/react-editor/theme';
// 启动时强制品牌色
setTheme({ mode: 'system', preset: 'blue' });
const current = getTheme(); // { mode, preset, resolvedMode }
const unsub = subscribeTheme(state => {
console.log('theme changed', state);
});
4. 品牌定制:覆盖语义变量
预设不够时,直接覆盖 CSS 变量即可;shadcn 组件与编辑器布局都会跟着变。
/* 全局品牌色(在引入 style.css 之后) */
:root {
--primary: oklch(0.55 0.18 40);
--primary-foreground: oklch(0.99 0 0);
--radius: 0.5rem;
--font-sans: 'PingFang SC', 'Helvetica Neue', sans-serif;
}
.dark {
--primary: oklch(0.72 0.14 40);
--primary-foreground: oklch(0.2 0 0);
}
常用变量:
| 变量 | 用途 |
|---|---|
--background / --foreground | 页面底 / 正文 |
--card / --popover | 卡片、弹出层 |
--primary / --primary-foreground | 主按钮、高亮、选中态 |
--muted / --muted-foreground | 次要背景 / 说明文字 |
--border / --input / --ring | 边框、输入框、焦点环 |
--destructive | 危险操作 |
--sidebar* | 侧栏相关 |
--radius | 全局圆角基准 |
在组件里也可以用 Tailwind 语义色:bg-background、text-foreground、bg-primary、border-border、text-muted-foreground 等(已映射到上表变量)。
注意: 若同时使用
ThemeSwitcher/setTheme(preset),预设会在运行时再次写入--primary等。品牌色若要「锁死」,请固定一个preset,或在业务里自行setProperty,不要和用户切换预设冲突。
5. 局部样式覆盖
变量覆盖不了的细节,可用稳定 class / 属性选择器。部分历史类名仍带 polotno- 前缀(兼容遗留),新代码优先用语义变量与 Tailwind。
/* 编辑器最外层 */
.polotno-app-container {
background: var(--background);
color: var(--foreground);
}
/* 侧栏 Tab 选中态跟主色 */
.polotno-side-panel-tab.active {
color: var(--primary);
}
/* 工作区底 */
.polotno-workspace-container {
background: var(--muted);
}
自建壳里也可以直接用语义类:
<div className="flex h-screen bg-background text-foreground">
<aside className="w-64 border-r border-border bg-sidebar text-sidebar-foreground">…</aside>
<main className="flex-1">…</main>
</div>
6. 字体
| 范围 | 怎么改 |
|---|---|
| UI 字体 | 覆盖 --font-sans / --font-heading,或在容器上设 font-family |
| 画布文字字体 | 与 UI 无关,走 store.fonts / 字体管理,见 编辑器配置 · 字体 |
:root {
--font-sans: 'Inter', 'PingFang SC', system-ui, sans-serif;
}
7. 注意事项
- 必须引入
import '@ydesign/react-editor/style.css',否则组件几乎无样式。 - 消费方不必自装 Tailwind;
style.css已含编译后的 utility。若业务项目自己也用 Tailwind v4,注意不要与包内语义色变量定义冲突。 - 暗色模式通过
<html class="dark">生效;推荐用setTheme/ThemeSwitcher,不要手写散落的 class 切换。 - SSR:首屏前根据 cookie / UA 设好
class="dark"与关键变量,避免亮→暗闪烁;useTheme在服务端有 light/neutral 的 fallback snapshot。 @ydesign/core画布本身无主题;画布背景色是设计稿数据(workareafill),不是 UI--background。
延伸阅读
- 定制化 —— 替换 / 扩展面板与工具栏
- 编辑器配置 —— 上传、i18n、字体、后端
- shadcn/ui Theming
- Tailwind CSS v4 Dark mode