Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 57 additions & 1 deletion website/app/layout.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,19 @@ export function generateMetadata(ctx: { url: string }) {
const navLink = 'text-fg-muted no-underline font-medium text-sm px-[11px] py-2 rounded-lg transition-colors duration-[140ms] hover:text-fg hover:bg-bg-subtle';
const panelLink = 'text-fg-muted no-underline font-medium text-sm px-3 py-[10px] rounded-[9px] hover:text-fg hover:bg-bg-subtle';

export default function RootLayout({ children }: { children: unknown }) {
export default function RootLayout({ children, url }: { children: unknown; url?: string | URL }) {
const nonce = cspNonce();
// #936 on-device A/B diagnostic. Inert unless the ENTRY page is loaded with
// ?diag=<mode>. The mode is baked into a head script that persists across
// client-router soft navs (add-only head merge keeps it), so loading
// /?diag=nudge once governs the whole session. Whitelisted so the value that
// reaches the inline script is always a known literal.
const DIAG_MODES = new Set(['control', 'reflow', 'repaint', 'recolor', 'nudge']);
let diagMode = '';
try {
const raw = new URL(String(url ?? ''), 'http://x').searchParams.get('diag') || '';
if (DIAG_MODES.has(raw)) diagMode = raw;
} catch { /* no url in this context */ }
return html`
<link rel="icon" href="/public/favicon.svg" type="image/svg+xml" sizes="any">
<link rel="icon" href="/public/favicon.png" type="image/png" sizes="32x32">
Expand Down Expand Up @@ -141,6 +152,51 @@ export default function RootLayout({ children }: { children: unknown }) {
});
</script>

<!-- #936 on-device soft-nav CSS diagnostic. Emitted only when the entry
load carried ?diag=<mode>; otherwise diagMode is '' and this whole
block is absent, so production is untouched. Applies a repaint/recalc
nudge to the swapped DOM after each client-router nav to see which one
(if any) restores styling on real Android Chrome. -->
${diagMode ? html`<script nonce="${nonce}" data-webjs-diag="${diagMode}">
(function () {
var mode = "${diagMode}";
var tick = 0;
function badge() {
var b = document.getElementById('webjs-diag-badge');
if (!b) {
b = document.createElement('div');
b.id = 'webjs-diag-badge';
b.style.cssText = 'position:fixed;left:8px;bottom:8px;z-index:99999;background:#111;color:#fff;font:600 12px/1.2 system-ui,sans-serif;padding:6px 9px;border-radius:8px;opacity:0.85;pointer-events:none;max-width:70vw';
(document.body || document.documentElement).appendChild(b);
}
b.textContent = 'diag: ' + mode + ' @ ' + location.pathname;
}
function nudge() {
try {
if (mode === 'reflow') { void document.body.offsetHeight; }
else if (mode === 'repaint') {
var el = document.body;
el.style.transform = 'translateZ(0)';
requestAnimationFrame(function () { requestAnimationFrame(function () { el.style.transform = ''; }); });
}
else if (mode === 'recolor') { document.documentElement.style.setProperty('--webjs-diag-tick', String(tick++)); }
else if (mode === 'nudge') {
var h = document.documentElement, prev = h.style.display;
h.style.display = 'none'; void h.offsetHeight; h.style.display = prev;
}
/* mode 'control' does nothing: it only shows the badge, to confirm the
bug still reproduces with the diagnostic script present. */
} catch (_) {}
}
document.addEventListener('webjs:navigate', function () {
requestAnimationFrame(function () { nudge(); badge(); });
});
if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', badge);
else badge();
try { console.log('[webjs-diag] active mode:', mode); } catch (_) {}
})();
</script>` : ''}

<link rel="stylesheet" href="/public/tailwind.css">
<style>
/* Foundation tokens + effects that Tailwind utilities cannot express. */
Expand Down
Loading