import { useState } from 'react' import ChordBox from './ChordBox' import RiffDiagram from './RiffDiagram' import { getGuitarVoicings, parseChord } from '../lib/voicings' import { CHORD_TYPES, NOTES, toRomanNumeral } from '../lib/theory' import { findSimilarProgressions, progressionInKey } from '../lib/education' // ─── Scale ideas per mode ───────────────────────────────────────────────────── const SCALE_IDEAS = { major: [ { name: 'Major Pentatonic', intervals: '1–2–3–5–6', scaleIntervals: [0,2,4,7,9], desc: 'Safe and bright. Everything you play will land. Start on the root, end on the root.' }, { name: 'Mixolydian', intervals: '1–2–3–4–5–6–♭7', scaleIntervals: [0,2,4,5,7,9,10], desc: 'Major with a bluesy ♭7. The defining sound of classic rock — Sweet Home Alabama lives here.' }, { name: 'Lydian', intervals: '1–2–3–♯4–5–6–7', scaleIntervals: [0,2,4,6,7,9,11], desc: 'Dreamy and floating. The ♯4 is the magic note — use it on long sustained notes for instant wonder.' }, ], minor: [ { name: 'Minor Pentatonic', intervals: '1–♭3–4–5–♭7', scaleIntervals: [0,3,5,7,10], desc: 'The blues box. Bends on ♭3 and slides to 5 are gold. Start here every time.' }, { name: 'Natural Minor', intervals: '1–2–♭3–4–5–♭6–♭7', scaleIntervals: [0,2,3,5,7,8,10], desc: 'Full Aeolian scale. Melodic and dark. The ♭6 gives it a cinematic quality.' }, { name: 'Dorian', intervals: '1–2–♭3–4–5–6–♭7', scaleIntervals: [0,2,3,5,7,9,10], desc: "Minor with a raised 6th — smooth and soulful. Santana's go-to. That major 6th is everything." }, ], dorian: [ { name: 'Dorian Mode', intervals: '1–2–♭3–4–5–6–♭7', scaleIntervals: [0,2,3,5,7,9,10], desc: "The raised 6th over minor is the colour. Mix freely with minor pentatonic and touch that 6th note." }, { name: 'Minor Pentatonic', intervals: '1–♭3–4–5–♭7', scaleIntervals: [0,3,5,7,10], desc: 'Safe backbone in Dorian. You can ignore the 6th — or highlight it for that Dorian sparkle.' }, { name: 'Blues Scale', intervals: '1–♭3–4–♭5–5–♭7', scaleIntervals: [0,3,5,6,7,10], desc: 'Add the ♭5 passing tone through the 5 — that slide is the essence of blues expression.' }, ], mixolydian: [ { name: 'Mixolydian Mode', intervals: '1–2–3–4–5–6–♭7', scaleIntervals: [0,2,4,5,7,9,10], desc: 'The ♭7 is your signature note. Hit it and slide down — instant swagger.' }, { name: 'Major Pentatonic', intervals: '1–2–3–5–6', scaleIntervals: [0,2,4,7,9], desc: 'Works beautifully over the I chord. Clean and reliable when you need to land safely.' }, { name: 'Blues Scale', intervals: '1–♭3–3–4–5–♭7', scaleIntervals: [0,3,4,5,7,10], desc: 'The hybrid blues scale. Bend the ♭3 up to the 3 — that tension and release is everything.' }, ], phrygian: [ { name: 'Phrygian Mode', intervals: '1–♭2–♭3–4–5–♭6–♭7', scaleIntervals: [0,1,3,5,7,8,10], desc: 'That ♭2 is the spine-chilling note. Lean on it. Spanish fire and metal darkness in one scale.' }, { name: 'Phrygian Dominant',intervals: '1–♭2–3–4–5–♭6–♭7', scaleIntervals: [0,1,4,5,7,8,10], desc: 'Raise the ♭3 to a major 3rd. Flamenco and Middle-Eastern intensity. Dramatic every time.' }, { name: 'Minor Pentatonic', intervals: '1–♭3–4–5–♭7', scaleIntervals: [0,3,5,7,10], desc: 'Avoid the ♭2 and play safe pentatonic runs — then hit the ♭2 as a surprise.' }, ], lydian: [ { name: 'Lydian Mode', intervals: '1–2–3–♯4–5–6–7', scaleIntervals: [0,2,4,6,7,9,11], desc: 'Float on the ♯4. John Williams writes entire film scores in Lydian. Sustain everything.' }, { name: 'Major Pentatonic', intervals: '1–2–3–5–6', scaleIntervals: [0,2,4,7,9], desc: 'The reliable base. Use Lydian mode sparingly on top for colour.' }, { name: 'Lydian Dominant', intervals: '1–2–3–♯4–5–6–♭7', scaleIntervals: [0,2,4,6,7,9,10], desc: 'Lydian with a ♭7 — the jazz/fusion ♯4 chord sound. Herbie Hancock territory.' }, ], } // Fallback const SCALE_FALLBACK = SCALE_IDEAS.major // ─── Style variations for a progression ────────────────────────────────────── const STYLE_VARIATIONS = [ { key: 'open', label: 'Open & Spacious', desc: 'Sus2 and add9 voicings — airy, gentle. Great for quiet intros and ambient sections.', typeMap: { maj: 'sus2', min: 'sus2', dom7: 'sus4', maj7: 'add9', min7: 'sus2', add9: 'sus2', sus4: 'sus4', sus2: 'sus2', dim: 'dim', aug: 'aug', half_dim: 'half_dim', maj6: 'sus2', min6: 'sus2' }, color: 'text-blue-400', border: 'border-blue-900/40', }, { key: 'jazz', label: 'Jazz Upgrade', desc: 'Triads → 7ths — instant sophistication. Works at any tempo, in any band context.', typeMap: { maj: 'maj7', min: 'min7', dom7: 'dom7', add9: 'maj7', sus2: 'sus2', sus4: 'sus4', dim: 'dim7', aug: 'aug', half_dim: 'half_dim', maj6: 'maj6', min6: 'min6' }, color: 'text-amber-400', border: 'border-amber-900/40', }, { key: 'blues', label: 'Blues Stomp', desc: 'Everything → dom7. Gritty, raw, powerful. All three chords want to slide and bend.', typeMap: { maj: 'dom7', min: 'dom7', maj7: 'dom7', min7: 'dom7', add9: 'dom7', sus2: 'dom7', sus4: 'dom7', dim: 'dim7', aug: 'aug', half_dim: 'dom7', maj6: 'dom7', min6: 'dom7' }, color: 'text-red-400', border: 'border-red-900/40', }, { key: 'modern', label: 'Neo-Soul / Modern', desc: "Add9 on majors, m7 on minors. D'Angelo, Thundercat, Childish Gambino territory.", typeMap: { maj: 'add9', min: 'min7', dom7: 'dom7', maj7: 'add9', min7: 'min7', add9: 'add9', sus2: 'sus2', sus4: 'sus4', dim: 'dim', aug: 'aug', half_dim: 'half_dim', maj6: 'add9', min6: 'min7' }, color: 'text-purple-400', border: 'border-purple-900/40', }, ] // Transform a chord via a type map function transformChord(chordStr, typeMap) { const p = parseChord(chordStr) if (!p) return chordStr const newType = typeMap[p.type] ?? p.type return NOTES[p.rootPc] + (CHORD_TYPES[newType]?.suffix ?? '') } // Get best voicings for a chord — prefer open shapes, then low-fret barre function getBestVoicings(chordStr, max = 4) { const all = getGuitarVoicings(chordStr) // Sort: open shapes first (label contains "Open"), then barre const open = all.filter(v => v.label.includes('Open')) const barre = all.filter(v => !v.label.includes('Open')) return [...open, ...barre].slice(0, max) } // ─── Per-chord voicing strip ────────────────────────────────────────────────── function ChordStrip({ chordStr, keyInfo, onChordClick }) { const voicings = getBestVoicings(chordStr, 4) const rn = keyInfo?.root ? toRomanNumeral(chordStr, keyInfo.root, keyInfo.mode) : '' return (
{rn && {rn}} click for all voicings
{voicings.length > 0 ? (
{voicings.map((v, i) => (

{v.label}

))}
) : (

No voicings available.

)}
) } // ─── Style variation section ────────────────────────────────────────────────── function StyleSection({ progression, onChordClick }) { const [expanded, setExpanded] = useState(null) return (
{STYLE_VARIATIONS.map(style => { const isOpen = expanded === style.key const transformed = progression.map(c => transformChord(c, style.typeMap)) return (
{isOpen && (
{transformed.map((c, i) => { const voicings = getBestVoicings(c, 2) return (
{voicings.map((v, vi) => (

{v.label}

))}
) })}
)}
) })}
) } // ─── Similar famous progressions ───────────────────────────────────────────── function SimilarSection({ progression, keyInfo, onChordClick }) { const similar = findSimilarProgressions(progression, keyInfo) if (!similar.length) return (

Play more and lock a key — similar progressions will appear here.

) return (
{similar.slice(0, 3).map(prog => { const chordsHere = keyInfo?.root ? progressionInKey(prog, keyInfo.root) : [] return (
{prog.name} {prog.pattern} {Math.round(prog.score * 100)}% match
{chordsHere.length > 0 && (
{chordsHere.map((c, i) => ( {i < chordsHere.length - 1 && } ))} in {keyInfo?.root} {keyInfo?.mode}
)}

{prog.songs.slice(0, 3).join(' · ')}

) })}
) } // ─── Main panel ─────────────────────────────────────────────────────────────── export default function CurrentJamPanel({ keyInfo, chordHistory, detectedProgression, onChordClick }) { const [open, setOpen] = useState(false) const [view, setView] = useState('voicings') // voicings | scales | styles | similar const { root, mode } = keyInfo ?? {} // Working progression: detected loop or last 4 unique chords const workingProgression = detectedProgression?.length ? detectedProgression : [...new Set([...chordHistory].reverse())].reverse().slice(-4) const scaleIdeas = SCALE_IDEAS[mode] ?? SCALE_FALLBACK const rootPc = root ? NOTES.indexOf(root) : null const hasSession = workingProgression.length > 0 return (
{open && (
{!hasSession ? (

Start listening and play some chords — your jam will appear here.

) : ( <> {/* ── Progression summary ── */}
{root ? ( {root} {mode} ) : ( Key detecting… )} {workingProgression.length > 0 && ( <> · {workingProgression.map((c, i) => ( {c} {root && {toRomanNumeral(c, root, mode)}} {i < workingProgression.length - 1 && } ))} )}
{/* ── View tabs ── */}
{[ { key: 'voicings', label: '🎸 Open Voicings' }, { key: 'scales', label: '🎵 Scales to Solo' }, { key: 'styles', label: '🎨 Style Options' }, { key: 'similar', label: '🔗 Similar Progressions' }, ].map(t => ( ))}
{/* ── Voicings: per chord open shapes ── */} {view === 'voicings' && (

Best open and barre voicings for each chord in your jam. Click a chord name to see all its voicings.

{workingProgression.map(chord => ( ))}
)} {/* ── Scales ── */} {view === 'scales' && (

Scales and modes that fit {root ? `${root} ${mode}` : 'your current key'}. Start with the pentatonic — add the extra notes once you feel comfortable.

{scaleIdeas.map(idea => (
{idea.name} {idea.intervals}
{rootPc !== null && idea.scaleIntervals && (

Purple = root · Grey = scale tone · Fret numbers above

)}

{idea.desc}

))}

Pro tip: always resolve to a chord tone at the end of a phrase — ♭7 leading to root, or 3rd landing on the 1.

)} {/* ── Style options ── */} {view === 'styles' && (

Your progression re-voiced four ways. Expand any style to see the chord boxes.

)} {/* ── Similar progressions ── */} {view === 'similar' && ( )} )}
)}
) }