主题定制指南
DayFlow Calendar 的外观由一组带命名空间的 CSS 自定义属性(--df-color-*)控制。所有 token 都定义在 @layer df-theme 内部,因此宿主应用无需使用 !important 即可覆盖它们——无论是否使用 Tailwind 都适用。
DayFlow 的共享基础样式是 token、组件基础规则和 df-* 语义辅助类的统一来源,例如 df-fill-primary、df-tint-primary、df-focus-ring 等。
目录
日历类型自定义颜色
基础自定义颜色
为每个日历类型定义独立的浅色和深色配色方案:
const calendar = useCalendarApp({
calendarTypes: [
{
id: 'personal',
name: '个人日程',
colors: {
lineColor: '#0891b2', // cyan-600
eventColor: '#cffafe', // cyan-100
eventSelectedColor: '#a5f3fc', // cyan-200
textColor: '#164e63', // cyan-900
},
darkColors: {
lineColor: '#22d3ee', // cyan-400
eventColor: '#164e63', // cyan-900
eventSelectedColor: '#083344', // cyan-950
textColor: '#cffafe', // cyan-100
},
},
],
});颜色属性说明
- lineColor:边框和强调色(事件左侧竖条)
- eventColor:事件背景填充色
- eventSelectedColor:选中事件时的背景填充色
- textColor:事件标题和时间的文字颜色
品牌颜色集成
{
id: 'brand',
name: '品牌活动',
colors: {
lineColor: '#6366f1', // 品牌靛蓝色
eventColor: '#e0e7ff', // Indigo-100
eventSelectedColor: '#c7d2fe', // Indigo-200
textColor: '#312e81', // Indigo-900
},
darkColors: {
lineColor: '#a5b4fc', // Indigo-300
eventColor: '#312e81', // Indigo-900
eventSelectedColor: '#1e1b4b', // Indigo-950
textColor: '#e0e7ff', // Indigo-100
},
}颜色生成工具函数
// utils/colorGenerator.ts
interface ColorSet {
lineColor: string;
eventColor: string;
eventSelectedColor: string;
textColor: string;
}
export function generateLightColors(baseColor: string): ColorSet {
return {
lineColor: baseColor,
eventColor: lighten(baseColor, 0.9),
eventSelectedColor: lighten(baseColor, 0.8),
textColor: darken(baseColor, 0.4),
};
}
export function generateDarkColors(baseColor: string): ColorSet {
return {
lineColor: lighten(baseColor, 0.3),
eventColor: darken(baseColor, 0.6),
eventSelectedColor: darken(baseColor, 0.7),
textColor: lighten(baseColor, 0.8),
};
}CSS 变量参考
所有 DayFlow 主题 token 均使用 --df-color- 前缀,以避免与宿主应用的变量命名冲突。
| 变量 | 用途 |
|---|---|
--df-color-background | 日历背景色 |
--df-color-foreground | 主文本颜色 |
--df-color-hover | 悬停状态背景色 |
--df-color-border | 边框和分割线 |
--df-color-card | 卡片 / 面板背景色 |
--df-color-card-foreground | 卡片内文本颜色 |
--df-color-muted | 低调背景区域 |
--df-color-muted-foreground | 辅助 / 次要文本颜色 |
--df-color-primary | 主强调色(按钮、选中状态等) |
--df-color-primary-foreground | 主色背景上的文本 |
--df-color-secondary | 次要强调色 |
--df-color-secondary-foreground | 次要色背景上的文本 |
--df-color-destructive | 破坏性操作(删除等) |
--df-color-destructive-foreground | 破坏性背景上的文本 |
语义辅助类
除了 CSS 变量之外,DayFlow 现在还暴露了一套主题感知的 df-* 语义辅助类,适合在 slot、自定义弹层、插件 UI 中复用,使外观与内置控件保持一致。
| 类名 | 含义 |
|---|---|
df-fill-primary | 主色实心背景 + 自动前景文字 |
df-fill-secondary | 次色实心背景 + 自动前景文字 |
df-fill-destructive | 危险态实心背景 + 自动前景文字 |
df-tint-primary | 主色轻染选中态 |
df-hover-primary | 主色语义悬停态 |
df-hover-primary-solid | 主色实心按钮悬停态 |
df-text-primary | 主色文字 |
df-border-primary | 主色边框 |
df-ring-primary | 主色 ring token |
df-focus-ring | 焦点时同时设置主色边框与 ring |
推荐优先使用这些 df-* 类或 --df-color-* 变量,不要再依赖 bg-primary、text-primary、hover:bg-primary/90 等旧的内部 Tailwind 语义类名。
覆盖方法
方法 1 — 容器级覆盖(适用于所有场景)
直接在 .df-calendar-container 上设置变量。由于该规则不属于任何 @layer,它始终优先于库的默认值,与 Tailwind 版本无关。
/* styles/globals.css */
.df-calendar-container {
--df-color-primary: #6366f1;
--df-color-background: #f9fafb;
--df-color-border: #e0e7ff;
}
/* 深色模式 — 当祖先元素带有 .dark 类时生效 */
.dark .df-calendar-container {
--df-color-primary: #a5b4fc;
--df-color-background: #1e1e2e;
--df-color-border: #312e81;
}大多数项目推荐使用此方法。变量仅作用于日历组件内部,不会影响外部元素。
Tailwind v4 集成
Tailwind v4 完全通过 CSS 配置,不再需要 tailwind.config.js。DayFlow 分发的 CSS 已经包含共享基础样式,因此主题 token 和 df-* 语义类在导入后即可使用。
选择正确的 CSS 文件
DayFlow 提供两个 CSS 产物:
| 文件 | 内容 | 适用场景 |
|---|---|---|
styles.css | 完整包,含 Tailwind preflight(CSS Reset) | 不使用 Tailwind 的项目 |
styles.components.css | 仅含组件样式,不含 CSS Reset | 已使用 Tailwind 的项目 |
最小配置
/* app.css — Tailwind 项目 */
@import '@dayflow/core/dist/styles.components.css';
@import 'tailwindcss';如果项目不使用 Tailwind,改为导入完整包:
/* app.css — 非 Tailwind 项目 */
@import '@dayflow/core/dist/styles.css';深色模式
DayFlow 监听任意祖先元素(包括 <html>)上的 .dark 类,通过 JavaScript 进行切换:
document.documentElement.classList.toggle('dark', isDark);无需显式设置类名时,也会自动响应系统级深色模式偏好。
在 Tailwind v4 中使用 theme.mode
DayFlow 发布的 CSS 已经内置了 theme.mode 所需的 .dark variant。在 Tailwind v4 项目里,只要导入 @dayflow/core/dist/styles.components.css,DayFlow 自身就会响应 <html> 上的 .dark 类切换。
如果你还希望项目里你自己写的 Tailwind dark: 工具类也跟随这个类名切换,再在 CSS 入口里补上 class-based 配置:
@import '@dayflow/core/dist/styles.components.css';
@import 'tailwindcss';
/* 可选:只有你自己的 Tailwind dark: 工具类需要跟随 .dark 时才需要 */
@variant dark (.dark &);如果不加这行,DayFlow 仍会通过 theme.mode 正常切换;只是你项目自己的 Tailwind dark: 工具类仍然保持 Tailwind 默认的媒体查询行为。
实践建议
大多数项目可以按下面的优先级来定制主题:
- 在
.df-calendar-container、.df-portal或你的包裹层上覆盖--df-color-*。 - 在自定义 slot / 插件 UI 中复用
df-fill-primary、df-focus-ring等df-*语义类。 - 只有在你要改布局而不是主题时,才去覆盖更底层的 utility 行为。
下面是 3 个对应的常见示例:
示例 1:优先覆盖 --df-color-* token
适合品牌色替换、浅色/深色主题统一、整套日历换肤。
这里同时覆盖 .df-calendar-container 和 .df-portal:
.df-calendar-container是日历主体根容器.df-portal是 DayFlow 通过 portal 渲染到document.body下的浮层根类,例如详情弹窗、下拉层、部分选择器面板
如果你只覆盖 .df-calendar-container,主体区域会换肤,但这类浮层可能仍然使用默认 token。
/* .my-calendar-shell 是你自己项目里的包裹层类名,不是 DayFlow 内置类 */
.my-calendar-shell .df-calendar-container,
.my-calendar-shell .df-portal {
--df-color-primary: #0f766e;
--df-color-primary-foreground: #ffffff;
--df-color-background: #f8fafc;
--df-color-border: #cbd5e1;
}
.dark .my-calendar-shell .df-calendar-container,
.dark .my-calendar-shell .df-portal {
--df-color-primary: #5eead4;
--df-color-primary-foreground: #042f2e;
--df-color-background: #0f172a;
--df-color-border: #334155;
}<div className='my-calendar-shell'>
<DayFlowCalendar calendar={calendar} />
</div>示例 2:在自定义 UI 中复用 df-* 语义类
适合 content slot、自定义弹层、插件按钮,让它们和 DayFlow 内置按钮保持一致。
function CustomToolbar() {
return (
<div className='flex items-center gap-2'>
<button className='df-fill-primary rounded-md px-3 py-1.5 text-sm font-medium df-hover-primary-solid'>
新建事件
</button>
<button className='rounded-md border px-3 py-1.5 text-sm df-focus-ring'>
聚焦搜索
</button>
<span className='df-tint-primary rounded-full px-2 py-0.5 text-xs font-medium'>
已连接
</span>
</div>
);
}示例 3:只改布局时再覆盖低层样式
适合调节间距、圆角、尺寸,不改变主题语义本身。
/* .my-compact-calendar 同样是你自己定义的包裹层类名 */
.my-compact-calendar .df-header {
padding-block: 0.25rem;
}
.my-compact-calendar .df-event {
border-radius: 6px;
}
.my-compact-calendar .df-mini-calendar-day {
width: 1.75rem;
height: 1.75rem;
}如果你的目标是“换色”,优先用示例 1;如果是“让自定义内容看起来像 DayFlow 内置控件”,优先用示例 2;如果只是“调整尺寸和间距”,再使用示例 3。
使用 Tailwind 工具类包裹日历
function ThemedCalendar({ calendar }) {
return (
<div className='rounded-2xl shadow-xl ring-1 ring-gray-200 dark:ring-gray-700'>
<DayFlowCalendar calendar={calendar} />
</div>
);
}创建自定义主题
// themes/oceanTheme.ts
export const oceanTheme = {
mode: 'light' as const,
calendarTypes: [
{
id: 'deep-ocean',
name: '深海蓝',
colors: {
lineColor: '#0369a1',
eventColor: '#e0f2fe',
eventSelectedColor: '#bae6fd',
textColor: '#0c4a6e',
},
darkColors: {
lineColor: '#7dd3fc',
eventColor: '#0c4a6e',
eventSelectedColor: '#083344',
textColor: '#e0f2fe',
},
},
{
id: 'coral-reef',
name: '珊瑚礁',
colors: {
lineColor: '#ea580c',
eventColor: '#ffedd5',
eventSelectedColor: '#fed7aa',
textColor: '#7c2d12',
},
darkColors: {
lineColor: '#fb923c',
eventColor: '#7c2d12',
eventSelectedColor: '#431407',
textColor: '#ffedd5',
},
},
],
};配合 CSS 变量覆盖使用,可实现完整的视觉一致性:
/* Ocean 主题 CSS token */
.df-calendar-container {
--df-color-primary: #0369a1;
--df-color-background: #f0f9ff;
--df-color-border: #bae6fd;
}
.dark .df-calendar-container {
--df-color-primary: #7dd3fc;
--df-color-background: #0c1220;
--df-color-border: #0c4a6e;
}资源
工具
- WebAIM 对比度检查器 - 检验颜色对比度
- Coolors - 生成配色方案
- 颜色对比度分析器 - 桌面工具
库
- chroma-js - 颜色操作
- tinycolor2 - 颜色工具
- color - 颜色转换
Tailwind 资源
- Tailwind v4 升级指南 - v3 → v4 迁移
- Tailwind CSS 层 - 层级文档