@@ -3,8 +3,10 @@ import { Card, CardHeader, CardTitle, CardContent } from '@/components/ui/card';
3
3
import { Tabs , TabsContent , TabsList , TabsTrigger } from '@/components/ui/tabs' ;
4
4
import { Button } from '@/components/ui/button' ;
5
5
import { Download , FileText } from 'lucide-react' ;
6
- import { SurParser , SurDocument , Note , Beat , Element , ElementType , NotePitch } from './lib/sur-parser' ;
6
+ import { SurParser , Note , Beat , Element , ElementType , NotePitch } from './lib/sur-parser' ;
7
+ import type { SurDocument , Section } from './lib/sur-parser/types' ;
7
8
import html2pdf from 'html2pdf.js' ;
9
+ import { SurFormatter } from './lib/sur-parser/formatter' ;
8
10
9
11
const DEFAULT_SUR = `%% CONFIG
10
12
name: "Albela Sajan"
@@ -92,31 +94,33 @@ const renderElement = (element: Element): string => {
92
94
}
93
95
94
96
// Return whichever is present
95
- return lyricsStr || noteStr ;
97
+ return lyricsStr || noteStr || '-' ;
96
98
} ;
97
99
98
- const renderBeat = ( beat : Beat ) : string => {
99
- if ( ! beat || ! beat . elements ) {
100
+ const renderBeat = ( beat : Beat | number ) : string => {
101
+ if ( typeof beat === 'number' ) {
102
+ return beat . toString ( ) ;
103
+ }
104
+
105
+ if ( ! beat || ! beat . elements || beat . elements . length === 0 ) {
100
106
return '-' ;
101
107
}
102
108
103
109
const elementStrings = beat . elements . map ( renderElement ) ;
104
110
105
- // Check if any element has lyrics
106
- const hasLyrics = beat . elements . some ( e => e . lyrics ) ;
107
-
108
- if ( hasLyrics ) {
109
- // If has lyrics, add spaces between elements and wrap in brackets
111
+ // Always wrap in brackets if it's marked as bracketed
112
+ if ( beat . bracketed ) {
110
113
return `[${ elementStrings . join ( ' ' ) } ]` ;
111
- } else {
112
- // If only notes, join without spaces
113
- return elementStrings . join ( '' ) ;
114
114
}
115
+
116
+ // Join without spaces for pure notes
117
+ return elementStrings . join ( '' ) ;
115
118
} ;
116
119
120
+ // Update the BeatGrid component to handle the new structure
117
121
const BeatGrid : React . FC < BeatGridProps > = ( { beats = [ ] , totalBeats = 16 , groupSize = 4 } ) => {
118
- const beatsToRender = Array . isArray ( beats ) ? beats : [ ] ;
119
- const groups = [ ] ;
122
+ // Ensure beats is always an array
123
+ const beatsToRender = [ ... beats ] ;
120
124
121
125
// Fill with empty beats if needed
122
126
while ( beatsToRender . length < totalBeats ) {
@@ -129,6 +133,7 @@ const BeatGrid: React.FC<BeatGridProps> = ({ beats = [], totalBeats = 16, groupS
129
133
}
130
134
131
135
// Group beats
136
+ const groups = [ ] ;
132
137
for ( let i = 0 ; i < totalBeats ; i += groupSize ) {
133
138
const group = beatsToRender . slice ( i , i + groupSize ) ;
134
139
groups . push ( group ) ;
@@ -141,7 +146,8 @@ const BeatGrid: React.FC<BeatGridProps> = ({ beats = [], totalBeats = 16, groupS
141
146
< div className = "grid grid-cols-4" >
142
147
{ group . map ( ( beat , beatIndex ) => {
143
148
const renderedBeat = renderBeat ( beat ) ;
144
- const isLyrics = beat ?. elements ?. some ( e => e ?. lyrics ) || false ;
149
+ const isLyrics = typeof beat !== 'number' &&
150
+ beat ?. elements ?. some ( e => e ?. lyrics ) || false ;
145
151
const className = isLyrics ? 'text-blue-600 font-medium' : 'text-black' ;
146
152
147
153
return (
@@ -314,6 +320,16 @@ const PDFExporter: React.FC<{
314
320
) ;
315
321
} ;
316
322
323
+ // Add this helper function at the top level
324
+ const groupBeatsIntoLines = ( beats : Beat [ ] , beatsPerLine : number = 16 ) : Beat [ ] [ ] => {
325
+ const lines : Beat [ ] [ ] = [ ] ;
326
+ for ( let i = 0 ; i < beats . length ; i += beatsPerLine ) {
327
+ lines . push ( beats . slice ( i , i + beatsPerLine ) ) ;
328
+ }
329
+ return lines ;
330
+ } ;
331
+
332
+ // Update the SUREditor component
317
333
const SUREditor : React . FC < { content : string ; onChange : ( content : string ) => void } > = ( { content, onChange } ) => {
318
334
const [ editableContent , setEditableContent ] = useState ( content ) ;
319
335
const parser = new SurParser ( ) ;
@@ -328,16 +344,19 @@ const SUREditor: React.FC<{ content: string; onChange: (content: string) => void
328
344
let previewContent = '' ;
329
345
try {
330
346
const surDoc = parser . parse ( editableContent ) ;
347
+ const formatter = new SurFormatter ( ) ;
348
+
331
349
if ( surDoc . composition . sections . length > 0 ) {
332
- // Build preview section by section
333
350
previewContent = surDoc . composition . sections . map ( section => {
334
- // Add section header
335
351
const sectionLines = [ `#${ section . title } ` ] ;
336
352
337
- // Add each line of beats
338
- section . beats . forEach ( beatLine => {
339
- const renderedBeats = beatLine . map ( beat => renderBeat ( beat ) ) . join ( ' ' ) ;
340
- sectionLines . push ( `b: ${ renderedBeats } ` ) ;
353
+ // Group beats into lines
354
+ const beatLines = groupBeatsIntoLines ( section . beats ) ;
355
+
356
+ beatLines . forEach ( ( beatLine ) => {
357
+ // Use the formatter to format the line
358
+ const renderedLine = formatter . formatLine ( beatLine ) ;
359
+ sectionLines . push ( `b: ${ renderedLine } ` ) ;
341
360
} ) ;
342
361
343
362
return sectionLines . join ( '\n' ) ;
@@ -417,23 +436,37 @@ const SUREditorViewer = () => {
417
436
{ ( ( ) => {
418
437
try {
419
438
const surDoc = parseSURFile ( content ) ;
420
- return surDoc . composition . sections . map ( ( section , sectionIdx ) => (
421
- < div key = { sectionIdx } className = "space-y-1.5" >
422
- < h3 className = "text-lg font-semibold text-blue-600 mb-1" >
423
- { section . title }
424
- </ h3 >
425
- < div className = "font-mono text-sm space-y-2" >
426
- { section . beats . map ( ( beatLine , lineIdx ) => (
427
- < BeatGrid
428
- key = { `${ sectionIdx } -${ lineIdx } ` }
429
- beats = { beatLine }
430
- totalBeats = { 16 }
431
- groupSize = { 4 }
432
- />
433
- ) ) }
439
+ console . log ( 'Rendering document:' , surDoc ) ;
440
+
441
+ 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
+
449
+ // Group beats into lines
450
+ const beatLines = groupBeatsIntoLines ( section . beats ) ;
451
+
452
+ return (
453
+ < div key = { sectionIdx } className = "space-y-1.5" >
454
+ < h3 className = "text-lg font-semibold text-blue-600 mb-1" >
455
+ { section . title }
456
+ </ h3 >
457
+ < div className = "font-mono text-sm space-y-2" >
458
+ { beatLines . map ( ( beatLine , lineIdx ) => (
459
+ < BeatGrid
460
+ key = { `${ sectionIdx } -${ lineIdx } ` }
461
+ beats = { beatLine }
462
+ totalBeats = { 16 }
463
+ groupSize = { 4 }
464
+ />
465
+ ) ) }
466
+ </ div >
434
467
</ div >
435
- </ div >
436
- ) ) ;
468
+ ) ;
469
+ } ) ;
437
470
} catch ( e ) {
438
471
console . error ( 'Error parsing SUR file:' , e ) ;
439
472
return < div > Error parsing SUR file</ div > ;
0 commit comments