feat(banner): slim loop strip — big Now Playing chord removed (task L-50, commit 1/2)

Key chip + last-5 history + loop chips on one wrapping row; the
playhead loop chip and the enlarged current history chip are the
"now"; p-2 chrome trim. The text-6xl Now Playing column, its divider,
and the dead currentRN computation are gone — the loop shows once.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
vadimwit
2026-07-11 16:28:25 +01:00
parent 8e7a648660
commit 800fd43778
+22 -39
View File
@@ -2,15 +2,21 @@ import { useRef, useEffect } from 'react'
import { toRomanNumeral } from '../lib/theory'
import { findLoopPosition } from '../lib/match'
const HISTORY_SHOWN = 8
// ─── ProgressionBanner — the SLIM LOOP STRIP (task L-50, one-screen.md §1.2) ──
//
// One full-width status row: key chip · chord history (last 5, age-faded) ·
// ♻ loop chips. The old right-30% "Now Playing" text-6xl chord + its divider
// are GONE per the user directive — the enlarged current history chip and the
// accent-glowing active loop chip ARE the now-playing display. Chrome trimmed
// (p-4 → p-2, history pb-1 dropped) so the strip lands at ~76px.
const HISTORY_SHOWN = 5
export default function ProgressionBanner({ chordHistory, keyInfo, detectedProgression, currentChord, onChordClick }) {
export default function ProgressionBanner({ chordHistory, keyInfo, detectedProgression, onChordClick }) {
const { root, mode, confidence } = keyInfo ?? {}
const visible = chordHistory.slice(-HISTORY_SHOWN)
const current = visible[visible.length - 1]
const loopPos = findLoopPosition(chordHistory, detectedProgression)
const currentRN = root && current ? toRomanNumeral(current, root, mode) : ''
const currentRef = useRef(null)
const prevChord = useRef(null)
@@ -25,14 +31,10 @@ export default function ProgressionBanner({ chordHistory, keyInfo, detectedProgr
}, [current])
return (
<div className="bg-panel border border-border rounded-2xl p-4 mb-3 flex gap-4">
<div className="bg-panel border border-border rounded-2xl p-2 mb-3 flex flex-wrap items-end gap-x-3 gap-y-1">
{/* ── Left: key + chord history + loop ── */}
<div className="w-full lg:w-[70%] min-w-0 flex flex-col gap-2">
{/* Key + history on one row */}
<div className="flex items-end gap-3">
<div className="shrink-0 flex items-baseline gap-1.5">
{/* ── Key chip ── */}
<div className="shrink-0 flex items-baseline gap-1.5 self-center">
{root ? (
<>
<span className="text-2xl font-bold text-accent">{root}</span>
@@ -46,12 +48,13 @@ export default function ProgressionBanner({ chordHistory, keyInfo, detectedProgr
)}
</div>
<div className="w-px h-6 bg-border shrink-0" />
<div className="w-px h-6 bg-border shrink-0 self-center" />
{/* ── Chord history (the enlarged current chip is the "now") ── */}
{!chordHistory.length ? (
<p className="text-gray-600 text-sm">Start listening</p>
<p className="text-gray-600 text-sm self-center">Start listening</p>
) : (
<div className="flex items-end gap-1 overflow-x-auto pb-1">
<div className="flex items-end gap-1 overflow-x-auto">
{visible.map((chord, i) => {
const isCurrent = i === visible.length - 1
const age = visible.length - 1 - i
@@ -77,18 +80,19 @@ export default function ProgressionBanner({ chordHistory, keyInfo, detectedProgr
<span className={`text-xs font-semibold mt-0.5 ${
isCurrent ? 'text-amber-400' : 'text-gray-500'
}`}>
{rn || '\u00A0'}
{rn || ' '}
</span>
</div>
)
})}
</div>
)}
</div>
{/* Loop */}
{/* ── Loop — on the same row (divider between); playhead chip = the now ── */}
{detectedProgression && (
<div className="flex items-center gap-1.5 flex-wrap">
<>
<div className="w-px h-6 bg-border shrink-0 self-center" />
<div className="flex items-center gap-1.5 flex-wrap self-center">
<span className="text-xs text-gray-500"></span>
{detectedProgression.map((chord, i) => {
const isActive = i === loopPos
@@ -112,29 +116,8 @@ export default function ProgressionBanner({ chordHistory, keyInfo, detectedProgr
})}
<span className="text-gray-600 text-xs"> loop</span>
</div>
</>
)}
</div>
{/* ── Divider ── */}
<div className="hidden lg:block w-px bg-border shrink-0" />
{/* ── Right: big chord ── */}
<div className="hidden lg:flex w-[30%] flex-col items-center justify-center gap-1">
{current ? (
<button
onClick={() => onChordClick?.(current)}
className="flex flex-col items-center gap-1 px-4 py-2 rounded-xl hover:bg-accent/10 transition-colors group"
title="Click to see voicings"
>
<p className="text-xs text-gray-600 uppercase tracking-widest">Now Playing</p>
<div className="text-6xl font-black text-amber-400 leading-none group-hover:text-accent transition-colors">{current}</div>
<div className="text-sm text-gray-500">{currentRN}</div>
<p className="text-[10px] text-gray-700 group-hover:text-gray-500 transition-colors">tap for voicings</p>
</button>
) : (
<p className="text-gray-600 text-xs text-center">Play a chord</p>
)}
</div>
</div>
)