报告与分析
import { useReadingWorkspace } from "@/shared/ui/reading-workspace-context"; import { ArrowLeft, Focus, Map as MapIcon, X } from "lucide-react"; import { AnimatePresence, motion, useReducedMotion } from "motion/react"; import { useState, type ReactNode } from "react"; import { cn } from "@/shared/ui/cn"; import { Button } from "@/shared/ui/button"; import { ReadingWorkspaceContent } from "@/shared/ui/reading-workspace"; import { OPERATIONAL_TIMELINE_LAYOUT } from "../operational-timeline/operational-timeline-model"; import { AnalysisArtifactWorkspace } from "./analysis-document-view"; import { ArtifactPeekBar } from "./artifact-peek-bar"; import { WorkbenchContentSplit } from "./workbench-content-split"; import { ARTIFACT_PANE_MIN_WIDTH } from "./workspace-model"; import { ARTIFACT_VIEW_CONTROL_BUTTON_CLASS_NAME, ARTIFACT_VIEW_CONTROL_SHELL_CLASS_NAME } from "./artifact-view-control-styles"; import type { AnalysisArtifact, ArtifactRequestedView, WorkbenchSurfaceMode } from "./workspace-model"; type WorkbenchMainFrameProps = { mapContent: ReactNode; mapOverlay?: ReactNode; timelineContent: ReactNode; timelineMode: "compact" | "expanded" | "summary"; timelineBottom: number; activeArtifact: AnalysisArtifact | null; pendingArtifact: AnalysisArtifact | null; surfaceMode: WorkbenchSurfaceMode; mapSplitAvailable: boolean; readingSplitAvailable?: boolean; onOpenPendingArtifact: () => void; onDestroyPendingArtifact: () => void; onSetArtifactView: (view: ArtifactRequestedView) => void; onCollapseArtifact: () => void; onDestroyArtifact: () => void; }; export function WorkbenchMainFrame({ mapContent, mapOverlay, timelineContent, timelineMode, timelineBottom, activeArtifact, pendingArtifact, surfaceMode: artifactSurfaceMode, mapSplitAvailable, readingSplitAvailable = false, onOpenPendingArtifact, onDestroyPendingArtifact, onSetArtifactView, onCollapseArtifact, onDestroyArtifact }: WorkbenchMainFrameProps) { const reading = useReadingWorkspace(); const surfaceMode = reading?.active ? reading.view === "map_split" && !readingSplitAvailable ? "focus" : reading.view : artifactSurfaceMode; const prefersReducedMotion = useReducedMotion(); const showMap = surfaceMode !== "focus"; const showArtifact = Boolean(!reading?.active && activeArtifact && surfaceMode !== "map_only"); const showArtifactViewControl = Boolean(activeArtifact && !reading?.active); const mapOnly = surfaceMode === "map_only"; const mapSplit = surfaceMode === "map_split"; const [mapPercentage, setMapPercentage] = useState(50); const viewControlLabel = mapOnly ? "返回分析成果" : mapSplit ? "专注分析" : mapSplitAvailable ? "半屏显示" : "显示地图"; const viewControlLeft = mapSplit ? `calc(${mapPercentage}% + 24px)` : "24px"; const timelineTransition = prefersReducedMotion ? { duration: 0 } : { duration: 0.28, ease: [0.22, 1, 0.36, 1] as const }; const viewControlTransition = prefersReducedMotion ? { duration: 0 } : { duration: 0.18, ease: [0.22, 1, 0.36, 1] as const }; const artifactTransition = prefersReducedMotion ? { duration: 0 } : { duration: 0.24, ease: [0.22, 1, 0.36, 1] as const }; // Map imagery fills the header backdrop; documents and controls reserve the header inset. return (
报告与分析