import { useMemo, useState } from 'react' import useAppStore from '../store/appStore' import { useProcesses } from '../hooks/useProcesses' import PreviewFrame from './PreviewFrame' import LogsPanel from './LogsPanel' import DbBrowserPanel from './DbBrowserPanel' import TerminalPanel from './TerminalPanel' export default function PreviewPanel() { const { runtime, project, templates } = useAppStore() const { status } = useProcesses() const [tab, setTab] = useState('preview') // 'preview' | 'logs' | 'db' const isRunning = status === 'running' // Resolve template's preview config (kind: frontend|backend, path). // Default to frontend:/ for templates that pre-date the preview block. const tplEntry = useMemo( () => templates.find((t) => t.id === project.template), [templates, project.template], ) const preview = tplEntry?.preview ?? { kind: 'frontend', path: '/' } const targetPort = preview.kind === 'backend' ? runtime.backendPort : runtime.frontendPort const iframeUrl = isRunning && targetPort ? `http://localhost:${targetPort}${preview.path || '/'}` : null return (
{/* ── Header — tabs only. Run / Stop / Reload / Open-in-browser all live in TopBar so they're visible from any panel. ───────────────── */}
{['preview', 'logs', 'db', 'terminal'].map((t) => ( ))}
{/* ── Body ─────────────────────────────────────────────────────────── */}
{/* Preview tab — always rendered so iframe keeps its state when switching tabs */}
{tab === 'logs' && (
)} {tab === 'db' && (
)} {/* Terminal stays mounted once visited so the PTY session survives tab switches. Rendered hidden when another tab is active. */} {tab === 'terminal' && (
)}
) }