Use Cases

Claude Code के साथ an Image Gallery Build करना

Claude Code का उपयोग करके building an image gallery सीखें। Practical code examples शामिल हैं।

画像ギャラリーको Claude Code सेbuildする

画像ギャラリーはポートフォリオ、ECサイト、写真共有アプリ आदि、多くの場面でज़रूरीになるcomponent है।Claude Code का उपयोग करके、マソンリーlayout、lightボックス、遅延読み込みを備えた高品質なギャラリーをefficientlybuild किया जा सकता है。

ギャラリーの要件を指示する

> 画像ギャラリーcomponentを作って。
> マソンリーlayout、lightボックスdisplay、
> 遅延読み込み、カテゴリフィルタリングをimplement करो。
> responsivesupportで。

マソンリーlayout

// src/components/MasonryGallery.tsx
'use client';
import { useState, useMemo } from 'react';

interface GalleryImage {
  id: string;
  src: string;
  alt: string;
  width: number;
  height: number;
  category: string;
}

interface Props {
  images: GalleryImage[];
  columns?: number;
}

export function MasonryGallery({ images, columns = 3 }: Props) {
  const [selectedCategory, setSelectedCategory] = useState<string | null>(null);
  const [lightboxIndex, setLightboxIndex] = useState<number | null>(null);

  const categories = useMemo(
    () => [...new Set(images.map((img) => img.category))],
    [images]
  );

  const filteredImages = useMemo(
    () => selectedCategory
      ? images.filter((img) => img.category === selectedCategory)
      : images,
    [images, selectedCategory]
  );

  // columnに画像を分配
  const columnImages = useMemo(() => {
    const cols: GalleryImage[][] = Array.from({ length: columns }, () => []);
    filteredImages.forEach((img, i) => {
      cols[i % columns].push(img);
    });
    return cols;
  }, [filteredImages, columns]);

  return (
    <div>
      {/* カテゴリfilter */}
      <div className="flex gap-2 mb-6 flex-wrap">
        <button
          onClick={() => setSelectedCategory(null)}
          className={`px-4 py-2 rounded-full text-sm ${
            !selectedCategory ? 'bg-blue-600 text-white' : 'bg-gray-100 dark:bg-gray-800'
          }`}
        >
          सभी
        </button>
        {categories.map((cat) => (
          <button
            key={cat}
            onClick={() => setSelectedCategory(cat)}
            className={`px-4 py-2 rounded-full text-sm ${
              selectedCategory === cat ? 'bg-blue-600 text-white' : 'bg-gray-100 dark:bg-gray-800 dark:text-gray-300'
            }`}
          >
            {cat}
          </button>
        ))}
      </div>

      {/* マソンリーgrid */}
      <div className="flex gap-4">
        {columnImages.map((col, colIndex) => (
          <div key={colIndex} className="flex-1 flex flex-col gap-4">
            {col.map((img) => (
              <div
                key={img.id}
                onClick={() => setLightboxIndex(filteredImages.indexOf(img))}
                className="cursor-pointer overflow-hidden rounded-lg hover:opacity-90 transition"
              >
                <img
                  src={img.src}
                  alt={img.alt}
                  loading="lazy"
                  className="w-full h-auto"
                  style={{ aspectRatio: `${img.width}/${img.height}` }}
                />
              </div>
            ))}
          </div>
        ))}
      </div>

      {/* lightボックス */}
      {lightboxIndex !== null && (
        <Lightbox
          images={filteredImages}
          currentIndex={lightboxIndex}
          onClose={() => setLightboxIndex(null)}
          onNavigate={setLightboxIndex}
        />
      )}
    </div>
  );
}

lightボックスcomponent

// src/components/Lightbox.tsx
'use client';
import { useEffect, useCallback } from 'react';

interface Props {
  images: GalleryImage[];
  currentIndex: number;
  onClose: () => void;
  onNavigate: (index: number) => void;
}

export function Lightbox({ images, currentIndex, onClose, onNavigate }: Props) {
  const current = images[currentIndex];

  const handleKeyDown = useCallback((e: KeyboardEvent) => {
    switch (e.key) {
      case 'Escape':
        onClose();
        break;
      case 'ArrowLeft':
        if (currentIndex > 0) onNavigate(currentIndex - 1);
        break;
      case 'ArrowRight':
        if (currentIndex < images.length - 1) onNavigate(currentIndex + 1);
        break;
    }
  }, [currentIndex, images.length, onClose, onNavigate]);

  useEffect(() => {
    document.addEventListener('keydown', handleKeyDown);
    document.body.style.overflow = 'hidden';
    return () => {
      document.removeEventListener('keydown', handleKeyDown);
      document.body.style.overflow = '';
    };
  }, [handleKeyDown]);

  return (
    <div
      className="fixed inset-0 bg-black/90 z-50 flex items-center justify-center"
      onClick={onClose}
    >
      <button onClick={onClose} className="absolute top-4 right-4 text-white text-3xl z-10">
        &times;
      </button>

      {currentIndex > 0 && (
        <button
          onClick={(e) => { e.stopPropagation(); onNavigate(currentIndex - 1); }}
          className="absolute left-4 text-white text-4xl hover:text-gray-300"
        >
          &#8249;
        </button>
      )}

      <img
        src={current.src}
        alt={current.alt}
        className="max-h-[90vh] max-w-[90vw] object-contain"
        onClick={(e) => e.stopPropagation()}
      />

      {currentIndex < images.length - 1 && (
        <button
          onClick={(e) => { e.stopPropagation(); onNavigate(currentIndex + 1); }}
          className="absolute right-4 text-white text-4xl hover:text-gray-300"
        >
          &#8250;
        </button>
      )}

      <div className="absolute bottom-4 text-white text-sm">
        {currentIndex + 1} / {images.length}
      </div>
    </div>
  );
}

performanceoptimization

画像のperformanceを高めるके लिए、निम्नलिखितのポイントをClaude Codeにaddで依頼 करें।

  • srcset属性: デバイス幅に応じた画像sizeの提供
  • BlurHash: 読み込みमेंのプレースホルダーdisplay
  • WebP/AVIF: अगला世代formatの自動変換
  • CDN配信: CloudflareやCloudFrontでのcache

関連記事

画像processing全般は画像processingのimplementation、performanceoptimizationはperformanceoptimizationガイドभी reference के लिए देखें。

画像optimizationにはCloudinary(cloudinary.com)の तरहなserviceのutilizationも検討するとよい होगा।

#Claude Code #画像ギャラリー #React #responsive #performance