--- phase: 08-frontend-performance-ux plan: 04 type: execute wave: 2 depends_on: - "08-01" files_modified: - frontend/src/components/sidebar/app-sidebar.ts - frontend/src/components/now-playing/now-playing.ts - frontend/src/components/search-bar/search-bar.ts - frontend/src/components/audio-player/controls/player-controls.ts - frontend/src/components/audio-player/seekbar/seek-bar.ts - frontend/src/components/audio-player/volume-control/volume-control.ts - frontend/src/components/audio-player/audio-player.ts - frontend/src/components/cover-grid/cover-grid.ts - frontend/src/components/cover-grid/cover-grid-styles.ts - frontend/src/components/track-list/track-list.ts - frontend/src/components/queue-panel/queue-panel.ts - frontend/src/components/track-details/track-details.ts - frontend/src/components/track-info/track-info.ts - frontend/src/components/artist-details/artist-details.ts - frontend/src/components/genre-details/genre-details.ts autonomous: false requirements: - UX-01 must_haves: truths: - "All components use px-based spacing (no em-based padding/gap/margin in sidebar or anywhere)" - "Icon sizes reference --yj-icon-sm/md/lg tokens instead of ad-hoc pixel or em values" - "Typography references --yj-text-xs/sm/md/lg/xl tokens instead of ad-hoc font-size values" - "Cover-grid dynamic text sizing tiers map to the type scale tokens" - "Visual consistency is verified by human inspection across all views" artifacts: - path: "frontend/src/components/sidebar/app-sidebar.ts" provides: "px-based spacing, icon tokens" contains: "--yj-icon-" - path: "frontend/src/components/now-playing/now-playing.ts" provides: "Icon tokens for cover placeholder" contains: "--yj-icon-lg" - path: "frontend/src/components/search-bar/search-bar.ts" provides: "Icon and type scale tokens" contains: "--yj-icon-sm" - path: "frontend/src/components/cover-grid/cover-grid.ts" provides: "Dynamic text sizing mapped to type scale tokens" contains: "--yj-text-" key_links: - from: "all components" to: "frontend/src/styles/tokens.css.ts" via: "import { designTokens } and include in static styles" pattern: "designTokens" --- Systematically audit and fix visual inconsistencies across all components — convert em-based spacing to px, apply icon size tokens, apply type scale tokens, and ensure coherent visual language. Purpose: The codebase has evolved with ad-hoc values (0.9em icons in sidebar, 24px in now-playing, 14px in search-bar, 11-16px dynamic text in cover-grid). This pass replaces them with the design tokens defined in Plan 01, creating a single source of truth for sizing. Output: All components use consistent design tokens. Human-verified visual quality. @/home/caleb/.config/opencode/get-shit-done/workflows/execute-plan.md @/home/caleb/.config/opencode/get-shit-done/templates/summary.md @.planning/PROJECT.md @.planning/ROADMAP.md @.planning/STATE.md @.planning/phases/08-frontend-performance-ux/08-CONTEXT.md @.planning/phases/08-frontend-performance-ux/08-01-SUMMARY.md @frontend/src/styles/tokens.css.ts @frontend/src/components/sidebar/app-sidebar.ts @frontend/src/components/now-playing/now-playing.ts @frontend/src/components/search-bar/search-bar.ts @frontend/src/components/cover-grid/cover-grid.ts @frontend/src/components/cover-grid/cover-grid-styles.ts From frontend/src/styles/tokens.css.ts: ```typescript export const designTokens = css` :host { --yj-icon-sm: 14px; --yj-icon-md: 18px; --yj-icon-lg: 24px; --yj-text-xs: 11px; --yj-text-sm: 12px; --yj-text-md: 13px; --yj-text-lg: 15px; --yj-text-xl: 18px; } `; ``` How to use in a component: ```typescript import { designTokens } from '../../styles/tokens.css'; @customElement('my-component') export class MyComponent extends LitElement { static styles = [designTokens, css` .icon { font-size: var(--yj-icon-md); } .label { font-size: var(--yj-text-sm); } `]; } ``` Known inconsistencies to fix: - app-sidebar.ts: em-based spacing (padding: 1em, gap: 0.6em, padding: 0.5em), icon 0.9em/1.1em, border-radius: 5px - now-playing.ts: cover placeholder icon font-size: 24px → --yj-icon-lg - search-bar.ts: search icon font-size: 14px → --yj-icon-sm, input font-size: 13px → --yj-text-md - cover-grid.ts: dynamic text sizing tiers (11px/10px, 14px/12px, 16px/13px) in updateSizeProperties() - Various components: ad-hoc font-size values that should map to type scale Task 1: Convert sidebar em-based spacing to px and apply icon/type tokens to sidebar, now-playing, search-bar, and audio-player components frontend/src/components/sidebar/app-sidebar.ts, frontend/src/components/now-playing/now-playing.ts, frontend/src/components/search-bar/search-bar.ts, frontend/src/components/audio-player/controls/player-controls.ts, frontend/src/components/audio-player/seekbar/seek-bar.ts, frontend/src/components/audio-player/volume-control/volume-control.ts, frontend/src/components/audio-player/audio-player.ts For EACH component listed, read the file first, then: 1. Import designTokens: `import { designTokens } from '../../styles/tokens.css';` (adjust relative path based on file location) 2. Add designTokens to the component's `static styles` array (prepend it so tokens are available to component styles) 3. Apply the following conversions: **app-sidebar.ts:** - Convert ALL em-based values to px equivalents: - `padding: 1em` → `padding: 16px` - `gap: 0.6em` → `gap: 10px` - `padding: 0.5em` → `padding: 8px` - Any other em values → compute px (base is ~16px for desktop) - Icon font-size `0.9em` → `var(--yj-icon-md)` (was ~14px, md=18px is closer to sidebar intent) - Icon font-size `1.1em` (collapsed mode) → `var(--yj-icon-md)` (same token, consistent) - Audit ALL font-size values and replace with appropriate --yj-text-* tokens - `border-radius: 5px` → keep as-is (border-radius doesn't need tokenizing) **now-playing.ts:** - Cover placeholder icon `font-size: 24px` → `font-size: var(--yj-icon-lg)` - Audit all font-size values → replace with --yj-text-* tokens **search-bar.ts:** - Search icon `font-size: 14px` → `font-size: var(--yj-icon-sm)` - Input `font-size: 13px` → `font-size: var(--yj-text-md)` - Audit all other font-size values **audio-player components (player-controls.ts, seek-bar.ts, volume-control.ts, audio-player.ts):** - Read each file, audit for ad-hoc font-size and icon-size values - Replace with appropriate --yj-text-* and --yj-icon-* tokens - Convert any em-based spacing to px if found **General rules:** - When mapping existing px values to tokens, pick the NEAREST token value. If 12px → --yj-text-sm (12px). If 13px → --yj-text-md (13px). If 14px and it's text → --yj-text-sm or --yj-text-md based on context. If 14px and it's an icon → --yj-icon-sm (14px). - Do NOT change values that are layout-specific (width, height, margins for positioning). Only convert font-size, icon font-size, and em-based spacing. - Do NOT change color values — those already use --yj- tokens. cd frontend && npx tsc --noEmit 2>&1 | head -30 Sidebar uses px-based spacing throughout. All icon sizes in sidebar, now-playing, search-bar, and audio-player use --yj-icon-* tokens. All text sizes in these components use --yj-text-* tokens. No em-based spacing remains. TypeScript compiles. Task 2: Apply design tokens to cover-grid dynamic text sizing, track-list, queue-panel, and remaining detail/info components frontend/src/components/cover-grid/cover-grid.ts, frontend/src/components/cover-grid/cover-grid-styles.ts, frontend/src/components/track-list/track-list.ts, frontend/src/components/queue-panel/queue-panel.ts, frontend/src/components/track-details/track-details.ts, frontend/src/components/track-info/track-info.ts, frontend/src/components/artist-details/artist-details.ts, frontend/src/components/genre-details/genre-details.ts For EACH component, read the file, import designTokens, add to static styles, then audit and fix: **cover-grid.ts — Dynamic text sizing:** The updateSizeProperties() method has hardcoded px values for text sizing tiers based on card size: - Small cards: 11px/10px → map to `--yj-text-xs` (11px) / computed smaller - Medium cards: 14px/12px → map to `--yj-text-lg` (15px) / `--yj-text-sm` (12px) — or adjust - Large cards: 16px/13px → map to values near `--yj-text-lg`/`--yj-text-md` For the dynamic sizing tiers, the approach depends on how they're applied: - If set as inline styles or CSS custom properties on the element, replace hardcoded values with references to the tokens: `var(--yj-text-xs)`, `var(--yj-text-sm)`, etc. - If set programmatically in JS (this.style.setProperty), use the token values directly or set CSS custom properties that reference the tokens - The goal is that card text sizes use the SAME scale as everything else, not independent magic numbers Read the updateSizeProperties() method carefully to understand the tier logic before modifying. **cover-grid-styles.ts:** - Audit for ad-hoc font-size values, replace with --yj-text-* tokens **track-list.ts:** - Import designTokens (if not already from Plan 03) - Audit ALL font-size values in styles — header, cells, sort labels, etc. - Replace with --yj-text-* tokens - Audit icon sizes (favorites icon was noted as 12px) → --yj-icon-sm **queue-panel.ts:** - Import designTokens (if not already from Plan 03) - Audit font-size values → --yj-text-* tokens - Audit icon sizes → --yj-icon-* tokens **track-details.ts, track-info.ts, artist-details.ts, genre-details.ts:** - Read each file, audit for font-size and icon-size values - Import designTokens, add to static styles - Replace ad-hoc values with tokens **Same rules as Task 1:** Only convert font-size, icon sizes, em-based spacing. Don't change layout dimensions or colors. cd frontend && npx tsc --noEmit 2>&1 | head -30 Cover-grid dynamic text tiers use type scale tokens. Track-list, queue-panel, and detail components use design tokens for all font-size and icon-size values. No meaningful ad-hoc font-size values remain across audited components. TypeScript compiles. Task 3: Visual consistency verification n/a Human verifies visual consistency after Tasks 1-2. What was built: - Sidebar: px-based spacing, icon tokens, type tokens - Now-playing: icon tokens, type tokens - Search bar: icon and type tokens - Audio player: icon and type tokens - Cover grid: dynamic text sizing mapped to type scale - Track list: type and icon tokens - Queue panel: type and icon tokens - Detail/info views: type and icon tokens How to verify — run the app and check each view: 1. Sidebar — Icons are consistent size, text is readable, spacing looks balanced (no too-tight or too-loose areas from em→px conversion) 2. Track list — Column headers, cell text, and sort indicators look consistent. Favorites icon is appropriately sized. 3. Cover grid — Album names scale with card size using the type scale tiers. Small, medium, and large cards all have readable text. 4. Queue panel — Track names, durations, and icons are consistently sized 5. Now playing — Cover placeholder icon is appropriately sized, track info text is consistent 6. Search bar — Search icon and input text are balanced 7. Audio player — Play/pause/skip icons, seek bar labels, volume icon are consistent 8. Detail views — Artist details, genre details, track details/info all use consistent typography 9. Overall — No view has text that looks noticeably different in size from the same-purpose text in another view Human visual inspection — type "approved" or describe specific visual issues to fix All views pass visual consistency check — no em-based spacing, icon sizes are consistent, typography follows the type scale, and no jarring size mismatches between views. 1. `cd frontend && npx tsc --noEmit` compiles without errors 2. `grep -r "0\.\d*em" frontend/src/components/sidebar/` returns no em-based spacing 3. `grep -rn "font-size:" frontend/src/components/ | grep -v "var(--yj-"` shows minimal remaining ad-hoc values (only layout-specific sizes) 4. All components that have styles import designTokens 5. Human verification confirms visual consistency - Zero em-based spacing values in sidebar - All icon sizes use --yj-icon-sm/md/lg tokens - All text sizes use --yj-text-xs/sm/md/lg/xl tokens (with minimal justified exceptions) - Cover-grid dynamic text tiers map to the type scale - Human approves visual consistency across all views - TypeScript compiles without errors After completion, create `.planning/phases/08-frontend-performance-ux/08-04-SUMMARY.md`