ImageGallery molecule + wire into VenueDetailStep and CoffinDetailsStep

New ImageGallery molecule:
- Hero display area with thumbnail strip below
- Hover thumbnail to preview in hero, click to lock selection
- First image selected by default, brand border on active thumb
- Keyboard accessible (Enter/Space to select)
- Single image mode (no thumbnails), horizontal scroll for many
- Stories: Default, SingleImage, TwoImages, CustomSizes

VenueDetailStep + CoffinDetailsStep:
- Replaced static hero Box with ImageGallery component
- Added optional images[] field to VenueDetail and CoffinProfile types
- Falls back to single imageUrl when images not provided

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-30 21:05:58 +11:00
parent 82231ee124
commit 3f21964bb7
6 changed files with 285 additions and 28 deletions

View File

@@ -2,6 +2,8 @@ import React from 'react';
import Box from '@mui/material/Box';
import type { SxProps, Theme } from '@mui/material/styles';
import { WizardLayout } from '../../templates/WizardLayout';
import { ImageGallery } from '../../molecules/ImageGallery';
import type { GalleryImage } from '../../molecules/ImageGallery';
import { Typography } from '../../atoms/Typography';
import { Button } from '../../atoms/Button';
@@ -17,6 +19,8 @@ export interface CoffinSpec {
export interface CoffinProfile {
name: string;
imageUrl: string;
/** Additional gallery images (if provided, imageUrl becomes the first) */
images?: GalleryImage[];
description?: string;
specs?: CoffinSpec[];
price: number;
@@ -163,20 +167,15 @@ export const CoffinDetailsStep: React.FC<CoffinDetailsStepProps> = ({
</Box>
}
>
{/* Left panel: image + description */}
<Box
role="img"
aria-label={`Photo of ${coffin.name}`}
sx={{
width: '100%',
height: { xs: 280, md: 400 },
borderRadius: 2,
backgroundImage: `url(${coffin.imageUrl})`,
backgroundSize: 'cover',
backgroundPosition: 'center',
backgroundColor: 'var(--fa-color-surface-subtle)',
mb: 3,
}}
{/* Left panel: image gallery + description */}
<ImageGallery
images={
coffin.images && coffin.images.length > 0
? coffin.images
: [{ src: coffin.imageUrl, alt: `Photo of ${coffin.name}` }]
}
heroHeight={{ xs: 280, md: 400 }}
sx={{ mb: 3 }}
/>
{coffin.description && (

View File

@@ -37,6 +37,24 @@ const sampleVenue: VenueDetail = {
id: 'west-chapel',
name: 'West Chapel',
imageUrl: 'https://images.unsplash.com/photo-1555396273-367ea4eb4db5?w=800&h=600&fit=crop',
images: [
{
src: 'https://images.unsplash.com/photo-1555396273-367ea4eb4db5?w=800&h=600&fit=crop',
alt: 'Chapel interior',
},
{
src: 'https://images.unsplash.com/photo-1464366400600-7168b8af9bc3?w=800&h=600&fit=crop',
alt: 'Garden area',
},
{
src: 'https://images.unsplash.com/photo-1519167758481-83f550bb49b3?w=800&h=600&fit=crop',
alt: 'Reception hall',
},
{
src: 'https://images.unsplash.com/photo-1507003211169-0a1dd7228f2d?w=800&h=600&fit=crop',
alt: 'Lakeside pavilion',
},
],
location: 'Strathfield',
venueType: 'Indoor Chapel',
capacity: 120,

View File

@@ -6,6 +6,8 @@ import PeopleOutlinedIcon from '@mui/icons-material/PeopleOutlined';
import CheckCircleOutlineIcon from '@mui/icons-material/CheckCircleOutline';
import type { SxProps, Theme } from '@mui/material/styles';
import { WizardLayout } from '../../templates/WizardLayout';
import { ImageGallery } from '../../molecules/ImageGallery';
import type { GalleryImage } from '../../molecules/ImageGallery';
import { Card } from '../../atoms/Card';
import { Chip } from '../../atoms/Chip';
import { Typography } from '../../atoms/Typography';
@@ -19,6 +21,8 @@ export interface VenueDetail {
id: string;
name: string;
imageUrl: string;
/** Additional gallery images (if provided, imageUrl becomes the first) */
images?: GalleryImage[];
location: string;
venueType?: string;
capacity?: number;
@@ -221,20 +225,15 @@ export const VenueDetailStep: React.FC<VenueDetailStepProps> = ({
>
{/* ═══════ LEFT PANEL: scrollable content ═══════ */}
{/* ─── Hero image ─── */}
<Box
role="img"
aria-label={`Photo of ${venue.name}`}
sx={{
width: '100%',
height: { xs: 280, md: 420 },
borderRadius: 2,
backgroundImage: `url(${venue.imageUrl})`,
backgroundSize: 'cover',
backgroundPosition: 'center',
backgroundColor: 'var(--fa-color-surface-subtle)',
mb: 3,
}}
{/* ─── Image gallery ─── */}
<ImageGallery
images={
venue.images && venue.images.length > 0
? venue.images
: [{ src: venue.imageUrl, alt: `Photo of ${venue.name}` }]
}
heroHeight={{ xs: 280, md: 420 }}
sx={{ mb: 3 }}
/>
{/* ─── Description ─── */}