Skip to content

Commit f161a90

Browse files
committed
Fix layout of preview tab
1 parent 96fbc8c commit f161a90

File tree

4 files changed

+213
-61
lines changed

4 files changed

+213
-61
lines changed

tailwind.config.js

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
module.exports = {
2+
// ... other config
3+
theme: {
4+
extend: {
5+
gridTemplateColumns: {
6+
'16': 'repeat(16, minmax(0, 1fr))',
7+
},
8+
},
9+
},
10+
// ... other config
11+
}

websur/src/artifact-component.tsx

+200-59
Original file line numberDiff line numberDiff line change
@@ -132,38 +132,17 @@ const BeatGrid: React.FC<BeatGridProps> = ({ beats = [], totalBeats = 16, groupS
132132
} as Beat);
133133
}
134134

135-
// Group beats
136-
const groups = [];
137-
for (let i = 0; i < totalBeats; i += groupSize) {
138-
const group = beatsToRender.slice(i, i + groupSize);
139-
groups.push(group);
140-
}
141-
142135
return (
143-
<div className="grid grid-cols-4 gap-0 border border-gray-200 rounded-lg">
144-
{groups.map((group, groupIndex) => (
145-
<div key={groupIndex} className="border-r border-gray-200 last:border-r-0">
146-
<div className="grid grid-cols-4">
147-
{group.map((beat, beatIndex) => {
148-
const renderedBeat = renderBeat(beat);
149-
const isLyrics = typeof beat !== 'number' &&
150-
beat?.elements?.some(e => e?.lyrics) || false;
151-
const className = isLyrics ? 'text-blue-600 font-medium' : 'text-black';
152-
153-
return (
154-
<div
155-
key={`${groupIndex}-${beatIndex}`}
156-
className="text-center p-1 border-r border-gray-100 last:border-r-0 relative group"
157-
title={`Beat ${groupIndex * groupSize + beatIndex + 1}`}
158-
>
159-
<span className={className}>{renderedBeat}</span>
160-
<div className="absolute -top-8 left-1/2 transform -translate-x-1/2 bg-black text-white text-xs px-2 py-1 rounded opacity-0 group-hover:opacity-100 transition-opacity duration-200 pointer-events-none">
161-
Beat {groupIndex * groupSize + beatIndex + 1}
162-
</div>
163-
</div>
164-
);
165-
})}
166-
</div>
136+
<div className="grid grid-cols-16 gap-1">
137+
{beatsToRender.map((beat, index) => (
138+
<div
139+
key={index}
140+
className={`border p-2 text-center hover:bg-gray-50 transition-colors ${
141+
index % groupSize === 0 ? 'border-l-2' : ''
142+
}`}
143+
title={`Beat ${index + 1}`}
144+
>
145+
{typeof beat === 'number' ? beat : formatter.formatBeat(beat)}
167146
</div>
168147
))}
169148
</div>
@@ -389,6 +368,71 @@ const SUREditor: React.FC<{ content: string; onChange: (content: string) => void
389368
);
390369
};
391370

371+
interface PreviewProps {
372+
document: SurDocument;
373+
}
374+
375+
const formatter = new SurFormatter();
376+
377+
export function Preview({ document }: PreviewProps) {
378+
if (!document) return null;
379+
380+
// Calculate total beats
381+
const totalBeats = document.composition.sections.reduce(
382+
(sum, section) => sum + section.beats.length,
383+
0
384+
);
385+
386+
return (
387+
<div className="preview-container">
388+
{/* Title Section */}
389+
<h1 className="text-2xl font-bold mb-4">
390+
{document.metadata.name || 'Untitled Composition'}
391+
</h1>
392+
393+
{/* Metadata Section */}
394+
<div className="metadata-section mb-4">
395+
<div className="grid grid-cols-2 gap-2">
396+
<div>Raag:</div>
397+
<div>{document.metadata.raag || 'Not specified'}</div>
398+
<div>Taal:</div>
399+
<div>{document.metadata.taal || 'Not specified'}</div>
400+
<div>Tempo:</div>
401+
<div>{document.metadata.tempo || 'Not specified'}</div>
402+
</div>
403+
</div>
404+
405+
{/* Statistics */}
406+
<div className="stats-section mb-4">
407+
<p>Total Beats: {totalBeats}</p>
408+
</div>
409+
410+
{/* Composition Sections */}
411+
{document.composition.sections.map((section, sectionIndex) => (
412+
<div key={sectionIndex} className="section-container mb-6">
413+
{/* Section Header */}
414+
<h2 className="text-xl font-semibold mb-2">
415+
{section.title || 'Untitled Section'}
416+
</h2>
417+
418+
{/* Beats Grid */}
419+
<div className="grid grid-cols-8 gap-2">
420+
{section.beats.map((beat, beatIndex) => (
421+
<div
422+
key={beatIndex}
423+
className="border p-2 text-center"
424+
title={`Beat ${beatIndex + 1}`}
425+
>
426+
{formatter.formatBeat(beat)}
427+
</div>
428+
))}
429+
</div>
430+
</div>
431+
))}
432+
</div>
433+
);
434+
}
435+
392436
const SUREditorViewer = () => {
393437
const [content, setContent] = useState(DEFAULT_SUR);
394438
const [hideControls, setHideControls] = useState(false);
@@ -410,58 +454,155 @@ const SUREditorViewer = () => {
410454

411455
<TabsContent value="preview">
412456
<Card className="w-full">
413-
<CardHeader className="border-b border-gray-200">
414-
<div className="flex justify-between items-start">
415-
<div onClick={toggleControls}>
416-
<CardTitle className="text-2xl font-bold mb-2">
417-
Preview
418-
</CardTitle>
457+
<CardHeader className="border-b border-gray-200 pb-6">
458+
{/* First Row: Title and Download Button */}
459+
<div className="flex justify-between items-center mb-4">
460+
<CardTitle className="text-3xl font-bold">
461+
{(() => {
462+
try {
463+
const surDoc = parseSURFile(content);
464+
return surDoc.metadata.name || 'Untitled Composition';
465+
} catch (e) {
466+
return 'Preview';
467+
}
468+
})()}
469+
</CardTitle>
470+
{(() => {
471+
try {
472+
const surDoc = parseSURFile(content);
473+
return (
474+
<PDFExporter
475+
config={{
476+
name: surDoc.metadata.name || 'Untitled',
477+
tempo: surDoc.metadata.tempo,
478+
beats_per_row: surDoc.metadata.beats_per_row
479+
}}
480+
composition={surDoc.composition.sections.map(section => ({
481+
title: section.title,
482+
lines: groupBeatsIntoLines(section.beats).map(line => ({
483+
beats: line
484+
}))
485+
}))}
486+
/>
487+
);
488+
} catch (e) {
489+
return null;
490+
}
491+
})()}
492+
</div>
493+
494+
{/* Second Row: Metadata */}
495+
<div className="cursor-pointer" onClick={toggleControls}>
496+
<div className={`metadata-section ${hideControls ? 'hidden' : ''}`}>
497+
{(() => {
498+
try {
499+
const surDoc = parseSURFile(content);
500+
return (
501+
<div className="bg-gray-50 rounded-lg p-4">
502+
<dl className="grid grid-cols-3 gap-6">
503+
<div>
504+
<dt className="text-sm font-medium text-gray-500 mb-1">Raag</dt>
505+
<dd className="text-base font-semibold text-gray-900">
506+
{surDoc.metadata.raag || 'Not specified'}
507+
</dd>
508+
</div>
509+
<div>
510+
<dt className="text-sm font-medium text-gray-500 mb-1">Taal</dt>
511+
<dd className="text-base font-semibold text-gray-900">
512+
{surDoc.metadata.taal || 'Not specified'}
513+
</dd>
514+
</div>
515+
<div>
516+
<dt className="text-sm font-medium text-gray-500 mb-1">Tempo</dt>
517+
<dd className="text-base font-semibold text-gray-900">
518+
{surDoc.metadata.tempo || 'Not specified'}
519+
</dd>
520+
</div>
521+
</dl>
522+
</div>
523+
);
524+
} catch (e) {
525+
return null;
526+
}
527+
})()}
419528
</div>
420529
</div>
421530
</CardHeader>
422-
531+
423532
<CardContent className="p-6">
424533
<div className="space-y-6">
425534
{/* Beat numbers row */}
426535
<div className="mb-3 font-mono text-sm">
427536
<div className="text-gray-600 mb-0.5">Beat:</div>
428-
<BeatGrid
429-
beats={Array.from({length: 16}, (_, i) => i + 1)}
430-
totalBeats={16}
431-
groupSize={4}
432-
/>
537+
<div className="grid grid-cols-4 gap-0 border border-gray-200 rounded-lg">
538+
{[0, 1, 2, 3].map((group) => (
539+
<div key={group} className="border-r border-gray-200 last:border-r-0">
540+
<div className="grid grid-cols-4">
541+
{[1, 2, 3, 4].map((num) => {
542+
const beatNum = group * 4 + num;
543+
return (
544+
<div
545+
key={beatNum}
546+
className="text-center p-2 border-r border-gray-100 last:border-r-0"
547+
title={`Beat ${beatNum}`}
548+
>
549+
{beatNum}
550+
</div>
551+
);
552+
})}
553+
</div>
554+
</div>
555+
))}
556+
</div>
433557
</div>
434-
558+
435559
{/* Composition sections */}
436560
{(() => {
437561
try {
438562
const surDoc = parseSURFile(content);
439-
console.log('Rendering document:', surDoc);
563+
const formatter = new SurFormatter();
440564

441565
return surDoc.composition.sections.map((section, sectionIdx) => {
442-
console.log('Rendering section:', section.title, 'beats:', section.beats);
443-
444-
if (!Array.isArray(section.beats)) {
445-
console.error('Section beats is not an array:', section.beats);
446-
return null;
447-
}
448-
449566
// Group beats into lines
450567
const beatLines = groupBeatsIntoLines(section.beats);
451568

452569
return (
453570
<div key={sectionIdx} className="space-y-1.5">
454-
<h3 className="text-lg font-semibold text-blue-600 mb-1">
571+
<h3 className="text-lg font-semibold text-blue-600 mb-2">
455572
{section.title}
456573
</h3>
457574
<div className="font-mono text-sm space-y-2">
458575
{beatLines.map((beatLine, lineIdx) => (
459-
<BeatGrid
460-
key={`${sectionIdx}-${lineIdx}`}
461-
beats={beatLine}
462-
totalBeats={16}
463-
groupSize={4}
464-
/>
576+
<div key={`${sectionIdx}-${lineIdx}`}
577+
className="grid grid-cols-4 gap-0 border border-gray-200 rounded-lg">
578+
{[0, 1, 2, 3].map((group) => (
579+
<div key={group} className="border-r border-gray-200 last:border-r-0">
580+
<div className="grid grid-cols-4">
581+
{[0, 1, 2, 3].map((num) => {
582+
const beatIndex = group * 4 + num;
583+
const beat = beatLine[beatIndex] || {
584+
elements: [{ note: { pitch: NotePitch.SILENCE } }],
585+
bracketed: false
586+
};
587+
return (
588+
<div
589+
key={beatIndex}
590+
className={`text-center p-2 border-r border-gray-100 last:border-r-0 relative group ${
591+
beat.elements.some(e => e.lyrics) ? 'text-blue-600' : ''
592+
}`}
593+
>
594+
{formatter.formatBeat(beat)}
595+
{/* Tooltip */}
596+
<div className="absolute -top-8 left-1/2 transform -translate-x-1/2 bg-black text-white text-xs px-2 py-1 rounded opacity-0 group-hover:opacity-100 transition-opacity duration-200 pointer-events-none">
597+
Beat {lineIdx * 16 + beatIndex + 1}
598+
</div>
599+
</div>
600+
);
601+
})}
602+
</div>
603+
</div>
604+
))}
605+
</div>
465606
))}
466607
</div>
467608
</div>

websur/src/lib/sur-parser/formatter.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ export class SurFormatter {
8686
);
8787
}
8888

89-
private formatBeat(beat: Beat): string {
89+
public formatBeat(beat: Beat): string {
9090
if (!beat || !beat.elements || beat.elements.length === 0) {
9191
return '-';
9292
}

websur/src/lib/sur-parser/parser.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -302,7 +302,7 @@ export class SurParser {
302302
sections.push(currentSection);
303303
}
304304
currentSection = {
305-
name: trimmedLine.slice(1),
305+
title: trimmedLine.slice(1).trim(),
306306
beats: []
307307
};
308308
currentRow = 0;

0 commit comments

Comments
 (0)