- Created comprehensive test suite for cache.ts covering:
- set() and get() operations with various data types
- TTL expiration logic (default, custom, and edge cases)
- has() method for checking key existence
- delete() method for removing individual keys
- clear() method for removing all keys
- Expiration boundary testing
- Different TTL values for different items
- TTL reset when items are overwritten
- Fixed vitest.config.ts to include src/utils/** tests
- Fixed tsconfig.json to include src/utils/** files
- Used vi.useFakeTimers() for deterministic time-based testing
- All tests properly isolated with beforeEach/afterEach hooks
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Ran npm run build successfully with exit code 0
- Next.js build verified after deletion of components-vite and pages-vite
- No build errors or missing module warnings
- Application builds correctly with cleaned up codebase
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Added 'Missing Scripts' section to scripts/README.md
- Documented generate-blog-images.mjs (referenced in package.json but not implemented)
- Included package.json references, description, recommended actions, and impact
- Suggests either removing references or implementing the script with OpenAI API
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Added comprehensive Content Workflows section to CONTRIBUTING.md
- Documented how to add portfolio projects with TypeScript data structure example
- Documented how to add blog posts using MDX format
- Documented i18n workflow for translations with JSON structure
- Added file location conventions for all locales (de, en, sr)
- Included step-by-step instructions and best practices
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
All automated verification steps completed successfully:
- TypeScript compilation: PASSED (npx tsc --noEmit)
- ESLint verification: PASSED (npm run lint)
- Build verification: PASSED (npm run build)
Implementation verified:
- throttle utility function created with proper TypeScript types
- usePageVisibility hook using Page Visibility API
- useIntersectionObserver hook with configurable options
- GlobalBackground animations conditionally render based on visibility
- Header scroll handler throttled to 100ms intervals
All acceptance criteria met:
✓ Animations pause when tab is inactive
✓ Animations pause when scrolled offscreen
✓ Animations resume when visible again
✓ Scroll handler throttled to ~100ms
✓ No console errors or warnings
✓ No regression in existing functionality
✓ Build succeeds without errors
✓ Linting passes
Verification report created with manual testing instructions.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Add next-intl internationalization support
- Use translation keys from pages.notfound (title, description, backHome)
- Change button from blue to white/zinc design system colors
- Link to default locale homepage
- Convert component to async for getTranslations
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Added Skeleton base component using zinc-700/50 and animate-pulse
- Created SkillsSkeleton with two-column grid layout
- Left column: 8 progress bar skeletons with labels and percentages
- Right column: 2x3 grid of card skeletons matching icon layout
- Replaced loading state with SkillsSkeleton component
- Added 2s delay to useEffect for easier skeleton visibility during testing
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Added focusedIndex state to track keyboard focus
- Enhanced handleKeyDown to support ArrowDown, ArrowUp, Enter, and Escape keys
- Added visual focus indicator with orange ring (ring-2 ring-orange-500)
- Implemented aria-activedescendant for screen reader support
- Added unique IDs to language options for accessibility
- Reset focusedIndex when dropdown opens/closes
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>