定制
主题
五套主题(浅色 / 纸张 / 纸张深色 / 深色 / OLED)与配色。解析顺序:显式选择(cookie)> 系统偏好 > 浅色(默认),配色用 CSS 变量集中管理。
fork 后你要改哪: 换配色改
src/styles/app.css的 CSS 变量;改兜底明暗改src/server/preferences.ts+__root.tsx里的 boot script。
工作原理
- 偏好:主题存在
themecookie 里,值是light、paper、paper-dark、dark或oled。getPreferences(src/server/preferences.ts)读取它,SSR 按 cookie 渲染, 无 cookie(或值非法)时兜底浅色。 - 系统偏好:
__root.tsx的<head>里有一段首绘前的内联脚本——没有 cookie 且prefers-color-scheme: dark时把<html>翻成深色(无闪烁)。它刻意不写 cookie: 没做过选择的访客持续跟随系统,点过切换按钮才锁定。纸张、纸张深色与 OLED 只来自显式选择(cookie / 设置里选),永远不会跟随系统。 - 应用:
__root.tsx把主题作为 class 加到<html class={theme}>(带suppressHydrationWarning,因为脚本可能在水合前改过 class)。 - 切换:两处入口——
ThemeToggle(src/features/theme/theme-toggle.tsx)在 浅色 → 纸张 → 纸张深色 → 深色 → OLED 间循环;账号设置页(app/account)的 「外观」区有带预览色卡的五选一。 施加都走src/features/theme/theme.ts的applyTheme:写 cookie(一年)+ 改<html>class + 同步 next-themes 的 localStorage。 - 客户端读真实主题:loader 的值在「无 cookie + 系统浅色」时是错的,依赖主题渲染的
组件(切换按钮图标、Toaster)用
useResolvedTheme在挂载后读 DOM。
改配色
配色集中在 src/styles/app.css 的 CSS 变量:
:root定义浅色令牌(--background、--foreground、--primary等);:root.dark, .dark覆盖为深色值;:root.paper, .paper覆盖为纸张(极简中性纸:纯中性灰纸底、发丝线边框、 墨色 primary,图表/语义色按色相骨架取铅笔色调)值;:root.paper-dark, .paper-dark覆盖为纸张深色(中性近黑面、浅墨 primary,类似电子墨水)值;:root.oled, .oled覆盖为 OLED 纯黑(#000000底、ember 强调,Dark 配色抬到纯黑上)值;dark:Tailwind 变体由.dark、.paper-dark或.oled祖先触发(两份样式表里的@custom-variant dark (&:where(.dark *, .paper-dark *, .oled *)));@theme inline把这些变量映射成 Tailwind v4 的--color-*,组件里就能用bg-background、text-fg-2这类类名。
色相骨架(所有主题共用)
每个变量在所有主题里绑定同一个色相——切主题只换明度/饱和度(调 tint),
绝不换"变量 → 色相"的对应关系。src/styles/app.css 里 "Theme hue skeleton"
注释是唯一事实源:
chart-1与primary= 品牌强调色(纸张系是墨色,其余是 ember 橙);chart-2与transfer= 蓝;chart-3、income、success= 绿;chart-4= 紫;chart-5与goal= 琥珀;chart-6= 粉;expense与destructive= 红。
新增一套主题 = 新加一个 :root.xxx, .xxx 变量块,按骨架给每个变量取一套
tint;shadcn 标准令牌和 Tailwind 桥接会自动重新解析。
新增一套主题 checklist
src/styles/app.css:新:root.xxx, .xxx变量块(按上表骨架铺 tint); 若是深色系主题,把.xxx加进两份样式表(app.css+docs.css)的@custom-variant dark选择器列表。src/features/theme/theme.ts:Theme联合类型、THEMES、isTheme登记;toSonnerTheme里为二元 sonner 指定light/dark。src/routes/docs/$.tsx:next-themesdefaultTheme映射(主题 →light或dark)+ cookie 正则登记;文档站二元切换器不会覆盖该主题的 cookie。src/routes/{-$locale}/app/account.tsx:THEME_PREVIEWS加色卡 (手抄 CSS 里的十六进制值)、labels加标签;必要时调 grid 列数。src/features/theme/theme-toggle.tsx:icons里加循环图标。- i18n:
en.ts与zh.ts各加一个themeX键。 - 主题只来自显式选择——boot script 只认 light/dark,新主题不跟随 OS。
灯箱类组件(sonner Toaster、fumadocs 文档站切换器)只认明暗二元——纸张在
Toaster 里按浅色渲染(toSonnerTheme),纸张深色与 OLED 按深色;文档站在
纸张 cookie 下固定用浅色,纸张深色/OLED cookie 下固定用深色,且不会把切换
结果写回纸张系 / OLED cookie。