diff --git a/docs/src/components/WorkflowHero.astro b/docs/src/components/WorkflowHero.astro index e0511217ce2..d85c0b17fa9 100644 --- a/docs/src/components/WorkflowHero.astro +++ b/docs/src/components/WorkflowHero.astro @@ -76,6 +76,8 @@ function unmountFromHero() { let renderVersion = 0; /** @type {number | undefined} */ let autoplayTimer; + const MINIMUM_STAGE_DIMENSION = 1; + const MINIMUM_RENDER_SCALE = 0.1; function stopCarousel() { window.clearInterval(autoplayTimer); @@ -103,8 +105,16 @@ function unmountFromHero() { const devicePixelRatio = window.devicePixelRatio || 1; const baseViewport = page.getViewport({ scale: 1 }); - const availableWidth = stage.clientWidth - 16; - const scale = Math.max(availableWidth / baseViewport.width, 0.5); + const stageStyles = window.getComputedStyle(stage); + const parseInset = (value) => Number.parseFloat(value) || 0; + const horizontalInset = parseInset(stageStyles.paddingLeft) + parseInset(stageStyles.paddingRight); + const verticalInset = parseInset(stageStyles.paddingTop) + parseInset(stageStyles.paddingBottom); + const availableWidth = Math.max(stage.clientWidth - horizontalInset, MINIMUM_STAGE_DIMENSION); + const availableHeight = Math.max(stage.clientHeight - verticalInset, MINIMUM_STAGE_DIMENSION); + const scale = Math.max( + Math.min(availableWidth / baseViewport.width, availableHeight / baseViewport.height), + MINIMUM_RENDER_SCALE, + ); const viewport = page.getViewport({ scale }); bufferCanvas.width = Math.floor(viewport.width * devicePixelRatio); @@ -130,7 +140,10 @@ function unmountFromHero() { canvasContext.drawImage(bufferCanvas, 0, 0); activePage = pageNumber; - loading?.setAttribute('hidden', 'hidden'); + if (loading) { + loading.setAttribute('hidden', 'hidden'); + loading.style.display = 'none'; + } root.classList.add('is-ready'); } diff --git a/docs/tests/slide-preview.spec.ts b/docs/tests/slide-preview.spec.ts index 8c00cca14fa..c40b1718230 100644 --- a/docs/tests/slide-preview.spec.ts +++ b/docs/tests/slide-preview.spec.ts @@ -38,6 +38,26 @@ test.describe('Slide Preview on Homepage', () => { await expect(slideHero).toHaveClass(/is-ready/); }); + test('should keep the rendered slide within the frame on mobile screens', async ({ page }) => { + await page.setViewportSize({ width: 390, height: 844 }); + await page.goto('/gh-aw/'); + await page.waitForLoadState('networkidle'); + + const loading = page.locator('[data-slide-loading]'); + await expect(loading).toBeHidden({ timeout: 10000 }); + + const stage = page.locator('[data-slide-stage]'); + const canvas = page.locator('[data-slide-canvas]'); + const stageBox = await stage.boundingBox(); + const canvasBox = await canvas.boundingBox(); + + expect(stageBox).not.toBeNull(); + expect(canvasBox).not.toBeNull(); + + expect(canvasBox!.width).toBeLessThanOrEqual(stageBox!.width); + expect(canvasBox!.height).toBeLessThanOrEqual(stageBox!.height); + }); + test('should be keyboard accessible', async ({ page }) => { // Wait for slides to load const loading = page.locator('[data-slide-loading]');