mcpField
C
component-preview

component-preview

github.com/civitaiデザイン・UI7.3k59 回インストール今日更新
リポジトリ

component-preview について

Component Preview は、Ladle を使って React コンポーネントを分離してプレビューするワークフローです。Mantine v7 と Tailwind のスタイルを使い、story 作成、ローカル表示、スクリーンショット撮影、反復確認を支援します。

主な機能

  1. 01React コンポーネントを分離してプレビュー
  2. 02状態ごとの Ladle story を作成
  3. 03Mantine v7 と Tailwind のスタイルで表示
  4. 04ライト・ダークテーマのスクリーンショット撮影
  5. 05見た目の変更を反復確認

活用シーン

  1. 01UI の変更後にコンポーネントを確認
  2. 02表示上の問題を再現して調査
  3. 03コミット前にコンポーネントの変更を確認

インストール

コマンドをコピーしてターミナルで実行します。

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

インストール後、Claude Code で/component-previewを入力して読み込まれたか確認します。

詳細

コンポーネントのプレビュー

Ladle(軽量な Storybook の代替ツール)を使い、Mantine v7 と Tailwind の実際のスタイルを適用して React コンポーネントを単独でプレビューします。開発サーバーは不要です。

使用するタイミング

  • UI コンポーネントを変更した後 — 積極的にプレビューを提案します
  • ユーザーが「どんな見た目か見せて」や「プレビューを生成して」と依頼したとき
  • 見た目の問題をデバッグするとき — 再現用のストーリーを作成して調整します
  • コミット前にコンポーネントの変更をレビューするとき

前提条件

Ladle はプロジェクトのルートに設定されています。

  • .ladle/components.tsx — MantineProvider とテーマを含むグローバルプロバイダー
  • .ladle/config.mjs — ストーリーの検出設定
  • .ladle/vite.config.ts — ~/ パスエイリアスと PostCSS を含む Vite の設定

現在の作業ツリーにこれらが存在しない場合は、main からコピーするか作成してください。詳細は下記のセットアップリファレンスを参照してください。

ワークフロー

1. ストーリーを作成/更新する

プレビューするコンポーネントの近くに .stories.tsx ファイルを作成します。

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

ストーリーの構成:

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 に一致するストーリーを自動検出します。

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

ストーリーパスの形式: ストーリーパスはファイル名とエクスポート名から決まります。

  • ファイル:EligibleModels.stories.tsx、エクスポート:Default -> パス:eligible-models--default
  • ファイル:ModelCard.stories.tsx、エクスポート:WithBadge -> パス:model-card--with-badge

パターン:ケバブケースのファイル名 + -- + ケバブケースのエクスポート名。

4. ユーザーに提示する
  1. PNG ファイルに対して Read ツールを使い、スクリーンショットをインラインで表示します
  2. 画像ビューアーで見たい場合は、ユーザー向けに開きます。
    start "" "<path-to-screenshot>"
    
  3. フィードバックを求めます — 「この見た目で問題ありませんか?何か調整しますか?」
  4. 反復します — 変更を希望された場合は、コンポーネントを変更し、再撮影して提示します

複雑なコンポーネントへの対応

コンポーネントによっては、アプリのコンテキストに大きく依存します。その場合は、次のように対応します。

簡単(そのまま実行)
  • 表示用コンポーネント(バッジ、カード、リスト、アコーディオン)
  • Mantine と Tailwind のみを使用するコンポーネント
  • props が単純なコンポーネント
中程度(データをモックする)
  • tRPC データを使用するコンポーネント — 型を取り出してモックオブジェクトを作成します
  • 画像を含むコンポーネント — プレースホルダーの div または null 画像のフォールバックを使います
  • リンクを含むコンポーネント — Next.js の <Link> の代わりに <div> または <a href="#"> を使います
難しい(ユーザーに相談)
  • 複数のプロバイダー(認証、ルーター、tRPC コンテキスト)と密接に結合したコンポーネント
  • API を呼び出す複雑なフックを使うコンポーネント
  • CSS モジュールへの依存が大きいコンポーネント

難しいケースに遭遇した場合は、ユーザーに次のように伝えます。

「このコンポーネントは[認証/ルーター/tRPC コンテキスト]に依存しています。次のいずれかで対応できます。

  1. 依存関係をモックする(セットアップに手間がかかりますが、より正確です)
  2. 表示部分だけをストーリーに切り出す(より手早く、十分近い見た目になります)
  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、その他のコンテナー内にある場合は、ストーリー内で親のスタイルを再現します
  • ストーリーは一時的なものにする — 単発のレビュー用ストーリーはレビュー後に削除できます。再利用可能なコンポーネントのストーリーは残せます
  • Ladle のポート — 開発サーバー(3000)やその他のサービスとの競合を避けるため、必ず61111を使用します

コメント