diff --git a/docs/superpowers/plans/2026-05-19-app-detail-fixed-sidebar-scroll.md b/docs/superpowers/plans/2026-05-19-app-detail-fixed-sidebar-scroll.md new file mode 100644 index 00000000..297a872f --- /dev/null +++ b/docs/superpowers/plans/2026-05-19-app-detail-fixed-sidebar-scroll.md @@ -0,0 +1,150 @@ +# App Detail Fixed Sidebar Scroll Implementation Plan + +> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. + +**Goal:** Keep the app detail modal's left action/meta column fixed on desktop while the right detail/review column scrolls independently. + +**Architecture:** Reuse the existing `AppDetailModal.vue` popup and change only its internal layout classes/markers. The modal panel becomes a bounded, non-scrolling shell on desktop, while the right column becomes the desktop scroll container; mobile keeps the single-column scroll behavior. + +**Tech Stack:** Vue 3 SFC, Tailwind CSS utilities, Vitest, Testing Library Vue. + +--- + +## File Structure + +- Modify: `src/components/AppDetailModal.vue` - adjust modal shell, left column, right scroll column, and scroll reset target. +- Modify: `src/__tests__/unit/AppDetailModal.test.ts` - assert modal shell and scroll column contract. + +## Task 1: Add Layout Contract Test + +**Files:** +- Modify: `src/__tests__/unit/AppDetailModal.test.ts` + +- [ ] **Step 1: Add assertions to the popup modal test** + +In `src/__tests__/unit/AppDetailModal.test.ts`, update `renders detail content inside a popup-style modal overlay` so the body after the `.modal-panel` assertion is: + +```ts + const panel = overlay?.querySelector(".modal-panel"); + expect(panel).toBeTruthy(); + expect(panel?.className).toContain("overflow-hidden"); + expect(panel?.className).toContain("lg:max-h-[85vh]"); + expect(panel?.querySelector('[data-testid="detail-fixed-sidebar"]')).toBeTruthy(); + expect(panel?.querySelector('[data-testid="detail-scroll-content"]')).toBeTruthy(); + expect( + panel?.querySelector('[data-testid="detail-scroll-content"]')?.className, + ).toContain("lg:overflow-y-auto"); +``` + +- [ ] **Step 2: Run test to verify failure** + +Run: `npm run test -- --run src/__tests__/unit/AppDetailModal.test.ts` + +Expected: FAIL because `data-testid="detail-fixed-sidebar"`, `data-testid="detail-scroll-content"`, and the new modal classes are not present. + +## Task 2: Implement Fixed Sidebar Layout + +**Files:** +- Modify: `src/components/AppDetailModal.vue` +- Modify: `src/__tests__/unit/AppDetailModal.test.ts` + +- [ ] **Step 1: Update modal shell classes** + +In `src/components/AppDetailModal.vue`, change the `.modal-panel` class from: + +```vue +class="modal-panel relative w-full max-w-5xl max-h-[85vh] overflow-y-auto overscroll-contain scrollbar-nowidth rounded-3xl border border-white/10 bg-white/95 px-6 pb-6 shadow-2xl dark:border-slate-800 dark:bg-slate-900" +``` + +to: + +```vue +class="modal-panel relative flex w-full max-w-5xl max-h-[85vh] overflow-y-auto overscroll-contain scrollbar-nowidth rounded-3xl border border-white/10 bg-white/95 px-6 pb-6 shadow-2xl dark:border-slate-800 dark:bg-slate-900 lg:max-h-[85vh] lg:overflow-hidden lg:pb-0" +``` + +- [ ] **Step 2: Move the return button into the fixed sidebar** + +In `src/components/AppDetailModal.vue`, replace the top-level return button and main layout start with: + +```vue + +
+ +
+ +``` + +Remove the old sticky top-level return button and the old left column opening: + +```vue + + + + +
+ +
+``` + +- [ ] **Step 3: Make the right column the desktop scroll container** + +In `src/components/AppDetailModal.vue`, change the right column opening from: + +```vue +
+``` + +to: + +```vue +
+``` + +- [ ] **Step 4: Update scroll reset target if needed** + +In `src/App.vue`, keep the existing modal scroll reset selector if it still points at `.modal-panel`. If the right column needs reset instead, change the query to: + +```ts +const modal = document.querySelector( + '[data-app-modal="detail"] [data-testid="detail-scroll-content"]', +); +``` + +Use `modal.scrollTop = 0` as it does today. + +- [ ] **Step 5: Run focused test** + +Run: `npm run test -- --run src/__tests__/unit/AppDetailModal.test.ts` + +Expected: PASS. + +- [ ] **Step 6: Run build verification** + +Run: `npm run build:vite` + +Expected: PASS. + +- [ ] **Step 7: Commit implementation** + +Run: + +```bash +git add src/components/AppDetailModal.vue src/App.vue src/__tests__/unit/AppDetailModal.test.ts +git commit -m "fix(ui): pin detail modal sidebar" +``` + +Expected: commit succeeds.