Document compact info card design approach
This commit is contained in:
324
docs/COMPACT_CARDS.md
Normal file
324
docs/COMPACT_CARDS.md
Normal file
@@ -0,0 +1,324 @@
|
|||||||
|
# Compact Info Card Design
|
||||||
|
|
||||||
|
## Problem Statement
|
||||||
|
|
||||||
|
The original design used large square photo grids that consumed excessive screen space, making it difficult to scan through multiple dogs quickly. Photos were displayed at 1:1 aspect ratio taking up 50-100% of card width.
|
||||||
|
|
||||||
|
## Solution: Horizontal Info Cards
|
||||||
|
|
||||||
|
Transformed to a **compact horizontal card layout** with small avatar photos and prominent metadata, optimized for information scanning and list navigation.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Design Specifications
|
||||||
|
|
||||||
|
### Layout Structure
|
||||||
|
```
|
||||||
|
┌─────────────────────────────────────────────────────────────────┐
|
||||||
|
│ [Avatar] Name ♂ Breed • Age • Color → │
|
||||||
|
│ 80x80 Golden Retriever #REG-12345 │
|
||||||
|
└─────────────────────────────────────────────────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
### Card Components
|
||||||
|
|
||||||
|
#### 1. Avatar Photo (80x80px)
|
||||||
|
- **Size:** Fixed 80px × 80px
|
||||||
|
- **Shape:** Rounded corners (var(--radius))
|
||||||
|
- **Border:** 2px solid var(--border)
|
||||||
|
- **Background:** var(--bg-primary) when no photo
|
||||||
|
- **Fallback:** Dog icon at 32px, muted color
|
||||||
|
- **Object Fit:** cover (crops to fill square)
|
||||||
|
|
||||||
|
#### 2. Info Section (Flex: 1)
|
||||||
|
- **Name:** 1.125rem, bold, truncate with ellipsis
|
||||||
|
- **Sex Icon:** Colored ♂/♀ (blue for male, pink for female)
|
||||||
|
- **Metadata Row:**
|
||||||
|
- Breed name
|
||||||
|
- Age (calculated, with calendar icon)
|
||||||
|
- Color (if available)
|
||||||
|
- Separated by bullets (•)
|
||||||
|
- **Registration Badge:**
|
||||||
|
- Monospace font
|
||||||
|
- Hash icon prefix
|
||||||
|
- Dark background pill
|
||||||
|
- 1px border
|
||||||
|
|
||||||
|
#### 3. Arrow Indicator
|
||||||
|
- **Icon:** ArrowRight at 20px
|
||||||
|
- **Color:** var(--text-muted)
|
||||||
|
- **Opacity:** 0.5 default, increases on hover
|
||||||
|
- **Purpose:** Visual affordance for clickability
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Space Comparison
|
||||||
|
|
||||||
|
### Before (Square Grid)
|
||||||
|
```
|
||||||
|
[===============]
|
||||||
|
[ Photo ]
|
||||||
|
[ 300x300 ]
|
||||||
|
[===============]
|
||||||
|
Name
|
||||||
|
Breed • Sex
|
||||||
|
```
|
||||||
|
**Height:** ~380px per card
|
||||||
|
**Width:** 280-300px
|
||||||
|
**Photos per viewport:** 2-3 (desktop)
|
||||||
|
|
||||||
|
### After (Horizontal Card)
|
||||||
|
```
|
||||||
|
[Avatar] Name, Breed, Age, Badge →
|
||||||
|
80x80
|
||||||
|
```
|
||||||
|
**Height:** ~100px per card
|
||||||
|
**Width:** Full container width
|
||||||
|
**Cards per viewport:** 6-8 (desktop)
|
||||||
|
|
||||||
|
### Metrics
|
||||||
|
| Metric | Before | After | Improvement |
|
||||||
|
|--------|--------|-------|-------------|
|
||||||
|
| Card height | 380px | 100px | **-74%** |
|
||||||
|
| Photo area | 90,000px² | 6,400px² | **-93%** |
|
||||||
|
| Scannable info | 2-3 cards | 6-8 cards | **+200%** |
|
||||||
|
| Scroll distance | 760px | 200px | **-74%** |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Implementation Details
|
||||||
|
|
||||||
|
### React Component Structure
|
||||||
|
```jsx
|
||||||
|
<Link to={`/dogs/${dog.id}`} className="card">
|
||||||
|
{/* Avatar */}
|
||||||
|
<div className="avatar-80">
|
||||||
|
{photo ? <img src={photo} /> : <Dog icon />}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Info */}
|
||||||
|
<div className="info-section">
|
||||||
|
<h3>{name} <span>{sex icon}</span></h3>
|
||||||
|
<div className="metadata">
|
||||||
|
{breed} • {age} • {color}
|
||||||
|
</div>
|
||||||
|
<div className="badge">
|
||||||
|
<Hash /> {registration}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Arrow */}
|
||||||
|
<ArrowRight />
|
||||||
|
</Link>
|
||||||
|
```
|
||||||
|
|
||||||
|
### CSS Styling
|
||||||
|
```css
|
||||||
|
.card {
|
||||||
|
display: flex;
|
||||||
|
gap: 1rem;
|
||||||
|
align-items: center;
|
||||||
|
padding: 1rem;
|
||||||
|
transition: all 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card:hover {
|
||||||
|
border-color: var(--primary);
|
||||||
|
transform: translateY(-2px);
|
||||||
|
box-shadow: 0 8px 16px rgba(0,0,0,0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.avatar-80 {
|
||||||
|
width: 80px;
|
||||||
|
height: 80px;
|
||||||
|
border-radius: var(--radius);
|
||||||
|
border: 2px solid var(--border);
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.info-section {
|
||||||
|
flex: 1;
|
||||||
|
min-width: 0; /* Allow text truncation */
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Age Calculation
|
||||||
|
|
||||||
|
Dynamic age display from birth date:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const calculateAge = (birthDate) => {
|
||||||
|
const today = new Date()
|
||||||
|
const birth = new Date(birthDate)
|
||||||
|
let years = today.getFullYear() - birth.getFullYear()
|
||||||
|
let months = today.getMonth() - birth.getMonth()
|
||||||
|
|
||||||
|
if (months < 0) {
|
||||||
|
years--
|
||||||
|
months += 12
|
||||||
|
}
|
||||||
|
|
||||||
|
// Format: "2y 3mo" or "8mo" or "3y"
|
||||||
|
if (years === 0) return `${months}mo`
|
||||||
|
if (months === 0) return `${years}y`
|
||||||
|
return `${years}y ${months}mo`
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Interactive States
|
||||||
|
|
||||||
|
### Default
|
||||||
|
- Border: var(--border)
|
||||||
|
- Shadow: var(--shadow-sm)
|
||||||
|
- Transform: none
|
||||||
|
|
||||||
|
### Hover
|
||||||
|
- Border: var(--primary)
|
||||||
|
- Shadow: 0 8px 16px rgba(0,0,0,0.3)
|
||||||
|
- Transform: translateY(-2px)
|
||||||
|
- Arrow opacity: 1.0
|
||||||
|
- Transition: 0.2s cubic-bezier
|
||||||
|
|
||||||
|
### Active/Click
|
||||||
|
- Navigate to detail page
|
||||||
|
- Maintains selection state in history
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Responsive Behavior
|
||||||
|
|
||||||
|
### Desktop (>768px)
|
||||||
|
- Full horizontal layout
|
||||||
|
- All metadata visible
|
||||||
|
- Hover effects enabled
|
||||||
|
|
||||||
|
### Tablet (768px - 1024px)
|
||||||
|
- Slightly smaller avatar (70px)
|
||||||
|
- Abbreviated metadata
|
||||||
|
- Touch-friendly spacing
|
||||||
|
|
||||||
|
### Mobile (<768px)
|
||||||
|
- Avatar: 60px
|
||||||
|
- Name on top line
|
||||||
|
- Metadata stacks below
|
||||||
|
- Registration badge wraps
|
||||||
|
- Larger tap targets
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Accessibility
|
||||||
|
|
||||||
|
### Keyboard Navigation
|
||||||
|
- Cards are focusable links
|
||||||
|
- Tab order follows visual order
|
||||||
|
- Enter/Space to activate
|
||||||
|
- Focus ring with primary color
|
||||||
|
|
||||||
|
### Screen Readers
|
||||||
|
- Semantic HTML (Link + heading structure)
|
||||||
|
- Alt text on avatar images
|
||||||
|
- Icon meanings in aria-labels
|
||||||
|
- Registration formatted as code
|
||||||
|
|
||||||
|
### Color Contrast
|
||||||
|
- Name: High contrast (var(--text-primary))
|
||||||
|
- Metadata: Medium contrast (var(--text-secondary))
|
||||||
|
- Icons: Sufficient contrast ratios
|
||||||
|
- Sex icons: Color + symbol (not color-only)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Benefits
|
||||||
|
|
||||||
|
### User Experience
|
||||||
|
1. **Faster Scanning** - See 3x more dogs without scrolling
|
||||||
|
2. **Quick Comparison** - All key info visible at once
|
||||||
|
3. **Less Cognitive Load** - Consistent layout, predictable
|
||||||
|
4. **Better Navigation** - Clear visual hierarchy
|
||||||
|
|
||||||
|
### Performance
|
||||||
|
1. **Smaller Images** - Avatar size reduces bandwidth
|
||||||
|
2. **Lazy Loading** - Efficient with IntersectionObserver
|
||||||
|
3. **Less Rendering** - Simpler DOM structure
|
||||||
|
4. **Faster Scrolling** - Fewer pixels to paint
|
||||||
|
|
||||||
|
### Mobile
|
||||||
|
1. **Touch Targets** - Full card width clickable
|
||||||
|
2. **Vertical Real Estate** - More content on screen
|
||||||
|
3. **Thumb-Friendly** - No precise tapping required
|
||||||
|
4. **Data Efficient** - Smaller photo downloads
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Usage Context
|
||||||
|
|
||||||
|
### Dashboard
|
||||||
|
- Shows 6-8 recent dogs
|
||||||
|
- "View All" button to Dogs page
|
||||||
|
- Provides quick overview
|
||||||
|
|
||||||
|
### Dogs List
|
||||||
|
- Full searchable/filterable catalog
|
||||||
|
- Horizontal scroll on mobile
|
||||||
|
- Infinite scroll potential
|
||||||
|
- Batch operations possible
|
||||||
|
|
||||||
|
### NOT Used For
|
||||||
|
- Dog detail page (uses full photo gallery)
|
||||||
|
- Pedigree tree (uses compact nodes)
|
||||||
|
- Print layouts (uses different format)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Future Enhancements
|
||||||
|
|
||||||
|
### Planned
|
||||||
|
- [ ] Checkbox selection mode (bulk actions)
|
||||||
|
- [ ] Drag-to-reorder in custom lists
|
||||||
|
- [ ] Quick actions menu (edit, delete)
|
||||||
|
- [ ] Photo upload from card
|
||||||
|
- [ ] Inline editing of name/breed
|
||||||
|
|
||||||
|
### Considered
|
||||||
|
- Multi-select with Shift+Click
|
||||||
|
- Card density options (compact/comfortable/spacious)
|
||||||
|
- Alternative views (grid toggle)
|
||||||
|
- Column sorting (name, age, breed)
|
||||||
|
- Grouping (by breed, age range)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
### Example 1: Male with Photo
|
||||||
|
```
|
||||||
|
┌───────────────────────────────────────────────────────────┐
|
||||||
|
│ [Photo] Max ♂ → │
|
||||||
|
│ Golden Retriever • 2y 3mo • Golden │
|
||||||
|
│ #AKC-SR123456 │
|
||||||
|
└───────────────────────────────────────────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
### Example 2: Female No Photo
|
||||||
|
```
|
||||||
|
┌───────────────────────────────────────────────────────────┐
|
||||||
|
│ [🐶] Bella ♀ → │
|
||||||
|
│ icon Labrador Retriever • 8mo • Black │
|
||||||
|
└───────────────────────────────────────────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
### Example 3: Puppy No Registration
|
||||||
|
```
|
||||||
|
┌───────────────────────────────────────────────────────────┐
|
||||||
|
│ [Photo] Rocky ♂ → │
|
||||||
|
│ German Shepherd • 3mo │
|
||||||
|
└───────────────────────────────────────────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
*Last Updated: March 8, 2026*
|
||||||
Reference in New Issue
Block a user