Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 | 4x 4x 4x | import React, { useState } from 'react';
import { useLabState } from '../useLabState';
import {
Atom, Target, Volume2, Globe, BookOpen, FastForward, StopCircle,
Code2, Download, Bug, Maximize2, Minimize2, Cpu
} from 'lucide-react';
import { api } from '../api';
import { vscodeNative } from '../vscodeNative';
import MarkdownText from './MarkdownText';
export default function ContentHeader() {
const [isExpanded, setIsExpanded] = useState(false);
const {
selectedArtifact, setSelectedArtifact, isFullscreen, setIsFullscreen,
isSpeaking, currentObjective, webGroundingEnabled, setWebGroundingEnabled,
journalOpen, setJournalOpen, journalEntries, isAutoRunning, setIsAutoRunning,
isAutoLoopEnabled, setIsAutoLoopEnabled, isLoading, autonomyTimeoutRef,
timerIntervalRef, setIsWaitingForTelemetry, logAgentAction,
forceNextStep, cycleCount, setViewSource,
selectedModelObj, selectModelViaPicker,
} = useLabState();
return (
<div className={`shrink-0 border-b border-lab-border bg-lab-bg-secondary/90 backdrop-blur-md z-10 ${isFullscreen && !selectedArtifact ? 'hidden' : ''}`}>
<div className="flex items-center justify-between px-5 py-3">
<div className="flex items-center gap-4">
<div className="flex flex-col gap-2.5 max-w-2xl cursor-pointer" onClick={() => setIsExpanded(!isExpanded)}>
<div className="flex items-center gap-2.5">
<Atom className="w-5 h-5 text-lab-accent shrink-0" />
<div className={`text-sm font-bold tracking-tight text-lab-fg ${!isExpanded ? 'line-clamp-2' : ''}`}>
{selectedArtifact ? <MarkdownText content={selectedArtifact.prompt || selectedArtifact.content || ''} /> : 'Science Animator'}
</div>
</div>
</div>
{selectedArtifact && currentObjective.task && (
<span className="text-[9px] text-lab-warning font-bold uppercase tracking-wider flex items-center gap-1 px-2 py-0.5 bg-lab-warning/10 border border-amber-500/20 rounded-full">
<Target className="w-2.5 h-2.5" /> {currentObjective.task}
</span>
)}
{isSpeaking && (
<div className="flex items-center gap-1.5 px-2 py-0.5 bg-lab-accent/10 border border-lab-accent/20 rounded-full animate-pulse">
<Volume2 className="w-3 h-3 text-lab-accent" />
<span className="text-[8px] font-bold text-lab-accent uppercase">Audio</span>
</div>
)}
</div>
<div className="flex items-center gap-3">
<button onClick={selectModelViaPicker} className="flex items-center gap-1.5 px-2.5 py-1 rounded-lg border border-lab-border text-lab-fg-secondary hover:text-lab-fg hover:bg-lab-bg-elevated transition-all text-[9px] font-bold uppercase tracking-wide" title="Select Model">
<Cpu className="w-3.5 h-3.5" />
<span className="hidden md:inline">{selectedModelObj?.name || 'Select Model'}</span>
</button>
<button onClick={() => setWebGroundingEnabled(!webGroundingEnabled)} className={`p-1.5 rounded-lg transition-all ${webGroundingEnabled ? 'bg-blue-600 text-white ring-1 ring-blue-400/30' : 'text-lab-fg-secondary hover:text-lab-fg hover:bg-lab-bg-elevated'}`} title={webGroundingEnabled ? 'Web Grounding ON' : 'Web Grounding OFF'}>
<Globe className="w-3.5 h-3.5" />
</button>
<button onClick={() => setJournalOpen(!journalOpen)} className={`relative p-1.5 rounded-lg transition-all ${journalOpen ? 'bg-amber-600 text-white ring-1 ring-amber-400/30' : 'text-lab-fg-secondary hover:text-lab-fg hover:bg-lab-bg-elevated'}`} title={journalOpen ? 'Close Journal' : 'Research Journal'}>
<BookOpen className="w-3.5 h-3.5" />
{journalEntries.length > 0 && !journalOpen && <span className="absolute -top-0.5 -right-0.5 w-2 h-2 bg-lab-warning rounded-full" />}
</button>
<button onClick={() => {
if (isAutoRunning) {
setIsAutoRunning(false);
setIsAutoLoopEnabled(false);
if (autonomyTimeoutRef.current) { clearTimeout(autonomyTimeoutRef.current); autonomyTimeoutRef.current = null; }
if (timerIntervalRef.current) { clearInterval(timerIntervalRef.current); }
setIsWaitingForTelemetry(false);
logAgentAction("Loop Stop", "Stopped by user.");
} else if (selectedArtifact && !isLoading) {
setIsAutoLoopEnabled(true);
setIsAutoRunning(true);
forceNextStep();
}
}} disabled={isLoading && !isAutoRunning} className={`flex items-center gap-1.5 px-2.5 py-1 rounded-lg border transition-all text-[9px] font-bold uppercase tracking-wide ${isAutoRunning ? 'bg-lab-error/10 border-red-500/40 text-lab-error' : isAutoLoopEnabled ? 'bg-lab-warning/10 border-amber-500/40 text-lab-warning' : 'border-lab-border text-lab-fg-secondary hover:text-lab-fg'}`} title={isAutoRunning ? 'Stop Loop' : 'Advance Research'}>
{isAutoRunning ? <StopCircle className="w-3.5 h-3.5" /> : <FastForward className="w-3.5 h-3.5" />}
<span className="hidden md:inline">{isAutoRunning ? 'Stop' : 'Loop'}</span>
</button>
{selectedArtifact && (
<div className="flex items-center gap-1 pl-2 border-l border-lab-border">
<button onClick={() => setViewSource(selectedArtifact)} className="p-1.5 text-lab-fg-secondary hover:text-white rounded-lg hover:bg-lab-bg-elevated transition-colors" title="View Source"><Code2 className="w-3.5 h-3.5" /></button>
<button onClick={async () => { const blob = await api.exportSimulation(selectedArtifact.id, selectedArtifact.content); const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = `simulation-${selectedArtifact.id}.zip`; a.click(); URL.revokeObjectURL(url); }} className="p-1.5 text-lab-fg-secondary hover:text-white rounded-lg hover:bg-lab-bg-elevated transition-colors" title="Export Simulation"><Download className="w-3.5 h-3.5" /></button>
<button onClick={() => { alert('DevTools: Cmd+Option+I (macOS) or Ctrl+Shift+I'); }} className="p-1.5 text-lab-fg-secondary hover:text-white rounded-lg hover:bg-lab-bg-elevated transition-colors" title="Toggle DevTools"><Bug className="w-3.5 h-3.5" /></button>
<button onClick={() => setIsFullscreen(!isFullscreen)} className="p-1.5 text-lab-fg-secondary hover:text-white rounded-lg hover:bg-lab-bg-elevated transition-colors" title="Fullscreen">{isFullscreen ? <Minimize2 className="w-3.5 h-3.5" /> : <Maximize2 className="w-3.5 h-3.5" />}</button>
<button onClick={() => { setSelectedArtifact(null); setIsFullscreen(false); setIsAutoRunning(false); }} className="ml-1 px-2.5 py-1 bg-lab-bg-elevated hover:bg-lab-bg-elevated text-lab-fg-secondary text-[9px] font-bold rounded-md uppercase transition-colors">Close</button>
</div>
)}
</div>
</div>
</div>
);
}
|