fix: decouple timeline from workspace layout

The regression recurred because a floating timeline height was still exported as shared layout space and its z-index exceeded artifacts and notices. Reserve zero layout height and define the timeline below artifact and notification overlays.
This commit is contained in:
2026-08-19 16:58:55 +08:00
parent 760370c93f
commit 21dbfd82b6
5 changed files with 15 additions and 12 deletions
@@ -925,13 +925,7 @@ export function MapWorkbenchPage({
{ {
...WORKBENCH_LAYOUT_CSS_VARIABLES, ...WORKBENCH_LAYOUT_CSS_VARIABLES,
"--workbench-agent-current-width": `${currentAgentWidth}px`, "--workbench-agent-current-width": `${currentAgentWidth}px`,
"--workbench-timeline-height": `${ "--workbench-timeline-height": `${OPERATIONAL_TIMELINE_LAYOUT.overlayReservedHeight}px`
!timelineVisible
? 0
: !isLargeScreen
? OPERATIONAL_TIMELINE_LAYOUT.mobileSummaryHeight + timelineBottom
: OPERATIONAL_TIMELINE_LAYOUT[timelineMode].height + timelineBottom
}px`
} as CSSProperties } as CSSProperties
} }
> >
@@ -1094,7 +1088,7 @@ export function MapWorkbenchPage({
{shouldShowTaskTicker ? ( {shouldShowTaskTicker ? (
<motion.div <motion.div
key="agent-task-ticker-shell" key="agent-task-ticker-shell"
className="fixed left-1/2 right-auto top-24 z-20 w-[calc(100%-1.5rem)] [translate:-50%_0] md:absolute md:w-[var(--workbench-ticker-width)] 2xl:w-[var(--workbench-ticker-width-wide)]" className="fixed left-1/2 right-auto top-24 z-50 w-[calc(100%-1.5rem)] [translate:-50%_0] md:absolute md:w-[var(--workbench-ticker-width)] 2xl:w-[var(--workbench-ticker-width-wide)]"
style={{ transformOrigin: "top center" }} style={{ transformOrigin: "top center" }}
initial={ initial={
prefersReducedMotion prefersReducedMotion
@@ -4,6 +4,7 @@ import {
canCenterTimelineBesideMapScale, canCenterTimelineBesideMapScale,
clusterOperationalEvents, clusterOperationalEvents,
createOperationalEvents, createOperationalEvents,
OPERATIONAL_TIMELINE_LAYOUT,
resolveTimelineScaleLayout resolveTimelineScaleLayout
} from "./operational-timeline-model"; } from "./operational-timeline-model";
@@ -15,6 +16,10 @@ const workOrder: ScheduledConditionItem = {
}; };
describe("operational timeline model", () => { describe("operational timeline model", () => {
it("does not reserve workspace layout space for the floating timeline", () => {
expect(OPERATIONAL_TIMELINE_LAYOUT.overlayReservedHeight).toBe(0);
});
it("creates linked plan and actual events for active work orders", () => { it("creates linked plan and actual events for active work orders", () => {
const events = createOperationalEvents([workOrder]); const events = createOperationalEvents([workOrder]);
expect(events.map((event) => event.lane)).toEqual(["plan", "actual"]); expect(events.map((event) => event.lane)).toEqual(["plan", "actual"]);
@@ -38,7 +38,8 @@ export const OPERATIONAL_TIMELINE_LAYOUT = {
mapScaleSafeWidth: 520, mapScaleSafeWidth: 520,
floatingGap: 48, floatingGap: 48,
edgeInset: 24, edgeInset: 24,
scaleCollisionOffset: 56 scaleCollisionOffset: 56,
overlayReservedHeight: 0
} as const; } as const;
export type TimelineScaleLayout = { export type TimelineScaleLayout = {
@@ -17,7 +17,7 @@ export function ArtifactPeekBar({
<aside <aside
aria-label="Agent 成果预览" aria-label="Agent 成果预览"
className={cn( className={cn(
"acrylic-panel pointer-events-auto absolute bottom-[calc(var(--workbench-timeline-height)+1rem)] z-30 flex min-h-[76px] w-[min(680px,calc(100%-2rem))] items-center gap-3 rounded-2xl border px-3 py-2.5 text-slate-900", "acrylic-panel pointer-events-auto absolute top-28 z-40 flex min-h-[76px] w-[min(680px,calc(100%-2rem))] items-center gap-3 rounded-2xl border px-3 py-2.5 text-slate-900",
"left-1/2 -translate-x-1/2", "left-1/2 -translate-x-1/2",
surfaceMode === "map_split" && "2xl:left-[25%]" surfaceMode === "map_split" && "2xl:left-[25%]"
)} )}
@@ -95,7 +95,10 @@ export function WorkbenchMainFrame({
id="artifact-workspace" id="artifact-workspace"
aria-label={`${activeArtifact.title}工作区`} aria-label={`${activeArtifact.title}工作区`}
aria-hidden={!showArtifact} aria-hidden={!showArtifact}
className={cn("relative min-h-0 min-w-0 overflow-hidden", !showArtifact && "hidden")} className={cn(
"relative z-30 min-h-0 min-w-0 overflow-hidden",
!showArtifact && "hidden"
)}
> >
<AnalysisArtifactWorkspace <AnalysisArtifactWorkspace
artifact={activeArtifact} artifact={activeArtifact}
@@ -119,7 +122,7 @@ export function WorkbenchMainFrame({
</div> </div>
<motion.div <motion.div
className="pointer-events-auto absolute left-3 z-40 mx-auto min-h-0" className="pointer-events-auto absolute left-3 z-20 mx-auto min-h-0"
initial={false} initial={false}
animate={{ animate={{
bottom: timelineBottom, bottom: timelineBottom,