Refactor data fetching architecture from centralized App state to component-local data management for improved maintainability and data freshness guarantees. Changes: - SettingsModal: Fetch config data on modal open - RecipePanel: Fetch recipe list on panel open - IOMonitorPage: Fetch IO list on page mount with real-time updates - Remove unnecessary props drilling through component hierarchy - Simplify App.tsx by removing centralized config/recipes state New feature: - Add InitializeModal for sequential axis initialization (X, Y, Z) - Each axis initializes with 3-second staggered start - Progress bar animation for each axis - Auto-close on completion 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
62 lines
2.5 KiB
TypeScript
62 lines
2.5 KiB
TypeScript
import React from 'react';
|
|
import { Header } from './Header';
|
|
import { Footer } from './Footer';
|
|
import { RobotTarget } from '../../types';
|
|
|
|
interface LayoutProps {
|
|
children: React.ReactNode;
|
|
currentTime: Date;
|
|
isHostConnected: boolean;
|
|
robotTarget: RobotTarget;
|
|
onTabChange: (tab: 'recipe' | 'motion' | 'camera' | 'setting' | 'initialize' | null) => void;
|
|
activeTab: 'recipe' | 'motion' | 'camera' | 'setting' | 'initialize' | null;
|
|
isLoading: boolean;
|
|
}
|
|
|
|
export const Layout: React.FC<LayoutProps> = ({
|
|
children,
|
|
currentTime,
|
|
isHostConnected,
|
|
robotTarget,
|
|
onTabChange,
|
|
activeTab,
|
|
isLoading
|
|
}) => {
|
|
return (
|
|
<div className="relative w-screen h-screen bg-slate-950 text-slate-100 overflow-hidden font-sans">
|
|
{/* Animated Nebula Background */}
|
|
<div className="absolute inset-0 bg-gradient-to-br from-slate-950 via-[#050a15] to-[#0a0f20] animate-gradient bg-[length:400%_400%] z-0"></div>
|
|
<div className="absolute inset-0 grid-bg opacity-30 z-0"></div>
|
|
<div className="absolute inset-0 scanlines z-50 pointer-events-none"></div>
|
|
|
|
{/* LOADING OVERLAY */}
|
|
{isLoading && (
|
|
<div className="absolute inset-0 z-[100] bg-black flex flex-col items-center justify-center gap-6">
|
|
<div className="relative">
|
|
<div className="w-24 h-24 border-4 border-neon-blue/30 rounded-full animate-spin"></div>
|
|
<div className="absolute inset-0 border-t-4 border-neon-blue rounded-full animate-spin"></div>
|
|
<div className="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 text-neon-blue text-2xl font-tech font-bold">●</div>
|
|
</div>
|
|
<div className="text-center">
|
|
<h2 className="text-2xl font-tech font-bold text-white tracking-widest mb-2">SYSTEM INITIALIZING</h2>
|
|
<p className="font-mono text-neon-blue text-sm animate-pulse">ESTABLISHING CONNECTION...</p>
|
|
</div>
|
|
</div>
|
|
)}
|
|
|
|
<Header
|
|
currentTime={currentTime}
|
|
onTabChange={onTabChange}
|
|
activeTab={activeTab}
|
|
/>
|
|
|
|
{/* Main Content Area */}
|
|
<div className="absolute inset-0 pt-20 pb-10 z-10">
|
|
{children}
|
|
</div>
|
|
|
|
<Footer isHostConnected={isHostConnected} robotTarget={robotTarget} />
|
|
</div>
|
|
);
|
|
};
|