/** * Responsive Testing Utilities for KLZ Cables * Tools for testing and validating responsive design */ import { BREAKPOINTS, getViewport, Viewport } from './responsive'; // Test viewport configurations export const TEST_VIEWPORTS = { mobile: { width: 375, height: 667, name: 'Mobile (iPhone SE)', breakpoint: 'xs', }, mobileLarge: { width: 414, height: 896, name: 'Mobile Large (iPhone 11)', breakpoint: 'sm', }, tablet: { width: 768, height: 1024, name: 'Tablet (iPad)', breakpoint: 'md', }, tabletLandscape: { width: 1024, height: 768, name: 'Tablet Landscape', breakpoint: 'lg', }, desktop: { width: 1280, height: 800, name: 'Desktop (Laptop)', breakpoint: 'xl', }, desktopLarge: { width: 1440, height: 900, name: 'Desktop Large', breakpoint: '2xl', }, desktopWide: { width: 1920, height: 1080, name: 'Desktop Wide (Full HD)', breakpoint: '3xl', }, }; /** * Responsive Design Checklist * Comprehensive checklist for validating responsive design */ export const RESPONSIVE_CHECKLIST = { layout: [ 'Content stacks properly on mobile (1 column)', 'Grid layouts adapt to screen size (2-4 columns)', 'No horizontal scrolling at any breakpoint', 'Content remains within safe areas', 'Padding and margins scale appropriately', ], typography: [ 'Text remains readable at all sizes', 'Line height is optimized for mobile', 'Headings scale appropriately', 'No text overflow or clipping', 'Font size meets WCAG guidelines (16px minimum)', ], navigation: [ 'Mobile menu is accessible (44px touch targets)', 'Desktop navigation hides on mobile', 'Menu items are properly spaced', 'Active states are visible', 'Back/forward navigation works', ], images: [ 'Images load with appropriate sizes', 'Aspect ratios are maintained', 'No layout shift during loading', 'Lazy loading works correctly', 'Placeholder blur is applied', ], forms: [ 'Input fields are 44px minimum touch target', 'Labels remain visible', 'Error messages are readable', 'Form submits on mobile', 'Keyboard navigation works', ], performance: [ 'Images are properly sized for viewport', 'No unnecessary large assets on mobile', 'Critical CSS is loaded', 'Touch interactions are smooth', 'No layout thrashing', ], accessibility: [ 'Touch targets are 44px minimum', 'Focus indicators are visible', 'Screen readers work correctly', 'Color contrast meets WCAG AA', 'Zoom is not restricted', ], }; /** * Generate responsive design report */ export function generateResponsiveReport(): string { const viewport = getViewport(); const report = ` Responsive Design Report - KLZ Cables ===================================== Current Viewport: - Width: ${viewport.width}px - Height: ${viewport.height}px - Breakpoint: ${viewport.breakpoint} - Device Type: ${viewport.isMobile ? 'Mobile' : viewport.isTablet ? 'Tablet' : 'Desktop'} Breakpoint Configuration: - xs: ${BREAKPOINTS.xs}px - sm: ${BREAKPOINTS.sm}px - md: ${BREAKPOINTS.md}px - lg: ${BREAKPOINTS.lg}px - xl: ${BREAKPOINTS.xl}px - 2xl: ${BREAKPOINTS['2xl']}px - 3xl: ${BREAKPOINTS['3xl']}px Touch Target Verification: - Minimum: 44px × 44px - Recommended: 48px × 48px - Large: 56px × 56px Image Optimization: - Mobile Quality: 75% - Tablet Quality: 85% - Desktop Quality: 90% Typography Scale: - Fluid typography using CSS clamp() - Mobile: 16px base - Desktop: 18px base - Line height: 1.4-1.6 Generated: ${new Date().toISOString()} `.trim(); return report; } /** * Validate responsive design rules */ export function validateResponsiveDesign(): { passed: boolean; warnings: string[]; errors: string[]; } { const warnings: string[] = []; const errors: string[] = []; // Check viewport if (typeof window === 'undefined') { warnings.push('Server-side rendering detected - some checks skipped'); } // Check minimum touch target size const buttons = document.querySelectorAll('button, a'); buttons.forEach((el) => { const rect = el.getBoundingClientRect(); if (rect.width < 44 || rect.height < 44) { warnings.push(`Element ${el.tagName} has touch target < 44px`); } }); // Check for horizontal scroll if (document.body.scrollWidth > window.innerWidth) { errors.push('Horizontal scrolling detected'); } // Check text size const textElements = document.querySelectorAll('p, span, div'); textElements.forEach((el) => { const computed = window.getComputedStyle(el); const fontSize = parseFloat(computed.fontSize); if (fontSize < 16 && el.textContent && el.textContent.length > 50) { warnings.push(`Text element ${el.tagName} has font-size < 16px`); } }); return { passed: errors.length === 0, warnings, errors, }; } /** * Responsive design utilities for testing */ export const ResponsiveTestUtils = { // Set viewport for testing setViewport: (width: number, height: number) => { if (typeof window !== 'undefined') { window.innerWidth = width; window.innerHeight = height; window.dispatchEvent(new Event('resize')); } }, // Simulate mobile viewport simulateMobile: () => { ResponsiveTestUtils.setViewport(375, 667); }, // Simulate tablet viewport simulateTablet: () => { ResponsiveTestUtils.setViewport(768, 1024); }, // Simulate desktop viewport simulateDesktop: () => { ResponsiveTestUtils.setViewport(1280, 800); }, // Check if element is in viewport isElementInViewport: (element: HTMLElement, offset = 0): boolean => { const rect = element.getBoundingClientRect(); return ( rect.top >= -offset && rect.left >= -offset && rect.bottom <= (window.innerHeight + offset) && rect.right <= (window.innerWidth + offset) ); }, // Measure touch target size measureTouchTarget: (element: HTMLElement): { width: number; height: number; valid: boolean } => { const rect = element.getBoundingClientRect(); return { width: rect.width, height: rect.height, valid: rect.width >= 44 && rect.height >= 44, }; }, // Check text readability checkTextReadability: (element: HTMLElement): { fontSize: number; lineHeight: number; valid: boolean } => { const computed = window.getComputedStyle(element); const fontSize = parseFloat(computed.fontSize); const lineHeight = parseFloat(computed.lineHeight); return { fontSize, lineHeight, valid: fontSize >= 16 && lineHeight >= 1.4, }; }, // Generate responsive test report generateTestReport: () => { const viewport = getViewport(); const validation = validateResponsiveDesign(); return { viewport, validation, timestamp: new Date().toISOString(), }; }, }; /** * Responsive design patterns for common scenarios */ export const RESPONSIVE_PATTERNS = { // Mobile-first card grid cardGrid: { mobile: { columns: 1, gap: '1rem' }, tablet: { columns: 2, gap: '1.5rem' }, desktop: { columns: 3, gap: '2rem' }, }, // Hero section hero: { mobile: { layout: 'stacked', padding: '2rem 1rem' }, tablet: { layout: 'split', padding: '3rem 2rem' }, desktop: { layout: 'split', padding: '4rem 3rem' }, }, // Form layout form: { mobile: { columns: 1, fieldWidth: '100%' }, tablet: { columns: 2, fieldWidth: '48%' }, desktop: { columns: 2, fieldWidth: '48%' }, }, // Navigation navigation: { mobile: { type: 'hamburger', itemsPerScreen: 6 }, tablet: { type: 'hybrid', itemsPerScreen: 8 }, desktop: { type: 'full', itemsPerScreen: 12 }, }, // Image gallery gallery: { mobile: { columns: 1, aspectRatio: '4:3' }, tablet: { columns: 2, aspectRatio: '1:1' }, desktop: { columns: 3, aspectRatio: '16:9' }, }, }; export default { TEST_VIEWPORTS, RESPONSIVE_CHECKLIST, generateResponsiveReport, validateResponsiveDesign, ResponsiveTestUtils, RESPONSIVE_PATTERNS, };