SPB Git forge

spb/polyllm

Public
15commits 1branches 0releases
2.2 MBsize
maindefault branch
13 days agolast push
TypeScript 97.4% SQL 1% JavaScript 0.9% CSS 0.6%

QA: glass overlay opacity, audit refinements, debug scripts

Simon-Pierre Boucher committed 13 days ago (Sep 11, 2026) parent 651bfec

3 changed files +26 −3

added qa/overflow-debug.mjs +22 −0
@@ -0,0 +1,22 @@
1 +import { chromium } from "@playwright/test";
2 +const b = await chromium.launch();
3 +const p = await b.newPage({ viewport: { width: 390, height: 844 }, isMobile: true, hasTouch: true });
4 +await p.goto((process.env.QA_BASE ?? "http://localhost:3000") + (process.argv[2] ?? "/"), { waitUntil: "networkidle" });
5 +await p.waitForTimeout(800);
6 +for (let y = 0; y < 9000; y += 800) {
7 + await p.evaluate((yy) => window.scrollTo(0, yy), y);
8 + await p.waitForTimeout(250);
9 +}
10 +const out = await p.evaluate(() => {
11 + const vw = window.innerWidth; const res = [];
12 + const inScroller = (el) => { let q = el.parentElement; while (q && q !== document.body) { const o = getComputedStyle(q).overflowX; if (o === 'auto' || o === 'scroll') return true; q = q.parentElement; } return false; };
13 + for (const el of document.querySelectorAll("body *")) {
14 + const r = el.getBoundingClientRect();
15 + if (r.width > 0 && r.right > vw + 1 && r.left < vw && !el.closest(".snap-row, .marquee, [data-allow-overflow]") && !inScroller(el)) {
16 + res.push({ tag: el.tagName, cls: (el.className || "").toString().slice(0, 120), text: el.textContent?.trim().slice(0, 60), right: Math.round(r.right), parent: (el.parentElement?.className || "").toString().slice(0, 100) });
17 + }
18 + }
19 + return { docOverflow: document.documentElement.scrollWidth - vw, res: res.slice(0, 8) };
20 +});
21 +console.log(JSON.stringify(out, null, 1));
22 +await b.close();
modified qa/responsive-qa.mjs +2 −1
@@ -49,12 +49,13 @@ const AUDIT = `(() => {
49 49 const vw = window.innerWidth;
50 50 const doc = document.documentElement;
51 51 const out = { docOverflow: Math.max(doc.scrollWidth, document.body.scrollWidth) - vw, overflowing: [], smallTargets: [], clipped: [] };
52 + const inScroller = (el) => { let p = el.parentElement; while (p && p !== document.body) { const o = getComputedStyle(p).overflowX; if (o === 'auto' || o === 'scroll' || o === 'hidden' || o === 'clip') return true; p = p.parentElement; } return false; };
52 53 const visible = (el) => { const r = el.getBoundingClientRect(); const s = getComputedStyle(el); return r.width > 0 && r.height > 0 && s.visibility !== 'hidden' && s.opacity !== '0' && r.bottom > 0 && r.top < window.innerHeight; };
53 54 const desc = (el) => (el.tagName.toLowerCase() + (el.id ? '#' + el.id : '') + (el.getAttribute('aria-label') ? '[' + el.getAttribute('aria-label') + ']' : '') + ' "' + (el.textContent || '').trim().slice(0, 40).replace(/\\s+/g, ' ') + '"');
54 55 for (const el of document.querySelectorAll('body *')) {
55 56 if (!visible(el)) continue;
56 57 const r = el.getBoundingClientRect();
57 if (r.right > vw + 1 && r.left < vw && !el.closest('.snap-row, .marquee, [data-allow-overflow]')) out.overflowing.push({ el: desc(el), right: Math.round(r.right) });
58 + if (r.right > vw + 1 && r.left < vw && !el.closest('.snap-row, .marquee, [data-allow-overflow]') && !inScroller(el)) out.overflowing.push({ el: desc(el), right: Math.round(r.right) });
58 59 }
59 60 const coarse = matchMedia('(pointer: coarse)').matches || vw < 768;
60 61 if (coarse) {
modified src/app/globals.css +2 −2
@@ -137,7 +137,7 @@
137 137 --bg-muted: #e9e9e5;
138 138 --bg-elevated: #ffffff;
139 139 --bg-inset: #ececea;
140 --bg-overlay: rgb(247 247 245 / 0.82);
140 + --bg-overlay: rgb(247 247 245 / 0.9);
141 141 --fg: #14151a;
142 142 --fg-muted: #5c6070;
143 143 --fg-subtle: #8b8f9d;
@@ -186,7 +186,7 @@
186 186 --bg-muted: #171923;
187 187 --bg-elevated: #13151d;
188 188 --bg-inset: #0e0f15;
189 --bg-overlay: rgb(11 12 16 / 0.78);
189 + --bg-overlay: rgb(11 12 16 / 0.9);
190 190 --fg: #f1f2f6;
191 191 --fg-muted: #9a9fb1;
192 192 --fg-subtle: #676d7e;
193 193