claude-design-ui-framework

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Claude Design UI Framework

Claude Design UI 框架

Skill by ara.so — Design Skills collection.
Claude Design is a sophisticated UI/UX framework for building Anthropic Claude-powered applications. It provides React components, Tailwind CSS utilities, screenshot-to-React conversion, Figma integration, and Artifacts-style rendering for AI-generated content. The framework includes stream-ready components, adaptive color systems, and built-in hooks for Claude's Messages API.
ara.so 提供的 Skill — 设计技能合集。
Claude Design 是一个用于构建基于Anthropic Claude的应用的成熟UI/UX框架。它提供React组件、Tailwind CSS工具类、截图转React代码功能、Figma集成,以及针对AI生成内容的Artifacts风格渲染能力。该框架包含支持流式响应的组件、自适应色彩系统,以及用于Claude Messages API的内置hooks。

Installation

安装

Download Pre-built Package

下载预构建包

bash
undefined
bash
undefined

Download from releases

从发布页下载

From Source

从源码安装

bash
undefined
bash
undefined

Clone repository

克隆仓库

Install dependencies

安装依赖

npm install
npm install

or

pnpm install
pnpm install

or

yarn install
undefined
yarn install
undefined

Quick Start

快速开始

bash
undefined
bash
undefined

Start development server

启动开发服务器

npm run dev
npm run dev

Build for production

构建生产版本

npm run build
npm run build

Preview production build

预览生产构建

npm run preview
undefined
npm run preview
undefined

Project Structure

项目结构

Claude-Code-Design-AI/
├── src/
│   ├── components/       # React components
│   │   ├── ui/          # Base UI components
│   │   ├── artifacts/   # Artifacts-style viewers
│   │   └── stream/      # Stream-ready components
│   ├── hooks/           # Custom React hooks
│   ├── lib/             # Utilities and helpers
│   ├── styles/          # Tailwind configurations
│   └── types/           # TypeScript definitions
├── public/              # Static assets
└── examples/            # Example implementations
Claude-Code-Design-AI/
├── src/
│   ├── components/       # React组件
│   │   ├── ui/          # 基础UI组件
│   │   ├── artifacts/   # Artifacts风格查看器
│   │   └── stream/      # 支持流式响应的组件
│   ├── hooks/           # 自定义React hooks
│   ├── lib/             # 工具函数与助手
│   ├── styles/          # Tailwind配置
│   └── types/           # TypeScript类型定义
├── public/              # 静态资源
└── examples/            # 示例实现

Core Components

核心组件

Artifacts UI Engine

Artifacts UI引擎

The Artifacts UI engine renders AI-generated content with live previews:
typescript
import { ArtifactViewer } from '@/components/artifacts/ArtifactViewer';
import { useState } from 'react';

function App() {
  const [artifact, setArtifact] = useState({
    type: 'code',
    language: 'typescript',
    content: '',
    isStreaming: true
  });

  return (
    <ArtifactViewer
      artifact={artifact}
      onUpdate={setArtifact}
      theme="dark"
      showLineNumbers
      enableCopy
    />
  );
}
Artifacts UI引擎可渲染AI生成内容并提供实时预览:
typescript
import { ArtifactViewer } from '@/components/artifacts/ArtifactViewer';
import { useState } from 'react';

function App() {
  const [artifact, setArtifact] = useState({
    type: 'code',
    language: 'typescript',
    content: '',
    isStreaming: true
  });

  return (
    <ArtifactViewer
      artifact={artifact}
      onUpdate={setArtifact}
      theme="dark"
      showLineNumbers
      enableCopy
    />
  );
}

Stream-Ready Chat Component

支持流式响应的聊天组件

Handle Claude's streaming responses with built-in typing animations:
typescript
import { StreamChat } from '@/components/stream/StreamChat';
import Anthropic from '@anthropic-ai/sdk';

const client = new Anthropic({
  apiKey: process.env.ANTHROPIC_API_KEY,
});

function ChatInterface() {
  const [messages, setMessages] = useState([]);
  const [isStreaming, setIsStreaming] = useState(false);

  const handleSendMessage = async (userMessage: string) => {
    setMessages(prev => [...prev, { role: 'user', content: userMessage }]);
    setIsStreaming(true);

    const stream = await client.messages.stream({
      model: 'claude-3-5-sonnet-20241022',
      max_tokens: 1024,
      messages: [{ role: 'user', content: userMessage }],
    });

    let assistantMessage = '';
    for await (const chunk of stream) {
      if (chunk.type === 'content_block_delta') {
        assistantMessage += chunk.delta.text;
        setMessages(prev => {
          const updated = [...prev];
          const lastMsg = updated[updated.length - 1];
          if (lastMsg?.role === 'assistant') {
            lastMsg.content = assistantMessage;
          } else {
            updated.push({ role: 'assistant', content: assistantMessage });
          }
          return updated;
        });
      }
    }

    setIsStreaming(false);
  };

  return (
    <StreamChat
      messages={messages}
      onSend={handleSendMessage}
      isStreaming={isStreaming}
      placeholder="Ask Claude anything..."
    />
  );
}
通过内置打字动画处理Claude的流式响应:
typescript
import { StreamChat } from '@/components/stream/StreamChat';
import Anthropic from '@anthropic-ai/sdk';

const client = new Anthropic({
  apiKey: process.env.ANTHROPIC_API_KEY,
});

function ChatInterface() {
  const [messages, setMessages] = useState([]);
  const [isStreaming, setIsStreaming] = useState(false);

  const handleSendMessage = async (userMessage: string) => {
    setMessages(prev => [...prev, { role: 'user', content: userMessage }]);
    setIsStreaming(true);

    const stream = await client.messages.stream({
      model: 'claude-3-5-sonnet-20241022',
      max_tokens: 1024,
      messages: [{ role: 'user', content: userMessage }],
    });

    let assistantMessage = '';
    for await (const chunk of stream) {
      if (chunk.type === 'content_block_delta') {
        assistantMessage += chunk.delta.text;
        setMessages(prev => {
          const updated = [...prev];
          const lastMsg = updated[updated.length - 1];
          if (lastMsg?.role === 'assistant') {
            lastMsg.content = assistantMessage;
          } else {
            updated.push({ role: 'assistant', content: assistantMessage });
          }
          return updated;
        });
      }
    }

    setIsStreaming(false);
  };

  return (
    <StreamChat
      messages={messages}
      onSend={handleSendMessage}
      isStreaming={isStreaming}
      placeholder="Ask Claude anything..."
    />
  );
}

Screenshot to React Conversion

截图转React代码

Convert screenshots or designs to React code:
typescript
import { screenshotToReact } from '@/lib/screenshot-converter';
import { useState } from 'react';

function ScreenshotConverter() {
  const [imageFile, setImageFile] = useState<File | null>(null);
  const [generatedCode, setGeneratedCode] = useState('');

  const handleConvert = async () => {
    if (!imageFile) return;

    const base64Image = await fileToBase64(imageFile);
    
    const code = await screenshotToReact({
      image: base64Image,
      framework: 'react',
      styling: 'tailwind',
      componentType: 'functional',
      typescript: true,
    });

    setGeneratedCode(code);
  };

  return (
    <div className="screenshot-converter">
      <input
        type="file"
        accept="image/*"
        onChange={(e) => setImageFile(e.target.files?.[0] || null)}
      />
      <button onClick={handleConvert}>Convert to React</button>
      <pre className="generated-code">{generatedCode}</pre>
    </div>
  );
}

async function fileToBase64(file: File): Promise<string> {
  return new Promise((resolve, reject) => {
    const reader = new FileReader();
    reader.onload = () => resolve(reader.result as string);
    reader.onerror = reject;
    reader.readAsDataURL(file);
  });
}
将截图或设计稿转换为React代码:
typescript
import { screenshotToReact } from '@/lib/screenshot-converter';
import { useState } from 'react';

function ScreenshotConverter() {
  const [imageFile, setImageFile] = useState<File | null>(null);
  const [generatedCode, setGeneratedCode] = useState('');

  const handleConvert = async () => {
    if (!imageFile) return;

    const base64Image = await fileToBase64(imageFile);
    
    const code = await screenshotToReact({
      image: base64Image,
      framework: 'react',
      styling: 'tailwind',
      componentType: 'functional',
      typescript: true,
    });

    setGeneratedCode(code);
  };

  return (
    <div className="screenshot-converter">
      <input
        type="file"
        accept="image/*"
        onChange={(e) => setImageFile(e.target.files?.[0] || null)}
      />
      <button onClick={handleConvert}>转换为React代码</button>
      <pre className="generated-code">{generatedCode}</pre>
    </div>
  );
}

async function fileToBase64(file: File): Promise<string> {
  return new Promise((resolve, reject) => {
    const reader = new FileReader();
    reader.onload = () => resolve(reader.result as string);
    reader.onerror = reject;
    reader.readAsDataURL(file);
  });
}

Custom Hooks

自定义Hooks

useClaudeStream

useClaudeStream

Hook for managing Claude streaming responses:
typescript
import { useClaudeStream } from '@/hooks/useClaudeStream';

function MyComponent() {
  const {
    messages,
    isStreaming,
    error,
    sendMessage,
    clearMessages
  } = useClaudeStream({
    apiKey: process.env.ANTHROPIC_API_KEY,
    model: 'claude-3-5-sonnet-20241022',
    maxTokens: 2048,
  });

  return (
    <div>
      {messages.map((msg, i) => (
        <div key={i} className={`message ${msg.role}`}>
          {msg.content}
        </div>
      ))}
      {isStreaming && <div className="typing-indicator">Claude is typing...</div>}
      {error && <div className="error">{error.message}</div>}
      <button onClick={() => sendMessage('Hello!')}>Send</button>
    </div>
  );
}
用于管理Claude流式响应的Hook:
typescript
import { useClaudeStream } from '@/hooks/useClaudeStream';

function MyComponent() {
  const {
    messages,
    isStreaming,
    error,
    sendMessage,
    clearMessages
  } = useClaudeStream({
    apiKey: process.env.ANTHROPIC_API_KEY,
    model: 'claude-3-5-sonnet-20241022',
    maxTokens: 2048,
  });

  return (
    <div>
      {messages.map((msg, i) => (
        <div key={i} className={`message ${msg.role}`}>
          {msg.content}
        </div>
      ))}
      {isStreaming && <div className="typing-indicator">Claude正在输入...</div>}
      {error && <div className="error">{error.message}</div>}
      <button onClick={() => sendMessage('Hello!')}>发送</button>
    </div>
  );
}

useDarkMode

useDarkMode

Toggle dark mode with system preference detection:
typescript
import { useDarkMode } from '@/hooks/useDarkMode';

function ThemeToggle() {
  const { isDark, toggle, setDark, setLight } = useDarkMode({
    defaultDark: false,
    storageKey: 'claude-design-theme',
  });

  return (
    <button onClick={toggle}>
      {isDark ? '🌙 Dark' : '☀️ Light'}
    </button>
  );
}
切换深色模式并支持系统偏好检测:
typescript
import { useDarkMode } from '@/hooks/useDarkMode';

function ThemeToggle() {
  const { isDark, toggle, setDark, setLight } = useDarkMode({
    defaultDark: false,
    storageKey: 'claude-design-theme',
  });

  return (
    <button onClick={toggle}>
      {isDark ? '🌙 深色' : '☀️ 浅色'}
    </button>
  );
}

useResponsiveLayout

useResponsiveLayout

Adaptive layouts based on viewport:
typescript
import { useResponsiveLayout } from '@/hooks/useResponsiveLayout';

function ResponsiveComponent() {
  const { isMobile, isTablet, isDesktop, breakpoint } = useResponsiveLayout();

  return (
    <div className={`layout-${breakpoint}`}>
      {isMobile && <MobileView />}
      {isTablet && <TabletView />}
      {isDesktop && <DesktopView />}
    </div>
  );
}
基于视口的自适应布局:
typescript
import { useResponsiveLayout } from '@/hooks/useResponsiveLayout';

function ResponsiveComponent() {
  const { isMobile, isTablet, isDesktop, breakpoint } = useResponsiveLayout();

  return (
    <div className={`layout-${breakpoint}`}>
      {isMobile && <MobileView />}
      {isTablet && <TabletView />}
      {isDesktop && <DesktopView />}
    </div>
  );
}

Tailwind Configuration

Tailwind配置

Extending the Design System

扩展设计系统

typescript
// tailwind.config.ts
import type { Config } from 'tailwindcss';
import { claudeDesignPreset } from '@/styles/tailwind-preset';

export default {
  presets: [claudeDesignPreset],
  content: [
    './index.html',
    './src/**/*.{js,ts,jsx,tsx}',
  ],
  theme: {
    extend: {
      colors: {
        'claude-primary': '#d97757',
        'claude-secondary': '#0078D7',
        'artifact-bg': 'var(--artifact-bg)',
      },
      fontFamily: {
        'sans': ['Inter', 'system-ui', 'sans-serif'],
        'mono': ['Fira Code', 'monospace'],
      },
      animation: {
        'typing': 'typing 1.5s steps(40) infinite',
        'stream': 'stream 2s ease-in-out infinite',
      },
    },
  },
  plugins: [],
} satisfies Config;
typescript
// tailwind.config.ts
import type { Config } from 'tailwindcss';
import { claudeDesignPreset } from '@/styles/tailwind-preset';

export default {
  presets: [claudeDesignPreset],
  content: [
    './index.html',
    './src/**/*.{js,ts,jsx,tsx}',
  ],
  theme: {
    extend: {
      colors: {
        'claude-primary': '#d97757',
        'claude-secondary': '#0078D7',
        'artifact-bg': 'var(--artifact-bg)',
      },
      fontFamily: {
        'sans': ['Inter', 'system-ui', 'sans-serif'],
        'mono': ['Fira Code', 'monospace'],
      },
      animation: {
        'typing': 'typing 1.5s steps(40) infinite',
        'stream': 'stream 2s ease-in-out infinite',
      },
    },
  },
  plugins: [],
} satisfies Config;

Custom Utility Classes

自定义工具类

css
/* src/styles/custom.css */
@tailwind base;
@tailwind components;
@tailwind utilities;

@layer components {
  .artifact-container {
    @apply rounded-lg border border-gray-200 dark:border-gray-800 bg-white dark:bg-gray-950 p-4;
  }

  .stream-message {
    @apply animate-stream opacity-80;
  }

  .code-block {
    @apply font-mono text-sm bg-gray-100 dark:bg-gray-900 p-4 rounded overflow-x-auto;
  }

  .ai-confidence-high {
    @apply bg-green-50 border-green-200 dark:bg-green-950 dark:border-green-800;
  }

  .ai-confidence-medium {
    @apply bg-yellow-50 border-yellow-200 dark:bg-yellow-950 dark:border-yellow-800;
  }

  .ai-confidence-low {
    @apply bg-red-50 border-red-200 dark:bg-red-950 dark:border-red-800;
  }
}
css
/* src/styles/custom.css */
@tailwind base;
@tailwind components;
@tailwind utilities;

@layer components {
  .artifact-container {
    @apply rounded-lg border border-gray-200 dark:border-gray-800 bg-white dark:bg-gray-950 p-4;
  }

  .stream-message {
    @apply animate-stream opacity-80;
  }

  .code-block {
    @apply font-mono text-sm bg-gray-100 dark:bg-gray-900 p-4 rounded overflow-x-auto;
  }

  .ai-confidence-high {
    @apply bg-green-50 border-green-200 dark:bg-green-950 dark:border-green-800;
  }

  .ai-confidence-medium {
    @apply bg-yellow-50 border-yellow-200 dark:bg-yellow-950 dark:border-yellow-800;
  }

  .ai-confidence-low {
    @apply bg-red-50 border-red-200 dark:bg-red-950 dark:border-red-800;
  }
}

Figma Integration

Figma集成

Export Components from Figma

从Figma导出组件

typescript
import { figmaToReact } from '@/lib/figma-converter';

async function exportFigmaComponent(figmaUrl: string) {
  const component = await figmaToReact({
    url: figmaUrl,
    apiToken: process.env.FIGMA_API_TOKEN,
    options: {
      framework: 'react',
      typescript: true,
      styling: 'tailwind',
      includeShadcn: true,
    },
  });

  return component;
}
typescript
import { figmaToReact } from '@/lib/figma-converter';

async function exportFigmaComponent(figmaUrl: string) {
  const component = await figmaToReact({
    url: figmaUrl,
    apiToken: process.env.FIGMA_API_TOKEN,
    options: {
      framework: 'react',
      typescript: true,
      styling: 'tailwind',
      includeShadcn: true,
    },
  });

  return component;
}

shadcn/ui Integration

shadcn/ui集成

Claude Design works seamlessly with shadcn/ui components:
bash
undefined
Claude Design可与shadcn/ui组件无缝协作:
bash
undefined

Initialize shadcn/ui in your project

在项目中初始化shadcn/ui

npx shadcn-ui@latest init
npx shadcn-ui@latest init

Add components

添加组件

npx shadcn-ui@latest add button npx shadcn-ui@latest add card npx shadcn-ui@latest add dialog

```typescript
import { Button } from '@/components/ui/button';
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import { ArtifactViewer } from '@/components/artifacts/ArtifactViewer';

function ArtifactCard({ artifact }) {
  return (
    <Card className="artifact-container">
      <CardHeader>
        <CardTitle>{artifact.title}</CardTitle>
      </CardHeader>
      <CardContent>
        <ArtifactViewer artifact={artifact} />
        <Button variant="outline" className="mt-4">
          Export Code
        </Button>
      </CardContent>
    </Card>
  );
}
npx shadcn-ui@latest add button npx shadcn-ui@latest add card npx shadcn-ui@latest add dialog

```typescript
import { Button } from '@/components/ui/button';
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import { ArtifactViewer } from '@/components/artifacts/ArtifactViewer';

function ArtifactCard({ artifact }) {
  return (
    <Card className="artifact-container">
      <CardHeader>
        <CardTitle>{artifact.title}</CardTitle>
      </CardHeader>
      <CardContent>
        <ArtifactViewer artifact={artifact} />
        <Button variant="outline" className="mt-4">
          导出代码
        </Button>
      </CardContent>
    </Card>
  );
}

SVG Icon Creator

SVG图标生成器

Generate custom SVG icons programmatically:
typescript
import { createSVGIcon } from '@/lib/svg-creator';

const customIcon = createSVGIcon({
  name: 'claude-logo',
  size: 24,
  viewBox: '0 0 24 24',
  paths: [
    'M12 2L2 7v10c0 5.55 3.84 10.74 9 12 5.16-1.26 9-6.45 9-12V7l-10-5z',
  ],
  fill: 'currentColor',
  stroke: 'none',
});

// Use in React
function MyIcon() {
  return (
    <svg
      width={customIcon.size}
      height={customIcon.size}
      viewBox={customIcon.viewBox}
      fill={customIcon.fill}
    >
      {customIcon.paths.map((d, i) => (
        <path key={i} d={d} />
      ))}
    </svg>
  );
}
以编程方式生成自定义SVG图标:
typescript
import { createSVGIcon } from '@/lib/svg-creator';

const customIcon = createSVGIcon({
  name: 'claude-logo',
  size: 24,
  viewBox: '0 0 24 24',
  paths: [
    'M12 2L2 7v10c0 5.55 3.84 10.74 9 12 5.16-1.26 9-6.45 9-12V7l-10-5z',
  ],
  fill: 'currentColor',
  stroke: 'none',
});

// 在React中使用
function MyIcon() {
  return (
    <svg
      width={customIcon.size}
      height={customIcon.size}
      viewBox={customIcon.viewBox}
      fill={customIcon.fill}
    >
      {customIcon.paths.map((d, i) => (
        <path key={i} d={d} />
      ))}
    </svg>
  );
}

Common Patterns

常见模式

Real-time Code Preview

实时代码预览

typescript
import { CodePreview } from '@/components/artifacts/CodePreview';
import { useState, useEffect } from 'react';

function LiveCodeEditor() {
  const [code, setCode] = useState('');
  const [preview, setPreview] = useState('');

  useEffect(() => {
    const timer = setTimeout(() => {
      setPreview(code);
    }, 500);
    return () => clearTimeout(timer);
  }, [code]);

  return (
    <div className="grid grid-cols-2 gap-4">
      <textarea
        value={code}
        onChange={(e) => setCode(e.target.value)}
        className="code-block"
      />
      <CodePreview
        code={preview}
        language="tsx"
        showPreview
        autoRefresh
      />
    </div>
  );
}
typescript
import { CodePreview } from '@/components/artifacts/CodePreview';
import { useState, useEffect } from 'react';

function LiveCodeEditor() {
  const [code, setCode] = useState('');
  const [preview, setPreview] = useState('');

  useEffect(() => {
    const timer = setTimeout(() => {
      setPreview(code);
    }, 500);
    return () => clearTimeout(timer);
  }, [code]);

  return (
    <div className="grid grid-cols-2 gap-4">
      <textarea
        value={code}
        onChange={(e) => setCode(e.target.value)}
        className="code-block"
      />
      <CodePreview
        code={preview}
        language="tsx"
        showPreview
        autoRefresh
      />
    </div>
  );
}

Adaptive Color Based on AI Confidence

基于AI置信度的自适应色彩

typescript
import { useAIConfidence } from '@/hooks/useAIConfidence';

function AIResponse({ message, metadata }) {
  const confidence = useAIConfidence(metadata);

  return (
    <div className={`
      p-4 rounded-lg
      ${confidence > 0.8 ? 'ai-confidence-high' : ''}
      ${confidence > 0.5 && confidence <= 0.8 ? 'ai-confidence-medium' : ''}
      ${confidence <= 0.5 ? 'ai-confidence-low' : ''}
    `}>
      <p>{message}</p>
      <span className="text-xs text-gray-500">
        Confidence: {(confidence * 100).toFixed(0)}%
      </span>
    </div>
  );
}
typescript
import { useAIConfidence } from '@/hooks/useAIConfidence';

function AIResponse({ message, metadata }) {
  const confidence = useAIConfidence(metadata);

  return (
    <div className={`
      p-4 rounded-lg
      ${confidence > 0.8 ? 'ai-confidence-high' : ''}
      ${confidence > 0.5 && confidence <= 0.8 ? 'ai-confidence-medium' : ''}
      ${confidence <= 0.5 ? 'ai-confidence-low' : ''}
    `}>
      <p>{message}</p>
      <span className="text-xs text-gray-500">
        置信度: {(confidence * 100).toFixed(0)}%
      </span>
    </div>
  );
}

Markdown with LaTeX Rendering

支持LaTeX的Markdown渲染

typescript
import { MarkdownRenderer } from '@/components/ui/MarkdownRenderer';

function DocumentViewer({ content }) {
  return (
    <MarkdownRenderer
      content={content}
      enableLatex
      enableCodeHighlight
      sanitize
      className="prose dark:prose-invert max-w-none"
    />
  );
}
typescript
import { MarkdownRenderer } from '@/components/ui/MarkdownRenderer';

function DocumentViewer({ content }) {
  return (
    <MarkdownRenderer
      content={content}
      enableLatex
      enableCodeHighlight
      sanitize
      className="prose dark:prose-invert max-w-none"
    />
  );
}

Environment Configuration

环境配置

Create a
.env
file in your project root:
bash
undefined
在项目根目录创建
.env
文件:
bash
undefined

Anthropic API

Anthropic API

ANTHROPIC_API_KEY=your_api_key_here
ANTHROPIC_API_KEY=your_api_key_here

Figma Integration (optional)

Figma集成(可选)

FIGMA_API_TOKEN=your_figma_token_here
FIGMA_API_TOKEN=your_figma_token_here

Application Settings

应用设置

VITE_APP_TITLE=Claude Design App VITE_DEFAULT_MODEL=claude-3-5-sonnet-20241022 VITE_MAX_TOKENS=4096

Access environment variables:

```typescript
const config = {
  anthropicKey: import.meta.env.ANTHROPIC_API_KEY,
  figmaToken: import.meta.env.FIGMA_API_TOKEN,
  defaultModel: import.meta.env.VITE_DEFAULT_MODEL,
  maxTokens: parseInt(import.meta.env.VITE_MAX_TOKENS || '4096'),
};
VITE_APP_TITLE=Claude Design App VITE_DEFAULT_MODEL=claude-3-5-sonnet-20241022 VITE_MAX_TOKENS=4096

访问环境变量:

```typescript
const config = {
  anthropicKey: import.meta.env.ANTHROPIC_API_KEY,
  figmaToken: import.meta.env.FIGMA_API_TOKEN,
  defaultModel: import.meta.env.VITE_DEFAULT_MODEL,
  maxTokens: parseInt(import.meta.env.VITE_MAX_TOKENS || '4096'),
};

Troubleshooting

故障排除

Streaming Not Working

流式响应不工作

Issue: Claude's streaming responses aren't displaying properly.
Solution: Ensure you're using the latest Anthropic SDK and that your API key has streaming enabled:
typescript
// Verify SDK version
import Anthropic from '@anthropic-ai/sdk';
console.log(Anthropic.VERSION); // Should be >= 0.17.0

// Use proper stream handling
const stream = await client.messages.stream({
  model: 'claude-3-5-sonnet-20241022',
  max_tokens: 1024,
  messages: [{ role: 'user', content: 'Hello' }],
});

// Handle all event types
stream.on('text', (text) => console.log(text));
stream.on('error', (error) => console.error(error));
stream.on('end', () => console.log('Stream ended'));
问题:Claude的流式响应无法正常显示。
解决方案:确保使用最新版Anthropic SDK,且API密钥已启用流式响应:
typescript
// 验证SDK版本
import Anthropic from '@anthropic-ai/sdk';
console.log(Anthropic.VERSION); // 应 >= 0.17.0

// 使用正确的流式处理方式
const stream = await client.messages.stream({
  model: 'claude-3-5-sonnet-20241022',
  max_tokens: 1024,
  messages: [{ role: 'user', content: 'Hello' }],
});

// 处理所有事件类型
stream.on('text', (text) => console.log(text));
stream.on('error', (error) => console.error(error));
stream.on('end', () => console.log('流已结束'));

Dark Mode Not Persisting

深色模式不持久

Issue: Dark mode preference resets on page reload.
Solution: Verify localStorage is accessible and the key matches:
typescript
import { useDarkMode } from '@/hooks/useDarkMode';

// Ensure storageKey is consistent
const { isDark, toggle } = useDarkMode({
  storageKey: 'claude-design-theme', // Must match across app
  defaultDark: window.matchMedia('(prefers-color-scheme: dark)').matches,
});
问题:页面刷新后深色模式偏好重置。
解决方案:验证localStorage可访问且密钥一致:
typescript
import { useDarkMode } from '@/hooks/useDarkMode';

// 确保storageKey在整个应用中一致
const { isDark, toggle } = useDarkMode({
  storageKey: 'claude-design-theme', // 必须在应用中保持一致
  defaultDark: window.matchMedia('(prefers-color-scheme: dark)').matches,
});

Tailwind Classes Not Applying

Tailwind类不生效

Issue: Custom Tailwind classes from Claude Design aren't working.
Solution: Ensure the preset is properly imported:
typescript
// tailwind.config.ts
import { claudeDesignPreset } from './src/styles/tailwind-preset';

export default {
  presets: [claudeDesignPreset], // Must be first
  content: ['./src/**/*.{js,ts,jsx,tsx}'],
  // ... rest of config
};
问题:Claude Design的自定义Tailwind类无法工作。
解决方案:确保正确导入预设:
typescript
// tailwind.config.ts
import { claudeDesignPreset } from './src/styles/tailwind-preset';

export default {
  presets: [claudeDesignPreset], // 必须放在首位
  content: ['./src/**/*.{js,ts,jsx,tsx}'],
  // ... 其余配置
};

Screenshot Conversion Fails

截图转换失败

Issue: Screenshot-to-React conversion produces invalid code.
Solution: Ensure image is properly base64 encoded and within size limits:
typescript
async function convertScreenshot(file: File) {
  // Validate file size (max 5MB)
  if (file.size > 5 * 1024 * 1024) {
    throw new Error('Image too large. Max 5MB.');
  }

  // Validate file type
  if (!file.type.startsWith('image/')) {
    throw new Error('Invalid file type. Must be an image.');
  }

  const base64 = await fileToBase64(file);
  
  return await screenshotToReact({
    image: base64,
    framework: 'react',
    styling: 'tailwind',
  });
}
问题:截图转React代码生成无效代码。
解决方案:确保图片已正确base64编码且在大小限制内:
typescript
async function convertScreenshot(file: File) {
  // 验证文件大小(最大5MB)
  if (file.size > 5 * 1024 * 1024) {
    throw new Error('图片过大,最大支持5MB。');
  }

  // 验证文件类型
  if (!file.type.startsWith('image/')) {
    throw new Error('无效文件类型,必须为图片。');
  }

  const base64 = await fileToBase64(file);
  
  return await screenshotToReact({
    image: base64,
    framework: 'react',
    styling: 'tailwind',
  });
}

Build Errors with TypeScript

TypeScript构建错误

Issue: TypeScript errors during build.
Solution: Ensure all types are properly exported:
typescript
// src/types/index.ts
export interface ArtifactType {
  type: 'code' | 'document' | 'chart';
  content: string;
  language?: string;
  isStreaming?: boolean;
}

export interface MessageType {
  role: 'user' | 'assistant';
  content: string;
  timestamp?: number;
}

// Use in components
import type { ArtifactType, MessageType } from '@/types';
问题:构建过程中出现TypeScript错误。
解决方案:确保所有类型已正确导出:
typescript
// src/types/index.ts
export interface ArtifactType {
  type: 'code' | 'document' | 'chart';
  content: string;
  language?: string;
  isStreaming?: boolean;
}

export interface MessageType {
  role: 'user' | 'assistant';
  content: string;
  timestamp?: number;
}

// 在组件中使用
import type { ArtifactType, MessageType } from '@/types';

Best Practices

最佳实践

  1. Always sanitize AI-generated content before rendering to prevent XSS attacks
  2. Use environment variables for all API keys and secrets
  3. Implement error boundaries around streaming components
  4. Optimize for mobile using the responsive layout hooks
  5. Leverage Tailwind's JIT mode for faster development builds
  6. Cache frequently used components with React.memo
  7. Use TypeScript strict mode to catch type errors early
  1. 始终清理AI生成的内容后再渲染,防止XSS攻击
  2. 使用环境变量存储所有API密钥和敏感信息
  3. 在流式响应组件周围实现错误边界
  4. 使用响应式布局hooks优化移动端体验
  5. 利用Tailwind的JIT模式加快开发构建速度
  6. 使用React.memo缓存频繁使用的组件
  7. 启用TypeScript严格模式提前捕获类型错误

Additional Resources

额外资源