152 lines
6.2 KiB
TypeScript
152 lines
6.2 KiB
TypeScript
import React from 'react';
|
|
import { Phase, Language, Theme } from '../types';
|
|
import { Activity, Target, Crosshair, Map, FileText, CheckCircle, Lock, Moon, Sun, Languages, ShieldCheck, Terminal } from 'lucide-react';
|
|
|
|
interface LayoutProps {
|
|
currentPhase: Phase;
|
|
maxAllowedPhase: Phase;
|
|
onPhaseSelect: (phase: Phase) => void;
|
|
children: React.ReactNode;
|
|
theme: Theme;
|
|
toggleTheme: () => void;
|
|
language: Language;
|
|
setLanguage: (lang: Language) => void;
|
|
labels: any;
|
|
}
|
|
|
|
const getStepIcon = (id: Phase) => {
|
|
switch(id) {
|
|
case Phase.Input: return Terminal;
|
|
case Phase.ProductAnalysis: return Activity;
|
|
case Phase.ICPDiscovery: return Target;
|
|
case Phase.WhaleHunting: return Crosshair;
|
|
case Phase.Strategy: return Map;
|
|
case Phase.AssetGeneration: return FileText;
|
|
case Phase.SalesEnablement: return ShieldCheck;
|
|
default: return Activity;
|
|
}
|
|
}
|
|
|
|
export const Layout: React.FC<LayoutProps> = ({
|
|
currentPhase,
|
|
maxAllowedPhase,
|
|
onPhaseSelect,
|
|
children,
|
|
theme,
|
|
toggleTheme,
|
|
language,
|
|
setLanguage,
|
|
labels
|
|
}) => {
|
|
|
|
const steps = [
|
|
{ id: Phase.Input, label: labels.initTitle ? 'Input' : 'Input' }, // Fallback label
|
|
{ id: Phase.ProductAnalysis, label: labels.phase1 },
|
|
{ id: Phase.ICPDiscovery, label: labels.phase2 },
|
|
{ id: Phase.WhaleHunting, label: labels.phase3 },
|
|
{ id: Phase.Strategy, label: labels.phase4 },
|
|
{ id: Phase.AssetGeneration, label: labels.phase5 },
|
|
{ id: Phase.SalesEnablement, label: labels.phase6 },
|
|
];
|
|
|
|
return (
|
|
<div className={`min-h-screen flex font-sans transition-colors duration-300 ${theme === 'dark' ? 'dark bg-robo-900 text-slate-200' : 'bg-slate-50 text-slate-900'}`}>
|
|
{/* Sidebar */}
|
|
<div className="w-80 border-r flex-shrink-0 flex flex-col transition-colors duration-300
|
|
bg-white border-slate-200
|
|
dark:bg-robo-800 dark:border-robo-700
|
|
">
|
|
<div className="p-6 border-b transition-colors duration-300 border-slate-200 dark:border-robo-700">
|
|
<h1 className="text-xl font-bold font-mono tracking-tighter flex items-center gap-2 text-slate-900 dark:text-white">
|
|
<div className="w-3 h-3 bg-robo-500 dark:bg-robo-accent rounded-full animate-pulse"></div>
|
|
ROBOPLANET
|
|
</h1>
|
|
<p className="text-xs mt-1 uppercase tracking-widest text-slate-500 dark:text-robo-400">GTM Architect Engine</p>
|
|
</div>
|
|
|
|
<div className="px-4 py-4 flex gap-2">
|
|
<button
|
|
onClick={toggleTheme}
|
|
className="flex-1 flex items-center justify-center gap-2 p-2 rounded-md text-sm font-medium transition-colors
|
|
bg-slate-100 hover:bg-slate-200 text-slate-700
|
|
dark:bg-robo-900 dark:hover:bg-robo-700 dark:text-slate-300"
|
|
>
|
|
{theme === 'light' ? <Moon size={16}/> : <Sun size={16}/>}
|
|
{theme === 'light' ? 'Dark' : 'Light'}
|
|
</button>
|
|
<button
|
|
onClick={() => setLanguage(language === 'en' ? 'de' : 'en')}
|
|
className="flex-1 flex items-center justify-center gap-2 p-2 rounded-md text-sm font-medium transition-colors
|
|
bg-slate-100 hover:bg-slate-200 text-slate-700
|
|
dark:bg-robo-900 dark:hover:bg-robo-700 dark:text-slate-300"
|
|
>
|
|
<Languages size={16}/>
|
|
{language.toUpperCase()}
|
|
</button>
|
|
</div>
|
|
|
|
<nav className="flex-1 p-4 space-y-2 overflow-y-auto">
|
|
{steps.map((step) => {
|
|
const isActive = currentPhase === step.id;
|
|
const isCompleted = currentPhase > step.id;
|
|
const isUnlocked = step.id <= maxAllowedPhase;
|
|
const Icon = getStepIcon(step.id);
|
|
|
|
return (
|
|
<button
|
|
key={step.id}
|
|
onClick={() => isUnlocked && onPhaseSelect(step.id)}
|
|
disabled={!isUnlocked}
|
|
className={`w-full flex items-center gap-3 p-3 rounded-lg transition-all border text-left
|
|
${isActive
|
|
? 'bg-blue-50 border-blue-200 text-blue-700 shadow-sm dark:bg-robo-700 dark:border-robo-500 dark:text-white dark:shadow-lg'
|
|
: isUnlocked
|
|
? 'border-transparent text-slate-600 hover:bg-slate-100 cursor-pointer dark:text-slate-300 dark:hover:bg-robo-700/50'
|
|
: 'border-transparent text-slate-300 dark:text-slate-600 cursor-not-allowed'
|
|
}
|
|
${isCompleted && !isActive ? 'text-emerald-600 dark:text-emerald-400' : ''}
|
|
`}
|
|
>
|
|
<div className={`p-2 rounded-md transition-colors ${
|
|
isActive
|
|
? 'bg-blue-100 dark:bg-robo-500 text-blue-600 dark:text-white'
|
|
: isUnlocked && !isActive
|
|
? 'bg-slate-200 dark:bg-robo-900 text-slate-600 dark:text-slate-400'
|
|
: 'bg-slate-100 dark:bg-robo-900/50'
|
|
}`}>
|
|
{isCompleted ? <CheckCircle size={16} /> : <Icon size={16} />}
|
|
</div>
|
|
<div className="flex-1">
|
|
<div className="text-xs font-bold uppercase tracking-wider opacity-70">
|
|
{step.id === 0 ? 'Start' : `Phase 0${step.id}`}
|
|
</div>
|
|
<div className="font-medium text-sm truncate">{step.label}</div>
|
|
</div>
|
|
{!isUnlocked && <Lock size={12} className="opacity-30" />}
|
|
</button>
|
|
);
|
|
})}
|
|
</nav>
|
|
|
|
<div className="p-4 border-t text-xs font-mono transition-colors duration-300
|
|
border-slate-200 text-slate-400
|
|
dark:border-robo-700 dark:text-slate-500
|
|
">
|
|
System Status: ONLINE<br/>
|
|
Language: {language.toUpperCase()}<br/>
|
|
Mode: {theme.toUpperCase()}
|
|
</div>
|
|
</div>
|
|
|
|
{/* Main Content */}
|
|
<main className="flex-1 overflow-y-auto relative transition-colors duration-300
|
|
bg-slate-50
|
|
dark:bg-gradient-to-br dark:from-robo-900 dark:to-[#0b1120]
|
|
">
|
|
<div className="max-w-5xl mx-auto p-8 pb-32">
|
|
{children}
|
|
</div>
|
|
</main>
|
|
</div>
|
|
);
|
|
}; |