From b1471cedb5a278f6910b1851b18e41ecced85103 Mon Sep 17 00:00:00 2001 From: Nico Verbruggen Date: Mon, 23 Mar 2026 22:58:52 +0100 Subject: [PATCH] Modal on mobile devices --- tests/e2e/screenshots.mjs | 23 ++++++++++++++++++++++- web/src/css/style.css | 31 +++++++++++++++++++++++++++++++ web/src/index.html | 23 +++++++++++++++++++---- web/src/js/app.js | 9 +++++++++ 4 files changed, 81 insertions(+), 5 deletions(-) diff --git a/tests/e2e/screenshots.mjs b/tests/e2e/screenshots.mjs index d8b1113..9d24707 100644 --- a/tests/e2e/screenshots.mjs +++ b/tests/e2e/screenshots.mjs @@ -14,9 +14,26 @@ const shot = async (page, name, testInfo) => { await page.screenshot({ path: `screenshots/${project}/${name}.png`, fullPage: true }); }; +/** Dismiss the mobile warning modal if it's open. */ +const dismissMobileModal = async (page) => { + const dialog = page.locator('#mobile-dialog'); + if (await dialog.evaluate(el => el.open).catch(() => false)) { + await page.click('#btn-mobile-continue'); + await expect(dialog).not.toBeVisible(); + } +}; + test('capture all steps', async ({ page }, testInfo) => { - // 1. Connect step + const isMobile = testInfo.project.name === 'mobile'; + + // 1. Connect step (with mobile modal if applicable) await page.goto('/'); + if (isMobile) { + // Capture the mobile warning modal + await expect(page.locator('#mobile-dialog')).toBeVisible(); + await page.screenshot({ path: `screenshots/mobile/00-mobile-warning.png` }); + await page.click('#btn-mobile-continue'); + } await expect(page.locator('#step-connect')).not.toBeHidden(); await injectMockDevice(page); await shot(page, '01-connect', testInfo); @@ -78,6 +95,7 @@ test('capture all steps', async ({ page }, testInfo) => { test('incompatible firmware', async ({ page }, testInfo) => { await page.goto('/'); + await dismissMobileModal(page); await injectMockDevice(page, { firmware: '5.0.0' }); await page.click('#btn-connect'); await page.click('#btn-connect-ready'); @@ -87,6 +105,7 @@ test('incompatible firmware', async ({ page }, testInfo) => { test('unknown model', async ({ page }, testInfo) => { await page.goto('/'); + await dismissMobileModal(page); await injectMockDevice(page, { serial: 'X9990A0000000' }); await page.click('#btn-connect'); await page.click('#btn-connect-ready'); @@ -97,12 +116,14 @@ test('unknown model', async ({ page }, testInfo) => { test('unsupported browser', async ({ page }, testInfo) => { await page.addInitScript(() => { delete window.showDirectoryPicker; }); await page.goto('/'); + await dismissMobileModal(page); await expect(page.locator('#connect-unsupported-hint')).toBeVisible(); await shot(page, '13-connect-unsupported', testInfo); }); test('disclaimer dialog', async ({ page }, testInfo) => { await page.goto('/'); + await dismissMobileModal(page); await page.click('#btn-how-it-works'); await expect(page.locator('#how-it-works-dialog')).toBeVisible(); await page.waitForTimeout(200); diff --git a/web/src/css/style.css b/web/src/css/style.css index 9a831fa..e5462ac 100644 --- a/web/src/css/style.css +++ b/web/src/css/style.css @@ -606,6 +606,30 @@ button.btn-success:hover { } /* Status banners */ +.notice { + background: #e8f7fa; + border: 1px solid #b2e4ed; + color: #0b6e80; + padding: 0.75rem 1rem; + border-radius: 8px; + margin-bottom: 1.5rem; + font-size: 0.88rem; + line-height: 1.5; +} + +.notice-heading { + font-size: 0.7rem; + font-weight: 700; + text-transform: uppercase; + letter-spacing: 0.04em; + margin-bottom: 0.3rem; +} + +.notice a { + color: #0b6e80; + text-decoration: underline; +} + .warning { background: var(--warning-bg); border: 1px solid var(--warning-border); @@ -1216,6 +1240,13 @@ button:focus-visible { margin-bottom: 0.5rem; } +.modal-footer { + padding: 1rem 1.25rem; + border-top: 1px solid var(--border-light); + display: flex; + justify-content: flex-end; +} + .modal-body a { color: var(--primary); text-decoration: none; diff --git a/web/src/index.html b/web/src/index.html index e13e01a..6987bb9 100644 --- a/web/src/index.html +++ b/web/src/index.html @@ -93,9 +93,9 @@