Skip to main content
VisionaryAI’s image gallery provides a beautiful, responsive interface for viewing all your DALL-E 3 generated images. The gallery automatically updates when new images are created and displays them in reverse chronological order. The gallery uses a responsive grid that adapts to your screen size:
1 column layout on small screens
  • Full-width images for easy viewing
  • Vertical scrolling through your collection
components/Images.tsx
<div className="grid gap-4 grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 px-0 md:px-10">
  {images?.imageUrls?.map((image: ImageType, num: Number) => (
    // Image cards...
  ))}
</div>
The gallery automatically adjusts its layout using Tailwind CSS responsive breakpoints, ensuring optimal viewing on any device.
The most recent image (first in the gallery) receives special treatment:
  • Double size: Spans 2 columns and 2 rows on medium+ screens
  • Prominent display: Makes your latest creation stand out
  • Auto-refresh: Updates automatically when you generate new images
components/Images.tsx
<div
  className={`relative cursor-help 
    ${num === 0 && "md:col-span-2 md:row-span-2"}
    hover:scale-[104%] transition transform duration-300 ease-in-out
  `}
>
The featured image position makes it easy to quickly check your most recent generation without scrolling.

Interactive image cards

Each image card includes interactive features for a better viewing experience:

Hover effects

When you hover over an image:
1

Scale animation

The image scales up to 104% of its original size with smooth animation.
2

Prompt overlay

A white overlay fades in (80% opacity) displaying the prompt used to generate the image.
3

Prompt text

The original prompt appears centered on the overlay in a light, readable font.
components/Images.tsx
<div className="absolute flex justify-center items-center w-full h-full bg-white opacity-0 hover:opacity-80 transition-opacity duration-200 z-10">
  <p className="text-center font-light text-lg p-5">
    {image.name.split("_").shift()?.toString().split(".").shift()}
  </p>
</div>
The prompt text is extracted from the image filename, which follows the pattern: prompt_timestamp.png

Smooth transitions

All gallery interactions use CSS transitions:
  • Scale: 300ms ease-in-out for smooth enlargement
  • Opacity: 200ms transition for overlay fade
  • Transform: GPU-accelerated for smooth performance

Refresh functionality

The gallery includes a floating refresh button for manual updates:

Button location

  • Fixed position at bottom-right of the screen
  • Floats above all content (z-index: 20)
  • Always accessible regardless of scroll position
components/Images.tsx
<button
  onClick={() => refreshImages(images)}
  className="fixed bottom-10 right-10 bg-violet-400/90 text-white px-5 py-3 rounded-md hover:bg-violet-500 focus:outline-none focus:ring-2 font-bold z-20"
>
  {!isLoading && isValidating ? "Refreshing..." : "Refresh Images"}
</button>

Button states

Displays “Refresh Images” in violet with 90% opacity background.
Shows “Refreshing…” while fetching updated image list from the server.
Background changes to solid violet on hover with smooth color transition.
The refresh button passes current images to the refresh function for optimistic UI updates, showing cached data while new data loads.

Automatic updates

The gallery automatically refreshes when you generate new images:
components/PromptInput.tsx
const { mutate: updateImages } = useSWR("images", fetchImages, {
  revalidateOnFocus: false,
});

const submitPrompt = async (useSuggestion?: boolean) => {
  // ... image generation logic ...
  
  updateImages(); // Automatically refresh gallery
};
SWR’s mutate function triggers a revalidation of the gallery data, ensuring new images appear without manual refresh.

Loading states

The gallery provides clear feedback during data fetching:

Initial load

When first loading the gallery:
Loading AI Generated Images...
This message appears centered above the gallery grid with:
  • Light font weight for subtle appearance
  • Violet “AI” text for brand consistency
  • Bottom padding to separate from images

Empty state

If no images exist yet, the grid simply remains empty. Users can generate their first image using the prompt input above.

Image sorting

Images are automatically sorted by timestamp in descending order (newest first):
azure/src/functions/getImages.js
const sortedImageUrls = imageUrls.sort((a, b) => {
  const aName = a.name.split("_").pop().toString().split(".").shift();
  const bName = b.name.split("_").pop().toString().split(".").shift();
  return bName - aName; 
})
This ensures:
  • Your latest creations always appear first
  • The featured image is always your most recent generation
  • Chronological browsing from new to old
Filenames include Unix timestamps, enabling precise chronological sorting even when multiple images are generated in quick succession.

Image data structure

Each image in the gallery includes:
components/Images.tsx
type ImageType = {
  name: string;  // Format: "prompt_timestamp.png"
  url: string;   // Full Azure Blob Storage URL with SAS token
};

URL structure

Image URLs follow this pattern:
https://{accountName}.blob.core.windows.net/{containerName}/{imageName}?{sasToken}
SAS (Shared Access Signature) tokens provide time-limited, secure access to images in Azure Blob Storage without exposing account keys.
The filename format prompt_timestamp.png allows extracting both the generation prompt and exact creation time from the filename alone.

Performance optimization

The gallery is optimized for fast loading and smooth interactions:

Image optimization

Next.js Image component provides:
components/Images.tsx
<Image
  unoptimized={true}
  src={image.url}
  alt={image.name}
  width={500}
  height={500}
  className="w-full rounded-sm shadow-2xl drop-shadow-lg z-10"
/>
  • unoptimized={true}: Images served directly from Azure Blob Storage
  • Consistent 500x500 dimensions for predictable layout
  • Shadow and drop-shadow for visual depth
Images are set to unoptimized because they’re already optimized by DALL-E 3 at 1024x1024 and served through Azure’s CDN.

SWR caching

Gallery data is cached using SWR:
components/Images.tsx
const {
  data: images,
  isLoading,
  mutate: refreshImages,
  isValidating,
} = useSWR("images", fetchImages, {
  revalidateOnFocus: false,
});
Benefits:
  • Instant display of cached images on page load
  • Background revalidation when manually triggered
  • Optimistic UI updates during refresh
  • Reduced API calls with revalidateOnFocus: false

Responsive design features

The gallery adapts to different screen sizes:
BreakpointColumnsPaddingFeatured
Mobile (< 768px)1None1x1
Tablet (768px+)22.5rem2x2
Desktop (1024px+)32.5rem2x2
Wide (1280px+)42.5rem2x2

Accessibility

The gallery includes accessibility features:
  • Alt text: Each image uses its filename as alt text
  • Keyboard navigation: All interactive elements are keyboard accessible
  • Focus states: Visible focus rings on buttons
  • Cursor hints: cursor-help indicates prompt overlay on hover
While alt text is provided, it uses the technical filename. For production use, consider storing more descriptive alt text with each image.

Next steps

Azure integration

Learn how images are stored and served through Azure

Image generation

Understand the image creation process

Build docs developers (and LLMs) love