Update chord diagrams to match horizontal fretboard style
This commit is contained in:
1 parent
45c10a9ef5
commit
d0d406360e
1 file changed
+61
-24
+61
-24
@@ -150,42 +150,67 @@ const SONG_LIBRARY = [
|
|||||||
function ChordDiagram({ name }) {
|
function ChordDiagram({ name }) {
|
||||||
const sh = CHORDS[name];
|
const sh = CHORDS[name];
|
||||||
if (!sh) return null;
|
if (!sh) return null;
|
||||||
const NX=8, NG=14, NS=6, NF=4, NY=18, FH=16;
|
|
||||||
const W = NX*2 + NG*(NS-1), H = NY + FH*NF + 8;
|
const NUM_FRETS=5, NS=6, W=320, H=200;
|
||||||
|
const TOP=44, BOT=H-24, LEFT=44, RIGHT=W-12;
|
||||||
|
const strGap=(BOT-TOP)/(NS-1);
|
||||||
|
const fretGap=(RIGHT-LEFT)/NUM_FRETS;
|
||||||
|
const STRING_LABELS=["e","B","G","D","A","E"];
|
||||||
|
|
||||||
|
// Build note list from chord shape: open strings + fretted dots
|
||||||
|
const notes = [];
|
||||||
|
sh.open.forEach(s=>{ notes.push({str:s, fret:0, label:"o", muted:false}); });
|
||||||
|
sh.muted.forEach(s=>{ notes.push({str:s, fret:-1, label:"x", muted:true}); });
|
||||||
|
sh.dots.forEach(({s,f,n})=>{ notes.push({str:s, fret:f, label:n, muted:false, finger:true}); });
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div style={{textAlign:"center"}}>
|
<div style={{background:"#0A0A0E",borderRadius:10,padding:"10px 6px",
|
||||||
<div style={{color:C.amber,fontWeight:700,fontSize:16,marginBottom:8}}>{name}</div>
|
border:"1px solid "+C.fret,marginBottom:8}}>
|
||||||
<svg width={W} height={H}>
|
<div style={{textAlign:"center",marginBottom:6,fontWeight:700,fontSize:15,color:C.amber}}>{name}</div>
|
||||||
<rect x={NX} y={NY-3} width={NG*(NS-1)} height={3} fill={C.text}/>
|
<svg width={W} height={H} style={{display:"block",margin:"0 auto"}}>
|
||||||
{Array.from({length:NF+1},(_,f)=>(
|
<line x1={LEFT} y1={TOP-2} x2={LEFT} y2={BOT+2} stroke={C.text} strokeWidth={3}/>
|
||||||
<line key={f} x1={NX} y1={NY+f*FH} x2={NX+NG*(NS-1)} y2={NY+f*FH} stroke={C.fret} strokeWidth={1}/>
|
{Array.from({length:NUM_FRETS+1},(_,f)=>(
|
||||||
|
<line key={f} x1={LEFT+f*fretGap} y1={TOP} x2={LEFT+f*fretGap} y2={BOT} stroke={C.fret} strokeWidth={1}/>
|
||||||
))}
|
))}
|
||||||
{Array.from({length:NS},(_,s)=>(
|
{Array.from({length:NS},(_,s)=>(
|
||||||
<line key={s} x1={NX+s*NG} y1={NY} x2={NX+s*NG} y2={NY+NF*FH} stroke={C.string} strokeWidth={1}/>
|
<line key={s} x1={LEFT} y1={TOP+s*strGap} x2={RIGHT} y2={TOP+s*strGap}
|
||||||
|
stroke={C.string} strokeWidth={s===0?0.8:s===5?2:1.2}/>
|
||||||
))}
|
))}
|
||||||
{sh.dots.map(({s,f,n},i)=>{
|
{STRING_LABELS.map((n,s)=>(
|
||||||
const cx=NX+s*NG, cy=NY+(f-0.5)*FH;
|
<text key={s} x={LEFT-10} y={TOP+s*strGap+4} textAnchor="middle"
|
||||||
|
fontSize={10} fill={C.amber} fontFamily="monospace" fontWeight="600">{n}</text>
|
||||||
|
))}
|
||||||
|
{Array.from({length:NUM_FRETS},(_,f)=>(
|
||||||
|
<text key={f} x={LEFT+(f+0.5)*fretGap} y={BOT+16} textAnchor="middle"
|
||||||
|
fontSize={9} fill={C.muted} fontFamily="monospace">{f+1}</text>
|
||||||
|
))}
|
||||||
|
{sh.muted.map(s=>{
|
||||||
|
const cy=TOP+s*strGap;
|
||||||
return (
|
return (
|
||||||
<g key={i}>
|
<g key={"m"+s}>
|
||||||
<circle cx={cx} cy={cy} r={6} fill={C.amber}/>
|
<line x1={LEFT-18} y1={cy-6} x2={LEFT-8} y2={cy+6} stroke={C.coral} strokeWidth={2}/>
|
||||||
<text x={cx} y={cy+4} textAnchor="middle" fontSize={8} fill="#1A1A1F">{n}</text>
|
<line x1={LEFT-8} y1={cy-6} x2={LEFT-18} y2={cy+6} stroke={C.coral} strokeWidth={2}/>
|
||||||
</g>
|
</g>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
{sh.open.map(s=>(
|
{sh.open.map(s=>(
|
||||||
<circle key={s} cx={NX+s*NG} cy={NY-9} r={4} fill="none" stroke={C.sage} strokeWidth={1.5}/>
|
<circle key={"o"+s} cx={LEFT-13} cy={TOP+s*strGap} r={5}
|
||||||
|
fill="none" stroke={C.sage} strokeWidth={2}/>
|
||||||
))}
|
))}
|
||||||
{sh.muted.map(s=>{
|
{sh.dots.map(({s,f,n},i)=>{
|
||||||
const cx=NX+s*NG;
|
const cx = LEFT+(f-0.5)*fretGap;
|
||||||
|
const cy = TOP+s*strGap;
|
||||||
return (
|
return (
|
||||||
<g key={s}>
|
<g key={i}>
|
||||||
<line x1={cx-4} y1={NY-13} x2={cx+4} y2={NY-5} stroke={C.coral} strokeWidth={1.5}/>
|
<circle cx={cx} cy={cy} r={14} fill="rgba(212,168,71,0.12)"/>
|
||||||
<line x1={cx+4} y1={NY-13} x2={cx-4} y2={NY-5} stroke={C.coral} strokeWidth={1.5}/>
|
<circle cx={cx} cy={cy} r={11} fill={C.amber}/>
|
||||||
|
<text x={cx} y={cy+5} textAnchor="middle" fontSize={13}
|
||||||
|
fill="#1A1A1F" fontWeight="900" fontFamily="monospace">{n}</text>
|
||||||
</g>
|
</g>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
</svg>
|
</svg>
|
||||||
<div style={{fontFamily:"monospace",fontSize:10,color:C.muted,marginTop:6}}>{sh.label}</div>
|
<div style={{textAlign:"center",fontFamily:"monospace",fontSize:10,color:C.muted,marginTop:4}}>{sh.label}</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -903,8 +928,9 @@ function HamburgerMenu({ onTuner, onBasics, onSongSearch, onClose }) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function GuitarTuner({ onBack, onMenu }) {
|
function GuitarTuner({ onBack, onGoTuner, onGoBasics, onGoSongSearch }) {
|
||||||
const [listening, setListening] = useState(false);
|
const [listening, setListening] = useState(false);
|
||||||
|
const [menuOpen, setMenuOpen] = useState(false);
|
||||||
const [detectedNote, setDetectedNote] = useState("");
|
const [detectedNote, setDetectedNote] = useState("");
|
||||||
const [detectedFreq, setDetectedFreq] = useState(0);
|
const [detectedFreq, setDetectedFreq] = useState(0);
|
||||||
const [cents, setCents] = useState(0);
|
const [cents, setCents] = useState(0);
|
||||||
@@ -981,13 +1007,19 @@ function GuitarTuner({ onBack, onMenu }) {
|
|||||||
<span style={{color:C.amber}}>Guitar</span><span>Teacher</span>
|
<span style={{color:C.amber}}>Guitar</span><span>Teacher</span>
|
||||||
<span style={{fontWeight:600,fontSize:14,color:C.muted,marginLeft:8}}>/ Tuner</span>
|
<span style={{fontWeight:600,fontSize:14,color:C.muted,marginLeft:8}}>/ Tuner</span>
|
||||||
</div>
|
</div>
|
||||||
<button onClick={()=>onMenu()}
|
<button onClick={()=>setMenuOpen(true)}
|
||||||
style={{background:"none",border:"none",cursor:"pointer",padding:4,display:"flex",flexDirection:"column",gap:5}}>
|
style={{background:"none",border:"none",cursor:"pointer",padding:4,display:"flex",flexDirection:"column",gap:5}}>
|
||||||
<div style={{width:22,height:2,background:C.muted,borderRadius:1}}/>
|
<div style={{width:22,height:2,background:C.muted,borderRadius:1}}/>
|
||||||
<div style={{width:22,height:2,background:C.muted,borderRadius:1}}/>
|
<div style={{width:22,height:2,background:C.muted,borderRadius:1}}/>
|
||||||
<div style={{width:22,height:2,background:C.muted,borderRadius:1}}/>
|
<div style={{width:22,height:2,background:C.muted,borderRadius:1}}/>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
{menuOpen && <HamburgerMenu
|
||||||
|
onTuner={()=>{setMenuOpen(false);}}
|
||||||
|
onBasics={()=>{setMenuOpen(false);onGoBasics();}}
|
||||||
|
onSongSearch={()=>{setMenuOpen(false);onGoSongSearch();}}
|
||||||
|
onClose={()=>setMenuOpen(false)}
|
||||||
|
/>}
|
||||||
|
|
||||||
<div style={{flex:1,display:"flex",alignItems:"center",justifyContent:"center",padding:"24px 20px 60px"}}>
|
<div style={{flex:1,display:"flex",alignItems:"center",justifyContent:"center",padding:"24px 20px 60px"}}>
|
||||||
<div style={{maxWidth:480,width:"100%"}}>
|
<div style={{maxWidth:480,width:"100%"}}>
|
||||||
@@ -1227,7 +1259,12 @@ function App() {
|
|||||||
|
|
||||||
const css = "*{box-sizing:border-box;margin:0;padding:0} body{background:#1A1A1F} input::placeholder{color:#9A9490} p+p{margin-top:10px}";
|
const css = "*{box-sizing:border-box;margin:0;padding:0} body{background:#1A1A1F} input::placeholder{color:#9A9490} p+p{margin-top:10px}";
|
||||||
|
|
||||||
if (showTuner) return <GuitarTuner onBack={()=>setShowTuner(false)} onMenu={()=>setMenuOpen(true)}/>;
|
if (showTuner) return <GuitarTuner
|
||||||
|
onBack={()=>setShowTuner(false)}
|
||||||
|
onGoTuner={()=>{}}
|
||||||
|
onGoBasics={()=>{setShowTuner(false);setSplash(false);setLesson(0);}}
|
||||||
|
onGoSongSearch={()=>{setShowTuner(false);setSplash(false);setLesson(7);}}
|
||||||
|
/>;
|
||||||
|
|
||||||
if (splash) return (
|
if (splash) return (
|
||||||
<div style={{background:C.bg,color:C.text,minHeight:"100vh",fontFamily:"sans-serif",display:"flex",flexDirection:"column"}}>
|
<div style={{background:C.bg,color:C.text,minHeight:"100vh",fontFamily:"sans-serif",display:"flex",flexDirection:"column"}}>
|
||||||
|
|||||||
Reference in new issue
Block a user