banatie-service/apps/landing/src/components/shared/EXPANDED_IMAGE_VIEW.md

4.7 KiB
Raw Blame History

ExpandedImageView Component

Displays full-size images in modal overlays with loading, error, and success states.

Features

  • Loading State: Purple spinner with descriptive text
  • Error State: Clear error message with retry button
  • Success State: Smooth fade-in transition
  • Optional Metadata: Display filename, dimensions, and file size
  • Responsive Padding: Adapts to mobile, tablet, and desktop
  • Accessibility: ARIA live regions, semantic roles, keyboard support

Props

interface ExpandedImageViewProps {
  imageUrl: string;           // Required: Image URL to display
  alt?: string;               // Optional: Alt text (default: 'Full size view')
  metadata?: {                // Optional: Image metadata
    filename?: string;        // e.g., 'sunset_1024x768.png'
    size?: string;            // e.g., '2.4 MB'
    dimensions?: string;      // e.g., '1024 × 768'
  };
  showMetadata?: boolean;     // Optional: Show metadata bar (default: false)
}

Usage Examples

Basic Usage

import { ExpandedImageView } from '@/components/shared/ExpandedImageView';

export default function ImageModal({ imageUrl }: { imageUrl: string }) {
  return (
    <div className="fixed inset-0 bg-black/90 z-50">
      <ExpandedImageView
        imageUrl={imageUrl}
        alt="Generated landscape image"
      />
    </div>
  );
}

With Metadata

import { ExpandedImageView } from '@/components/shared/ExpandedImageView';

export default function ImageGalleryModal({ image }: { image: Image }) {
  return (
    <div className="fixed inset-0 bg-black/90 z-50">
      <ExpandedImageView
        imageUrl={image.url}
        alt={image.prompt}
        showMetadata
        metadata={{
          filename: image.filename,
          dimensions: `${image.width} × ${image.height}`,
          size: formatFileSize(image.sizeBytes)
        }}
      />
    </div>
  );
}

In Page Provider System

'use client';

import { useState } from 'react';
import { ExpandedImageView } from '@/components/shared/ExpandedImageView';
import { CompactFooter } from '@/components/shared/CompactFooter';

export default function ImageViewerPage() {
  const [selectedImage, setSelectedImage] = useState<string | null>(null);

  return (
    <>
      {/* Gallery */}
      <div className="grid grid-cols-3 gap-4 p-6">
        {images.map((img) => (
          <img
            key={img.id}
            src={img.thumbnail}
            onClick={() => setSelectedImage(img.fullUrl)}
            className="cursor-pointer hover:opacity-80"
          />
        ))}
      </div>

      {/* Overlay */}
      {selectedImage && (
        <div
          className="fixed inset-0 bg-black/90 z-50 flex flex-col"
          onClick={() => setSelectedImage(null)}
        >
          <nav className="h-16 border-b border-white/10">
            <button onClick={() => setSelectedImage(null)}>Close</button>
          </nav>

          <main className="flex-1 overflow-auto">
            <ExpandedImageView
              imageUrl={selectedImage}
              alt="Expanded gallery image"
              showMetadata
            />
          </main>

          <CompactFooter />
        </div>
      )}
    </>
  );
}

Accessibility Features

ARIA Roles

  • Loading State: role="status" with aria-live="polite"
  • Error State: role="alert" with aria-live="assertive"
  • Icon Elements: aria-hidden="true" (decorative only)

Keyboard Support

  • Retry button is keyboard accessible (Enter/Space)
  • Image click event stops propagation (prevents modal close)
  • Integrates with modal close handlers (Escape key)

Visual Design

  • Loading: Purple spinner (border-purple-600) matches Banatie design
  • Error: Red color scheme (red-900/20, red-700/50, red-400)
  • Image: Shadow (shadow-2xl) and rounded corners (rounded-lg)
  • Metadata: Subtle bar with Banatie card styling

Layout Constraints

  • Max Image Height: calc(100vh - 12rem) reserves space for nav/footer
  • Object Fit: object-contain maintains aspect ratio
  • Responsive Padding: p-4 sm:p-6 md:p-8
  • Metadata Wrapping: Flexbox with flex-wrap for mobile

Performance

  • Lazy State Management: Only renders visible state (loading/error/success)
  • Event Handlers: Optimized with direct callbacks
  • Image Loading: Native browser lazy loading via onLoad/onError
  • Transition: CSS-only fade animation (no JavaScript)

Error Handling

  • Network Failures: Catches onerror events
  • User Retry: Resets state and triggers re-render
  • Clear Messaging: Friendly error text with actionable button
  • Visual Feedback: Icon and color coding for quick recognition