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) => (
))}
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) }} />}
)}
)
}