feat: add animated components for enhanced UI/UX
- Introduced DrawLine component for drawing animations. - Added LazyRevealImage component for lazy loading images with reveal animations. - Implemented TextDiffuseReveal for animated text reveals with staggered effects. - Created TopProgressBar for a dynamic loading indicator. - Added PointCloud mock for testing animations. - Developed useReducedMotion hook to handle user preferences for reduced motion. - Centralized animation configurations in config.ts for easier management. - Defined animation variants in variants.ts for consistent animation effects. - Established AnimationProvider to supply global animation settings. - Created tests for AnimationProvider and useReducedMotion hook. - Added SVG assets for branding and UI elements. - Documented frontend review plan and hero circuit board animation plan.
This commit is contained in:
1 parent
0ab6930f92
commit
08dd046887
76 files changed
+21682
-1197
No files matched your search
@@ -0,0 +1,501 @@
|
||||
# Design Document: Site Improvements - Footer & Companies
|
||||
|
||||
## Overview
|
||||
|
||||
This design implements site-wide improvements including spacing standardization, a complete footer component with contact information and social links, an animated company logos banner with infinite scroll, and reorganization of the Experience section into Software/Hardware categories. The implementation maintains the existing minimalist design system using Monument Extended typography, #ccff00 accent color, and Framer Motion animations.
|
||||
|
||||
The design focuses on three main areas:
|
||||
1. **Spacing System Standardization**: Applying consistent spacing tokens across all sections
|
||||
2. **Footer Component**: A new footer with contact info, social links, and copyright
|
||||
3. **CompanyLogos Component**: An infinite-scroll animated banner displaying company logos
|
||||
4. **Experience Section Refactor**: Categorizing experiences into Software and Hardware groups
|
||||
|
||||
All components follow the established design system patterns from `globals.css` and integrate with the existing Framer Motion animation infrastructure.
|
||||
|
||||
## Architecture
|
||||
|
||||
### Component Structure
|
||||
|
||||
```
|
||||
app/
|
||||
├── components/
|
||||
│ ├── Footer.tsx (replace existing)
|
||||
│ ├── CompanyLogos.tsx (new)
|
||||
│ ├── Experience.tsx (refactor)
|
||||
│ └── Section.tsx (update spacing)
|
||||
├── page.tsx (update layout)
|
||||
└── globals.css (spacing documentation)
|
||||
```
|
||||
|
||||
### Data Flow
|
||||
|
||||
1. **Footer Component**: Static data (email, social links) defined as constants within the component
|
||||
2. **CompanyLogos Component**: Logo data (company names, image paths) defined as constants, rendered with animation
|
||||
3. **Experience Component**: Existing data from `usePortfolioData()` hook, filtered and categorized by type field
|
||||
|
||||
### Animation Strategy
|
||||
|
||||
All animations use Framer Motion with reduced motion support:
|
||||
- **CompanyLogos**: Continuous horizontal scroll using `animate` with infinite loop
|
||||
- **Footer**: Subtle hover states on social links
|
||||
- **Experience**: Existing stagger animations maintained, category headers added
|
||||
|
||||
## Components and Interfaces
|
||||
|
||||
### 1. Footer Component
|
||||
|
||||
**Purpose**: Display contact information, social links, and copyright in a consistent footer layout.
|
||||
|
||||
**Props**: None (self-contained component)
|
||||
|
||||
**Structure**:
|
||||
```tsx
|
||||
interface SocialLink {
|
||||
name: string;
|
||||
href: string;
|
||||
icon: string; // SVG path or icon identifier
|
||||
ariaLabel: string;
|
||||
}
|
||||
|
||||
const socialLinks: SocialLink[] = [
|
||||
{ name: 'GitHub', href: 'https://github.com/...', icon: '...', ariaLabel: 'Visit GitHub profile' },
|
||||
{ name: 'LinkedIn', href: 'https://linkedin.com/...', icon: '...', ariaLabel: 'Visit LinkedIn profile' },
|
||||
// ... more links
|
||||
];
|
||||
```
|
||||
|
||||
**Layout**:
|
||||
- Desktop: Three-column grid (contact info | social links | copyright)
|
||||
- Tablet: Two-column grid (contact/social | copyright)
|
||||
- Mobile: Single column stack
|
||||
|
||||
**Styling**:
|
||||
- Background: `var(--ink)` with `border-t: 1px solid rgba(255,255,255,0.06)`
|
||||
- Typography: Monument Extended for headings, Geist Mono for body text
|
||||
- Accent: `var(--slash)` for link hover states
|
||||
- Padding: `py-sp-12 px-sp-16` (desktop), `py-sp-8 px-sp-6` (mobile)
|
||||
|
||||
### 2. CompanyLogos Component
|
||||
|
||||
**Purpose**: Display an infinite-scrolling banner of company logos after the header.
|
||||
|
||||
**Props**: None (self-contained component)
|
||||
|
||||
**Structure**:
|
||||
```tsx
|
||||
interface CompanyLogo {
|
||||
name: string;
|
||||
imagePath: string;
|
||||
alt: string;
|
||||
}
|
||||
|
||||
const companies: CompanyLogo[] = [
|
||||
{ name: 'Apolo Energia', imagePath: '/logos/apolo.svg', alt: 'Apolo Energia logo' },
|
||||
{ name: 'Julia Beauty Lashes', imagePath: '/logos/julia.svg', alt: 'Julia Beauty Lashes logo' },
|
||||
{ name: 'Innovo', imagePath: '/logos/innovo.svg', alt: 'Innovo logo' },
|
||||
{ name: 'TeraByteShop', imagePath: '/logos/terabyte.svg', alt: 'TeraByteShop logo' },
|
||||
{ name: 'Pichau', imagePath: '/logos/pichau.svg', alt: 'Pichau logo' },
|
||||
];
|
||||
```
|
||||
|
||||
**Animation Implementation**:
|
||||
```tsx
|
||||
// Duplicate logo array for seamless loop
|
||||
const duplicatedLogos = [...companies, ...companies];
|
||||
|
||||
// Framer Motion animation
|
||||
<motion.div
|
||||
animate={{
|
||||
x: [0, -50%], // Move by half the width (one set of logos)
|
||||
}}
|
||||
transition={{
|
||||
duration: 30, // 30 seconds for full loop
|
||||
repeat: Infinity,
|
||||
ease: "linear",
|
||||
}}
|
||||
>
|
||||
{duplicatedLogos.map((logo, index) => (
|
||||
<img key={`${logo.name}-${index}`} src={logo.imagePath} alt={logo.alt} />
|
||||
))}
|
||||
</motion.div>
|
||||
```
|
||||
|
||||
**Reduced Motion Handling**:
|
||||
```tsx
|
||||
const shouldReduceMotion = useReducedMotion();
|
||||
|
||||
// If reduced motion, display static grid instead of animation
|
||||
{shouldReduceMotion ? (
|
||||
<div className="grid grid-cols-5 gap-sp-6">
|
||||
{companies.map(logo => <img key={logo.name} ... />)}
|
||||
</div>
|
||||
) : (
|
||||
<motion.div animate={...} />
|
||||
)}
|
||||
```
|
||||
|
||||
**Styling**:
|
||||
- Container: `overflow-hidden` with `border-b: 1px solid var(--border)`
|
||||
- Background: `var(--paper)` with optional subtle grid pattern
|
||||
- Logo sizing: `h-12` (48px) with `grayscale` filter, `grayscale-0` on hover
|
||||
- Spacing: `py-sp-8` vertical padding, `gap-sp-12` between logos
|
||||
|
||||
### 3. Experience Component Refactor
|
||||
|
||||
**Purpose**: Organize experience entries into Software and Hardware categories.
|
||||
|
||||
**Changes**:
|
||||
1. Add category filtering logic
|
||||
2. Render two separate sections with category headers
|
||||
3. Maintain existing card structure and animations
|
||||
|
||||
**Implementation**:
|
||||
```tsx
|
||||
const softwareExperiences = sortedExperiences.filter(exp => exp.type === 'Software');
|
||||
const hardwareExperiences = sortedExperiences.filter(exp => exp.type === 'Hardware');
|
||||
|
||||
return (
|
||||
<Section id="experience" ...>
|
||||
{/* Software Category */}
|
||||
<div className="mb-sp-12">
|
||||
<h3 className="font-display text-2xl font-bold mb-sp-6 flex items-center gap-sp-3">
|
||||
<span className="text-[var(--slash)]">/</span> Software
|
||||
</h3>
|
||||
<motion.div variants={listVariants}>
|
||||
{softwareExperiences.map(exp => <ExperienceCard key={exp.id} {...exp} />)}
|
||||
</motion.div>
|
||||
</div>
|
||||
|
||||
{/* Hardware Category */}
|
||||
<div>
|
||||
<h3 className="font-display text-2xl font-bold mb-sp-6 flex items-center gap-sp-3">
|
||||
<span className="text-[var(--slash)]">/</span> Hardware
|
||||
</h3>
|
||||
<motion.div variants={listVariants}>
|
||||
{hardwareExperiences.map(exp => <ExperienceCard key={exp.id} {...exp} />)}
|
||||
</motion.div>
|
||||
</div>
|
||||
</Section>
|
||||
);
|
||||
```
|
||||
|
||||
**Styling**:
|
||||
- Category headers: Monument Extended, `text-2xl`, with slash accent
|
||||
- Separator: `mb-sp-12` between categories
|
||||
- Cards: Maintain existing styling and animations
|
||||
|
||||
### 4. Spacing System Updates
|
||||
|
||||
**Standardization**:
|
||||
All sections should use consistent spacing tokens from `globals.css`:
|
||||
- Section padding: `py-sp-20 px-sp-16` (desktop), `py-sp-16 px-sp-6` (mobile)
|
||||
- Section margins: `mb-sp-12` between major sections
|
||||
- Card spacing: `space-y-sp-6` for vertical stacks
|
||||
- Grid gaps: `gap-sp-6` for 2-column, `gap-sp-4` for 4-column
|
||||
|
||||
**Responsive Scaling**:
|
||||
Tailwind responsive utilities handle breakpoints:
|
||||
- Mobile: `px-sp-6 py-sp-16`
|
||||
- Tablet: `px-sp-10 py-sp-18`
|
||||
- Desktop: `px-sp-16 py-sp-20`
|
||||
|
||||
## Data Models
|
||||
|
||||
### SocialLink
|
||||
```typescript
|
||||
interface SocialLink {
|
||||
name: string; // Display name (e.g., "GitHub")
|
||||
href: string; // Full URL
|
||||
icon: string; // SVG path or icon component reference
|
||||
ariaLabel: string; // Accessibility label
|
||||
}
|
||||
```
|
||||
|
||||
### CompanyLogo
|
||||
```typescript
|
||||
interface CompanyLogo {
|
||||
name: string; // Company name
|
||||
imagePath: string; // Path to logo image (SVG preferred)
|
||||
alt: string; // Alt text for accessibility
|
||||
}
|
||||
```
|
||||
|
||||
### Experience (existing, with type field)
|
||||
```typescript
|
||||
interface Experience {
|
||||
id: string;
|
||||
title: string;
|
||||
company: string;
|
||||
type: 'Software' | 'Hardware'; // Used for categorization
|
||||
period: string;
|
||||
location: string;
|
||||
description: string;
|
||||
achievements: string[];
|
||||
technologies: string[];
|
||||
featured: boolean;
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
## Correctness Properties
|
||||
|
||||
*A property is a characteristic or behavior that should hold true across all valid executions of a system—essentially, a formal statement about what the system should do. Properties serve as the bridge between human-readable specifications and machine-verifiable correctness guarantees.*
|
||||
|
||||
### Property 1: Consistent Spacing System
|
||||
|
||||
*For any* major section or container element in the site, it should use spacing tokens from the design system (sp-1 through sp-24) with appropriate responsive modifiers for different viewport sizes.
|
||||
|
||||
**Validates: Requirements 1.1, 1.2, 1.3, 1.4**
|
||||
|
||||
### Property 2: Social Links Open in New Tab
|
||||
|
||||
*For any* social media link in the Footer component, it should have `target="_blank"` and `rel="noopener noreferrer"` attributes to open in a new tab securely.
|
||||
|
||||
**Validates: Requirements 2.7**
|
||||
|
||||
### Property 3: Responsive Component Layout
|
||||
|
||||
*For any* new component (Footer, CompanyLogos, Experience categories), it should include Tailwind responsive utility classes (sm:, md:, lg:) to adapt layout across viewport sizes.
|
||||
|
||||
**Validates: Requirements 2.6, 3.7, 4.5**
|
||||
|
||||
### Property 4: Reduced Motion Respect
|
||||
|
||||
*For any* animated component, when `useReducedMotion()` returns true, the component should render a static alternative without motion animations.
|
||||
|
||||
**Validates: Requirements 3.6, 6.3**
|
||||
|
||||
### Property 5: Experience Categorization
|
||||
|
||||
*For any* experience entry in the Experience section, it should be filtered by its `type` field and rendered within the corresponding Software or Hardware category group.
|
||||
|
||||
**Validates: Requirements 4.1**
|
||||
|
||||
### Property 6: Chronological Ordering Within Categories
|
||||
|
||||
*For any* category group in the Experience section, the experience entries within that group should be sorted in descending chronological order by year.
|
||||
|
||||
**Validates: Requirements 4.3**
|
||||
|
||||
### Property 7: Monument Extended Typography
|
||||
|
||||
*For any* heading element (h1, h2, h3) in new components (Footer, CompanyLogos, Experience categories), it should use the `font-display` class which applies Monument Extended font family.
|
||||
|
||||
**Validates: Requirements 2.4, 4.2, 5.4**
|
||||
|
||||
### Property 8: Slash Color Accents
|
||||
|
||||
*For any* accent element (category separators, hover states, decorative elements) in new components, it should use `var(--slash)` color (#ccff00) via Tailwind classes like `text-[var(--slash)]` or `bg-[var(--slash)]`.
|
||||
|
||||
**Validates: Requirements 5.1, 5.2**
|
||||
|
||||
### Property 9: ARIA Labels for Links
|
||||
|
||||
*For any* social media link in the Footer component, it should have a descriptive `aria-label` attribute that identifies the platform and action.
|
||||
|
||||
**Validates: Requirements 6.1**
|
||||
|
||||
### Property 10: Alt Text for Images
|
||||
|
||||
*For any* company logo image in the CompanyLogos component, it should have a non-empty `alt` attribute describing the company.
|
||||
|
||||
**Validates: Requirements 6.2**
|
||||
|
||||
### Property 11: Semantic Heading Hierarchy
|
||||
|
||||
*For any* sequence of heading elements in the Experience section, the heading levels should follow proper semantic hierarchy (h2 for section title, h3 for categories, no skipped levels).
|
||||
|
||||
**Validates: Requirements 6.4**
|
||||
|
||||
### Property 12: Keyboard Navigation Support
|
||||
|
||||
*For any* interactive element (links, buttons) in new components, it should be keyboard accessible with proper focus states and no negative tabindex values.
|
||||
|
||||
**Validates: Requirements 6.5**
|
||||
|
||||
## Error Handling
|
||||
|
||||
### Footer Component
|
||||
|
||||
**Missing Social Links Data**:
|
||||
- Gracefully render empty state or hide social links section
|
||||
- Log warning to console in development mode
|
||||
- Ensure layout doesn't break with missing data
|
||||
|
||||
**Invalid Email Format**:
|
||||
- Display email as-is (validation is not the footer's responsibility)
|
||||
- Ensure mailto: link is properly formatted
|
||||
|
||||
### CompanyLogos Component
|
||||
|
||||
**Missing Logo Images**:
|
||||
- Display company name as fallback text
|
||||
- Log warning for missing images in development
|
||||
- Maintain layout spacing even with missing images
|
||||
|
||||
**Animation Performance Issues**:
|
||||
- Monitor frame rate using `useAnimationFrame` hook
|
||||
- Fallback to static display if performance drops below threshold
|
||||
- Respect `prefers-reduced-motion` preference
|
||||
|
||||
### Experience Component
|
||||
|
||||
**Missing Type Field**:
|
||||
- Default to "Software" category if type is undefined
|
||||
- Log warning for entries without type field
|
||||
- Ensure all entries are displayed (don't silently drop data)
|
||||
|
||||
**Empty Categories**:
|
||||
- Hide category header if no entries exist for that type
|
||||
- Maintain spacing consistency when categories are hidden
|
||||
|
||||
### General Error Handling
|
||||
|
||||
**Component Render Errors**:
|
||||
- Wrap components in Error Boundaries
|
||||
- Display user-friendly error message
|
||||
- Log detailed error information for debugging
|
||||
|
||||
**Responsive Layout Issues**:
|
||||
- Use CSS fallbacks for unsupported features
|
||||
- Test across major browsers and devices
|
||||
- Ensure content remains accessible even if styling fails
|
||||
|
||||
## Testing Strategy
|
||||
|
||||
### Dual Testing Approach
|
||||
|
||||
This feature requires both unit tests and property-based tests to ensure comprehensive coverage:
|
||||
|
||||
**Unit Tests**: Focus on specific examples, edge cases, and integration points
|
||||
- Specific component rendering scenarios
|
||||
- Edge cases (empty data, missing fields)
|
||||
- User interaction flows (clicking links, reduced motion)
|
||||
- Integration between components
|
||||
|
||||
**Property-Based Tests**: Verify universal properties across all inputs
|
||||
- Spacing consistency across generated component trees
|
||||
- Accessibility attributes across generated link/image sets
|
||||
- Categorization logic across generated experience data
|
||||
- Responsive class application across generated components
|
||||
|
||||
### Testing Framework
|
||||
|
||||
**Framework**: Vitest + React Testing Library + fast-check
|
||||
- Vitest for test runner and assertions
|
||||
- React Testing Library for component testing
|
||||
- fast-check for property-based testing (TypeScript-native)
|
||||
|
||||
**Property Test Configuration**:
|
||||
- Minimum 100 iterations per property test
|
||||
- Each test tagged with: `Feature: site-improvements-footer-companies, Property {number}: {property_text}`
|
||||
- Use custom generators for component props and data structures
|
||||
|
||||
### Unit Test Coverage
|
||||
|
||||
**Footer Component**:
|
||||
- Renders contact information correctly
|
||||
- Renders all social links with correct attributes
|
||||
- Displays current year in copyright
|
||||
- Opens social links in new tab
|
||||
- Applies correct styling classes
|
||||
- Responsive layout changes at breakpoints
|
||||
|
||||
**CompanyLogos Component**:
|
||||
- Renders all five company logos
|
||||
- Duplicates logo array for infinite scroll
|
||||
- Applies animation with correct configuration
|
||||
- Displays static grid when reduced motion is enabled
|
||||
- Handles missing logo images gracefully
|
||||
- Maintains responsive layout
|
||||
|
||||
**Experience Component**:
|
||||
- Filters experiences by Software/Hardware type
|
||||
- Renders category headers with correct styling
|
||||
- Maintains chronological order within categories
|
||||
- Hides empty categories
|
||||
- Applies consistent spacing between categories
|
||||
- Responsive layout on mobile devices
|
||||
|
||||
### Property-Based Test Coverage
|
||||
|
||||
**Property 1: Consistent Spacing System**
|
||||
- Generate random component trees with various nesting levels
|
||||
- Verify all spacing classes use design system tokens
|
||||
- Check responsive modifiers are present
|
||||
|
||||
**Property 2: Social Links Open in New Tab**
|
||||
- Generate random arrays of social links
|
||||
- Verify each link has target="_blank" and rel="noopener noreferrer"
|
||||
|
||||
**Property 3: Responsive Component Layout**
|
||||
- Generate random component configurations
|
||||
- Verify presence of responsive utility classes
|
||||
|
||||
**Property 4: Reduced Motion Respect**
|
||||
- Generate random animation configurations
|
||||
- Verify static rendering when reduced motion is true
|
||||
|
||||
**Property 5: Experience Categorization**
|
||||
- Generate random experience arrays with mixed types
|
||||
- Verify correct filtering and grouping by type
|
||||
|
||||
**Property 6: Chronological Ordering Within Categories**
|
||||
- Generate random experience arrays with various dates
|
||||
- Verify descending chronological order within each category
|
||||
|
||||
**Property 7: Monument Extended Typography**
|
||||
- Generate random heading elements
|
||||
- Verify font-display class is applied
|
||||
|
||||
**Property 8: Slash Color Accents**
|
||||
- Generate random accent elements
|
||||
- Verify var(--slash) color usage
|
||||
|
||||
**Property 9: ARIA Labels for Links**
|
||||
- Generate random social link arrays
|
||||
- Verify each has descriptive aria-label
|
||||
|
||||
**Property 10: Alt Text for Images**
|
||||
- Generate random logo arrays
|
||||
- Verify each image has non-empty alt text
|
||||
|
||||
**Property 11: Semantic Heading Hierarchy**
|
||||
- Generate random heading sequences
|
||||
- Verify proper h2 → h3 hierarchy without skips
|
||||
|
||||
**Property 12: Keyboard Navigation Support**
|
||||
- Generate random interactive elements
|
||||
- Verify focusability and proper tabindex values
|
||||
|
||||
### Integration Testing
|
||||
|
||||
**Page Layout Integration**:
|
||||
- Verify CompanyLogos appears after Header
|
||||
- Verify Footer appears at bottom of page
|
||||
- Verify spacing between all sections is consistent
|
||||
- Test full page scroll behavior
|
||||
|
||||
**Animation Performance**:
|
||||
- Monitor CompanyLogos animation frame rate
|
||||
- Verify smooth scrolling across devices
|
||||
- Test reduced motion fallback behavior
|
||||
|
||||
**Accessibility Testing**:
|
||||
- Run axe-core automated accessibility tests
|
||||
- Verify keyboard navigation through all components
|
||||
- Test screen reader compatibility
|
||||
- Verify color contrast ratios meet WCAG AA standards
|
||||
|
||||
### Visual Regression Testing
|
||||
|
||||
**Snapshot Tests**:
|
||||
- Footer component in all responsive states
|
||||
- CompanyLogos with animation and static states
|
||||
- Experience section with both categories populated
|
||||
- Experience section with one empty category
|
||||
|
||||
**Cross-Browser Testing**:
|
||||
- Chrome, Firefox, Safari, Edge
|
||||
- Mobile browsers (iOS Safari, Chrome Mobile)
|
||||
- Verify consistent rendering and animation performance
|
||||
Reference in new issue
Block a user