@hosanna/chordpro 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE.md +201 -0
- package/README.md +177 -0
- package/dist/chunk-6VAMM7S3.mjs +388 -0
- package/dist/chunk-CTBAE2XK.mjs +1154 -0
- package/dist/chunk-PENNIH4J.mjs +1143 -0
- package/dist/chunk-QZY7KJWK.mjs +749 -0
- package/dist/chunk-TUKJQWXG.mjs +50 -0
- package/dist/editor/index.d.mts +44 -0
- package/dist/editor/index.d.ts +44 -0
- package/dist/editor/index.js +789 -0
- package/dist/editor/index.mjs +16 -0
- package/dist/index.d.mts +5 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +3459 -0
- package/dist/index.mjs +54 -0
- package/dist/parser/index.d.mts +185 -0
- package/dist/parser/index.d.ts +185 -0
- package/dist/parser/index.js +1567 -0
- package/dist/parser/index.mjs +32 -0
- package/dist/renderer/index.d.mts +52 -0
- package/dist/renderer/index.d.ts +52 -0
- package/dist/renderer/index.js +2237 -0
- package/dist/renderer/index.mjs +15 -0
- package/package.json +74 -0
|
@@ -0,0 +1,1154 @@
|
|
|
1
|
+
import {
|
|
2
|
+
chordDictionary,
|
|
3
|
+
parseChordPro,
|
|
4
|
+
transposeChord
|
|
5
|
+
} from "./chunk-PENNIH4J.mjs";
|
|
6
|
+
|
|
7
|
+
// src/renderer/ChordProRenderer.tsx
|
|
8
|
+
import {
|
|
9
|
+
BookOpen,
|
|
10
|
+
Disc,
|
|
11
|
+
Flame,
|
|
12
|
+
HelpCircle,
|
|
13
|
+
Info,
|
|
14
|
+
Key,
|
|
15
|
+
LayoutGrid,
|
|
16
|
+
Music,
|
|
17
|
+
Pause,
|
|
18
|
+
Play,
|
|
19
|
+
Repeat,
|
|
20
|
+
SkipBack,
|
|
21
|
+
SkipForward,
|
|
22
|
+
User,
|
|
23
|
+
X
|
|
24
|
+
} from "lucide-react";
|
|
25
|
+
import React, { useCallback, useMemo as useMemo2, useRef, useState } from "react";
|
|
26
|
+
import YouTube from "react-youtube";
|
|
27
|
+
|
|
28
|
+
// src/renderer/ChordRoll.tsx
|
|
29
|
+
import { useMemo } from "react";
|
|
30
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
31
|
+
function GuitarDiagram({
|
|
32
|
+
frets,
|
|
33
|
+
fingers,
|
|
34
|
+
barre
|
|
35
|
+
}) {
|
|
36
|
+
const maxFret = Math.max(...frets);
|
|
37
|
+
let startFret = 1;
|
|
38
|
+
if (maxFret > 4) {
|
|
39
|
+
const minFret = Math.min(...frets.filter((f) => f > 0));
|
|
40
|
+
startFret = minFret;
|
|
41
|
+
}
|
|
42
|
+
const numFrets = 4;
|
|
43
|
+
const width = 100;
|
|
44
|
+
const height = 110;
|
|
45
|
+
const getStringX = (index) => 14 + index * 14;
|
|
46
|
+
const getFretY = (index) => 22 + index * 20;
|
|
47
|
+
return /* @__PURE__ */ jsxs(
|
|
48
|
+
"svg",
|
|
49
|
+
{
|
|
50
|
+
width,
|
|
51
|
+
height,
|
|
52
|
+
className: "text-m3-text dark:text-m3-dark-text select-none",
|
|
53
|
+
children: [
|
|
54
|
+
/* @__PURE__ */ jsx(
|
|
55
|
+
"line",
|
|
56
|
+
{
|
|
57
|
+
x1: getStringX(0),
|
|
58
|
+
y1: getFretY(0) - (startFret === 1 ? 3 : 0),
|
|
59
|
+
x2: getStringX(5),
|
|
60
|
+
y2: getFretY(0) - (startFret === 1 ? 3 : 0),
|
|
61
|
+
className: "stroke-zinc-800 dark:stroke-zinc-200",
|
|
62
|
+
strokeWidth: startFret === 1 ? 3.5 : 1.5
|
|
63
|
+
}
|
|
64
|
+
),
|
|
65
|
+
startFret > 1 && /* @__PURE__ */ jsxs(
|
|
66
|
+
"text",
|
|
67
|
+
{
|
|
68
|
+
x: getStringX(0) - 4,
|
|
69
|
+
y: getFretY(0) + 12,
|
|
70
|
+
fontSize: "8",
|
|
71
|
+
className: "font-mono font-black fill-m3-primary dark:fill-m3-dark-primary",
|
|
72
|
+
textAnchor: "end",
|
|
73
|
+
children: [
|
|
74
|
+
startFret,
|
|
75
|
+
"\xAA"
|
|
76
|
+
]
|
|
77
|
+
}
|
|
78
|
+
),
|
|
79
|
+
[0, 1, 2, 3, 4, 5].map((idx) => /* @__PURE__ */ jsx(
|
|
80
|
+
"line",
|
|
81
|
+
{
|
|
82
|
+
x1: getStringX(idx),
|
|
83
|
+
y1: getFretY(0),
|
|
84
|
+
x2: getStringX(idx),
|
|
85
|
+
y2: getFretY(numFrets),
|
|
86
|
+
className: "stroke-zinc-400 dark:stroke-zinc-600",
|
|
87
|
+
strokeOpacity: "0.5",
|
|
88
|
+
strokeWidth: "1.2"
|
|
89
|
+
},
|
|
90
|
+
idx
|
|
91
|
+
)),
|
|
92
|
+
[0, 1, 2, 3, 4].map((idx) => /* @__PURE__ */ jsx(
|
|
93
|
+
"line",
|
|
94
|
+
{
|
|
95
|
+
x1: getStringX(0),
|
|
96
|
+
y1: getFretY(idx),
|
|
97
|
+
x2: getStringX(5),
|
|
98
|
+
y2: getFretY(idx),
|
|
99
|
+
className: "stroke-zinc-400 dark:stroke-zinc-600",
|
|
100
|
+
strokeOpacity: "0.4",
|
|
101
|
+
strokeWidth: "1"
|
|
102
|
+
},
|
|
103
|
+
idx
|
|
104
|
+
)),
|
|
105
|
+
barre !== void 0 && (() => {
|
|
106
|
+
const barreFretInWindow = barre - startFret;
|
|
107
|
+
if (barreFretInWindow >= 0 && barreFretInWindow < numFrets) {
|
|
108
|
+
const y = getFretY(barreFretInWindow) + 10;
|
|
109
|
+
const startStr = frets.findIndex((f) => f === barre);
|
|
110
|
+
const endStr = 5;
|
|
111
|
+
if (startStr !== -1) {
|
|
112
|
+
return /* @__PURE__ */ jsx(
|
|
113
|
+
"rect",
|
|
114
|
+
{
|
|
115
|
+
x: getStringX(startStr) - 4,
|
|
116
|
+
y: y - 4,
|
|
117
|
+
width: getStringX(endStr) - getStringX(startStr) + 8,
|
|
118
|
+
height: 8,
|
|
119
|
+
rx: 4,
|
|
120
|
+
className: "fill-m3-primary dark:fill-m3-dark-primary opacity-80"
|
|
121
|
+
}
|
|
122
|
+
);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
return null;
|
|
126
|
+
})(),
|
|
127
|
+
frets.map((fret, stringIdx) => {
|
|
128
|
+
if (fret === -1) {
|
|
129
|
+
return /* @__PURE__ */ jsx(
|
|
130
|
+
"text",
|
|
131
|
+
{
|
|
132
|
+
x: getStringX(stringIdx),
|
|
133
|
+
y: 12,
|
|
134
|
+
fontSize: "10",
|
|
135
|
+
fontWeight: "bold",
|
|
136
|
+
className: "fill-red-500 font-black",
|
|
137
|
+
textAnchor: "middle",
|
|
138
|
+
children: "\xD7"
|
|
139
|
+
},
|
|
140
|
+
stringIdx
|
|
141
|
+
);
|
|
142
|
+
}
|
|
143
|
+
if (fret === 0) {
|
|
144
|
+
return /* @__PURE__ */ jsx(
|
|
145
|
+
"circle",
|
|
146
|
+
{
|
|
147
|
+
cx: getStringX(stringIdx),
|
|
148
|
+
cy: 10,
|
|
149
|
+
r: 2,
|
|
150
|
+
fill: "none",
|
|
151
|
+
className: "stroke-emerald-500",
|
|
152
|
+
strokeWidth: "1.2"
|
|
153
|
+
},
|
|
154
|
+
stringIdx
|
|
155
|
+
);
|
|
156
|
+
}
|
|
157
|
+
const fretInWindow = fret - startFret;
|
|
158
|
+
if (fretInWindow >= 0 && fretInWindow < numFrets) {
|
|
159
|
+
const cx = getStringX(stringIdx);
|
|
160
|
+
const cy = getFretY(fretInWindow) + 10;
|
|
161
|
+
const finger = fingers ? fingers[stringIdx] : 0;
|
|
162
|
+
return /* @__PURE__ */ jsxs("g", { children: [
|
|
163
|
+
!(barre !== void 0 && fret === barre && stringIdx >= frets.findIndex((f) => f === barre)) && /* @__PURE__ */ jsx(
|
|
164
|
+
"circle",
|
|
165
|
+
{
|
|
166
|
+
cx,
|
|
167
|
+
cy,
|
|
168
|
+
r: 5,
|
|
169
|
+
className: "fill-m3-primary dark:fill-m3-dark-primary"
|
|
170
|
+
}
|
|
171
|
+
),
|
|
172
|
+
finger > 0 && /* @__PURE__ */ jsx(
|
|
173
|
+
"text",
|
|
174
|
+
{
|
|
175
|
+
x: cx,
|
|
176
|
+
y: cy + 2.5,
|
|
177
|
+
fontSize: "6.5",
|
|
178
|
+
fontWeight: "bold",
|
|
179
|
+
fill: "white",
|
|
180
|
+
textAnchor: "middle",
|
|
181
|
+
className: "font-bold fill-white",
|
|
182
|
+
children: finger
|
|
183
|
+
}
|
|
184
|
+
)
|
|
185
|
+
] }, stringIdx);
|
|
186
|
+
}
|
|
187
|
+
return null;
|
|
188
|
+
})
|
|
189
|
+
]
|
|
190
|
+
}
|
|
191
|
+
);
|
|
192
|
+
}
|
|
193
|
+
function PianoDiagram({ highlightKeys }) {
|
|
194
|
+
const whiteKeySemitones = [
|
|
195
|
+
0,
|
|
196
|
+
2,
|
|
197
|
+
4,
|
|
198
|
+
5,
|
|
199
|
+
7,
|
|
200
|
+
9,
|
|
201
|
+
11,
|
|
202
|
+
// Octave 1
|
|
203
|
+
12,
|
|
204
|
+
14,
|
|
205
|
+
16,
|
|
206
|
+
17,
|
|
207
|
+
19,
|
|
208
|
+
21,
|
|
209
|
+
23
|
|
210
|
+
// Octave 2
|
|
211
|
+
];
|
|
212
|
+
const keyWidth = 14;
|
|
213
|
+
const keyHeight = 56;
|
|
214
|
+
const blackWidth = 9;
|
|
215
|
+
const blackHeight = 34;
|
|
216
|
+
const blackKeySemitones = [1, 3, 6, 8, 10, 13, 15, 18, 20, 22];
|
|
217
|
+
const getBlackKeyX = (semitone) => {
|
|
218
|
+
const octave = Math.floor(semitone / 12);
|
|
219
|
+
const semitoneInOctave = semitone % 12;
|
|
220
|
+
let whiteIndexBefore = 0;
|
|
221
|
+
if (semitoneInOctave === 1) whiteIndexBefore = 1;
|
|
222
|
+
else if (semitoneInOctave === 3) whiteIndexBefore = 2;
|
|
223
|
+
else if (semitoneInOctave === 6) whiteIndexBefore = 4;
|
|
224
|
+
else if (semitoneInOctave === 8) whiteIndexBefore = 5;
|
|
225
|
+
else if (semitoneInOctave === 10) whiteIndexBefore = 6;
|
|
226
|
+
const absoluteWhiteIndex = octave * 7 + whiteIndexBefore;
|
|
227
|
+
return absoluteWhiteIndex * keyWidth - blackWidth / 2;
|
|
228
|
+
};
|
|
229
|
+
return /* @__PURE__ */ jsxs(
|
|
230
|
+
"svg",
|
|
231
|
+
{
|
|
232
|
+
width: 14 * keyWidth + 2,
|
|
233
|
+
height: keyHeight + 4,
|
|
234
|
+
className: "text-m3-text dark:text-m3-dark-text p-1 rounded-lg bg-zinc-100 dark:bg-zinc-900 border border-m3-border dark:border-m3-dark-border select-none",
|
|
235
|
+
children: [
|
|
236
|
+
whiteKeySemitones.map((st, idx) => {
|
|
237
|
+
const isHighlighted = highlightKeys.includes(st);
|
|
238
|
+
const x = idx * keyWidth + 1;
|
|
239
|
+
return /* @__PURE__ */ jsxs("g", { children: [
|
|
240
|
+
/* @__PURE__ */ jsx(
|
|
241
|
+
"rect",
|
|
242
|
+
{
|
|
243
|
+
x,
|
|
244
|
+
y: 2,
|
|
245
|
+
width: keyWidth - 1,
|
|
246
|
+
height: keyHeight,
|
|
247
|
+
rx: 1.5,
|
|
248
|
+
className: `${isHighlighted ? "fill-m3-primary dark:fill-m3-dark-primary" : "fill-white dark:fill-zinc-800"} stroke-zinc-300 dark:stroke-zinc-700`,
|
|
249
|
+
strokeWidth: "0.8"
|
|
250
|
+
}
|
|
251
|
+
),
|
|
252
|
+
isHighlighted && /* @__PURE__ */ jsx(
|
|
253
|
+
"circle",
|
|
254
|
+
{
|
|
255
|
+
cx: x + (keyWidth - 1) / 2,
|
|
256
|
+
cy: keyHeight - 8,
|
|
257
|
+
r: 2,
|
|
258
|
+
className: "fill-white dark:fill-zinc-900"
|
|
259
|
+
}
|
|
260
|
+
)
|
|
261
|
+
] }, st);
|
|
262
|
+
}),
|
|
263
|
+
blackKeySemitones.map((st) => {
|
|
264
|
+
const isHighlighted = highlightKeys.includes(st);
|
|
265
|
+
const x = getBlackKeyX(st) + 1;
|
|
266
|
+
return /* @__PURE__ */ jsx("g", { children: /* @__PURE__ */ jsx(
|
|
267
|
+
"rect",
|
|
268
|
+
{
|
|
269
|
+
x,
|
|
270
|
+
y: 2,
|
|
271
|
+
width: blackWidth,
|
|
272
|
+
height: blackHeight,
|
|
273
|
+
rx: 1,
|
|
274
|
+
className: `${isHighlighted ? "fill-m3-primary dark:fill-m3-dark-primary" : "fill-zinc-800 dark:fill-zinc-950"} stroke-zinc-900 dark:stroke-black`,
|
|
275
|
+
strokeWidth: "0.8"
|
|
276
|
+
}
|
|
277
|
+
) }, st);
|
|
278
|
+
})
|
|
279
|
+
]
|
|
280
|
+
}
|
|
281
|
+
);
|
|
282
|
+
}
|
|
283
|
+
function ChordRoll({
|
|
284
|
+
uniqueChords,
|
|
285
|
+
transposeVal,
|
|
286
|
+
capoVal = 0,
|
|
287
|
+
onChordClick,
|
|
288
|
+
instrument,
|
|
289
|
+
showDiagrams,
|
|
290
|
+
showChords
|
|
291
|
+
}) {
|
|
292
|
+
const isGuitar = instrument === "guitar";
|
|
293
|
+
const effectiveTranspose = transposeVal - (isGuitar ? capoVal : 0);
|
|
294
|
+
const chordItems = useMemo(() => {
|
|
295
|
+
return uniqueChords.map((chord) => {
|
|
296
|
+
const transposed = transposeChord(chord, effectiveTranspose);
|
|
297
|
+
const fingering = chordDictionary.getFingering(transposed);
|
|
298
|
+
return {
|
|
299
|
+
original: chord,
|
|
300
|
+
transposed,
|
|
301
|
+
fingering
|
|
302
|
+
};
|
|
303
|
+
});
|
|
304
|
+
}, [uniqueChords, effectiveTranspose]);
|
|
305
|
+
if (uniqueChords.length === 0 || !showDiagrams || !showChords) return null;
|
|
306
|
+
return /* @__PURE__ */ jsxs(
|
|
307
|
+
"div",
|
|
308
|
+
{
|
|
309
|
+
className: "w-full select-none mb-6",
|
|
310
|
+
onTouchStart: (e) => e.stopPropagation(),
|
|
311
|
+
onTouchMove: (e) => e.stopPropagation(),
|
|
312
|
+
onTouchEnd: (e) => e.stopPropagation(),
|
|
313
|
+
children: [
|
|
314
|
+
isGuitar && capoVal > 0 && /* @__PURE__ */ jsx("div", { className: "px-4 mb-2 flex items-center justify-between", children: /* @__PURE__ */ jsxs("span", { className: "text-[11px] font-bold text-amber-700 dark:text-amber-400 bg-amber-50 dark:bg-amber-950/50 px-2.5 py-0.5 rounded-md border border-amber-200 dark:border-amber-900/40", children: [
|
|
315
|
+
"Capo na ",
|
|
316
|
+
capoVal,
|
|
317
|
+
"\xAA casa \u2014 acordes em formato relativo"
|
|
318
|
+
] }) }),
|
|
319
|
+
/* @__PURE__ */ jsx("div", { className: "flex flex-row overflow-x-auto gap-6 py-2 px-4 no-scrollbar scroll-smooth", children: chordItems.map((item, idx) => {
|
|
320
|
+
const isPiano = instrument === "piano";
|
|
321
|
+
return /* @__PURE__ */ jsxs(
|
|
322
|
+
"div",
|
|
323
|
+
{
|
|
324
|
+
onClick: () => onChordClick?.(item.transposed),
|
|
325
|
+
className: `flex flex-col items-center p-2 transition-all cursor-pointer hover:opacity-85 shrink-0 ${isPiano ? "w-48" : "w-24"}`,
|
|
326
|
+
title: "Clique para ver detalhes do acorde",
|
|
327
|
+
children: [
|
|
328
|
+
/* @__PURE__ */ jsx("span", { className: "text-xs font-black text-m3-primary dark:text-m3-dark-primary font-mono mb-1.5", children: item.transposed }),
|
|
329
|
+
/* @__PURE__ */ jsx("div", { className: "flex items-center justify-center flex-1 min-h-17.5", children: item.fingering ? isPiano && item.fingering.piano ? /* @__PURE__ */ jsx(
|
|
330
|
+
PianoDiagram,
|
|
331
|
+
{
|
|
332
|
+
highlightKeys: item.fingering.piano.highlightKeys
|
|
333
|
+
}
|
|
334
|
+
) : !isPiano && item.fingering.guitar ? /* @__PURE__ */ jsx(
|
|
335
|
+
GuitarDiagram,
|
|
336
|
+
{
|
|
337
|
+
frets: item.fingering.guitar.frets,
|
|
338
|
+
fingers: item.fingering.guitar.fingers,
|
|
339
|
+
barre: item.fingering.guitar.barre
|
|
340
|
+
}
|
|
341
|
+
) : /* @__PURE__ */ jsx("div", { className: "text-[10px] text-zinc-400 font-mono italic", children: "Sem visual" }) : /* @__PURE__ */ jsx("div", { className: "text-[10px] text-zinc-400 font-mono italic", children: "N\xE3o registado" }) }),
|
|
342
|
+
item.fingering?.piano && /* @__PURE__ */ jsx("span", { className: "text-[9px] font-bold text-m3-secondary dark:text-m3-dark-secondary mt-1.5 font-mono whitespace-nowrap overflow-hidden text-ellipsis max-w-full", children: item.fingering.piano.notes.join(" - ") })
|
|
343
|
+
]
|
|
344
|
+
},
|
|
345
|
+
idx
|
|
346
|
+
);
|
|
347
|
+
}) })
|
|
348
|
+
]
|
|
349
|
+
}
|
|
350
|
+
);
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
// src/renderer/ChordProRenderer.tsx
|
|
354
|
+
import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
355
|
+
var YT_ID_REGEX = /(?:youtu\.be\/|youtube\.com\/(?:embed\/|v\/|watch\?v=|watch\?.+&v=))([^&?]+)/;
|
|
356
|
+
function extractYoutubeId(urlOrId) {
|
|
357
|
+
const match = urlOrId.match(YT_ID_REGEX);
|
|
358
|
+
return match?.[1] || urlOrId;
|
|
359
|
+
}
|
|
360
|
+
function getDuration(duration) {
|
|
361
|
+
const seconds = Number(duration);
|
|
362
|
+
if (isNaN(seconds)) {
|
|
363
|
+
return "00:00";
|
|
364
|
+
} else {
|
|
365
|
+
return `${Math.trunc(seconds / 60)}:${seconds % 60}`;
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
var ChordProRenderer = React.memo(
|
|
369
|
+
({
|
|
370
|
+
content,
|
|
371
|
+
showChords,
|
|
372
|
+
transposeVal = 0,
|
|
373
|
+
capoVal = 0,
|
|
374
|
+
onTransposeChange,
|
|
375
|
+
onCapoChange,
|
|
376
|
+
twoColumnLayout = false,
|
|
377
|
+
fontSize,
|
|
378
|
+
instrument = "guitar",
|
|
379
|
+
showDiagrams = false,
|
|
380
|
+
fileName,
|
|
381
|
+
showYoutubePlayer: showYoutubePlayerProp,
|
|
382
|
+
onShowYoutubePlayerChange,
|
|
383
|
+
scrollContainerRef
|
|
384
|
+
}) => {
|
|
385
|
+
const [ytPlayerRef, setYtPlayerRef] = useState(null);
|
|
386
|
+
const [isPlayingYoutube, setIsPlayingYoutube] = useState(false);
|
|
387
|
+
const [isYoutubeRepeat, setIsYoutubeRepeat] = useState(false);
|
|
388
|
+
const [showYoutubeInternal, setShowYoutubeInternal] = useState(false);
|
|
389
|
+
const showYoutubePlayer = showYoutubePlayerProp ?? showYoutubeInternal;
|
|
390
|
+
const setShowYoutubePlayer = useCallback(
|
|
391
|
+
(val) => {
|
|
392
|
+
setShowYoutubeInternal(val);
|
|
393
|
+
onShowYoutubePlayerChange?.(val);
|
|
394
|
+
},
|
|
395
|
+
[onShowYoutubePlayerChange]
|
|
396
|
+
);
|
|
397
|
+
const isYoutubeRepeatRef = useRef(isYoutubeRepeat);
|
|
398
|
+
isYoutubeRepeatRef.current = isYoutubeRepeat;
|
|
399
|
+
const parsedSong = useMemo2(() => {
|
|
400
|
+
return parseChordPro(content);
|
|
401
|
+
}, [content]);
|
|
402
|
+
const { metadata } = parsedSong;
|
|
403
|
+
const isGuitar = instrument === "guitar";
|
|
404
|
+
const effectiveCapo = isGuitar ? capoVal : 0;
|
|
405
|
+
const effectiveTranspose = transposeVal - effectiveCapo;
|
|
406
|
+
const soundingKey = useMemo2(() => {
|
|
407
|
+
return transposeChord(metadata.key || "C", transposeVal);
|
|
408
|
+
}, [metadata.key, transposeVal]);
|
|
409
|
+
const renderedKey = useMemo2(() => {
|
|
410
|
+
return transposeChord(metadata.key || "C", effectiveTranspose);
|
|
411
|
+
}, [metadata.key, effectiveTranspose]);
|
|
412
|
+
const resolvedUniqueChords = useMemo2(() => {
|
|
413
|
+
const chords = /* @__PURE__ */ new Set();
|
|
414
|
+
for (const section of parsedSong.sections) {
|
|
415
|
+
for (const line of section.lines) {
|
|
416
|
+
if (line.segments) {
|
|
417
|
+
for (const seg of line.segments) {
|
|
418
|
+
if (seg.chord) chords.add(seg.chord);
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
if (line.measures) {
|
|
422
|
+
for (const m of line.measures) {
|
|
423
|
+
for (const c of m.chords) {
|
|
424
|
+
if (c.chord) chords.add(c.chord);
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
return Array.from(chords);
|
|
431
|
+
}, [parsedSong]);
|
|
432
|
+
const [selectedChord, setSelectedChord] = useState(null);
|
|
433
|
+
const [modalInstrument, setModalInstrument] = useState(
|
|
434
|
+
instrument
|
|
435
|
+
);
|
|
436
|
+
const chordFingering = useMemo2(() => {
|
|
437
|
+
if (!selectedChord) return null;
|
|
438
|
+
return chordDictionary.getFingering(selectedChord);
|
|
439
|
+
}, [selectedChord]);
|
|
440
|
+
const handleChordClick = (chord) => {
|
|
441
|
+
setModalInstrument(instrument);
|
|
442
|
+
setSelectedChord(chord);
|
|
443
|
+
};
|
|
444
|
+
return /* @__PURE__ */ jsxs2("div", { className: "relative flex flex-col flex-1 overflow-hidden h-full", children: [
|
|
445
|
+
/* @__PURE__ */ jsx2(
|
|
446
|
+
"div",
|
|
447
|
+
{
|
|
448
|
+
ref: scrollContainerRef,
|
|
449
|
+
className: "flex-1 overflow-y-auto px-4 py-4 sm:px-6 bg-slate-50 dark:bg-slate-950 print-page select-text leading-relaxed no-scrollbar relative",
|
|
450
|
+
children: /* @__PURE__ */ jsxs2("div", { className: "max-w-3xl mx-auto print-song-card", children: [
|
|
451
|
+
/* @__PURE__ */ jsxs2("div", { className: "mb-6 border-b border-neutral-100 dark:border-slate-800 pb-5 select-none", children: [
|
|
452
|
+
/* @__PURE__ */ jsxs2("div", { className: "flex items-start justify-between gap-4 flex-wrap", children: [
|
|
453
|
+
/* @__PURE__ */ jsxs2("div", { children: [
|
|
454
|
+
/* @__PURE__ */ jsx2("h2", { className: "text-2xl font-bold tracking-tight text-neutral-900 dark:text-white", children: metadata.title }),
|
|
455
|
+
metadata.subtitle && /* @__PURE__ */ jsx2("h3", { className: "text-[15px] font-medium text-neutral-600 dark:text-neutral-400 mt-1", children: metadata.subtitle }),
|
|
456
|
+
(metadata.artist || metadata.composer) && /* @__PURE__ */ jsxs2("div", { className: "flex items-center gap-1.5 text-xs text-neutral-500 mt-2 font-medium flex-wrap", children: [
|
|
457
|
+
/* @__PURE__ */ jsx2(User, { className: "w-3.5 h-3.5 text-[#0284c7]" }),
|
|
458
|
+
/* @__PURE__ */ jsxs2("span", { children: [
|
|
459
|
+
"Por:",
|
|
460
|
+
" ",
|
|
461
|
+
[metadata.artist, metadata.composer].filter(Boolean).join(" / ")
|
|
462
|
+
] })
|
|
463
|
+
] }),
|
|
464
|
+
metadata.translator && /* @__PURE__ */ jsxs2("div", { className: "flex items-center gap-1.5 text-xs text-neutral-500 mt-2 font-medium flex-wrap", children: [
|
|
465
|
+
/* @__PURE__ */ jsx2(User, { className: "w-3.5 h-3.5 text-[#0284c7]" }),
|
|
466
|
+
/* @__PURE__ */ jsxs2("span", { children: [
|
|
467
|
+
"Traduzido por: ",
|
|
468
|
+
metadata.translator
|
|
469
|
+
] })
|
|
470
|
+
] }),
|
|
471
|
+
metadata.album && /* @__PURE__ */ jsxs2("div", { className: "flex items-center gap-1.5 text-xs text-neutral-500 mt-1 font-medium", children: [
|
|
472
|
+
/* @__PURE__ */ jsx2(Disc, { className: "w-3.5 h-3.5 text-[#0284c7]" }),
|
|
473
|
+
/* @__PURE__ */ jsxs2("span", { children: [
|
|
474
|
+
"\xC1lbum: ",
|
|
475
|
+
metadata.album
|
|
476
|
+
] })
|
|
477
|
+
] })
|
|
478
|
+
] }),
|
|
479
|
+
/* @__PURE__ */ jsxs2("div", { className: "flex flex-wrap items-center gap-1.5 justify-end", children: [
|
|
480
|
+
metadata.songNumber && /* @__PURE__ */ jsxs2("span", { className: "text-[10px] font-bold bg-neutral-100 dark:bg-slate-800 text-neutral-600 dark:text-neutral-400 px-2 py-1 rounded-lg border border-neutral-200 dark:border-slate-700", children: [
|
|
481
|
+
"N\xBA ",
|
|
482
|
+
metadata.songNumber
|
|
483
|
+
] }),
|
|
484
|
+
(metadata.key || transposeVal !== 0) && /* @__PURE__ */ jsxs2("span", { className: "text-[10px] font-bold bg-indigo-50 dark:bg-indigo-950/40 text-indigo-700 dark:text-indigo-300 px-2.5 py-1 rounded-lg border border-indigo-100 dark:border-indigo-950/50 flex items-center gap-1", children: [
|
|
485
|
+
/* @__PURE__ */ jsx2(Key, { className: "w-3 h-3" }),
|
|
486
|
+
"Tom: ",
|
|
487
|
+
soundingKey
|
|
488
|
+
] }),
|
|
489
|
+
effectiveCapo > 0 && /* @__PURE__ */ jsxs2("span", { className: "text-[10px] font-bold bg-amber-50 dark:bg-amber-950/40 text-amber-700 dark:text-amber-300 px-2.5 py-1 rounded-lg border border-amber-100 dark:border-amber-950/50", children: [
|
|
490
|
+
"Capo: ",
|
|
491
|
+
effectiveCapo,
|
|
492
|
+
"\xAA casa"
|
|
493
|
+
] }),
|
|
494
|
+
effectiveCapo > 0 && /* @__PURE__ */ jsxs2("span", { className: "text-[10px] font-bold bg-emerald-50 dark:bg-emerald-950/40 text-emerald-700 dark:text-emerald-300 px-2.5 py-1 rounded-lg border border-emerald-100 dark:border-emerald-950/50", children: [
|
|
495
|
+
"Formato: ",
|
|
496
|
+
renderedKey
|
|
497
|
+
] }),
|
|
498
|
+
metadata.originalKey && /* @__PURE__ */ jsxs2("span", { className: "text-[10px] font-bold bg-purple-50 dark:bg-purple-950/40 text-purple-700 dark:text-purple-300 px-2.5 py-1 rounded-lg border border-purple-100 dark:border-purple-950/50", children: [
|
|
499
|
+
"Tom Orig: ",
|
|
500
|
+
metadata.originalKey
|
|
501
|
+
] }),
|
|
502
|
+
metadata.capo && metadata.capo !== "0" && effectiveCapo === 0 && /* @__PURE__ */ jsxs2("span", { className: "text-[10px] font-bold bg-amber-50 dark:bg-amber-950/40 text-amber-700 dark:text-amber-300 px-2.5 py-1 rounded-lg border border-amber-100 dark:border-amber-950/50", children: [
|
|
503
|
+
"Capo Orig: ",
|
|
504
|
+
metadata.capo,
|
|
505
|
+
"\xAA casa"
|
|
506
|
+
] }),
|
|
507
|
+
metadata.tempo && /* @__PURE__ */ jsxs2("span", { className: "text-[10px] font-bold bg-emerald-50 dark:bg-emerald-950/40 text-emerald-700 dark:text-emerald-300 px-2.5 py-1 rounded-lg border border-emerald-100 dark:border-emerald-950/50 flex items-center gap-1", children: [
|
|
508
|
+
/* @__PURE__ */ jsx2(Flame, { className: "w-3 h-3" }),
|
|
509
|
+
metadata.tempo,
|
|
510
|
+
" BPM"
|
|
511
|
+
] }),
|
|
512
|
+
metadata.time && /* @__PURE__ */ jsx2("span", { className: "text-[10px] font-bold bg-cyan-50 dark:bg-cyan-950/40 text-cyan-700 dark:text-cyan-300 px-2.5 py-1 rounded-lg border border-cyan-100 dark:border-cyan-950/50", children: metadata.time }),
|
|
513
|
+
metadata.ccli && /* @__PURE__ */ jsxs2("span", { className: "text-[10px] font-bold bg-slate-100 dark:bg-slate-800 text-slate-500 dark:text-slate-400 px-2.5 py-1 rounded-lg border border-slate-200 dark:border-slate-700", children: [
|
|
514
|
+
"CCLI: ",
|
|
515
|
+
metadata.ccli
|
|
516
|
+
] })
|
|
517
|
+
] })
|
|
518
|
+
] }),
|
|
519
|
+
(metadata.copyright || metadata.duration) && /* @__PURE__ */ jsxs2("div", { className: "flex items-center gap-4 text-[10px] text-neutral-400 dark:text-neutral-500 mt-3 pt-3 border-t border-neutral-100 dark:border-slate-800/50", children: [
|
|
520
|
+
metadata.copyright && /* @__PURE__ */ jsxs2("span", { children: [
|
|
521
|
+
"\xA9 ",
|
|
522
|
+
metadata.copyright
|
|
523
|
+
] }),
|
|
524
|
+
metadata.duration && /* @__PURE__ */ jsxs2("span", { children: [
|
|
525
|
+
"Dura\xE7\xE3o: ",
|
|
526
|
+
getDuration(metadata.duration)
|
|
527
|
+
] })
|
|
528
|
+
] }),
|
|
529
|
+
(transposeVal !== 0 || effectiveCapo !== 0) && /* @__PURE__ */ jsxs2("div", { className: "mt-4 bg-indigo-50 dark:bg-indigo-950/40 text-xs px-3 py-2 rounded-xl text-indigo-700 dark:text-indigo-300 flex items-center justify-between border border-indigo-100 dark:border-indigo-950/50 flex-wrap gap-2", children: [
|
|
530
|
+
/* @__PURE__ */ jsxs2("div", { className: "flex items-center gap-2 flex-wrap", children: [
|
|
531
|
+
/* @__PURE__ */ jsxs2("span", { className: "font-semibold", children: [
|
|
532
|
+
"Tom:",
|
|
533
|
+
" ",
|
|
534
|
+
/* @__PURE__ */ jsx2("span", { className: "text-indigo-600 dark:text-indigo-400 font-bold bg-white dark:bg-zinc-900 px-2 py-0.5 rounded border ml-0.5 text-xs", children: soundingKey })
|
|
535
|
+
] }),
|
|
536
|
+
effectiveCapo > 0 && /* @__PURE__ */ jsxs2("span", { className: "font-semibold text-amber-700 dark:text-amber-300", children: [
|
|
537
|
+
"\u2022 Capo:",
|
|
538
|
+
" ",
|
|
539
|
+
/* @__PURE__ */ jsxs2("span", { className: "text-amber-700 dark:text-amber-300 font-bold bg-amber-100 dark:bg-amber-900/60 px-2 py-0.5 rounded border border-amber-300 dark:border-amber-800 text-xs ml-0.5", children: [
|
|
540
|
+
effectiveCapo,
|
|
541
|
+
"\xAA casa (",
|
|
542
|
+
renderedKey,
|
|
543
|
+
")"
|
|
544
|
+
] })
|
|
545
|
+
] })
|
|
546
|
+
] }),
|
|
547
|
+
(onTransposeChange || onCapoChange) && /* @__PURE__ */ jsx2(
|
|
548
|
+
"button",
|
|
549
|
+
{
|
|
550
|
+
type: "button",
|
|
551
|
+
onClick: () => {
|
|
552
|
+
onTransposeChange?.(0);
|
|
553
|
+
onCapoChange?.(0);
|
|
554
|
+
},
|
|
555
|
+
className: "text-[10px] font-bold hover:underline underline-offset-2 uppercase text-indigo-600 dark:text-indigo-400 cursor-pointer",
|
|
556
|
+
children: "Repor Tom / Capo"
|
|
557
|
+
}
|
|
558
|
+
)
|
|
559
|
+
] })
|
|
560
|
+
] }),
|
|
561
|
+
/* @__PURE__ */ jsx2(
|
|
562
|
+
ChordRoll,
|
|
563
|
+
{
|
|
564
|
+
uniqueChords: resolvedUniqueChords,
|
|
565
|
+
transposeVal,
|
|
566
|
+
capoVal: effectiveCapo,
|
|
567
|
+
onChordClick: handleChordClick,
|
|
568
|
+
instrument,
|
|
569
|
+
showDiagrams,
|
|
570
|
+
showChords
|
|
571
|
+
}
|
|
572
|
+
),
|
|
573
|
+
/* @__PURE__ */ jsx2(
|
|
574
|
+
"div",
|
|
575
|
+
{
|
|
576
|
+
className: `font-sans leading-relaxed text-sm select-text ${twoColumnLayout ? "columns-1 sm:columns-2 gap-8 space-y-6 [column-fill:_balance]" : "space-y-6"}`,
|
|
577
|
+
style: fontSize ? { fontSize: `${fontSize}px` } : void 0,
|
|
578
|
+
children: parsedSong.sections.map((section, secIdx) => {
|
|
579
|
+
const isChorus = section.type === "chorus";
|
|
580
|
+
const isBridge = section.type === "bridge";
|
|
581
|
+
if (section.type === "new_song") {
|
|
582
|
+
return /* @__PURE__ */ jsxs2(
|
|
583
|
+
"div",
|
|
584
|
+
{
|
|
585
|
+
className: "w-full my-12 flex items-center justify-center select-none break-before-column",
|
|
586
|
+
children: [
|
|
587
|
+
/* @__PURE__ */ jsx2("div", { className: "flex-1 border-t-2 border-slate-200 dark:border-slate-800 border-dashed" }),
|
|
588
|
+
/* @__PURE__ */ jsx2(Music, { className: "w-5 h-5 mx-4 text-slate-300 dark:text-slate-700" }),
|
|
589
|
+
/* @__PURE__ */ jsx2("div", { className: "flex-1 border-t-2 border-slate-200 dark:border-slate-800 border-dashed" })
|
|
590
|
+
]
|
|
591
|
+
},
|
|
592
|
+
secIdx
|
|
593
|
+
);
|
|
594
|
+
}
|
|
595
|
+
if (section.type === "grid") {
|
|
596
|
+
const maxMeasures = Math.max(
|
|
597
|
+
1,
|
|
598
|
+
...section.lines.map((l) => l.measures?.length || 1)
|
|
599
|
+
);
|
|
600
|
+
return /* @__PURE__ */ jsxs2(
|
|
601
|
+
"div",
|
|
602
|
+
{
|
|
603
|
+
className: `bg-slate-100/60 dark:bg-slate-900/40 p-4 rounded-xl border border-slate-200/80 dark:border-slate-800/60 my-6 ${twoColumnLayout ? "break-inside-avoid-column inline-block w-full" : ""}`,
|
|
604
|
+
children: [
|
|
605
|
+
/* @__PURE__ */ jsxs2("div", { className: "flex items-center justify-between mb-3", children: [
|
|
606
|
+
/* @__PURE__ */ jsxs2("div", { className: "flex items-center gap-1.5 text-[11px] font-bold text-slate-500 dark:text-slate-400 uppercase tracking-wider select-none", children: [
|
|
607
|
+
/* @__PURE__ */ jsx2(LayoutGrid, { className: "w-3.5 h-3.5" }),
|
|
608
|
+
/* @__PURE__ */ jsx2("span", { children: section.label || "Instrumental" })
|
|
609
|
+
] }),
|
|
610
|
+
section.repeat && /* @__PURE__ */ jsxs2("span", { className: "text-[10px] font-black bg-indigo-100 dark:bg-indigo-900/50 text-indigo-700 dark:text-indigo-300 px-2 py-0.5 rounded uppercase border border-indigo-200 dark:border-indigo-800/50", children: [
|
|
611
|
+
"Repetir ",
|
|
612
|
+
section.repeat,
|
|
613
|
+
"x"
|
|
614
|
+
] })
|
|
615
|
+
] }),
|
|
616
|
+
/* @__PURE__ */ jsx2("div", { className: "space-y-1.5 font-medium", children: section.lines.map((line, lineIdx) => /* @__PURE__ */ jsx2(
|
|
617
|
+
LineRenderer,
|
|
618
|
+
{
|
|
619
|
+
line,
|
|
620
|
+
showChords,
|
|
621
|
+
transpose: effectiveTranspose,
|
|
622
|
+
onChordClick: handleChordClick,
|
|
623
|
+
maxGridMeasures: maxMeasures
|
|
624
|
+
},
|
|
625
|
+
lineIdx
|
|
626
|
+
)) })
|
|
627
|
+
]
|
|
628
|
+
},
|
|
629
|
+
secIdx
|
|
630
|
+
);
|
|
631
|
+
}
|
|
632
|
+
if (isChorus || isBridge) {
|
|
633
|
+
const borderColor = isChorus ? "border-m3-primary/30 dark:border-m3-dark-primary/30" : "border-amber-500/30 dark:border-amber-400/30";
|
|
634
|
+
const labelColor = isChorus ? "text-m3-text dark:text-m3-dark-text" : "text-amber-700 dark:text-amber-400";
|
|
635
|
+
const iconColor = isChorus ? "text-m3-secondary" : "text-amber-500";
|
|
636
|
+
return /* @__PURE__ */ jsxs2(
|
|
637
|
+
"div",
|
|
638
|
+
{
|
|
639
|
+
className: `pl-4 md:pl-6 border-l-2 my-6 ${borderColor} ${twoColumnLayout ? "break-inside-avoid-column inline-block w-full" : ""}`,
|
|
640
|
+
children: [
|
|
641
|
+
/* @__PURE__ */ jsxs2(
|
|
642
|
+
"div",
|
|
643
|
+
{
|
|
644
|
+
className: `flex items-center gap-1.5 text-[11px] font-bold uppercase tracking-wider mb-3 select-none ${labelColor}`,
|
|
645
|
+
children: [
|
|
646
|
+
/* @__PURE__ */ jsx2(
|
|
647
|
+
Music,
|
|
648
|
+
{
|
|
649
|
+
className: `w-3.5 h-3.5 shrink-0 ${iconColor}`
|
|
650
|
+
}
|
|
651
|
+
),
|
|
652
|
+
/* @__PURE__ */ jsx2("span", { children: section.label || (isChorus ? "Refr\xE3o" : "Ponte") }),
|
|
653
|
+
section.repeat && /* @__PURE__ */ jsxs2(
|
|
654
|
+
"span",
|
|
655
|
+
{
|
|
656
|
+
className: `ml-2 px-2 py-0.5 rounded text-[10px] font-black border ${isChorus ? "bg-blue-100/50 border-blue-200 text-blue-700 dark:bg-blue-900/30 dark:border-blue-800 dark:text-blue-300" : "bg-amber-100/50 border-amber-200 text-amber-700 dark:bg-amber-900/30 dark:border-amber-800 dark:text-amber-300"}`,
|
|
657
|
+
children: [
|
|
658
|
+
section.repeat,
|
|
659
|
+
"x"
|
|
660
|
+
]
|
|
661
|
+
}
|
|
662
|
+
)
|
|
663
|
+
]
|
|
664
|
+
}
|
|
665
|
+
),
|
|
666
|
+
/* @__PURE__ */ jsx2("div", { className: "space-y-4 font-medium", children: section.lines.length === 0 ? /* @__PURE__ */ jsx2(
|
|
667
|
+
"div",
|
|
668
|
+
{
|
|
669
|
+
className: `text-xs italic my-1 opacity-70 ${labelColor}`,
|
|
670
|
+
children: "(Repete o refr\xE3o)"
|
|
671
|
+
}
|
|
672
|
+
) : section.lines.map((line, lineIdx) => /* @__PURE__ */ jsx2(
|
|
673
|
+
LineRenderer,
|
|
674
|
+
{
|
|
675
|
+
line,
|
|
676
|
+
showChords,
|
|
677
|
+
transpose: effectiveTranspose,
|
|
678
|
+
onChordClick: handleChordClick
|
|
679
|
+
},
|
|
680
|
+
lineIdx
|
|
681
|
+
)) })
|
|
682
|
+
]
|
|
683
|
+
},
|
|
684
|
+
secIdx
|
|
685
|
+
);
|
|
686
|
+
}
|
|
687
|
+
if (section.type === "tab") {
|
|
688
|
+
return /* @__PURE__ */ jsxs2(
|
|
689
|
+
"div",
|
|
690
|
+
{
|
|
691
|
+
className: `bg-slate-900 p-4 pt-6 rounded-xl shadow-inner border border-slate-800 my-6 select-text relative group ${twoColumnLayout ? "break-inside-avoid-column inline-block w-full" : ""}`,
|
|
692
|
+
children: [
|
|
693
|
+
/* @__PURE__ */ jsx2("div", { className: "absolute top-0 left-4 -translate-y-1/2 bg-slate-800 text-[10px] font-bold text-slate-300 uppercase tracking-widest px-2 py-0.5 rounded border border-slate-700 shadow-sm select-none", children: section.label || "Tablatura" }),
|
|
694
|
+
/* @__PURE__ */ jsx2("div", { className: "overflow-x-auto no-scrollbar", children: /* @__PURE__ */ jsx2("pre", { className: "font-mono text-[13px] md:text-sm text-slate-300 leading-relaxed whitespace-pre drop-shadow-sm", children: section.lines.map((line) => line.text || "").join("\n") }) })
|
|
695
|
+
]
|
|
696
|
+
},
|
|
697
|
+
secIdx
|
|
698
|
+
);
|
|
699
|
+
}
|
|
700
|
+
if (section.type === "comment") {
|
|
701
|
+
return /* @__PURE__ */ jsx2(
|
|
702
|
+
"div",
|
|
703
|
+
{
|
|
704
|
+
className: `my-2 select-none pl-3 text-[11px] italic text-m3-secondary/70 dark:text-m3-dark-secondary/70 ${twoColumnLayout ? "break-inside-avoid-column inline-block w-full" : ""}`,
|
|
705
|
+
children: section.lines.map((l) => l.text).join(", ")
|
|
706
|
+
},
|
|
707
|
+
secIdx
|
|
708
|
+
);
|
|
709
|
+
}
|
|
710
|
+
return /* @__PURE__ */ jsxs2(
|
|
711
|
+
"div",
|
|
712
|
+
{
|
|
713
|
+
className: `relative pl-6 sm:pl-8 border-l border-m3-border/30 dark:border-m3-dark-border/30 py-1.5 my-4 ${twoColumnLayout ? "break-inside-avoid-column inline-block w-full" : ""}`,
|
|
714
|
+
children: [
|
|
715
|
+
section.label && /* @__PURE__ */ jsx2("div", { className: "absolute -left-0.5 top-0 bottom-0 w-0.5 bg-m3-secondary/20 dark:bg-m3-dark-secondary/20 rounded-full" }),
|
|
716
|
+
section.label && /* @__PURE__ */ jsxs2("div", { className: "flex items-center gap-1.5 text-[11px] font-bold text-m3-text/60 dark:text-m3-dark-text/60 uppercase tracking-wider mb-3 select-none", children: [
|
|
717
|
+
/* @__PURE__ */ jsx2(Music, { className: "w-3.5 h-3.5 text-m3-secondary/60 shrink-0" }),
|
|
718
|
+
/* @__PURE__ */ jsx2("span", { children: section.label }),
|
|
719
|
+
section.repeat && /* @__PURE__ */ jsxs2("span", { className: "ml-2 bg-slate-100 dark:bg-slate-800 text-slate-600 dark:text-slate-300 px-2 py-0.5 rounded text-[10px] font-black border border-slate-200 dark:border-slate-700", children: [
|
|
720
|
+
section.repeat,
|
|
721
|
+
"x"
|
|
722
|
+
] })
|
|
723
|
+
] }),
|
|
724
|
+
/* @__PURE__ */ jsx2("div", { className: "space-y-4", children: section.lines.map((line, lineIdx) => /* @__PURE__ */ jsx2(
|
|
725
|
+
LineRenderer,
|
|
726
|
+
{
|
|
727
|
+
line,
|
|
728
|
+
showChords,
|
|
729
|
+
transpose: effectiveTranspose,
|
|
730
|
+
onChordClick: handleChordClick
|
|
731
|
+
},
|
|
732
|
+
lineIdx
|
|
733
|
+
)) })
|
|
734
|
+
]
|
|
735
|
+
},
|
|
736
|
+
secIdx
|
|
737
|
+
);
|
|
738
|
+
})
|
|
739
|
+
}
|
|
740
|
+
),
|
|
741
|
+
/* @__PURE__ */ jsxs2("div", { className: "border-t border-neutral-100 dark:border-zinc-900 pt-6 mt-12 pb-12 text-center text-[10px] text-neutral-400 dark:text-neutral-500 select-none space-y-1.5", children: [
|
|
742
|
+
metadata.artist && /* @__PURE__ */ jsxs2("p", { children: [
|
|
743
|
+
"Artista Original: ",
|
|
744
|
+
metadata.artist
|
|
745
|
+
] }),
|
|
746
|
+
metadata.composer && /* @__PURE__ */ jsxs2("p", { children: [
|
|
747
|
+
"Compositor: ",
|
|
748
|
+
metadata.composer
|
|
749
|
+
] }),
|
|
750
|
+
metadata.lyricist && /* @__PURE__ */ jsxs2("p", { children: [
|
|
751
|
+
"Letra: ",
|
|
752
|
+
metadata.lyricist
|
|
753
|
+
] }),
|
|
754
|
+
metadata.arranger && /* @__PURE__ */ jsxs2("p", { children: [
|
|
755
|
+
"Arranjo: ",
|
|
756
|
+
metadata.arranger
|
|
757
|
+
] }),
|
|
758
|
+
metadata.year && /* @__PURE__ */ jsxs2("p", { children: [
|
|
759
|
+
"Ano: ",
|
|
760
|
+
metadata.year
|
|
761
|
+
] }),
|
|
762
|
+
metadata.originalKey && /* @__PURE__ */ jsxs2("p", { children: [
|
|
763
|
+
"Tom Original: ",
|
|
764
|
+
metadata.originalKey
|
|
765
|
+
] }),
|
|
766
|
+
/* @__PURE__ */ jsxs2("div", { className: "pt-2 mt-2 border-t border-neutral-50/50 dark:border-zinc-900/50 inline-block", children: [
|
|
767
|
+
metadata.copyright && /* @__PURE__ */ jsxs2("p", { children: [
|
|
768
|
+
"\xA9 Copyright: ",
|
|
769
|
+
metadata.copyright
|
|
770
|
+
] }),
|
|
771
|
+
metadata.ccli && /* @__PURE__ */ jsxs2("p", { children: [
|
|
772
|
+
"CCLI: ",
|
|
773
|
+
metadata.ccli
|
|
774
|
+
] })
|
|
775
|
+
] }),
|
|
776
|
+
fileName && /* @__PURE__ */ jsxs2("p", { className: "mt-4 opacity-50", children: [
|
|
777
|
+
"Ficheiro base: ",
|
|
778
|
+
fileName
|
|
779
|
+
] })
|
|
780
|
+
] })
|
|
781
|
+
] })
|
|
782
|
+
}
|
|
783
|
+
),
|
|
784
|
+
metadata.youtube && showYoutubePlayer && /* @__PURE__ */ jsx2("div", { className: "hidden", children: /* @__PURE__ */ jsx2(
|
|
785
|
+
YouTube,
|
|
786
|
+
{
|
|
787
|
+
videoId: extractYoutubeId(metadata.youtube),
|
|
788
|
+
opts: {
|
|
789
|
+
height: "0",
|
|
790
|
+
width: "0",
|
|
791
|
+
playerVars: { autoplay: 1, controls: 0, disablekb: 1 }
|
|
792
|
+
},
|
|
793
|
+
onReady: (e) => {
|
|
794
|
+
setYtPlayerRef(e.target);
|
|
795
|
+
e.target.pauseVideo();
|
|
796
|
+
setIsPlayingYoutube(false);
|
|
797
|
+
},
|
|
798
|
+
onPlay: () => setIsPlayingYoutube(true),
|
|
799
|
+
onPause: () => setIsPlayingYoutube(false),
|
|
800
|
+
onEnd: (e) => {
|
|
801
|
+
if (isYoutubeRepeatRef.current) {
|
|
802
|
+
e.target.seekTo(0, true);
|
|
803
|
+
e.target.playVideo();
|
|
804
|
+
} else {
|
|
805
|
+
setIsPlayingYoutube(false);
|
|
806
|
+
}
|
|
807
|
+
}
|
|
808
|
+
}
|
|
809
|
+
) }),
|
|
810
|
+
showYoutubePlayer && metadata.youtube && /* @__PURE__ */ jsxs2("div", { className: "fixed bottom-0 left-0 right-0 h-16 bg-m3-card dark:bg-m3-dark-card border-t border-m3-border dark:border-m3-dark-border shadow-[0_-4px_10px_rgba(0,0,0,0.05)] z-[200] px-4 flex items-center justify-between animate-in slide-in-from-bottom-full", children: [
|
|
811
|
+
/* @__PURE__ */ jsxs2("div", { className: "flex items-center gap-3", children: [
|
|
812
|
+
/* @__PURE__ */ jsx2("div", { className: "w-10 h-10 rounded overflow-hidden bg-slate-200 dark:bg-slate-800 shrink-0 border border-m3-border/50", children: metadata.youtube.match(YT_ID_REGEX) || metadata.youtube.match(/^[^&?]+$/) ? /* @__PURE__ */ jsx2(
|
|
813
|
+
"img",
|
|
814
|
+
{
|
|
815
|
+
src: `https://img.youtube.com/vi/${extractYoutubeId(metadata.youtube)}/default.jpg`,
|
|
816
|
+
alt: "YouTube Thumbnail",
|
|
817
|
+
className: "w-full h-full object-cover scale-150"
|
|
818
|
+
}
|
|
819
|
+
) : /* @__PURE__ */ jsx2(Disc, { className: "w-5 h-5 m-auto mt-2.5 text-m3-secondary opacity-50" }) }),
|
|
820
|
+
/* @__PURE__ */ jsxs2("div", { className: "hidden sm:block", children: [
|
|
821
|
+
/* @__PURE__ */ jsx2("p", { className: "text-[10px] font-black text-m3-text dark:text-m3-dark-text truncate max-w-[120px]", children: metadata.title }),
|
|
822
|
+
/* @__PURE__ */ jsx2("p", { className: "text-[9px] text-m3-secondary font-medium", children: "\xC1udio do YouTube" })
|
|
823
|
+
] })
|
|
824
|
+
] }),
|
|
825
|
+
/* @__PURE__ */ jsxs2("div", { className: "flex items-center gap-4", children: [
|
|
826
|
+
/* @__PURE__ */ jsx2(
|
|
827
|
+
"button",
|
|
828
|
+
{
|
|
829
|
+
onClick: async () => {
|
|
830
|
+
if (!ytPlayerRef) return;
|
|
831
|
+
const t = await ytPlayerRef.getCurrentTime();
|
|
832
|
+
ytPlayerRef.seekTo(Math.max(0, t - 10), true);
|
|
833
|
+
},
|
|
834
|
+
className: "text-m3-secondary hover:text-m3-primary transition-colors active:scale-95",
|
|
835
|
+
title: "Retroceder 10s",
|
|
836
|
+
children: /* @__PURE__ */ jsx2(SkipBack, { className: "w-4 h-4" })
|
|
837
|
+
}
|
|
838
|
+
),
|
|
839
|
+
/* @__PURE__ */ jsx2(
|
|
840
|
+
"button",
|
|
841
|
+
{
|
|
842
|
+
onClick: () => {
|
|
843
|
+
if (!ytPlayerRef) return;
|
|
844
|
+
if (isPlayingYoutube) ytPlayerRef.pauseVideo();
|
|
845
|
+
else ytPlayerRef.playVideo();
|
|
846
|
+
},
|
|
847
|
+
className: "w-10 h-10 rounded-full bg-m3-primary text-white flex items-center justify-center hover:opacity-95 shadow-md active:scale-95 transition-all",
|
|
848
|
+
children: isPlayingYoutube ? /* @__PURE__ */ jsx2(Pause, { className: "w-5 h-5" }) : /* @__PURE__ */ jsx2(Play, { className: "w-5 h-5 ml-1" })
|
|
849
|
+
}
|
|
850
|
+
),
|
|
851
|
+
/* @__PURE__ */ jsx2(
|
|
852
|
+
"button",
|
|
853
|
+
{
|
|
854
|
+
onClick: async () => {
|
|
855
|
+
if (!ytPlayerRef) return;
|
|
856
|
+
const t = await ytPlayerRef.getCurrentTime();
|
|
857
|
+
ytPlayerRef.seekTo(t + 10, true);
|
|
858
|
+
},
|
|
859
|
+
className: "text-m3-secondary hover:text-m3-primary transition-colors active:scale-95",
|
|
860
|
+
children: /* @__PURE__ */ jsx2(SkipForward, { className: "w-4 h-4" })
|
|
861
|
+
}
|
|
862
|
+
),
|
|
863
|
+
/* @__PURE__ */ jsx2(
|
|
864
|
+
"button",
|
|
865
|
+
{
|
|
866
|
+
onClick: () => setIsYoutubeRepeat((r) => !r),
|
|
867
|
+
className: `ml-2 transition-colors active:scale-95 ${isYoutubeRepeat ? "text-m3-primary" : "text-m3-secondary hover:text-m3-text"}`,
|
|
868
|
+
children: /* @__PURE__ */ jsx2(Repeat, { className: "w-4 h-4" })
|
|
869
|
+
}
|
|
870
|
+
)
|
|
871
|
+
] }),
|
|
872
|
+
/* @__PURE__ */ jsx2("div", { className: "flex items-center gap-2", children: /* @__PURE__ */ jsx2(
|
|
873
|
+
"button",
|
|
874
|
+
{
|
|
875
|
+
onClick: () => {
|
|
876
|
+
ytPlayerRef?.pauseVideo();
|
|
877
|
+
setIsPlayingYoutube(false);
|
|
878
|
+
setShowYoutubePlayer(false);
|
|
879
|
+
},
|
|
880
|
+
className: "p-2 text-m3-secondary hover:text-red-500 transition-colors",
|
|
881
|
+
children: /* @__PURE__ */ jsx2(X, { className: "w-4 h-4" })
|
|
882
|
+
}
|
|
883
|
+
) })
|
|
884
|
+
] }),
|
|
885
|
+
selectedChord && /* @__PURE__ */ jsx2("div", { className: "fixed inset-0 bg-black/60 z-50 flex items-center justify-center p-4 select-none animate-in fade-in duration-200", children: /* @__PURE__ */ jsxs2("div", { className: "bg-m3-card dark:bg-m3-dark-card border border-m3-border dark:border-m3-dark-border rounded-3xl w-full max-w-sm overflow-hidden shadow-2xl flex flex-col p-6 space-y-4 animate-in zoom-in-95 duration-200", children: [
|
|
886
|
+
/* @__PURE__ */ jsxs2("div", { className: "flex items-center justify-between", children: [
|
|
887
|
+
/* @__PURE__ */ jsxs2("div", { className: "flex items-center gap-2", children: [
|
|
888
|
+
/* @__PURE__ */ jsx2(BookOpen, { className: "w-5 h-5 text-m3-primary dark:text-m3-dark-primary" }),
|
|
889
|
+
/* @__PURE__ */ jsxs2("h3", { className: "text-sm font-black text-m3-text dark:text-m3-dark-text uppercase tracking-wider", children: [
|
|
890
|
+
"Dicion\xE1rio: ",
|
|
891
|
+
selectedChord
|
|
892
|
+
] })
|
|
893
|
+
] }),
|
|
894
|
+
/* @__PURE__ */ jsx2(
|
|
895
|
+
"button",
|
|
896
|
+
{
|
|
897
|
+
onClick: () => setSelectedChord(null),
|
|
898
|
+
className: "p-1 rounded-full hover:bg-m3-hover dark:hover:bg-m3-dark-hover text-m3-secondary dark:text-m3-dark-secondary",
|
|
899
|
+
children: /* @__PURE__ */ jsx2(X, { className: "w-5 h-5" })
|
|
900
|
+
}
|
|
901
|
+
)
|
|
902
|
+
] }),
|
|
903
|
+
/* @__PURE__ */ jsxs2("div", { className: "flex bg-m3-sidebar dark:bg-m3-dark-sidebar p-1 rounded-2xl border border-m3-border dark:border-m3-dark-border", children: [
|
|
904
|
+
/* @__PURE__ */ jsx2(
|
|
905
|
+
"button",
|
|
906
|
+
{
|
|
907
|
+
onClick: () => setModalInstrument("guitar"),
|
|
908
|
+
className: `flex-1 py-2 text-xs font-bold rounded-xl transition-all ${modalInstrument === "guitar" ? "bg-m3-primary text-white shadow-sm" : "text-m3-secondary dark:text-m3-dark-secondary hover:text-m3-text"}`,
|
|
909
|
+
children: "Diagrama de Guitarra"
|
|
910
|
+
}
|
|
911
|
+
),
|
|
912
|
+
/* @__PURE__ */ jsx2(
|
|
913
|
+
"button",
|
|
914
|
+
{
|
|
915
|
+
onClick: () => setModalInstrument("piano"),
|
|
916
|
+
className: `flex-1 py-2 text-xs font-bold rounded-xl transition-all ${modalInstrument === "piano" ? "bg-m3-primary text-white shadow-sm" : "text-m3-secondary dark:text-m3-dark-secondary hover:text-m3-text"}`,
|
|
917
|
+
children: "Teclado de Piano"
|
|
918
|
+
}
|
|
919
|
+
)
|
|
920
|
+
] }),
|
|
921
|
+
/* @__PURE__ */ jsx2("div", { className: "py-4 flex flex-col items-center justify-center min-h-[140px] border border-m3-border/30 dark:border-m3-dark-border/30 rounded-2xl bg-m3-sidebar/30 dark:bg-m3-dark-sidebar/10", children: chordFingering ? modalInstrument === "guitar" && chordFingering.guitar ? /* @__PURE__ */ jsx2(
|
|
922
|
+
GuitarDiagram,
|
|
923
|
+
{
|
|
924
|
+
frets: chordFingering.guitar.frets,
|
|
925
|
+
fingers: chordFingering.guitar.fingers,
|
|
926
|
+
barre: chordFingering.guitar.barre
|
|
927
|
+
}
|
|
928
|
+
) : modalInstrument === "piano" && chordFingering.piano ? /* @__PURE__ */ jsx2(
|
|
929
|
+
PianoDiagram,
|
|
930
|
+
{
|
|
931
|
+
highlightKeys: chordFingering.piano.highlightKeys
|
|
932
|
+
}
|
|
933
|
+
) : /* @__PURE__ */ jsxs2("div", { className: "text-center p-4", children: [
|
|
934
|
+
/* @__PURE__ */ jsx2(HelpCircle, { className: "w-8 h-8 mx-auto text-amber-500 opacity-80 mb-2" }),
|
|
935
|
+
/* @__PURE__ */ jsxs2("p", { className: "text-xs text-m3-secondary dark:text-m3-dark-secondary font-medium", children: [
|
|
936
|
+
"O diagrama para",
|
|
937
|
+
" ",
|
|
938
|
+
modalInstrument === "guitar" ? "Guitarra" : "Piano",
|
|
939
|
+
" ",
|
|
940
|
+
"n\xE3o p\xF4de ser calculado."
|
|
941
|
+
] })
|
|
942
|
+
] }) : /* @__PURE__ */ jsxs2("div", { className: "text-center p-6 space-y-2", children: [
|
|
943
|
+
/* @__PURE__ */ jsx2(HelpCircle, { className: "w-8 h-8 mx-auto text-amber-500 opacity-80" }),
|
|
944
|
+
/* @__PURE__ */ jsxs2("p", { className: "text-xs text-m3-text dark:text-m3-dark-text font-bold", children: [
|
|
945
|
+
'Acorde "',
|
|
946
|
+
selectedChord,
|
|
947
|
+
'" n\xE3o registado'
|
|
948
|
+
] }),
|
|
949
|
+
/* @__PURE__ */ jsx2("p", { className: "text-[10px] text-m3-secondary dark:text-m3-dark-secondary max-w-[200px] leading-normal", children: "Este acorde n\xE3o se encontra no nosso dicion\xE1rio estrito, mas pode toc\xE1-lo com as notas de acompanhamento habituais." })
|
|
950
|
+
] }) }),
|
|
951
|
+
chordFingering?.piano && /* @__PURE__ */ jsxs2("div", { className: "text-center font-mono text-xs text-m3-secondary dark:text-m3-dark-secondary bg-m3-sidebar dark:bg-m3-dark-sidebar py-2 rounded-xl", children: [
|
|
952
|
+
"Notas do Acorde:",
|
|
953
|
+
" ",
|
|
954
|
+
/* @__PURE__ */ jsx2("span", { className: "font-bold text-m3-primary dark:text-m3-dark-primary", children: chordFingering.piano.notes.join(" - ") })
|
|
955
|
+
] }),
|
|
956
|
+
/* @__PURE__ */ jsx2(
|
|
957
|
+
"button",
|
|
958
|
+
{
|
|
959
|
+
onClick: () => setSelectedChord(null),
|
|
960
|
+
className: "w-full bg-m3-sidebar dark:bg-m3-dark-sidebar hover:bg-m3-hover dark:hover:bg-m3-dark-hover text-m3-text dark:text-m3-dark-text text-xs py-3 rounded-2xl border border-m3-border dark:border-m3-dark-border font-bold active:scale-95 transition-all",
|
|
961
|
+
children: "Voltar ao C\xE2ntico"
|
|
962
|
+
}
|
|
963
|
+
)
|
|
964
|
+
] }) })
|
|
965
|
+
] });
|
|
966
|
+
}
|
|
967
|
+
);
|
|
968
|
+
var LineRenderer = React.memo(
|
|
969
|
+
({
|
|
970
|
+
line,
|
|
971
|
+
showChords,
|
|
972
|
+
transpose = 0,
|
|
973
|
+
onChordClick,
|
|
974
|
+
maxGridMeasures
|
|
975
|
+
}) => {
|
|
976
|
+
if (line.type === "empty") return /* @__PURE__ */ jsx2("div", { className: "h-2" });
|
|
977
|
+
if (line.type === "comment") return /* @__PURE__ */ jsx2(CommentRenderer, { line });
|
|
978
|
+
if (line.type === "comment_box") return /* @__PURE__ */ jsx2(CommentBoxRenderer, { line });
|
|
979
|
+
if (line.type === "chord-section")
|
|
980
|
+
return /* @__PURE__ */ jsx2(
|
|
981
|
+
ChordSectionRenderer,
|
|
982
|
+
{
|
|
983
|
+
line,
|
|
984
|
+
showChords,
|
|
985
|
+
transpose,
|
|
986
|
+
onChordClick,
|
|
987
|
+
maxMeasures: maxGridMeasures
|
|
988
|
+
}
|
|
989
|
+
);
|
|
990
|
+
return /* @__PURE__ */ jsx2(
|
|
991
|
+
LyricsRenderer,
|
|
992
|
+
{
|
|
993
|
+
line,
|
|
994
|
+
showChords,
|
|
995
|
+
transpose,
|
|
996
|
+
onChordClick
|
|
997
|
+
}
|
|
998
|
+
);
|
|
999
|
+
}
|
|
1000
|
+
);
|
|
1001
|
+
var CommentRenderer = React.memo(({ line }) => /* @__PURE__ */ jsx2("div", { className: "text-xs text-slate-400 dark:text-slate-500 italic my-1", children: line.text }));
|
|
1002
|
+
var CommentBoxRenderer = React.memo(({ line }) => /* @__PURE__ */ jsxs2("div", { className: "bg-amber-100 dark:bg-amber-900/30 border-l-4 border-amber-500 text-amber-900 dark:text-amber-200 p-2.5 my-2.5 rounded-r-md text-xs font-bold tracking-wide flex items-center gap-2 shadow-sm max-w-fit", children: [
|
|
1003
|
+
/* @__PURE__ */ jsx2(Info, { className: "w-4 h-4 shrink-0 text-amber-600 dark:text-amber-500" }),
|
|
1004
|
+
/* @__PURE__ */ jsx2("span", { children: line.text })
|
|
1005
|
+
] }));
|
|
1006
|
+
var LyricsRenderer = React.memo(
|
|
1007
|
+
({
|
|
1008
|
+
line,
|
|
1009
|
+
showChords,
|
|
1010
|
+
transpose = 0,
|
|
1011
|
+
onChordClick
|
|
1012
|
+
}) => {
|
|
1013
|
+
const segments = line.segments || [];
|
|
1014
|
+
return /* @__PURE__ */ jsx2("div", { className: "flex flex-wrap items-end leading-relaxed", children: segments.map((seg, segIdx) => {
|
|
1015
|
+
const hasChord = !!seg.chord;
|
|
1016
|
+
const transposed = hasChord ? transposeChord(seg.chord, transpose) : "";
|
|
1017
|
+
return /* @__PURE__ */ jsxs2(
|
|
1018
|
+
"div",
|
|
1019
|
+
{
|
|
1020
|
+
className: "flex flex-col justify-end relative select-text",
|
|
1021
|
+
style: {
|
|
1022
|
+
minWidth: hasChord && showChords ? `${Math.max(1.1, transposed.length * 0.65)}em` : void 0
|
|
1023
|
+
},
|
|
1024
|
+
children: [
|
|
1025
|
+
showChords && hasChord && /* @__PURE__ */ jsx2(
|
|
1026
|
+
"span",
|
|
1027
|
+
{
|
|
1028
|
+
className: "font-black text-[#0284c7] font-mono select-none pr-1 inline-block pb-0.5 transition-all cursor-pointer hover:opacity-80",
|
|
1029
|
+
style: { fontSize: "0.85em", lineHeight: "1" },
|
|
1030
|
+
onClick: () => onChordClick?.(transposed),
|
|
1031
|
+
children: transposed
|
|
1032
|
+
}
|
|
1033
|
+
),
|
|
1034
|
+
/* @__PURE__ */ jsx2("span", { className: "text-slate-800 dark:text-slate-200 whitespace-pre", children: seg.text || "\xA0" })
|
|
1035
|
+
]
|
|
1036
|
+
},
|
|
1037
|
+
segIdx
|
|
1038
|
+
);
|
|
1039
|
+
}) });
|
|
1040
|
+
}
|
|
1041
|
+
);
|
|
1042
|
+
var ChordSectionRenderer = React.memo(
|
|
1043
|
+
({
|
|
1044
|
+
line,
|
|
1045
|
+
showChords,
|
|
1046
|
+
transpose = 0,
|
|
1047
|
+
onChordClick,
|
|
1048
|
+
maxMeasures
|
|
1049
|
+
}) => {
|
|
1050
|
+
if (!showChords) return null;
|
|
1051
|
+
const measures = line.measures || [];
|
|
1052
|
+
const hasTiming = measures.some(
|
|
1053
|
+
(m) => m.chords.some((c) => c.timing !== void 0 && c.timing !== 1)
|
|
1054
|
+
);
|
|
1055
|
+
const isGridAligned = maxMeasures !== void 0 && maxMeasures > 0;
|
|
1056
|
+
return /* @__PURE__ */ jsxs2("div", { className: "my-1.5 p-1 w-full flex items-stretch bg-slate-50/80 dark:bg-slate-900/40 rounded-lg border border-slate-200/50 dark:border-slate-800/50 shadow-sm", children: [
|
|
1057
|
+
line.startBarline && /* @__PURE__ */ jsx2("div", { className: "flex items-center justify-center shrink-0 w-6", children: renderBarline(line.startBarline) }),
|
|
1058
|
+
/* @__PURE__ */ jsxs2(
|
|
1059
|
+
"div",
|
|
1060
|
+
{
|
|
1061
|
+
className: isGridAligned ? "grid gap-1 flex-1" : "flex flex-wrap flex-1",
|
|
1062
|
+
style: isGridAligned ? {
|
|
1063
|
+
gridTemplateColumns: `repeat(${maxMeasures}, minmax(0, 1fr))`
|
|
1064
|
+
} : void 0,
|
|
1065
|
+
children: [
|
|
1066
|
+
measures.map((measure, mIdx) => {
|
|
1067
|
+
return /* @__PURE__ */ jsxs2(
|
|
1068
|
+
"div",
|
|
1069
|
+
{
|
|
1070
|
+
className: `flex items-stretch border-r border-slate-200/60 dark:border-slate-700/50 last:border-none ${isGridAligned ? "" : "flex-1 min-w-[120px]"}`,
|
|
1071
|
+
children: [
|
|
1072
|
+
/* @__PURE__ */ jsx2("div", { className: "flex-1 flex items-center justify-evenly gap-1 px-1 py-1", children: measure.chords.map((chordSeg, cIdx) => {
|
|
1073
|
+
const transposed = transposeChord(
|
|
1074
|
+
chordSeg.chord,
|
|
1075
|
+
transpose
|
|
1076
|
+
);
|
|
1077
|
+
const timing = chordSeg.timing ?? 1;
|
|
1078
|
+
return /* @__PURE__ */ jsxs2(
|
|
1079
|
+
"span",
|
|
1080
|
+
{
|
|
1081
|
+
className: "flex-1 flex items-center justify-center cursor-pointer rounded transition-colors hover:bg-white dark:hover:bg-slate-800 py-1.5 px-1 min-w-max shadow-sm border border-transparent hover:border-slate-200 dark:hover:border-slate-700",
|
|
1082
|
+
style: { flexGrow: timing },
|
|
1083
|
+
onClick: () => onChordClick?.(transposed),
|
|
1084
|
+
title: timing !== 1 ? `Dura\xE7\xE3o: ${timing}x` : void 0,
|
|
1085
|
+
children: [
|
|
1086
|
+
/* @__PURE__ */ jsx2("span", { className: "font-bold text-[#0284c7] dark:text-sky-400 font-mono select-none text-[15px] tracking-wide", children: transposed }),
|
|
1087
|
+
hasTiming && timing !== 1 && /* @__PURE__ */ jsxs2("span", { className: "ml-0.5 mt-0.5 text-[10px] font-semibold text-indigo-400 dark:text-indigo-500 opacity-80", children: [
|
|
1088
|
+
timing,
|
|
1089
|
+
"\xD7"
|
|
1090
|
+
] })
|
|
1091
|
+
]
|
|
1092
|
+
},
|
|
1093
|
+
cIdx
|
|
1094
|
+
);
|
|
1095
|
+
}) }),
|
|
1096
|
+
measure.endBarline && /* @__PURE__ */ jsx2("div", { className: "flex items-center justify-center shrink-0 px-1 w-6 bg-slate-100/50 dark:bg-slate-800/50 rounded-r", children: renderBarline(measure.endBarline) })
|
|
1097
|
+
]
|
|
1098
|
+
},
|
|
1099
|
+
mIdx
|
|
1100
|
+
);
|
|
1101
|
+
}),
|
|
1102
|
+
isGridAligned && Array.from({
|
|
1103
|
+
length: Math.max(0, maxMeasures - measures.length)
|
|
1104
|
+
}).map((_, i) => /* @__PURE__ */ jsx2(
|
|
1105
|
+
"div",
|
|
1106
|
+
{
|
|
1107
|
+
className: "border-r border-slate-200/60 dark:border-slate-700/50 last:border-none bg-slate-50/30 dark:bg-slate-800/10 rounded-sm"
|
|
1108
|
+
},
|
|
1109
|
+
`empty-${i}`
|
|
1110
|
+
))
|
|
1111
|
+
]
|
|
1112
|
+
}
|
|
1113
|
+
)
|
|
1114
|
+
] });
|
|
1115
|
+
}
|
|
1116
|
+
);
|
|
1117
|
+
function renderBarline(barline) {
|
|
1118
|
+
const wrapperStyle = "flex items-center justify-center flex-shrink-0 select-none";
|
|
1119
|
+
const repeatStyle = "text-indigo-400 dark:text-indigo-500 text-[18px] leading-none";
|
|
1120
|
+
const normalStyle = "text-slate-300 dark:text-slate-600 font-black text-[16px] leading-none";
|
|
1121
|
+
switch (barline) {
|
|
1122
|
+
case "|:":
|
|
1123
|
+
return /* @__PURE__ */ jsx2("span", { className: wrapperStyle, title: "Start repeat", children: /* @__PURE__ */ jsx2("span", { className: repeatStyle, children: "\u{1D106}" }) });
|
|
1124
|
+
case ":|":
|
|
1125
|
+
return /* @__PURE__ */ jsx2("span", { className: wrapperStyle, title: "End repeat", children: /* @__PURE__ */ jsx2("span", { className: repeatStyle, children: "\u{1D107}" }) });
|
|
1126
|
+
case "||":
|
|
1127
|
+
return /* @__PURE__ */ jsx2("span", { className: wrapperStyle, title: "Double barline", children: /* @__PURE__ */ jsx2("span", { className: normalStyle, children: "\u2016" }) });
|
|
1128
|
+
case "|]":
|
|
1129
|
+
return /* @__PURE__ */ jsx2("span", { className: wrapperStyle, title: "End of piece", children: /* @__PURE__ */ jsx2("span", { className: normalStyle, children: "\u{1D102}" }) });
|
|
1130
|
+
case "|":
|
|
1131
|
+
return /* @__PURE__ */ jsx2("span", { className: wrapperStyle, children: /* @__PURE__ */ jsx2("span", { className: normalStyle, children: "|" }) });
|
|
1132
|
+
default:
|
|
1133
|
+
return /* @__PURE__ */ jsx2(
|
|
1134
|
+
"span",
|
|
1135
|
+
{
|
|
1136
|
+
className: `${wrapperStyle} text-slate-400 dark:text-slate-500 text-xs font-bold tracking-widest`,
|
|
1137
|
+
children: barline
|
|
1138
|
+
}
|
|
1139
|
+
);
|
|
1140
|
+
}
|
|
1141
|
+
}
|
|
1142
|
+
var ChordProRenderer_default = ChordProRenderer;
|
|
1143
|
+
|
|
1144
|
+
export {
|
|
1145
|
+
GuitarDiagram,
|
|
1146
|
+
PianoDiagram,
|
|
1147
|
+
ChordRoll,
|
|
1148
|
+
ChordProRenderer,
|
|
1149
|
+
ChordProRenderer_default
|
|
1150
|
+
};
|
|
1151
|
+
/**
|
|
1152
|
+
* @license
|
|
1153
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
1154
|
+
*/
|