Center Glass Stage tab icons above their labels
This commit is contained in:
@@ -6,8 +6,9 @@ html[data-layout="glass-stage"] :is(#listPane button,.settings-section-row,.note
|
||||
html[data-layout="glass-stage"] :is(.bottom-nav-btn,.nav-item,.playlist-item) { min-height:44px; color:var(--text-2); }
|
||||
html[data-layout="glass-stage"] .bottom-nav { gap:2px; padding-inline:4px; }
|
||||
html[data-layout="glass-stage"] .bottom-nav-btn { border:1px solid transparent; border-radius:18px; gap:6px; min-width:44px; background:transparent; }
|
||||
html[data-layout="glass-stage"] .bottom-nav-icon { display:grid; place-items:center; width:24px; height:24px; background:none; box-shadow:none; transform:none; }
|
||||
html[data-layout="glass-stage"] .bottom-nav-icon { display:grid; place-items:center; width:24px; height:24px; padding:0; background:none; box-shadow:none; transform:none; }
|
||||
html[data-layout="glass-stage"] .bottom-nav-label { font-size:11px; }
|
||||
html[data-layout="glass-stage"] .bottom-nav-badge { top:6px; left:calc(50% + 8px); margin-left:0; }
|
||||
html[data-layout="glass-stage"] .bottom-nav-btn.active { color:var(--accent-bright); background:var(--tile-hi); border-color:var(--glass-line); }
|
||||
html[data-layout="glass-stage"] .bottom-nav-btn.active .bottom-nav-icon { background:none; box-shadow:none; transform:none; }
|
||||
html[data-layout="glass-stage"] :is(.bottom-nav-badge,.nav-badge,.pl-count) { background:var(--tile-hi); border:1px solid var(--glass-line); color:var(--text-2); border-radius:99px; font-size:11px; min-width:18px; font-variant-numeric:tabular-nums; }
|
||||
|
||||
2
playwright.glass-navigation.config.js
Normal file
2
playwright.glass-navigation.config.js
Normal file
@@ -0,0 +1,2 @@
|
||||
const { defineConfig } = require('@playwright/test');
|
||||
module.exports = defineConfig({ ...require('./playwright.classic.config'), testMatch: /glass-navigation\.spec\.js/ });
|
||||
46
tests/glass-navigation.spec.js
Normal file
46
tests/glass-navigation.spec.js
Normal file
@@ -0,0 +1,46 @@
|
||||
const { test, expect } = require('@playwright/test');
|
||||
const { execFileSync } = require('node:child_process');
|
||||
const { openClassic } = require('./helpers/classic-fixture');
|
||||
const { differentPixels } = require('./helpers/png-diff');
|
||||
const { readFileSync } = require('node:fs');
|
||||
const phoneCss = readFileSync('frontend/styles.css', 'utf8').replaceAll('(display-mode: standalone)', '(min-width: 0px)');
|
||||
const beforeCss = execFileSync('git', ['show', '5e78374:frontend/theme-glass-controls.css'], { encoding: 'utf8' });
|
||||
async function setup(page, layout) {
|
||||
const phone = page.viewportSize().width === 390;
|
||||
if (phone) await page.route('**/styles.css', route => route.fulfill({ contentType: 'text/css', body: phoneCss }));
|
||||
await openClassic(page, { populated: true, standalone: phone, settings: { autoPreload: false } });
|
||||
await page.addStyleTag({ content: '*,*::before,*::after{animation:none!important;transition:none!important;caret-color:transparent!important}#bottomNav{display:flex!important}' });
|
||||
await page.evaluate(layout => { data.settings.layout = layout; applyAppearance(); view = { type: 'queue' }; render(); }, layout);
|
||||
await page.evaluate(async () => { await document.fonts.ready; await new Promise(resolve => requestAnimationFrame(() => requestAnimationFrame(resolve))); });
|
||||
}
|
||||
for (const layout of ['glass-stage', 'classic']) for (const width of [390, 1440]) {
|
||||
test(`${layout} bottom tabs at ${width}`, async ({ page, context }) => {
|
||||
await page.setViewportSize({ width, height: 900 });
|
||||
const before = await context.newPage(); await before.setViewportSize({ width, height: 900 });
|
||||
await before.route('**/theme-glass-controls.css', route => route.fulfill({ contentType: 'text/css', body: beforeCss }));
|
||||
await setup(before, layout);
|
||||
const baseline = await before.screenshot({ path: `/tmp/ytplayer-done8-A-before-${layout}-${width}.png` });
|
||||
await setup(page, layout);
|
||||
const result = await page.screenshot({ path: `/tmp/ytplayer-done8-A-after-${layout}-${width}.png` });
|
||||
if (layout === 'classic') {
|
||||
const geometry = p => p.locator('.bottom-nav-btn,.bottom-nav-icon,.bottom-nav-label').evaluateAll(nodes => nodes.map(el => { const r = el.getBoundingClientRect(), s = getComputedStyle(el); return [r.x,r.y,r.width,r.height,s.padding,s.color,s.display]; }));
|
||||
expect(await geometry(page)).toEqual(await geometry(before));
|
||||
expect(differentPixels(baseline, result)).toBeLessThanOrEqual(32);
|
||||
}
|
||||
else {
|
||||
const positions = await page.locator('.bottom-nav-btn').evaluateAll(buttons => buttons.map(button => {
|
||||
const icon = button.querySelector('svg').getBoundingClientRect(), label = button.querySelector('.bottom-nav-label').getBoundingClientRect();
|
||||
return { offset: Math.abs(icon.x + icon.width / 2 - label.x - label.width / 2), above: icon.bottom <= label.top, target: button.getBoundingClientRect().height };
|
||||
}));
|
||||
expect(positions.every(p => p.offset <= 1 && p.above && p.target >= 44)).toBe(true);
|
||||
const badge = await page.locator('#bnQueueCount').evaluate(el => {
|
||||
const icon = el.parentElement.querySelector('svg').getBoundingClientRect(), r = el.getBoundingClientRect();
|
||||
return { x: r.left - icon.right, y: r.top - icon.top };
|
||||
});
|
||||
expect(Math.abs(badge.x)).toBeLessThanOrEqual(5);
|
||||
expect(Math.abs(badge.y)).toBeLessThanOrEqual(5);
|
||||
await expect(page.locator('.bottom-nav-btn.active')).toHaveAttribute('aria-label', 'Queue');
|
||||
}
|
||||
await before.close();
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user