From ca758882ef1c246144c6c855600ecc56f75798d7 Mon Sep 17 00:00:00 2001 From: juanatsap Date: Thu, 20 Nov 2025 20:01:57 +0000 Subject: [PATCH] fix: Position theme switcher and info button tooltips on TOP for mobile MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The theme switcher and info button tooltips were appearing on the RIGHT in mobile view instead of on TOP (like macOS Dock style) because they didn't have the .fixed-btn class and weren't included in the mobile media query rules. Changes: - static/css/04-interactive/_tooltips.css: Add .color-theme-switcher and .info-button selectors to mobile @media (max-width: 900px) rules - Now tooltips appear ABOVE these buttons on mobile with bottom: calc(100% + 8px) Testing: - Added mobile tooltip position test - Verified theme switcher and info tooltips now positioned on top on mobile - Desktop behavior unchanged (tooltips still on right) Mobile tooltip positioning now consistent across ALL buttons: āœ… All bottom dock buttons show tooltips on TOP (macOS Dock style) --- static/css/04-interactive/_tooltips.css | 8 +- tests/mjs/33-mobile-tooltip-position-test.mjs | 131 ++++++++++++++++++ 2 files changed, 137 insertions(+), 2 deletions(-) create mode 100755 tests/mjs/33-mobile-tooltip-position-test.mjs diff --git a/static/css/04-interactive/_tooltips.css b/static/css/04-interactive/_tooltips.css index 8a534f1..7391327 100644 --- a/static/css/04-interactive/_tooltips.css +++ b/static/css/04-interactive/_tooltips.css @@ -126,7 +126,9 @@ } /* Fixed buttons (left side) get TOP tooltips on mobile - like macOS Dock */ - .fixed-btn.has-tooltip::before { + .fixed-btn.has-tooltip::before, + .color-theme-switcher.has-tooltip::before, + .info-button.has-tooltip::before { bottom: calc(100% + 8px); /* 8px gap above button */ left: 50%; top: auto; @@ -134,7 +136,9 @@ transform: translateX(-50%) scale(0.8); } - .fixed-btn.has-tooltip:hover::before { + .fixed-btn.has-tooltip:hover::before, + .color-theme-switcher.has-tooltip:hover::before, + .info-button.has-tooltip:hover::before { transform: translateX(-50%) scale(1); } diff --git a/tests/mjs/33-mobile-tooltip-position-test.mjs b/tests/mjs/33-mobile-tooltip-position-test.mjs new file mode 100755 index 0000000..edf4818 --- /dev/null +++ b/tests/mjs/33-mobile-tooltip-position-test.mjs @@ -0,0 +1,131 @@ +#!/usr/bin/env bun +import { chromium } from 'playwright'; + +(async () => { + const browser = await chromium.launch({ headless: false }); + + console.log('========================================'); + console.log(' MOBILE TOOLTIP POSITION TEST'); + console.log(' Testing tooltip appears ABOVE buttons'); + console.log('========================================\n'); + + // Test with actual mobile viewport + const page = await browser.newPage({ + viewport: { width: 375, height: 667 }, + hasTouch: true, + isMobile: true + }); + + await page.goto('http://localhost:1999/'); + await page.waitForLoadState('networkidle'); + await page.waitForTimeout(2000); + + const buttonsToTest = [ + { id: 'color-theme-switcher', name: 'Theme Switcher' }, + { id: 'info-button', name: 'Info Button' } + ]; + + for (const btn of buttonsToTest) { + console.log(`\nšŸ” Testing: ${btn.name}`); + console.log('─────────────────────────────'); + + const button = page.locator(`#${btn.id}`); + const exists = await button.count() > 0; + + if (!exists) { + console.log(`āŒ Button NOT FOUND in DOM`); + continue; + } + + const isVisible = await button.isVisible(); + console.log(`Button visible: ${isVisible ? 'āœ…' : 'āŒ'}`); + + if (!isVisible) continue; + + // Get button position + const buttonBox = await button.boundingBox(); + console.log(`Button position: y=${Math.round(buttonBox.y)}, height=${buttonBox.height}`); + + // Tap (touch) the button to trigger hover state + await button.tap(); + await page.waitForTimeout(500); + + // Get computed tooltip styles + const tooltipInfo = await page.evaluate((id) => { + const btn = document.getElementById(id); + if (!btn) return null; + + const btnRect = btn.getBoundingClientRect(); + const computed = window.getComputedStyle(btn, '::before'); + + // Parse transform to get actual Y offset + const transform = computed.transform; + let transformY = 0; + if (transform && transform !== 'none') { + const matrix = transform.match(/matrix\((.+)\)/); + if (matrix) { + const values = matrix[1].split(', '); + transformY = parseFloat(values[5] || 0); + } + } + + return { + buttonTop: btnRect.top, + buttonBottom: btnRect.bottom, + opacity: computed.opacity, + visibility: computed.visibility, + display: computed.display, + bottom: computed.bottom, + top: computed.top, + left: computed.left, + position: computed.position, + content: computed.content, + transform: computed.transform + }; + }, btn.id); + + if (!tooltipInfo) { + console.log('āŒ Could not get tooltip info'); + continue; + } + + console.log(`\nTooltip CSS:`); + console.log(` - Visibility: ${tooltipInfo.visibility}`); + console.log(` - Display: ${tooltipInfo.display}`); + console.log(` - Opacity: ${tooltipInfo.opacity}`); + console.log(` - Position: ${tooltipInfo.position}`); + console.log(` - Bottom: ${tooltipInfo.bottom}`); + console.log(` - Top: ${tooltipInfo.top}`); + console.log(` - Left: ${tooltipInfo.left}`); + console.log(` - Transform: ${tooltipInfo.transform}`); + + // Check if tooltip is positioned ABOVE the button + // On mobile with our CSS, bottom should be calc(100% + 8px) which means + // the tooltip bottom edge is 8px above the button top + const bottomValue = parseFloat(tooltipInfo.bottom); + + if (tooltipInfo.display === 'none') { + console.log('\nāš ļø Tooltip is HIDDEN (display: none) - Expected for touch devices'); + } else if (tooltipInfo.bottom && tooltipInfo.bottom.includes('100%')) { + console.log('\nāœ… Tooltip positioned ABOVE button (bottom: calc(100% + 8px))'); + } else if (tooltipInfo.left && tooltipInfo.left.includes('100%')) { + console.log('\nāŒ Tooltip positioned to RIGHT (should be ABOVE on mobile!)'); + } else { + console.log('\nāš ļø Unclear positioning'); + } + } + + // Take screenshot + await page.screenshot({ + path: '/Users/txeo/Git/yo/cv/tests/mjs/screenshots/mobile-tooltip-positions.png', + fullPage: true + }); + console.log('\nšŸ“ø Screenshot saved\n'); + + console.log('========================================'); + console.log(' TEST COMPLETE'); + console.log('========================================\n'); + + await page.waitForTimeout(3000); + await browser.close(); +})();