Anthropic Skills 中文文档
首页
使用指南
技能列表
  • 🎨 创意与设计
  • 💻 开发与技术
  • 🏢 企业与沟通
  • 📄 文档处理
  • 🔧 元技能
  • GitHub 仓库
  • Claude 官网
  • Skills 官方文档
GitHub
首页
使用指南
技能列表
  • 🎨 创意与设计
  • 💻 开发与技术
  • 🏢 企业与沟通
  • 📄 文档处理
  • 🔧 元技能
  • GitHub 仓库
  • Claude 官网
  • Skills 官方文档
GitHub
  • 技能列表
  • 🎨 创意与设计

    • 🎨 算法艺术生成

      • 📋 概览
      • 📖 完整指南
    • 🖼️ 画布设计

      • 📋 概览
      • 📖 完整指南
    • 🎬 Slack GIF 创建器

      • 📋 概览
      • 📖 完整指南
    • 🎨 主题工厂

      • 📋 概览
      • 📖 完整指南
  • 💻 开发与技术

    • 🎨 Web 组件构建器

      • 📋 概览
      • 📖 完整指南
    • 📦 MCP 服务器构建器

      • 📋 概览
      • 📖 完整指南
    • 🧪 Web 应用测试工具

      • 📋 概览
      • 📖 完整指南
  • 🏢 企业与沟通

    • 🎨 品牌指南

      • 📋 概览
      • 📖 完整指南
    • 📢 企业内部沟通

      • 📋 概览
      • 📖 完整指南
    • 💎 前端设计

      • 📋 概览
      • 📖 完整指南
  • 📄 文档处理

    • 📘 Word 文档处理

      • 📋 概览
      • 📖 完整指南
    • 📕 PDF 文档处理

      • 📋 概览
      • 📖 完整指南
    • 📙 PowerPoint 演示文稿处理

      • 📋 概览
      • 📖 完整指南
    • 📗 Excel 表格处理

      • 📋 概览
      • 📖 完整指南
  • 🔧 元技能

    • 🛠️ Skill 创建器

      • 📋 概览
      • 📖 完整指南
    • 📝 Skill 模板

      • 📋 概览
      • 📖 完整参考

Web Artifacts Builder 完整指南

本文档包含使用 Web Artifacts Builder 创建复杂 claude.ai artifacts 的完整技术细节。如果您是初次接触,建议先阅读 📋 概览。

目录

  • 目录
  • 技术栈详解
    • 核心技术
    • 版本要求
  • 完整工作流程
    • 阶段 1:项目初始化
    • 阶段 2:开发 Artifact
    • 阶段 3:打包 Artifact
    • 阶段 4:分享 Artifact
  • 设计和样式指南
    • 避免 "AI 风格"
    • Tailwind CSS 最佳实践
  • 常见开发任务
    • 添加新组件
    • 创建自定义组件
    • 添加图标
    • 数据获取
  • 完整示例
    • 示例 1:待办事项应用
    • 示例 2:数据表格
  • 故障排除
    • 常见问题
  • 参考资源
    • 官方文档
    • 组件示例
    • 工具

技术栈详解

核心技术

┌─────────────────────────────────────┐
│         开发环境 (Vite)              │
│  ┌──────────────────────────────┐   │
│  │   React 18 + TypeScript      │   │
│  │                              │   │
│  │  ┌────────────────────────┐  │   │
│  │  │  shadcn/ui 组件库      │  │   │
│  │  │  (40+ 组件)            │  │   │
│  │  └────────────────────────┘  │   │
│  │                              │   │
│  │  ┌────────────────────────┐  │   │
│  │  │  Tailwind CSS 3.4.1    │  │   │
│  │  │  (实用类样式)          │  │   │
│  │  └────────────────────────┘  │   │
│  └──────────────────────────────┘   │
└─────────────────────────────────────┘
                 │
                 ▼
┌─────────────────────────────────────┐
│      打包工具 (Parcel)               │
│  - 编译 TypeScript                  │
│  - 处理 Tailwind CSS                │
│  - 解析路径别名 (@/)                │
│  - 内联所有资源                     │
└─────────────────────────────────────┘
                 │
                 ▼
        📄 bundle.html
    (自包含的 artifact)

版本要求

技术版本说明
Node.js≥18.0.0必需
React18.x自动安装
TypeScript5.x自动安装
Vite自动选择根据 Node 版本
Tailwind CSS3.4.1固定版本
Parcel最新打包时安装

完整工作流程

阶段 1:项目初始化

运行初始化脚本

bash scripts/init-artifact.sh <project-name>

参数:

  • <project-name>:项目名称(小写字母、数字、连字符)

执行过程:

[1/7] 创建项目目录
  └─ 创建 <project-name>/

[2/7] 初始化 Vite + React + TypeScript
  ├─ 运行 npm create vite@latest
  ├─ 选择 React 模板
  └─ 选择 TypeScript 变体

[3/7] 安装依赖
  └─ npm install

[4/7] 安装 Tailwind CSS
  ├─ npm install -D tailwindcss postcss autoprefixer
  └─ npx tailwindcss init -p

[5/7] 配置 shadcn/ui
  ├─ 安装 @shadcn/ui CLI
  ├─ 初始化配置
  └─ 设置主题和别名

[6/7] 预装 shadcn/ui 组件
  └─ 安装 40+ 常用组件及依赖

[7/7] 配置路径别名
  ├─ 更新 tsconfig.json
  ├─ 更新 vite.config.ts
  └─ 创建 @/ 别名指向 src/

✅ 项目初始化完成!

生成的项目结构

<project-name>/
├── src/
│   ├── main.tsx                 # 应用入口
│   ├── App.tsx                  # 主组件
│   ├── App.css                  # 样式
│   ├── index.css                # 全局样式 + Tailwind
│   ├── vite-env.d.ts           # Vite 类型定义
│   ├── components/
│   │   └── ui/                 # shadcn/ui 组件
│   │       ├── button.tsx
│   │       ├── card.tsx
│   │       ├── dialog.tsx
│   │       ├── input.tsx
│   │       ├── select.tsx
│   │       └── ... (40+ 组件)
│   └── lib/
│       └── utils.ts            # 工具函数 (cn, clsx)
├── public/                      # 静态资源
├── index.html                   # HTML 模板
├── package.json                 # 依赖配置
├── tsconfig.json               # TypeScript 配置
├── vite.config.ts              # Vite 配置
├── tailwind.config.js          # Tailwind 配置
├── postcss.config.js           # PostCSS 配置
├── components.json             # shadcn/ui 配置
└── README.md

关键配置文件

vite.config.ts:

import path from 'path'
import react from '@vitejs/plugin-react'
import { defineConfig } from 'vite'

export default defineConfig({
  plugins: [react()],
  resolve: {
    alias: {
      '@': path.resolve(__dirname, './src'),
    },
  },
})

tsconfig.json(关键部分):

{
  "compilerOptions": {
    "baseUrl": ".",
    "paths": {
      "@/*": ["./src/*"]
    }
  }
}

tailwind.config.js:

module.exports = {
  darkMode: ["class"],
  content: [
    "./index.html",
    "./src/**/*.{ts,tsx,js,jsx}",
  ],
  theme: {
    extend: {
      // shadcn/ui 主题配置
      colors: {
        border: "hsl(var(--border))",
        input: "hsl(var(--input))",
        ring: "hsl(var(--ring))",
        background: "hsl(var(--background))",
        foreground: "hsl(var(--foreground))",
        // ... 更多颜色
      },
      borderRadius: {
        lg: "var(--radius)",
        md: "calc(var(--radius) - 2px)",
        sm: "calc(var(--radius) - 4px)",
      },
    },
  },
  plugins: [require("tailwindcss-animate")],
}

阶段 2:开发 Artifact

基础开发流程

# 进入项目目录
cd <project-name>

# 启动开发服务器
npm run dev

# 浏览器访问 http://localhost:5173

编辑 App.tsx

基础示例:

import { useState } from 'react'
import { Button } from '@/components/ui/button'
import {
  Card,
  CardContent,
  CardDescription,
  CardFooter,
  CardHeader,
  CardTitle,
} from '@/components/ui/card'

function App() {
  const [count, setCount] = useState(0)

  return (
    <div className="min-h-screen bg-gradient-to-br from-gray-50 to-gray-100 p-8">
      <div className="max-w-md mx-auto">
        <Card>
          <CardHeader>
            <CardTitle>计数器应用</CardTitle>
            <CardDescription>
              点击按钮增加计数
            </CardDescription>
          </CardHeader>
          <CardContent>
            <div className="text-center">
              <p className="text-6xl font-bold text-blue-600 mb-4">
                {count}
              </p>
              <p className="text-sm text-gray-500">
                当前计数
              </p>
            </div>
          </CardContent>
          <CardFooter className="flex gap-2">
            <Button 
              onClick={() => setCount(count + 1)}
              className="flex-1"
            >
              增加
            </Button>
            <Button 
              onClick={() => setCount(0)}
              variant="outline"
              className="flex-1"
            >
              重置
            </Button>
          </CardFooter>
        </Card>
      </div>
    </div>
  )
}

export default App

使用 shadcn/ui 组件

表单示例:

import { useState } from 'react'
import { Button } from '@/components/ui/button'
import { Input } from '@/components/ui/input'
import { Label } from '@/components/ui/label'
import { Textarea } from '@/components/ui/textarea'
import {
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
  SelectValue,
} from '@/components/ui/select'

function ContactForm() {
  const [formData, setFormData] = useState({
    name: '',
    email: '',
    type: '',
    message: ''
  })

  const handleSubmit = (e: React.FormEvent) => {
    e.preventDefault()
    console.log('提交数据:', formData)
  }

  return (
    <form onSubmit={handleSubmit} className="space-y-4">
      <div>
        <Label htmlFor="name">姓名</Label>
        <Input
          id="name"
          value={formData.name}
          onChange={(e) => setFormData({ ...formData, name: e.target.value })}
          placeholder="请输入您的姓名"
        />
      </div>

      <div>
        <Label htmlFor="email">邮箱</Label>
        <Input
          id="email"
          type="email"
          value={formData.email}
          onChange={(e) => setFormData({ ...formData, email: e.target.value })}
          placeholder="your@email.com"
        />
      </div>

      <div>
        <Label htmlFor="type">咨询类型</Label>
        <Select
          value={formData.type}
          onValueChange={(value) => setFormData({ ...formData, type: value })}
        >
          <SelectTrigger id="type">
            <SelectValue placeholder="请选择" />
          </SelectTrigger>
          <SelectContent>
            <SelectItem value="general">一般咨询</SelectItem>
            <SelectItem value="support">技术支持</SelectItem>
            <SelectItem value="sales">销售咨询</SelectItem>
          </SelectContent>
        </Select>
      </div>

      <div>
        <Label htmlFor="message">留言</Label>
        <Textarea
          id="message"
          value={formData.message}
          onChange={(e) => setFormData({ ...formData, message: e.target.value })}
          placeholder="请输入您的留言"
          rows={4}
        />
      </div>

      <Button type="submit" className="w-full">
        提交
      </Button>
    </form>
  )
}

对话框示例:

import {
  Dialog,
  DialogContent,
  DialogDescription,
  DialogHeader,
  DialogTitle,
  DialogTrigger,
  DialogFooter,
} from '@/components/ui/dialog'
import { Button } from '@/components/ui/button'

function ConfirmDialog() {
  return (
    <Dialog>
      <DialogTrigger asChild>
        <Button variant="destructive">删除</Button>
      </DialogTrigger>
      <DialogContent>
        <DialogHeader>
          <DialogTitle>确认删除?</DialogTitle>
          <DialogDescription>
            此操作无法撤销。确定要删除这个项目吗?
          </DialogDescription>
        </DialogHeader>
        <DialogFooter>
          <Button variant="outline">取消</Button>
          <Button variant="destructive">确认删除</Button>
        </DialogFooter>
      </DialogContent>
    </Dialog>
  )
}

状态管理

使用 React Context:

// src/context/AppContext.tsx
import { createContext, useContext, useState, ReactNode } from 'react'

interface AppContextType {
  user: { name: string; email: string } | null
  setUser: (user: { name: string; email: string } | null) => void
  theme: 'light' | 'dark'
  setTheme: (theme: 'light' | 'dark') => void
}

const AppContext = createContext<AppContextType | undefined>(undefined)

export function AppProvider({ children }: { children: ReactNode }) {
  const [user, setUser] = useState<{ name: string; email: string } | null>(null)
  const [theme, setTheme] = useState<'light' | 'dark'>('light')

  return (
    <AppContext.Provider value={{ user, setUser, theme, setTheme }}>
      {children}
    </AppContext.Provider>
  )
}

export function useApp() {
  const context = useContext(AppContext)
  if (!context) {
    throw new Error('useApp must be used within AppProvider')
  }
  return context
}

在 main.tsx 中使用:

import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App.tsx'
import { AppProvider } from './context/AppContext.tsx'
import './index.css'

ReactDOM.createRoot(document.getElementById('root')!).render(
  <React.StrictMode>
    <AppProvider>
      <App />
    </AppProvider>
  </React.StrictMode>,
)

阶段 3:打包 Artifact

运行打包脚本

bash scripts/bundle-artifact.sh

执行过程:

[1/5] 检查 index.html
  ✅ 找到 index.html

[2/5] 安装打包依赖
  ├─ npm install -D parcel
  ├─ npm install -D @parcel/config-default
  ├─ npm install -D parcel-resolver-tspaths
  └─ npm install -D html-inline

[3/5] 创建 Parcel 配置
  └─ 生成 .parcelrc

[4/5] 使用 Parcel 构建
  ├─ 编译 TypeScript
  ├─ 处理 Tailwind CSS
  ├─ 解析 @/ 路径别名
  └─ 生成 dist/ 目录

[5/5] 内联所有资源
  ├─ 运行 html-inline
  ├─ 内联 JavaScript
  ├─ 内联 CSS
  └─ 生成 bundle.html

✅ 打包完成!文件位置: bundle.html

Parcel 配置(.parcelrc)

{
  "extends": "@parcel/config-default",
  "resolvers": ["parcel-resolver-tspaths", "..."]
}

说明:

  • @parcel/config-default:使用默认配置
  • parcel-resolver-tspaths:支持 TypeScript 路径别名(@/)

打包输出

dist/ 目录结构:

dist/
├── index.html           # 带外部资源引用的 HTML
├── index.[hash].js      # 编译后的 JavaScript
└── index.[hash].css     # 编译后的 CSS

bundle.html:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>My Artifact</title>
  <style>
    /* 所有 CSS 内联在这里 */
    /* 包括 Tailwind、shadcn/ui 和自定义样式 */
  </style>
</head>
<body>
  <div id="root"></div>
  <script>
    // 所有 JavaScript 内联在这里
    // 包括 React、组件代码和依赖
  </script>
</body>
</html>

阶段 4:分享 Artifact

在 Claude 对话中分享

  1. 读取 bundle.html:

    cat bundle.html
    
  2. 发送给用户: 直接将文件内容作为代码块发送

  3. 用户查看: Claude 会将其渲染为交互式 artifact

文件大小考虑

典型大小:

  • 简单应用(1-2 组件):~200-500 KB
  • 中等应用(5-10 组件):~500 KB - 1 MB
  • 复杂应用(20+ 组件):1-3 MB

优化建议:

  • 移除未使用的 shadcn/ui 组件
  • 精简 Tailwind CSS(使用 purge)
  • 避免大型第三方库

设计和样式指南

避免 "AI 风格"

问题模式

// ❌ 避免:所有内容居中
function BadLayout() {
  return (
    <div className="flex items-center justify-center min-h-screen">
      <div className="text-center">
        {/* 所有内容都居中 */}
      </div>
    </div>
  )
}

// ❌ 避免:紫色渐变
<div className="bg-gradient-to-r from-purple-500 to-pink-500">

// ❌ 避免:统一圆角
<Button className="rounded-xl" />
<Card className="rounded-xl" />
<Input className="rounded-xl" />

推荐模式

// ✅ 推荐:实用的布局
function GoodLayout() {
  return (
    <div className="min-h-screen bg-gray-50">
      <header className="bg-white shadow">
        <nav className="max-w-7xl mx-auto px-4 py-4">
          {/* 导航内容 */}
        </nav>
      </header>
      <main className="max-w-7xl mx-auto px-4 py-8">
        <div className="grid grid-cols-1 md:grid-cols-3 gap-6">
          {/* 网格布局 */}
        </div>
      </main>
    </div>
  )
}

// ✅ 推荐:品牌色系统
const colors = {
  primary: 'blue',      // 主色
  secondary: 'green',   // 辅助色
  accent: 'orange',     // 强调色
  neutral: 'gray',      // 中性色
}

// ✅ 推荐:语义化圆角
<Button className="rounded-md" />     // 中等圆角
<Card className="rounded-lg" />       // 大圆角
<Badge className="rounded-full" />    // 完全圆角

Tailwind CSS 最佳实践

响应式设计

function ResponsiveCard() {
  return (
    <Card className="
      w-full              
      md:w-1/2            
      lg:w-1/3            
      p-4                 
      md:p-6              
      lg:p-8              
    ">
      <h2 className="
        text-xl           
        md:text-2xl       
        lg:text-3xl       
        font-bold
      ">
        响应式标题
      </h2>
    </Card>
  )
}

组合实用类

// ✅ 使用 cn() 工具函数组合类
import { cn } from '@/lib/utils'

function DynamicButton({ variant, className }: ButtonProps) {
  return (
    <button
      className={cn(
        // 基础样式
        "px-4 py-2 rounded-md font-medium transition-colors",
        // 条件样式
        variant === 'primary' && "bg-blue-600 text-white hover:bg-blue-700",
        variant === 'secondary' && "bg-gray-200 text-gray-900 hover:bg-gray-300",
        // 自定义样式
        className
      )}
    >
      按钮
    </button>
  )
}

常见开发任务

添加新组件

安装单个组件:

npx shadcn-ui@latest add <component-name>

# 示例
npx shadcn-ui@latest add dropdown-menu
npx shadcn-ui@latest add date-picker
npx shadcn-ui@latest add data-table

查看可用组件:

npx shadcn-ui@latest add
# 会显示所有可用组件列表

创建自定义组件

// src/components/CustomCard.tsx
import { Card, CardHeader, CardTitle, CardContent } from '@/components/ui/card'
import { ReactNode } from 'react'

interface CustomCardProps {
  title: string
  icon?: ReactNode
  children: ReactNode
}

export function CustomCard({ title, icon, children }: CustomCardProps) {
  return (
    <Card>
      <CardHeader>
        <CardTitle className="flex items-center gap-2">
          {icon}
          {title}
        </CardTitle>
      </CardHeader>
      <CardContent>
        {children}
      </CardContent>
    </Card>
  )
}

添加图标

安装 lucide-react:

npm install lucide-react

使用图标:

import { Search, User, Settings, X } from 'lucide-react'

function IconExample() {
  return (
    <div className="flex gap-2">
      <Search className="h-4 w-4" />
      <User className="h-5 w-5 text-blue-600" />
      <Settings className="h-6 w-6 text-gray-500" />
      <X className="h-4 w-4 hover:text-red-600 cursor-pointer" />
    </div>
  )
}

数据获取

import { useState, useEffect } from 'react'

function DataFetching() {
  const [data, setData] = useState(null)
  const [loading, setLoading] = useState(true)
  const [error, setError] = useState(null)

  useEffect(() => {
    fetch('https://api.example.com/data')
      .then(res => res.json())
      .then(data => {
        setData(data)
        setLoading(false)
      })
      .catch(err => {
        setError(err.message)
        setLoading(false)
      })
  }, [])

  if (loading) return <div>加载中...</div>
  if (error) return <div>错误: {error}</div>

  return <div>{/* 渲染数据 */}</div>
}

完整示例

示例 1:待办事项应用

import { useState } from 'react'
import { Button } from '@/components/ui/button'
import { Input } from '@/components/ui/input'
import { Checkbox } from '@/components/ui/checkbox'
import { Card, CardHeader, CardTitle, CardContent } from '@/components/ui/card'
import { X } from 'lucide-react'

interface Todo {
  id: number
  text: string
  completed: boolean
}

function TodoApp() {
  const [todos, setTodos] = useState<Todo[]>([])
  const [input, setInput] = useState('')

  const addTodo = () => {
    if (input.trim()) {
      setTodos([...todos, {
        id: Date.now(),
        text: input,
        completed: false
      }])
      setInput('')
    }
  }

  const toggleTodo = (id: number) => {
    setTodos(todos.map(todo =>
      todo.id === id ? { ...todo, completed: !todo.completed } : todo
    ))
  }

  const deleteTodo = (id: number) => {
    setTodos(todos.filter(todo => todo.id !== id))
  }

  return (
    <div className="min-h-screen bg-gray-50 p-8">
      <Card className="max-w-2xl mx-auto">
        <CardHeader>
          <CardTitle>待办事项</CardTitle>
        </CardHeader>
        <CardContent className="space-y-4">
          <div className="flex gap-2">
            <Input
              value={input}
              onChange={(e) => setInput(e.target.value)}
              onKeyPress={(e) => e.key === 'Enter' && addTodo()}
              placeholder="添加新任务..."
            />
            <Button onClick={addTodo}>添加</Button>
          </div>

          <div className="space-y-2">
            {todos.map(todo => (
              <div
                key={todo.id}
                className="flex items-center gap-2 p-3 bg-white rounded-lg border"
              >
                <Checkbox
                  checked={todo.completed}
                  onCheckedChange={() => toggleTodo(todo.id)}
                />
                <span className={`flex-1 ${todo.completed ? 'line-through text-gray-400' : ''}`}>
                  {todo.text}
                </span>
                <Button
                  variant="ghost"
                  size="sm"
                  onClick={() => deleteTodo(todo.id)}
                >
                  <X className="h-4 w-4" />
                </Button>
              </div>
            ))}
          </div>

          {todos.length === 0 && (
            <p className="text-center text-gray-400 py-8">
              暂无任务,添加一个吧!
            </p>
          )}
        </CardContent>
      </Card>
    </div>
  )
}

export default TodoApp

示例 2:数据表格

import {
  Table,
  TableBody,
  TableCell,
  TableHead,
  TableHeader,
  TableRow,
} from '@/components/ui/table'
import { Badge } from '@/components/ui/badge'

interface User {
  id: number
  name: string
  email: string
  role: 'admin' | 'user'
  status: 'active' | 'inactive'
}

const users: User[] = [
  { id: 1, name: '张三', email: 'zhang@example.com', role: 'admin', status: 'active' },
  { id: 2, name: '李四', email: 'li@example.com', role: 'user', status: 'active' },
  { id: 3, name: '王五', email: 'wang@example.com', role: 'user', status: 'inactive' },
]

function UserTable() {
  return (
    <Table>
      <TableHeader>
        <TableRow>
          <TableHead>ID</TableHead>
          <TableHead>姓名</TableHead>
          <TableHead>邮箱</TableHead>
          <TableHead>角色</TableHead>
          <TableHead>状态</TableHead>
        </TableRow>
      </TableHeader>
      <TableBody>
        {users.map(user => (
          <TableRow key={user.id}>
            <TableCell>{user.id}</TableCell>
            <TableCell className="font-medium">{user.name}</TableCell>
            <TableCell>{user.email}</TableCell>
            <TableCell>
              <Badge variant={user.role === 'admin' ? 'default' : 'secondary'}>
                {user.role === 'admin' ? '管理员' : '用户'}
              </Badge>
            </TableCell>
            <TableCell>
              <Badge variant={user.status === 'active' ? 'default' : 'outline'}>
                {user.status === 'active' ? '活跃' : '停用'}
              </Badge>
            </TableCell>
          </TableRow>
        ))}
      </TableBody>
    </Table>
  )
}

故障排除

常见问题

1. 打包后样式丢失

原因:Tailwind 未正确扫描文件

解决:

// tailwind.config.js
module.exports = {
  content: [
    "./index.html",
    "./src/**/*.{ts,tsx,js,jsx}", // 确保包含所有文件
  ],
  // ...
}

2. 路径别名不工作

原因:配置不一致

解决:

// tsconfig.json
{
  "compilerOptions": {
    "baseUrl": ".",
    "paths": {
      "@/*": ["./src/*"]
    }
  }
}
// vite.config.ts
import path from 'path'

export default defineConfig({
  resolve: {
    alias: {
      '@': path.resolve(__dirname, './src'),
    },
  },
})

3. Parcel 构建失败

原因:缺少 .parcelrc 配置

解决:运行打包脚本会自动创建

或手动创建:

{
  "extends": "@parcel/config-default",
  "resolvers": ["parcel-resolver-tspaths", "..."]
}

参考资源

官方文档

  • shadcn/ui: https://ui.shadcn.com
  • React: https://react.dev
  • TypeScript: https://www.typescriptlang.org
  • Vite: https://vitejs.dev
  • Tailwind CSS: https://tailwindcss.com
  • Parcel: https://parceljs.org

组件示例

  • shadcn/ui 示例: https://ui.shadcn.com/examples
  • Tailwind 组件: https://tailwindui.com/components

工具

  • lucide-react 图标: https://lucide.dev
  • Radix UI: https://www.radix-ui.com

返回:📋 概览 | 技能列表

Prev
📋 概览