# Script Library — Left Pane Takeover Design Spec > **Created:** 2026-03-13 > **Feature:** Redesign Script Library left pane to have two distinct modes: Browse and Configure --- ## Overview The Script Library left pane gains two distinct modes. In **Browse mode** the user sees the full template list with filter bar and a "Configure →" button on each card. Clicking "Configure →" transitions the entire left pane to **Configure mode**, which replaces the list with a full-height view of the selected template's header, parameter form, and action buttons. The right pane (preview/output) is always visible. "Back to library" returns to Browse mode with filter/search state preserved. --- ## Goals - Make template selection intentional (no accidental click-to-configure) - Give the parameter form more vertical space - Keep the output preview always visible on the right - Preserve filter/search state across Browse ↔ Configure transitions --- ## Non-Goals - No changes to the right pane (`ScriptPreview`, `ScriptGeneratorPanel` output section) - No changes to the Zustand store shape or actions - No changes to the filter/search debounce logic - No changes to routing --- ## Left Pane — Two Modes ### Browse Mode Rendered when `selectedTemplate === null` OR when the user has returned via "Back to library". Layout (top to bottom, full pane height): 1. **Filter bar** (`ScriptFilterBar`) — category pills + search input, same as current 2. **Template list** (`ScriptTemplateList`) — scrollable, fills remaining height **TemplateCard changes:** - Remove the full-card `onClick` that calls `selectTemplate()` - Remove the active/selected visual state (`bg-primary/10 border-l-[3px]` etc.) — cards are never "selected" in browse mode, they are only "configured" - Add a **"Configure →"** button to each card (right-aligned, replaces the old click-anywhere behavior) - Style: `bg-primary/10 border border-primary/20 text-primary text-xs px-2.5 py-1 rounded-md hover:bg-primary/20 transition-colors` - On click: calls `selectTemplate(template.id)` then transitions pane to Configure mode - The rest of the card (name, description, tags, complexity badge) is non-interactive ### Configure Mode Rendered when `selectedTemplate !== null` (or `isLoadingDetail === true`). The entire left pane (including filter bar area) is replaced by the Configure view. No filter bar visible. Layout (top to bottom, full pane height, `overflow-y-auto`): 1. **Back button** — top of pane - `← Back to library` - Style: `flex items-center gap-1.5 text-xs text-muted-foreground hover:text-foreground transition-colors mb-4` - On click: calls `store.clearOutput()` then sets pane mode back to Browse (see State section) - Does NOT call `selectTemplate(null)` or clear `selectedTemplate` in the store — the store selection is preserved; only the pane view changes 2. **Template header** - Name: `text-base font-semibold font-heading text-foreground` - Description (if present): `text-sm text-muted-foreground mt-0.5` - Tag row: complexity badge + category name + template tags (first 3, overflow as `+N`) — same badge styles as current `TemplateCard` - `ShieldAlert` elevation icon if `requires_elevation` - Separator: `border-t border-border mt-3 pt-3` 3. **`ScriptParameterForm`** (existing component, `canGenerate` prop unchanged) 4. **Action bar** - **Generate** button: full-width, `bg-gradient-brand`, same disabled/loading behavior as current - **Download .ps1** + **Copy** buttons: side by side below Generate, each `flex-1` - Error text below if `generateError` is set - Warnings callout above Generate if `generationWarnings.length > 0` (same amber box as current) **Loading state:** When `isLoadingDetail === true`, the Configure pane shows a centered `` instead of the template content. Same as current panel behavior. --- ## State — Pane Mode Pane mode is **local React state** in `ScriptLibraryPage`, not the Zustand store. ```tsx const [paneMode, setPaneMode] = useState<'browse' | 'configure'>('browse') ``` Transitions: - `'browse' → 'configure'`: triggered by "Configure →" button click (after `selectTemplate()` call) - `'configure' → 'browse'`: triggered by "Back to library" button click **Filter/search preservation:** Filter bar state (`inputValue`, `setInputValue`, store's `activeCategoryId`, `searchQuery`) is untouched by pane mode transitions. The filter bar simply unmounts in configure mode and remounts with the same state in browse mode. **`isLoadingDetail` drives configure pane content, not pane mode.** When the user clicks "Configure →": 1. `selectTemplate(id)` is called (sets `isLoadingDetail: true` in store) 2. `setPaneMode('configure')` is called immediately — the user sees the loading spinner in configure mode, not a flash of browse mode 3. When `isLoadingDetail` becomes false, the full configure view renders --- ## Component Changes ### `ScriptLibraryPage.tsx` — Modified - Add `paneMode` state (`'browse' | 'configure'`) - Pass `onConfigure` callback to `ScriptTemplateList` (called with `template.id` on "Configure →" click) - `onConfigure` calls `selectTemplate(id)` then `setPaneMode('configure')` - Pass `onBack` callback to the configure pane - `onBack` calls `clearOutput()` then `setPaneMode('browse')` - Render left pane conditionally: - `paneMode === 'browse'`: `ScriptFilterBar` + `ScriptTemplateList` - `paneMode === 'configure'`: new `ScriptConfigurePane` component ### `TemplateCard.tsx` — Modified - Remove `onClick` on the card root button; change root element to `
` - Remove `isActive` / active border-l styling - Add "Configure →" button ### `ScriptTemplateList.tsx` — Modified - Accept `onConfigure: (id: string) => void` prop - Pass it to each `TemplateCard` ### `ScriptConfigurePane.tsx` — New Component Encapsulates the configure mode layout: - Back button → calls `onBack` prop - Template header (name, description, tags, complexity, elevation) - Loading spinner when `isLoadingDetail` - `ScriptParameterForm` (with `canGenerate`) - Warnings callout - Action bar: Generate (full-width), Download .ps1 + Copy (side-by-side below) - Error text Props: ```tsx interface Props { canGenerate: boolean onBack: () => void } ``` All data read directly from Zustand store (`selectedTemplate`, `isLoadingDetail`, `generatedScript`, etc.). ### `ScriptGeneratorPanel.tsx` — Removed (or repurposed) The current `ScriptGeneratorPanel` is superseded by `ScriptConfigurePane`. It should be deleted; its logic is absorbed into `ScriptConfigurePane`. --- ## Visual Spec ### Configure Pane — action bar ``` ┌─────────────────────────────────┐ │ [Generate Script] │ ← full-width, bg-gradient-brand │ [Download .ps1] [Copy] │ ← side-by-side, flex-1 each │ │ └─────────────────────────────────┘ ``` ### "Configure →" button on TemplateCard ``` ┌──────────────────────────────────────────────────┐ │ Restart Windows Service [Beginner] 🛡 │ │ Stops and restarts a named service │ │ services windows +1 [Configure →]│ └──────────────────────────────────────────────────┘ ``` --- ## Affected Files | File | Change | |------|--------| | `frontend/src/pages/ScriptLibraryPage.tsx` | Add `paneMode` state, `onConfigure`/`onBack` callbacks, conditional left-pane render | | `frontend/src/components/scripts/TemplateCard.tsx` | Remove full-card click, add "Configure →" button | | `frontend/src/components/scripts/ScriptTemplateList.tsx` | Accept + thread `onConfigure` prop | | `frontend/src/components/scripts/ScriptConfigurePane.tsx` | New — configure mode layout | | `frontend/src/components/scripts/ScriptGeneratorPanel.tsx` | Delete — superseded by `ScriptConfigurePane` | No store changes. No API changes. No routing changes.