mcpField
S
stitch-react-components

stitch-react-components

github.com/gabelul开发4756 次安装14 周前更新
代码仓库

关于 stitch-react-components

这项技能可将 Stitch 设计、本地 HTML 或网址转换为适用于 Vite 和普通 React 项目的模块化组件,并指导设计令牌提取、主题处理和组件组织;不适用于 Next.js。

主要功能

  1. 01将 HTML 设计转换为 React 组件
  2. 02支持 Stitch、本地文件和网址来源
  3. 03提取设计令牌并支持深色模式
  4. 04组织组件、数据和共享类型
  5. 05提供 HTML 下载脚本

适用场景

  1. 01在 Vite React 应用中重建 Stitch 屏幕
  2. 02将本地 HTML 设计转换为 React 组件
  3. 03将网页设计移植到普通 React 项目

MCP 相关

输入来自 Stitch 屏幕时,技能会通过 Stitch MCP 查找相关工具并获取屏幕元数据;其他 HTML 来源无需 Stitch MCP。

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/gabelul/stitch-kit --skill stitch-react-components

安装后在 Claude Code 中输入/stitch-react-components确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

references/
tailwind-to-react.md
resources/
architecture-checklist.md
component-template.tsx
scripts/
fetch-stitch.sh

详细介绍

Stitch → Vite / React 组件

限制: 仅当用户明确提到“Stitch”和 React(Vite、CRA,或未提及 Next.js 的“React app”)时,才使用此技能。

你是一名前端工程师,负责将 Stitch 移动端/桌面端设计转换为简洁、模块化的 React 组件,使用 Vite + TypeScript。此技能适用于纯 React 应用,不适用于 Next.js App Router。对于 Next.js,请改用 stitch-nextjs-components。

何时使用此技能,何时使用 Next.js

场景使用
用户说“React app”、“Vite”、“CRA”stitch-react-components
用户说“Next.js”、“App Router”、“SSR”stitch-nextjs-components
用户希望之后添加 shadcn/ui 组件stitch-react-components → 然后使用 stitch-shadcn-ui
用户需要服务端渲染或基于文件的路由stitch-nextjs-components

前提条件

HTML 源文件。以下任意一种都可以:

  • 一个 Stitch 屏幕 — 需要访问 Stitch MCP 并生成屏幕
  • 一个 本地 HTML 文件 — 无需 Stitch 账号
  • 一个 URL — 无需 Stitch 账号

另外还需要:

  • Node.js + npm/pnpm
  • 已初始化的 Vite + React 项目:npm create vite@latest my-app -- --template react-ts

步骤 1:解析来源

后续所有步骤都读取同一个文件:temp/source.html。根据用户提供的来源,选择对应方式获取 HTML 并保存到该文件,然后继续步骤 2——无论标记来自哪里,此技能的其余部分都相同。

来自 Stitch 屏幕:

  1. 发现命名空间 — 使用 list_tools 查找 Stitch MCP 前缀
  2. 获取元数据 — 使用 [prefix]:get_screen,并提供数字格式的 projectId 和 screenId
  3. 下载 HTML — GCS URL 需要使用可靠的下载器:
    bash scripts/fetch-stitch.sh "[htmlCode.downloadUrl]" "temp/source.html"
    
  4. 视觉检查 — 改写前检查 screenshot.downloadUrl。在该 URL 后附加 =s0 可获取完整分辨率;无论 API 报告的 width/height 是多少,原始 URL 都只提供 512px 缩略图。

来自本地 HTML 文件:

mkdir -p temp && cp "path/to/design.html" temp/source.html

来自 URL:

bash scripts/fetch-stitch.sh "https://example.com/page" "temp/source.html"

尽管名称如此,该脚本是通用的加固型下载器:它会跟随重定向、重试暂时性故障、处理 gzip,并在结果为空时明确报错。它不关心 URL 是否指向 Stitch。

**来自屏幕截图:**没有上传途径——Stitch MCP API 没有图像上传工具。可以通过 stitch-mcp-generate-screen-from-text 根据文本提示词重建设计,也可以手动编写 HTML,然后使用上面的本地文件方式。

只有 Stitch 方式需要 API 密钥。转换本地文件或 URL 完全不需要 Google 账号。

步骤 2:项目结构

src/
├── components/           ← One file per component
│   └── [Name].tsx
├── data/
│   └── mockData.ts       ← Static content (never in components)
├── theme/
│   ├── tokens.ts         ← Design token constants
│   └── useTheme.ts       ← Dark mode hook
├── types/
│   └── index.ts          ← Shared TypeScript types
├── App.tsx               ← Root component
└── main.tsx              ← Entry point

步骤 3:提取设计令牌

按以下顺序,从 HTML 实际提供的内容中解析令牌:

  1. <head> 中的内联 tailwind.config(Stitch 输出的内容)——如果存在,直接使用。
  2. CSS 自定义属性(:root { --color-primary: ... })——手写和模板化 HTML 中很常见。
  3. 外链或内联样式表——解析声明的颜色、字体系列、圆角和间距。
  4. 最后手段——根据标记中出现频率最高的计算值推导令牌(主导背景色、文字颜色、强调色、标题/正文使用的字体、边框圆角),并告知用户你的推断,以便他们纠正。

URL 方式只会下载单个 HTML 响应——外链样式表可能不会一并获取。如果上述方式都无法解析某个令牌,请如实说明,不要凭空编造配色方案。

// src/theme/tokens.ts
export const lightTokens = {
  background: '#FFFFFF',
  surface:    '#F4F4F5',
  primary:    '#6366F1',
  primaryFg:  '#FFFFFF',
  text:       '#09090B',
  textMuted:  '#71717A',
  border:     '#E4E4E7',
} as const

export const darkTokens = {
  background: '#09090B',
  surface:    '#18181B',
  primary:    '#818CF8',
  primaryFg:  '#09090B',
  text:       '#FAFAFA',
  textMuted:  '#A1A1AA',
  border:     '#27272A',
} as const

export type ThemeTokens = typeof lightTokens
// src/theme/useTheme.ts
import { useEffect, useState } from 'react'
import { lightTokens, darkTokens, type ThemeTokens } from './tokens'

/**
 * Returns current theme tokens based on system color scheme.
 * Listens for system-level dark/light mode changes.
 */
export function useTheme(): ThemeTokens {
  const [isDark, setIsDark] = useState(
    () => window.matchMedia('(prefers-color-scheme: dark)').matches
  )

  useEffect(() => {
    const mq = window.matchMedia('(prefers-color-scheme: dark)')
    const handler = (e: MediaQueryListEvent) => setIsDark(e.matches)
    mq.addEventListener('change', handler)
    return () => mq.removeEventListener('change', handler)
  }, [])

  return isDark ? darkTokens : lightTokens
}

步骤 4:组件转换规则

布局映射
HTML/CSS→ React / Tailwind
display:flex; flex-direction:column<div className="flex flex-col gap-4">
display:flex; flex-direction:row<div className="flex items-center gap-2">
justify-content:space-between<div className="flex justify-between">
display:grid; grid-template-columns:1fr 1fr<div className="grid grid-cols-2 gap-4">
overflow-y:scroll<div className="overflow-y-auto">
长列表items.map(item => <Card key={item.id} {...item} />)
<img><img src="..." alt="..." className="object-cover">
Tailwind 类映射

如果源 HTML 中的 Tailwind 类未引用自定义 token,请直接在 JSX 中使用。将自定义 token 映射为 CSS 变量:

// Source HTML: bg-primary → CSS variable → Tailwind arbitrary value
// OR: use inline style with token value

// Option A — Tailwind arbitrary value (if custom tokens in tailwind.config)
<div className="bg-[--color-primary] text-[--color-primaryFg]">

// Option B — inline style with useTheme()
const theme = useTheme()
<div style={{ backgroundColor: theme.primary, color: theme.primaryFg }}>
组件模板
// src/components/StitchComponent.tsx

/**
 * Props for StitchComponent — all data via props, never fetched inside.
 */
interface StitchComponentProps {
  /** Primary heading text */
  title: string
  /** Supporting description — optional */
  description?: string
  /** Primary action callback */
  onAction?: () => void
}

/**
 * StitchComponent — [describe purpose in one sentence]
 */
export function StitchComponent({
  title,
  description,
  onAction,
}: Readonly<StitchComponentProps>) {
  const theme = useTheme()

  return (
    <div
      className="rounded-xl border p-4 gap-2 flex flex-col"
      style={{
        backgroundColor: theme.surface,
        borderColor: theme.border,
      }}
    >
      <h3 className="text-base font-semibold" style={{ color: theme.text }}>
        {title}
      </h3>

      {description ? (
        <p className="text-sm" style={{ color: theme.textMuted }}>
          {description}
        </p>
      ) : null}

      {onAction ? (
        <button
          onClick={onAction}
          className="rounded-lg px-4 py-2 text-sm font-medium transition-opacity hover:opacity-90"
          style={{ backgroundColor: theme.primary, color: theme.primaryFg }}
          type="button"
        >
          Action
        </button>
      ) : null}
    </div>
  )
}

步骤 5:架构规则

  • 每个文件仅放置一个组件 — 避免单文件混乱
  • 静态数据放在 src/data/mockData.ts 中 — 不要在 JSX 中硬编码
  • 共享类型放在 src/types/index.ts 中
  • 每个组件都要有 Readonly<ComponentNameProps> 接口
  • 不要硬编码十六进制颜色 — 使用 useTheme() 或 CSS 变量
  • 不要使用 any 类型

步骤 6:与 shadcn/ui 集成

将设计转换为基础 React 组件后,可以进一步集成 shadcn/ui:

npx shadcn@latest init    # Set up shadcn in your Vite project
npx shadcn@latest add button card input dialog

然后使用 stitch-shadcn-ui 技能,用 shadcn 组件替换原始 HTML 元素,同时保留设计 token。

故障排除

问题解决方法
Tailwind 类未生效检查 tailwind.config.js 的 content 是否包含 ./src/**/*.{ts,tsx}
暗色模式无法切换确认在组件层级调用了 useTheme(),而不是将其提升到更高层级
图片未显示添加明确的 width 和 height,或使用 className="w-full h-auto"
props 类型错误确保使用 Readonly<> 包装,并提供所有必需的 props

参考资料

  • resources/component-template.tsx — 组件样板
  • resources/architecture-checklist.md — 发布前检查清单
  • references/tailwind-to-react.md — token + 类映射指南(源 HTML → React/Tailwind)
  • scripts/fetch-stitch.sh — 可靠的 GCS HTML 下载器
  • stitch-shadcn-ui — 基础转换后添加 shadcn/ui 组件
  • docs/tailwind-reference.md — Tailwind 实用类查询

评论

支持 Markdown