styling-react-with-tailwind
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseReferences:
- Guide - details on token system and patterns
参考资料:
- 指南 - 详细介绍令牌系统与模式
Overview
概述
This codebase uses:
- Tailwind CSS with semantic design tokens via plugin
tw-colors - tailwind-variants () for type-safe variant styling
tv() - Rose Pine color palette (light: Dawn, dark: Moon)
本代码库使用:
- 结合插件实现语义化设计令牌的Tailwind CSS
tw-colors - 用于类型安全变体样式的tailwind-variants()
tv() - Rose Pine调色板(浅色模式:Dawn,深色模式:Moon)
Token System
令牌系统
Color Token Pattern
颜色令牌规则
{property}-{category}-{semantic}Text tokens:
- - Primary body text
text-text-base - - Secondary/subtle text
text-text-muted - - Interactive link color (iris purple)
text-text-link - - Emphasized text
text-text-strong
Background tokens:
- - Page background
bg-background-base - - Card surfaces
bg-background-card - - Button backgrounds
bg-background-button - - Info callouts
bg-background-informative
Border tokens:
- - Subtle borders
border-border-muted - - Form field borders
border-border-input - - Info borders
border-border-informative
{property}-{category}-{semantic}文本令牌:
- - 主要正文文本
text-text-base - - 次要/弱化文本
text-text-muted - - 交互链接颜色(鸢尾紫)
text-text-link - - 强调文本
text-text-strong
背景令牌:
- - 页面背景
bg-background-base - - 卡片表面
bg-background-card - - 按钮背景
bg-background-button - - 信息提示框背景
bg-background-informative
边框令牌:
- - 弱化边框
border-border-muted - - 表单字段边框
border-border-input - - 信息提示框边框
border-border-informative
Spacing & Layout
间距与布局
Standard Tailwind spacing scale. Use semantic sizing:
- ,
p-4,gap-2- standard spacingm-0 - - content width constraints
max-w-7xl
采用标准Tailwind间距刻度,使用语义化尺寸:
- ,
p-4,gap-2- 标准间距m-0 - - 内容宽度限制
max-w-7xl
Component Patterns
组件模式
Pattern 1: Slots (Multi-element components)
模式1:Slots(多元素组件)
Use when component has multiple styled children.
tsx
import { tv, VariantProps } from 'tailwind-variants';
import { classnames } from '~/core/classnames';
const Styles = tv({
slots: {
root: ['flex', 'items-center', 'gap-2'],
label: ['text-text-base', 'font-medium'],
icon: ['text-text-muted', 'w-4', 'h-4'],
},
variants: {
size: {
sm: { root: 'p-2', label: 'text-sm' },
md: { root: 'p-4', label: 'text-base' },
},
intent: {
primary: { root: 'bg-background-button', label: 'text-text-strong' },
ghost: { root: 'bg-transparent', label: 'text-text-muted' },
},
},
defaultVariants: {
size: 'md',
intent: 'primary',
},
});
type StyleProps = VariantProps<typeof Styles>;
type Props = StyleProps & {
className?: string;
children: React.ReactNode;
};
export function MyComponent(props: Props) {
const styles = Styles({ size: props.size, intent: props.intent });
return (
<div className={classnames(styles.root(), props.className)}>
<span className={styles.icon()}>*</span>
<span className={styles.label()}>{props.children}</span>
</div>
);
}适用于组件包含多个带样式子元素的场景。
tsx
import { tv, VariantProps } from 'tailwind-variants';
import { classnames } from '~/core/classnames';
const Styles = tv({
slots: {
root: ['flex', 'items-center', 'gap-2'],
label: ['text-text-base', 'font-medium'],
icon: ['text-text-muted', 'w-4', 'h-4'],
},
variants: {
size: {
sm: { root: 'p-2', label: 'text-sm' },
md: { root: 'p-4', label: 'text-base' },
},
intent: {
primary: { root: 'bg-background-button', label: 'text-text-strong' },
ghost: { root: 'bg-transparent', label: 'text-text-muted' },
},
},
defaultVariants: {
size: 'md',
intent: 'primary',
},
});
type StyleProps = VariantProps<typeof Styles>;
type Props = StyleProps & {
className?: string;
children: React.ReactNode;
};
export function MyComponent(props: Props) {
const styles = Styles({ size: props.size, intent: props.intent });
return (
<div className={classnames(styles.root(), props.className)}>
<span className={styles.icon()}>*</span>
<span className={styles.label()}>{props.children}</span>
</div>
);
}Pattern 2: Base (Single-element components)
模式2:Base(单元素组件)
Use when component is a single styled element.
tsx
import { tv, VariantProps } from 'tailwind-variants';
import { classnames } from '~/core/classnames';
const Styles = tv({
base: [
'border',
'border-border-muted',
'rounded',
'transition-colors',
],
variants: {
variant: {
solid: 'border-2',
dashed: 'border-dashed',
},
},
defaultVariants: {
variant: 'solid',
},
});
type Props = VariantProps<typeof Styles> & {
className?: string;
};
export function Divider(props: Props) {
const styles = Styles({ variant: props.variant });
return <hr className={classnames(styles, props.className)} />;
}适用于组件为单个带样式元素的场景。
tsx
import { tv, VariantProps } from 'tailwind-variants';
import { classnames } from '~/core/classnames';
const Styles = tv({
base: [
'border',
'border-border-muted',
'rounded',
'transition-colors',
],
variants: {
variant: {
solid: 'border-2',
dashed: 'border-dashed',
},
},
defaultVariants: {
variant: 'solid',
},
});
type Props = VariantProps<typeof Styles> & {
className?: string;
};
export function Divider(props: Props) {
const styles = Styles({ variant: props.variant });
return <hr className={classnames(styles, props.className)} />;
}Pattern 3: Compound Variants
模式3:复合变体
For conditional style combinations:
tsx
const Styles = tv({
base: ['rounded', 'px-4', 'py-2'],
variants: {
intent: { primary: '', danger: '' },
disabled: { true: 'opacity-50 cursor-not-allowed' },
},
compoundVariants: [
{
intent: 'primary',
disabled: false,
class: 'bg-background-button hover:bg-background-hover',
},
{
intent: 'danger',
disabled: false,
class: 'bg-red-500 hover:bg-red-600',
},
],
});用于条件样式组合:
tsx
const Styles = tv({
base: ['rounded', 'px-4', 'py-2'],
variants: {
intent: { primary: '', danger: '' },
disabled: { true: 'opacity-50 cursor-not-allowed' },
},
compoundVariants: [
{
intent: 'primary',
disabled: false,
class: 'bg-background-button hover:bg-background-hover',
},
{
intent: 'danger',
disabled: false,
class: 'bg-red-500 hover:bg-red-600',
},
],
});Key Utilities
核心工具
classnames()
classnames()
Always use for merging classes safely:
tsx
import { classnames } from '~/core/classnames';
// Merges and deduplicates Tailwind classes
classnames(styles.root(), props.className, isActive && 'ring-2');请始终使用该工具安全合并类名:
tsx
import { classnames } from '~/core/classnames';
// 合并并去重Tailwind类名
classnames(styles.root(), props.className, isActive && 'ring-2');Box with asChild
带asChild的Box组件
For polymorphic components:
tsx
import { Box } from '~/components/ds/box/Box';
<Box asChild className="text-text-link">
<a href="/path">Link styled as Box</a>
</Box>用于多态组件:
tsx
import { Box } from '~/components/ds/box/Box';
<Box asChild className="text-text-link">
<a href="/path">样式为Box的链接</a>
</Box>Quick Reference
速查表
| Need | Use |
|---|---|
| Multiple styled elements | |
| Single styled element | |
| Variant types | |
| Merge classes | |
| Conditional variants | |
| Purple accent | |
| Muted text | |
| Card background | |
| 需求 | 解决方案 |
|---|---|
| 多个带样式元素 | |
| 单个带样式元素 | |
| 变体类型 | |
| 合并类名 | |
| 条件变体 | |
| 紫色强调色 | |
| 弱化文本 | |
| 卡片背景 | |
Common Mistakes
常见错误
- Using raw colors - Always use semantic tokens (not
text-text-base)text-gray-900 - Forgetting classnames() - Props className won't merge properly without it
- Destructuring props - Use not
props.xper codebase convention{ x } - Missing VariantProps - Always type variants for IDE completion
- 直接使用原始颜色 - 请始终使用语义化令牌(如而非
text-text-base)text-gray-900 - 忘记使用classnames() - 不使用该工具的话,Props中的className无法正确合并
- 解构Props - 根据代码库约定,请使用而非
props.x{ x } - 缺失VariantProps - 请始终为变体添加类型以获得IDE自动补全支持