feat: Reordered technique page sidebar (plugins first), added prominent…

- "frontend/src/pages/TechniquePage.tsx"
- "frontend/src/App.css"

GSD-Task: S04/T01
This commit is contained in:
jlightner 2026-03-30 11:34:14 +00:00
parent b4d4caeda6
commit 61d52d719e
10 changed files with 622 additions and 28 deletions

View file

@ -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. |

View file

@ -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

View file

@ -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".

View file

@ -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
}

View file

@ -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 408510 in the sidebar column):
- Move the `{displayPlugins && displayPlugins.length > 0 && ( <section className="technique-plugins"> ... </section> )}` JSX block so it appears FIRST inside `<div className="technique-columns__sidebar">`, before the key moments section.
- Final sidebar order: Plugins Referenced → Key Moments → Signal Chains → Related Techniques.
2. **Creator emphasis in TechniquePage.tsx** (~line 232248, the `technique-header__meta` div):
- Remove the `<Link className="technique-header__creator">` from inside `technique-header__meta`.
- Add a new `<div className="technique-header__creator-block">` between the `<h1>` title and the `technique-header__meta` div.
- Inside the creator block, render:
```tsx
{technique.creator_info && (
<div className="technique-header__creator-block">
<Link to={`/creators/${technique.creator_info.slug}`} className="technique-header__creator-link">
{technique.creator_info.name}
</Link>
{technique.creator_info.genres && technique.creator_info.genres.length > 0 && (
<span className="technique-header__creator-genres">
{technique.creator_info.genres.map((g) => (
<span key={g} className="pill pill--genre-small">{g}</span>
))}
</span>
)}
</div>
)}
```
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 `<span className="badge badge--category">{displayCategory}</span>` to:
```tsx
<span className={`badge badge--category badge--cat-${displayCategory?.toLowerCase().replace(/\s+/g, '-') ?? ''}`}>
{displayCategory}
</span>
```
- 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

View file

@ -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 ~400510):
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 `<Link>` 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., `<div className="technique-header__creator-block">`. Larger font (1rem1.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 3118 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.

View file

@ -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 408510 in the sidebar column):
- Move the `{displayPlugins && displayPlugins.length > 0 && ( <section className="technique-plugins"> ... </section> )}` JSX block so it appears FIRST inside `<div className="technique-columns__sidebar">`, before the key moments section.
- Final sidebar order: Plugins Referenced → Key Moments → Signal Chains → Related Techniques.
2. **Creator emphasis in TechniquePage.tsx** (~line 232248, the `technique-header__meta` div):
- Remove the `<Link className="technique-header__creator">` from inside `technique-header__meta`.
- Add a new `<div className="technique-header__creator-block">` between the `<h1>` title and the `technique-header__meta` div.
- Inside the creator block, render:
```tsx
{technique.creator_info && (
<div className="technique-header__creator-block">
<Link to={`/creators/${technique.creator_info.slug}`} className="technique-header__creator-link">
{technique.creator_info.name}
</Link>
{technique.creator_info.genres && technique.creator_info.genres.length > 0 && (
<span className="technique-header__creator-genres">
{technique.creator_info.genres.map((g) => (
<span key={g} className="pill pill--genre-small">{g}</span>
))}
</span>
)}
</div>
)}
```
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 `<span className="badge badge--category">{displayCategory}</span>` to:
```tsx
<span className={`badge badge--category badge--cat-${displayCategory?.toLowerCase().replace(/\s+/g, '-') ?? ''}`}>
{displayCategory}
</span>
```
- 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

View file

@ -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.

View file

@ -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 {

View file

@ -226,8 +226,24 @@ export default function TechniquePage() {
{/* Header */}
<header className="technique-header">
<h1 className="technique-header__title">{displayTitle}</h1>
{technique.creator_info && (
<div className="technique-header__creator-block">
<Link to={`/creators/${technique.creator_info.slug}`} className="technique-header__creator-link">
{technique.creator_info.name}
</Link>
{technique.creator_info.genres && technique.creator_info.genres.length > 0 && (
<span className="technique-header__creator-genres">
{technique.creator_info.genres.map((g) => (
<span key={g} className="pill pill--genre-small">{g}</span>
))}
</span>
)}
</div>
)}
<div className="technique-header__meta">
<span className="badge badge--category">{displayCategory}</span>
<span className={`badge badge--category badge--cat-${displayCategory?.toLowerCase().replace(/\s+/g, '-') ?? ''}`}>
{displayCategory}
</span>
{displayTags && displayTags.length > 0 && (
<span className="technique-header__tags">
{displayTags.map((tag) => (
@ -237,14 +253,6 @@ export default function TechniquePage() {
))}
</span>
)}
{technique.creator_info && (
<Link
to={`/creators/${technique.creator_info.slug}`}
className="technique-header__creator"
>
by {technique.creator_info.name}
</Link>
)}
{displayQuality && (
<span
className={`badge badge--quality badge--quality-${displayQuality}`}
@ -405,6 +413,20 @@ export default function TechniquePage() {
</div>
<div className="technique-columns__sidebar">
{/* Plugins */}
{displayPlugins && displayPlugins.length > 0 && (
<section className="technique-plugins">
<h2>Plugins Referenced</h2>
<div className="pill-list">
{displayPlugins.map((plugin) => (
<span key={plugin} className="pill pill--plugin">
{plugin}
</span>
))}
</div>
</section>
)}
{/* Key moments (always from live data — not versioned) */}
{technique.key_moments.length > 0 && (
<section className="technique-moments">
@ -472,20 +494,6 @@ export default function TechniquePage() {
</section>
)}
{/* Plugins */}
{displayPlugins && displayPlugins.length > 0 && (
<section className="technique-plugins">
<h2>Plugins Referenced</h2>
<div className="pill-list">
{displayPlugins.map((plugin) => (
<span key={plugin} className="pill pill--plugin">
{plugin}
</span>
))}
</div>
</section>
)}
{/* Related techniques (always from live data) */}
{technique.related_links.length > 0 && (
<section className="technique-related">