Makelore 2.0 initial clean snapshot
This commit is contained in:
53
src/components/layout/MainLayout.tsx
Normal file
53
src/components/layout/MainLayout.tsx
Normal file
@@ -0,0 +1,53 @@
|
||||
/**
|
||||
* Main Layout Component
|
||||
* TitleBar at top, then sidebar + content below.
|
||||
*/
|
||||
import { Outlet, useLocation, useNavigate } from 'react-router-dom';
|
||||
import { useEffect } from 'react';
|
||||
import { LockKeyhole, Settings2 } from 'lucide-react';
|
||||
import { Sidebar } from './Sidebar';
|
||||
import { TitleBar } from './TitleBar';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { getAiModuleForPath } from '@/lib/ai-modules';
|
||||
import { useOpencodeStore } from '@/stores/opencode';
|
||||
import { useProjectConfigStore } from '@/stores/project-config';
|
||||
|
||||
export function MainLayout() {
|
||||
const activeProject = useOpencodeStore((state) => state.activeProject);
|
||||
const config = useProjectConfigStore((state) => activeProject ? state.configsByProjectId[activeProject.id] : undefined);
|
||||
const load = useProjectConfigStore((state) => state.load);
|
||||
const location = useLocation();
|
||||
const navigate = useNavigate();
|
||||
const isPaintingModule = getAiModuleForPath(location.pathname) === 'painting';
|
||||
const isInitializationSafeRoute = location.pathname === '/project-config' || isPaintingModule;
|
||||
|
||||
useEffect(() => {
|
||||
if (activeProject && !isPaintingModule) void load(activeProject.id).catch(() => undefined);
|
||||
}, [activeProject, isPaintingModule, load]);
|
||||
|
||||
const initializationBlocked = Boolean(activeProject && (!config || !config.initialized) && !isInitializationSafeRoute);
|
||||
return (
|
||||
<div data-testid="main-layout" className="flex h-screen flex-col overflow-hidden bg-background">
|
||||
{/* Title bar: drag region on macOS, icon + controls on Windows */}
|
||||
<TitleBar integrated />
|
||||
|
||||
{/* Below the title bar: sidebar + content */}
|
||||
<div className="flex min-h-0 flex-1 overflow-hidden">
|
||||
<Sidebar />
|
||||
<main data-testid="main-content" className="relative min-h-0 flex-1 overflow-auto p-6">
|
||||
<Outlet />
|
||||
{initializationBlocked ? (
|
||||
<div data-testid="project-initialization-gate" className="absolute inset-0 z-50 flex items-center justify-center bg-white/95 p-6">
|
||||
<div className="max-w-md rounded-2xl border-2 border-[#26384D] bg-[#FFFFFF] p-8 text-center shadow-[8px_8px_0_#26384D]">
|
||||
<LockKeyhole className="mx-auto h-10 w-10" />
|
||||
<h1 className="mt-4 text-2xl font-black">项目尚未初始化</h1>
|
||||
<p className="mt-3 text-sm font-bold text-[#68788B]">完成模板 Agent 名称确认后,聊天、任务和其他项目功能才会启用。</p>
|
||||
<Button onClick={() => navigate('/project-config')} className="mt-6 border-2 border-[#26384D] bg-[#3A5578] font-black text-white shadow-[4px_4px_0_#26384D]"><Settings2 className="mr-2 h-4 w-4" />打开项目配置</Button>
|
||||
</div>
|
||||
</div>
|
||||
) : null}
|
||||
</main>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user