mcpField
C
component-preview

component-preview

github.com/civitai设计与 UI7.3k59 次安装今天更新
代码仓库

关于 component-preview

Component Preview 是一套借助 Ladle 隔离预览 React 组件的工作流,使用 Mantine v7 和 Tailwind 样式。它涵盖创建 story、本地渲染、截图及迭代,适用于 UI 检查。

主要功能

  1. 01隔离预览 React 组件
  2. 02为组件状态创建 Ladle stories
  3. 03使用 Mantine v7 和 Tailwind 样式渲染
  4. 04捕获浅色与深色主题截图
  5. 05根据视觉变化迭代

适用场景

  1. 01修改 UI 后检查组件效果
  2. 02复现并排查视觉问题
  3. 03提交前审查组件变更

安装

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

$npx skills add https://github.com/civitai/civitai --skill component-preview

安装后在 Claude Code 中输入/component-preview确认已加载。

详细介绍

组件预览

使用 Ladle 隔离预览 React 组件(轻量级 Storybook 替代方案),并应用真实的 Mantine v7 + Tailwind 样式。无需开发服务器。

适用场景

  • 修改 UI 组件后 — 主动提出预览组件
  • 用户提出“让我看看效果”或“生成预览”时
  • 调试视觉问题时 — 创建 story 以复现问题并迭代调整
  • 提交前审查组件变更时

前置条件

项目根目录已配置 Ladle:

  • .ladle/components.tsx — 包含 MantineProvider + theme 的全局 provider
  • .ladle/config.mjs — Story 发现配置
  • .ladle/vite.config.ts — 配置了 ~/ 路径别名 + PostCSS 的 Vite 配置

如果当前工作树中没有这些文件,请从 main 复制或创建。请参阅下方的设置参考。

工作流

1. 创建/更新 Story

在要预览的组件附近创建一个 .stories.tsx 文件:

src/components/MyComponent/MyComponent.stories.tsx
src/pages/challenges/EligibleModels.stories.tsx

Story 结构:

import { /* Mantine components */ } from '@mantine/core';
// Import the component or recreate the relevant JSX

// Mock data that represents realistic API responses
const mockData = [ ... ];

// Render the component with different states
function Preview({ data }) {
  return (
    <div style={{ width: 320 }}> {/* Constrain to realistic width */}
      <MyComponent data={data} />
    </div>
  );
}

/** Default state */
export const Default = () => <Preview data={mockData} />;

/** Empty state */
export const Empty = () => <Preview data={[]} />;

/** Loading or edge case states */
export const LongList = () => <Preview data={longMockData} />;

重要模式:

  • 为包装元素设置一个符合实际情况的 width(例如,侧边栏设为 320px,主要内容设为 600px)
  • 从真实组件复制 Mantine 组件的确切 props 和 Tailwind 类
  • 从父级上下文复制所有内联 styles props(例如 Accordion 样式)
  • 如果组件使用 useComputedColorScheme 和 useMantineTheme,也要使用它们
  • 创建 2-4 个变体来展示不同状态(默认、空、单个项目、溢出)
2. 启动 Ladle
# Check if Ladle is already running
curl -s -o /dev/null -w "%{http_code}" http://localhost:61111/

# If not running, start it (from project root or worktree root)
cd <worktree-path>
npx ladle serve --port 61111 &
# Wait for it to be ready (~3-5 seconds)

Ladle 会自动发现符合 src/**/*.stories.tsx 的 story。

3. 捕获屏幕截图

使用浏览器自动化技能捕获裁剪并留有边距的屏幕截图:

# Create a browser session
node ~/.claude/skills/browser-automation/cli.mjs session http://localhost:61111 --name ladle

# Capture all story variants in dark and light themes
node ~/.claude/skills/browser-automation/cli.mjs run "
  const stories = [
    { name: 'default', path: 'my-component--default' },
    { name: 'empty', path: 'my-component--empty' },
  ];
  const themes = ['dark', 'light'];
  const dir = '<session-screenshots-dir>';

  for (const theme of themes) {
    for (const story of stories) {
      await page.goto('http://localhost:61111/?story=' + story.path + '&theme=' + theme + '&mode=preview');
      await page.waitForTimeout(800);
      const wrapper = page.locator('.ladle-story-wrapper');
      await wrapper.screenshot({ path: dir + '/crop-' + theme + '-' + story.name + '.png' });
    }
  }
" --label "Component preview screenshots" -s ladle

Story 路径格式: Story 路径根据文件名和导出名称生成:

  • 文件:EligibleModels.stories.tsx,导出:Default -> 路径:eligible-models--default
  • 文件:ModelCard.stories.tsx,导出:WithBadge -> 路径:model-card--with-badge

模式:kebab-case 文件名 + -- + kebab-case 导出名称。

4. 呈现给用户
  1. 使用 PNG 文件上的 Read 工具内嵌显示屏幕截图
  2. 如果用户想用图像查看器查看,请打开文件:
    start "" "<path-to-screenshot>"
    
  3. 征求反馈 — “这样看起来对吗?需要我做什么调整吗?”
  4. 迭代 — 如果用户希望修改,则修改组件、重新截图并再次呈现

处理复杂组件

有些组件严重依赖应用上下文。遇到这种情况时:

简单(直接处理)
  • 展示型组件(徽章、卡片、列表、折叠面板)
  • 仅使用 Mantine + Tailwind 的组件
  • props 简单的组件
中等(模拟数据)
  • 使用 tRPC 数据的组件 — 提取类型并创建模拟对象
  • 包含图片的组件 — 使用占位 div 或 null 图片回退
  • 包含链接的组件 — 使用 <div> 或 <a href="#"> 替代 Next.js <Link>
困难(请用户决定)
  • 与多个 provider(身份验证、路由器、tRPC 上下文)深度耦合的组件
  • 使用会调用 API 的复杂钩子的组件
  • 严重依赖 CSS 模块的组件

遇到困难的情况时,告诉用户:

“这个组件依赖 [auth/router/tRPC context]。我可以:

  1. 模拟这些依赖(需要更多设置,但更准确)
  2. 只提取视觉部分放入 story(更快,效果也足够接近)
  3. 跳过预览,我们可以改在开发服务器上检查

你希望怎么做?”

设置参考

如果工作树中尚未配置 Ladle,请创建以下文件:

.ladle/components.tsx
import { MantineProvider, createTheme, Modal } from '@mantine/core';
import type { GlobalProvider } from '@ladle/react';

import '@mantine/core/styles.layer.css';
import '../src/styles/globals.css';

// Theme subset from src/providers/ThemeProvider.tsx
const theme = createTheme({
  components: {
    Badge: {
      styles: { leftSection: { lineHeight: 1 } },
      defaultProps: { radius: 'sm', variant: 'light' },
    },
    ActionIcon: {
      defaultProps: { color: 'gray', variant: 'subtle' },
    },
    Tooltip: {
      defaultProps: { withArrow: true },
    },
  },
  colors: {
    dark: ['#C1C2C5','#A6A7AB','#8c8fa3','#5C5F66','#373A40','#2C2E33','#25262B','#1A1B1E','#141517','#101113'],
    blue: ['#E7F5FF','#D0EBFF','#A5D8FF','#74C0FC','#4DABF7','#339AF0','#228BE6','#1C7ED6','#1971C2','#1864AB'],
  },
  white: '#fefefe',
  black: '#222',
});

export const Provider: GlobalProvider = ({ children, globalState }) => (
  <MantineProvider
    theme={theme}
    defaultColorScheme={globalState.theme === 'dark' ? 'dark' : 'light'}
    forceColorScheme={globalState.theme === 'dark' ? 'dark' : 'light'}
  >
    <div className="ladle-story-wrapper" style={{ padding: 24, width: 'fit-content' }}>
      {children}
    </div>
  </MantineProvider>
);
.ladle/config.mjs
/** @type {import('@ladle/react').UserConfig} */
export default {
  stories: 'src/**/*.stories.tsx',
  defaultStory: '',
  viteConfig: '.ladle/vite.config.ts',
};
.ladle/vite.config.ts
import { defineConfig } from 'vite';
import path from 'path';

export default defineConfig({
  resolve: {
    alias: { '~': path.resolve(__dirname, '../src') },
  },
  css: {
    postcss: path.resolve(__dirname, '..'),
  },
});
确保已安装 Ladle
pnpm add -D @ladle/react

提示

  • 优先使用深色主题 — Civitai 默认使用深色模式,因此先截取深色主题
  • 限制宽度 — 始终设置与实际场景匹配的宽度(侧边栏 = ~320px,主内容 = ~600px,整页 = ~1200px)
  • 复制父级样式 — 如果组件位于 Accordion、Card 或其他容器内,请在 story 中复现这些父级样式
  • 保持 story 临时性 — 一次性评审的 story 之后可以删除;可复用组件的 story 可以保留
  • Ladle 端口 — 始终使用 61111,以避免与开发服务器 (3000) 和其他服务冲突

评论

支持 Markdown