diff --git a/.gsd/milestones/M006/M006-ROADMAP.md b/.gsd/milestones/M006/M006-ROADMAP.md new file mode 100644 index 0000000..cf1ba93 --- /dev/null +++ b/.gsd/milestones/M006/M006-ROADMAP.md @@ -0,0 +1,14 @@ +# M006: + +## Vision +Consolidate admin navigation into a dropdown, add head/tail log viewing and commit SHA tracking to the pipeline, clean up technique page tag styling and sidebar order, redesign the Topics browse page with a Music Theory category, and add app version footer. + +## Slice Overview +| ID | Slice | Risk | Depends | Done | After this | +|----|-------|------|---------|------|------------| +| S01 | Admin Navigation Dropdown + Header Cleanup | low | — | ⬜ | Header shows Home, Topics, Creators, and an Admin dropdown. Clicking Admin reveals Review, Reports, Pipeline links. ModeToggle removed from header. | +| S02 | Pipeline Page: Head/Tail Log View + Token Count | low | — | ⬜ | Pipeline event log shows Head/Tail toggle buttons. Head shows first N events, Tail shows last N events. Token counts visible per event and per video. | +| S03 | Git Commit SHA in Pipeline Version Metadata | low | — | ⬜ | Running the pipeline captures the current git commit SHA. Viewing a technique page version shows the commit hash in the metadata panel. | +| S04 | Technique Page: Sidebar Reorder, Creator Emphasis, Tag Polish | medium | — | ⬜ | Technique page sidebar shows Plugins Referenced at top. Creator name is visually prominent. Tags use a coherent color system. | +| S05 | Topics Page Redesign + Music Theory Category | high | — | ⬜ | Topics page shows 7 categories (including Music Theory) with an improved visual layout — category cards with descriptions, sub-topic counts, better structure. | +| S06 | App Footer with Version Info | low | — | ⬜ | Every page shows a subtle footer with app version, build date, and optional repo link. | diff --git a/.gsd/milestones/M006/slices/S01/S01-PLAN.md b/.gsd/milestones/M006/slices/S01/S01-PLAN.md new file mode 100644 index 0000000..a3f759d --- /dev/null +++ b/.gsd/milestones/M006/slices/S01/S01-PLAN.md @@ -0,0 +1,34 @@ +# S01: Admin Navigation Dropdown + Header Cleanup + +**Goal:** Header nav shows Home, Topics, Creators as flat links and an Admin dropdown. Clicking Admin reveals Review, Reports, Pipeline links. ModeToggle removed from header (kept on ReviewQueue page). +**Demo:** After this: Header shows Home, Topics, Creators, and an Admin dropdown. Clicking Admin reveals Review, Reports, Pipeline links. ModeToggle removed from header. + +## Tasks +- [x] **T01: Created AdminDropdown component with click-outside/Escape close, wired into App.tsx header replacing 3 admin links + ModeToggle, added dropdown CSS using existing theme tokens** — Create an AdminDropdown React component, replace the 3 admin nav links and ModeToggle in App.tsx, and add dropdown CSS to App.css. + +**Context:** The header in `App.tsx` currently has 6 flat `` elements (Home, Topics, Creators, Review, Reports, Pipeline) plus a ``. Goal: group the 3 admin links behind an "Admin" dropdown, remove ModeToggle from the header. ModeToggle is still used by `ReviewQueue.tsx` — do NOT delete the component or its CSS. + +**Click-outside pattern** — adapt from `Home.tsx` (typeahead): +```tsx +const dropdownRef = useRef(null); +useEffect(() => { + function handler(e: MouseEvent) { + if (dropdownRef.current && !dropdownRef.current.contains(e.target as Node)) { + setOpen(false); + } + } + document.addEventListener("mousedown", handler); + return () => document.removeEventListener("mousedown", handler); +}, []); +``` + +**CSS variables available** (all defined in App.css `:root`): +- Trigger text: `--color-text-on-header` / `--color-text-on-header-hover` +- Dropdown background: `--color-bg-surface` +- Border: `--color-border` +- Shadow: `--color-shadow-heavy` +- Item hover bg: `--color-bg-surface-hover` +- Item text: `--color-text-primary` + - Estimate: 30m + - Files: frontend/src/components/AdminDropdown.tsx, frontend/src/App.tsx, frontend/src/App.css + - Verify: cd frontend && npx tsc --noEmit && npx vite build diff --git a/.gsd/milestones/M006/slices/S01/S01-RESEARCH.md b/.gsd/milestones/M006/slices/S01/S01-RESEARCH.md new file mode 100644 index 0000000..9c8ff5c --- /dev/null +++ b/.gsd/milestones/M006/slices/S01/S01-RESEARCH.md @@ -0,0 +1,124 @@ +# S01 Research — Admin Navigation Dropdown + Header Cleanup + +## Summary + +Straightforward frontend slice. The header nav in `App.tsx` currently shows 6 flat links (Home, Topics, Creators, Review, Reports, Pipeline) plus a `ModeToggle` component. The goal: group the 3 admin links (Review, Reports, Pipeline) behind an "Admin" dropdown, and remove `ModeToggle` from the header (it stays on the ReviewQueue page). + +No new dependencies needed. No backend changes. No library lookups required — the codebase already has a click-outside dropdown pattern in `Home.tsx` (typeahead) that can be adapted. + +## Recommendation + +Single task. All changes are in 2 files (`App.tsx`, `App.css`) plus optionally extracting the dropdown into a small component. The ModeToggle component file itself is NOT deleted — it's still imported by `ReviewQueue.tsx`. + +## Implementation Landscape + +### Current State + +**`frontend/src/App.tsx`** — The app shell. Header contains: +- Brand link (`Chrysopedia`) +- `
` containing: + - ` -
diff --git a/frontend/src/components/AdminDropdown.tsx b/frontend/src/components/AdminDropdown.tsx new file mode 100644 index 0000000..f626c65 --- /dev/null +++ b/frontend/src/components/AdminDropdown.tsx @@ -0,0 +1,73 @@ +import { useEffect, useRef, useState } from "react"; +import { Link } from "react-router-dom"; + +export default function AdminDropdown() { + const [open, setOpen] = useState(false); + const dropdownRef = useRef(null); + + // Close on outside click + useEffect(() => { + function handler(e: MouseEvent) { + if ( + dropdownRef.current && + !dropdownRef.current.contains(e.target as Node) + ) { + setOpen(false); + } + } + document.addEventListener("mousedown", handler); + return () => document.removeEventListener("mousedown", handler); + }, []); + + // Close on Escape + useEffect(() => { + function handler(e: KeyboardEvent) { + if (e.key === "Escape") setOpen(false); + } + if (open) { + document.addEventListener("keydown", handler); + return () => document.removeEventListener("keydown", handler); + } + }, [open]); + + return ( +
+ + {open && ( +
+ setOpen(false)} + > + Review + + setOpen(false)} + > + Reports + + setOpen(false)} + > + Pipeline + +
+ )} +
+ ); +}