foundation-theme
Foundation 脚手架的主题注册系统使用指南。说明如何注册新主题、切换主题、扩展调色板,以及如何在组件里安全地消费主题色。
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
메뉴
Foundation 脚手架的主题注册系统使用指南。说明如何注册新主题、切换主题、扩展调色板,以及如何在组件里安全地消费主题色。
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
SOC 직업 분류 기준
Foundation 脚手架的子窗口系统使用指南:ChildWindowService(Open/Close/List)、事件总线通信(定向 / 广播)、预设类型(confirm / message / blank)、新增子窗口类型标准操作,以及"子窗口 MVVM 与主窗口一致、通信只走事件总线"等铁律。
MUI 9 数据展示类组件在 Foundation 项目中的详尽用法。当使用 Typography/Avatar/Badge/Chip/Divider/List/Table/Tooltip 时参考。
MUI 9 反馈类组件在 Foundation 项目中的详尽用法。当使用 Alert/Dialog/Progress/Skeleton/Snackbar/Backdrop 时参考。
Foundation 项目 @mui/icons-material 图标库详尽用法指南。Icon 铁律:只用 *Rounded 系列,禁止 emoji/Unicode/第三方 icon 包。
MUI 9 输入类组件在 Foundation 项目中的详尽用法。当使用 Button/TextField/Select/Checkbox/Switch/Slider/Radio/Rating/Autocomplete/ToggleButton/FAB 时参考。
MUI 9 布局类组件在 Foundation 项目中的详尽用法。当使用 Box/Container/Grid/Stack/ImageList 时参考。
| name | foundation-theme |
| description | Foundation 脚手架的主题注册系统使用指南。说明如何注册新主题、切换主题、扩展调色板,以及如何在组件里安全地消费主题色。 |
Foundation 脚手架内置一套注册式主题系统,建立在 MUI Theme 之上:
bg.surface / text.primary / accent ...),而不是裸十六进制色值;themeRegistry,可在运行时增删切换;<FoundationThemeProvider> 把当前预设编译成 MUI Theme 注入下游,组件继续用 MUI 的 sx / useTheme() 即可。默认注册了
foundation-light(白色,默认)与foundation-dark(暗色)两个预设。
src/styles/themes/
├── types.ts # FoundationPalette / FoundationThemePreset 接口
├── buildMuiTheme.ts # preset → MUI Theme 编译器(含组件覆盖)
├── registry.ts # 注册中心单例(register / get / list / subscribe)
├── ThemeProvider.tsx # <FoundationThemeProvider> + useFoundationTheme
├── presets/
│ ├── light.ts # 默认白色预设
│ └── dark.ts # 暗色预设
└── index.ts # 对外出口(含 registerFoundationThemes 启动函数)
App.tsx 顶部调用一次:
import { FoundationThemeProvider, registerFoundationThemes } from '@/styles/themes';
registerFoundationThemes(); // 幂等:内置 light + dark
export const App = () => (
<FoundationThemeProvider>
{/* ... */}
</FoundationThemeProvider>
);
registerFoundationThemes() 内部会把 light 标记为默认主题。如果你想换默认主题,不要直接改这个函数——注册一个新主题并指定 default: true(见第 4 节)。
铁律: 组件样式禁止硬编码十六进制。所有颜色必须从 theme.palette.foundation 取。
推荐:在 <Name>.styles.ts 写工厂函数:
// MyCard.styles.ts
import type { SxProps, Theme } from '@mui/material';
export const myCardStyles = (theme: Theme): Record<string, SxProps<Theme>> => {
const fp = theme.palette.foundation; // ← 语义调色板
return {
root: {
backgroundColor: fp.bg.surface,
border: `1px solid ${fp.divider}`,
color: fp.text.primary,
borderRadius: 1,
},
accent: { color: fp.accent },
};
};
// MyCard.tsx
import { useTheme } from '@mui/material';
import { myCardStyles } from './MyCard.styles';
export const MyCard = () => {
const theme = useTheme();
const styles = myCardStyles(theme);
return <Box sx={styles.root}>...</Box>;
};
可用槽位见 FoundationPalette:
| 槽位 | 用途 |
|---|---|
bg.base | 标题栏 / 最外层 |
bg.sidebar | 侧边栏 |
bg.content | 主内容区 |
bg.surface | 卡片 / Paper |
bg.elevated | 输入框 / Tooltip 内层 |
bg.hover / bg.active | 半透明 hover/active 覆盖 |
text.primary / text.secondary / text.muted | 文字三级 |
divider | 分隔线 |
accent / accentHover | 品牌强调色(按钮主色) |
status.danger / success / warning | 状态色 |
// src/styles/themes/presets/brand.ts
import type { FoundationThemePreset } from '../types';
export const brandPreset: FoundationThemePreset = {
name: 'brand-purple',
label: 'Brand · Purple',
mode: 'light',
palette: {
bg: {
base: '#f4f3ff',
sidebar: '#ffffff',
content: '#ffffff',
surface: '#ffffff',
elevated: '#faf9ff',
hover: 'rgba(99, 102, 241, 0.06)',
active: 'rgba(99, 102, 241, 0.12)',
},
text: { primary: '#1e1b4b', secondary: '#475569', muted: '#94a3b8' },
divider: 'rgba(30, 27, 75, 0.08)',
accent: '#6366f1',
accentHover: '#4f46e5',
status: { danger: '#dc2626', success: '#16a34a', warning: '#d97706' },
},
};
注册(推荐在应用启动时和 registerFoundationThemes() 一起):
import { themeRegistry } from '@/styles/themes';
import { brandPreset } from '@/styles/themes/presets/brand';
themeRegistry.register(brandPreset, { default: true }); // 设为默认
register是幂等的:相同name会覆盖。如果不指定default,注册的第一个主题自动成为默认。
任意组件里:
import { useFoundationTheme } from '@/styles/themes';
const ThemeSwitcher = () => {
const { current, available, setTheme } = useFoundationTheme();
return (
<select value={current.name} onChange={(e) => setTheme(e.target.value)}>
{available.map((p) => (
<option key={p.name} value={p.name}>{p.label}</option>
))}
</select>
);
};
<FoundationThemeProvider> 订阅了 themeRegistry.subscribe,新增 / 移除主题时 available 列表会自动刷新。
FoundationThemePreset.muiOverrides 字段会被 createTheme(base, muiOverrides) 深合并:
export const denseLight: FoundationThemePreset = {
...lightPreset,
name: 'foundation-light-dense',
label: 'Light · Dense',
muiOverrides: {
components: {
MuiButton: { defaultProps: { size: 'small' } },
},
typography: { fontSize: 13 },
},
};
❌ 在组件里直接写颜色:
<Box sx={{ backgroundColor: '#ffffff', color: '#0f172a' }} />
❌ 重新建立独立的 ThemeProvider:
<ThemeProvider theme={createTheme({ palette: { mode: 'dark' } })}>
❌ 旁路注册中心,直接 import 预设给 ThemeProvider:
import { lightPreset } from '@/styles/themes';
<ThemeProvider theme={buildMuiTheme(lightPreset)}>
✅ 永远走 <FoundationThemeProvider> + themeRegistry。
borderRadius: 6(方形圆角,不是圆形);hover/active 必有 transition;borderRadius: 8;borderRadius: 6,hover 用 bg.hover;bg.base,下方分隔线用 divider;bg.sidebar,激活项背景用 bg.active;后端 internal/app/window_<os>.go 里的 BackgroundColour 控制 webview 在 React 接管前的初始底色。当默认主题变更时,需要同步修改这个值,避免启动闪白 / 闪黑:
// 默认 light 主题:白色底
BackgroundColour: application.NewRGB(255, 255, 255),
如果你把默认主题切到深色,这里也要改成对应深色 RGB。