@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,2237 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
|
|
30
|
+
// src/renderer/index.ts
|
|
31
|
+
var renderer_exports = {};
|
|
32
|
+
__export(renderer_exports, {
|
|
33
|
+
ChordProRenderer: () => ChordProRenderer,
|
|
34
|
+
ChordRoll: () => ChordRoll,
|
|
35
|
+
GuitarDiagram: () => GuitarDiagram,
|
|
36
|
+
PianoDiagram: () => PianoDiagram,
|
|
37
|
+
default: () => ChordProRenderer_default
|
|
38
|
+
});
|
|
39
|
+
module.exports = __toCommonJS(renderer_exports);
|
|
40
|
+
|
|
41
|
+
// src/renderer/ChordProRenderer.tsx
|
|
42
|
+
var import_lucide_react = require("lucide-react");
|
|
43
|
+
var import_react2 = __toESM(require("react"));
|
|
44
|
+
var import_react_youtube = __toESM(require("react-youtube"));
|
|
45
|
+
|
|
46
|
+
// src/parser/chordDictionary.ts
|
|
47
|
+
var NOTE_ALIASES = {
|
|
48
|
+
C: 0,
|
|
49
|
+
"B#": 0,
|
|
50
|
+
Do: 0,
|
|
51
|
+
DO: 0,
|
|
52
|
+
"C#": 1,
|
|
53
|
+
Db: 1,
|
|
54
|
+
D: 2,
|
|
55
|
+
Re: 2,
|
|
56
|
+
RE: 2,
|
|
57
|
+
R\u00E9: 2,
|
|
58
|
+
R\u00C9: 2,
|
|
59
|
+
"D#": 3,
|
|
60
|
+
Eb: 3,
|
|
61
|
+
E: 4,
|
|
62
|
+
Fb: 4,
|
|
63
|
+
Mi: 4,
|
|
64
|
+
MI: 4,
|
|
65
|
+
F: 5,
|
|
66
|
+
"E#": 5,
|
|
67
|
+
Fa: 5,
|
|
68
|
+
FA: 5,
|
|
69
|
+
F\u00E1: 5,
|
|
70
|
+
F\u00C1: 5,
|
|
71
|
+
"F#": 6,
|
|
72
|
+
Gb: 6,
|
|
73
|
+
G: 7,
|
|
74
|
+
Sol: 7,
|
|
75
|
+
SOL: 7,
|
|
76
|
+
"G#": 8,
|
|
77
|
+
Ab: 8,
|
|
78
|
+
A: 9,
|
|
79
|
+
La: 9,
|
|
80
|
+
LA: 9,
|
|
81
|
+
L\u00E1: 9,
|
|
82
|
+
L\u00C1: 9,
|
|
83
|
+
"A#": 10,
|
|
84
|
+
Bb: 10,
|
|
85
|
+
B: 11,
|
|
86
|
+
Cb: 11,
|
|
87
|
+
Si: 11,
|
|
88
|
+
SI: 11
|
|
89
|
+
};
|
|
90
|
+
var ROOT_KEYS = Object.keys(NOTE_ALIASES).sort((a, b) => b.length - a.length);
|
|
91
|
+
var ROOT_PATTERN = new RegExp(`^(${ROOT_KEYS.join("|")})`, "i");
|
|
92
|
+
var SEMITONE_NAMES = [
|
|
93
|
+
"C",
|
|
94
|
+
"C#",
|
|
95
|
+
"D",
|
|
96
|
+
"D#",
|
|
97
|
+
"E",
|
|
98
|
+
"F",
|
|
99
|
+
"F#",
|
|
100
|
+
"G",
|
|
101
|
+
"G#",
|
|
102
|
+
"A",
|
|
103
|
+
"A#",
|
|
104
|
+
"B"
|
|
105
|
+
];
|
|
106
|
+
function resolveRootSemitone(raw) {
|
|
107
|
+
if (raw in NOTE_ALIASES) return NOTE_ALIASES[raw];
|
|
108
|
+
const titleCase = raw.charAt(0).toUpperCase() + raw.slice(1).toLowerCase();
|
|
109
|
+
if (titleCase in NOTE_ALIASES) return NOTE_ALIASES[titleCase];
|
|
110
|
+
const upper = raw.toUpperCase();
|
|
111
|
+
if (upper in NOTE_ALIASES) return NOTE_ALIASES[upper];
|
|
112
|
+
return null;
|
|
113
|
+
}
|
|
114
|
+
function pitchClassName(semitone) {
|
|
115
|
+
return SEMITONE_NAMES[(semitone % 12 + 12) % 12];
|
|
116
|
+
}
|
|
117
|
+
var CHORD_QUALITIES = [
|
|
118
|
+
{
|
|
119
|
+
id: "major",
|
|
120
|
+
label: "Major",
|
|
121
|
+
intervals: [0, 4, 7],
|
|
122
|
+
aliases: ["", "M", "maj", "Maj", "MAJ"]
|
|
123
|
+
},
|
|
124
|
+
{
|
|
125
|
+
id: "minor",
|
|
126
|
+
label: "Minor",
|
|
127
|
+
intervals: [0, 3, 7],
|
|
128
|
+
aliases: ["m", "min", "Min", "MIN", "-"]
|
|
129
|
+
},
|
|
130
|
+
{
|
|
131
|
+
id: "dim",
|
|
132
|
+
label: "Diminished",
|
|
133
|
+
intervals: [0, 3, 6],
|
|
134
|
+
aliases: ["dim", "o", "\xB0"]
|
|
135
|
+
},
|
|
136
|
+
{
|
|
137
|
+
id: "aug",
|
|
138
|
+
label: "Augmented",
|
|
139
|
+
intervals: [0, 4, 8],
|
|
140
|
+
aliases: ["aug", "+"]
|
|
141
|
+
},
|
|
142
|
+
{
|
|
143
|
+
id: "sus2",
|
|
144
|
+
label: "Suspended 2nd",
|
|
145
|
+
intervals: [0, 2, 7],
|
|
146
|
+
aliases: ["sus2"]
|
|
147
|
+
},
|
|
148
|
+
{
|
|
149
|
+
id: "sus4",
|
|
150
|
+
label: "Suspended 4th",
|
|
151
|
+
intervals: [0, 5, 7],
|
|
152
|
+
aliases: ["sus4", "sus"]
|
|
153
|
+
},
|
|
154
|
+
{ id: "five", label: "Power chord", intervals: [0, 7], aliases: ["5"] },
|
|
155
|
+
{ id: "six", label: "6th", intervals: [0, 4, 7, 9], aliases: ["6"] },
|
|
156
|
+
{
|
|
157
|
+
id: "m6",
|
|
158
|
+
label: "Minor 6th",
|
|
159
|
+
intervals: [0, 3, 7, 9],
|
|
160
|
+
aliases: ["m6", "min6"]
|
|
161
|
+
},
|
|
162
|
+
{
|
|
163
|
+
id: "six9",
|
|
164
|
+
label: "6/9",
|
|
165
|
+
intervals: [0, 4, 7, 9, 14],
|
|
166
|
+
aliases: ["6/9", "69"]
|
|
167
|
+
},
|
|
168
|
+
{
|
|
169
|
+
id: "dom7",
|
|
170
|
+
label: "Dominant 7th",
|
|
171
|
+
intervals: [0, 4, 7, 10],
|
|
172
|
+
aliases: ["7"]
|
|
173
|
+
},
|
|
174
|
+
{
|
|
175
|
+
id: "maj7",
|
|
176
|
+
label: "Major 7th",
|
|
177
|
+
intervals: [0, 4, 7, 11],
|
|
178
|
+
aliases: ["maj7", "Maj7", "MAJ7", "M7", "\u0394", "\u03947"]
|
|
179
|
+
},
|
|
180
|
+
{
|
|
181
|
+
id: "m7",
|
|
182
|
+
label: "Minor 7th",
|
|
183
|
+
intervals: [0, 3, 7, 10],
|
|
184
|
+
aliases: ["m7", "min7", "Min7"]
|
|
185
|
+
},
|
|
186
|
+
{
|
|
187
|
+
id: "mMaj7",
|
|
188
|
+
label: "Minor Major 7th",
|
|
189
|
+
intervals: [0, 3, 7, 11],
|
|
190
|
+
aliases: ["mMaj7", "m(maj7)", "mM7", "minMaj7"]
|
|
191
|
+
},
|
|
192
|
+
{
|
|
193
|
+
id: "m7b5",
|
|
194
|
+
label: "Half-diminished 7th",
|
|
195
|
+
intervals: [0, 3, 6, 10],
|
|
196
|
+
aliases: ["m7b5", "m7-5", "\xF8", "\xF87"]
|
|
197
|
+
},
|
|
198
|
+
{
|
|
199
|
+
id: "dim7",
|
|
200
|
+
label: "Diminished 7th",
|
|
201
|
+
intervals: [0, 3, 6, 9],
|
|
202
|
+
aliases: ["dim7", "o7", "\xB07"]
|
|
203
|
+
},
|
|
204
|
+
{
|
|
205
|
+
id: "aug7",
|
|
206
|
+
label: "7#5",
|
|
207
|
+
intervals: [0, 4, 8, 10],
|
|
208
|
+
aliases: ["7#5", "aug7"]
|
|
209
|
+
},
|
|
210
|
+
{ id: "dom7b5", label: "7b5", intervals: [0, 4, 6, 10], aliases: ["7b5"] },
|
|
211
|
+
{
|
|
212
|
+
id: "dom7sus4",
|
|
213
|
+
label: "7sus4",
|
|
214
|
+
intervals: [0, 5, 7, 10],
|
|
215
|
+
aliases: ["7sus4"]
|
|
216
|
+
},
|
|
217
|
+
{
|
|
218
|
+
id: "dom7sus2",
|
|
219
|
+
label: "7sus2",
|
|
220
|
+
intervals: [0, 2, 7, 10],
|
|
221
|
+
aliases: ["7sus2"]
|
|
222
|
+
},
|
|
223
|
+
{ id: "nine", label: "9th", intervals: [0, 4, 7, 10, 14], aliases: ["9"] },
|
|
224
|
+
{
|
|
225
|
+
id: "maj9",
|
|
226
|
+
label: "Major 9th",
|
|
227
|
+
intervals: [0, 4, 7, 11, 14],
|
|
228
|
+
aliases: ["maj9", "Maj9", "M9"]
|
|
229
|
+
},
|
|
230
|
+
{
|
|
231
|
+
id: "m9",
|
|
232
|
+
label: "Minor 9th",
|
|
233
|
+
intervals: [0, 3, 7, 10, 14],
|
|
234
|
+
aliases: ["m9", "min9"]
|
|
235
|
+
},
|
|
236
|
+
{ id: "add9", label: "Add 9", intervals: [0, 4, 7, 14], aliases: ["add9"] },
|
|
237
|
+
{
|
|
238
|
+
id: "madd9",
|
|
239
|
+
label: "Minor Add 9",
|
|
240
|
+
intervals: [0, 3, 7, 14],
|
|
241
|
+
aliases: ["madd9", "minAdd9"]
|
|
242
|
+
},
|
|
243
|
+
{
|
|
244
|
+
id: "eleven",
|
|
245
|
+
label: "11th",
|
|
246
|
+
intervals: [0, 4, 7, 10, 14, 17],
|
|
247
|
+
aliases: ["11"]
|
|
248
|
+
},
|
|
249
|
+
{
|
|
250
|
+
id: "m11",
|
|
251
|
+
label: "Minor 11th",
|
|
252
|
+
intervals: [0, 3, 7, 10, 14, 17],
|
|
253
|
+
aliases: ["m11"]
|
|
254
|
+
},
|
|
255
|
+
{
|
|
256
|
+
id: "thirteen",
|
|
257
|
+
label: "13th",
|
|
258
|
+
intervals: [0, 4, 7, 10, 14, 17, 21],
|
|
259
|
+
aliases: ["13"]
|
|
260
|
+
},
|
|
261
|
+
{
|
|
262
|
+
id: "m13",
|
|
263
|
+
label: "Minor 13th",
|
|
264
|
+
intervals: [0, 3, 7, 10, 14, 17, 21],
|
|
265
|
+
aliases: ["m13"]
|
|
266
|
+
},
|
|
267
|
+
{
|
|
268
|
+
id: "dom7sharp9",
|
|
269
|
+
label: "7#9",
|
|
270
|
+
intervals: [0, 4, 7, 10, 15],
|
|
271
|
+
aliases: ["7#9"]
|
|
272
|
+
},
|
|
273
|
+
{
|
|
274
|
+
id: "dom7flat9",
|
|
275
|
+
label: "7b9",
|
|
276
|
+
intervals: [0, 4, 7, 10, 13],
|
|
277
|
+
aliases: ["7b9"]
|
|
278
|
+
},
|
|
279
|
+
{
|
|
280
|
+
id: "maj7sharp5",
|
|
281
|
+
label: "maj7#5",
|
|
282
|
+
intervals: [0, 4, 8, 11],
|
|
283
|
+
aliases: ["maj7#5"]
|
|
284
|
+
},
|
|
285
|
+
{
|
|
286
|
+
id: "maj7flat5",
|
|
287
|
+
label: "maj7b5",
|
|
288
|
+
intervals: [0, 4, 6, 11],
|
|
289
|
+
aliases: ["maj7b5"]
|
|
290
|
+
}
|
|
291
|
+
];
|
|
292
|
+
var QUALITY_BY_ID = Object.fromEntries(
|
|
293
|
+
CHORD_QUALITIES.map((q) => [q.id, q])
|
|
294
|
+
);
|
|
295
|
+
var QUALITY_ALIAS_TABLE = CHORD_QUALITIES.flatMap(
|
|
296
|
+
(quality) => quality.aliases.map((alias) => ({ alias, quality }))
|
|
297
|
+
).sort((a, b) => b.alias.length - a.alias.length);
|
|
298
|
+
function resolveQuality(qualitySymbol) {
|
|
299
|
+
if (qualitySymbol === "") return QUALITY_BY_ID.major;
|
|
300
|
+
const exact = QUALITY_ALIAS_TABLE.find(
|
|
301
|
+
(e) => e.alias !== "" && e.alias === qualitySymbol
|
|
302
|
+
);
|
|
303
|
+
if (exact) return exact.quality;
|
|
304
|
+
const lower = qualitySymbol.toLowerCase();
|
|
305
|
+
const loose = QUALITY_ALIAS_TABLE.find(
|
|
306
|
+
(e) => e.alias !== "" && e.alias.toLowerCase() === lower
|
|
307
|
+
);
|
|
308
|
+
if (loose) return loose.quality;
|
|
309
|
+
return QUALITY_BY_ID.major;
|
|
310
|
+
}
|
|
311
|
+
var QUALITY_SIMPLIFICATION = {
|
|
312
|
+
dim: "minor",
|
|
313
|
+
dim7: "minor",
|
|
314
|
+
aug: "major",
|
|
315
|
+
six: "major",
|
|
316
|
+
m6: "minor",
|
|
317
|
+
six9: "major",
|
|
318
|
+
mMaj7: "m7",
|
|
319
|
+
m7b5: "m7",
|
|
320
|
+
aug7: "dom7",
|
|
321
|
+
dom7b5: "dom7",
|
|
322
|
+
dom7sus4: "sus4",
|
|
323
|
+
dom7sus2: "sus2",
|
|
324
|
+
nine: "dom7",
|
|
325
|
+
maj9: "maj7",
|
|
326
|
+
m9: "m7",
|
|
327
|
+
add9: "major",
|
|
328
|
+
madd9: "minor",
|
|
329
|
+
eleven: "dom7",
|
|
330
|
+
m11: "m7",
|
|
331
|
+
thirteen: "dom7",
|
|
332
|
+
m13: "m7",
|
|
333
|
+
dom7sharp9: "dom7",
|
|
334
|
+
dom7flat9: "dom7",
|
|
335
|
+
maj7sharp5: "maj7",
|
|
336
|
+
maj7flat5: "maj7"
|
|
337
|
+
};
|
|
338
|
+
var SLASH_CONTAINING_ALIASES = QUALITY_ALIAS_TABLE.filter(
|
|
339
|
+
(e) => e.alias.includes("/")
|
|
340
|
+
).sort((a, b) => b.alias.length - a.alias.length);
|
|
341
|
+
function parseChordSymbol(chord) {
|
|
342
|
+
const cleaned = chord.replace(/[()]/g, "").trim();
|
|
343
|
+
if (!cleaned) return null;
|
|
344
|
+
const rootMatch = cleaned.match(ROOT_PATTERN);
|
|
345
|
+
if (!rootMatch) return null;
|
|
346
|
+
const rootText = rootMatch[1];
|
|
347
|
+
const rootSemitone = resolveRootSemitone(rootText);
|
|
348
|
+
if (rootSemitone === null) return null;
|
|
349
|
+
const remainder = cleaned.slice(rootText.length);
|
|
350
|
+
const slashAlias = SLASH_CONTAINING_ALIASES.find(
|
|
351
|
+
(e) => remainder.startsWith(e.alias)
|
|
352
|
+
);
|
|
353
|
+
let qualitySymbol;
|
|
354
|
+
let bassPart;
|
|
355
|
+
if (slashAlias) {
|
|
356
|
+
qualitySymbol = slashAlias.alias;
|
|
357
|
+
const rest = remainder.slice(slashAlias.alias.length);
|
|
358
|
+
bassPart = rest.startsWith("/") ? rest.slice(1).trim() : void 0;
|
|
359
|
+
} else {
|
|
360
|
+
const slashIndex = remainder.indexOf("/");
|
|
361
|
+
if (slashIndex === -1) {
|
|
362
|
+
qualitySymbol = remainder;
|
|
363
|
+
} else {
|
|
364
|
+
qualitySymbol = remainder.slice(0, slashIndex);
|
|
365
|
+
bassPart = remainder.slice(slashIndex + 1).trim();
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
const quality = resolveQuality(qualitySymbol);
|
|
369
|
+
let bassSemitone;
|
|
370
|
+
if (bassPart) {
|
|
371
|
+
const bassMatch = bassPart.match(ROOT_PATTERN);
|
|
372
|
+
if (bassMatch) {
|
|
373
|
+
const resolved = resolveRootSemitone(bassMatch[1]);
|
|
374
|
+
if (resolved !== null) bassSemitone = resolved;
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
return {
|
|
378
|
+
raw: cleaned,
|
|
379
|
+
rootSemitone,
|
|
380
|
+
rootDisplay: pitchClassName(rootSemitone),
|
|
381
|
+
quality,
|
|
382
|
+
bassSemitone
|
|
383
|
+
};
|
|
384
|
+
}
|
|
385
|
+
function computePianoVoicing(rootSemitone, intervals, bassSemitone) {
|
|
386
|
+
const rootPc = (rootSemitone % 12 + 12) % 12;
|
|
387
|
+
if (bassSemitone !== void 0) {
|
|
388
|
+
const bassPc = (bassSemitone % 12 + 12) % 12;
|
|
389
|
+
const notes2 = [pitchClassName(bassPc)];
|
|
390
|
+
const highlightKeys2 = [bassPc];
|
|
391
|
+
for (const iv of intervals) {
|
|
392
|
+
const key = (rootPc + iv) % 12 + 12;
|
|
393
|
+
const name = pitchClassName(rootPc + iv);
|
|
394
|
+
highlightKeys2.push(key);
|
|
395
|
+
if (!notes2.includes(name)) notes2.push(name);
|
|
396
|
+
}
|
|
397
|
+
return { notes: notes2, highlightKeys: highlightKeys2 };
|
|
398
|
+
}
|
|
399
|
+
const notes = intervals.map((iv) => pitchClassName(rootPc + iv));
|
|
400
|
+
const highlightKeys = intervals.map((iv) => (rootPc + iv) % 24);
|
|
401
|
+
return { notes, highlightKeys };
|
|
402
|
+
}
|
|
403
|
+
var OPEN_CHORD_SHAPES = {
|
|
404
|
+
C: { frets: [-1, 3, 2, 0, 1, 0], fingers: [0, 3, 2, 0, 1, 0] },
|
|
405
|
+
Cm: { frets: [-1, 3, 5, 5, 4, 3], fingers: [0, 1, 3, 4, 2, 1], barre: 3 },
|
|
406
|
+
C7: { frets: [-1, 3, 2, 3, 1, 0], fingers: [0, 3, 2, 4, 1, 0] },
|
|
407
|
+
Cmaj7: { frets: [-1, 3, 2, 0, 0, 0], fingers: [0, 3, 2, 0, 0, 0] },
|
|
408
|
+
Cm7: { frets: [-1, 3, 5, 3, 4, 3], fingers: [0, 1, 3, 1, 2, 1], barre: 3 },
|
|
409
|
+
Csus4: { frets: [-1, 3, 3, 0, 1, 1], fingers: [0, 3, 4, 0, 1, 1] },
|
|
410
|
+
Csus2: { frets: [-1, 3, 0, 0, 1, 3], fingers: [0, 2, 0, 0, 1, 4] },
|
|
411
|
+
Cadd9: { frets: [-1, 3, 2, 0, 3, 0], fingers: [0, 2, 1, 0, 3, 0] },
|
|
412
|
+
C9: { frets: [-1, 3, 2, 3, 3, 3], fingers: [0, 2, 1, 3, 3, 3], barre: 3 },
|
|
413
|
+
C6: { frets: [-1, 3, 2, 2, 1, 0], fingers: [0, 4, 2, 3, 1, 0] },
|
|
414
|
+
"C#": { frets: [-1, 4, 6, 6, 6, 4], fingers: [0, 1, 2, 3, 4, 1], barre: 4 },
|
|
415
|
+
"C#m": {
|
|
416
|
+
frets: [-1, 4, 6, 6, 5, 4],
|
|
417
|
+
fingers: [0, 1, 3, 4, 2, 1],
|
|
418
|
+
barre: 4
|
|
419
|
+
},
|
|
420
|
+
"C#7": { frets: [-1, 4, 3, 4, 2, -1], fingers: [0, 3, 2, 4, 1, 0] },
|
|
421
|
+
"C#maj7": {
|
|
422
|
+
frets: [-1, 4, 6, 5, 6, 4],
|
|
423
|
+
fingers: [0, 1, 3, 2, 4, 1],
|
|
424
|
+
barre: 4
|
|
425
|
+
},
|
|
426
|
+
"C#m7": {
|
|
427
|
+
frets: [-1, 4, 6, 4, 5, 4],
|
|
428
|
+
fingers: [0, 1, 3, 1, 2, 1],
|
|
429
|
+
barre: 4
|
|
430
|
+
},
|
|
431
|
+
D: { frets: [-1, -1, 0, 2, 3, 2], fingers: [0, 0, 0, 1, 3, 2] },
|
|
432
|
+
Dm: { frets: [-1, -1, 0, 2, 3, 1], fingers: [0, 0, 0, 2, 3, 1] },
|
|
433
|
+
D7: { frets: [-1, -1, 0, 2, 1, 2], fingers: [0, 0, 0, 2, 1, 3] },
|
|
434
|
+
Dmaj7: {
|
|
435
|
+
frets: [-1, -1, 0, 2, 2, 2],
|
|
436
|
+
fingers: [0, 0, 0, 1, 1, 1],
|
|
437
|
+
barre: 2
|
|
438
|
+
},
|
|
439
|
+
Dm7: { frets: [-1, -1, 0, 2, 1, 1], fingers: [0, 0, 0, 2, 1, 1], barre: 1 },
|
|
440
|
+
Dsus4: { frets: [-1, -1, 0, 2, 3, 3], fingers: [0, 0, 0, 1, 2, 3] },
|
|
441
|
+
Dsus2: { frets: [-1, -1, 0, 2, 3, 0], fingers: [0, 0, 0, 1, 2, 0] },
|
|
442
|
+
Dadd9: { frets: [-1, -1, 0, 2, 5, 2], fingers: [0, 0, 0, 1, 4, 2] },
|
|
443
|
+
D6: { frets: [-1, -1, 0, 2, 0, 2], fingers: [0, 0, 0, 2, 0, 3] },
|
|
444
|
+
D9: { frets: [-1, -1, 0, 2, 1, 0], fingers: [0, 0, 0, 2, 1, 0] },
|
|
445
|
+
Eb: { frets: [-1, 6, 8, 8, 8, 6], fingers: [0, 1, 2, 3, 4, 1], barre: 6 },
|
|
446
|
+
Ebm: { frets: [-1, 6, 8, 8, 7, 6], fingers: [0, 1, 3, 4, 2, 1], barre: 6 },
|
|
447
|
+
Eb7: { frets: [-1, 6, 5, 6, 4, -1], fingers: [0, 3, 2, 4, 1, 0] },
|
|
448
|
+
E: { frets: [0, 2, 2, 1, 0, 0], fingers: [0, 2, 3, 1, 0, 0] },
|
|
449
|
+
Em: { frets: [0, 2, 2, 0, 0, 0], fingers: [0, 2, 3, 0, 0, 0] },
|
|
450
|
+
E7: { frets: [0, 2, 0, 1, 0, 0], fingers: [0, 2, 0, 1, 0, 0] },
|
|
451
|
+
Emaj7: { frets: [0, 2, 1, 1, 0, 0], fingers: [0, 3, 1, 2, 0, 0] },
|
|
452
|
+
Em7: { frets: [0, 2, 0, 0, 0, 0], fingers: [0, 2, 0, 0, 0, 0] },
|
|
453
|
+
Esus4: { frets: [0, 2, 2, 2, 0, 0], fingers: [0, 2, 3, 4, 0, 0] },
|
|
454
|
+
Eadd9: { frets: [0, 2, 4, 1, 0, 0], fingers: [0, 2, 4, 1, 0, 0] },
|
|
455
|
+
E6: { frets: [0, 2, 2, 1, 2, 0], fingers: [0, 2, 3, 1, 4, 0] },
|
|
456
|
+
E9: { frets: [0, 2, 0, 1, 3, 0], fingers: [0, 2, 0, 1, 4, 0] },
|
|
457
|
+
F: { frets: [1, 3, 3, 2, 1, 1], fingers: [1, 3, 4, 2, 1, 1], barre: 1 },
|
|
458
|
+
Fm: { frets: [1, 3, 3, 1, 1, 1], fingers: [1, 3, 4, 1, 1, 1], barre: 1 },
|
|
459
|
+
F7: { frets: [1, 3, 1, 2, 1, 1], fingers: [1, 3, 1, 2, 1, 1], barre: 1 },
|
|
460
|
+
Fmaj7: { frets: [-1, 3, 3, 2, 1, 0], fingers: [0, 3, 4, 2, 1, 0] },
|
|
461
|
+
Fm7: { frets: [1, 3, 1, 1, 1, 1], fingers: [1, 3, 1, 1, 1, 1], barre: 1 },
|
|
462
|
+
"F#": { frets: [2, 4, 4, 3, 2, 2], fingers: [1, 3, 4, 2, 1, 1], barre: 2 },
|
|
463
|
+
"F#m": { frets: [2, 4, 4, 2, 2, 2], fingers: [1, 3, 4, 1, 1, 1], barre: 2 },
|
|
464
|
+
"F#7": { frets: [2, 4, 2, 3, 2, 2], fingers: [1, 3, 1, 2, 1, 1], barre: 2 },
|
|
465
|
+
"F#m7": {
|
|
466
|
+
frets: [2, 4, 2, 2, 2, 2],
|
|
467
|
+
fingers: [1, 3, 1, 1, 1, 1],
|
|
468
|
+
barre: 2
|
|
469
|
+
},
|
|
470
|
+
G: { frets: [3, 2, 0, 0, 3, 3], fingers: [2, 1, 0, 0, 3, 4] },
|
|
471
|
+
Gm: { frets: [3, 5, 5, 3, 3, 3], fingers: [1, 3, 4, 1, 1, 1], barre: 3 },
|
|
472
|
+
G7: { frets: [3, 2, 0, 0, 0, 1], fingers: [3, 2, 0, 0, 0, 1] },
|
|
473
|
+
Gmaj7: { frets: [3, 2, 0, 0, 0, 2], fingers: [2, 1, 0, 0, 0, 3] },
|
|
474
|
+
Gm7: { frets: [3, 5, 3, 3, 3, 3], fingers: [1, 3, 1, 1, 1, 1], barre: 3 },
|
|
475
|
+
Gsus4: { frets: [3, 3, 0, 0, 3, 3], fingers: [2, 3, 0, 0, 1, 4] },
|
|
476
|
+
Gadd9: { frets: [3, 2, 0, 2, 0, 3], fingers: [2, 1, 0, 3, 0, 4] },
|
|
477
|
+
G6: { frets: [3, 2, 0, 0, 0, 0], fingers: [3, 2, 0, 0, 0, 0] },
|
|
478
|
+
Ab: { frets: [4, 6, 6, 5, 4, 4], fingers: [1, 3, 4, 2, 1, 1], barre: 4 },
|
|
479
|
+
Abm: { frets: [4, 6, 6, 4, 4, 4], fingers: [1, 3, 4, 1, 1, 1], barre: 4 },
|
|
480
|
+
A: { frets: [-1, 0, 2, 2, 2, 0], fingers: [0, 0, 1, 2, 3, 0] },
|
|
481
|
+
Am: { frets: [-1, 0, 2, 2, 1, 0], fingers: [0, 0, 2, 3, 1, 0] },
|
|
482
|
+
A7: { frets: [-1, 0, 2, 0, 2, 0], fingers: [0, 0, 1, 0, 2, 0] },
|
|
483
|
+
Amaj7: { frets: [-1, 0, 2, 1, 2, 0], fingers: [0, 0, 2, 1, 3, 0] },
|
|
484
|
+
Am7: { frets: [-1, 0, 2, 0, 1, 0], fingers: [0, 0, 2, 0, 1, 0] },
|
|
485
|
+
Asus4: { frets: [-1, 0, 2, 2, 3, 0], fingers: [0, 0, 1, 2, 4, 0] },
|
|
486
|
+
Asus2: { frets: [-1, 0, 2, 2, 0, 0], fingers: [0, 0, 1, 2, 0, 0] },
|
|
487
|
+
Aadd9: { frets: [-1, 0, 2, 4, 2, 0], fingers: [0, 0, 1, 3, 2, 0] },
|
|
488
|
+
A6: { frets: [-1, 0, 2, 2, 2, 2], fingers: [0, 0, 1, 1, 1, 1], barre: 2 },
|
|
489
|
+
A9: { frets: [-1, 0, 2, 4, 2, 3], fingers: [0, 0, 1, 3, 2, 4] },
|
|
490
|
+
Bb: { frets: [-1, 1, 3, 3, 3, 1], fingers: [0, 1, 2, 3, 4, 1], barre: 1 },
|
|
491
|
+
Bbm: { frets: [-1, 1, 3, 3, 2, 1], fingers: [0, 1, 3, 4, 2, 1], barre: 1 },
|
|
492
|
+
Bb7: { frets: [-1, 1, 3, 1, 3, 1], fingers: [0, 1, 3, 1, 4, 1], barre: 1 },
|
|
493
|
+
B: { frets: [-1, 2, 4, 4, 4, 2], fingers: [0, 1, 2, 3, 4, 1], barre: 2 },
|
|
494
|
+
Bm: { frets: [-1, 2, 4, 4, 3, 2], fingers: [0, 1, 3, 4, 2, 1], barre: 2 },
|
|
495
|
+
B7: { frets: [-1, 2, 1, 2, 0, 2], fingers: [0, 2, 1, 3, 0, 4] },
|
|
496
|
+
Bmaj7: {
|
|
497
|
+
frets: [-1, 2, 4, 3, 4, 2],
|
|
498
|
+
fingers: [0, 1, 3, 2, 4, 1],
|
|
499
|
+
barre: 2
|
|
500
|
+
},
|
|
501
|
+
Bm7: { frets: [-1, 2, 4, 2, 3, 2], fingers: [0, 1, 3, 1, 2, 1], barre: 2 }
|
|
502
|
+
};
|
|
503
|
+
var SLASH_CHORD_SHAPES = {
|
|
504
|
+
"C/E": { frets: [0, 3, 2, 0, 1, 0], fingers: [0, 3, 2, 0, 1, 0] },
|
|
505
|
+
"C/G": { frets: [3, 3, 2, 0, 1, 0], fingers: [3, 4, 2, 0, 1, 0] },
|
|
506
|
+
"C/Bb": { frets: [-1, 3, 2, 3, 1, 0], fingers: [0, 3, 2, 4, 1, 0] },
|
|
507
|
+
"D/F#": { frets: [2, 0, 0, 2, 3, 2], fingers: [1, 0, 0, 2, 4, 3] },
|
|
508
|
+
"D/A": { frets: [-1, 0, 0, 2, 3, 2], fingers: [0, 0, 0, 1, 3, 2] },
|
|
509
|
+
"E/G#": { frets: [4, 2, 2, 1, 0, 0], fingers: [4, 2, 3, 1, 0, 0] },
|
|
510
|
+
"E/B": { frets: [0, 2, 2, 1, 0, 0], fingers: [0, 2, 3, 1, 0, 0] },
|
|
511
|
+
"F/A": { frets: [-1, 0, 3, 2, 1, 1], fingers: [0, 0, 3, 2, 1, 1] },
|
|
512
|
+
"F/C": {
|
|
513
|
+
frets: [8, 8, 10, 10, 10, 8],
|
|
514
|
+
fingers: [1, 1, 2, 3, 4, 1],
|
|
515
|
+
barre: 8
|
|
516
|
+
},
|
|
517
|
+
"G/B": { frets: [-1, 2, 0, 0, 3, 3], fingers: [0, 1, 0, 0, 3, 4] },
|
|
518
|
+
"G/D": { frets: [-1, -1, 0, 0, 3, 3], fingers: [0, 0, 0, 0, 3, 4] },
|
|
519
|
+
"G/F": { frets: [3, 2, 0, 0, 0, 1], fingers: [3, 2, 0, 0, 0, 1] },
|
|
520
|
+
"A/C#": { frets: [-1, 4, 2, 2, 2, -1], fingers: [0, 4, 1, 1, 1, 0] },
|
|
521
|
+
"A/E": { frets: [0, 0, 2, 2, 2, 0], fingers: [0, 0, 1, 2, 3, 0] },
|
|
522
|
+
"A/G": { frets: [3, 0, 2, 2, 2, 0], fingers: [4, 0, 1, 2, 3, 0] },
|
|
523
|
+
"B/D#": { frets: [-1, 6, 4, 4, 4, -1], fingers: [0, 3, 1, 1, 1, 0] },
|
|
524
|
+
"B/F#": {
|
|
525
|
+
frets: [2, 2, 4, 4, 4, 2],
|
|
526
|
+
fingers: [1, 1, 2, 3, 4, 1],
|
|
527
|
+
barre: 2
|
|
528
|
+
},
|
|
529
|
+
"Am/G": { frets: [3, 0, 2, 2, 1, 0], fingers: [4, 0, 2, 3, 1, 0] },
|
|
530
|
+
"Am/F#": { frets: [2, 0, 2, 2, 1, 0], fingers: [2, 0, 3, 4, 1, 0] },
|
|
531
|
+
"Am/E": { frets: [0, 0, 2, 2, 1, 0], fingers: [0, 0, 2, 3, 1, 0] },
|
|
532
|
+
"Dm/C": { frets: [-1, 3, 0, 2, 3, 1], fingers: [0, 3, 0, 2, 4, 1] },
|
|
533
|
+
"Dm/B": { frets: [-1, 2, 0, 2, 3, 1], fingers: [0, 2, 0, 3, 4, 1] },
|
|
534
|
+
"Dm/A": { frets: [-1, 0, 0, 2, 3, 1], fingers: [0, 0, 0, 2, 3, 1] },
|
|
535
|
+
"Dm/F": { frets: [1, -1, 0, 2, 3, 1], fingers: [1, 0, 0, 2, 4, 3] },
|
|
536
|
+
"Em/D": { frets: [0, 2, 0, 0, 0, 0], fingers: [0, 2, 0, 0, 0, 0] },
|
|
537
|
+
"Em/C#": { frets: [0, 4, 2, 0, 0, 0], fingers: [0, 3, 1, 0, 0, 0] },
|
|
538
|
+
"Em/B": {
|
|
539
|
+
frets: [7, 7, 9, 9, 8, 7],
|
|
540
|
+
fingers: [1, 1, 3, 4, 2, 1],
|
|
541
|
+
barre: 7
|
|
542
|
+
},
|
|
543
|
+
"Em/G": { frets: [3, 2, 2, 0, 0, 0], fingers: [3, 1, 2, 0, 0, 0] },
|
|
544
|
+
"Fm/Eb": { frets: [-1, 6, 6, 5, 6, -1], fingers: [0, 2, 3, 1, 4, 0] },
|
|
545
|
+
"Gm/F": {
|
|
546
|
+
frets: [3, 5, 3, 3, 3, 3],
|
|
547
|
+
fingers: [1, 3, 1, 1, 1, 1],
|
|
548
|
+
barre: 3
|
|
549
|
+
},
|
|
550
|
+
"Bm/A": { frets: [-1, 0, 4, 4, 3, 2], fingers: [0, 0, 3, 4, 2, 1] }
|
|
551
|
+
};
|
|
552
|
+
var CANONICAL_SUFFIX = {
|
|
553
|
+
major: "",
|
|
554
|
+
minor: "m",
|
|
555
|
+
dom7: "7",
|
|
556
|
+
maj7: "maj7",
|
|
557
|
+
m7: "m7",
|
|
558
|
+
sus4: "sus4",
|
|
559
|
+
sus2: "sus2",
|
|
560
|
+
six: "6",
|
|
561
|
+
add9: "add9",
|
|
562
|
+
nine: "9"
|
|
563
|
+
};
|
|
564
|
+
var E_FORM = {
|
|
565
|
+
major: {
|
|
566
|
+
formRootSemitone: 4,
|
|
567
|
+
frets: [0, 2, 2, 1, 0, 0],
|
|
568
|
+
openFingers: [0, 2, 3, 1, 0, 0],
|
|
569
|
+
barreFingers: [1, 3, 4, 2, 1, 1]
|
|
570
|
+
},
|
|
571
|
+
minor: {
|
|
572
|
+
formRootSemitone: 4,
|
|
573
|
+
frets: [0, 2, 2, 0, 0, 0],
|
|
574
|
+
openFingers: [0, 2, 3, 0, 0, 0],
|
|
575
|
+
barreFingers: [1, 3, 4, 1, 1, 1]
|
|
576
|
+
},
|
|
577
|
+
dom7: {
|
|
578
|
+
formRootSemitone: 4,
|
|
579
|
+
frets: [0, 2, 0, 1, 0, 0],
|
|
580
|
+
openFingers: [0, 2, 0, 1, 0, 0],
|
|
581
|
+
barreFingers: [1, 3, 1, 2, 1, 1]
|
|
582
|
+
},
|
|
583
|
+
m7: {
|
|
584
|
+
formRootSemitone: 4,
|
|
585
|
+
frets: [0, 2, 0, 0, 0, 0],
|
|
586
|
+
openFingers: [0, 2, 0, 0, 0, 0],
|
|
587
|
+
barreFingers: [1, 3, 1, 1, 1, 1]
|
|
588
|
+
},
|
|
589
|
+
maj7: {
|
|
590
|
+
formRootSemitone: 4,
|
|
591
|
+
frets: [0, 2, 1, 1, 0, 0],
|
|
592
|
+
openFingers: [0, 3, 1, 2, 0, 0],
|
|
593
|
+
barreFingers: [1, 3, 2, 2, 1, 1]
|
|
594
|
+
},
|
|
595
|
+
sus4: {
|
|
596
|
+
formRootSemitone: 4,
|
|
597
|
+
frets: [0, 2, 2, 2, 0, 0],
|
|
598
|
+
openFingers: [0, 2, 3, 4, 0, 0],
|
|
599
|
+
barreFingers: [1, 3, 4, 4, 1, 1]
|
|
600
|
+
}
|
|
601
|
+
};
|
|
602
|
+
var A_FORM = {
|
|
603
|
+
major: {
|
|
604
|
+
formRootSemitone: 9,
|
|
605
|
+
frets: [-1, 0, 2, 2, 2, 0],
|
|
606
|
+
openFingers: [0, 0, 1, 2, 3, 0],
|
|
607
|
+
barreFingers: [0, 1, 3, 4, 4, 1]
|
|
608
|
+
},
|
|
609
|
+
minor: {
|
|
610
|
+
formRootSemitone: 9,
|
|
611
|
+
frets: [-1, 0, 2, 2, 1, 0],
|
|
612
|
+
openFingers: [0, 0, 2, 3, 1, 0],
|
|
613
|
+
barreFingers: [0, 1, 3, 4, 2, 1]
|
|
614
|
+
},
|
|
615
|
+
dom7: {
|
|
616
|
+
formRootSemitone: 9,
|
|
617
|
+
frets: [-1, 0, 2, 0, 2, 0],
|
|
618
|
+
openFingers: [0, 0, 1, 0, 2, 0],
|
|
619
|
+
barreFingers: [0, 1, 3, 1, 4, 1]
|
|
620
|
+
},
|
|
621
|
+
m7: {
|
|
622
|
+
formRootSemitone: 9,
|
|
623
|
+
frets: [-1, 0, 2, 0, 1, 0],
|
|
624
|
+
openFingers: [0, 0, 2, 0, 1, 0],
|
|
625
|
+
barreFingers: [0, 1, 3, 1, 2, 1]
|
|
626
|
+
},
|
|
627
|
+
maj7: {
|
|
628
|
+
formRootSemitone: 9,
|
|
629
|
+
frets: [-1, 0, 2, 1, 2, 0],
|
|
630
|
+
openFingers: [0, 0, 2, 1, 3, 0],
|
|
631
|
+
barreFingers: [0, 1, 3, 2, 4, 1]
|
|
632
|
+
},
|
|
633
|
+
sus4: {
|
|
634
|
+
formRootSemitone: 9,
|
|
635
|
+
frets: [-1, 0, 2, 2, 3, 0],
|
|
636
|
+
openFingers: [0, 0, 1, 2, 4, 0],
|
|
637
|
+
barreFingers: [0, 1, 3, 3, 4, 1]
|
|
638
|
+
},
|
|
639
|
+
sus2: {
|
|
640
|
+
formRootSemitone: 9,
|
|
641
|
+
frets: [-1, 0, 2, 2, 0, 0],
|
|
642
|
+
openFingers: [0, 0, 1, 2, 0, 0],
|
|
643
|
+
barreFingers: [0, 1, 3, 4, 1, 1]
|
|
644
|
+
}
|
|
645
|
+
};
|
|
646
|
+
function realizeTemplate(t, targetSemitone) {
|
|
647
|
+
const shift = ((targetSemitone - t.formRootSemitone) % 12 + 12) % 12;
|
|
648
|
+
const frets = t.frets.map((f) => f < 0 ? f : f + shift);
|
|
649
|
+
if (shift === 0) return { frets, fingers: t.openFingers ?? t.barreFingers };
|
|
650
|
+
return { frets, fingers: t.barreFingers, barre: shift };
|
|
651
|
+
}
|
|
652
|
+
function maxFret(shape) {
|
|
653
|
+
return Math.max(0, ...shape.frets.filter((f) => f >= 0));
|
|
654
|
+
}
|
|
655
|
+
function templateFingering(qualityId, targetSemitone) {
|
|
656
|
+
const e = E_FORM[qualityId];
|
|
657
|
+
const a = A_FORM[qualityId];
|
|
658
|
+
if (!e && !a) return null;
|
|
659
|
+
if (e && !a) return realizeTemplate(e, targetSemitone);
|
|
660
|
+
if (a && !e) return realizeTemplate(a, targetSemitone);
|
|
661
|
+
const eShape = realizeTemplate(e, targetSemitone);
|
|
662
|
+
const aShape = realizeTemplate(a, targetSemitone);
|
|
663
|
+
return maxFret(aShape) <= maxFret(eShape) ? aShape : eShape;
|
|
664
|
+
}
|
|
665
|
+
function powerChordShape(targetSemitone) {
|
|
666
|
+
const shift = ((targetSemitone - 4) % 12 + 12) % 12;
|
|
667
|
+
return {
|
|
668
|
+
frets: [shift, shift + 2, shift + 2, -1, -1, -1],
|
|
669
|
+
fingers: [1, 3, 4, 0, 0, 0]
|
|
670
|
+
};
|
|
671
|
+
}
|
|
672
|
+
var TEMPLATE_QUALITIES = /* @__PURE__ */ new Set([
|
|
673
|
+
"major",
|
|
674
|
+
"minor",
|
|
675
|
+
"dom7",
|
|
676
|
+
"m7",
|
|
677
|
+
"maj7",
|
|
678
|
+
"sus4",
|
|
679
|
+
"sus2"
|
|
680
|
+
]);
|
|
681
|
+
function getGuitarFingering(parsed) {
|
|
682
|
+
const { rootSemitone, quality, raw, rootDisplay } = parsed;
|
|
683
|
+
if (SLASH_CHORD_SHAPES[raw])
|
|
684
|
+
return { shape: SLASH_CHORD_SHAPES[raw], approximate: false };
|
|
685
|
+
if (OPEN_CHORD_SHAPES[raw])
|
|
686
|
+
return { shape: OPEN_CHORD_SHAPES[raw], approximate: false };
|
|
687
|
+
const suffix = CANONICAL_SUFFIX[quality.id];
|
|
688
|
+
if (suffix !== void 0) {
|
|
689
|
+
const canonical = rootDisplay + suffix;
|
|
690
|
+
if (OPEN_CHORD_SHAPES[canonical])
|
|
691
|
+
return { shape: OPEN_CHORD_SHAPES[canonical], approximate: false };
|
|
692
|
+
}
|
|
693
|
+
if (quality.id === "five")
|
|
694
|
+
return { shape: powerChordShape(rootSemitone), approximate: false };
|
|
695
|
+
if (TEMPLATE_QUALITIES.has(quality.id)) {
|
|
696
|
+
const shape = templateFingering(quality.id, rootSemitone);
|
|
697
|
+
if (shape) return { shape, approximate: false };
|
|
698
|
+
}
|
|
699
|
+
let fallbackId = QUALITY_SIMPLIFICATION[quality.id];
|
|
700
|
+
let hops = 0;
|
|
701
|
+
while (fallbackId && hops < 4) {
|
|
702
|
+
if (TEMPLATE_QUALITIES.has(fallbackId)) {
|
|
703
|
+
const shape = templateFingering(fallbackId, rootSemitone);
|
|
704
|
+
if (shape) return { shape, approximate: true };
|
|
705
|
+
}
|
|
706
|
+
const suf = CANONICAL_SUFFIX[fallbackId];
|
|
707
|
+
if (suf !== void 0) {
|
|
708
|
+
const canonical = rootDisplay + suf;
|
|
709
|
+
if (OPEN_CHORD_SHAPES[canonical])
|
|
710
|
+
return {
|
|
711
|
+
shape: OPEN_CHORD_SHAPES[canonical],
|
|
712
|
+
approximate: true
|
|
713
|
+
};
|
|
714
|
+
}
|
|
715
|
+
fallbackId = QUALITY_SIMPLIFICATION[fallbackId];
|
|
716
|
+
hops += 1;
|
|
717
|
+
}
|
|
718
|
+
return null;
|
|
719
|
+
}
|
|
720
|
+
var DefaultChordDictionary = class {
|
|
721
|
+
getFingering(chord) {
|
|
722
|
+
const parsed = parseChordSymbol(chord);
|
|
723
|
+
if (!parsed) return null;
|
|
724
|
+
const piano = computePianoVoicing(
|
|
725
|
+
parsed.rootSemitone,
|
|
726
|
+
parsed.quality.intervals,
|
|
727
|
+
parsed.bassSemitone
|
|
728
|
+
);
|
|
729
|
+
const guitar = getGuitarFingering(parsed);
|
|
730
|
+
return {
|
|
731
|
+
chord: parsed.raw,
|
|
732
|
+
qualityId: parsed.quality.id,
|
|
733
|
+
qualityLabel: parsed.quality.label,
|
|
734
|
+
piano,
|
|
735
|
+
guitar: guitar ? {
|
|
736
|
+
frets: guitar.shape.frets,
|
|
737
|
+
fingers: guitar.shape.fingers,
|
|
738
|
+
barre: guitar.shape.barre,
|
|
739
|
+
approximate: guitar.approximate || void 0
|
|
740
|
+
} : void 0
|
|
741
|
+
};
|
|
742
|
+
}
|
|
743
|
+
};
|
|
744
|
+
var chordDictionary = new DefaultChordDictionary();
|
|
745
|
+
|
|
746
|
+
// src/parser/parser.ts
|
|
747
|
+
var TIMING_REGEX = /^(.+?)@([0-9]*\.?[0-9]+)x$/;
|
|
748
|
+
function parseChordTiming(rawChord) {
|
|
749
|
+
const match = rawChord.match(TIMING_REGEX);
|
|
750
|
+
if (match) return { chord: match[1], timing: parseFloat(match[2]) };
|
|
751
|
+
return { chord: rawChord };
|
|
752
|
+
}
|
|
753
|
+
function parseLineSegments(lineText) {
|
|
754
|
+
const segments = [];
|
|
755
|
+
const regex = /\[([^\]]+)\]/g;
|
|
756
|
+
let match;
|
|
757
|
+
let lastIndex = 0;
|
|
758
|
+
let currentChord = "";
|
|
759
|
+
let currentTiming;
|
|
760
|
+
while ((match = regex.exec(lineText)) !== null) {
|
|
761
|
+
const rawChord = match[1];
|
|
762
|
+
const { chord, timing } = parseChordTiming(rawChord);
|
|
763
|
+
const textBefore = lineText.slice(lastIndex, match.index);
|
|
764
|
+
if (lastIndex === 0 && textBefore === "") {
|
|
765
|
+
currentChord = chord;
|
|
766
|
+
currentTiming = timing;
|
|
767
|
+
} else {
|
|
768
|
+
segments.push({
|
|
769
|
+
chord: currentChord,
|
|
770
|
+
text: textBefore,
|
|
771
|
+
timing: currentTiming
|
|
772
|
+
});
|
|
773
|
+
currentChord = chord;
|
|
774
|
+
currentTiming = timing;
|
|
775
|
+
}
|
|
776
|
+
lastIndex = regex.lastIndex;
|
|
777
|
+
}
|
|
778
|
+
const remainingText = lineText.slice(lastIndex);
|
|
779
|
+
segments.push({
|
|
780
|
+
chord: currentChord,
|
|
781
|
+
text: remainingText,
|
|
782
|
+
timing: currentTiming
|
|
783
|
+
});
|
|
784
|
+
return segments;
|
|
785
|
+
}
|
|
786
|
+
function parseChordPro(content) {
|
|
787
|
+
const lines = content.split(/\r?\n/);
|
|
788
|
+
const metadata = {};
|
|
789
|
+
const sections = [];
|
|
790
|
+
let currentSection = null;
|
|
791
|
+
let isTab = false;
|
|
792
|
+
let isGrid = false;
|
|
793
|
+
let lastChorusLines = [];
|
|
794
|
+
const commitSection = () => {
|
|
795
|
+
if (currentSection) {
|
|
796
|
+
sections.push(currentSection);
|
|
797
|
+
if (currentSection.type === "chorus") {
|
|
798
|
+
lastChorusLines = [...currentSection.lines];
|
|
799
|
+
}
|
|
800
|
+
currentSection = null;
|
|
801
|
+
}
|
|
802
|
+
};
|
|
803
|
+
const aliasMap = {
|
|
804
|
+
t: "title",
|
|
805
|
+
st: "subtitle",
|
|
806
|
+
a: "artist",
|
|
807
|
+
k: "key",
|
|
808
|
+
c: "comment",
|
|
809
|
+
ci: "comment_italic",
|
|
810
|
+
cb: "comment_box",
|
|
811
|
+
soc: "start_of_chorus",
|
|
812
|
+
eoc: "end_of_chorus",
|
|
813
|
+
sov: "start_of_verse",
|
|
814
|
+
eov: "end_of_verse",
|
|
815
|
+
sob: "start_of_bridge",
|
|
816
|
+
eob: "end_of_bridge",
|
|
817
|
+
sot: "start_of_tab",
|
|
818
|
+
eot: "end_of_tab",
|
|
819
|
+
sog: "start_of_grid",
|
|
820
|
+
eog: "end_of_grid",
|
|
821
|
+
ch: "chorus",
|
|
822
|
+
v: "verse",
|
|
823
|
+
b: "bridge",
|
|
824
|
+
re: "repeat",
|
|
825
|
+
ns: "new_song",
|
|
826
|
+
time_signature: "time",
|
|
827
|
+
timesignature: "time",
|
|
828
|
+
"time signature": "time",
|
|
829
|
+
original_key: "original_key",
|
|
830
|
+
"original key": "original_key"
|
|
831
|
+
};
|
|
832
|
+
for (let line of lines) {
|
|
833
|
+
const trimmed = line.trim();
|
|
834
|
+
if (trimmed.startsWith("{") && trimmed.endsWith("}")) {
|
|
835
|
+
const directive = trimmed.slice(1, -1).trim();
|
|
836
|
+
const colonIndex = directive.indexOf(":");
|
|
837
|
+
let rawName = directive;
|
|
838
|
+
let value = "";
|
|
839
|
+
if (colonIndex !== -1) {
|
|
840
|
+
rawName = directive.substring(0, colonIndex).trim();
|
|
841
|
+
value = directive.substring(colonIndex + 1).trim();
|
|
842
|
+
}
|
|
843
|
+
const lowerName = rawName.toLowerCase();
|
|
844
|
+
const name = aliasMap[lowerName] || lowerName;
|
|
845
|
+
switch (name) {
|
|
846
|
+
case "start_of_chorus":
|
|
847
|
+
commitSection();
|
|
848
|
+
currentSection = {
|
|
849
|
+
type: "chorus",
|
|
850
|
+
label: value || "Refr\xE3o",
|
|
851
|
+
lines: []
|
|
852
|
+
};
|
|
853
|
+
break;
|
|
854
|
+
case "start_of_verse":
|
|
855
|
+
commitSection();
|
|
856
|
+
currentSection = {
|
|
857
|
+
type: "verse",
|
|
858
|
+
label: value || "Verso",
|
|
859
|
+
lines: []
|
|
860
|
+
};
|
|
861
|
+
break;
|
|
862
|
+
case "start_of_bridge":
|
|
863
|
+
commitSection();
|
|
864
|
+
currentSection = {
|
|
865
|
+
type: "bridge",
|
|
866
|
+
label: value || "Ponte",
|
|
867
|
+
lines: []
|
|
868
|
+
};
|
|
869
|
+
break;
|
|
870
|
+
case "start_of_tab":
|
|
871
|
+
commitSection();
|
|
872
|
+
isTab = true;
|
|
873
|
+
currentSection = {
|
|
874
|
+
type: "tab",
|
|
875
|
+
label: value || "Tablatura",
|
|
876
|
+
lines: []
|
|
877
|
+
};
|
|
878
|
+
break;
|
|
879
|
+
case "start_of_grid":
|
|
880
|
+
commitSection();
|
|
881
|
+
isGrid = true;
|
|
882
|
+
currentSection = { type: "grid", label: value || "Grid", lines: [] };
|
|
883
|
+
break;
|
|
884
|
+
case "end_of_chorus":
|
|
885
|
+
if (currentSection?.type === "chorus") commitSection();
|
|
886
|
+
break;
|
|
887
|
+
case "end_of_verse":
|
|
888
|
+
if (currentSection?.type === "verse") commitSection();
|
|
889
|
+
break;
|
|
890
|
+
case "end_of_bridge":
|
|
891
|
+
if (currentSection?.type === "bridge") commitSection();
|
|
892
|
+
break;
|
|
893
|
+
case "end_of_tab":
|
|
894
|
+
isTab = false;
|
|
895
|
+
if (currentSection?.type === "tab") commitSection();
|
|
896
|
+
break;
|
|
897
|
+
case "end_of_grid":
|
|
898
|
+
isGrid = false;
|
|
899
|
+
if (currentSection?.type === "grid") commitSection();
|
|
900
|
+
break;
|
|
901
|
+
case "chorus":
|
|
902
|
+
commitSection();
|
|
903
|
+
sections.push({
|
|
904
|
+
type: "chorus",
|
|
905
|
+
label: value || "Refr\xE3o",
|
|
906
|
+
lines: [...lastChorusLines]
|
|
907
|
+
});
|
|
908
|
+
break;
|
|
909
|
+
case "verse":
|
|
910
|
+
commitSection();
|
|
911
|
+
currentSection = {
|
|
912
|
+
type: "verse",
|
|
913
|
+
label: value || "Verso",
|
|
914
|
+
lines: []
|
|
915
|
+
};
|
|
916
|
+
break;
|
|
917
|
+
case "bridge":
|
|
918
|
+
commitSection();
|
|
919
|
+
currentSection = {
|
|
920
|
+
type: "bridge",
|
|
921
|
+
label: value || "Ponte",
|
|
922
|
+
lines: []
|
|
923
|
+
};
|
|
924
|
+
break;
|
|
925
|
+
case "comment":
|
|
926
|
+
case "comment_italic":
|
|
927
|
+
const commentLine = { type: "comment", text: value };
|
|
928
|
+
if (currentSection) currentSection.lines.push(commentLine);
|
|
929
|
+
else sections.push({ type: "comment", lines: [commentLine] });
|
|
930
|
+
break;
|
|
931
|
+
case "comment_box":
|
|
932
|
+
const cbLine = { type: "comment_box", text: value };
|
|
933
|
+
if (currentSection) currentSection.lines.push(cbLine);
|
|
934
|
+
else sections.push({ type: "comment", lines: [cbLine] });
|
|
935
|
+
break;
|
|
936
|
+
case "repeat":
|
|
937
|
+
if (currentSection) {
|
|
938
|
+
currentSection.repeat = value || "2";
|
|
939
|
+
} else {
|
|
940
|
+
sections.push({
|
|
941
|
+
type: "comment",
|
|
942
|
+
lines: [
|
|
943
|
+
{ type: "comment_box", text: `Repetir: ${value || "2"}` }
|
|
944
|
+
]
|
|
945
|
+
});
|
|
946
|
+
}
|
|
947
|
+
break;
|
|
948
|
+
case "new_song":
|
|
949
|
+
commitSection();
|
|
950
|
+
sections.push({ type: "new_song", lines: [] });
|
|
951
|
+
break;
|
|
952
|
+
case "duration":
|
|
953
|
+
if (/^\d{1,2}:\d{2}$/.test(value)) {
|
|
954
|
+
const [minutes, seconds] = value.split(":").map(Number);
|
|
955
|
+
metadata["duration"] = (minutes * 60 + seconds).toString();
|
|
956
|
+
} else {
|
|
957
|
+
metadata["duration"] = value;
|
|
958
|
+
}
|
|
959
|
+
break;
|
|
960
|
+
default:
|
|
961
|
+
if (value) {
|
|
962
|
+
const metaKey = name.replace(
|
|
963
|
+
/[-_\s]+([a-zA-Z])/g,
|
|
964
|
+
(_, letter) => letter.toUpperCase()
|
|
965
|
+
).replace(/\s+/g, "");
|
|
966
|
+
metadata[metaKey] = value;
|
|
967
|
+
}
|
|
968
|
+
break;
|
|
969
|
+
}
|
|
970
|
+
continue;
|
|
971
|
+
}
|
|
972
|
+
if (trimmed === "") {
|
|
973
|
+
if (currentSection) currentSection.lines.push({ type: "empty" });
|
|
974
|
+
continue;
|
|
975
|
+
}
|
|
976
|
+
if (trimmed.startsWith("#") && !isTab) continue;
|
|
977
|
+
let lineType = "lyrics";
|
|
978
|
+
let parsedSegments = [];
|
|
979
|
+
if (isTab) {
|
|
980
|
+
lineType = "tab";
|
|
981
|
+
} else {
|
|
982
|
+
parsedSegments = parseLineSegments(line);
|
|
983
|
+
const textContent = parsedSegments.map((s) => s.text).join("");
|
|
984
|
+
const onlyBarsAndSpaces = /^[\s|:\-.%]*$/.test(textContent);
|
|
985
|
+
const hasBars = textContent.includes("|");
|
|
986
|
+
if (isGrid || onlyBarsAndSpaces && hasBars) {
|
|
987
|
+
lineType = "chord-section";
|
|
988
|
+
}
|
|
989
|
+
}
|
|
990
|
+
const parsedLine = { type: lineType };
|
|
991
|
+
if (lineType === "tab") {
|
|
992
|
+
parsedLine.text = line;
|
|
993
|
+
} else if (lineType === "lyrics") {
|
|
994
|
+
parsedLine.segments = parsedSegments;
|
|
995
|
+
} else if (lineType === "chord-section") {
|
|
996
|
+
parsedLine.segments = parsedSegments;
|
|
997
|
+
const measures = [];
|
|
998
|
+
let currentChords = [];
|
|
999
|
+
let startBarline = "";
|
|
1000
|
+
let hasSeenChord = false;
|
|
1001
|
+
let startBarlineFound = false;
|
|
1002
|
+
for (let i = 0; i < parsedSegments.length; i++) {
|
|
1003
|
+
const seg = parsedSegments[i];
|
|
1004
|
+
if (seg.chord) {
|
|
1005
|
+
currentChords.push({
|
|
1006
|
+
chord: seg.chord,
|
|
1007
|
+
text: "",
|
|
1008
|
+
timing: seg.timing
|
|
1009
|
+
});
|
|
1010
|
+
hasSeenChord = true;
|
|
1011
|
+
}
|
|
1012
|
+
const barlineMatches = seg.text.match(/\|\||:\||\|:|\|/g);
|
|
1013
|
+
if (barlineMatches) {
|
|
1014
|
+
for (let j = 0; j < barlineMatches.length; j++) {
|
|
1015
|
+
const b = barlineMatches[j];
|
|
1016
|
+
if (!hasSeenChord && !startBarlineFound) {
|
|
1017
|
+
startBarline = b;
|
|
1018
|
+
startBarlineFound = true;
|
|
1019
|
+
} else {
|
|
1020
|
+
measures.push({ chords: currentChords, endBarline: b });
|
|
1021
|
+
currentChords = [];
|
|
1022
|
+
}
|
|
1023
|
+
}
|
|
1024
|
+
}
|
|
1025
|
+
}
|
|
1026
|
+
if (currentChords.length > 0) {
|
|
1027
|
+
measures.push({ chords: currentChords, endBarline: "" });
|
|
1028
|
+
}
|
|
1029
|
+
parsedLine.measures = measures;
|
|
1030
|
+
parsedLine.startBarline = startBarline;
|
|
1031
|
+
}
|
|
1032
|
+
if (!currentSection) currentSection = { type: "verse", lines: [] };
|
|
1033
|
+
currentSection.lines.push(parsedLine);
|
|
1034
|
+
}
|
|
1035
|
+
commitSection();
|
|
1036
|
+
if (!metadata.title) metadata.title = "Sem T\xEDtulo";
|
|
1037
|
+
return { metadata, sections };
|
|
1038
|
+
}
|
|
1039
|
+
|
|
1040
|
+
// src/parser/transpose.ts
|
|
1041
|
+
var NOTE_TO_VAL = {
|
|
1042
|
+
C: 0,
|
|
1043
|
+
"C#": 1,
|
|
1044
|
+
DB: 1,
|
|
1045
|
+
D: 2,
|
|
1046
|
+
"D#": 3,
|
|
1047
|
+
EB: 3,
|
|
1048
|
+
E: 4,
|
|
1049
|
+
F: 5,
|
|
1050
|
+
"F#": 6,
|
|
1051
|
+
GB: 6,
|
|
1052
|
+
G: 7,
|
|
1053
|
+
"G#": 8,
|
|
1054
|
+
AB: 8,
|
|
1055
|
+
A: 9,
|
|
1056
|
+
"A#": 10,
|
|
1057
|
+
BB: 10,
|
|
1058
|
+
B: 11,
|
|
1059
|
+
DO: 0,
|
|
1060
|
+
RE: 2,
|
|
1061
|
+
R\u00C9: 2,
|
|
1062
|
+
MI: 4,
|
|
1063
|
+
FA: 5,
|
|
1064
|
+
F\u00C1: 5,
|
|
1065
|
+
SOL: 7,
|
|
1066
|
+
LA: 9,
|
|
1067
|
+
L\u00C1: 9,
|
|
1068
|
+
SI: 11
|
|
1069
|
+
};
|
|
1070
|
+
var SHARPS = [
|
|
1071
|
+
"C",
|
|
1072
|
+
"C#",
|
|
1073
|
+
"D",
|
|
1074
|
+
"D#",
|
|
1075
|
+
"E",
|
|
1076
|
+
"F",
|
|
1077
|
+
"F#",
|
|
1078
|
+
"G",
|
|
1079
|
+
"G#",
|
|
1080
|
+
"A",
|
|
1081
|
+
"A#",
|
|
1082
|
+
"B"
|
|
1083
|
+
];
|
|
1084
|
+
var FLATS = ["C", "Db", "D", "Eb", "E", "F", "Gb", "G", "Ab", "A", "Bb", "B"];
|
|
1085
|
+
function transposeNote(note, semitones, preferFlats = false) {
|
|
1086
|
+
const upper = note.toUpperCase();
|
|
1087
|
+
if (NOTE_TO_VAL[upper] === void 0) return note;
|
|
1088
|
+
const val = NOTE_TO_VAL[upper];
|
|
1089
|
+
const newVal = (val + semitones + 24) % 12;
|
|
1090
|
+
const targetScale = preferFlats ? FLATS : SHARPS;
|
|
1091
|
+
let transposed = targetScale[newVal];
|
|
1092
|
+
if (note[0] === note[0].toLowerCase()) {
|
|
1093
|
+
transposed = transposed.toLowerCase();
|
|
1094
|
+
}
|
|
1095
|
+
return transposed;
|
|
1096
|
+
}
|
|
1097
|
+
function transposeChord(chord, semitones) {
|
|
1098
|
+
if (!chord || semitones === 0) return chord;
|
|
1099
|
+
if (chord.includes("/")) {
|
|
1100
|
+
return chord.split("/").map((part) => transposeChord(part.trim(), semitones)).join("/");
|
|
1101
|
+
}
|
|
1102
|
+
const noteRegex = /^([A-G][#b]?|Do|Ré|Mi|Fá|Sol|Lá|Si|DO|RE|RÉ|MI|FA|FÁ|SOL|LA|LÁ|SI)/;
|
|
1103
|
+
const match = chord.match(noteRegex);
|
|
1104
|
+
if (!match) return chord;
|
|
1105
|
+
const note = match[1];
|
|
1106
|
+
const suffix = chord.slice(note.length);
|
|
1107
|
+
const preferFlats = chord.includes("b") || chord.includes("B");
|
|
1108
|
+
const transposedNote = transposeNote(note, semitones, preferFlats);
|
|
1109
|
+
return transposedNote + suffix;
|
|
1110
|
+
}
|
|
1111
|
+
|
|
1112
|
+
// src/renderer/ChordRoll.tsx
|
|
1113
|
+
var import_react = require("react");
|
|
1114
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
1115
|
+
function GuitarDiagram({
|
|
1116
|
+
frets,
|
|
1117
|
+
fingers,
|
|
1118
|
+
barre
|
|
1119
|
+
}) {
|
|
1120
|
+
const maxFret2 = Math.max(...frets);
|
|
1121
|
+
let startFret = 1;
|
|
1122
|
+
if (maxFret2 > 4) {
|
|
1123
|
+
const minFret = Math.min(...frets.filter((f) => f > 0));
|
|
1124
|
+
startFret = minFret;
|
|
1125
|
+
}
|
|
1126
|
+
const numFrets = 4;
|
|
1127
|
+
const width = 100;
|
|
1128
|
+
const height = 110;
|
|
1129
|
+
const getStringX = (index) => 14 + index * 14;
|
|
1130
|
+
const getFretY = (index) => 22 + index * 20;
|
|
1131
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
1132
|
+
"svg",
|
|
1133
|
+
{
|
|
1134
|
+
width,
|
|
1135
|
+
height,
|
|
1136
|
+
className: "text-m3-text dark:text-m3-dark-text select-none",
|
|
1137
|
+
children: [
|
|
1138
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1139
|
+
"line",
|
|
1140
|
+
{
|
|
1141
|
+
x1: getStringX(0),
|
|
1142
|
+
y1: getFretY(0) - (startFret === 1 ? 3 : 0),
|
|
1143
|
+
x2: getStringX(5),
|
|
1144
|
+
y2: getFretY(0) - (startFret === 1 ? 3 : 0),
|
|
1145
|
+
className: "stroke-zinc-800 dark:stroke-zinc-200",
|
|
1146
|
+
strokeWidth: startFret === 1 ? 3.5 : 1.5
|
|
1147
|
+
}
|
|
1148
|
+
),
|
|
1149
|
+
startFret > 1 && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
1150
|
+
"text",
|
|
1151
|
+
{
|
|
1152
|
+
x: getStringX(0) - 4,
|
|
1153
|
+
y: getFretY(0) + 12,
|
|
1154
|
+
fontSize: "8",
|
|
1155
|
+
className: "font-mono font-black fill-m3-primary dark:fill-m3-dark-primary",
|
|
1156
|
+
textAnchor: "end",
|
|
1157
|
+
children: [
|
|
1158
|
+
startFret,
|
|
1159
|
+
"\xAA"
|
|
1160
|
+
]
|
|
1161
|
+
}
|
|
1162
|
+
),
|
|
1163
|
+
[0, 1, 2, 3, 4, 5].map((idx) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1164
|
+
"line",
|
|
1165
|
+
{
|
|
1166
|
+
x1: getStringX(idx),
|
|
1167
|
+
y1: getFretY(0),
|
|
1168
|
+
x2: getStringX(idx),
|
|
1169
|
+
y2: getFretY(numFrets),
|
|
1170
|
+
className: "stroke-zinc-400 dark:stroke-zinc-600",
|
|
1171
|
+
strokeOpacity: "0.5",
|
|
1172
|
+
strokeWidth: "1.2"
|
|
1173
|
+
},
|
|
1174
|
+
idx
|
|
1175
|
+
)),
|
|
1176
|
+
[0, 1, 2, 3, 4].map((idx) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1177
|
+
"line",
|
|
1178
|
+
{
|
|
1179
|
+
x1: getStringX(0),
|
|
1180
|
+
y1: getFretY(idx),
|
|
1181
|
+
x2: getStringX(5),
|
|
1182
|
+
y2: getFretY(idx),
|
|
1183
|
+
className: "stroke-zinc-400 dark:stroke-zinc-600",
|
|
1184
|
+
strokeOpacity: "0.4",
|
|
1185
|
+
strokeWidth: "1"
|
|
1186
|
+
},
|
|
1187
|
+
idx
|
|
1188
|
+
)),
|
|
1189
|
+
barre !== void 0 && (() => {
|
|
1190
|
+
const barreFretInWindow = barre - startFret;
|
|
1191
|
+
if (barreFretInWindow >= 0 && barreFretInWindow < numFrets) {
|
|
1192
|
+
const y = getFretY(barreFretInWindow) + 10;
|
|
1193
|
+
const startStr = frets.findIndex((f) => f === barre);
|
|
1194
|
+
const endStr = 5;
|
|
1195
|
+
if (startStr !== -1) {
|
|
1196
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1197
|
+
"rect",
|
|
1198
|
+
{
|
|
1199
|
+
x: getStringX(startStr) - 4,
|
|
1200
|
+
y: y - 4,
|
|
1201
|
+
width: getStringX(endStr) - getStringX(startStr) + 8,
|
|
1202
|
+
height: 8,
|
|
1203
|
+
rx: 4,
|
|
1204
|
+
className: "fill-m3-primary dark:fill-m3-dark-primary opacity-80"
|
|
1205
|
+
}
|
|
1206
|
+
);
|
|
1207
|
+
}
|
|
1208
|
+
}
|
|
1209
|
+
return null;
|
|
1210
|
+
})(),
|
|
1211
|
+
frets.map((fret, stringIdx) => {
|
|
1212
|
+
if (fret === -1) {
|
|
1213
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1214
|
+
"text",
|
|
1215
|
+
{
|
|
1216
|
+
x: getStringX(stringIdx),
|
|
1217
|
+
y: 12,
|
|
1218
|
+
fontSize: "10",
|
|
1219
|
+
fontWeight: "bold",
|
|
1220
|
+
className: "fill-red-500 font-black",
|
|
1221
|
+
textAnchor: "middle",
|
|
1222
|
+
children: "\xD7"
|
|
1223
|
+
},
|
|
1224
|
+
stringIdx
|
|
1225
|
+
);
|
|
1226
|
+
}
|
|
1227
|
+
if (fret === 0) {
|
|
1228
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1229
|
+
"circle",
|
|
1230
|
+
{
|
|
1231
|
+
cx: getStringX(stringIdx),
|
|
1232
|
+
cy: 10,
|
|
1233
|
+
r: 2,
|
|
1234
|
+
fill: "none",
|
|
1235
|
+
className: "stroke-emerald-500",
|
|
1236
|
+
strokeWidth: "1.2"
|
|
1237
|
+
},
|
|
1238
|
+
stringIdx
|
|
1239
|
+
);
|
|
1240
|
+
}
|
|
1241
|
+
const fretInWindow = fret - startFret;
|
|
1242
|
+
if (fretInWindow >= 0 && fretInWindow < numFrets) {
|
|
1243
|
+
const cx = getStringX(stringIdx);
|
|
1244
|
+
const cy = getFretY(fretInWindow) + 10;
|
|
1245
|
+
const finger = fingers ? fingers[stringIdx] : 0;
|
|
1246
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("g", { children: [
|
|
1247
|
+
!(barre !== void 0 && fret === barre && stringIdx >= frets.findIndex((f) => f === barre)) && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1248
|
+
"circle",
|
|
1249
|
+
{
|
|
1250
|
+
cx,
|
|
1251
|
+
cy,
|
|
1252
|
+
r: 5,
|
|
1253
|
+
className: "fill-m3-primary dark:fill-m3-dark-primary"
|
|
1254
|
+
}
|
|
1255
|
+
),
|
|
1256
|
+
finger > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1257
|
+
"text",
|
|
1258
|
+
{
|
|
1259
|
+
x: cx,
|
|
1260
|
+
y: cy + 2.5,
|
|
1261
|
+
fontSize: "6.5",
|
|
1262
|
+
fontWeight: "bold",
|
|
1263
|
+
fill: "white",
|
|
1264
|
+
textAnchor: "middle",
|
|
1265
|
+
className: "font-bold fill-white",
|
|
1266
|
+
children: finger
|
|
1267
|
+
}
|
|
1268
|
+
)
|
|
1269
|
+
] }, stringIdx);
|
|
1270
|
+
}
|
|
1271
|
+
return null;
|
|
1272
|
+
})
|
|
1273
|
+
]
|
|
1274
|
+
}
|
|
1275
|
+
);
|
|
1276
|
+
}
|
|
1277
|
+
function PianoDiagram({ highlightKeys }) {
|
|
1278
|
+
const whiteKeySemitones = [
|
|
1279
|
+
0,
|
|
1280
|
+
2,
|
|
1281
|
+
4,
|
|
1282
|
+
5,
|
|
1283
|
+
7,
|
|
1284
|
+
9,
|
|
1285
|
+
11,
|
|
1286
|
+
// Octave 1
|
|
1287
|
+
12,
|
|
1288
|
+
14,
|
|
1289
|
+
16,
|
|
1290
|
+
17,
|
|
1291
|
+
19,
|
|
1292
|
+
21,
|
|
1293
|
+
23
|
|
1294
|
+
// Octave 2
|
|
1295
|
+
];
|
|
1296
|
+
const keyWidth = 14;
|
|
1297
|
+
const keyHeight = 56;
|
|
1298
|
+
const blackWidth = 9;
|
|
1299
|
+
const blackHeight = 34;
|
|
1300
|
+
const blackKeySemitones = [1, 3, 6, 8, 10, 13, 15, 18, 20, 22];
|
|
1301
|
+
const getBlackKeyX = (semitone) => {
|
|
1302
|
+
const octave = Math.floor(semitone / 12);
|
|
1303
|
+
const semitoneInOctave = semitone % 12;
|
|
1304
|
+
let whiteIndexBefore = 0;
|
|
1305
|
+
if (semitoneInOctave === 1) whiteIndexBefore = 1;
|
|
1306
|
+
else if (semitoneInOctave === 3) whiteIndexBefore = 2;
|
|
1307
|
+
else if (semitoneInOctave === 6) whiteIndexBefore = 4;
|
|
1308
|
+
else if (semitoneInOctave === 8) whiteIndexBefore = 5;
|
|
1309
|
+
else if (semitoneInOctave === 10) whiteIndexBefore = 6;
|
|
1310
|
+
const absoluteWhiteIndex = octave * 7 + whiteIndexBefore;
|
|
1311
|
+
return absoluteWhiteIndex * keyWidth - blackWidth / 2;
|
|
1312
|
+
};
|
|
1313
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
1314
|
+
"svg",
|
|
1315
|
+
{
|
|
1316
|
+
width: 14 * keyWidth + 2,
|
|
1317
|
+
height: keyHeight + 4,
|
|
1318
|
+
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",
|
|
1319
|
+
children: [
|
|
1320
|
+
whiteKeySemitones.map((st, idx) => {
|
|
1321
|
+
const isHighlighted = highlightKeys.includes(st);
|
|
1322
|
+
const x = idx * keyWidth + 1;
|
|
1323
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("g", { children: [
|
|
1324
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1325
|
+
"rect",
|
|
1326
|
+
{
|
|
1327
|
+
x,
|
|
1328
|
+
y: 2,
|
|
1329
|
+
width: keyWidth - 1,
|
|
1330
|
+
height: keyHeight,
|
|
1331
|
+
rx: 1.5,
|
|
1332
|
+
className: `${isHighlighted ? "fill-m3-primary dark:fill-m3-dark-primary" : "fill-white dark:fill-zinc-800"} stroke-zinc-300 dark:stroke-zinc-700`,
|
|
1333
|
+
strokeWidth: "0.8"
|
|
1334
|
+
}
|
|
1335
|
+
),
|
|
1336
|
+
isHighlighted && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1337
|
+
"circle",
|
|
1338
|
+
{
|
|
1339
|
+
cx: x + (keyWidth - 1) / 2,
|
|
1340
|
+
cy: keyHeight - 8,
|
|
1341
|
+
r: 2,
|
|
1342
|
+
className: "fill-white dark:fill-zinc-900"
|
|
1343
|
+
}
|
|
1344
|
+
)
|
|
1345
|
+
] }, st);
|
|
1346
|
+
}),
|
|
1347
|
+
blackKeySemitones.map((st) => {
|
|
1348
|
+
const isHighlighted = highlightKeys.includes(st);
|
|
1349
|
+
const x = getBlackKeyX(st) + 1;
|
|
1350
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("g", { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1351
|
+
"rect",
|
|
1352
|
+
{
|
|
1353
|
+
x,
|
|
1354
|
+
y: 2,
|
|
1355
|
+
width: blackWidth,
|
|
1356
|
+
height: blackHeight,
|
|
1357
|
+
rx: 1,
|
|
1358
|
+
className: `${isHighlighted ? "fill-m3-primary dark:fill-m3-dark-primary" : "fill-zinc-800 dark:fill-zinc-950"} stroke-zinc-900 dark:stroke-black`,
|
|
1359
|
+
strokeWidth: "0.8"
|
|
1360
|
+
}
|
|
1361
|
+
) }, st);
|
|
1362
|
+
})
|
|
1363
|
+
]
|
|
1364
|
+
}
|
|
1365
|
+
);
|
|
1366
|
+
}
|
|
1367
|
+
function ChordRoll({
|
|
1368
|
+
uniqueChords,
|
|
1369
|
+
transposeVal,
|
|
1370
|
+
capoVal = 0,
|
|
1371
|
+
onChordClick,
|
|
1372
|
+
instrument,
|
|
1373
|
+
showDiagrams,
|
|
1374
|
+
showChords
|
|
1375
|
+
}) {
|
|
1376
|
+
const isGuitar = instrument === "guitar";
|
|
1377
|
+
const effectiveTranspose = transposeVal - (isGuitar ? capoVal : 0);
|
|
1378
|
+
const chordItems = (0, import_react.useMemo)(() => {
|
|
1379
|
+
return uniqueChords.map((chord) => {
|
|
1380
|
+
const transposed = transposeChord(chord, effectiveTranspose);
|
|
1381
|
+
const fingering = chordDictionary.getFingering(transposed);
|
|
1382
|
+
return {
|
|
1383
|
+
original: chord,
|
|
1384
|
+
transposed,
|
|
1385
|
+
fingering
|
|
1386
|
+
};
|
|
1387
|
+
});
|
|
1388
|
+
}, [uniqueChords, effectiveTranspose]);
|
|
1389
|
+
if (uniqueChords.length === 0 || !showDiagrams || !showChords) return null;
|
|
1390
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
1391
|
+
"div",
|
|
1392
|
+
{
|
|
1393
|
+
className: "w-full select-none mb-6",
|
|
1394
|
+
onTouchStart: (e) => e.stopPropagation(),
|
|
1395
|
+
onTouchMove: (e) => e.stopPropagation(),
|
|
1396
|
+
onTouchEnd: (e) => e.stopPropagation(),
|
|
1397
|
+
children: [
|
|
1398
|
+
isGuitar && capoVal > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "px-4 mb-2 flex items-center justify-between", children: /* @__PURE__ */ (0, import_jsx_runtime.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: [
|
|
1399
|
+
"Capo na ",
|
|
1400
|
+
capoVal,
|
|
1401
|
+
"\xAA casa \u2014 acordes em formato relativo"
|
|
1402
|
+
] }) }),
|
|
1403
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "flex flex-row overflow-x-auto gap-6 py-2 px-4 no-scrollbar scroll-smooth", children: chordItems.map((item, idx) => {
|
|
1404
|
+
const isPiano = instrument === "piano";
|
|
1405
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
1406
|
+
"div",
|
|
1407
|
+
{
|
|
1408
|
+
onClick: () => onChordClick?.(item.transposed),
|
|
1409
|
+
className: `flex flex-col items-center p-2 transition-all cursor-pointer hover:opacity-85 shrink-0 ${isPiano ? "w-48" : "w-24"}`,
|
|
1410
|
+
title: "Clique para ver detalhes do acorde",
|
|
1411
|
+
children: [
|
|
1412
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "text-xs font-black text-m3-primary dark:text-m3-dark-primary font-mono mb-1.5", children: item.transposed }),
|
|
1413
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "flex items-center justify-center flex-1 min-h-17.5", children: item.fingering ? isPiano && item.fingering.piano ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1414
|
+
PianoDiagram,
|
|
1415
|
+
{
|
|
1416
|
+
highlightKeys: item.fingering.piano.highlightKeys
|
|
1417
|
+
}
|
|
1418
|
+
) : !isPiano && item.fingering.guitar ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1419
|
+
GuitarDiagram,
|
|
1420
|
+
{
|
|
1421
|
+
frets: item.fingering.guitar.frets,
|
|
1422
|
+
fingers: item.fingering.guitar.fingers,
|
|
1423
|
+
barre: item.fingering.guitar.barre
|
|
1424
|
+
}
|
|
1425
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "text-[10px] text-zinc-400 font-mono italic", children: "Sem visual" }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "text-[10px] text-zinc-400 font-mono italic", children: "N\xE3o registado" }) }),
|
|
1426
|
+
item.fingering?.piano && /* @__PURE__ */ (0, import_jsx_runtime.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(" - ") })
|
|
1427
|
+
]
|
|
1428
|
+
},
|
|
1429
|
+
idx
|
|
1430
|
+
);
|
|
1431
|
+
}) })
|
|
1432
|
+
]
|
|
1433
|
+
}
|
|
1434
|
+
);
|
|
1435
|
+
}
|
|
1436
|
+
|
|
1437
|
+
// src/renderer/ChordProRenderer.tsx
|
|
1438
|
+
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
1439
|
+
var YT_ID_REGEX = /(?:youtu\.be\/|youtube\.com\/(?:embed\/|v\/|watch\?v=|watch\?.+&v=))([^&?]+)/;
|
|
1440
|
+
function extractYoutubeId(urlOrId) {
|
|
1441
|
+
const match = urlOrId.match(YT_ID_REGEX);
|
|
1442
|
+
return match?.[1] || urlOrId;
|
|
1443
|
+
}
|
|
1444
|
+
function getDuration(duration) {
|
|
1445
|
+
const seconds = Number(duration);
|
|
1446
|
+
if (isNaN(seconds)) {
|
|
1447
|
+
return "00:00";
|
|
1448
|
+
} else {
|
|
1449
|
+
return `${Math.trunc(seconds / 60)}:${seconds % 60}`;
|
|
1450
|
+
}
|
|
1451
|
+
}
|
|
1452
|
+
var ChordProRenderer = import_react2.default.memo(
|
|
1453
|
+
({
|
|
1454
|
+
content,
|
|
1455
|
+
showChords,
|
|
1456
|
+
transposeVal = 0,
|
|
1457
|
+
capoVal = 0,
|
|
1458
|
+
onTransposeChange,
|
|
1459
|
+
onCapoChange,
|
|
1460
|
+
twoColumnLayout = false,
|
|
1461
|
+
fontSize,
|
|
1462
|
+
instrument = "guitar",
|
|
1463
|
+
showDiagrams = false,
|
|
1464
|
+
fileName,
|
|
1465
|
+
showYoutubePlayer: showYoutubePlayerProp,
|
|
1466
|
+
onShowYoutubePlayerChange,
|
|
1467
|
+
scrollContainerRef
|
|
1468
|
+
}) => {
|
|
1469
|
+
const [ytPlayerRef, setYtPlayerRef] = (0, import_react2.useState)(null);
|
|
1470
|
+
const [isPlayingYoutube, setIsPlayingYoutube] = (0, import_react2.useState)(false);
|
|
1471
|
+
const [isYoutubeRepeat, setIsYoutubeRepeat] = (0, import_react2.useState)(false);
|
|
1472
|
+
const [showYoutubeInternal, setShowYoutubeInternal] = (0, import_react2.useState)(false);
|
|
1473
|
+
const showYoutubePlayer = showYoutubePlayerProp ?? showYoutubeInternal;
|
|
1474
|
+
const setShowYoutubePlayer = (0, import_react2.useCallback)(
|
|
1475
|
+
(val) => {
|
|
1476
|
+
setShowYoutubeInternal(val);
|
|
1477
|
+
onShowYoutubePlayerChange?.(val);
|
|
1478
|
+
},
|
|
1479
|
+
[onShowYoutubePlayerChange]
|
|
1480
|
+
);
|
|
1481
|
+
const isYoutubeRepeatRef = (0, import_react2.useRef)(isYoutubeRepeat);
|
|
1482
|
+
isYoutubeRepeatRef.current = isYoutubeRepeat;
|
|
1483
|
+
const parsedSong = (0, import_react2.useMemo)(() => {
|
|
1484
|
+
return parseChordPro(content);
|
|
1485
|
+
}, [content]);
|
|
1486
|
+
const { metadata } = parsedSong;
|
|
1487
|
+
const isGuitar = instrument === "guitar";
|
|
1488
|
+
const effectiveCapo = isGuitar ? capoVal : 0;
|
|
1489
|
+
const effectiveTranspose = transposeVal - effectiveCapo;
|
|
1490
|
+
const soundingKey = (0, import_react2.useMemo)(() => {
|
|
1491
|
+
return transposeChord(metadata.key || "C", transposeVal);
|
|
1492
|
+
}, [metadata.key, transposeVal]);
|
|
1493
|
+
const renderedKey = (0, import_react2.useMemo)(() => {
|
|
1494
|
+
return transposeChord(metadata.key || "C", effectiveTranspose);
|
|
1495
|
+
}, [metadata.key, effectiveTranspose]);
|
|
1496
|
+
const resolvedUniqueChords = (0, import_react2.useMemo)(() => {
|
|
1497
|
+
const chords = /* @__PURE__ */ new Set();
|
|
1498
|
+
for (const section of parsedSong.sections) {
|
|
1499
|
+
for (const line of section.lines) {
|
|
1500
|
+
if (line.segments) {
|
|
1501
|
+
for (const seg of line.segments) {
|
|
1502
|
+
if (seg.chord) chords.add(seg.chord);
|
|
1503
|
+
}
|
|
1504
|
+
}
|
|
1505
|
+
if (line.measures) {
|
|
1506
|
+
for (const m of line.measures) {
|
|
1507
|
+
for (const c of m.chords) {
|
|
1508
|
+
if (c.chord) chords.add(c.chord);
|
|
1509
|
+
}
|
|
1510
|
+
}
|
|
1511
|
+
}
|
|
1512
|
+
}
|
|
1513
|
+
}
|
|
1514
|
+
return Array.from(chords);
|
|
1515
|
+
}, [parsedSong]);
|
|
1516
|
+
const [selectedChord, setSelectedChord] = (0, import_react2.useState)(null);
|
|
1517
|
+
const [modalInstrument, setModalInstrument] = (0, import_react2.useState)(
|
|
1518
|
+
instrument
|
|
1519
|
+
);
|
|
1520
|
+
const chordFingering = (0, import_react2.useMemo)(() => {
|
|
1521
|
+
if (!selectedChord) return null;
|
|
1522
|
+
return chordDictionary.getFingering(selectedChord);
|
|
1523
|
+
}, [selectedChord]);
|
|
1524
|
+
const handleChordClick = (chord) => {
|
|
1525
|
+
setModalInstrument(instrument);
|
|
1526
|
+
setSelectedChord(chord);
|
|
1527
|
+
};
|
|
1528
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "relative flex flex-col flex-1 overflow-hidden h-full", children: [
|
|
1529
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
1530
|
+
"div",
|
|
1531
|
+
{
|
|
1532
|
+
ref: scrollContainerRef,
|
|
1533
|
+
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",
|
|
1534
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "max-w-3xl mx-auto print-song-card", children: [
|
|
1535
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "mb-6 border-b border-neutral-100 dark:border-slate-800 pb-5 select-none", children: [
|
|
1536
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "flex items-start justify-between gap-4 flex-wrap", children: [
|
|
1537
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { children: [
|
|
1538
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("h2", { className: "text-2xl font-bold tracking-tight text-neutral-900 dark:text-white", children: metadata.title }),
|
|
1539
|
+
metadata.subtitle && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("h3", { className: "text-[15px] font-medium text-neutral-600 dark:text-neutral-400 mt-1", children: metadata.subtitle }),
|
|
1540
|
+
(metadata.artist || metadata.composer) && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "flex items-center gap-1.5 text-xs text-neutral-500 mt-2 font-medium flex-wrap", children: [
|
|
1541
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_lucide_react.User, { className: "w-3.5 h-3.5 text-[#0284c7]" }),
|
|
1542
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { children: [
|
|
1543
|
+
"Por:",
|
|
1544
|
+
" ",
|
|
1545
|
+
[metadata.artist, metadata.composer].filter(Boolean).join(" / ")
|
|
1546
|
+
] })
|
|
1547
|
+
] }),
|
|
1548
|
+
metadata.translator && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "flex items-center gap-1.5 text-xs text-neutral-500 mt-2 font-medium flex-wrap", children: [
|
|
1549
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_lucide_react.User, { className: "w-3.5 h-3.5 text-[#0284c7]" }),
|
|
1550
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { children: [
|
|
1551
|
+
"Traduzido por: ",
|
|
1552
|
+
metadata.translator
|
|
1553
|
+
] })
|
|
1554
|
+
] }),
|
|
1555
|
+
metadata.album && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "flex items-center gap-1.5 text-xs text-neutral-500 mt-1 font-medium", children: [
|
|
1556
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_lucide_react.Disc, { className: "w-3.5 h-3.5 text-[#0284c7]" }),
|
|
1557
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { children: [
|
|
1558
|
+
"\xC1lbum: ",
|
|
1559
|
+
metadata.album
|
|
1560
|
+
] })
|
|
1561
|
+
] })
|
|
1562
|
+
] }),
|
|
1563
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "flex flex-wrap items-center gap-1.5 justify-end", children: [
|
|
1564
|
+
metadata.songNumber && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("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: [
|
|
1565
|
+
"N\xBA ",
|
|
1566
|
+
metadata.songNumber
|
|
1567
|
+
] }),
|
|
1568
|
+
(metadata.key || transposeVal !== 0) && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("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: [
|
|
1569
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_lucide_react.Key, { className: "w-3 h-3" }),
|
|
1570
|
+
"Tom: ",
|
|
1571
|
+
soundingKey
|
|
1572
|
+
] }),
|
|
1573
|
+
effectiveCapo > 0 && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("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: [
|
|
1574
|
+
"Capo: ",
|
|
1575
|
+
effectiveCapo,
|
|
1576
|
+
"\xAA casa"
|
|
1577
|
+
] }),
|
|
1578
|
+
effectiveCapo > 0 && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("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: [
|
|
1579
|
+
"Formato: ",
|
|
1580
|
+
renderedKey
|
|
1581
|
+
] }),
|
|
1582
|
+
metadata.originalKey && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("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: [
|
|
1583
|
+
"Tom Orig: ",
|
|
1584
|
+
metadata.originalKey
|
|
1585
|
+
] }),
|
|
1586
|
+
metadata.capo && metadata.capo !== "0" && effectiveCapo === 0 && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("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: [
|
|
1587
|
+
"Capo Orig: ",
|
|
1588
|
+
metadata.capo,
|
|
1589
|
+
"\xAA casa"
|
|
1590
|
+
] }),
|
|
1591
|
+
metadata.tempo && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("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: [
|
|
1592
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_lucide_react.Flame, { className: "w-3 h-3" }),
|
|
1593
|
+
metadata.tempo,
|
|
1594
|
+
" BPM"
|
|
1595
|
+
] }),
|
|
1596
|
+
metadata.time && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("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 }),
|
|
1597
|
+
metadata.ccli && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("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: [
|
|
1598
|
+
"CCLI: ",
|
|
1599
|
+
metadata.ccli
|
|
1600
|
+
] })
|
|
1601
|
+
] })
|
|
1602
|
+
] }),
|
|
1603
|
+
(metadata.copyright || metadata.duration) && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("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: [
|
|
1604
|
+
metadata.copyright && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { children: [
|
|
1605
|
+
"\xA9 ",
|
|
1606
|
+
metadata.copyright
|
|
1607
|
+
] }),
|
|
1608
|
+
metadata.duration && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { children: [
|
|
1609
|
+
"Dura\xE7\xE3o: ",
|
|
1610
|
+
getDuration(metadata.duration)
|
|
1611
|
+
] })
|
|
1612
|
+
] }),
|
|
1613
|
+
(transposeVal !== 0 || effectiveCapo !== 0) && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("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: [
|
|
1614
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "flex items-center gap-2 flex-wrap", children: [
|
|
1615
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { className: "font-semibold", children: [
|
|
1616
|
+
"Tom:",
|
|
1617
|
+
" ",
|
|
1618
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("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 })
|
|
1619
|
+
] }),
|
|
1620
|
+
effectiveCapo > 0 && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { className: "font-semibold text-amber-700 dark:text-amber-300", children: [
|
|
1621
|
+
"\u2022 Capo:",
|
|
1622
|
+
" ",
|
|
1623
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("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: [
|
|
1624
|
+
effectiveCapo,
|
|
1625
|
+
"\xAA casa (",
|
|
1626
|
+
renderedKey,
|
|
1627
|
+
")"
|
|
1628
|
+
] })
|
|
1629
|
+
] })
|
|
1630
|
+
] }),
|
|
1631
|
+
(onTransposeChange || onCapoChange) && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
1632
|
+
"button",
|
|
1633
|
+
{
|
|
1634
|
+
type: "button",
|
|
1635
|
+
onClick: () => {
|
|
1636
|
+
onTransposeChange?.(0);
|
|
1637
|
+
onCapoChange?.(0);
|
|
1638
|
+
},
|
|
1639
|
+
className: "text-[10px] font-bold hover:underline underline-offset-2 uppercase text-indigo-600 dark:text-indigo-400 cursor-pointer",
|
|
1640
|
+
children: "Repor Tom / Capo"
|
|
1641
|
+
}
|
|
1642
|
+
)
|
|
1643
|
+
] })
|
|
1644
|
+
] }),
|
|
1645
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
1646
|
+
ChordRoll,
|
|
1647
|
+
{
|
|
1648
|
+
uniqueChords: resolvedUniqueChords,
|
|
1649
|
+
transposeVal,
|
|
1650
|
+
capoVal: effectiveCapo,
|
|
1651
|
+
onChordClick: handleChordClick,
|
|
1652
|
+
instrument,
|
|
1653
|
+
showDiagrams,
|
|
1654
|
+
showChords
|
|
1655
|
+
}
|
|
1656
|
+
),
|
|
1657
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
1658
|
+
"div",
|
|
1659
|
+
{
|
|
1660
|
+
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"}`,
|
|
1661
|
+
style: fontSize ? { fontSize: `${fontSize}px` } : void 0,
|
|
1662
|
+
children: parsedSong.sections.map((section, secIdx) => {
|
|
1663
|
+
const isChorus = section.type === "chorus";
|
|
1664
|
+
const isBridge = section.type === "bridge";
|
|
1665
|
+
if (section.type === "new_song") {
|
|
1666
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
1667
|
+
"div",
|
|
1668
|
+
{
|
|
1669
|
+
className: "w-full my-12 flex items-center justify-center select-none break-before-column",
|
|
1670
|
+
children: [
|
|
1671
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "flex-1 border-t-2 border-slate-200 dark:border-slate-800 border-dashed" }),
|
|
1672
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_lucide_react.Music, { className: "w-5 h-5 mx-4 text-slate-300 dark:text-slate-700" }),
|
|
1673
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "flex-1 border-t-2 border-slate-200 dark:border-slate-800 border-dashed" })
|
|
1674
|
+
]
|
|
1675
|
+
},
|
|
1676
|
+
secIdx
|
|
1677
|
+
);
|
|
1678
|
+
}
|
|
1679
|
+
if (section.type === "grid") {
|
|
1680
|
+
const maxMeasures = Math.max(
|
|
1681
|
+
1,
|
|
1682
|
+
...section.lines.map((l) => l.measures?.length || 1)
|
|
1683
|
+
);
|
|
1684
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
1685
|
+
"div",
|
|
1686
|
+
{
|
|
1687
|
+
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" : ""}`,
|
|
1688
|
+
children: [
|
|
1689
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "flex items-center justify-between mb-3", children: [
|
|
1690
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("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: [
|
|
1691
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_lucide_react.LayoutGrid, { className: "w-3.5 h-3.5" }),
|
|
1692
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { children: section.label || "Instrumental" })
|
|
1693
|
+
] }),
|
|
1694
|
+
section.repeat && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("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: [
|
|
1695
|
+
"Repetir ",
|
|
1696
|
+
section.repeat,
|
|
1697
|
+
"x"
|
|
1698
|
+
] })
|
|
1699
|
+
] }),
|
|
1700
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "space-y-1.5 font-medium", children: section.lines.map((line, lineIdx) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
1701
|
+
LineRenderer,
|
|
1702
|
+
{
|
|
1703
|
+
line,
|
|
1704
|
+
showChords,
|
|
1705
|
+
transpose: effectiveTranspose,
|
|
1706
|
+
onChordClick: handleChordClick,
|
|
1707
|
+
maxGridMeasures: maxMeasures
|
|
1708
|
+
},
|
|
1709
|
+
lineIdx
|
|
1710
|
+
)) })
|
|
1711
|
+
]
|
|
1712
|
+
},
|
|
1713
|
+
secIdx
|
|
1714
|
+
);
|
|
1715
|
+
}
|
|
1716
|
+
if (isChorus || isBridge) {
|
|
1717
|
+
const borderColor = isChorus ? "border-m3-primary/30 dark:border-m3-dark-primary/30" : "border-amber-500/30 dark:border-amber-400/30";
|
|
1718
|
+
const labelColor = isChorus ? "text-m3-text dark:text-m3-dark-text" : "text-amber-700 dark:text-amber-400";
|
|
1719
|
+
const iconColor = isChorus ? "text-m3-secondary" : "text-amber-500";
|
|
1720
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
1721
|
+
"div",
|
|
1722
|
+
{
|
|
1723
|
+
className: `pl-4 md:pl-6 border-l-2 my-6 ${borderColor} ${twoColumnLayout ? "break-inside-avoid-column inline-block w-full" : ""}`,
|
|
1724
|
+
children: [
|
|
1725
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
1726
|
+
"div",
|
|
1727
|
+
{
|
|
1728
|
+
className: `flex items-center gap-1.5 text-[11px] font-bold uppercase tracking-wider mb-3 select-none ${labelColor}`,
|
|
1729
|
+
children: [
|
|
1730
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
1731
|
+
import_lucide_react.Music,
|
|
1732
|
+
{
|
|
1733
|
+
className: `w-3.5 h-3.5 shrink-0 ${iconColor}`
|
|
1734
|
+
}
|
|
1735
|
+
),
|
|
1736
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { children: section.label || (isChorus ? "Refr\xE3o" : "Ponte") }),
|
|
1737
|
+
section.repeat && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
1738
|
+
"span",
|
|
1739
|
+
{
|
|
1740
|
+
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"}`,
|
|
1741
|
+
children: [
|
|
1742
|
+
section.repeat,
|
|
1743
|
+
"x"
|
|
1744
|
+
]
|
|
1745
|
+
}
|
|
1746
|
+
)
|
|
1747
|
+
]
|
|
1748
|
+
}
|
|
1749
|
+
),
|
|
1750
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "space-y-4 font-medium", children: section.lines.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
1751
|
+
"div",
|
|
1752
|
+
{
|
|
1753
|
+
className: `text-xs italic my-1 opacity-70 ${labelColor}`,
|
|
1754
|
+
children: "(Repete o refr\xE3o)"
|
|
1755
|
+
}
|
|
1756
|
+
) : section.lines.map((line, lineIdx) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
1757
|
+
LineRenderer,
|
|
1758
|
+
{
|
|
1759
|
+
line,
|
|
1760
|
+
showChords,
|
|
1761
|
+
transpose: effectiveTranspose,
|
|
1762
|
+
onChordClick: handleChordClick
|
|
1763
|
+
},
|
|
1764
|
+
lineIdx
|
|
1765
|
+
)) })
|
|
1766
|
+
]
|
|
1767
|
+
},
|
|
1768
|
+
secIdx
|
|
1769
|
+
);
|
|
1770
|
+
}
|
|
1771
|
+
if (section.type === "tab") {
|
|
1772
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
1773
|
+
"div",
|
|
1774
|
+
{
|
|
1775
|
+
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" : ""}`,
|
|
1776
|
+
children: [
|
|
1777
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("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" }),
|
|
1778
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "overflow-x-auto no-scrollbar", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("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") }) })
|
|
1779
|
+
]
|
|
1780
|
+
},
|
|
1781
|
+
secIdx
|
|
1782
|
+
);
|
|
1783
|
+
}
|
|
1784
|
+
if (section.type === "comment") {
|
|
1785
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
1786
|
+
"div",
|
|
1787
|
+
{
|
|
1788
|
+
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" : ""}`,
|
|
1789
|
+
children: section.lines.map((l) => l.text).join(", ")
|
|
1790
|
+
},
|
|
1791
|
+
secIdx
|
|
1792
|
+
);
|
|
1793
|
+
}
|
|
1794
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
1795
|
+
"div",
|
|
1796
|
+
{
|
|
1797
|
+
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" : ""}`,
|
|
1798
|
+
children: [
|
|
1799
|
+
section.label && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("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" }),
|
|
1800
|
+
section.label && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("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: [
|
|
1801
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_lucide_react.Music, { className: "w-3.5 h-3.5 text-m3-secondary/60 shrink-0" }),
|
|
1802
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { children: section.label }),
|
|
1803
|
+
section.repeat && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("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: [
|
|
1804
|
+
section.repeat,
|
|
1805
|
+
"x"
|
|
1806
|
+
] })
|
|
1807
|
+
] }),
|
|
1808
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "space-y-4", children: section.lines.map((line, lineIdx) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
1809
|
+
LineRenderer,
|
|
1810
|
+
{
|
|
1811
|
+
line,
|
|
1812
|
+
showChords,
|
|
1813
|
+
transpose: effectiveTranspose,
|
|
1814
|
+
onChordClick: handleChordClick
|
|
1815
|
+
},
|
|
1816
|
+
lineIdx
|
|
1817
|
+
)) })
|
|
1818
|
+
]
|
|
1819
|
+
},
|
|
1820
|
+
secIdx
|
|
1821
|
+
);
|
|
1822
|
+
})
|
|
1823
|
+
}
|
|
1824
|
+
),
|
|
1825
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("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: [
|
|
1826
|
+
metadata.artist && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("p", { children: [
|
|
1827
|
+
"Artista Original: ",
|
|
1828
|
+
metadata.artist
|
|
1829
|
+
] }),
|
|
1830
|
+
metadata.composer && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("p", { children: [
|
|
1831
|
+
"Compositor: ",
|
|
1832
|
+
metadata.composer
|
|
1833
|
+
] }),
|
|
1834
|
+
metadata.lyricist && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("p", { children: [
|
|
1835
|
+
"Letra: ",
|
|
1836
|
+
metadata.lyricist
|
|
1837
|
+
] }),
|
|
1838
|
+
metadata.arranger && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("p", { children: [
|
|
1839
|
+
"Arranjo: ",
|
|
1840
|
+
metadata.arranger
|
|
1841
|
+
] }),
|
|
1842
|
+
metadata.year && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("p", { children: [
|
|
1843
|
+
"Ano: ",
|
|
1844
|
+
metadata.year
|
|
1845
|
+
] }),
|
|
1846
|
+
metadata.originalKey && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("p", { children: [
|
|
1847
|
+
"Tom Original: ",
|
|
1848
|
+
metadata.originalKey
|
|
1849
|
+
] }),
|
|
1850
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "pt-2 mt-2 border-t border-neutral-50/50 dark:border-zinc-900/50 inline-block", children: [
|
|
1851
|
+
metadata.copyright && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("p", { children: [
|
|
1852
|
+
"\xA9 Copyright: ",
|
|
1853
|
+
metadata.copyright
|
|
1854
|
+
] }),
|
|
1855
|
+
metadata.ccli && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("p", { children: [
|
|
1856
|
+
"CCLI: ",
|
|
1857
|
+
metadata.ccli
|
|
1858
|
+
] })
|
|
1859
|
+
] }),
|
|
1860
|
+
fileName && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("p", { className: "mt-4 opacity-50", children: [
|
|
1861
|
+
"Ficheiro base: ",
|
|
1862
|
+
fileName
|
|
1863
|
+
] })
|
|
1864
|
+
] })
|
|
1865
|
+
] })
|
|
1866
|
+
}
|
|
1867
|
+
),
|
|
1868
|
+
metadata.youtube && showYoutubePlayer && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "hidden", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
1869
|
+
import_react_youtube.default,
|
|
1870
|
+
{
|
|
1871
|
+
videoId: extractYoutubeId(metadata.youtube),
|
|
1872
|
+
opts: {
|
|
1873
|
+
height: "0",
|
|
1874
|
+
width: "0",
|
|
1875
|
+
playerVars: { autoplay: 1, controls: 0, disablekb: 1 }
|
|
1876
|
+
},
|
|
1877
|
+
onReady: (e) => {
|
|
1878
|
+
setYtPlayerRef(e.target);
|
|
1879
|
+
e.target.pauseVideo();
|
|
1880
|
+
setIsPlayingYoutube(false);
|
|
1881
|
+
},
|
|
1882
|
+
onPlay: () => setIsPlayingYoutube(true),
|
|
1883
|
+
onPause: () => setIsPlayingYoutube(false),
|
|
1884
|
+
onEnd: (e) => {
|
|
1885
|
+
if (isYoutubeRepeatRef.current) {
|
|
1886
|
+
e.target.seekTo(0, true);
|
|
1887
|
+
e.target.playVideo();
|
|
1888
|
+
} else {
|
|
1889
|
+
setIsPlayingYoutube(false);
|
|
1890
|
+
}
|
|
1891
|
+
}
|
|
1892
|
+
}
|
|
1893
|
+
) }),
|
|
1894
|
+
showYoutubePlayer && metadata.youtube && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("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: [
|
|
1895
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "flex items-center gap-3", children: [
|
|
1896
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("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__ */ (0, import_jsx_runtime2.jsx)(
|
|
1897
|
+
"img",
|
|
1898
|
+
{
|
|
1899
|
+
src: `https://img.youtube.com/vi/${extractYoutubeId(metadata.youtube)}/default.jpg`,
|
|
1900
|
+
alt: "YouTube Thumbnail",
|
|
1901
|
+
className: "w-full h-full object-cover scale-150"
|
|
1902
|
+
}
|
|
1903
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_lucide_react.Disc, { className: "w-5 h-5 m-auto mt-2.5 text-m3-secondary opacity-50" }) }),
|
|
1904
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "hidden sm:block", children: [
|
|
1905
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "text-[10px] font-black text-m3-text dark:text-m3-dark-text truncate max-w-[120px]", children: metadata.title }),
|
|
1906
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "text-[9px] text-m3-secondary font-medium", children: "\xC1udio do YouTube" })
|
|
1907
|
+
] })
|
|
1908
|
+
] }),
|
|
1909
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "flex items-center gap-4", children: [
|
|
1910
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
1911
|
+
"button",
|
|
1912
|
+
{
|
|
1913
|
+
onClick: async () => {
|
|
1914
|
+
if (!ytPlayerRef) return;
|
|
1915
|
+
const t = await ytPlayerRef.getCurrentTime();
|
|
1916
|
+
ytPlayerRef.seekTo(Math.max(0, t - 10), true);
|
|
1917
|
+
},
|
|
1918
|
+
className: "text-m3-secondary hover:text-m3-primary transition-colors active:scale-95",
|
|
1919
|
+
title: "Retroceder 10s",
|
|
1920
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_lucide_react.SkipBack, { className: "w-4 h-4" })
|
|
1921
|
+
}
|
|
1922
|
+
),
|
|
1923
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
1924
|
+
"button",
|
|
1925
|
+
{
|
|
1926
|
+
onClick: () => {
|
|
1927
|
+
if (!ytPlayerRef) return;
|
|
1928
|
+
if (isPlayingYoutube) ytPlayerRef.pauseVideo();
|
|
1929
|
+
else ytPlayerRef.playVideo();
|
|
1930
|
+
},
|
|
1931
|
+
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",
|
|
1932
|
+
children: isPlayingYoutube ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_lucide_react.Pause, { className: "w-5 h-5" }) : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_lucide_react.Play, { className: "w-5 h-5 ml-1" })
|
|
1933
|
+
}
|
|
1934
|
+
),
|
|
1935
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
1936
|
+
"button",
|
|
1937
|
+
{
|
|
1938
|
+
onClick: async () => {
|
|
1939
|
+
if (!ytPlayerRef) return;
|
|
1940
|
+
const t = await ytPlayerRef.getCurrentTime();
|
|
1941
|
+
ytPlayerRef.seekTo(t + 10, true);
|
|
1942
|
+
},
|
|
1943
|
+
className: "text-m3-secondary hover:text-m3-primary transition-colors active:scale-95",
|
|
1944
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_lucide_react.SkipForward, { className: "w-4 h-4" })
|
|
1945
|
+
}
|
|
1946
|
+
),
|
|
1947
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
1948
|
+
"button",
|
|
1949
|
+
{
|
|
1950
|
+
onClick: () => setIsYoutubeRepeat((r) => !r),
|
|
1951
|
+
className: `ml-2 transition-colors active:scale-95 ${isYoutubeRepeat ? "text-m3-primary" : "text-m3-secondary hover:text-m3-text"}`,
|
|
1952
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_lucide_react.Repeat, { className: "w-4 h-4" })
|
|
1953
|
+
}
|
|
1954
|
+
)
|
|
1955
|
+
] }),
|
|
1956
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "flex items-center gap-2", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
1957
|
+
"button",
|
|
1958
|
+
{
|
|
1959
|
+
onClick: () => {
|
|
1960
|
+
ytPlayerRef?.pauseVideo();
|
|
1961
|
+
setIsPlayingYoutube(false);
|
|
1962
|
+
setShowYoutubePlayer(false);
|
|
1963
|
+
},
|
|
1964
|
+
className: "p-2 text-m3-secondary hover:text-red-500 transition-colors",
|
|
1965
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_lucide_react.X, { className: "w-4 h-4" })
|
|
1966
|
+
}
|
|
1967
|
+
) })
|
|
1968
|
+
] }),
|
|
1969
|
+
selectedChord && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("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__ */ (0, import_jsx_runtime2.jsxs)("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: [
|
|
1970
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "flex items-center justify-between", children: [
|
|
1971
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "flex items-center gap-2", children: [
|
|
1972
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_lucide_react.BookOpen, { className: "w-5 h-5 text-m3-primary dark:text-m3-dark-primary" }),
|
|
1973
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("h3", { className: "text-sm font-black text-m3-text dark:text-m3-dark-text uppercase tracking-wider", children: [
|
|
1974
|
+
"Dicion\xE1rio: ",
|
|
1975
|
+
selectedChord
|
|
1976
|
+
] })
|
|
1977
|
+
] }),
|
|
1978
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
1979
|
+
"button",
|
|
1980
|
+
{
|
|
1981
|
+
onClick: () => setSelectedChord(null),
|
|
1982
|
+
className: "p-1 rounded-full hover:bg-m3-hover dark:hover:bg-m3-dark-hover text-m3-secondary dark:text-m3-dark-secondary",
|
|
1983
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_lucide_react.X, { className: "w-5 h-5" })
|
|
1984
|
+
}
|
|
1985
|
+
)
|
|
1986
|
+
] }),
|
|
1987
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("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: [
|
|
1988
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
1989
|
+
"button",
|
|
1990
|
+
{
|
|
1991
|
+
onClick: () => setModalInstrument("guitar"),
|
|
1992
|
+
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"}`,
|
|
1993
|
+
children: "Diagrama de Guitarra"
|
|
1994
|
+
}
|
|
1995
|
+
),
|
|
1996
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
1997
|
+
"button",
|
|
1998
|
+
{
|
|
1999
|
+
onClick: () => setModalInstrument("piano"),
|
|
2000
|
+
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"}`,
|
|
2001
|
+
children: "Teclado de Piano"
|
|
2002
|
+
}
|
|
2003
|
+
)
|
|
2004
|
+
] }),
|
|
2005
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("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__ */ (0, import_jsx_runtime2.jsx)(
|
|
2006
|
+
GuitarDiagram,
|
|
2007
|
+
{
|
|
2008
|
+
frets: chordFingering.guitar.frets,
|
|
2009
|
+
fingers: chordFingering.guitar.fingers,
|
|
2010
|
+
barre: chordFingering.guitar.barre
|
|
2011
|
+
}
|
|
2012
|
+
) : modalInstrument === "piano" && chordFingering.piano ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
2013
|
+
PianoDiagram,
|
|
2014
|
+
{
|
|
2015
|
+
highlightKeys: chordFingering.piano.highlightKeys
|
|
2016
|
+
}
|
|
2017
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "text-center p-4", children: [
|
|
2018
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_lucide_react.HelpCircle, { className: "w-8 h-8 mx-auto text-amber-500 opacity-80 mb-2" }),
|
|
2019
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("p", { className: "text-xs text-m3-secondary dark:text-m3-dark-secondary font-medium", children: [
|
|
2020
|
+
"O diagrama para",
|
|
2021
|
+
" ",
|
|
2022
|
+
modalInstrument === "guitar" ? "Guitarra" : "Piano",
|
|
2023
|
+
" ",
|
|
2024
|
+
"n\xE3o p\xF4de ser calculado."
|
|
2025
|
+
] })
|
|
2026
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "text-center p-6 space-y-2", children: [
|
|
2027
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_lucide_react.HelpCircle, { className: "w-8 h-8 mx-auto text-amber-500 opacity-80" }),
|
|
2028
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("p", { className: "text-xs text-m3-text dark:text-m3-dark-text font-bold", children: [
|
|
2029
|
+
'Acorde "',
|
|
2030
|
+
selectedChord,
|
|
2031
|
+
'" n\xE3o registado'
|
|
2032
|
+
] }),
|
|
2033
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("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." })
|
|
2034
|
+
] }) }),
|
|
2035
|
+
chordFingering?.piano && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("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: [
|
|
2036
|
+
"Notas do Acorde:",
|
|
2037
|
+
" ",
|
|
2038
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "font-bold text-m3-primary dark:text-m3-dark-primary", children: chordFingering.piano.notes.join(" - ") })
|
|
2039
|
+
] }),
|
|
2040
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
2041
|
+
"button",
|
|
2042
|
+
{
|
|
2043
|
+
onClick: () => setSelectedChord(null),
|
|
2044
|
+
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",
|
|
2045
|
+
children: "Voltar ao C\xE2ntico"
|
|
2046
|
+
}
|
|
2047
|
+
)
|
|
2048
|
+
] }) })
|
|
2049
|
+
] });
|
|
2050
|
+
}
|
|
2051
|
+
);
|
|
2052
|
+
var LineRenderer = import_react2.default.memo(
|
|
2053
|
+
({
|
|
2054
|
+
line,
|
|
2055
|
+
showChords,
|
|
2056
|
+
transpose = 0,
|
|
2057
|
+
onChordClick,
|
|
2058
|
+
maxGridMeasures
|
|
2059
|
+
}) => {
|
|
2060
|
+
if (line.type === "empty") return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "h-2" });
|
|
2061
|
+
if (line.type === "comment") return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(CommentRenderer, { line });
|
|
2062
|
+
if (line.type === "comment_box") return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(CommentBoxRenderer, { line });
|
|
2063
|
+
if (line.type === "chord-section")
|
|
2064
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
2065
|
+
ChordSectionRenderer,
|
|
2066
|
+
{
|
|
2067
|
+
line,
|
|
2068
|
+
showChords,
|
|
2069
|
+
transpose,
|
|
2070
|
+
onChordClick,
|
|
2071
|
+
maxMeasures: maxGridMeasures
|
|
2072
|
+
}
|
|
2073
|
+
);
|
|
2074
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
2075
|
+
LyricsRenderer,
|
|
2076
|
+
{
|
|
2077
|
+
line,
|
|
2078
|
+
showChords,
|
|
2079
|
+
transpose,
|
|
2080
|
+
onChordClick
|
|
2081
|
+
}
|
|
2082
|
+
);
|
|
2083
|
+
}
|
|
2084
|
+
);
|
|
2085
|
+
var CommentRenderer = import_react2.default.memo(({ line }) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "text-xs text-slate-400 dark:text-slate-500 italic my-1", children: line.text }));
|
|
2086
|
+
var CommentBoxRenderer = import_react2.default.memo(({ line }) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("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: [
|
|
2087
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_lucide_react.Info, { className: "w-4 h-4 shrink-0 text-amber-600 dark:text-amber-500" }),
|
|
2088
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { children: line.text })
|
|
2089
|
+
] }));
|
|
2090
|
+
var LyricsRenderer = import_react2.default.memo(
|
|
2091
|
+
({
|
|
2092
|
+
line,
|
|
2093
|
+
showChords,
|
|
2094
|
+
transpose = 0,
|
|
2095
|
+
onChordClick
|
|
2096
|
+
}) => {
|
|
2097
|
+
const segments = line.segments || [];
|
|
2098
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "flex flex-wrap items-end leading-relaxed", children: segments.map((seg, segIdx) => {
|
|
2099
|
+
const hasChord = !!seg.chord;
|
|
2100
|
+
const transposed = hasChord ? transposeChord(seg.chord, transpose) : "";
|
|
2101
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
2102
|
+
"div",
|
|
2103
|
+
{
|
|
2104
|
+
className: "flex flex-col justify-end relative select-text",
|
|
2105
|
+
style: {
|
|
2106
|
+
minWidth: hasChord && showChords ? `${Math.max(1.1, transposed.length * 0.65)}em` : void 0
|
|
2107
|
+
},
|
|
2108
|
+
children: [
|
|
2109
|
+
showChords && hasChord && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
2110
|
+
"span",
|
|
2111
|
+
{
|
|
2112
|
+
className: "font-black text-[#0284c7] font-mono select-none pr-1 inline-block pb-0.5 transition-all cursor-pointer hover:opacity-80",
|
|
2113
|
+
style: { fontSize: "0.85em", lineHeight: "1" },
|
|
2114
|
+
onClick: () => onChordClick?.(transposed),
|
|
2115
|
+
children: transposed
|
|
2116
|
+
}
|
|
2117
|
+
),
|
|
2118
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "text-slate-800 dark:text-slate-200 whitespace-pre", children: seg.text || "\xA0" })
|
|
2119
|
+
]
|
|
2120
|
+
},
|
|
2121
|
+
segIdx
|
|
2122
|
+
);
|
|
2123
|
+
}) });
|
|
2124
|
+
}
|
|
2125
|
+
);
|
|
2126
|
+
var ChordSectionRenderer = import_react2.default.memo(
|
|
2127
|
+
({
|
|
2128
|
+
line,
|
|
2129
|
+
showChords,
|
|
2130
|
+
transpose = 0,
|
|
2131
|
+
onChordClick,
|
|
2132
|
+
maxMeasures
|
|
2133
|
+
}) => {
|
|
2134
|
+
if (!showChords) return null;
|
|
2135
|
+
const measures = line.measures || [];
|
|
2136
|
+
const hasTiming = measures.some(
|
|
2137
|
+
(m) => m.chords.some((c) => c.timing !== void 0 && c.timing !== 1)
|
|
2138
|
+
);
|
|
2139
|
+
const isGridAligned = maxMeasures !== void 0 && maxMeasures > 0;
|
|
2140
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("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: [
|
|
2141
|
+
line.startBarline && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "flex items-center justify-center shrink-0 w-6", children: renderBarline(line.startBarline) }),
|
|
2142
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
2143
|
+
"div",
|
|
2144
|
+
{
|
|
2145
|
+
className: isGridAligned ? "grid gap-1 flex-1" : "flex flex-wrap flex-1",
|
|
2146
|
+
style: isGridAligned ? {
|
|
2147
|
+
gridTemplateColumns: `repeat(${maxMeasures}, minmax(0, 1fr))`
|
|
2148
|
+
} : void 0,
|
|
2149
|
+
children: [
|
|
2150
|
+
measures.map((measure, mIdx) => {
|
|
2151
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
2152
|
+
"div",
|
|
2153
|
+
{
|
|
2154
|
+
className: `flex items-stretch border-r border-slate-200/60 dark:border-slate-700/50 last:border-none ${isGridAligned ? "" : "flex-1 min-w-[120px]"}`,
|
|
2155
|
+
children: [
|
|
2156
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "flex-1 flex items-center justify-evenly gap-1 px-1 py-1", children: measure.chords.map((chordSeg, cIdx) => {
|
|
2157
|
+
const transposed = transposeChord(
|
|
2158
|
+
chordSeg.chord,
|
|
2159
|
+
transpose
|
|
2160
|
+
);
|
|
2161
|
+
const timing = chordSeg.timing ?? 1;
|
|
2162
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
2163
|
+
"span",
|
|
2164
|
+
{
|
|
2165
|
+
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",
|
|
2166
|
+
style: { flexGrow: timing },
|
|
2167
|
+
onClick: () => onChordClick?.(transposed),
|
|
2168
|
+
title: timing !== 1 ? `Dura\xE7\xE3o: ${timing}x` : void 0,
|
|
2169
|
+
children: [
|
|
2170
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "font-bold text-[#0284c7] dark:text-sky-400 font-mono select-none text-[15px] tracking-wide", children: transposed }),
|
|
2171
|
+
hasTiming && timing !== 1 && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { className: "ml-0.5 mt-0.5 text-[10px] font-semibold text-indigo-400 dark:text-indigo-500 opacity-80", children: [
|
|
2172
|
+
timing,
|
|
2173
|
+
"\xD7"
|
|
2174
|
+
] })
|
|
2175
|
+
]
|
|
2176
|
+
},
|
|
2177
|
+
cIdx
|
|
2178
|
+
);
|
|
2179
|
+
}) }),
|
|
2180
|
+
measure.endBarline && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("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) })
|
|
2181
|
+
]
|
|
2182
|
+
},
|
|
2183
|
+
mIdx
|
|
2184
|
+
);
|
|
2185
|
+
}),
|
|
2186
|
+
isGridAligned && Array.from({
|
|
2187
|
+
length: Math.max(0, maxMeasures - measures.length)
|
|
2188
|
+
}).map((_, i) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
2189
|
+
"div",
|
|
2190
|
+
{
|
|
2191
|
+
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"
|
|
2192
|
+
},
|
|
2193
|
+
`empty-${i}`
|
|
2194
|
+
))
|
|
2195
|
+
]
|
|
2196
|
+
}
|
|
2197
|
+
)
|
|
2198
|
+
] });
|
|
2199
|
+
}
|
|
2200
|
+
);
|
|
2201
|
+
function renderBarline(barline) {
|
|
2202
|
+
const wrapperStyle = "flex items-center justify-center flex-shrink-0 select-none";
|
|
2203
|
+
const repeatStyle = "text-indigo-400 dark:text-indigo-500 text-[18px] leading-none";
|
|
2204
|
+
const normalStyle = "text-slate-300 dark:text-slate-600 font-black text-[16px] leading-none";
|
|
2205
|
+
switch (barline) {
|
|
2206
|
+
case "|:":
|
|
2207
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: wrapperStyle, title: "Start repeat", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: repeatStyle, children: "\u{1D106}" }) });
|
|
2208
|
+
case ":|":
|
|
2209
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: wrapperStyle, title: "End repeat", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: repeatStyle, children: "\u{1D107}" }) });
|
|
2210
|
+
case "||":
|
|
2211
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: wrapperStyle, title: "Double barline", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: normalStyle, children: "\u2016" }) });
|
|
2212
|
+
case "|]":
|
|
2213
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: wrapperStyle, title: "End of piece", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: normalStyle, children: "\u{1D102}" }) });
|
|
2214
|
+
case "|":
|
|
2215
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: wrapperStyle, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: normalStyle, children: "|" }) });
|
|
2216
|
+
default:
|
|
2217
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
2218
|
+
"span",
|
|
2219
|
+
{
|
|
2220
|
+
className: `${wrapperStyle} text-slate-400 dark:text-slate-500 text-xs font-bold tracking-widest`,
|
|
2221
|
+
children: barline
|
|
2222
|
+
}
|
|
2223
|
+
);
|
|
2224
|
+
}
|
|
2225
|
+
}
|
|
2226
|
+
var ChordProRenderer_default = ChordProRenderer;
|
|
2227
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
2228
|
+
0 && (module.exports = {
|
|
2229
|
+
ChordProRenderer,
|
|
2230
|
+
ChordRoll,
|
|
2231
|
+
GuitarDiagram,
|
|
2232
|
+
PianoDiagram
|
|
2233
|
+
});
|
|
2234
|
+
/**
|
|
2235
|
+
* @license
|
|
2236
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
2237
|
+
*/
|