diff --git a/.gsd/milestones/M006/M006-ROADMAP.md b/.gsd/milestones/M006/M006-ROADMAP.md index d989b6c..711eca0 100644 --- a/.gsd/milestones/M006/M006-ROADMAP.md +++ b/.gsd/milestones/M006/M006-ROADMAP.md @@ -8,7 +8,7 @@ Consolidate admin navigation into a dropdown, add head/tail log viewing and comm |----|-------|------|---------|------|------------| | 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. | +| 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/S03/S03-SUMMARY.md b/.gsd/milestones/M006/slices/S03/S03-SUMMARY.md new file mode 100644 index 0000000..4db9d32 --- /dev/null +++ b/.gsd/milestones/M006/slices/S03/S03-SUMMARY.md @@ -0,0 +1,88 @@ +--- +id: S03 +parent: M006 +milestone: M006 +provides: + - git_commit_sha in pipeline_metadata dict + - Commit row in version metadata panel +requires: + [] +affects: + - S06 +key_files: + - docker/Dockerfile.api + - docker-compose.yml + - backend/config.py + - backend/pipeline/stages.py + - frontend/src/pages/TechniquePage.tsx +key_decisions: + - 4-tier SHA resolution: .git-commit file → git rev-parse → env/config → unknown + - Hide unknown SHA from UI — only render Commit row when a real hash was captured +patterns_established: + - Docker build-arg → file → runtime reader pattern for baking build-time metadata into containers +observability_surfaces: + - none +drill_down_paths: + - .gsd/milestones/M006/slices/S03/tasks/T01-SUMMARY.md + - .gsd/milestones/M006/slices/S03/tasks/T02-SUMMARY.md +duration: "" +verification_result: passed +completed_at: 2026-03-30T11:26:49.606Z +blocker_discovered: false +--- + +# S03: Git Commit SHA in Pipeline Version Metadata + +**Pipeline now captures the git commit SHA at Docker build time and displays it in the technique page version metadata panel.** + +## What Happened + +Two tasks delivered the full vertical slice — backend SHA capture and frontend display. + +T01 added a `GIT_COMMIT_SHA` build arg to `Dockerfile.api` that writes the SHA to `/app/.git-commit` at build time. Both `chrysopedia-api` and `chrysopedia-worker` compose services pass this arg. A new `_get_git_commit_sha()` helper in `stages.py` resolves the SHA through a 4-tier fallback chain: (1) read `/app/.git-commit`, (2) run `git rev-parse --short HEAD`, (3) read `GIT_COMMIT_SHA` env var / config setting, (4) return `"unknown"`. The `_capture_pipeline_metadata()` function now includes `git_commit_sha` in its return dict. + +T02 added a conditional "Commit" row to the version metadata panel in `TechniquePage.tsx`. It reuses the existing `version-metadata__hash-value` monospace styling and displays only the first 7 characters. When the SHA is `"unknown"` (i.e., the image wasn't built with the arg), the row is hidden entirely. + +Verified: frontend builds with zero errors, `_capture_pipeline_metadata()` returns `git_commit_sha` key inside the running container. Currently returns `"unknown"` because the running containers pre-date the Dockerfile change — a `docker compose build` with `GIT_COMMIT_SHA=$(git rev-parse --short HEAD)` will bake in a real SHA. + +## Verification + +1. `ssh ub01 'cd /vmPool/r/repos/xpltdco/chrysopedia/frontend && npm run build 2>&1 | tail -5'` — exit 0, clean build in 696ms +2. `docker exec chrysopedia-api python -c "from pipeline.stages import _capture_pipeline_metadata; ..."` — exit 0, git_commit_sha key present with "unknown" fallback +3. Grep confirmed all 5 files contain the expected code changes on ub01 + +## Requirements Advanced + +None. + +## Requirements Validated + +None. + +## New Requirements Surfaced + +None. + +## Requirements Invalidated or Re-scoped + +None. + +## Deviations + +T02 added a filter to hide "unknown" SHA from the UI — not in the original plan but a sensible UX decision (showing literal "unknown" is meaningless to users). + +## Known Limitations + +Running containers still use the old image without .git-commit baked in. A `docker compose build --build-arg GIT_COMMIT_SHA=$(git rev-parse --short HEAD)` is needed to see real SHAs. This is expected — the build/deploy step is outside slice scope. + +## Follow-ups + +Consider adding GIT_COMMIT_SHA to the CI/CD build command or a Makefile target so rebuilds automatically capture the SHA. + +## Files Created/Modified + +- `docker/Dockerfile.api` — Added GIT_COMMIT_SHA build arg and RUN echo to write SHA to /app/.git-commit +- `docker-compose.yml` — Added GIT_COMMIT_SHA build arg to both chrysopedia-api and chrysopedia-worker services +- `backend/config.py` — Added git_commit_sha field to Settings class with 'unknown' default +- `backend/pipeline/stages.py` — Added _get_git_commit_sha() helper with 4-tier fallback; added git_commit_sha to _capture_pipeline_metadata() +- `frontend/src/pages/TechniquePage.tsx` — Added conditional Commit row to version metadata panel with 7-char abbreviated SHA diff --git a/.gsd/milestones/M006/slices/S03/S03-UAT.md b/.gsd/milestones/M006/slices/S03/S03-UAT.md new file mode 100644 index 0000000..34bafce --- /dev/null +++ b/.gsd/milestones/M006/slices/S03/S03-UAT.md @@ -0,0 +1,57 @@ +# S03: Git Commit SHA in Pipeline Version Metadata — UAT + +**Milestone:** M006 +**Written:** 2026-03-30T11:26:49.606Z + +## UAT: Git Commit SHA in Pipeline Version Metadata + +### Preconditions +- Chrysopedia stack running on ub01 (`docker ps --filter name=chrysopedia` shows all services) +- At least one technique page exists with version data (from a prior pipeline run) +- Access to ub01 via SSH + +### Test 1: Backend — SHA present in pipeline metadata +**Steps:** +1. SSH to ub01 +2. Run: `docker exec chrysopedia-api python -c "from pipeline.stages import _capture_pipeline_metadata; import json; m = _capture_pipeline_metadata(); print(json.dumps(m, indent=2))"` +3. Verify output contains `"git_commit_sha"` key + +**Expected:** Key is present. Value is `"unknown"` on current containers (pre-rebuild) or a 7+ char hex string after rebuild. + +### Test 2: Backend — SHA resolution fallback chain +**Steps:** +1. Run: `docker exec chrysopedia-api python -c "from pipeline.stages import _get_git_commit_sha; print(repr(_get_git_commit_sha()))"` +2. Verify returns a string (not None, not an exception) + +**Expected:** Returns `'unknown'` in current container (no .git-commit file, no git binary). After `docker compose build --build-arg GIT_COMMIT_SHA=$(git rev-parse --short HEAD)`, returns the actual short SHA. + +### Test 3: Frontend — Build succeeds with commit SHA rendering code +**Steps:** +1. SSH to ub01 +2. Run: `cd /vmPool/r/repos/xpltdco/chrysopedia/frontend && npm run build` +3. Verify exit code 0, no TypeScript errors + +**Expected:** Clean build, zero errors. + +### Test 4: Frontend — Commit row hidden when SHA is "unknown" +**Steps:** +1. Open http://ub01:8096 in browser +2. Navigate to any technique page with version history +3. Expand a version's metadata panel +4. Look for a "Commit" row + +**Expected:** No "Commit" row visible (current containers have "unknown" SHA, which is filtered out). + +### Test 5: Frontend — Commit row visible after rebuild with real SHA +**Precondition:** Rebuild images with SHA: `cd /vmPool/r/repos/xpltdco/chrysopedia && GIT_COMMIT_SHA=$(git rev-parse --short HEAD) docker compose build chrysopedia-api && docker compose up -d` +**Steps:** +1. Re-run the pipeline on any video (or wait for next scheduled run) +2. Navigate to the resulting technique page's version metadata panel +3. Look for a "Commit" row + +**Expected:** "Commit" row shows a 7-character hex string (e.g., `a1b2c3d`), rendered in monospace font matching the prompt hash styling. + +### Edge Cases +- **No version data:** Technique pages without version history don't show the metadata panel at all — no crash expected. +- **SHA longer than 7 chars:** Display truncates to first 7 characters regardless of full SHA length. +- **Empty string SHA:** Treated same as any non-"unknown" value — would show empty code tag. Low risk since the fallback chain always produces either a real SHA or "unknown". diff --git a/.gsd/milestones/M006/slices/S03/tasks/T02-VERIFY.json b/.gsd/milestones/M006/slices/S03/tasks/T02-VERIFY.json new file mode 100644 index 0000000..b1af370 --- /dev/null +++ b/.gsd/milestones/M006/slices/S03/tasks/T02-VERIFY.json @@ -0,0 +1,18 @@ +{ + "schemaVersion": 1, + "taskId": "T02", + "unitId": "M006/S03/T02", + "timestamp": 1774869947205, + "passed": false, + "discoverySource": "task-plan", + "checks": [ + { + "command": "ssh ub01 'cd /vmPool/r/repos/xpltdco/chrysopedia/frontend", + "exitCode": 2, + "durationMs": 7, + "verdict": "fail" + } + ], + "retryAttempt": 1, + "maxRetries": 2 +} diff --git a/.gsd/milestones/M006/slices/S04/S04-PLAN.md b/.gsd/milestones/M006/slices/S04/S04-PLAN.md index e2b74bd..b64c138 100644 --- a/.gsd/milestones/M006/slices/S04/S04-PLAN.md +++ b/.gsd/milestones/M006/slices/S04/S04-PLAN.md @@ -1,6 +1,95 @@ # S04: Technique Page: Sidebar Reorder, Creator Emphasis, Tag Polish -**Goal:** Improve technique page visual hierarchy: plugins first in sidebar, creator stands out, tags make sense +**Goal:** Technique page sidebar shows Plugins Referenced at top. Creator name is visually prominent in a dedicated row. Category badges use per-category colors. **Demo:** After this: Technique page sidebar shows Plugins Referenced at top. Creator name is visually prominent. Tags use a coherent color system. ## Tasks +- [x] **T01: Reordered technique page sidebar (plugins first), added prominent creator block with genre pills, and implemented per-category badge color system with 6 category-specific color pairs** — Single task covering all three S04 concerns in TechniquePage.tsx and App.css. + +## Steps + +1. **Sidebar reorder in TechniquePage.tsx** (~line 408–510 in the sidebar column): + - Move the `{displayPlugins && displayPlugins.length > 0 && (
...
)}` JSX block so it appears FIRST inside `
`, before the key moments section. + - Final sidebar order: Plugins Referenced → Key Moments → Signal Chains → Related Techniques. + +2. **Creator emphasis in TechniquePage.tsx** (~line 232–248, the `technique-header__meta` div): + - Remove the `` from inside `technique-header__meta`. + - Add a new `
` between the `

` title and the `technique-header__meta` div. + - Inside the creator block, render: + ```tsx + {technique.creator_info && ( +
+ + {technique.creator_info.name} + + {technique.creator_info.genres && technique.creator_info.genres.length > 0 && ( + + {technique.creator_info.genres.map((g) => ( + {g} + ))} + + )} +
+ )} + ``` + +3. **Creator emphasis CSS in App.css** (after the existing `.technique-header__title` styles, ~line 1296): + - Add `.technique-header__creator-block` — `display: flex; align-items: center; gap: 0.5rem; flex-wrap: wrap; margin-bottom: 0.5rem;` + - Add `.technique-header__creator-link` — `font-size: 1.125rem; font-weight: 600; color: var(--color-link-accent); text-decoration: none;` + - Add `.technique-header__creator-link:hover` — `text-decoration: underline; color: var(--color-accent-hover);` + - Add `.pill--genre-small` — `font-size: 0.625rem; padding: 0.0625rem 0.375rem; background: var(--color-pill-bg); color: var(--color-text-secondary);` + - Remove the old `.technique-header__creator` and `.technique-header__creator:hover` rules. + +4. **Category color variables in App.css** (add to the `:root` block, after the existing `--color-badge-category-*` variables): + ```css + /* Per-category badge colors */ + --color-badge-cat-sound-design-bg: #0d3b3b; + --color-badge-cat-sound-design-text: #5eead4; + --color-badge-cat-mixing-bg: #2e1065; + --color-badge-cat-mixing-text: #c4b5fd; + --color-badge-cat-synthesis-bg: #0c2461; + --color-badge-cat-synthesis-text: #93c5fd; + --color-badge-cat-arrangement-bg: #422006; + --color-badge-cat-arrangement-text: #fcd34d; + --color-badge-cat-workflow-bg: #052e16; + --color-badge-cat-workflow-text: #6ee7b7; + --color-badge-cat-mastering-bg: #4a1035; + --color-badge-cat-mastering-text: #f9a8d4; + ``` + +5. **Category badge CSS classes in App.css** (after the existing `.badge--category` rule): + ```css + .badge--cat-sound-design { background: var(--color-badge-cat-sound-design-bg); color: var(--color-badge-cat-sound-design-text); } + .badge--cat-mixing { background: var(--color-badge-cat-mixing-bg); color: var(--color-badge-cat-mixing-text); } + .badge--cat-synthesis { background: var(--color-badge-cat-synthesis-bg); color: var(--color-badge-cat-synthesis-text); } + .badge--cat-arrangement { background: var(--color-badge-cat-arrangement-bg); color: var(--color-badge-cat-arrangement-text); } + .badge--cat-workflow { background: var(--color-badge-cat-workflow-bg); color: var(--color-badge-cat-workflow-text); } + .badge--cat-mastering { background: var(--color-badge-cat-mastering-bg); color: var(--color-badge-cat-mastering-text); } + ``` + +6. **Dynamic category class in TechniquePage.tsx** — in the header where the category badge is rendered (~line 234): + - Change `{displayCategory}` to: + ```tsx + + {displayCategory} + + ``` + - The `.badge--category` base style (indigo) remains as fallback for any unrecognized category. + +7. **Verify:** Run `cd frontend && npx tsc --noEmit && npx vite build` — both must pass with zero errors. + +## Must-Haves + +- [ ] Sidebar Plugins Referenced section appears first in the sidebar column +- [ ] Creator block sits between the title h1 and the meta row, not inline with badges +- [ ] Creator link uses font-size >= 1rem and font-weight 600 +- [ ] Creator genres render as small pills when present +- [ ] 12 new CSS custom properties for 6 category color pairs +- [ ] 6 `.badge--cat-*` CSS classes using the custom properties +- [ ] Category badge JSX derives class from topic_category with slug conversion +- [ ] Base `.badge--category` (indigo) remains as fallback for unknown categories +- [ ] TypeScript compilation passes +- [ ] Vite production build succeeds + - Estimate: 45m + - Files: frontend/src/pages/TechniquePage.tsx, frontend/src/App.css + - Verify: cd frontend && npx tsc --noEmit && npx vite build diff --git a/.gsd/milestones/M006/slices/S04/S04-RESEARCH.md b/.gsd/milestones/M006/slices/S04/S04-RESEARCH.md new file mode 100644 index 0000000..5dbe497 --- /dev/null +++ b/.gsd/milestones/M006/slices/S04/S04-RESEARCH.md @@ -0,0 +1,111 @@ +# S04 Research — Technique Page: Sidebar Reorder, Creator Emphasis, Tag Polish + +## Summary + +This is a **light research** slice — purely frontend CSS + JSX changes to one page (`TechniquePage.tsx`) and the shared stylesheet (`App.css`). No backend changes, no new APIs, no new dependencies. All work follows established patterns already in the codebase. + +Three independent concerns, all in the same two files: +1. **Sidebar reorder:** Move "Plugins Referenced" section to the top of the sidebar +2. **Creator emphasis:** Make the creator name visually prominent (currently a small 0.875rem cyan link inline with other meta) +3. **Tag polish:** Implement a coherent color system for the 6 `topic_category` badges and the `topic_tags` pills + +## Recommendation + +Execute as a single task. All three changes are in `TechniquePage.tsx` (JSX order + minor markup) and `App.css` (new category color variables + creator styling + possible tag pill variants). The changes are small enough that splitting into multiple tasks would add more overhead than value. + +## Implementation Landscape + +### Files to Modify + +| File | What changes | +|------|-------------| +| `frontend/src/pages/TechniquePage.tsx` | Reorder sidebar sections (move Plugins above Key Moments); restructure creator display from inline link to a more prominent block | +| `frontend/src/App.css` | Add per-category color variables; add creator emphasis styles; optionally refine pill styles for tag coherence | + +### 1. Sidebar Reorder + +Current sidebar order in `TechniquePage.tsx` (lines ~400–510): +1. Key Moments (`technique-moments`) +2. Signal Chains (`technique-chains`) +3. Plugins Referenced (`technique-plugins`) +4. Related Techniques (`technique-related`) + +Target order: +1. **Plugins Referenced** (moved to top) +2. Key Moments +3. Signal Chains +4. Related Techniques + +This is a pure JSX block reorder — move the `{displayPlugins && ...}` block before the `{technique.key_moments.length > 0 && ...}` block. No logic changes. + +### 2. Creator Emphasis + +Current state: Creator is a small `` with class `technique-header__creator` rendered inline inside the `technique-header__meta` flex row alongside the category badge and topic tags. Styled as `font-size: 0.875rem; color: var(--color-link-accent)`. + +The creator link text is `by {technique.creator_info.name}`. + +Options for emphasis: +- **A) Larger text + dedicated row:** Pull the creator out of the `technique-header__meta` flex row and render it as its own line below the title, e.g., `
`. Larger font (1rem–1.125rem), bolder weight. Still a link. Can optionally show genre pills from `creator_info.genres`. +- **B) Keep inline but increase visual weight:** Bump font-size to 1rem, add font-weight 600, drop the "by" prefix, make the name the primary visual anchor. + +**Recommendation: Option A.** A dedicated row between the title and the meta row gives the creator name room to breathe. The `CreatorInfo` type already includes `genres: string[] | null` which can be shown as small pills next to the name. + +### 3. Tag Color System + +Current state: All `topic_tags` pills use the same generic `--color-pill-bg` (#22222e) / `--color-pill-text` (#e2e2ea). The `topic_category` badge uses `--color-badge-category-bg` (#1e1b4b indigo) / `--color-badge-category-text` (#93c5fd blue). + +There are 6 canonical categories from `config/canonical_tags.yaml`: +1. **Sound design** — creating/shaping sounds +2. **Mixing** — balancing/processing +3. **Synthesis** — generating sound +4. **Arrangement** — song structure +5. **Workflow** — creative process/productivity +6. **Mastering** — final processing + +A "coherent color system" means the category badge gets a distinct color per category, and the topic_tags pills under that category should feel visually related. + +**Approach:** Add 6 pairs of CSS variables for category badges: +``` +--color-badge-cat-{slug}-bg / --color-badge-cat-{slug}-text +``` + +In the JSX, derive a CSS class from the `topic_category` string: +```tsx +const catSlug = displayCategory?.toLowerCase().replace(/\s+/g, '-'); +className={`badge badge--category badge--cat-${catSlug}`} +``` + +The 6 category colors (dark-mode appropriate, low-saturation backgrounds with readable text): + +| Category | BG | Text | Vibe | +|----------|-----|------|------| +| Sound design | deep teal | bright teal | creation/sound | +| Mixing | deep purple | light purple | processing | +| Synthesis | deep blue | light blue | waveforms | +| Arrangement | deep amber | light amber | structure | +| Workflow | deep green | light green | productivity | +| Mastering | deep rose | light rose | polish/finish | + +For `topic_tags` pills: keep the current neutral style. The category badge provides the color identity; making every tag colorful would be visually noisy. The pills can get a subtle left-border or slight tint matching their category if desired, but the default neutral pill is fine. + +### Existing CSS Variable Pattern + +All colors are defined as CSS custom properties in `:root` (lines 3–118 of App.css). The project uses a dark theme with `#0f0f14` page background, cyan (`#22d3ee`) accent, and semantic variable names. Per D017, there are 77 variables. Adding 12 more (6 categories × bg+text) is consistent with the pattern. + +### Verification + +- `cd frontend && npx tsc --noEmit` — zero TypeScript errors +- `cd frontend && npx vite build` — production build succeeds +- Visual verification via browser at the running app (http://ub01:8096) after `docker compose build && docker compose up -d` on ub01 + +### Risk: Category String Matching + +The `topic_category` values come from the database. They are stored as user-facing strings like "Sound design", not slugs. The CSS class derivation (`toLowerCase().replace(/\s+/g, '-')`) must match the CSS selectors exactly. Fallback: the base `.badge--category` style applies when no category-specific class matches, so unknown categories get the current indigo styling. + +### No Backend Changes Needed + +The API already returns `creator_info` (with name, slug, genres), `topic_category`, `topic_tags`, and `plugins`. All data needed for these UI changes is already available in the frontend. + +### No New Dependencies + +Pure CSS + JSX changes within the existing React/Vite/TypeScript stack. diff --git a/.gsd/milestones/M006/slices/S04/tasks/T01-PLAN.md b/.gsd/milestones/M006/slices/S04/tasks/T01-PLAN.md new file mode 100644 index 0000000..2b53420 --- /dev/null +++ b/.gsd/milestones/M006/slices/S04/tasks/T01-PLAN.md @@ -0,0 +1,108 @@ +--- +estimated_steps: 76 +estimated_files: 2 +skills_used: [] +--- + +# T01: Reorder sidebar, add creator emphasis block, implement per-category badge colors + +Single task covering all three S04 concerns in TechniquePage.tsx and App.css. + +## Steps + +1. **Sidebar reorder in TechniquePage.tsx** (~line 408–510 in the sidebar column): + - Move the `{displayPlugins && displayPlugins.length > 0 && (
...
)}` JSX block so it appears FIRST inside `
`, before the key moments section. + - Final sidebar order: Plugins Referenced → Key Moments → Signal Chains → Related Techniques. + +2. **Creator emphasis in TechniquePage.tsx** (~line 232–248, the `technique-header__meta` div): + - Remove the `` from inside `technique-header__meta`. + - Add a new `
` between the `

` title and the `technique-header__meta` div. + - Inside the creator block, render: + ```tsx + {technique.creator_info && ( +
+ + {technique.creator_info.name} + + {technique.creator_info.genres && technique.creator_info.genres.length > 0 && ( + + {technique.creator_info.genres.map((g) => ( + {g} + ))} + + )} +
+ )} + ``` + +3. **Creator emphasis CSS in App.css** (after the existing `.technique-header__title` styles, ~line 1296): + - Add `.technique-header__creator-block` — `display: flex; align-items: center; gap: 0.5rem; flex-wrap: wrap; margin-bottom: 0.5rem;` + - Add `.technique-header__creator-link` — `font-size: 1.125rem; font-weight: 600; color: var(--color-link-accent); text-decoration: none;` + - Add `.technique-header__creator-link:hover` — `text-decoration: underline; color: var(--color-accent-hover);` + - Add `.pill--genre-small` — `font-size: 0.625rem; padding: 0.0625rem 0.375rem; background: var(--color-pill-bg); color: var(--color-text-secondary);` + - Remove the old `.technique-header__creator` and `.technique-header__creator:hover` rules. + +4. **Category color variables in App.css** (add to the `:root` block, after the existing `--color-badge-category-*` variables): + ```css + /* Per-category badge colors */ + --color-badge-cat-sound-design-bg: #0d3b3b; + --color-badge-cat-sound-design-text: #5eead4; + --color-badge-cat-mixing-bg: #2e1065; + --color-badge-cat-mixing-text: #c4b5fd; + --color-badge-cat-synthesis-bg: #0c2461; + --color-badge-cat-synthesis-text: #93c5fd; + --color-badge-cat-arrangement-bg: #422006; + --color-badge-cat-arrangement-text: #fcd34d; + --color-badge-cat-workflow-bg: #052e16; + --color-badge-cat-workflow-text: #6ee7b7; + --color-badge-cat-mastering-bg: #4a1035; + --color-badge-cat-mastering-text: #f9a8d4; + ``` + +5. **Category badge CSS classes in App.css** (after the existing `.badge--category` rule): + ```css + .badge--cat-sound-design { background: var(--color-badge-cat-sound-design-bg); color: var(--color-badge-cat-sound-design-text); } + .badge--cat-mixing { background: var(--color-badge-cat-mixing-bg); color: var(--color-badge-cat-mixing-text); } + .badge--cat-synthesis { background: var(--color-badge-cat-synthesis-bg); color: var(--color-badge-cat-synthesis-text); } + .badge--cat-arrangement { background: var(--color-badge-cat-arrangement-bg); color: var(--color-badge-cat-arrangement-text); } + .badge--cat-workflow { background: var(--color-badge-cat-workflow-bg); color: var(--color-badge-cat-workflow-text); } + .badge--cat-mastering { background: var(--color-badge-cat-mastering-bg); color: var(--color-badge-cat-mastering-text); } + ``` + +6. **Dynamic category class in TechniquePage.tsx** — in the header where the category badge is rendered (~line 234): + - Change `{displayCategory}` to: + ```tsx + + {displayCategory} + + ``` + - The `.badge--category` base style (indigo) remains as fallback for any unrecognized category. + +7. **Verify:** Run `cd frontend && npx tsc --noEmit && npx vite build` — both must pass with zero errors. + +## Must-Haves + +- [ ] Sidebar Plugins Referenced section appears first in the sidebar column +- [ ] Creator block sits between the title h1 and the meta row, not inline with badges +- [ ] Creator link uses font-size >= 1rem and font-weight 600 +- [ ] Creator genres render as small pills when present +- [ ] 12 new CSS custom properties for 6 category color pairs +- [ ] 6 `.badge--cat-*` CSS classes using the custom properties +- [ ] Category badge JSX derives class from topic_category with slug conversion +- [ ] Base `.badge--category` (indigo) remains as fallback for unknown categories +- [ ] TypeScript compilation passes +- [ ] Vite production build succeeds + +## Inputs + +- ``frontend/src/pages/TechniquePage.tsx` — current technique page with sidebar sections, header meta row, and category badge` +- ``frontend/src/App.css` — CSS custom properties and technique page styles` + +## Expected Output + +- ``frontend/src/pages/TechniquePage.tsx` — sidebar reordered (plugins first), creator in dedicated block, category badge with dynamic class` +- ``frontend/src/App.css` — 12 new category color variables, 6 badge--cat-* classes, creator-block styles, genre-small pill style` + +## Verification + +cd frontend && npx tsc --noEmit && npx vite build diff --git a/.gsd/milestones/M006/slices/S04/tasks/T01-SUMMARY.md b/.gsd/milestones/M006/slices/S04/tasks/T01-SUMMARY.md new file mode 100644 index 0000000..acfd2a7 --- /dev/null +++ b/.gsd/milestones/M006/slices/S04/tasks/T01-SUMMARY.md @@ -0,0 +1,77 @@ +--- +id: T01 +parent: S04 +milestone: M006 +provides: [] +requires: [] +affects: [] +key_files: ["frontend/src/pages/TechniquePage.tsx", "frontend/src/App.css"] +key_decisions: ["Category slug conversion uses toLowerCase().replace(/\s+/g, '-') for CSS class derivation"] +patterns_established: [] +drill_down_paths: [] +observability_surfaces: [] +duration: "" +verification_result: "TypeScript compilation (tsc --noEmit) passed with zero errors. Vite production build succeeded (47 modules, 811ms). Grep verification confirmed sidebar order (plugins at line 418 before key moments at 432), creator-block placement, 12 new CSS variables, 6 badge--cat-* classes, and dynamic category class in JSX." +completed_at: 2026-03-30T11:34:06.126Z +blocker_discovered: false +--- + +# T01: Reordered technique page sidebar (plugins first), added prominent creator block with genre pills, and implemented per-category badge color system with 6 category-specific color pairs + +> Reordered technique page sidebar (plugins first), added prominent creator block with genre pills, and implemented per-category badge color system with 6 category-specific color pairs + +## What Happened +--- +id: T01 +parent: S04 +milestone: M006 +key_files: + - frontend/src/pages/TechniquePage.tsx + - frontend/src/App.css +key_decisions: + - Category slug conversion uses toLowerCase().replace(/\s+/g, '-') for CSS class derivation +duration: "" +verification_result: passed +completed_at: 2026-03-30T11:34:06.127Z +blocker_discovered: false +--- + +# T01: Reordered technique page sidebar (plugins first), added prominent creator block with genre pills, and implemented per-category badge color system with 6 category-specific color pairs + +**Reordered technique page sidebar (plugins first), added prominent creator block with genre pills, and implemented per-category badge color system with 6 category-specific color pairs** + +## What Happened + +Three changes to TechniquePage.tsx and App.css: (1) Moved Plugins Referenced section to top of sidebar column, before Key Moments. (2) Extracted creator from inline meta row into a dedicated creator-block between title and meta, with larger font-size/weight and genre pills. (3) Added 12 CSS custom properties for 6 category color pairs, 6 .badge--cat-* classes, and dynamic category class derivation in JSX with .badge--category as fallback. + +## Verification + +TypeScript compilation (tsc --noEmit) passed with zero errors. Vite production build succeeded (47 modules, 811ms). Grep verification confirmed sidebar order (plugins at line 418 before key moments at 432), creator-block placement, 12 new CSS variables, 6 badge--cat-* classes, and dynamic category class in JSX. + +## Verification Evidence + +| # | Command | Exit Code | Verdict | Duration | +|---|---------|-----------|---------|----------| +| 1 | `cd frontend && npx tsc --noEmit` | 0 | ✅ pass | 2900ms | +| 2 | `cd frontend && npx vite build` | 0 | ✅ pass | 2700ms | + + +## Deviations + +None. + +## Known Issues + +None. + +## Files Created/Modified + +- `frontend/src/pages/TechniquePage.tsx` +- `frontend/src/App.css` + + +## Deviations +None. + +## Known Issues +None. diff --git a/frontend/src/App.css b/frontend/src/App.css index 75ec723..e1a6724 100644 --- a/frontend/src/App.css +++ b/frontend/src/App.css @@ -85,6 +85,20 @@ --color-badge-quality-unstructured-bg: #422006; --color-badge-quality-unstructured-text: #fcd34d; + /* Per-category badge colors */ + --color-badge-cat-sound-design-bg: #0d3b3b; + --color-badge-cat-sound-design-text: #5eead4; + --color-badge-cat-mixing-bg: #2e1065; + --color-badge-cat-mixing-text: #c4b5fd; + --color-badge-cat-synthesis-bg: #0c2461; + --color-badge-cat-synthesis-text: #93c5fd; + --color-badge-cat-arrangement-bg: #422006; + --color-badge-cat-arrangement-text: #fcd34d; + --color-badge-cat-workflow-bg: #052e16; + --color-badge-cat-workflow-text: #6ee7b7; + --color-badge-cat-mastering-bg: #4a1035; + --color-badge-cat-mastering-text: #f9a8d4; + /* Genre pills */ --color-genre-pill-bg: #1a1a24; --color-genre-pill-text: #e2e2ea; @@ -1184,6 +1198,13 @@ body { color: var(--color-badge-category-text); } +.badge--cat-sound-design { background: var(--color-badge-cat-sound-design-bg); color: var(--color-badge-cat-sound-design-text); } +.badge--cat-mixing { background: var(--color-badge-cat-mixing-bg); color: var(--color-badge-cat-mixing-text); } +.badge--cat-synthesis { background: var(--color-badge-cat-synthesis-bg); color: var(--color-badge-cat-synthesis-text); } +.badge--cat-arrangement { background: var(--color-badge-cat-arrangement-bg); color: var(--color-badge-cat-arrangement-text); } +.badge--cat-workflow { background: var(--color-badge-cat-workflow-bg); color: var(--color-badge-cat-workflow-text); } +.badge--cat-mastering { background: var(--color-badge-cat-mastering-bg); color: var(--color-badge-cat-mastering-text); } + .badge--type { font-size: 0.6875rem; text-transform: uppercase; @@ -1305,14 +1326,31 @@ body { gap: 0.25rem; } -.technique-header__creator { - font-size: 0.875rem; +.technique-header__creator-block { + display: flex; + align-items: center; + gap: 0.5rem; + flex-wrap: wrap; + margin-bottom: 0.5rem; +} + +.technique-header__creator-link { + font-size: 1.125rem; + font-weight: 600; color: var(--color-link-accent); text-decoration: none; } -.technique-header__creator:hover { +.technique-header__creator-link:hover { text-decoration: underline; + color: var(--color-accent-hover); +} + +.pill--genre-small { + font-size: 0.625rem; + padding: 0.0625rem 0.375rem; + background: var(--color-pill-bg); + color: var(--color-text-secondary); } .technique-header__stats { diff --git a/frontend/src/pages/TechniquePage.tsx b/frontend/src/pages/TechniquePage.tsx index 2e3adb5..4be1851 100644 --- a/frontend/src/pages/TechniquePage.tsx +++ b/frontend/src/pages/TechniquePage.tsx @@ -226,8 +226,24 @@ export default function TechniquePage() { {/* Header */}

{displayTitle}

+ {technique.creator_info && ( +
+ + {technique.creator_info.name} + + {technique.creator_info.genres && technique.creator_info.genres.length > 0 && ( + + {technique.creator_info.genres.map((g) => ( + {g} + ))} + + )} +
+ )}
- {displayCategory} + + {displayCategory} + {displayTags && displayTags.length > 0 && ( {displayTags.map((tag) => ( @@ -237,14 +253,6 @@ export default function TechniquePage() { ))} )} - {technique.creator_info && ( - - by {technique.creator_info.name} - - )} {displayQuality && (
+ {/* Plugins */} + {displayPlugins && displayPlugins.length > 0 && ( +
+

Plugins Referenced

+
+ {displayPlugins.map((plugin) => ( + + {plugin} + + ))} +
+
+ )} + {/* Key moments (always from live data — not versioned) */} {technique.key_moments.length > 0 && (
@@ -472,20 +494,6 @@ export default function TechniquePage() {
)} - {/* Plugins */} - {displayPlugins && displayPlugins.length > 0 && ( -
-

Plugins Referenced

-
- {displayPlugins.map((plugin) => ( - - {plugin} - - ))} -
-
- )} - {/* Related techniques (always from live data) */} {technique.related_links.length > 0 && (