import { useState } from 'react' import ChordBox from './ChordBox' import MiniPiano from './MiniPiano' import { getGuitarVoicings, getPianoTechniques, parseChord } from '../lib/voicings' import { CHORD_TYPES, NOTES, getChordsInKey, toRomanNumeral } from '../lib/theory' import { FAMOUS_PROGRESSIONS, progressionInKey } from '../lib/education' const CHORD_TYPE_OPTIONS = [ { key: 'maj', label: 'Major' }, { key: 'min', label: 'Minor' }, { key: 'dom7', label: '7' }, { key: 'maj7', label: 'maj7' }, { key: 'min7', label: 'm7' }, { key: 'dim', label: 'dim' }, { key: 'dim7', label: 'dim7' }, { key: 'half_dim', label: 'm7♭5' }, { key: 'aug', label: 'aug' }, { key: 'sus4', label: 'sus4' }, { key: 'sus2', label: 'sus2' }, { key: 'maj6', label: '6' }, { key: 'min6', label: 'm6' }, { key: 'add9', label: 'add9' }, ] const MAJOR_TYPES = new Set(['maj','maj7','maj6','add9','sus4','sus2','aug','dom7']) // ─── Quick-pick chip row ────────────────────────────────────────────────────── function ChipRow({ label, chords, active, keyInfo, onSelect }) { if (!chords?.length) return null return (
{label}
{chords.map(chord => { const rn = keyInfo?.root ? toRomanNumeral(chord, keyInfo.root, keyInfo.mode) : '' return ( ) })}
) } // ─── Guitar voicings grid ───────────────────────────────────────────────────── function GuitarGrid({ chordName }) { const voicings = getGuitarVoicings(chordName) if (!voicings.length) return

No voicings for {chordName}.

return (
{voicings.map((v, i) => (

{v.label}

))}

Purple = chord tone · finger numbers inside dots (1=index 4=pinky) · fret number on left if not starting at fret 1

) } // ─── Piano techniques grid ──────────────────────────────────────────────────── function PianoGrid({ chordName }) { const parsed = parseChord(chordName) const techniques = getPianoTechniques(chordName) const rootPc = parsed?.rootPc ?? 0 if (!techniques.length) return

No techniques for {chordName}.

return (
{techniques.map((t, i) => (

{t.name}

{t.desc}

Tip: {t.tip}

))}
) } // ─── Famous progressions using this chord as tonic ─────────────────────────── function ProgressionCards({ chordName, onChordClick }) { const parsed = parseChord(chordName) if (!parsed) return null const { rootPc, type } = parsed const root = NOTES[rootPc] const isMajor = MAJOR_TYPES.has(type) const matching = FAMOUS_PROGRESSIONS.filter(p => { const q0 = p.qualities[0] return isMajor ? MAJOR_TYPES.has(q0) : !MAJOR_TYPES.has(q0) }).slice(0, 6) return (

Famous progressions with {chordName} as the tonic. Click any chord to see its voicings.

{matching.map(prog => { const chordsHere = progressionInKey(prog, root) return (
{prog.name} {prog.pattern} {prog.genre.slice(0, 2).map(g => ( {g} ))}
{chordsHere.map((c, i) => ( {i < chordsHere.length - 1 && } ))}

{prog.description}

{prog.songs.length > 0 && (

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

)}
) })}
) } // ─── Main panel ─────────────────────────────────────────────────────────────── export default function ExplorePanel({ keyInfo, chordHistory, onChordClick }) { const [open, setOpen] = useState(false) const [root, setRoot] = useState('C') const [typeKey, setTypeKey] = useState('maj') const [view, setView] = useState('guitar') // guitar | piano | progressions const [active, setActive] = useState('') const chordName = root + (CHORD_TYPES[typeKey]?.suffix ?? '') function selectChord(chord) { setActive(chord) const p = parseChord(chord) if (p) { setRoot(NOTES[p.rootPc]); setTypeKey(p.type) } } // Context-aware quick-picks const recentChords = [...new Set([...(chordHistory ?? [])].reverse())].slice(0, 12) const keyChords = keyInfo?.root ? getChordsInKey(keyInfo.root, keyInfo.mode ?? 'major') : [] return (
{open && (
{/* ── Context quick-picks ── */} {(recentChords.length > 0 || keyChords.length > 0) && (
{keyChords.length > 0 && recentChords.length > 0 &&
} {keyChords.length > 0 && ( )}
)} {/* ── Manual chord picker ── */}
{NOTES.map(n => ( ))}
{chordName}
{/* ── View tabs ── */}
{[ { key: 'guitar', label: '🎸 Guitar Voicings' }, { key: 'piano', label: '🎹 Piano Techniques' }, { key: 'progressions', label: '🎵 Progressions' }, ].map(t => ( ))}
{/* ── Content ── */} {view === 'guitar' && } {view === 'piano' && } {view === 'progressions' && { selectChord(c); onChordClick?.(c) }} />}
)}
) }