docs(quick-12): Add favorite icon to album grid track list dropdown

This commit is contained in:
2026-03-05 11:44:52 -05:00
parent 06d2c4702e
commit 3e9c143a6e
@@ -0,0 +1,177 @@
---
phase: quick-12
plan: 12
type: execute
wave: 1
depends_on: []
files_modified:
- frontend/src/components/cover-grid/album-dropdown.ts
autonomous: true
requirements: []
---
<objective>
Add a favorite (heart/star) icon to each track row in the album grid dropdown (`<album-dropdown>`), matching the existing pattern from `<track-list>`.
Purpose: Users can see at a glance which tracks are favorited and toggle favorites directly from the album dropdown, consistent with the track list view.
Output: Updated `album-dropdown.ts` with per-track favorite icon.
</objective>
<execution_context>
@/home/caleb/.config/opencode/get-shit-done/workflows/execute-plan.md
@/home/caleb/.config/opencode/get-shit-done/templates/summary.md
</execution_context>
<context>
@.planning/STATE.md
@frontend/src/components/cover-grid/album-dropdown.ts
@frontend/src/store/controllers/favorites-controller.ts
<interfaces>
<!-- Existing pattern from track-list.ts to replicate -->
From frontend/src/store/controllers/favorites-controller.ts:
```typescript
export class FavoritesController implements ReactiveController {
constructor(host: ReactiveControllerHost);
isFavorited(filePath: string): boolean;
get iconName(): string; // returns 'heart' or 'star'
toggleFavorite(filePath: string): Promise<void>;
}
```
Existing favorite icon pattern from track-list.ts:
```typescript
// In the component class:
private favCtrl = new FavoritesController(this);
// In renderTrackRow():
const isFav = this.favCtrl.isFavorited(track.FilePath);
const favVariant = isFav ? 'solid' : 'regular';
// In the template, as the FIRST element in the track row:
<div
class=${classMap({ 'fav-icon': true, favorited: isFav })}
@click=${(e: MouseEvent) => {
e.stopPropagation();
void this.favCtrl.toggleFavorite(track.FilePath);
}}
>
<wa-icon
name=${this.favCtrl.iconName}
variant=${favVariant}
></wa-icon>
</div>
```
CSS for favorite icon (from track-list.ts):
```css
.fav-icon {
display: flex; align-items: center; justify-content: center;
width: 24px; flex-shrink: 0; cursor: pointer;
color: var(--yj-text-tertiary, #666);
font-size: var(--yj-text-sm);
transition: color 0.1s ease;
}
.fav-icon:hover { color: var(--yj-text-primary, #fff); }
.fav-icon.favorited { color: var(--yj-accent, #ffd43b); }
.fav-icon.favorited:hover { color: var(--yj-accent, #ffd43b); opacity: 0.8; }
```
</interfaces>
</context>
<tasks>
<task type="auto">
<name>Task 1: Add favorite icon to album dropdown track rows</name>
<files>frontend/src/components/cover-grid/album-dropdown.ts</files>
<action>
Modify `album-dropdown.ts` to add a per-track favorite icon, following the exact pattern from `track-list.ts`:
1. **Add imports:**
- Import `FavoritesController` from `@store/controllers/favorites-controller`
- Import `classMap` from `lit/directives/class-map.js`
2. **Add controller instance** to the class body (next to the existing `player` controller):
```typescript
private favCtrl = new FavoritesController(this);
```
3. **Add CSS** for `.fav-icon` inside the existing `static override styles = css\`...\`` block, after the `.track-duration` rule. Use a compact sizing appropriate for the 12px font dropdown (use `width: 18px` instead of track-list's `24px`, and `font-size: 11px` to be proportional to the 12px track rows):
```css
.fav-icon {
display: flex;
align-items: center;
justify-content: center;
width: 18px;
flex-shrink: 0;
cursor: pointer;
color: var(--yj-text-tertiary, #666);
font-size: 11px;
transition: color 0.1s ease;
}
.fav-icon:hover {
color: var(--yj-text-primary, #fff);
}
.fav-icon.favorited {
color: var(--yj-accent, #ffd43b);
}
.fav-icon.favorited:hover {
color: var(--yj-accent, #ffd43b);
opacity: 0.8;
}
```
4. **Update `renderTrackRow()`** to add the favorite icon BETWEEN the track number and the track title. Compute `isFav` and `favVariant` at the top of the method, then insert the icon element:
```typescript
const isFav = this.favCtrl.isFavorited(track.FilePath);
const favVariant = isFav ? 'solid' : 'regular';
```
Insert after `<span class="track-number">` and before `<span class="track-title">`:
```html
<div
class=${classMap({ 'fav-icon': true, favorited: isFav })}
@click=${(e: MouseEvent) => {
e.stopPropagation();
void this.favCtrl.toggleFavorite(track.FilePath);
}}
>
<wa-icon
name=${this.favCtrl.iconName}
variant=${favVariant}
></wa-icon>
</div>
```
**Important:** The click handler MUST call `e.stopPropagation()` to prevent the track-row click handler from also firing when toggling favorites.
</action>
<verify>
Run: `cd frontend && npx tsc --noEmit`
Verify: TypeScript compilation passes with no errors in album-dropdown.ts.
</verify>
<done>
- Album dropdown track rows display a heart/star icon (matching user's configured icon style) between the track number and title
- Favorited tracks show the icon in accent color (solid variant)
- Non-favorited tracks show a subtle tertiary-colored icon (regular variant)
- Clicking the icon toggles the favorite state without triggering track selection
- Icon reactively updates when favorite state changes (via FavoritesController subscription)
</done>
</task>
</tasks>
<verification>
`cd frontend && npx tsc --noEmit` — full TypeScript check passes
</verification>
<success_criteria>
- Favorite icon visible in album dropdown track rows
- Icon matches configured style (heart or star)
- Favorited state reflected visually (solid + accent color vs regular + tertiary)
- Click toggles favorite without selecting/playing track
- No TypeScript errors
</success_criteria>
<output>
After completion, create `.planning/quick/12-add-favorite-icon-to-album-grid-track-li/12-SUMMARY.md`
</output>