diff options
| author | Adam Soltys <[email protected]> | 2026-09-23 13:00:36 -0700 |
|---|---|---|
| committer | Adam Soltys <[email protected]> | 2026-09-23 13:00:36 -0700 |
| commit | c6070c1891f4712b23397746f6aab1e2f070c3f8 (patch) | |
| tree | dba36d85fa42bcc5f47012dd00c0614140b8f650 /tools | |
| parent | 2fbfe122ae0e7d59a6b1df08cccd091010bc94ec (diff) | |
| download | coinosv3-c6070c1891f4712b23397746f6aab1e2f070c3f8.tar.gz coinosv3-c6070c1891f4712b23397746f6aab1e2f070c3f8.zip | |
Keep chat headers and composers pinned without page scrolling
Diffstat (limited to 'tools')
| -rw-r--r-- | tools/chat-layout-test.js | 54 |
1 files changed, 51 insertions, 3 deletions
diff --git a/tools/chat-layout-test.js b/tools/chat-layout-test.js index d8a3687..34c8dc0 100644 --- a/tools/chat-layout-test.js +++ b/tools/chat-layout-test.js @@ -35,7 +35,7 @@ const composerFits = () => page.evaluate(() => { }); try { - for (const vp of [{ width: 1280, height: 800, name: 'laptop' }, { width: 390, height: 844, name: 'phone' }, { width: 1024, height: 600, name: 'short laptop' }]) { + for (const vp of [{ width: 1280, height: 800, name: 'laptop' }, { width: 390, height: 844, name: 'phone' }, { width: 1024, height: 600, name: 'short laptop' }, { width: 390, height: 400, name: 'phone with keyboard' }, { width: 844, height: 390, name: 'landscape phone' }]) { console.log(`\n[${vp.name} ${vp.width}x${vp.height}]`); await page.setViewport({ width: vp.width, height: vp.height }); if (vp.name === 'laptop') { @@ -83,14 +83,40 @@ try { r = await composerFits(); check('...and with the member list open as well', r.fits, `bottom ${r.bottom} of ${r.vh}`); - // NB not asserting the page never scrolls: the footer legitimately sits - // below the fold. What matters is that the composer doesn't. + const frame = await page.evaluate(() => { + const footer = document.querySelector('.footer'); + const head = document.querySelector('.chat-head').getBoundingClientRect(); + return { + footerHidden: !footer || getComputedStyle(footer).display === 'none', + pageFits: document.documentElement.scrollHeight <= innerHeight, + headerFits: head.top >= 0 && head.bottom <= innerHeight, + }; + }); + check('footer hidden, header visible, and no page scrolling', frame.footerHidden && frame.pageFits && frame.headerFits, JSON.stringify(frame)); // put it back for the next viewport await page.evaluate(() => { const e = [...document.querySelectorAll('.chat-head .col')].find((n) => n.className.includes('clickable')); if (e) e.click(); }); await sleep(300); await page.evaluate(() => { const b = [...document.querySelectorAll('.chat-head button')].find((e) => /add person/i.test(e.textContent)); if (b) b.click(); }); await sleep(300); + + const pinned = await page.evaluate(() => { + const log = document.querySelector('.chat-log'); + const head = document.querySelector('.chat-head'); + const compose = document.querySelector('.chat-compose'); + const headTop = head.getBoundingClientRect().top; + const composeTop = compose.getBoundingClientRect().top; + const backlog = document.createElement('div'); + backlog.style.cssText = 'height:3000px;flex-shrink:0'; + log.append(backlog); + log.scrollTop = log.scrollHeight; + const result = log.scrollTop > 0 && head.getBoundingClientRect().top === headTop + && compose.getBoundingClientRect().top === composeTop + && document.documentElement.scrollHeight <= innerHeight; + backlog.remove(); + return result; + }); + check('a long message history scrolls with the name and composer pinned', pinned); } await page.setViewport({ width: 1280, height: 800 }); await sleep(500); @@ -134,6 +160,28 @@ try { check('and the naming field puts itself away', !two.field); const r2 = await composerFits(); check('composer still on screen', r2.fits, `bottom ${r2.bottom} of ${r2.vh}`); + + console.log('\n[direct messages]'); + await page.click('.chat-back'); + await sleep(500); + check('footer returns when the conversation closes', await page.$eval('.footer', (el) => getComputedStyle(el).display !== 'none')); + await click('button', 'New message'); + await setInput('input[placeholder*="npub" i]', '79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798'); + await click('button', 'Open'); + await page.waitForSelector('.chat-compose'); + await page.setViewport({ width: 390, height: 844 }); + await sleep(500); + const dm = await composerFits(); + check('DM composer fits and footer is hidden', dm.fits && await page.$eval('.footer', (el) => getComputedStyle(el).display === 'none')); + const keyboard = await page.evaluate(() => { + Object.defineProperty(window.visualViewport, 'height', { configurable: true, value: 400 }); + window.visualViewport.dispatchEvent(new Event('resize')); + const bottom = document.querySelector('.chat-compose').getBoundingClientRect().bottom; + delete window.visualViewport.height; + window.visualViewport.dispatchEvent(new Event('resize')); + return bottom <= 400; + }); + check('DM composer follows a keyboard that only resizes the visual viewport', keyboard); } catch (e) { check('run completed', false, e.message); } finally { |
