增加 dashboard 顶部折叠功能
这个提交包含在:
@@ -59,6 +59,23 @@ const DATA_HUB_ITEMS = [
|
||||
{ title: "最新同步摘要", href: "/docs/coverage-matrix.html", description: "覆盖矩阵与本地生成态入口。", badge: "generated" }
|
||||
];
|
||||
|
||||
const HERO_FOLD_STORAGE_KEY = "websafe.dashboard.heroFolded";
|
||||
|
||||
function readHeroFolded() {
|
||||
try {
|
||||
return window.localStorage.getItem(HERO_FOLD_STORAGE_KEY) === "1";
|
||||
} catch (_error) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function writeHeroFolded(value) {
|
||||
try {
|
||||
window.localStorage.setItem(HERO_FOLD_STORAGE_KEY, value ? "1" : "0");
|
||||
} catch (_error) {
|
||||
}
|
||||
}
|
||||
|
||||
const state = {
|
||||
routeSection: resolveRouteSection(),
|
||||
summary: null,
|
||||
@@ -72,6 +89,12 @@ const state = {
|
||||
refreshHandle: null,
|
||||
refreshMs: 5000,
|
||||
autoRefresh: true,
|
||||
heroFolded: readHeroFolded(),
|
||||
syncStatus: {
|
||||
kind: "boot",
|
||||
title: "启动中",
|
||||
detail: "正在载入本地生成数据"
|
||||
},
|
||||
filters: {
|
||||
search: "",
|
||||
status: "",
|
||||
@@ -303,6 +326,7 @@ function renderMetrics() {
|
||||
}
|
||||
|
||||
function renderSyncState(kind, title, detail) {
|
||||
state.syncStatus = { kind, title, detail };
|
||||
$("syncState").innerHTML = `
|
||||
${icon("sync", "icon icon-sync")}
|
||||
<div>
|
||||
@@ -311,6 +335,7 @@ function renderSyncState(kind, title, detail) {
|
||||
</div>
|
||||
`;
|
||||
$("syncState").dataset.kind = kind;
|
||||
renderHeroChrome();
|
||||
}
|
||||
|
||||
function renderSectionNav() {
|
||||
@@ -1244,14 +1269,34 @@ function renderWorkspace() {
|
||||
workspace.innerHTML = html;
|
||||
}
|
||||
|
||||
function renderHeroChrome() {
|
||||
const meta = sectionMeta();
|
||||
const chip = $("heroSectionChip");
|
||||
const title = $("heroSummaryTitle");
|
||||
const detail = $("heroSummaryDetail");
|
||||
const toggle = $("toggleHeroCollapse");
|
||||
const toggleLabel = $("heroToggleLabel");
|
||||
if (!chip || !title || !detail || !toggle || !toggleLabel) return;
|
||||
|
||||
chip.innerHTML = `${icon(meta.icon)}<span>${escapeHtml(meta.label)}</span>`;
|
||||
title.textContent = state.heroFolded ? `${meta.label} · 顶部区域已折叠` : `${meta.label} · 顶部操作区`;
|
||||
detail.textContent = state.heroFolded
|
||||
? `${state.syncStatus.title} · ${state.syncStatus.detail}`
|
||||
: `${meta.description} · ${state.syncStatus.detail}`;
|
||||
toggleLabel.textContent = state.heroFolded ? "展开顶部" : "折叠顶部";
|
||||
toggle.setAttribute("aria-expanded", String(!state.heroFolded));
|
||||
}
|
||||
|
||||
function syncRouteChrome() {
|
||||
const compactHero = state.routeSection !== "overview";
|
||||
document.body.dataset.routeSection = state.routeSection;
|
||||
document.body.classList.toggle("hero-compact", compactHero);
|
||||
document.body.classList.toggle("hero-folded", state.heroFolded);
|
||||
}
|
||||
|
||||
function renderAll() {
|
||||
syncRouteChrome();
|
||||
renderHeroChrome();
|
||||
renderMetrics();
|
||||
renderSectionNav();
|
||||
renderTopMenus();
|
||||
@@ -1285,6 +1330,14 @@ function clearFilters() {
|
||||
|
||||
function attachGlobalEvents() {
|
||||
document.addEventListener("click", (event) => {
|
||||
const heroToggle = event.target.closest("[data-hero-toggle]");
|
||||
if (heroToggle) {
|
||||
state.heroFolded = !state.heroFolded;
|
||||
writeHeroFolded(state.heroFolded);
|
||||
renderAll();
|
||||
return;
|
||||
}
|
||||
|
||||
const toggle = event.target.closest("[data-panel-toggle]");
|
||||
if (toggle) {
|
||||
const key = toggle.dataset.panelToggle;
|
||||
|
||||
在新工单中引用
屏蔽一个用户