mirror of
https://gitcode.com/JianFeeeee/HomeAgent.git
synced 2026-09-23 10:28:06 +00:00
前端刻意没有构建链(纯 CSS + Vanilla JS,go:embed 进二进制),所以拆法是:
外壳 dashboard.html 留 {{DASHBOARD_CSS}} / {{DASHBOARD_JS}} 两个占位符,
init() 启动时把两份资产原样填回去 —— **发出的 HTML 与拆分前逐字节一致**,
但 6637 行的单文件变成三份,便于编辑与评审。
dashboard.html 168 行 外壳(head/body 结构 + 两个占位符)
dashboard.css 2099 行 样式
dashboard.js 4371 行 脚本
逐字节校验(三重):
* 组装结果 sha256 == git HEAD 里拆分前的 dashboard.html;
* 真实实例 GET /(带 API key)返回体 sha256 同上:0ef14b49…c053;
* 新增 TestDashboardAssetsSplit:占位符必须存在、样式/脚本不得再内联回外壳、
组装结果不得残留占位符且必须含样式与脚本特征串。
按行号切片时踩过一次坑并已修正:`</style>`/`</script>` 两个闭合标签被切掉
(正好少 27 字节)——正是因为当时少了逐字节校验,现在把它固化成断言。
169 lines
5.2 KiB
HTML
169 lines
5.2 KiB
HTML
<!doctype html>
|
|
<html lang="zh-CN">
|
|
<head>
|
|
<meta charset="UTF-8" />
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
<title>HomeAgent Dashboard</title>
|
|
<link rel="icon" type="image/svg+xml" href="/logo.svg" />
|
|
<script
|
|
src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"
|
|
onerror="window._THREE_FAILED = true"
|
|
></script>
|
|
<script
|
|
src="https://cdn.jsdelivr.net/npm/three@0.128.0/examples/js/controls/OrbitControls.js"
|
|
onerror="window._THREE_FAILED = true"
|
|
></script>
|
|
<script
|
|
src="https://cdnjs.cloudflare.com/ajax/libs/marked/4.3.0/marked.min.js"
|
|
onerror="console.warn('marked CDN failed')"
|
|
></script>
|
|
<script
|
|
src="https://cdn.jsdelivr.net/npm/dompurify@3.2.4/dist/purify.min.js"
|
|
onerror="console.warn('DOMPurify CDN failed')"
|
|
></script>
|
|
<script>
|
|
setTimeout(function () {
|
|
if (!window.THREE) window._THREE_FAILED = true;
|
|
}, 8000);
|
|
</script>
|
|
<style>
|
|
{{DASHBOARD_CSS}}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div id="bg-layer"></div>
|
|
<div class="palette-pop" id="palette-pop"></div>
|
|
<nav id="sidebar">
|
|
<h1>
|
|
<img
|
|
src="/logo.svg"
|
|
alt="HomeAgent"
|
|
style="
|
|
height: 22px;
|
|
width: 22px;
|
|
vertical-align: middle;
|
|
margin-right: 6px;
|
|
flex-shrink: 0;
|
|
border-radius: 6px;
|
|
"
|
|
/>HomeAgent
|
|
</h1>
|
|
<div class="nav-links">
|
|
<a
|
|
class="active"
|
|
onclick="switchTab('overview')"
|
|
data-i18n="navOverview"
|
|
>概览</a
|
|
>
|
|
<a onclick="switchTab('chat')" data-i18n="navChat">对话</a>
|
|
<a onclick="switchTab('plugins')" data-i18n="navPlugins">插件</a>
|
|
<a onclick="switchTab('settings')" data-i18n="navSettings">设置</a>
|
|
<a onclick="switchTab('adapters')" data-i18n="navAdapters">适配器</a>
|
|
<a onclick="switchTab('kernel')" data-i18n="navKernel">内核</a>
|
|
</div>
|
|
<div class="nav-footer">
|
|
<div style="display: flex; align-items: center; gap: 4px">
|
|
<button
|
|
class="theme-btn"
|
|
onclick="toggleTheme()"
|
|
id="theme-btn"
|
|
title="切换亮色/暗色模式"
|
|
>
|
|
<svg
|
|
viewBox="0 0 24 24"
|
|
width="15"
|
|
height="15"
|
|
fill="none"
|
|
stroke="currentColor"
|
|
stroke-width="2"
|
|
stroke-linecap="round"
|
|
>
|
|
<path d="M21 12.8A9 9 0 1 1 11.2 3a7 7 0 0 0 9.8 9.8z" />
|
|
</svg>
|
|
</button>
|
|
<button
|
|
class="theme-btn"
|
|
onclick="toggleAppearance()"
|
|
id="palette-btn"
|
|
title="外观:主题色 / 背景图"
|
|
>
|
|
<svg
|
|
viewBox="0 0 24 24"
|
|
width="15"
|
|
height="15"
|
|
fill="none"
|
|
stroke="currentColor"
|
|
stroke-width="2"
|
|
stroke-linecap="round"
|
|
stroke-linejoin="round"
|
|
>
|
|
<path
|
|
d="M12 22a10 10 0 1 1 10-10c0 2.2-1.8 4-4 4h-2a3 3 0 0 0-3 3c0 1.1.9 2 2 2 1.4 0 2.5-1.1 3.6-2.1C19.3 18.5 20 20 21.5 20.5A1 1 0 0 0 22 19c0-4-3.6-7-10-7-5.5 0-9 3.8-9 9z"
|
|
/>
|
|
<circle cx="7.5" cy="10.5" r="1" />
|
|
<circle cx="12" cy="7.5" r="1" />
|
|
<circle cx="16.5" cy="10.5" r="1" />
|
|
</svg>
|
|
</button>
|
|
<button
|
|
class="btn btn-ghost btn-sm"
|
|
onclick="toggleLang()"
|
|
id="lang-btn"
|
|
title="切换语言/Language"
|
|
style="font-size: 13px; min-width: 28px"
|
|
>
|
|
EN
|
|
</button>
|
|
<button
|
|
class="btn btn-ghost btn-sm"
|
|
onclick="logout()"
|
|
data-i18n="navLogout"
|
|
>
|
|
退出登录
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</nav>
|
|
<div class="main-wrap">
|
|
<header class="topbar">
|
|
<button
|
|
class="sidebar-toggle"
|
|
onclick="toggleSidebar()"
|
|
id="sidebar-toggle"
|
|
title="切换侧边栏"
|
|
aria-label="切换侧边栏"
|
|
>
|
|
<svg
|
|
viewBox="0 0 24 24"
|
|
width="15"
|
|
height="15"
|
|
fill="none"
|
|
stroke="currentColor"
|
|
stroke-width="2"
|
|
stroke-linecap="round"
|
|
>
|
|
<path d="M4 6h16M4 12h16M4 18h16" />
|
|
</svg>
|
|
</button>
|
|
<div class="breadcrumb" id="breadcrumb">
|
|
<span class="crumb-home">HomeAgent</span>
|
|
<span class="crumb-sep">/</span>
|
|
<span class="crumb-current" data-i18n="navOverview">概览</span>
|
|
</div>
|
|
</header>
|
|
<div class="container" id="app">
|
|
<div id="tab-overview" class="tab-content active"></div>
|
|
<div id="tab-chat" class="tab-content"></div>
|
|
<div id="tab-plugins" class="tab-content"></div>
|
|
<div id="tab-settings" class="tab-content"></div>
|
|
<div id="tab-adapters" class="tab-content"></div>
|
|
<div id="tab-kernel" class="tab-content"></div>
|
|
</div>
|
|
</div>
|
|
<div id="toast" class="toast"></div>
|
|
<script>
|
|
{{DASHBOARD_JS}}
|
|
</script>
|
|
</body>
|
|
</html>
|