feat: rewrite ScriptLibraryPage with Browse/Configure pane modes

- Add paneMode state ('browse' | 'configure') local to page
- Move ScriptFilterBar inside left pane column (hidden in configure mode)
- inputValue owned at page level to survive mode transitions
- Left pane: ScriptFilterBar + ScriptTemplateList in browse; ScriptConfigurePane in configure
- Right pane: ScriptPreview only (read-only); empty state when no template selected
- canGenerate derived from usePermissions().isEngineer (matching ScriptGeneratorPanel pattern)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
chihlasm
2026-03-13 12:38:05 -04:00
parent da86136ef3
commit 16c0132b02

View File

@@ -1,19 +1,28 @@
import { useState, useEffect } from 'react'
import { Terminal } from 'lucide-react'
import { useScriptGeneratorStore } from '@/store/scriptGeneratorStore'
import { usePermissions } from '@/hooks/usePermissions'
import { ScriptFilterBar } from '@/components/scripts/ScriptFilterBar'
import { ScriptTemplateList } from '@/components/scripts/ScriptTemplateList'
import { ScriptGeneratorPanel } from '@/components/scripts/ScriptGeneratorPanel'
import { ScriptConfigurePane } from '@/components/scripts/ScriptConfigurePane'
import { ScriptPreview } from '@/components/scripts/ScriptPreview'
export default function ScriptLibraryPage() {
// inputValue is owned here so ScriptFilterBar and ScriptTemplateList
// can coordinate clear-search without direct coupling.
const [paneMode, setPaneMode] = useState<'browse' | 'configure'>('browse')
// inputValue owned here so it survives Configure ↔ Browse transitions
const [inputValue, setInputValue] = useState('')
const loadCategories = useScriptGeneratorStore(s => s.loadCategories)
const loadTemplates = useScriptGeneratorStore(s => s.loadTemplates)
const setSearch = useScriptGeneratorStore(s => s.setSearch)
const selectTemplate = useScriptGeneratorStore(s => s.selectTemplate)
const clearOutput = useScriptGeneratorStore(s => s.clearOutput)
const selectedTemplate = useScriptGeneratorStore(s => s.selectedTemplate)
const { isEngineer } = usePermissions()
const canGenerate = isEngineer
useEffect(() => {
// loadCategories must complete before loadTemplates can resolve slugs
loadCategories().then(() => loadTemplates())
}, [loadCategories, loadTemplates])
@@ -22,6 +31,16 @@ export default function ScriptLibraryPage() {
setSearch('')
}
const onConfigure = (id: string) => {
selectTemplate(id)
setPaneMode('configure')
}
const onBack = () => {
clearOutput()
setPaneMode('browse')
}
return (
<div className="flex flex-col gap-4 p-6 h-full">
{/* Page header */}
@@ -32,18 +51,37 @@ export default function ScriptLibraryPage() {
</p>
</div>
{/* Filter bar */}
<ScriptFilterBar inputValue={inputValue} setInputValue={setInputValue} />
{/* Two-column layout */}
<div className="grid grid-cols-[320px_1fr] gap-4 flex-1 min-h-0">
{/* Template list — scrollable */}
<div className="glass-card-static overflow-y-auto">
<ScriptTemplateList inputValue={inputValue} onClearSearch={onClearSearch} />
</div>
{/* Left pane — Browse or Configure mode */}
{paneMode === 'browse' ? (
<div className="glass-card-static flex flex-col overflow-hidden">
<div className="p-2 pb-0">
<ScriptFilterBar inputValue={inputValue} setInputValue={setInputValue} />
</div>
<div className="flex-1 overflow-y-auto">
<ScriptTemplateList
inputValue={inputValue}
onClearSearch={onClearSearch}
onConfigure={onConfigure}
/>
</div>
</div>
) : (
<ScriptConfigurePane canGenerate={canGenerate} onBack={onBack} />
)}
{/* Generator panel */}
<ScriptGeneratorPanel />
{/* Right pane — read-only ScriptPreview */}
{selectedTemplate === null ? (
<div className="glass-card-static h-full flex flex-col items-center justify-center gap-3 text-center p-8">
<Terminal size={40} className="text-muted-foreground/40" />
<p className="text-sm text-muted-foreground">Select a template to get started</p>
</div>
) : (
<div className="glass-card-static h-full overflow-hidden p-4">
<ScriptPreview />
</div>
)}
</div>
</div>
)