Glass Stage: float the section rail again, centred above the mini player
This commit is contained in:
@@ -20,42 +20,7 @@ async function setup(page, width, layout = 'glass-stage') {
|
||||
}, layout);
|
||||
await page.evaluate(async () => { await document.fonts.ready; await new Promise(r => requestAnimationFrame(() => requestAnimationFrame(r))); });
|
||||
}
|
||||
for (const width of [390, 1440]) test(`panel rail and bottom clearance at ${width}`, async ({ page }, info) => {
|
||||
await setup(page, width);
|
||||
// The desktop rail was hidden in the old build; expose it for baseline evidence.
|
||||
if (before && width === 1440) await page.addStyleTag({ content: 'html[data-layout="glass-stage"] #sectionRail{display:flex!important}' });
|
||||
for (const section of ['player', 'meta', 'notes', 'related', 'list']) {
|
||||
await page.locator(`#sectionRail [data-sec="${section}"]`).click();
|
||||
await page.evaluate(() => { document.getElementById('miniBar').classList.remove('hidden'); updateBottomChrome(); });
|
||||
await page.waitForTimeout(100);
|
||||
if (!before) {
|
||||
const metrics = await page.evaluate(() => {
|
||||
const rail = document.getElementById('sectionRail'), header = document.querySelector('#listPane .list-header');
|
||||
const r = rail.getBoundingClientRect(), h = header.getBoundingClientRect();
|
||||
const m = document.getElementById('miniBar').getBoundingClientRect(), p = document.getElementById('miniProgress').getBoundingClientRect(), nav = document.getElementById('bottomNav').getBoundingClientRect();
|
||||
return { parent: rail.parentElement.id, railBottom: r.bottom, headingTop: h.top, miniBottom: m.bottom, progressBottom: p.bottom, navTop: nav.height ? nav.top : innerHeight, overflow: getComputedStyle(document.getElementById('miniBar')).overflow };
|
||||
});
|
||||
expect(metrics.parent).toBe('listPane');
|
||||
expect(metrics.railBottom).toBeLessThanOrEqual(metrics.headingTop);
|
||||
expect(metrics.miniBottom).toBeLessThanOrEqual(metrics.navTop);
|
||||
expect(metrics.progressBottom).toBeLessThanOrEqual(metrics.miniBottom);
|
||||
expect(metrics.overflow).toBe('hidden');
|
||||
}
|
||||
await page.screenshot({ path: `/tmp/done9-${before ? 'before' : 'after'}-${info.project.name}-${width}-${section}.png` });
|
||||
}
|
||||
if (!before) {
|
||||
await page.evaluate(() => {
|
||||
const body = document.querySelector('.body'); body.scrollTop = body.scrollHeight;
|
||||
const cards = document.getElementById('cards'); cards.scrollTop = cards.scrollHeight;
|
||||
document.getElementById('miniBar').classList.remove('hidden'); updateBottomChrome();
|
||||
});
|
||||
await page.waitForTimeout(100);
|
||||
const tail = await page.locator('#cards .card').last().boundingBox(), mini = await page.locator('#miniBar').boundingBox();
|
||||
expect(tail.y + tail.height).toBeLessThanOrEqual(mini.y - 8);
|
||||
}
|
||||
});
|
||||
module.exports = { setup };
|
||||
|
||||
// The rail-in-panel test was removed: the Glass rail floats again (see glass-rail-float.spec.js).
|
||||
for (const width of [390, 1440]) test(`Classic panel layout unchanged at ${width}`, async ({ page, context }, info) => {
|
||||
const baseline = await context.newPage();
|
||||
await baseline.route('**/theme-glass-panel.css', r => r.fulfill({ contentType: 'text/css', body: '' }));
|
||||
|
||||
32
tests/glass-rail-float.spec.js
Normal file
32
tests/glass-rail-float.spec.js
Normal file
@@ -0,0 +1,32 @@
|
||||
const { test, expect } = require('@playwright/test');
|
||||
const { readFileSync } = require('node:fs');
|
||||
const { openClassic, showPlayingFixture } = require('./helpers/classic-fixture');
|
||||
const phoneCss = readFileSync('frontend/styles.css', 'utf8').replaceAll('(display-mode: standalone)', '(min-width: 0px)').replaceAll('env(safe-area-inset-bottom)', '34px');
|
||||
|
||||
// Glass Stage section rail floats centred above the mini player and stays put while the page scrolls.
|
||||
test('glass rail floats above the mini player and ignores scroll', async ({ page }) => {
|
||||
await page.setViewportSize({ width: 390, height: 844 });
|
||||
await page.route('**/styles.css', r => r.fulfill({ contentType: 'text/css', body: phoneCss }));
|
||||
await openClassic(page, { populated: true, standalone: true, settings: { autoPreload: false } });
|
||||
await showPlayingFixture(page);
|
||||
await page.evaluate(() => {
|
||||
data.settings.layout = 'glass-stage'; applyAppearance();
|
||||
document.getElementById('miniBar').classList.remove('hidden'); updateBottomChrome(); SectionRail.refresh();
|
||||
});
|
||||
await page.waitForTimeout(300);
|
||||
const at = () => page.evaluate(() => {
|
||||
const r = document.getElementById('sectionRail').getBoundingClientRect(), m = document.getElementById('miniBar').getBoundingClientRect();
|
||||
return { top: r.top, bottom: r.bottom, center: (r.left + r.right) / 2, miniTop: m.top, parent: document.getElementById('sectionRail').parentElement.id, pos: getComputedStyle(document.getElementById('sectionRail')).position };
|
||||
});
|
||||
const a = await at();
|
||||
expect(a.pos).toBe('fixed');
|
||||
expect(a.parent).not.toBe('listPane');
|
||||
expect(Math.abs(a.center - 195)).toBeLessThan(2);
|
||||
expect(a.bottom).toBeLessThanOrEqual(a.miniTop);
|
||||
await page.screenshot({ path: process.env.SHOT_DIR ? `${process.env.SHOT_DIR}/rail-a.png` : undefined });
|
||||
await page.evaluate(() => { for (const el of [document.scrollingElement, ...document.querySelectorAll('.body,#listPane,.player-pane')]) el && (el.scrollTop += 600); });
|
||||
await page.waitForTimeout(200);
|
||||
const b = await at();
|
||||
expect(Math.abs(b.top - a.top)).toBeLessThan(1);
|
||||
await page.screenshot({ path: process.env.SHOT_DIR ? `${process.env.SHOT_DIR}/rail-b.png` : undefined });
|
||||
});
|
||||
Reference in New Issue
Block a user