Files
fusion/packages/dashboard/app/index.html
gsxdsm 5a9095e547 fix(dashboard): re-drop viewport zoom flags + add vpdebug overlay
FN-5204 reintroduced `maximum-scale=1.0, user-scalable=no` into the
viewport meta as part of unrelated test-mode work, undoing the
Android-tablet fix from fbf7e2cb4. Drop them again.

Also add a `?vpdebug` query-flag-gated overlay that prints live
window / visualViewport / html / body / #root / #board bounding
boxes to a fixed top-right panel. Diagnostic only — remove once
the remaining Android tablet cut-off case is understood.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-22 04:04:43 -07:00

124 lines
6.1 KiB
HTML

<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover" />
<script>
// Append ?vpdebug to the URL to show a fixed overlay with the live
// viewport / element dimensions. Diagnostic only — remove once the
// Android tablet cut-off issue is understood.
(function () {
if (!/[?&]vpdebug\b/.test(location.search)) return;
var box = document.createElement('div');
box.style.cssText =
'position:fixed;top:0;right:0;z-index:2147483647;background:#000;color:#0f0;font:11px/1.3 monospace;padding:6px 8px;border:1px solid #0f0;white-space:pre;pointer-events:none;max-width:60vw;';
var update = function () {
var f = function (el) {
if (!el) return 'none';
var r = el.getBoundingClientRect();
return Math.round(r.width) + 'x' + Math.round(r.height) + ' @' + Math.round(r.left) + ',' + Math.round(r.top);
};
var vv = window.visualViewport;
box.textContent =
'win ' + window.innerWidth + 'x' + window.innerHeight + '\n' +
'vv ' + (vv ? Math.round(vv.width) + 'x' + Math.round(vv.height) + ' s' + vv.scale.toFixed(2) + ' o' + Math.round(vv.offsetLeft) + ',' + Math.round(vv.offsetTop) : 'n/a') + '\n' +
'dpr ' + window.devicePixelRatio + '\n' +
'html ' + f(document.documentElement) + '\n' +
'body ' + f(document.body) + '\n' +
'root ' + f(document.getElementById('root')) + '\n' +
'board ' + f(document.getElementById('board')) + '\n' +
'sx ' + window.scrollX + ' sy ' + window.scrollY + '\n' +
'ua ' + (navigator.userAgent || '').slice(0, 80);
};
var attach = function () {
if (!document.body) {
requestAnimationFrame(attach);
return;
}
document.body.appendChild(box);
update();
setInterval(update, 500);
window.addEventListener('resize', update);
window.addEventListener('orientationchange', update);
if (window.visualViewport) {
window.visualViewport.addEventListener('resize', update);
window.visualViewport.addEventListener('scroll', update);
}
};
attach();
})();
</script>
<title>Fusion</title>
<link rel="icon" type="image/svg+xml" href="/logo.svg" />
<link rel="manifest" href="/manifest.json" />
<link
rel="preload"
href="/fonts/SymbolsNerdFontMono-Regular.ttf"
as="font"
type="font/ttf"
crossorigin
/>
<meta name="theme-color" content="#1a1a2e" />
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
<link rel="apple-touch-icon" href="/icons/icon-192.png" />
<script>
// Theme initialization - runs before React to prevent flash
(function() {
try {
var mode = localStorage.getItem('kb-dashboard-theme-mode') || 'dark';
var colorTheme = localStorage.getItem('kb-dashboard-color-theme') || 'default';
var validThemes = ['default', 'ocean', 'forest', 'sunset', 'zen', 'berry', 'high-contrast', 'industrial', 'monochrome', 'slate', 'ash', 'graphite', 'silver', 'solarized', 'factory', 'ayu', 'one-dark', 'nord', 'dracula', 'gruvbox', 'tokyo-night', 'catppuccin-mocha', 'github-dark', 'everforest', 'rose-pine', 'kanagawa', 'night-owl', 'palenight', 'monokai-pro', 'slime', 'brutalist', 'neon-city', 'parchment', 'terminal', 'glass', 'horizon', 'vitesse', 'outrun', 'snazzy', 'porple', 'espresso', 'mars', 'poimandres', 'ember', 'rust', 'copper', 'foundry', 'carbon', 'sandstone', 'lagoon', 'frost', 'lavender', 'neon-bloom', 'sepia'];
if (!validThemes.includes(colorTheme)) {
colorTheme = 'default';
}
var fontScale = Number(localStorage.getItem('kb-dashboard-font-scale-pct') || '100');
if (!Number.isFinite(fontScale)) {
fontScale = 100;
}
fontScale = Math.min(125, Math.max(85, Math.round(fontScale)));
var systemDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
var effectiveMode = mode === 'system' ? (systemDark ? 'dark' : 'light') : mode;
document.documentElement.setAttribute('data-theme', effectiveMode);
document.documentElement.setAttribute('data-color-theme', colorTheme);
document.documentElement.style.fontSize = fontScale + '%';
if (colorTheme !== 'default') {
var base = document.baseURI || (document.location && document.location.href) || '';
var themeDataUrl;
if (!base) {
themeDataUrl = '/theme-data.css';
} else if (base.indexOf('http://') === 0 || base.indexOf('https://') === 0) {
themeDataUrl = new URL('/theme-data.css', base).toString();
} else if (base.indexOf('file://') === 0) {
if (base.endsWith('/')) {
themeDataUrl = base.slice(0, -1) + '/theme-data.css';
} else {
var lastSlashIndex = base.lastIndexOf('/');
themeDataUrl = lastSlashIndex >= 0
? base.slice(0, lastSlashIndex) + '/theme-data.css'
: '/theme-data.css';
}
} else {
themeDataUrl = '/theme-data.css';
}
var existingLink = document.getElementById('theme-data');
if (existingLink && existingLink.tagName === 'LINK' && existingLink.href !== themeDataUrl) {
existingLink.href = themeDataUrl;
}
}
} catch (e) {
document.documentElement.setAttribute('data-theme', 'dark');
document.documentElement.setAttribute('data-color-theme', 'default');
document.documentElement.style.fontSize = '100%';
}
})();
</script>
<script type="module" src="./main.tsx"></script>
<!-- fusion:view-preload -->
<link rel="stylesheet" href="/theme-data.css" id="theme-data" />
</head>
<body>
<div id="root"></div>
</body>
</html>