'use client'; import type { ReactNode } from 'react'; import { ArrowLeft } from 'lucide-react'; import { useI18n } from '@/lib/hooks/use-i18n'; import { useRouter, useSearchParams } from 'next/navigation'; import type { StageMode } from '@/lib/types/stage'; import { classroomExitLabelKey, exitClassroom } from '@/lib/workbench/classroom-exit'; import { HeaderControls } from './stage/header-controls'; interface HeaderProps { readonly currentSceneTitle: string; readonly mode?: StageMode; readonly proModeActive?: boolean; readonly canEdit?: boolean; readonly onToggleEditMode?: () => void; /** Replaces the default back-to-home arrow as the header's leftmost control. `PlaybackChromeRoot` passes the workbench's return control here while a session is attached and full-screen playback is on, so the top-left back affordance becomes the back-to-workspace control instead of a home arrow (which would navigate away from the hosted classroom entirely). */ readonly backControl?: ReactNode; /** Drops the back slot entirely (no `backControl`, no home arrow). The embedded workbench form uses this: the conversation sits beside/above the classroom, so any back affordance here would duplicate the chat's own back and could exit the workbench. */ readonly hideBackControl?: boolean; /** Hide application-global controls in a workbench-attached classroom. */ readonly hideGlobalControls?: boolean; /** Hide course-level share/export in a workbench-attached classroom. */ readonly hideCourseActions?: boolean; } export function Header({ currentSceneTitle, mode, proModeActive, canEdit, onToggleEditMode, backControl, hideBackControl, hideGlobalControls, hideCourseActions, }: HeaderProps) { const { t } = useI18n(); const router = useRouter(); const searchParams = useSearchParams(); const exitLabel = t(classroomExitLabelKey(searchParams)); return ( <>
{hideBackControl ? null : (backControl ?? ( ))} {/* Title block — hidden when `mode === 'edit'`. Header lives inside `PlaybackChromeRoot`, which is unmounted by `Stage` once mode flips to 'edit', so in steady state this branch is always taken. The guard exists for the ~280ms AnimatePresence exit window where the playback chrome is still rendering its exit animation while `mode` has already flipped — without the guard, this title would briefly stack on top of the incoming EditChromeRoot's CommandBar title during the cross-fade. */} {mode !== 'edit' && (
{t('stage.currentScene')}

{currentSceneTitle || t('common.loading')}

)}
{/* Standalone classroom keeps the full cluster. Workbench-attached classrooms omit both the global capsule and course share/export. */}
); }