关于 design-to-component-translator
这项技能帮助开发者将视觉设计规格转为 React 组件,涵盖设计令牌、交互状态、响应式规则与无障碍实现。
主要功能
- 01提取设计尺寸与样式
- 02将设计值映射到令牌
- 03生成语义化 React 组件
- 04实现交互与响应式状态
- 05补充无障碍支持和变体文档
适用场景
- 01将 Figma 按钮规格转为 React
- 02依据设计稿构建响应式组件
- 03记录组件变体及视觉状态
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ patricio0312rev/ skills --skill design-to-component-translator安装后在 Claude Code 中输入/design-to-component-translator确认已加载。
详细介绍
设计稿转组件
将设计规范转换为像素级精准、可用于生产环境的 React 组件。
核心工作流
- 分析设计规范:提取间距、颜色、排版和尺寸
- 映射到设计令牌:将设计值转换为设计系统令牌
- 生成结构:创建语义化 HTML 结构
- 应用样式:使用 Tailwind/CSS 实现精确尺寸
- 添加状态:包含悬停、焦点、激活和禁用状态
- 处理响应式设计:实现特定断点规则
- 确保无障碍性:添加 ARIA 标签和键盘导航
- 记录变体:列出所有视觉状态和属性
设计规范分析
从 Figma/设计稿中提取
间距与布局:
- 内边距:
p-4(16px)、px-6(水平 24px) - 外边距:
m-2(8px)、mt-4(顶部 16px) - 间隔:
gap-3(弹性项目之间间隔 12px) - 宽度/高度:
w-64(256px)、h-10(40px)
排版:
- 字体系列:
font-sans、font-mono - 字号:
text-sm(14px)、text-base(16px)、text-lg(18px) - 字重:
font-normal(400)、font-medium(500)、font-semibold(600) - 行高:
leading-tight、leading-normal、leading-relaxed - 字间距:
tracking-tight、tracking-normal、tracking-wide
颜色:
- 背景:
bg-blue-500、bg-gray-100 - 文本:
text-gray-900、text-white - 边框:
border-gray-300、border-blue-600 - 不透明度:
bg-opacity-50、text-opacity-75
边框与圆角:
- 边框宽度:
border、border-2、border-t-4 - 边框圆角:
rounded(4px)、rounded-md(6px)、rounded-lg(8px)、rounded-full
阴影:
shadow-sm、shadow、shadow-md、shadow-lg、shadow-xl
设计令牌映射
创建令牌系统
// tokens.ts
export const tokens = {
colors: {
primary: {
50: "#eff6ff",
100: "#dbeafe",
500: "#3b82f6",
600: "#2563eb",
700: "#1d4ed8",
},
gray: {
100: "#f3f4f6",
300: "#d1d5db",
500: "#6b7280",
700: "#374151",
900: "#111827",
},
},
spacing: {
xs: "0.25rem", // 4px
sm: "0.5rem", // 8px
md: "1rem", // 16px
lg: "1.5rem", // 24px
xl: "2rem", // 32px
},
fontSize: {
xs: ["0.75rem", { lineHeight: "1rem" }],
sm: ["0.875rem", { lineHeight: "1.25rem" }],
base: ["1rem", { lineHeight: "1.5rem" }],
lg: ["1.125rem", { lineHeight: "1.75rem" }],
xl: ["1.25rem", { lineHeight: "1.75rem" }],
},
borderRadius: {
sm: "0.25rem", // 4px
md: "0.375rem", // 6px
lg: "0.5rem", // 8px
full: "9999px",
},
shadows: {
sm: "0 1px 2px 0 rgb(0 0 0 / 0.05)",
md: "0 4px 6px -1px rgb(0 0 0 / 0.1)",
lg: "0 10px 15px -3px rgb(0 0 0 / 0.1)",
},
};
Tailwind 配置
// tailwind.config.js
module.exports = {
theme: {
extend: {
colors: {
primary: {
50: "#eff6ff",
100: "#dbeafe",
500: "#3b82f6",
600: "#2563eb",
700: "#1d4ed8",
},
},
spacing: {
18: "4.5rem",
88: "22rem",
},
fontSize: {
"2xs": "0.625rem",
},
},
},
};
组件转换示例
根据 Figma 规范制作按钮
Figma 规范:
- 高度:40px
- 内边距:12px 24px
- 边框圆角:6px
- 字体:Inter Medium 14px
- 背景:#3B82F6
- 文本:#FFFFFF
- 悬停:#2563EB
- 阴影:0 1px 3px rgba(0,0,0,0.1)
转换后的组件:
import { cn } from "@/lib/utils";
interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
variant?: "primary" | "secondary";
size?: "sm" | "md" | "lg";
}
export const Button = ({
variant = "primary",
size = "md",
className,
children,
...props
}: ButtonProps) => {
return (
<button
className={cn(
// Base styles
"inline-flex items-center justify-center rounded-md font-medium",
"transition-colors duration-200",
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary-500 focus-visible:ring-offset-2",
"disabled:pointer-events-none disabled:opacity-50",
// Variant: Primary (matches Figma)
variant === "primary" && [
"bg-primary-500 text-white shadow-sm",
"hover:bg-primary-600",
"active:bg-primary-700",
],
// Size: Medium (40px height, 12px 24px padding)
size === "md" && "h-10 px-6 text-sm",
className
)}
{...props}
>
{children}
</button>
);
};
根据设计规范制作卡片
Figma 规范:
- 内边距:24px
- 边框圆角:12px
- 背景:#FFFFFF
- 边框:1px solid #E5E7EB
- 阴影:0 1px 3px rgba(0,0,0,0.1)
- 最大宽度:400px
转换后的组件:
interface CardProps extends React.HTMLAttributes<HTMLDivElement> {
elevated?: boolean;
}
export const Card = ({
elevated = false,
className,
children,
...props
}: CardProps) => {
return (
<div
className={cn(
// Base from Figma
"max-w-sm rounded-xl bg-white p-6",
"border border-gray-200",
// Conditional shadow
elevated ? "shadow-lg" : "shadow-sm",
// Hover state (not in Figma, but good UX)
"transition-shadow duration-200 hover:shadow-md",
className
)}
{...props}
>
{children}
</div>
);
};
交互状态
悬停状态
// Figma: Background changes from #3B82F6 to #2563EB on hover
className={cn(
'bg-primary-500',
'hover:bg-primary-600',
'transition-colors duration-200'
)}
焦点状态
// Accessible focus ring
className={cn(
'focus:outline-none',
'focus-visible:ring-2 focus-visible:ring-primary-500 focus-visible:ring-offset-2'
)}
激活/按下状态
// Figma: Slightly darker on click
className={cn(
'active:bg-primary-700',
'active:scale-[0.98]', // Slight scale down
'transition-all duration-100'
)}
禁用状态
// Figma: 50% opacity, no interactions
className={cn(
'disabled:opacity-50',
'disabled:cursor-not-allowed',
'disabled:pointer-events-none'
)}
响应式设计转换
断点映射
// Figma artboards → Tailwind breakpoints
// Mobile (375px): default (no prefix)
// Tablet (768px): md:
// Desktop (1024px): lg:
// Wide (1280px): xl:
<div
className={cn(
// Mobile: Stack vertically, full width
"flex flex-col gap-4 w-full",
// Tablet: Side by side, 50% each
"md:flex-row md:gap-6",
// Desktop: Max width container
"lg:max-w-6xl lg:mx-auto"
)}
/>
响应式排版
// Figma mobile: 14px, desktop: 16px
<h1 className="text-sm md:text-base lg:text-lg font-semibold">
Responsive Heading
</h1>
响应式间距
// Figma mobile: 16px padding, desktop: 24px
<div className="p-4 md:p-6 lg:p-8">Content</div>
设计系统集成
使用 shadcn/ui 模式
// Leveraging shadcn's composable approach
import { cn } from "@/lib/utils";
const buttonVariants = cva(
"inline-flex items-center justify-center rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:opacity-50 disabled:pointer-events-none ring-offset-background",
{
variants: {
variant: {
default: "bg-primary text-primary-foreground hover:bg-primary/90",
destructive:
"bg-destructive text-destructive-foreground hover:bg-destructive/90",
outline:
"border border-input hover:bg-accent hover:text-accent-foreground",
secondary:
"bg-secondary text-secondary-foreground hover:bg-secondary/80",
ghost: "hover:bg-accent hover:text-accent-foreground",
link: "underline-offset-4 hover:underline text-primary",
},
size: {
default: "h-10 py-2 px-4",
sm: "h-9 px-3 rounded-md",
lg: "h-11 px-8 rounded-md",
icon: "h-10 w-10",
},
},
defaultVariants: {
variant: "default",
size: "default",
},
}
);
颜色系统转换
从 Figma 转换为 CSS 变量
/* Figma colors → CSS variables */
:root {
/* Primary from Figma #3B82F6 */
--primary: 221 83% 60%;
--primary-foreground: 0 0% 100%;
/* Secondary from Figma #6B7280 */
--secondary: 220 9% 46%;
--secondary-foreground: 0 0% 100%;
/* Backgrounds */
--background: 0 0% 100%;
--foreground: 222 47% 11%;
/* Borders */
--border: 220 13% 91%;
--input: 220 13% 91%;
--ring: 221 83% 60%;
/* Radius from Figma */
--radius: 0.5rem;
}
在组件中使用
<div className="bg-background text-foreground border-border">
<button className="bg-primary text-primary-foreground">Button</button>
</div>
动画与过渡
根据 Figma 设计制作微交互
// Figma: Button scales slightly on hover
<button className={cn(
'transition-all duration-200',
'hover:scale-105',
'active:scale-95'
)}>
Hover me
</button>
// Figma: Card lifts on hover
<div className={cn(
'transition-all duration-300',
'hover:-translate-y-1 hover:shadow-lg'
)}>
Card content
</div>
// Figma: Fade in on mount
<div className="animate-in fade-in duration-500">
Fading content
</div>
尺寸转换
Figma 像素 → Tailwind 类
| Figma | Tailwind | 值 |
|---|---|---|
| 2px | 0.5 | 0.125rem |
| 4px | 1 | 0.25rem |
| 8px | 2 | 0.5rem |
| 12px | 3 | 0.75rem |
| 16px | 4 | 1rem |
| 20px | 5 | 1.25rem |
| 24px | 6 | 1.5rem |
| 32px | 8 | 2rem |
| 40px | 10 | 2.5rem |
| 48px | 12 | 3rem |
自定义值
// Figma: 18px (not in default Tailwind)
<div className="w-[18px] h-[18px]">{/* or add to config */}</div>
无障碍映射
从视觉设计到无障碍
// Figma shows disabled state
<button
disabled={isDisabled}
aria-disabled={isDisabled}
className={cn(
isDisabled && 'opacity-50 cursor-not-allowed'
)}
>
Submit
</button>
// Figma shows error state
<input
aria-invalid={hasError}
aria-describedby={hasError ? 'error-message' : undefined}
className={cn(
hasError && 'border-red-500 focus:ring-red-500'
)}
/>
常见模式
表单输入框转换
Figma 规范:
- 高度:44px
- 内边距:12px 16px
- 边框:1px #D1D5DB
- 边框圆角:8px
- 焦点边框:2px #3B82F6
<input
className={cn(
"h-11 w-full rounded-lg border border-gray-300 px-4",
"text-base text-gray-900 placeholder:text-gray-500",
"focus:border-primary-500 focus:ring-2 focus:ring-primary-500 focus:ring-offset-0",
"disabled:cursor-not-allowed disabled:opacity-50"
)}
/>
图标按钮转换
Figma 规范:
- 尺寸:40x40px
- 图标:居中显示,尺寸为 20x20px
- 边框圆角:8px
- 悬停背景:#F3F4F6
<button
className={cn(
"flex h-10 w-10 items-center justify-center rounded-lg",
"text-gray-700 transition-colors",
"hover:bg-gray-100",
"focus-visible:ring-2 focus-visible:ring-primary-500"
)}
>
<Icon className="h-5 w-5" />
</button>
最佳实践
- 反复核对:确认所有尺寸都与 Figma 完全一致
- 使用设计令牌:映射到令牌,而不是硬编码数值
- 覆盖所有状态:包括悬停、聚焦、激活、禁用和错误状态
- 响应式设计:实现设计中的所有断点
- 无障碍访问:在 Figma 显示状态的地方添加 ARIA
- 动画:使过渡时长与设计一致
- 深色模式:如果有相关设计,使用类变体实现
- 组件变体:创建可复用的变体属性
- 文档:记录与设计不一致之处
- 评审:取得设计师对实现的认可
输出检查清单
每次从设计到组件的转换都应包括:
- 间距与 Figma 尺寸完全一致
- 字体排印的字号比例和字重
- 设计系统中的所有颜色值
- 边框圆角和阴影
- 悬停状态样式
- 聚焦状态样式(无障碍)
- 激活/按下状态样式
- 禁用状态样式
- 响应式断点规则
- 设计令牌映射文档
- 无障碍属性
- 各状态的组件变体
评论
支持 Markdown