主题定制指南

DayFlow Calendar 的外观由一组带命名空间的 CSS 自定义属性(--df-color-*)控制。所有 token 都定义在 @layer df-theme 内部,因此宿主应用无需使用 !important 即可覆盖它们——无论是否使用 Tailwind 都适用。

DayFlow 的共享基础样式是 token、组件基础规则和 df-* 语义辅助类的统一来源,例如 df-fill-primarydf-tint-primarydf-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-primarytext-primaryhover: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 默认的媒体查询行为。

实践建议

大多数项目可以按下面的优先级来定制主题:

  1. .df-calendar-container.df-portal 或你的包裹层上覆盖 --df-color-*
  2. 在自定义 slot / 插件 UI 中复用 df-fill-primarydf-focus-ringdf-* 语义类。
  3. 只有在你要改布局而不是主题时,才去覆盖更底层的 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;
}

资源

工具

Tailwind 资源

相关文档

On this page