'use client' import { useEffect, useState, useRef } from 'react' import { useRouter } from 'next/navigation' import { useStore } from '@/lib/store' import { Sidebar } from './Sidebar' import { KeyboardShortcutsProvider, useUserShortcuts } from '@/hooks/useKeyboardShortcuts' import { Bell, Search, X, Command } from 'lucide-react' import Link from 'next/link' import clsx from 'clsx' interface TerminalLayoutProps { children: React.ReactNode title?: string subtitle?: string actions?: React.ReactNode hideHeaderSearch?: boolean // New prop to control header elements } export function TerminalLayout({ children, title, subtitle, actions, hideHeaderSearch = false }: TerminalLayoutProps) { const router = useRouter() const { isAuthenticated, isLoading, checkAuth, domains } = useStore() const [sidebarCollapsed, setSidebarCollapsed] = useState(false) const [notificationsOpen, setNotificationsOpen] = useState(false) const [searchOpen, setSearchOpen] = useState(false) const [searchQuery, setSearchQuery] = useState('') const [mounted, setMounted] = useState(false) const authCheckedRef = useRef(false) // Ensure component is mounted before rendering useEffect(() => { setMounted(true) }, []) // Load sidebar state from localStorage useEffect(() => { if (mounted) { const saved = localStorage.getItem('sidebar-collapsed') if (saved) { setSidebarCollapsed(saved === 'true') } } }, [mounted]) // Check auth only once on mount useEffect(() => { if (!authCheckedRef.current) { authCheckedRef.current = true checkAuth() } }, [checkAuth]) useEffect(() => { if (!isLoading && !isAuthenticated) { router.push('/login') } }, [isLoading, isAuthenticated, router]) // Available domains for notifications const availableDomains = domains?.filter(d => d.is_available) || [] const hasNotifications = availableDomains.length > 0 // Show loading only if we're still checking auth if (!mounted || isLoading) { return (

Loading Terminal...

) } if (!isAuthenticated) { return null } return (
{/* Background Effects */}
{/* Sidebar */} {/* Main Content Area */}
{/* Top Bar - No longer sticky if hideHeaderSearch is true, or generally refined */}
{/* Left: Title */}
{title && (

{title}

)} {subtitle && (

{subtitle}

)}
{/* Right: Actions */}
{!hideHeaderSearch && ( <> {/* Quick Search */} {/* Mobile Search */} {/* Notifications */}
{/* Notifications Dropdown */} {notificationsOpen && (

Notifications

{availableDomains.length > 0 ? (
{availableDomains.slice(0, 5).map((domain) => ( setNotificationsOpen(false)} className="flex items-start gap-3 p-3 hover:bg-white/5 rounded-lg transition-colors" >

{domain.name}

Available now!

))}
) : (

No notifications

We'll notify you when domains become available

)}
)}
{/* Keyboard Shortcuts Hint */} )} {/* Custom Actions */} {actions}
{/* Page Content */}
{children}
{/* Quick Search Modal - Only if not hidden, or maybe still available via hotkey? Let's keep it available via hotkey but hidden from UI if requested */} {searchOpen && (
setSearchOpen(false)} >
e.stopPropagation()} >
setSearchQuery(e.target.value)} className="flex-1 bg-transparent text-foreground placeholder:text-foreground-subtle outline-none text-lg" autoFocus />
Start typing to search...
)} {/* Keyboard shortcut for search - Still active unless strictly disabled */} setSearchOpen(true)} keys={['Meta', 'k']} />
) } // Keyboard shortcut component function KeyboardShortcut({ onTrigger, keys }: { onTrigger: () => void, keys: string[] }) { useEffect(() => { const handler = (e: KeyboardEvent) => { if (keys.includes('Meta') && e.metaKey && e.key === 'k') { e.preventDefault() onTrigger() } } document.addEventListener('keydown', handler) return () => document.removeEventListener('keydown', handler) }, [onTrigger, keys]) return null } // User shortcuts wrapper function UserShortcutsWrapper() { useUserShortcuts() return null }