astrion-website/demo/demo.html

167 lines
9.4 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<!-- 关键防纯白闪:浏览器默认 canvas 背景色由 color-scheme 决定。iframe 内整页导航(新建对话进 /new
时新文档第一帧绘制前,未样式化 canvas 默认纯白——此处声明 dark 使其从第一帧起就是深色。
与下方内联背景规则互补meta 管样式就绪前的 UA 默认画布,内联规则管样式就绪后。 -->
<meta name="color-scheme" content="dark">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Astrion</title>
<link rel="icon" type="image/svg+xml" href="/static/astrion-avatar.svg">
<link rel="icon" type="image/png" sizes="32x32" href="/static/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/static/favicon-16x16.png">
<link rel="apple-touch-icon" sizes="180x180" href="/static/apple-touch-icon.png">
<link rel="stylesheet" href="/static/style.css">
<!-- 防白闪:演示区固定 dark 主题,但 data-theme 要等 main.js(2.1MB) 执行 theme.ts 后才写上 html。
窗口期内产品首屏回退 (:root:not([data-theme])) 令 --surface-base=#faf9f5实测白帧采样正是此色
而 main.css 的 #app{background:var(--surface-base)} 无条件生效——只盖 html/body 没用,#app 画在
body 之上且 min-height 铺满全页,必须把 #app 一起锁深色。规则全部 !importantmain.css 是外链
后加载同优先级会被它压过。data-theme 落地后 :not() 选择器自动失效,产品 dark 规则无缝接管。 -->
<style>html:not([data-theme]), html:not([data-theme]) body, html:not([data-theme]) #app { background: #1a1a1a !important; } html:not([data-theme]) { color-scheme: dark !important; }</style>
<link rel="stylesheet" href="/static/easter-eggs/flood.css">
<link rel="stylesheet" href="/static/easter-eggs/snake.css">
</head>
<body>
<div id="app"></div>
<script>
// 全局复制代码块函数
function decodeHtmlEntities(text) {
const textarea = document.createElement('textarea');
textarea.innerHTML = text || '';
return textarea.value;
}
function copyCodeBlock(blockId) {
const codeElement = document.querySelector(`[data-code-id="${blockId}"]`);
if (!codeElement) return;
const button = document.querySelector(`[data-code="${blockId}"]`);
if (button && button.classList.contains('copied')) return;
const raw = codeElement?.dataset?.originalCode || codeElement?.textContent || '';
const codeContent = decodeHtmlEntities(raw);
if (!button) {
navigator.clipboard.writeText(codeContent).catch((err) => console.error('复制失败:', err));
return;
}
if (!button.dataset.originalLabel) {
button.dataset.originalLabel = button.getAttribute('aria-label') || '复制代码';
}
navigator.clipboard.writeText(codeContent).then(() => {
button.classList.add('copied');
button.setAttribute('aria-label', '已复制');
setTimeout(() => {
button.classList.remove('copied');
button.setAttribute('aria-label', button.dataset.originalLabel);
}, 2000);
}).catch((err) => {
console.error('复制失败:', err);
button.classList.remove('copied');
button.setAttribute('aria-label', button.dataset.originalLabel || '复制代码');
});
}
</script>
<script src="/static/easter-eggs/registry.js"></script>
<script src="/static/easter-eggs/flood.js"></script>
<script src="/static/easter-eggs/snake.js"></script>
<script src="/static/security.js"></script>
<script>
/* 演示引导:注册 mock SW等 controllerchange 后换路由、再加载真实前端 */
(function () {
// 防白闪协作:父页在本文档导航期间隐藏 iframe收到 ready 才显示。信号必须等「主题真正落地」
// theme.ts 把 data-theme 写到 <html>)之后发——此前首帧画面是首屏回退浅色 #faf9f5发早了
// 父页就会把白帧渐显出来v26 实测踩坑)。主路径 MutationObserver 等 data-themewindow load
// +300ms 与 4s 超时两级兜底,防主题脚本异常时 iframe 永久隐藏。双 rAF 保证首帧已上屏。
if (window.parent !== window) {
var readySent = false;
var sendReadyOnce = function () {
if (readySent) return;
readySent = true;
requestAnimationFrame(function () {
requestAnimationFrame(function () {
try { window.parent.postMessage('astrion-demo-frame-ready', location.origin); } catch (e) {}
});
});
};
if (document.documentElement.hasAttribute('data-theme')) {
sendReadyOnce();
} else {
var themeObserver = new MutationObserver(function () {
if (document.documentElement.hasAttribute('data-theme')) {
themeObserver.disconnect();
sendReadyOnce();
}
});
themeObserver.observe(document.documentElement, { attributes: true, attributeFilter: ['data-theme'] });
window.addEventListener('load', function () { setTimeout(sendReadyOnce, 300); });
setTimeout(sendReadyOnce, 4000);
}
}
// 防白闪第二道防线:隐藏时机提前到「点击发生」而非 beforeunload。新建对话是 location.href='/new'
// 整页导航beforeunload → 导航 commit 之间只有 SW 响应的十几毫秒不够一帧渲染——opacity:0
// 来不及上屏,浏览器 commit 时会画「未绘制 iframe 占位白」(实测竞态输赢不稳定)。点击捕获阶段
// 比产品逻辑与导航流程早整整一个事件周期,且同源可直接同步操作父页 DOMpostMessage 是异步
// 任务,仍有竞态)。若 800ms 内导航未发生(产品逻辑取消等)则恢复显示,防 iframe 永久黑洞。
document.addEventListener('click', function (e) {
var t = e.target && e.target.closest ? e.target.closest('button.sidebar-nav-row') : null;
if (!t || (t.textContent || '').indexOf('新建对话') === -1) return;
try {
if (window.parent === window) return;
var frames = window.parent.document.querySelectorAll('.demo-frame iframe');
for (var i = 0; i < frames.length; i++) frames[i].classList.remove('demo-frame-ready');
setTimeout(function () {
for (var j = 0; j < frames.length; j++) frames[j].classList.add('demo-frame-ready');
}, 800);
} catch (err) {}
}, true);
// 固定演示呈现状态:夜间配色 + 极简模式 + 快捷窗口自动展开,不受访客浏览器缓存影响
try {
localStorage.setItem('agents_ui_theme', 'dark');
localStorage.setItem('agents_personalization_experiments', JSON.stringify({ blockDisplayMode: 'minimal' }));
localStorage.setItem('agents_quick_dock_auto_expand', 'true');
} catch (e) {}
// 对话路由与 /new 空对话页都保留当前路径;其余一律回落默认对话。
// (此前 /new 会被强制拉回默认对话,导致「新建对话」按钮跳了又被顶回来)
var TARGET = (/^\/(?:conv_)?\d{8}_\d{6}_\d{3}$/.test(location.pathname) || location.pathname === '/new') ? location.pathname : '/20260823_122836_778';
// 演示禁用:工作流编辑器与个人空间管理员页的「打开」按钮(/workflows、/admin/* 均不在演示范围,
// 点击会 404 或开空白新标签。不动产品代码仅演示层注入MutationObserver 持续生效,幂等。
function demoDisable(btn, tip) {
if (btn.disabled) return;
btn.disabled = true;
btn.style.opacity = '0.4';
btn.style.cursor = 'not-allowed';
btn.title = tip;
}
function disableDemoBlockedButtons() {
// 侧边栏:工作流
var btns = document.querySelectorAll('button.sidebar-nav-row');
for (var i = 0; i < btns.length; i++) {
if (btns[i].querySelector('.workflow-icon')) demoDisable(btns[i], '演示环境未包含工作流编辑器');
}
// 个人空间-管理员 tab全部「打开」按钮.admin-monitor-page 为该 tab 独有容器,不会误伤其他设置按钮)
var adminBtns = document.querySelectorAll('.admin-monitor-page .settings-secondary-button');
for (var j = 0; j < adminBtns.length; j++) demoDisable(adminBtns[j], '演示环境未包含管理页面');
}
new MutationObserver(disableDemoBlockedButtons).observe(document.documentElement, { childList: true, subtree: true });
function loadMain() {
var s = document.createElement('script');
s.type = 'module';
s.src = '/static/dist/assets/main.js';
document.body.appendChild(s);
}
async function boot() {
if (!('serviceWorker' in navigator)) { loadMain(); return; }
try { await navigator.serviceWorker.register('/sw.js'); } catch (e) { loadMain(); return; }
if (!navigator.serviceWorker.controller) {
await new Promise(function (resolve) {
navigator.serviceWorker.addEventListener('controllerchange', resolve, { once: true });
setTimeout(resolve, 4000); // 兜底,防止极端情况下死等
});
}
history.replaceState(null, '', TARGET);
loadMain();
}
boot();
})();
</script>
</body>
</html>