fix(hub): eliminate iframe flash when switching instance nav tabs

Use soft in-frame navigation and loading overlay in hub instance shell; pass embed=1 for iframe SSO opens.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
dekun
2026-06-17 19:27:52 +08:00
parent be7f5d5072
commit 6520234bd8
9 changed files with 137 additions and 13 deletions
+82
View File
@@ -283,10 +283,92 @@
apply(data.theme, { skipStore: true });
}
function notifyParentFrameNavStart() {
if (!isHubLinked()) return;
try {
window.parent.postMessage({ type: "instance-frame-navigating", theme: get() }, "*");
} catch (_) {}
}
function notifyParentFrameReady() {
if (!isHubLinked()) return;
try {
window.parent.postMessage({ type: "instance-frame-ready" }, "*");
} catch (_) {}
}
/** 中控 iframe 内:拦截顶栏导航,fetch 后 document.write 原地换页,避免 iframe 卸载白屏 */
function initHubEmbedInFrameNav() {
if (!isHubLinked()) return;
let navToken = 0;
function isSoftNavLink(a) {
if (!a || !a.getAttribute) return false;
return !!a.closest(".top-nav, .strategy-subnav");
}
async function navigateInFrame(href, opts) {
const token = ++navToken;
notifyParentFrameNavStart();
try {
const r = await fetch(href, { credentials: "same-origin" });
if (token !== navToken) return;
if (!r.ok) {
location.href = href;
return;
}
const html = await r.text();
if (token !== navToken) return;
document.open();
document.write(html);
document.close();
let path = href;
try {
const u = new URL(href, location.href);
path = u.pathname + u.search + u.hash;
} catch (_) {}
if (opts && opts.replace) history.replaceState(null, "", path);
else history.pushState(null, "", path);
} catch (_) {
if (token === navToken) location.href = href;
}
}
document.addEventListener(
"click",
(ev) => {
const a = ev.target.closest("a[href]");
if (!a || !isSoftNavLink(a) || ev.defaultPrevented) return;
if (ev.button !== 0 || ev.ctrlKey || ev.metaKey || ev.shiftKey || ev.altKey) return;
const rawHref = a.getAttribute("href");
if (!rawHref || rawHref.startsWith("#") || rawHref.startsWith("javascript:")) return;
let target;
try {
target = new URL(rawHref, location.href);
} catch (_) {
return;
}
if (target.origin !== location.origin) return;
const nextHref = target.pathname + target.search + target.hash;
if (target.pathname === location.pathname && target.search === location.search) return;
ev.preventDefault();
void navigateInFrame(nextHref);
},
true
);
window.addEventListener("popstate", () => {
void navigateInFrame(location.pathname + location.search + location.hash, { replace: true });
});
}
function boot() {
if (isHubLinked()) {
apply(get(), { skipStore: true });
window.addEventListener("message", (ev) => initFromHubMessage(ev.data));
initHubEmbedInFrameNav();
notifyParentFrameReady();
try {
window.parent.postMessage({ type: "instance-theme-ready" }, "*");
} catch (_) {}
+10
View File
@@ -1,4 +1,14 @@
/* 紧接 instance_theme.js 之后加载,避免亮色下先闪暗色底 */
html {
background: #0b0d14;
color-scheme: dark;
}
html[data-theme="light"] {
background: #d8e2ec;
color-scheme: light;
}
html[data-theme="light"] body {
background: #d8e2ec !important;
color: #1a2838 !important;