639a99b8ea
Fixes three critical mobile issues across Android and iPhone: 1. HORIZONTAL SCROLL ELIMINATION (CRITICAL) - Added overflow-x: hidden to html and body globally - Landscape: Aggressive max-width: 100vw on all containers - Fixed .cv-page, .cv-container overflow issues - Prevented scale transform from causing overflow 2. LANDSCAPE MODE COMPLETE FIX - Single column layout enforced (grid-template-columns: 1fr) - Photo visible and sized appropriately (max-width: 120px) - Hamburger menu visible and accessible - Action bar simplified (center controls hidden) - Language selector compact - Smaller buttons (40px) with recalculated positions - Typography reduced for better fit 3. BUTTON CENTERING (VERIFIED WORKING) - Confirmed perfect centering in portrait mode - Android: 290px bar centered at viewport center (188px) - iPhone: Identical centering behavior - Landscape: 240px bar for 5 buttons (40px each) Files modified: - static/css/01-foundation/_reset.css - Global overflow-x fix - static/css/05-responsive/_breakpoints.css - Comprehensive landscape overhaul - tests/mjs/54-landscape-mode-test.mjs - Landscape validation (Android + iPhone) - tests/mjs/55-button-centering-test.mjs - Button centering validation - tests/mjs/56-landscape-debug-test.mjs - Media query debugging tool - tests/mjs/57-horizontal-scroll-debug.mjs - Scroll width debugging tool Test results: ✅ Portrait: Buttons perfectly centered (0px offset) ✅ Landscape: Single column, no horizontal scroll ✅ Hamburger visible and accessible in landscape ✅ Photo visible in all orientations ✅ Android + iPhone parity confirmed
118 lines
5.4 KiB
JavaScript
Executable File
118 lines
5.4 KiB
JavaScript
Executable File
#!/usr/bin/env node
|
|
|
|
import { chromium } from 'playwright';
|
|
|
|
const LANDSCAPE_VIEWPORT = { width: 667, height: 375 }; // iPhone SE landscape
|
|
|
|
(async () => {
|
|
const browser = await chromium.launch({ headless: true });
|
|
|
|
console.log('🧪 Testing Landscape Mode Layout\n');
|
|
|
|
// TEST 1: Android Landscape
|
|
console.log('📱 TEST 1: Android Landscape (Pixel 5)\n');
|
|
const androidContext = await browser.newContext({
|
|
viewport: LANDSCAPE_VIEWPORT,
|
|
userAgent: 'Mozilla/5.0 (Linux; Android 11; Pixel 5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.91 Mobile Safari/537.36',
|
|
hasTouch: true
|
|
});
|
|
const androidPage = await androidContext.newPage();
|
|
|
|
await androidPage.goto('http://localhost:1999/?lang=en&view=extended');
|
|
await androidPage.waitForLoadState('networkidle');
|
|
|
|
const androidLayout = await androidPage.evaluate(() => {
|
|
const page1 = document.querySelector('.page-1 .page-content');
|
|
const sidebar = document.querySelector('.cv-sidebar-left');
|
|
const hamburger = document.querySelector('.hamburger-btn'); // Correct class name
|
|
const photo = document.querySelector('.cv-photo');
|
|
const buttons = document.querySelector('.download-btn');
|
|
|
|
const gridCols = window.getComputedStyle(page1).gridTemplateColumns;
|
|
// Single column if it's just one value (e.g., "667px" not "300px 667px")
|
|
const singleColumn = !gridCols.includes(' ');
|
|
|
|
return {
|
|
gridColumns: gridCols,
|
|
singleColumn: singleColumn,
|
|
hamburgerVisible: hamburger ? window.getComputedStyle(hamburger).display !== 'none' : false,
|
|
photoMaxWidth: photo ? window.getComputedStyle(photo).maxWidth : 'N/A',
|
|
photoVisible: photo ? window.getComputedStyle(photo).display !== 'none' : false,
|
|
buttonWidth: buttons ? window.getComputedStyle(buttons).width : 'N/A',
|
|
hasHorizontalScroll: document.body.scrollWidth > window.innerWidth
|
|
};
|
|
});
|
|
|
|
console.log('Android Landscape Layout:');
|
|
console.log(` • Grid columns: ${androidLayout.gridColumns}`);
|
|
console.log(` • Single column: ${androidLayout.singleColumn ? '✅' : '❌'}`);
|
|
console.log(` • Hamburger menu visible: ${androidLayout.hamburgerVisible ? '✅' : '❌'}`);
|
|
console.log(` • Photo max-width: ${androidLayout.photoMaxWidth}`);
|
|
console.log(` • Photo visible: ${androidLayout.photoVisible ? '✅' : '❌'}`);
|
|
console.log(` • Button width: ${androidLayout.buttonWidth}`);
|
|
console.log(` • Has horizontal scroll: ${androidLayout.hasHorizontalScroll ? '❌ FAIL' : '✅'}\n`);
|
|
|
|
await androidPage.screenshot({
|
|
path: 'tests/screenshots/landscape-android.png',
|
|
fullPage: true
|
|
});
|
|
|
|
await androidContext.close();
|
|
|
|
// TEST 2: iPhone Landscape
|
|
console.log('📱 TEST 2: iPhone Landscape (iPhone 12)\n');
|
|
const iphoneContext = await browser.newContext({
|
|
viewport: { width: 844, height: 390 }, // iPhone 12 landscape
|
|
userAgent: 'Mozilla/5.0 (iPhone; CPU iPhone OS 15_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.0 Mobile/15E148 Safari/604.1',
|
|
hasTouch: true
|
|
});
|
|
const iphonePage = await iphoneContext.newPage();
|
|
|
|
await iphonePage.goto('http://localhost:1999/?lang=en&view=extended');
|
|
await iphonePage.waitForLoadState('networkidle');
|
|
|
|
const iphoneLayout = await iphonePage.evaluate(() => {
|
|
const page1 = document.querySelector('.page-1 .page-content');
|
|
const photo = document.querySelector('.cv-photo');
|
|
const buttons = document.querySelector('.download-btn');
|
|
|
|
const gridCols = window.getComputedStyle(page1).gridTemplateColumns;
|
|
// Single column if it's just one value (e.g., "844px" not "300px 844px")
|
|
const singleColumn = !gridCols.includes(' ');
|
|
|
|
return {
|
|
gridColumns: gridCols,
|
|
singleColumn: singleColumn,
|
|
photoMaxWidth: photo ? window.getComputedStyle(photo).maxWidth : 'N/A',
|
|
photoVisible: photo ? window.getComputedStyle(photo).display !== 'none' : false,
|
|
buttonWidth: buttons ? window.getComputedStyle(buttons).width : 'N/A',
|
|
hasHorizontalScroll: document.body.scrollWidth > window.innerWidth
|
|
};
|
|
});
|
|
|
|
console.log('iPhone Landscape Layout:');
|
|
console.log(` • Grid columns: ${iphoneLayout.gridColumns}`);
|
|
console.log(` • Single column: ${iphoneLayout.singleColumn ? '✅' : '❌'}`);
|
|
console.log(` • Photo max-width: ${iphoneLayout.photoMaxWidth}`);
|
|
console.log(` • Photo visible: ${iphoneLayout.photoVisible ? '✅' : '❌'}`);
|
|
console.log(` • Button width: ${iphoneLayout.buttonWidth}`);
|
|
console.log(` • Has horizontal scroll: ${iphoneLayout.hasHorizontalScroll ? '❌ FAIL' : '✅'}\n`);
|
|
|
|
await iphonePage.screenshot({
|
|
path: 'tests/screenshots/landscape-iphone.png',
|
|
fullPage: true
|
|
});
|
|
|
|
await iphoneContext.close();
|
|
|
|
const allPassed = androidLayout.singleColumn && !androidLayout.hasHorizontalScroll &&
|
|
androidLayout.hamburgerVisible && androidLayout.photoVisible &&
|
|
iphoneLayout.singleColumn && !iphoneLayout.hasHorizontalScroll &&
|
|
iphoneLayout.photoVisible;
|
|
|
|
console.log(`${allPassed ? '✅' : '❌'} Tests ${allPassed ? 'PASSED' : 'FAILED'}\n`);
|
|
|
|
await browser.close();
|
|
process.exit(allPassed ? 0 : 1);
|
|
})();
|