feat(app): add ChordChart component with monospaced rendering
This commit is contained in:
48
app/app/components/chord-chart.tsx
Normal file
48
app/app/components/chord-chart.tsx
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
import type { Section } from "~/lib/types";
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
sections: Section[];
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildChordRow(chords: { offset: number; chord: string }[]): string {
|
||||||
|
let row = "";
|
||||||
|
for (const { offset, chord } of chords) {
|
||||||
|
while (row.length < offset) row += " ";
|
||||||
|
row += chord;
|
||||||
|
}
|
||||||
|
return row;
|
||||||
|
}
|
||||||
|
|
||||||
|
function SectionBlock({ section }: { section: Section }) {
|
||||||
|
return (
|
||||||
|
<div className="mb-6">
|
||||||
|
{section.label && (
|
||||||
|
<p className="text-xs text-muted-foreground mb-1">[{section.label}]</p>
|
||||||
|
)}
|
||||||
|
{section.lines.map((line, i) => (
|
||||||
|
<div key={i} className="leading-tight">
|
||||||
|
{line.chords.length > 0 && (
|
||||||
|
<pre className="text-primary text-sm font-mono whitespace-pre">
|
||||||
|
{buildChordRow(line.chords)}
|
||||||
|
</pre>
|
||||||
|
)}
|
||||||
|
{line.text && (
|
||||||
|
<pre className="text-foreground text-sm font-mono whitespace-pre">
|
||||||
|
{line.text}
|
||||||
|
</pre>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function ChordChart({ sections }: Props) {
|
||||||
|
return (
|
||||||
|
<div className="px-4 py-3">
|
||||||
|
{sections.map((section, i) => (
|
||||||
|
<SectionBlock key={i} section={section} />
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user