From e7a3ed6982ed61881921dce4a68f42f7d410829b Mon Sep 17 00:00:00 2001 From: chihlasm Date: Fri, 13 Mar 2026 11:49:14 -0400 Subject: [PATCH] docs: add script library pane takeover design spec Co-Authored-By: Claude Sonnet 4.6 --- ...-13-script-library-pane-takeover-design.md | 190 ++++++++++++++++++ 1 file changed, 190 insertions(+) create mode 100644 docs/superpowers/specs/2026-03-13-script-library-pane-takeover-design.md diff --git a/docs/superpowers/specs/2026-03-13-script-library-pane-takeover-design.md b/docs/superpowers/specs/2026-03-13-script-library-pane-takeover-design.md new file mode 100644 index 00000000..3adcaf62 --- /dev/null +++ b/docs/superpowers/specs/2026-03-13-script-library-pane-takeover-design.md @@ -0,0 +1,190 @@ +# 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.