This document defines the user interface design for OptiView - a high-performance image gallery application. The UI prioritizes visual content, fast loading, and intuitive interactions.
| Principle | Description |
|---|---|
| Content-First | Images are the hero; UI elements should be minimal and non-intrusive |
| Performance-Visible | Loading states (LQIP, dominant color) enhance perceived speed |
| Responsive | Adapts seamlessly from mobile to desktop |
| Accessible | Keyboard navigation, proper contrast, screen reader support |
| Route | Description |
|---|---|
/ |
Main gallery with filters and grid |
/upload |
Full-page upload interface |
Location: Fixed at top of viewport
Elements:
- Logo (left)
- Genre filter dropdown
- Rating filter dropdown
- Sort dropdown (Date/Rating + ASC/DESC)
┌─────────────────────────────────────────────────────────────────┐
│ [Logo] OptiView [Genre ▼] [Min Rating ▼] [Sort by ▼] │
└─────────────────────────────────────────────────────────────────┘
Behavior:
- Filters update URL query parameters
- Gallery reloads via TanStack Query when filters change
- Sticky on scroll
Layout: CSS Grid or CSS Columns-based masonry
Responsive Columns:
| Viewport Width | Columns |
|---|---|
| < 640px (Mobile) | 2 |
| 640px - 1024px (Tablet) | 3 |
| > 1024px (Desktop) | 4 |
Image Card Structure:
┌────────────────────┐
│ │
│ │ ← Aspect ratio preserved
│ [Image] │ ← LQIP blur while loading
│ │ ← Dominant color background
│ │
├────────────────────┤
│ ★★★★☆ Nature │ ← Interactive rating stars + Genre tag
└────────────────────┘
Rating Interaction:
- Stars are clickable - any user can change the rating
- Hover shows preview of potential rating
- Click on star N sets rating to N
- Optimistic UI update - reverts on API error
Loading Sequence per Card:
- Immediate: Container renders with aspect-ratio (prevents CLS)
- Immediate: Dominant color fills the image area
- ~100ms: LQIP (blurred 20px preview) appears
- Final: Full-resolution image fades in, blur transitions to sharp
Location: Fixed, bottom-right corner
Style:
- Circular button, 56px diameter
- Plus icon (+)
- Elevated shadow
- Secondary color from theme
Behavior:
- Click navigates to
/uploadroute - Subtle hover/focus animation
Trigger: Click on any image card
Layout:
┌─────────────────────────────────────────────────────────────────┐
│ [X] │
│ │
│ [<] [>] │
│ │
│ ┌─────────────────┐ │
│ │ │ │
│ │ Full Image │ │
│ │ │ │
│ │ (centered) │ │
│ │ │ │
│ └─────────────────┘ │
│ │
│ ★★★★☆ Nature │
│ │
│ [Download 1920px] [Download 1280px] [Download 640px] │
│ │
└─────────────────────────────────────────────────────────────────┘
Elements:
- Dark semi-transparent overlay (rgba(0,0,0,0.9))
- Close button (X) - top right
- Navigation arrows (< / >) - sides or bottom
- Image centered, max 90vh height
- Rating stars - interactive, below image
- Genre tag - displayed next to rating
- Download buttons below image
Download Options:
- Provide 2-3 size options (e.g., 1920px, 1280px, 640px)
- Format: Use same format negotiation as gallery (AVIF/WebP/JPEG)
Interactions:
- Click outside image closes modal
- ESC key closes modal
- Arrow keys navigate between images
- Swipe gestures on mobile
Route: /upload
Layout:
┌─────────────────────────────────────────────────────────────────┐
│ [← Back to Gallery] │
├─────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ │ │
│ │ 📁 Drag & Drop Images Here │ │
│ │ or click to browse │ │
│ │ │ │
│ │ Supports: JPEG, PNG, WebP │ │
│ │ Max file size: 10MB │ │
│ │ │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
│ Upload Queue: │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ photo1.jpg [Genre: Nature ▼] ████████ 100% ✅ Done │ │
│ │ photo2.jpg [Genre: Architect▼] ████░░░░ 60% ⏳ Upload │ │
│ │ photo3.jpg [Genre: Uncategoriz] ░░░░░░░░ 0% ⏸ Wait │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
│ [Upload More] │
│ │
└─────────────────────────────────────────────────────────────────┘
Features:
- Full-page dropzone
- Multiple file selection supported
- File type validation (JPEG, PNG, WebP only)
- File size validation (max 10MB per file)
- Genre selection per image - dropdown for each file in the queue
- Progress bar per file
- Status indicators: Waiting / Uploading / Processing / Done / Error
- Auto-navigate to gallery after all uploads complete (optional)
Genre Selection:
| Aspect | Description |
|---|---|
| Available Genres | Nature, Architecture, Portrait, Uncategorized |
| Adding new genres | A user can add his/her own new genre |
| Selection Timing | Genre must be selected before or during upload |
| Default Value | Uncategorized |
| Immutability | Genre can only be set at upload time and cannot be changed later |
Default Values for New Uploads:
| Field | Default Value |
|---|---|
| Genre | Uncategorized |
| Rating | 3 (of 5) |
Purpose: Reusable component for displaying and editing image ratings.
Props:
| Prop | Type | Default | Description |
|---|---|---|---|
| rating | number | required | Current rating value 1-5 |
| readonly | boolean | false | If true stars are display only |
| size | sm / md / lg | md | Star size variant |
| onChange | function - rating: void | undefined | Callback when rating changes |
Size Variants:
| Variant | Star Size | Use Case |
|---|---|---|
| sm | 16px | Image card in gallery |
| md | 20px | Lightbox - default |
| lg | 24px | Lightbox - enhanced visibility |
Visual States:
| State | Filled Star | Empty Star |
|---|---|---|
| Default | ★ solid | ☆ outline |
| Hover | ★ highlighted with gold color | ☆ outline |
| Active | ★ highlighted | ☆ outline |
Interaction Behavior:
- Mouse hover over star N highlights all stars from 1 to N
- Click on star N calls onChange with value N
- Visual feedback: slight scale animation on hover 1.1x
- After successful API update: brief success flash optional
Accessibility:
- Each star is a button with aria-label
- aria-valuenow / aria-valuemax for screen readers
- Keyboard: Tab to focus / Enter or Space to select
| Breakpoint | Width | Columns | Header |
|---|---|---|---|
| Mobile | < 640px | 2 | Stacked filters |
| Tablet | 640px - 1024px | 3 | Inline filters |
| Desktop | > 1024px | 4 | Inline filters |
- Show skeleton placeholders with correct aspect ratios
- Or show empty grid structure with dominant color backgrounds
flowchart LR
A[Container with aspect-ratio] --> B[Dominant Color Fill]
B --> C[LQIP Blur Appears]
C --> D[Full Image Loads]
D --> E[Crossfade Transition]
CSS Implementation Reference:
.image-container {
position: relative;
background-color: var(--dominant-color); /* From API */
aspect-ratio: var(--aspect-ratio); /* From API */
}
.image-placeholder {
position: absolute;
inset: 0;
background-image: url(var(--lqip-base64));
background-size: cover;
filter: blur(20px);
transform: scale(1.1);
transition: opacity 0.3s ease;
}
.image-full {
opacity: 0;
transition: opacity 0.3s ease;
}
.image-full.loaded {
opacity: 1;
}
.image-full.loaded + .image-placeholder {
opacity: 0;
}| Requirement | Implementation |
|---|---|
| Keyboard Navigation | Tab through images, Enter to open lightbox |
| Focus Management | Focus trap in lightbox, return focus on close |
| Alt Text | Use filename or future caption field |
| Contrast | Minimum 4.5:1 for text on backgrounds |
| Touch Targets | Minimum 44x44px for interactive elements |
| Role | Color | Usage |
|---|---|---|
| Primary | #2563EB | Focus rings, active states |
| Background | #FAFAFA | Page background |
| Surface | #FFFFFF | Cards, header |
| Text Primary | #1F2937 | Body text |
| Text Secondary | #6B7280 | Metadata, captions |
| Border | #E5E7EB | Dividers, card borders |
| Overlay | rgba(0,0,0,0.9) | Lightbox background |
| Success | #10B981 | Upload success |
| Error | #EF4444 | Upload error |
| Element | Animation | Duration |
|---|---|---|
| Image load transition | Crossfade | 300ms |
| LQIP blur removal | Fade out | 300ms |
| Modal open/close | Fade + scale | 200ms |
| Card hover | Subtle lift | 150ms |
| FAB hover | Scale 1.05 | 150ms |
- Image editing after upload
- User profiles / authentication
- Image collections / albums
- Social sharing features
- Comments system
For design inspiration and interaction patterns:
- Unsplash (https://unsplash.com) - Masonry layout, LQIP technique
- Pexels (https://pexels.com) - Filter UI, download options
- Pinterest (https://pinterest.com) - Masonry grid behavior