← back to Wine Finder Next
COMPONENT_IMPROVEMENTS_QUICK_REF.md
433 lines
# Component Improvements Quick Reference
## Component Structure
### Main Page Component
**File:** `/app/membership/page.tsx`
```
MembershipPage
├── LoadingSkeleton (while loading)
├── JsonLd (SEO structured data)
├── Header (sticky, with info cards)
├── Navigation (4 tabs with keyboard support)
├── Content Tabs
│ ├── BottlesTab
│ ├── VotingTab
│ ├── MarketplaceTab
│ └── MyHoldingsTab
└── Footer (SEO info)
```
## Key Improvements by Component
### 1. LoadingSkeleton Component
**Location:** `/components/membership/LoadingSkeleton.tsx`
**Purpose:** Show realistic loading state
**Features:**
- Animated pulse effects
- Matches final layout
- Zero layout shift
- Improves perceived performance
**Usage:**
```tsx
if (loading) {
return <LoadingSkeleton />;
}
```
### 2. Header Component (Enhanced)
**Improvements:**
- Sticky positioning (`sticky top-0 z-50`)
- Better backdrop blur (`backdrop-blur-md`)
- Responsive padding (`px-4 sm:px-6 lg:px-8`)
- Slide-down animation on load
- Responsive info cards (1/2/3 columns)
**Key Classes:**
```css
.header {
@apply bg-black/30 backdrop-blur-md border-b border-white/10;
@apply sticky top-0 z-50;
@apply transition-all duration-300;
}
```
### 3. Navigation Tabs (Enhanced)
**Improvements:**
- Keyboard navigation support (Enter/Space)
- Focus indicators
- ARIA labels and current state
- Scale animation on active state
- Mobile-friendly icons
**Accessibility:**
```tsx
<button
aria-label="View bottles section"
aria-current={selectedTab === 'bottles' ? 'page' : undefined}
onKeyDown={(e) => {
if (e.key === 'Enter' || e.key === ' ') {
e.preventDefault();
setSelectedTab('bottles');
}
}}
className="focus:outline-none focus:ring-2 focus:ring-purple-400"
>
```
### 4. BottlesTab Component (Enhanced)
**Card Features:**
- Staggered entrance animations
- Hover scale effect
- Animated progress bars
- Semantic HTML (article, itemScope)
- Responsive grid (1/2/3 columns)
**Progress Bar:**
```tsx
<div
className="h-full bg-gradient-to-r from-purple-500 to-pink-500
transition-all duration-1000 ease-out"
style={{ width: `${fundingProgress}%` }}
role="progressbar"
aria-valuenow={fundingProgress}
aria-valuemin={0}
aria-valuemax={100}
aria-label={`${fundingProgress.toFixed(1)}% funded`}
/>
```
### 5. VotingTab Component (Enhanced)
**Features:**
- Enhanced progress bars with double borders
- Better contrast for accessibility
- Loading states during submission
- Fieldset/legend for vote choices
- Responsive stats grid (2/4 columns)
**Vote Interface:**
```tsx
{selectedVote === vote.id ? (
<div className="bg-black/20 p-4 rounded-lg space-y-3">
<input
id={`membership-id-${vote.id}`}
type="text"
style={{ fontSize: '16px' }} // Prevent iOS zoom
className="focus:ring-2 focus:ring-purple-400"
aria-required="true"
/>
<fieldset>
<legend className="sr-only">Choose your vote</legend>
{/* Vote choices */}
</fieldset>
</div>
) : (
<button>Cast Your Vote</button>
)}
```
### 6. MarketplaceTab Component (Enhanced)
**Features:**
- Loading state per listing
- Disabled states during purchase
- Staggered card animations
- Empty state message
**Purchase Button:**
```tsx
<button
onClick={() => handlePurchase(listing.id)}
disabled={isPurchasingThis}
className="transform hover:scale-105 disabled:opacity-50"
>
{isPurchasingThis ? 'Processing...' : 'Purchase Wine Share'}
</button>
```
### 7. MyHoldingsTab Component
**Features:**
- Centered layout
- Connect wallet CTA
- Responsive text sizing
## CSS Class Patterns
### Responsive Spacing
```css
/* Padding */
px-4 sm:px-6 lg:px-8
/* Gaps */
gap-3 sm:gap-4
/* Margins */
mb-4 sm:mb-6
```
### Responsive Typography
```css
/* Headers */
text-3xl sm:text-4xl
/* Body */
text-base sm:text-lg
/* Small */
text-xs sm:text-sm
```
### Responsive Grids
```css
/* Bottles */
grid-cols-1 md:grid-cols-2 lg:grid-cols-3
/* Stats */
grid-cols-2 lg:grid-cols-4
/* Marketplace */
grid-cols-1 md:grid-cols-2
```
### Animation Classes
```css
/* Entrance */
animate-fade-in
animate-slide-up
animate-slide-down
animate-scale-in
/* Loading */
animate-pulse
```
### Hover States
```css
/* Scale */
transform hover:scale-105
/* Shadow */
shadow-lg hover:shadow-xl
/* Background */
hover:bg-white/20
```
### Focus States
```css
focus:outline-none
focus:ring-2
focus:ring-purple-400
focus:ring-offset-2
focus:ring-offset-purple-900
```
## Accessibility Patterns
### ARIA Labels
```tsx
// Section labels
<section aria-label="Available wine bottles">
// Button labels
<button aria-label={`Buy shares of ${bottle.name}`}>
// Status indicators
<span role="status" aria-label={`Status: ${bottle.status}`}>
```
### Screen Reader Only
```tsx
<span className="sr-only">Membership Unit ID</span>
<label htmlFor="input-id" className="sr-only">
```
### Progress Indicators
```tsx
<div
role="progressbar"
aria-valuenow={percentage}
aria-valuemin={0}
aria-valuemax={100}
aria-label={`${percentage}% complete`}
/>
```
### Form Controls
```tsx
<input
id="unique-id"
aria-required="true"
aria-describedby="help-text"
/>
<fieldset>
<legend className="sr-only">Choose option</legend>
{/* Controls */}
</fieldset>
```
## Performance Patterns
### Memoization
```tsx
// Memoize expensive computations
const tabs = useMemo(() => [
{ id: 'bottles', label: 'Investment Bottles' },
// ...
], []);
// Memoize callbacks
const loadData = useCallback(async () => {
// ...
}, []);
```
### Parallel Fetching
```tsx
const [bottlesRes, votesRes, marketRes] = await Promise.all([
fetch('/api/membership/bottles'),
fetch('/api/membership/votes?active=true'),
fetch('/api/membership/marketplace?active=true')
]);
```
### Staggered Animations
```tsx
{bottles.map((bottle, index) => (
<article
style={{ animationDelay: `${index * 100}ms` }}
className="animate-scale-in"
>
))}
```
## Mobile Optimization
### iOS Input Fix
```tsx
<input
type="text"
style={{ fontSize: '16px' }} // Prevents auto-zoom
className="..."
/>
```
### Touch Targets
```css
/* Minimum 44px height for touch */
py-3 /* 0.75rem * 2 + line-height = ~44px */
```
### Flexible Layouts
```css
/* Flex direction changes */
flex-col sm:flex-row
/* Hide/show content */
hidden sm:block
sm:hidden
```
## Color Contrast
### Text on Dark Background
```css
text-white /* 21:1 - AAA */
text-gray-300 /* 11:1 - AAA */
text-gray-400 /* 8:1 - AA */
```
### Status Colors
```css
/* Success */
bg-green-500/20 text-green-300 border-green-500/50
/* Warning */
bg-yellow-500/20 text-yellow-300 border-yellow-500/50
/* Error */
bg-red-500/20 text-red-300 border-red-500/50
```
## Testing Commands
### Start Server
```bash
pm2 restart wine-finder-next
```
### View Logs
```bash
pm2 logs wine-finder-next
```
### Test Page
```bash
curl -I http://45.61.58.125:7250/membership
```
### Lighthouse Audit
```bash
npx lighthouse http://45.61.58.125:7250/membership --view
```
## Common Issues & Solutions
### Issue: iOS Auto-Zoom on Input
**Solution:** Set `fontSize: '16px'` inline style
### Issue: Layout Shift on Load
**Solution:** Use LoadingSkeleton with matching layout
### Issue: Poor Focus Visibility
**Solution:** Add `focus:ring-2 focus:ring-purple-400`
### Issue: Touch Targets Too Small
**Solution:** Minimum `py-3` padding (44px total)
### Issue: Animation Lag
**Solution:** Use `transform` and `opacity` only (GPU accelerated)
### Issue: Accessibility Warnings
**Solution:** Add proper ARIA labels and semantic HTML
## Browser Support
### Tested Browsers
- Chrome 120+ ✅
- Firefox 121+ ✅
- Safari 17+ ✅
- Edge 120+ ✅
- Mobile Safari (iOS 16+) ✅
- Chrome Mobile (Android 12+) ✅
### Polyfills Needed
- None (using modern Next.js features)
## Deployment Checklist
- [x] All components load without errors
- [x] Responsive design works on all breakpoints
- [x] Animations are smooth (60fps)
- [x] Accessibility features implemented
- [x] Loading skeleton prevents layout shift
- [x] Color contrast meets WCAG AA
- [x] Keyboard navigation works
- [x] Focus indicators visible
- [x] ARIA labels present
- [x] Mobile touch targets adequate
- [x] iOS input zoom prevented
- [ ] Images optimized (future)
- [ ] Performance metrics monitored
- [ ] Analytics integrated (future)