PMFlow/frontend/src/components/layout/Layout.tsx

75 lines
2.8 KiB
TypeScript

import { useEffect, useState } from "react";
import { Outlet, useLocation } from "react-router-dom";
import { Sidebar } from "./Sidebar";
import { TopBar } from "./TopBar";
import { FloatingQAChat } from "@/components/ai-steward/FloatingQAChat";
import { MobileProjectBottomNav, PMFlowOsHeader, ResponsiveAICopilot } from "@/features/pmflow-os/components/PMFlowOsFrame";
export default function Layout() {
const location = useLocation();
const [mobileSidebarOpen, setMobileSidebarOpen] = useState(false);
const isProjectLaunchSurface = location.pathname === "/project-launch";
const isPMFlowOsSurface = [
"/command-center",
"/structured-extraction",
"/change-review",
"/memory-writeback-result",
"/work-graph",
"/execution-bridge",
"/release-growth",
"/team-layer",
"/project-memory",
].includes(location.pathname);
useEffect(() => {
setMobileSidebarOpen(false);
window.scrollTo({ top: 0, left: 0, behavior: "auto" });
const main = document.querySelector("main");
if (main instanceof HTMLElement) {
main.scrollTop = 0;
}
}, [location.pathname, location.search]);
return (
<div className="relative flex h-screen overflow-hidden bg-[#f6f8fc] dark:bg-slate-950">
<Sidebar open={mobileSidebarOpen} onClose={() => setMobileSidebarOpen(false)} />
{mobileSidebarOpen && (
<button
type="button"
aria-label="关闭菜单遮罩"
className="fixed inset-0 z-40 bg-slate-900/45 md:hidden"
onClick={() => setMobileSidebarOpen(false)}
/>
)}
<div className="flex min-w-0 flex-1 flex-col overflow-hidden">
{isProjectLaunchSurface ? (
<main className="min-h-0 flex-1 overflow-hidden bg-white">
<Outlet />
</main>
) : isPMFlowOsSurface ? (
<>
<PMFlowOsHeader onMenuToggle={() => setMobileSidebarOpen((open) => !open)} />
<div className="min-h-0 flex-1 overflow-hidden bg-[linear-gradient(180deg,_#fbfdff,_#f6f9ff_40%,_#f8fafc)] px-3 pb-3 pt-3 sm:px-4 sm:pb-4 md:px-5 md:pb-5">
<div className="mx-auto flex h-full w-full max-w-[1880px] flex-col gap-3">
<ResponsiveAICopilot />
<main className="min-w-0 flex-1 overflow-auto lg:pr-20 min-[1440px]:pr-0">
<Outlet />
</main>
</div>
</div>
<MobileProjectBottomNav />
</>
) : (
<>
<TopBar onMenuToggle={() => setMobileSidebarOpen((open) => !open)} />
<main className="flex-1 overflow-auto bg-[#f6f8fc] p-3 dark:bg-slate-950 sm:p-4 md:p-6">
<Outlet />
</main>
</>
)}
</div>
{!isProjectLaunchSurface && !isPMFlowOsSurface ? <FloatingQAChat /> : null}
</div>
);
}