migration wip

This commit is contained in:
2025-12-29 18:18:48 +01:00
parent 292975299d
commit f86785bfb0
182 changed files with 30131 additions and 9321 deletions

326
lib/responsive-test.ts Normal file
View File

@@ -0,0 +1,326 @@
/**
* 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,
};