feat: tighten mobile-first workbench chrome

This commit is contained in:
kris
2026-03-30 00:59:07 +08:00
parent 0466f5b672
commit 25a050453e
3 changed files with 47 additions and 5 deletions

View File

@@ -778,6 +778,7 @@ function ensureAuthUi() {
</div>
<div class="helper-text" data-role="auth-message"></div>
<div class="auth-actions">
<button class="btn btn-secondary" type="button" data-action="logout-session">退出工作区</button>
<button class="btn btn-secondary" type="button" data-action="auth-refresh">重新加载</button>
<button class="btn btn-primary" type="submit" data-action="submit-auth">自动连接</button>
</div>
@@ -792,11 +793,13 @@ function renderAuthUi() {
ensureAuthUi();
const session = appState.session;
const openButton = document.querySelector('[data-action="open-auth"]');
const logoutButton = document.querySelector('[data-action="logout-session"]');
const logoutButtons = document.querySelectorAll('[data-action="logout-session"]');
const status = document.querySelector(".auth-status");
const message = document.querySelector('[data-role="auth-message"]');
if (openButton) openButton.textContent = session ? "连接状态" : "自动连接";
if (logoutButton) logoutButton.hidden = !session;
logoutButtons.forEach((button) => {
button.hidden = !session;
});
if (status) {
status.textContent = appState.busy
? appState.message || "正在加载..."
@@ -5348,7 +5351,7 @@ function renderDiscoveryScreen() {
];
const activeTab = getActiveDetailTab("discoveryDetailTab", detailTabs);
const selectedSummaryHtml = `
<div class="hero-card" style="padding:18px;">
<div class="hero-card discovery-selected-hero" style="padding:18px;">
<div class="entity-cell">
<div class="avatar-lg">${escapeHtml(initials(getAccountName(selected) || "SF"))}</div>
<div>
@@ -6035,7 +6038,7 @@ function renderProductionScreen() {
${renderMainAgentLandingNotice("production")}
<div class="panel pad">
<div class="panel-head"><div><h3>生产队列</h3><div class="panel-subtitle"></div></div></div>
<div class="layout-grid grid-4" style="margin-top:16px;">
<div class="layout-grid grid-4 production-queue-grid" style="margin-top:16px;">
<div class="queue-card"><h4>分析任务</h4><p> ${escapeHtml(formatNumber(jobs.filter((item) => item.line_type === "analysis").length))} </p></div>
<div class="queue-card"><h4>实拍剪辑</h4><p> ${escapeHtml(formatNumber(jobs.filter((item) => item.line_type === "real_cut").length))} </p></div>
<div class="queue-card"><h4>AI 视频</h4><p> ${escapeHtml(formatNumber(jobs.filter((item) => item.line_type === "ai_video").length))} </p></div>

View File

@@ -1930,6 +1930,7 @@ tbody tr:hover {
}
.topbar {
display: none;
margin-top: 6px;
padding: 14px;
border-radius: 18px;
@@ -2193,6 +2194,11 @@ tbody tr:hover {
text-align: center;
}
.discovery-selected-hero .mini-grid,
.production-queue-grid {
display: none;
}
.mobile-flow-focus-card {
display: grid;
gap: 10px;
@@ -2263,7 +2269,16 @@ tbody tr:hover {
.oneliner-fab {
right: 14px;
bottom: calc(96px + env(safe-area-inset-bottom));
padding: 11px 12px;
width: 52px;
height: 52px;
padding: 0;
gap: 0;
justify-content: center;
border-radius: 18px;
}
.oneliner-fab-text {
display: none;
}
table {

View File

@@ -30,6 +30,7 @@ test("mobile shell includes a native-like header, drawer toggle, and bottom tab
assert.match(HTML, /data-action="open-mobile-sidebar"/);
assert.match(HTML, /class="mobile-tabbar"/);
assert.match(HTML, /class="mobile-sidebar-backdrop"/);
assert.match(HTML, /class="mobile-workspace-summary"/);
assert.match(HTML, /data-screen-target="dashboard"[\s\S]*mobile-tabbar-item/);
assert.match(HTML, /data-screen-target="intake"[\s\S]*mobile-tabbar-item/);
assert.match(HTML, /data-screen-target="discovery"[\s\S]*mobile-tabbar-item/);
@@ -45,6 +46,10 @@ test("mobile shell styling uses safe-area padding, drawer navigation, and fixed
assert.match(CSS, /\.mobile-sidebar-open\s+\.sidebar\s*\{[\s\S]*transform:\s*translateX\(0\)/);
assert.match(CSS, /\.content\s*\{[\s\S]*padding-bottom:\s*calc\(110px \+ env\(safe-area-inset-bottom\)\)/);
assert.match(CSS, /\.oneliner-fab\s*\{[\s\S]*bottom:\s*calc\(96px \+ env\(safe-area-inset-bottom\)\)/);
assert.match(CSS, /@media \(max-width: 760px\)[\s\S]*\.mobile-workspace-summary\s*\{[\s\S]*display:\s*flex/);
assert.match(CSS, /@media \(max-width: 760px\)[\s\S]*\.workspace-switch span\s*\{[\s\S]*display:\s*none/);
assert.match(CSS, /@media \(max-width: 760px\)[\s\S]*\.auth-status\s*\{[\s\S]*display:\s*none/);
assert.match(CSS, /@media \(max-width: 760px\)[\s\S]*\.oneliner-fab-text\s*\{[\s\S]*display:\s*none/);
});
test("mobile shell javascript syncs drawer state and active labels with the current screen", () => {
@@ -54,6 +59,7 @@ test("mobile shell javascript syncs drawer state and active labels with the curr
assert.match(APP, /function setMobileSidebarOpen\(next\)/);
assert.match(APP, /function getScreenLabel\(screenId = appState\.screen\)/);
assert.match(APP, /function syncMobileShell\(\)/);
assert.match(APP, /const mobileWorkspaceSummary = document\.querySelector\("\.mobile-workspace-summary"\)/);
assert.match(shell, /syncMobileShell\(\);/);
assert.match(APP, /setMobileSidebarOpen\(false\);[\s\S]*appState\.screen = resolvedId;/);
assert.match(clicks, /name === "open-mobile-sidebar"/);
@@ -69,6 +75,13 @@ test("mobile layout turns screen actions and page tabs into native-like horizont
assert.match(CSS, /@media \(max-width: 760px\)[\s\S]*\.page-detail-tabs \.tab\s*\{[\s\S]*flex:\s*0 0 auto/);
});
test("mobile shell removes duplicated desktop topbar and collapses the main agent fab", () => {
assert.match(CSS, /@media \(max-width: 760px\)[\s\S]*\.topbar\s*\{[\s\S]*display:\s*none/);
assert.match(CSS, /@media \(max-width: 760px\)[\s\S]*\.oneliner-fab\s*\{[\s\S]*width:\s*52px/);
assert.match(CSS, /@media \(max-width: 760px\)[\s\S]*\.oneliner-fab\s*\{[\s\S]*justify-content:\s*center/);
assert.match(CSS, /@media \(max-width: 760px\)[\s\S]*\.oneliner-fab-text\s*\{[\s\S]*display:\s*none/);
});
test("detail tab buttons expose the active state for touch navigation", () => {
const detailTabs = extractBetween(APP, "function renderDetailTabs(stateKey, tabs) {", "function renderDiscoveryOverviewSection(");
assert.match(detailTabs, /aria-pressed="\$\{tab\.value === active \? "true" : "false"\}"/);
@@ -150,6 +163,17 @@ test("discovery and production screens expose mobile focus cards with next-step
assert.match(cssMobile, /\.mobile-flow-focus-card/);
});
test("mobile heavy screens mark redundant desktop metric blocks for compact hiding", () => {
const discovery = extractBetween(APP, "function renderDiscoveryScreen()", "function renderTrackingScreen()");
const production = extractBetween(APP, "function renderProductionScreen()", "function renderReviewScreen()");
const cssMobile = extractBetween(CSS, "@media (max-width: 760px) {", "@media (max-width: 560px) {");
assert.match(discovery, /discovery-selected-hero/);
assert.match(production, /production-queue-grid/);
assert.match(cssMobile, /\.discovery-selected-hero \.mini-grid/);
assert.match(cssMobile, /\.production-queue-grid/);
});
test("projects screen uses an adaptive project grid instead of a fixed three-column squeeze", () => {
const projects = extractBetween(APP, "function renderProjectsScreen()", "function getActiveDetailTab(");
assert.match(projects, /project-status-grid/);