@behindthemusictree/app-kit-ui 39.0.0 → 40.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/dist/{chunk-2K2SQOUJ.js → chunk-DPYUE6WD.js} +379 -411
- package/dist/chunk-DPYUE6WD.js.map +1 -0
- package/dist/genre-tree/index.cjs +461 -494
- package/dist/genre-tree/index.cjs.map +1 -1
- package/dist/genre-tree/index.d.ts +12 -5
- package/dist/genre-tree/index.js +1 -1
- package/dist/index.cjs +456 -489
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +1 -1
- package/package.json +6 -6
- package/dist/chunk-2K2SQOUJ.js.map +0 -1
|
@@ -50,12 +50,12 @@ module.exports = __toCommonJS(genre_tree_exports);
|
|
|
50
50
|
// src/genre-tree/GenreTreeView.tsx
|
|
51
51
|
var import_react19 = require("react");
|
|
52
52
|
var import_react_query3 = require("@tanstack/react-query");
|
|
53
|
+
var import_lucide_react13 = require("lucide-react");
|
|
53
54
|
var import_lucide_react14 = require("lucide-react");
|
|
54
|
-
var import_lucide_react15 = require("lucide-react");
|
|
55
55
|
var import_ui21 = require("@behindthemusictree/ui");
|
|
56
56
|
var import_genre_tree_view5 = require("@behindthemusictree/genre-tree-view");
|
|
57
57
|
var import_genre_tree30 = require("@behindthemusictree/app-kit/genre-tree");
|
|
58
|
-
var
|
|
58
|
+
var import_popup4 = require("@behindthemusictree/app-kit/popup");
|
|
59
59
|
|
|
60
60
|
// src/genre-tree/playlist-tree/size-metric.ts
|
|
61
61
|
var import_genre_tree = require("@behindthemusictree/app-kit/genre-tree");
|
|
@@ -69,7 +69,7 @@ var genrePlaylistSize = (genrePlaylist, metric) => {
|
|
|
69
69
|
};
|
|
70
70
|
|
|
71
71
|
// src/genre-tree/playlist-tree/toTreeNodes.ts
|
|
72
|
-
function toTreeNodes(genrePlaylists, sizeMetric) {
|
|
72
|
+
function toTreeNodes(genrePlaylists, sizeMetric, focusUuids) {
|
|
73
73
|
return genrePlaylists.map((genrePlaylist) => ({
|
|
74
74
|
id: genrePlaylist.uuid,
|
|
75
75
|
parentId: genrePlaylist.parent?.uuid ?? null,
|
|
@@ -80,16 +80,37 @@ function toTreeNodes(genrePlaylists, sizeMetric) {
|
|
|
80
80
|
side: genrePlaylist.criteria?.side ?? void 0,
|
|
81
81
|
wikidataId: genrePlaylist.criteria?.wikidataId ?? null,
|
|
82
82
|
umbrella: genrePlaylist.isUmbrella,
|
|
83
|
-
scene: genrePlaylist.scene ?? void 0
|
|
83
|
+
scene: genrePlaylist.scene ?? void 0,
|
|
84
|
+
muted: focusUuids ? !focusUuids.has(genrePlaylist.uuid) : void 0
|
|
84
85
|
}));
|
|
85
86
|
}
|
|
86
87
|
|
|
88
|
+
// src/genre-tree/playlist-tree/toGenreNodeStyles.ts
|
|
89
|
+
function toGenreNodeStyles(relations, genrePlaylists) {
|
|
90
|
+
const styles = /* @__PURE__ */ new Map();
|
|
91
|
+
if (!relations) return styles;
|
|
92
|
+
const genreUuidByPlaylistUuid = new Map(
|
|
93
|
+
genrePlaylists.flatMap((genrePlaylist) => genrePlaylist.criteria ? [[genrePlaylist.uuid, genrePlaylist.criteria.uuid]] : [])
|
|
94
|
+
);
|
|
95
|
+
const drawn = [relations, relations.parentNode, ...relations.childNodes, ...relations.ancestorNodes];
|
|
96
|
+
for (const entry of drawn) {
|
|
97
|
+
const genreUuid = entry && genreUuidByPlaylistUuid.get(entry.node.id);
|
|
98
|
+
if (entry && genreUuid) styles.set(genreUuid, { fill: entry.fill, textColor: entry.textColor });
|
|
99
|
+
}
|
|
100
|
+
return styles;
|
|
101
|
+
}
|
|
102
|
+
|
|
87
103
|
// src/genre-tree/playlist-tree/TreePerRoot.tsx
|
|
88
104
|
var import_genre_tree3 = require("@behindthemusictree/app-kit/genre-tree");
|
|
89
105
|
var import_react3 = require("react");
|
|
90
106
|
var import_genre_tree_view = require("@behindthemusictree/genre-tree-view");
|
|
91
107
|
var import_player = require("@behindthemusictree/app-kit/player");
|
|
108
|
+
|
|
109
|
+
// src/genre-tree/playlist-tree/useGenrePlaylistPlayback.tsx
|
|
110
|
+
var import_react2 = require("react");
|
|
111
|
+
var import_genre_tree2 = require("@behindthemusictree/app-kit/genre-tree");
|
|
92
112
|
var import_popup = require("@behindthemusictree/app-kit/popup");
|
|
113
|
+
var import_transport = require("@behindthemusictree/app-kit/transport");
|
|
93
114
|
|
|
94
115
|
// src/popup/InternalErrorPopup.tsx
|
|
95
116
|
var import_lucide_react2 = require("lucide-react");
|
|
@@ -305,18 +326,15 @@ function InternalErrorPopup({ errorCode, contactEmail, ...rest }) {
|
|
|
305
326
|
);
|
|
306
327
|
}
|
|
307
328
|
|
|
308
|
-
// src/genre-tree/playlist-tree/
|
|
309
|
-
var
|
|
310
|
-
|
|
311
|
-
// src/genre-tree/playlist-tree/useGenrePlaylistPlayback.ts
|
|
312
|
-
var import_react2 = require("react");
|
|
313
|
-
var import_genre_tree2 = require("@behindthemusictree/app-kit/genre-tree");
|
|
329
|
+
// src/genre-tree/playlist-tree/useGenrePlaylistPlayback.tsx
|
|
330
|
+
var import_jsx_runtime5 = require("react/jsx-runtime");
|
|
314
331
|
function useGenrePlaylistPlayback({
|
|
315
332
|
scope,
|
|
316
333
|
genrePlaylists,
|
|
317
334
|
artist = null
|
|
318
335
|
}) {
|
|
319
336
|
const { trackList, playNewTrackListFromGenrePlaylist } = (0, import_genre_tree2.useTrackList)();
|
|
337
|
+
const { showPopup } = (0, import_popup.usePopup)();
|
|
320
338
|
const origin = trackList?.origin;
|
|
321
339
|
const playing = (0, import_react2.useMemo)(() => {
|
|
322
340
|
if (!origin || origin.type !== import_genre_tree2.TrackListOriginType.GENRE_PLAYLIST || origin.scope !== scope) return null;
|
|
@@ -328,14 +346,20 @@ function useGenrePlaylistPlayback({
|
|
|
328
346
|
}, [origin, artist, genrePlaylists, scope]);
|
|
329
347
|
const play = (0, import_react2.useCallback)(async (playlist, requested) => {
|
|
330
348
|
if (artist && !playlist.criteria) return;
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
349
|
+
try {
|
|
350
|
+
const selection = scope === "reference" && playlist.criteria !== null ? requested ?? (0, import_genre_tree2.defaultGenreMusicSelection)(import_genre_tree2.GenreCatalogueCountsSchema.parse(playlist)) : void 0;
|
|
351
|
+
await (selection || artist ? playNewTrackListFromGenrePlaylist(playlist, scope, { selection, ...artist && { artistUuid: artist.uuid } }) : playNewTrackListFromGenrePlaylist(playlist, scope));
|
|
352
|
+
} catch (error) {
|
|
353
|
+
console.error("Failed to load genre playlist tracks:", error);
|
|
354
|
+
if (error instanceof import_genre_tree2.TracksFailureAlreadyReportedError) return;
|
|
355
|
+
showPopup(/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(InternalErrorPopup, { errorCode: error instanceof import_transport.AppError ? error.code : import_transport.ErrorCode.CLIENT_UNKNOWN }));
|
|
356
|
+
}
|
|
357
|
+
}, [artist, scope, playNewTrackListFromGenrePlaylist, showPopup]);
|
|
334
358
|
return (0, import_react2.useMemo)(() => ({ playing, play }), [playing, play]);
|
|
335
359
|
}
|
|
336
360
|
|
|
337
361
|
// src/genre-tree/playlist-tree/TreePerRoot.tsx
|
|
338
|
-
var
|
|
362
|
+
var import_jsx_runtime6 = require("react/jsx-runtime");
|
|
339
363
|
function GenrePlaylistTreePerRoot({
|
|
340
364
|
scope,
|
|
341
365
|
className: className2,
|
|
@@ -354,25 +378,16 @@ function GenrePlaylistTreePerRoot({
|
|
|
354
378
|
viewportRestore,
|
|
355
379
|
onViewportChange,
|
|
356
380
|
playback,
|
|
381
|
+
focusUuids,
|
|
357
382
|
...hostPanel
|
|
358
383
|
}) {
|
|
359
384
|
const { isPlaying, setIsPlaying } = (0, import_player.usePlayer)();
|
|
360
385
|
const defaultPlayback = useGenrePlaylistPlayback({ scope, genrePlaylists: genrePlaylistTreePerRoot });
|
|
361
386
|
const { playing, play } = playback ?? defaultPlayback;
|
|
362
387
|
const playingNodeId = playing?.uuid ?? null;
|
|
363
|
-
const { showPopup } = (0, import_popup.usePopup)();
|
|
364
388
|
const nodes = (0, import_react3.useMemo)(
|
|
365
|
-
() => genrePlaylistTreePerRoot
|
|
366
|
-
|
|
367
|
-
parentId: genrePlaylist.parent?.uuid ?? null,
|
|
368
|
-
name: genrePlaylist.name,
|
|
369
|
-
itemCount: (0, import_genre_tree3.genrePlaylistTrackCount)(genrePlaylist),
|
|
370
|
-
actionable: Boolean(genrePlaylist.criteria),
|
|
371
|
-
side: genrePlaylist.criteria?.side ?? void 0,
|
|
372
|
-
wikidataId: genrePlaylist.criteria?.wikidataId ?? null,
|
|
373
|
-
umbrella: genrePlaylist.isUmbrella
|
|
374
|
-
})),
|
|
375
|
-
[genrePlaylistTreePerRoot]
|
|
389
|
+
() => toTreeNodes(genrePlaylistTreePerRoot, "songs", focusUuids),
|
|
390
|
+
[genrePlaylistTreePerRoot, focusUuids]
|
|
376
391
|
);
|
|
377
392
|
const handlePlayPause = (0, import_react3.useCallback)(
|
|
378
393
|
(nodeId) => {
|
|
@@ -385,18 +400,14 @@ function GenrePlaylistTreePerRoot({
|
|
|
385
400
|
if ((0, import_genre_tree3.genrePlaylistTrackCount)(genrePlaylist) === 0) {
|
|
386
401
|
return;
|
|
387
402
|
}
|
|
388
|
-
play(genrePlaylist)
|
|
389
|
-
console.error("Failed to load genre playlist tracks:", error);
|
|
390
|
-
showPopup(/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(InternalErrorPopup, { errorCode: import_transport.ErrorCode.CLIENT_UNKNOWN }));
|
|
391
|
-
});
|
|
403
|
+
void play(genrePlaylist);
|
|
392
404
|
},
|
|
393
405
|
[
|
|
394
406
|
genrePlaylistTreePerRoot,
|
|
395
407
|
playingNodeId,
|
|
396
408
|
isPlaying,
|
|
397
409
|
setIsPlaying,
|
|
398
|
-
play
|
|
399
|
-
showPopup
|
|
410
|
+
play
|
|
400
411
|
]
|
|
401
412
|
);
|
|
402
413
|
const handleAddChild = (0, import_react3.useCallback)(
|
|
@@ -419,7 +430,7 @@ function GenrePlaylistTreePerRoot({
|
|
|
419
430
|
if (confirm(`Are you sure you want to delete "${node.name}"?`)) {
|
|
420
431
|
}
|
|
421
432
|
}, []);
|
|
422
|
-
return /* @__PURE__ */ (0,
|
|
433
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
423
434
|
import_genre_tree_view.GenreTree,
|
|
424
435
|
{
|
|
425
436
|
className: className2,
|
|
@@ -450,9 +461,7 @@ var import_genre_tree4 = require("@behindthemusictree/app-kit/genre-tree");
|
|
|
450
461
|
var import_react4 = require("react");
|
|
451
462
|
var import_genre_tree_view2 = require("@behindthemusictree/genre-tree-view");
|
|
452
463
|
var import_player2 = require("@behindthemusictree/app-kit/player");
|
|
453
|
-
var
|
|
454
|
-
var import_transport2 = require("@behindthemusictree/app-kit/transport");
|
|
455
|
-
var import_jsx_runtime6 = require("react/jsx-runtime");
|
|
464
|
+
var import_jsx_runtime7 = require("react/jsx-runtime");
|
|
456
465
|
function GenrePlaylistTreeWheel({
|
|
457
466
|
scope,
|
|
458
467
|
className: className2,
|
|
@@ -473,24 +482,16 @@ function GenrePlaylistTreeWheel({
|
|
|
473
482
|
viewportRestore,
|
|
474
483
|
onViewportChange,
|
|
475
484
|
playback,
|
|
485
|
+
focusUuids,
|
|
476
486
|
...hostPanel
|
|
477
487
|
}) {
|
|
478
488
|
const { isPlaying, setIsPlaying } = (0, import_player2.usePlayer)();
|
|
479
489
|
const defaultPlayback = useGenrePlaylistPlayback({ scope, genrePlaylists });
|
|
480
490
|
const { playing, play } = playback ?? defaultPlayback;
|
|
481
491
|
const playingNodeId = playing?.uuid ?? null;
|
|
482
|
-
const { showPopup } = (0, import_popup2.usePopup)();
|
|
483
492
|
const nodes = (0, import_react4.useMemo)(
|
|
484
|
-
() => genrePlaylists
|
|
485
|
-
|
|
486
|
-
parentId: genrePlaylist.parent?.uuid ?? null,
|
|
487
|
-
name: genrePlaylist.name,
|
|
488
|
-
itemCount: genrePlaylistSize(genrePlaylist, sizeMetric),
|
|
489
|
-
actionable: Boolean(genrePlaylist.criteria),
|
|
490
|
-
side: genrePlaylist.criteria?.side ?? void 0,
|
|
491
|
-
wikidataId: genrePlaylist.criteria?.wikidataId ?? null
|
|
492
|
-
})),
|
|
493
|
-
[genrePlaylists, sizeMetric]
|
|
493
|
+
() => toTreeNodes(genrePlaylists, sizeMetric, focusUuids),
|
|
494
|
+
[genrePlaylists, sizeMetric, focusUuids]
|
|
494
495
|
);
|
|
495
496
|
const handlePlayPause = (0, import_react4.useCallback)(
|
|
496
497
|
(nodeId) => {
|
|
@@ -503,18 +504,14 @@ function GenrePlaylistTreeWheel({
|
|
|
503
504
|
if ((0, import_genre_tree4.genrePlaylistTrackCount)(genrePlaylist) === 0) {
|
|
504
505
|
return;
|
|
505
506
|
}
|
|
506
|
-
play(genrePlaylist)
|
|
507
|
-
console.error("Failed to load genre playlist tracks:", error);
|
|
508
|
-
showPopup(/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(InternalErrorPopup, { errorCode: import_transport2.ErrorCode.CLIENT_UNKNOWN }));
|
|
509
|
-
});
|
|
507
|
+
void play(genrePlaylist);
|
|
510
508
|
},
|
|
511
509
|
[
|
|
512
510
|
genrePlaylists,
|
|
513
511
|
playingNodeId,
|
|
514
512
|
isPlaying,
|
|
515
513
|
setIsPlaying,
|
|
516
|
-
play
|
|
517
|
-
showPopup
|
|
514
|
+
play
|
|
518
515
|
]
|
|
519
516
|
);
|
|
520
517
|
const handleAddChild = (0, import_react4.useCallback)(
|
|
@@ -537,7 +534,7 @@ function GenrePlaylistTreeWheel({
|
|
|
537
534
|
if (confirm(`Are you sure you want to delete "${node.name}"?`)) {
|
|
538
535
|
}
|
|
539
536
|
}, []);
|
|
540
|
-
return /* @__PURE__ */ (0,
|
|
537
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
541
538
|
import_genre_tree_view2.GenreTreeWheel,
|
|
542
539
|
{
|
|
543
540
|
className: className2,
|
|
@@ -569,7 +566,7 @@ var import_genre_tree5 = require("@behindthemusictree/app-kit/genre-tree");
|
|
|
569
566
|
var import_react5 = require("react");
|
|
570
567
|
var import_genre_tree_view3 = require("@behindthemusictree/genre-tree-view");
|
|
571
568
|
var import_player3 = require("@behindthemusictree/app-kit/player");
|
|
572
|
-
var
|
|
569
|
+
var import_jsx_runtime8 = require("react/jsx-runtime");
|
|
573
570
|
function GenrePlaylistTreeWheelRadialPopCore(props) {
|
|
574
571
|
const {
|
|
575
572
|
scope,
|
|
@@ -602,7 +599,7 @@ function GenrePlaylistTreeWheelRadialPopCore(props) {
|
|
|
602
599
|
const defaultPlayback = useGenrePlaylistPlayback({ scope, genrePlaylists });
|
|
603
600
|
const { playing, play } = playback ?? defaultPlayback;
|
|
604
601
|
const playingNodeId = playing?.uuid ?? null;
|
|
605
|
-
const nodes = (0, import_react5.useMemo)(() => toTreeNodes(genrePlaylists, sizeMetric), [genrePlaylists, sizeMetric]);
|
|
602
|
+
const nodes = (0, import_react5.useMemo)(() => toTreeNodes(genrePlaylists, sizeMetric, props.focusUuids), [genrePlaylists, sizeMetric, props.focusUuids]);
|
|
606
603
|
const handlePlayPause = (0, import_react5.useCallback)(
|
|
607
604
|
(nodeId) => {
|
|
608
605
|
const genrePlaylist = genrePlaylists.find((g) => g.uuid === nodeId);
|
|
@@ -614,9 +611,7 @@ function GenrePlaylistTreeWheelRadialPopCore(props) {
|
|
|
614
611
|
if ((0, import_genre_tree5.genrePlaylistTrackCount)(genrePlaylist) === 0) {
|
|
615
612
|
return;
|
|
616
613
|
}
|
|
617
|
-
play(genrePlaylist)
|
|
618
|
-
console.error("Failed to load genre playlist tracks:", error);
|
|
619
|
-
});
|
|
614
|
+
void play(genrePlaylist);
|
|
620
615
|
},
|
|
621
616
|
[genrePlaylists, playingNodeId, isPlaying, setIsPlaying, play]
|
|
622
617
|
);
|
|
@@ -656,7 +651,7 @@ function GenrePlaylistTreeWheelRadialPopCore(props) {
|
|
|
656
651
|
onSelectedNodeChange,
|
|
657
652
|
...hostPanel
|
|
658
653
|
};
|
|
659
|
-
return outline ? /* @__PURE__ */ (0,
|
|
654
|
+
return outline ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_genre_tree_view3.GenreTreeOutline, { ...treeProps }) : /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
660
655
|
import_genre_tree_view3.GenreTreeWheelRadialPopCore,
|
|
661
656
|
{
|
|
662
657
|
...treeProps,
|
|
@@ -673,7 +668,7 @@ function GenrePlaylistTreeWheelRadialPopCore(props) {
|
|
|
673
668
|
|
|
674
669
|
// src/genre-tree/GenreTreeWheelHandoff.tsx
|
|
675
670
|
var import_react6 = require("react");
|
|
676
|
-
var
|
|
671
|
+
var import_jsx_runtime9 = require("react/jsx-runtime");
|
|
677
672
|
function GenreTreeWheelHandoff({ skeleton, children, onRevealedChange }) {
|
|
678
673
|
const [revealed, setRevealed] = (0, import_react6.useState)(false);
|
|
679
674
|
const onRevealedChangeRef = (0, import_react6.useRef)(onRevealedChange);
|
|
@@ -692,8 +687,8 @@ function GenreTreeWheelHandoff({ skeleton, children, onRevealedChange }) {
|
|
|
692
687
|
cancelAnimationFrame(innerFrame);
|
|
693
688
|
};
|
|
694
689
|
}, []);
|
|
695
|
-
return /* @__PURE__ */ (0,
|
|
696
|
-
/* @__PURE__ */ (0,
|
|
690
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "relative w-full h-full", children: [
|
|
691
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
697
692
|
"div",
|
|
698
693
|
{
|
|
699
694
|
className: "absolute inset-0 transition-opacity duration-150 ease-out",
|
|
@@ -702,7 +697,7 @@ function GenreTreeWheelHandoff({ skeleton, children, onRevealedChange }) {
|
|
|
702
697
|
children
|
|
703
698
|
}
|
|
704
699
|
),
|
|
705
|
-
!revealed && /* @__PURE__ */ (0,
|
|
700
|
+
!revealed && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "absolute inset-0", "aria-hidden": "true", children: skeleton })
|
|
706
701
|
] });
|
|
707
702
|
}
|
|
708
703
|
|
|
@@ -717,7 +712,7 @@ var import_genre_tree9 = require("@behindthemusictree/app-kit/genre-tree");
|
|
|
717
712
|
// src/genre-tree/search/SearchBox.tsx
|
|
718
713
|
var import_react7 = require("react");
|
|
719
714
|
var import_ui3 = require("@behindthemusictree/ui");
|
|
720
|
-
var
|
|
715
|
+
var import_jsx_runtime10 = require("react/jsx-runtime");
|
|
721
716
|
function SearchBox({
|
|
722
717
|
label,
|
|
723
718
|
placeholder,
|
|
@@ -739,7 +734,7 @@ function SearchBox({
|
|
|
739
734
|
groups.find((group) => group.key === groupKey)?.items.find((item) => item.key === itemKey)?.onSelect();
|
|
740
735
|
onPicked?.(groupKey, itemKey);
|
|
741
736
|
};
|
|
742
|
-
return /* @__PURE__ */ (0,
|
|
737
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: className2, onFocusCapture: onFocus, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
743
738
|
import_ui3.SearchCombobox,
|
|
744
739
|
{
|
|
745
740
|
ariaLabel: label,
|
|
@@ -771,7 +766,7 @@ var searchStatus = (state, count, noun) => state.isError ? SEARCH_FAILED_STATUS
|
|
|
771
766
|
|
|
772
767
|
// src/genre-tree/search/useArtistSearchGroup.tsx
|
|
773
768
|
var import_genre_tree6 = require("@behindthemusictree/app-kit/genre-tree");
|
|
774
|
-
var
|
|
769
|
+
var import_jsx_runtime11 = require("react/jsx-runtime");
|
|
775
770
|
function useArtistSearchGroup(getBaseUrl, text, onSelect, enabled = true) {
|
|
776
771
|
const search = (0, import_genre_tree6.useArtistSearch)(getBaseUrl, enabled ? text : "");
|
|
777
772
|
if (!enabled) return void 0;
|
|
@@ -780,15 +775,15 @@ function useArtistSearchGroup(getBaseUrl, text, onSelect, enabled = true) {
|
|
|
780
775
|
label: "Artists",
|
|
781
776
|
items: search.artists.map((artist) => ({
|
|
782
777
|
key: artist.uuid,
|
|
783
|
-
content: /* @__PURE__ */ (0,
|
|
784
|
-
/* @__PURE__ */ (0,
|
|
778
|
+
content: /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_jsx_runtime11.Fragment, { children: [
|
|
779
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("span", { className: "block truncate font-medium", children: [
|
|
785
780
|
artist.name,
|
|
786
|
-
artist.disambiguation && /* @__PURE__ */ (0,
|
|
781
|
+
artist.disambiguation && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("span", { className: "font-normal text-[var(--color-neutral-500)]", children: [
|
|
787
782
|
" \xB7 ",
|
|
788
783
|
artist.disambiguation
|
|
789
784
|
] })
|
|
790
785
|
] }),
|
|
791
|
-
artist.matchedAlias && /* @__PURE__ */ (0,
|
|
786
|
+
artist.matchedAlias && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("span", { className: "block truncate text-caption text-[var(--color-neutral-500)]", children: [
|
|
792
787
|
"also known as ",
|
|
793
788
|
artist.matchedAlias
|
|
794
789
|
] })
|
|
@@ -802,7 +797,7 @@ function useArtistSearchGroup(getBaseUrl, text, onSelect, enabled = true) {
|
|
|
802
797
|
|
|
803
798
|
// src/genre-tree/search/useSongSearchGroup.tsx
|
|
804
799
|
var import_genre_tree7 = require("@behindthemusictree/app-kit/genre-tree");
|
|
805
|
-
var
|
|
800
|
+
var import_jsx_runtime12 = require("react/jsx-runtime");
|
|
806
801
|
function useSongSearchGroup(getBaseUrl, text, onSelect, enabled = true) {
|
|
807
802
|
const search = (0, import_genre_tree7.useSongSearch)(getBaseUrl, enabled ? text : "");
|
|
808
803
|
if (!enabled) return void 0;
|
|
@@ -811,9 +806,9 @@ function useSongSearchGroup(getBaseUrl, text, onSelect, enabled = true) {
|
|
|
811
806
|
label: "Songs",
|
|
812
807
|
items: search.songs.map((song) => ({
|
|
813
808
|
key: song.uuid,
|
|
814
|
-
content: /* @__PURE__ */ (0,
|
|
815
|
-
/* @__PURE__ */ (0,
|
|
816
|
-
/* @__PURE__ */ (0,
|
|
809
|
+
content: /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("span", { className: (0, import_genre_tree7.isSongSearchResultPlayable)(song) ? void 0 : "opacity-60", children: [
|
|
810
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "block truncate font-medium", children: song.title }),
|
|
811
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "block truncate text-caption text-[var(--color-neutral-500)]", children: [song.artists.map((artist) => artist.name).join(", "), song.genre?.name ?? "No genre"].filter(Boolean).join(" \xB7 ") })
|
|
817
812
|
] }),
|
|
818
813
|
onSelect: () => onSelect(song)
|
|
819
814
|
})),
|
|
@@ -824,7 +819,7 @@ function useSongSearchGroup(getBaseUrl, text, onSelect, enabled = true) {
|
|
|
824
819
|
|
|
825
820
|
// src/genre-tree/search/useGenreRemoteSearchGroup.tsx
|
|
826
821
|
var import_genre_tree8 = require("@behindthemusictree/app-kit/genre-tree");
|
|
827
|
-
var
|
|
822
|
+
var import_jsx_runtime13 = require("react/jsx-runtime");
|
|
828
823
|
function useGenreRemoteSearchGroup(getBaseUrl, text, onSelect, { key = "genres", label = "Genres", filter, describe, ...options } = {}) {
|
|
829
824
|
const search = (0, import_genre_tree8.useGenreRemoteSearch)(getBaseUrl, text, options);
|
|
830
825
|
const genres = filter ? search.genres.filter(filter) : search.genres;
|
|
@@ -833,12 +828,12 @@ function useGenreRemoteSearchGroup(getBaseUrl, text, onSelect, { key = "genres",
|
|
|
833
828
|
label,
|
|
834
829
|
items: genres.map((genre) => ({
|
|
835
830
|
key: genre.uuid,
|
|
836
|
-
content: /* @__PURE__ */ (0,
|
|
837
|
-
/* @__PURE__ */ (0,
|
|
831
|
+
content: /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_jsx_runtime13.Fragment, { children: [
|
|
832
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("span", { className: "block truncate font-medium", children: [
|
|
838
833
|
genre.name,
|
|
839
|
-
genre.isUmbrella && /* @__PURE__ */ (0,
|
|
834
|
+
genre.isUmbrella && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "ml-2 text-caption font-normal italic text-[var(--color-text-muted)]", children: "umbrella" })
|
|
840
835
|
] }),
|
|
841
|
-
/* @__PURE__ */ (0,
|
|
836
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "block truncate text-caption text-[var(--color-neutral-500)]", children: describe?.(genre) ?? `${genre.treeName} \xB7 ${genre.root.name}` })
|
|
842
837
|
] }),
|
|
843
838
|
onSelect: () => onSelect(genre)
|
|
844
839
|
})),
|
|
@@ -848,7 +843,7 @@ function useGenreRemoteSearchGroup(getBaseUrl, text, onSelect, { key = "genres",
|
|
|
848
843
|
}
|
|
849
844
|
|
|
850
845
|
// src/genre-tree/GenreSearch.tsx
|
|
851
|
-
var
|
|
846
|
+
var import_jsx_runtime14 = require("react/jsx-runtime");
|
|
852
847
|
function GenreSearch({
|
|
853
848
|
genrePlaylists,
|
|
854
849
|
onSelect,
|
|
@@ -877,9 +872,9 @@ function GenreSearch({
|
|
|
877
872
|
label: hasExtras ? "Genres" : void 0,
|
|
878
873
|
items: results.map((genrePlaylist) => ({
|
|
879
874
|
key: genrePlaylist.uuid,
|
|
880
|
-
content: /* @__PURE__ */ (0,
|
|
875
|
+
content: /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_jsx_runtime14.Fragment, { children: [
|
|
881
876
|
genrePlaylist.name,
|
|
882
|
-
genrePlaylist.isUmbrella && /* @__PURE__ */ (0,
|
|
877
|
+
genrePlaylist.isUmbrella && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "ml-2 text-caption italic text-[var(--color-text-muted)]", children: "umbrella" })
|
|
883
878
|
] }),
|
|
884
879
|
onSelect: () => select(genrePlaylist)
|
|
885
880
|
}))
|
|
@@ -888,7 +883,7 @@ function GenreSearch({
|
|
|
888
883
|
(group) => active ? group : { ...group, items: [], status: "", loading: false }
|
|
889
884
|
)
|
|
890
885
|
];
|
|
891
|
-
return /* @__PURE__ */ (0,
|
|
886
|
+
return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: "genre-search w-[calc(var(--layout-detail-panel-w,25.5rem)-2*var(--layout-panel-inset,1rem))] shrink-0 max-md:w-full", children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
892
887
|
SearchBox,
|
|
893
888
|
{
|
|
894
889
|
label,
|
|
@@ -908,14 +903,14 @@ function GenreSearch({
|
|
|
908
903
|
clear();
|
|
909
904
|
onQueryChange?.("");
|
|
910
905
|
} : void 0,
|
|
911
|
-
leading: onPrevious && /* @__PURE__ */ (0,
|
|
906
|
+
leading: onPrevious && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("button", { type: "button", "aria-label": "Previous", title: "Previous", className: import_ui4.SEARCH_LEADING_BUTTON_CLASS, onClick: onPrevious, children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_lucide_react3.ArrowLeft, { "aria-hidden": "true", className: "h-4 w-4" }) }),
|
|
912
907
|
onFocus
|
|
913
908
|
}
|
|
914
909
|
) });
|
|
915
910
|
}
|
|
916
911
|
|
|
917
912
|
// src/genre-tree/GenreTreeSearch.tsx
|
|
918
|
-
var
|
|
913
|
+
var import_jsx_runtime15 = require("react/jsx-runtime");
|
|
919
914
|
function GenreTreeSearch({
|
|
920
915
|
artistBaseUrl,
|
|
921
916
|
songBaseUrl,
|
|
@@ -935,7 +930,7 @@ function GenreTreeSearch({
|
|
|
935
930
|
const deferredQuery = (0, import_react8.useDeferredValue)(query);
|
|
936
931
|
const artistGroup = useArtistSearchGroup(artistBaseUrl, deferredQuery, onArtistSelect, artistSearch);
|
|
937
932
|
const songGroup = useSongSearchGroup(songBaseUrl, deferredQuery, onSongSelect, songSearch);
|
|
938
|
-
const render = (hostGroups) => /* @__PURE__ */ (0,
|
|
933
|
+
const render = (hostGroups) => /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
939
934
|
GenreSearch,
|
|
940
935
|
{
|
|
941
936
|
...props,
|
|
@@ -950,7 +945,7 @@ function GenreTreeSearch({
|
|
|
950
945
|
extraGroups: [...extraGroups, ...hostGroups, artistGroup, songGroup].filter((group) => group !== void 0)
|
|
951
946
|
}
|
|
952
947
|
);
|
|
953
|
-
return SearchGroups ? /* @__PURE__ */ (0,
|
|
948
|
+
return SearchGroups ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(SearchGroups, { query: deferredQuery, focused, onSelectGenre, children: render }) : render([]);
|
|
954
949
|
}
|
|
955
950
|
|
|
956
951
|
// src/genre-tree/GenreDetailPanel.tsx
|
|
@@ -970,7 +965,7 @@ var import_ui6 = require("@behindthemusictree/ui");
|
|
|
970
965
|
// src/genre-tree/ShareActionButton.tsx
|
|
971
966
|
var import_lucide_react6 = require("lucide-react");
|
|
972
967
|
var import_ui5 = require("@behindthemusictree/ui");
|
|
973
|
-
var
|
|
968
|
+
var import_popup2 = require("@behindthemusictree/app-kit/popup");
|
|
974
969
|
|
|
975
970
|
// src/genre-tree/SharePopup.tsx
|
|
976
971
|
var import_react10 = require("react");
|
|
@@ -981,7 +976,7 @@ var import_si = require("react-icons/si");
|
|
|
981
976
|
// src/popup/Toast.tsx
|
|
982
977
|
var import_react9 = require("react");
|
|
983
978
|
var import_react_dom2 = require("react-dom");
|
|
984
|
-
var
|
|
979
|
+
var import_jsx_runtime16 = require("react/jsx-runtime");
|
|
985
980
|
function Toast({ message, onClose, durationMs = 2200 }) {
|
|
986
981
|
const [mounted, setMounted] = (0, import_react9.useState)(false);
|
|
987
982
|
(0, import_react9.useEffect)(() => {
|
|
@@ -991,7 +986,7 @@ function Toast({ message, onClose, durationMs = 2200 }) {
|
|
|
991
986
|
}, [durationMs, onClose]);
|
|
992
987
|
if (!mounted) return null;
|
|
993
988
|
return (0, import_react_dom2.createPortal)(
|
|
994
|
-
/* @__PURE__ */ (0,
|
|
989
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { className: "pointer-events-none fixed inset-x-0 bottom-8 z-[60] flex justify-center px-4", children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
995
990
|
"div",
|
|
996
991
|
{
|
|
997
992
|
role: "status",
|
|
@@ -1006,12 +1001,12 @@ function Toast({ message, onClose, durationMs = 2200 }) {
|
|
|
1006
1001
|
}
|
|
1007
1002
|
|
|
1008
1003
|
// src/genre-tree/ShareDestinationButton.tsx
|
|
1009
|
-
var
|
|
1004
|
+
var import_jsx_runtime17 = require("react/jsx-runtime");
|
|
1010
1005
|
var className = "group flex min-w-0 flex-1 flex-col items-center justify-center gap-1.5 rounded-xl px-2 py-2 text-caption text-[var(--color-text)] transition-colors hover:bg-[var(--color-surface-muted)] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-focus-ring)] disabled:cursor-not-allowed disabled:opacity-50";
|
|
1011
1006
|
function Contents({ icon, label }) {
|
|
1012
|
-
return /* @__PURE__ */ (0,
|
|
1013
|
-
/* @__PURE__ */ (0,
|
|
1014
|
-
/* @__PURE__ */ (0,
|
|
1007
|
+
return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(import_jsx_runtime17.Fragment, { children: [
|
|
1008
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "flex h-12 w-12 items-center justify-center rounded-full bg-[var(--color-surface-muted)] transition-colors group-hover:bg-[var(--color-border)]", children: icon }),
|
|
1009
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "max-w-full truncate", children: label })
|
|
1015
1010
|
] });
|
|
1016
1011
|
}
|
|
1017
1012
|
function ShareDestinationButton({
|
|
@@ -1023,29 +1018,29 @@ function ShareDestinationButton({
|
|
|
1023
1018
|
ariaLabel
|
|
1024
1019
|
}) {
|
|
1025
1020
|
if (href) {
|
|
1026
|
-
return /* @__PURE__ */ (0,
|
|
1021
|
+
return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("a", { href, target: "_blank", rel: "noopener noreferrer", "aria-label": ariaLabel, className, children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Contents, { icon, label }) });
|
|
1027
1022
|
}
|
|
1028
|
-
return /* @__PURE__ */ (0,
|
|
1023
|
+
return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("button", { type: "button", onClick, disabled, "aria-label": ariaLabel, className, children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Contents, { icon, label }) });
|
|
1029
1024
|
}
|
|
1030
1025
|
|
|
1031
1026
|
// src/genre-tree/SharePreviewCard.tsx
|
|
1032
1027
|
var import_lucide_react4 = require("lucide-react");
|
|
1033
|
-
var
|
|
1028
|
+
var import_jsx_runtime18 = require("react/jsx-runtime");
|
|
1034
1029
|
function SharePreviewCard({ target, url }) {
|
|
1035
1030
|
const Icon = { genre: import_lucide_react4.Music2, artist: import_lucide_react4.UserRound, song: import_lucide_react4.Music }[target.kind];
|
|
1036
1031
|
const typeLabel = { genre: "Genre", artist: "Artist", song: "Song" }[target.kind];
|
|
1037
|
-
return /* @__PURE__ */ (0,
|
|
1038
|
-
/* @__PURE__ */ (0,
|
|
1039
|
-
/* @__PURE__ */ (0,
|
|
1040
|
-
/* @__PURE__ */ (0,
|
|
1041
|
-
/* @__PURE__ */ (0,
|
|
1042
|
-
/* @__PURE__ */ (0,
|
|
1032
|
+
return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: "rounded-3xl bg-[var(--color-surface-muted)] p-4", children: /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "flex min-h-32 overflow-hidden rounded-2xl bg-[var(--color-surface)] shadow-lg", children: [
|
|
1033
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: "flex w-28 shrink-0 items-center justify-center bg-[var(--color-primary)]/15 text-[var(--color-primary)]", children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Icon, { "aria-hidden": "true", className: "h-10 w-10" }) }),
|
|
1034
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "flex min-w-0 flex-1 flex-col justify-center gap-1 p-4", children: [
|
|
1035
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "text-caption font-medium uppercase tracking-wide text-[var(--color-text-muted)]", children: typeLabel }),
|
|
1036
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "truncate text-base font-semibold text-[var(--color-text)]", title: target.name, children: target.name }),
|
|
1037
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "truncate text-body text-[var(--color-primary)]", title: url, children: url })
|
|
1043
1038
|
] })
|
|
1044
1039
|
] }) });
|
|
1045
1040
|
}
|
|
1046
1041
|
|
|
1047
1042
|
// src/genre-tree/SharePopup.tsx
|
|
1048
|
-
var
|
|
1043
|
+
var import_jsx_runtime19 = require("react/jsx-runtime");
|
|
1049
1044
|
function resolveAbsoluteUrl(url) {
|
|
1050
1045
|
try {
|
|
1051
1046
|
const parsed = new URL(url, window.location.href);
|
|
@@ -1120,8 +1115,8 @@ function SharePopup({ target, url, onClose }) {
|
|
|
1120
1115
|
setShareError("Could not open the share options.");
|
|
1121
1116
|
}
|
|
1122
1117
|
};
|
|
1123
|
-
return /* @__PURE__ */ (0,
|
|
1124
|
-
/* @__PURE__ */ (0,
|
|
1118
|
+
return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(import_jsx_runtime19.Fragment, { children: [
|
|
1119
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
1125
1120
|
BasePopup_default,
|
|
1126
1121
|
{
|
|
1127
1122
|
title: "Share",
|
|
@@ -1136,70 +1131,70 @@ function SharePopup({ target, url, onClose }) {
|
|
|
1136
1131
|
titleTextClassName: "!text-xl !font-semibold !text-[var(--color-text)]",
|
|
1137
1132
|
closeButtonClassName: "!h-10 !w-10 !rounded-none !border-0 !bg-transparent !p-0 !text-[var(--color-text)] hover:!bg-transparent hover:!text-[var(--color-text)]",
|
|
1138
1133
|
contentClassName: "!rounded-none !bg-transparent !px-6 !pb-6 !pt-2",
|
|
1139
|
-
children: /* @__PURE__ */ (0,
|
|
1140
|
-
/* @__PURE__ */ (0,
|
|
1141
|
-
/* @__PURE__ */ (0,
|
|
1142
|
-
/* @__PURE__ */ (0,
|
|
1134
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "flex flex-col gap-4", children: [
|
|
1135
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(SharePreviewCard, { target, url: absoluteUrl || url }),
|
|
1136
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "grid grid-cols-3 gap-1 rounded-3xl bg-[var(--color-surface)] p-3 sm:grid-cols-4", children: [
|
|
1137
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
1143
1138
|
ShareDestinationButton,
|
|
1144
1139
|
{
|
|
1145
1140
|
label: "Copy Link",
|
|
1146
|
-
icon: /* @__PURE__ */ (0,
|
|
1141
|
+
icon: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_lucide_react5.Link2, { "aria-hidden": "true", className: "h-6 w-6" }),
|
|
1147
1142
|
onClick: () => void handleCopy(),
|
|
1148
1143
|
ariaLabel: "Copy link",
|
|
1149
1144
|
disabled: !absoluteUrl
|
|
1150
1145
|
}
|
|
1151
1146
|
),
|
|
1152
|
-
/* @__PURE__ */ (0,
|
|
1147
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
1153
1148
|
ShareDestinationButton,
|
|
1154
1149
|
{
|
|
1155
1150
|
label: "WhatsApp",
|
|
1156
|
-
icon: /* @__PURE__ */ (0,
|
|
1151
|
+
icon: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_fa.FaWhatsapp, { "aria-hidden": "true", className: "h-9 w-9 text-[#25D366]" }),
|
|
1157
1152
|
href: destinationUrls?.whatsapp,
|
|
1158
1153
|
ariaLabel: `Share ${target.name} via WhatsApp`,
|
|
1159
1154
|
disabled: !absoluteUrl
|
|
1160
1155
|
}
|
|
1161
1156
|
),
|
|
1162
|
-
/* @__PURE__ */ (0,
|
|
1157
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
1163
1158
|
ShareDestinationButton,
|
|
1164
1159
|
{
|
|
1165
1160
|
label: "Gmail",
|
|
1166
|
-
icon: /* @__PURE__ */ (0,
|
|
1161
|
+
icon: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_si.SiGmail, { "aria-hidden": "true", className: "h-8 w-8 text-[#EA4335]" }),
|
|
1167
1162
|
href: destinationUrls?.gmail,
|
|
1168
1163
|
ariaLabel: `Email ${target.name} with Gmail`,
|
|
1169
1164
|
disabled: !absoluteUrl
|
|
1170
1165
|
}
|
|
1171
1166
|
),
|
|
1172
|
-
canUseNativeShare && /* @__PURE__ */ (0,
|
|
1167
|
+
canUseNativeShare && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
1173
1168
|
ShareDestinationButton,
|
|
1174
1169
|
{
|
|
1175
1170
|
label: "More",
|
|
1176
|
-
icon: /* @__PURE__ */ (0,
|
|
1171
|
+
icon: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_lucide_react5.Share2, { "aria-hidden": "true", className: "h-6 w-6" }),
|
|
1177
1172
|
onClick: () => void handleNativeShare(),
|
|
1178
1173
|
ariaLabel: "More sharing options",
|
|
1179
1174
|
disabled: !absoluteUrl
|
|
1180
1175
|
}
|
|
1181
1176
|
)
|
|
1182
1177
|
] }),
|
|
1183
|
-
copyStatus === "failed" && /* @__PURE__ */ (0,
|
|
1184
|
-
shareError && /* @__PURE__ */ (0,
|
|
1178
|
+
copyStatus === "failed" && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("p", { role: "alert", className: "text-center text-body text-[var(--color-red-500)]", children: "Could not copy the link." }),
|
|
1179
|
+
shareError && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("p", { role: "alert", className: "text-center text-body text-[var(--color-red-500)]", children: shareError })
|
|
1185
1180
|
] })
|
|
1186
1181
|
}
|
|
1187
1182
|
),
|
|
1188
|
-
toastId > 0 && /* @__PURE__ */ (0,
|
|
1183
|
+
toastId > 0 && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(Toast, { message: "Link copied", onClose: dismissToast }, toastId)
|
|
1189
1184
|
] });
|
|
1190
1185
|
}
|
|
1191
1186
|
|
|
1192
1187
|
// src/genre-tree/ShareActionButton.tsx
|
|
1193
|
-
var
|
|
1188
|
+
var import_jsx_runtime20 = require("react/jsx-runtime");
|
|
1194
1189
|
function ShareActionButton({ target, url }) {
|
|
1195
|
-
const { showPopup, hidePopup } = (0,
|
|
1190
|
+
const { showPopup, hidePopup } = (0, import_popup2.usePopup)();
|
|
1196
1191
|
const openSharePopup = () => {
|
|
1197
|
-
showPopup(/* @__PURE__ */ (0,
|
|
1192
|
+
showPopup(/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(SharePopup, { target, url, onClose: hidePopup }));
|
|
1198
1193
|
};
|
|
1199
|
-
return /* @__PURE__ */ (0,
|
|
1194
|
+
return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
1200
1195
|
import_ui5.ActionButton,
|
|
1201
1196
|
{
|
|
1202
|
-
icon: /* @__PURE__ */ (0,
|
|
1197
|
+
icon: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_lucide_react6.Share2, { "aria-hidden": "true", className: "w-5 h-5" }),
|
|
1203
1198
|
label: "Share",
|
|
1204
1199
|
"aria-label": `Share ${target.name}`,
|
|
1205
1200
|
title: `Share ${target.name}`,
|
|
@@ -1209,7 +1204,7 @@ function ShareActionButton({ target, url }) {
|
|
|
1209
1204
|
}
|
|
1210
1205
|
|
|
1211
1206
|
// src/genre-tree/GenreActionBand.tsx
|
|
1212
|
-
var
|
|
1207
|
+
var import_jsx_runtime21 = require("react/jsx-runtime");
|
|
1213
1208
|
function GenreActionBand({
|
|
1214
1209
|
node,
|
|
1215
1210
|
playActions,
|
|
@@ -1230,24 +1225,24 @@ function GenreActionBand({
|
|
|
1230
1225
|
items.push({
|
|
1231
1226
|
key: "zoom-in",
|
|
1232
1227
|
label: "Focus",
|
|
1233
|
-
icon: /* @__PURE__ */ (0,
|
|
1228
|
+
icon: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_lucide_react7.ZoomIn, { "aria-hidden": "true", className: "w-5 h-5" }),
|
|
1234
1229
|
onClick: onZoomIn
|
|
1235
1230
|
});
|
|
1236
1231
|
}
|
|
1237
1232
|
if (onAddChild) {
|
|
1238
|
-
adminItems.push({ key: "add-child", label: "Add", icon: /* @__PURE__ */ (0,
|
|
1233
|
+
adminItems.push({ key: "add-child", label: "Add", icon: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_lucide_react7.Plus, { "aria-hidden": "true", className: "w-5 h-5" }), onClick: onAddChild });
|
|
1239
1234
|
}
|
|
1240
1235
|
if (onRename) {
|
|
1241
|
-
adminItems.push({ key: "rename", label: "Rename", icon: /* @__PURE__ */ (0,
|
|
1236
|
+
adminItems.push({ key: "rename", label: "Rename", icon: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_lucide_react7.Pencil, { "aria-hidden": "true", className: "w-5 h-5" }), onClick: onRename });
|
|
1242
1237
|
}
|
|
1243
1238
|
if (onChangeParent) {
|
|
1244
|
-
adminItems.push({ key: "change-parent", label: "Parent", icon: /* @__PURE__ */ (0,
|
|
1239
|
+
adminItems.push({ key: "change-parent", label: "Parent", icon: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_lucide_react7.MoveUpRight, { "aria-hidden": "true", className: "w-5 h-5" }), onClick: onChangeParent });
|
|
1245
1240
|
}
|
|
1246
1241
|
if (onToggleSide) {
|
|
1247
1242
|
adminItems.push({
|
|
1248
1243
|
key: "toggle-side",
|
|
1249
1244
|
label: side === "pop" ? "Make core" : "Make pop",
|
|
1250
|
-
icon: /* @__PURE__ */ (0,
|
|
1245
|
+
icon: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_lucide_react7.ArrowLeftRight, { "aria-hidden": "true", className: "w-5 h-5" }),
|
|
1251
1246
|
onClick: onToggleSide,
|
|
1252
1247
|
disabled: !!toggleSideDisabledReason,
|
|
1253
1248
|
title: toggleSideDisabledReason
|
|
@@ -1262,9 +1257,9 @@ function GenreActionBand({
|
|
|
1262
1257
|
disabled: action.enabled ? !action.enabled(node) : false
|
|
1263
1258
|
});
|
|
1264
1259
|
}
|
|
1265
|
-
const renderItems = (list) => list.map((item) => /* @__PURE__ */ (0,
|
|
1260
|
+
const renderItems = (list) => list.map((item) => /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_ui6.ActionButton, { icon: item.icon, label: item.label, disabled: item.disabled, title: item.title, onClick: item.onClick }, item.key));
|
|
1266
1261
|
if (!playActions && items.length === 0 && adminItems.length === 0 && !(shareTarget && shareUrl)) return null;
|
|
1267
|
-
return /* @__PURE__ */ (0,
|
|
1262
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_ui6.PanelBleed, { children: /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
|
|
1268
1263
|
import_ui6.ActionBand,
|
|
1269
1264
|
{
|
|
1270
1265
|
className: "genre-action-band",
|
|
@@ -1272,7 +1267,7 @@ function GenreActionBand({
|
|
|
1272
1267
|
children: [
|
|
1273
1268
|
playActions,
|
|
1274
1269
|
renderItems(items),
|
|
1275
|
-
shareTarget && shareUrl && /* @__PURE__ */ (0,
|
|
1270
|
+
shareTarget && shareUrl && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ShareActionButton, { target: shareTarget, url: shareUrl })
|
|
1276
1271
|
]
|
|
1277
1272
|
}
|
|
1278
1273
|
) });
|
|
@@ -1296,7 +1291,7 @@ var REGION_GLOBE_PATHS = {
|
|
|
1296
1291
|
var REGION_GLOBES = ["africa", "americas", "asia"];
|
|
1297
1292
|
|
|
1298
1293
|
// src/genre-tree/RegionGlobeIcon.tsx
|
|
1299
|
-
var
|
|
1294
|
+
var import_jsx_runtime22 = require("react/jsx-runtime");
|
|
1300
1295
|
var ROTATION_INTERVAL_MS = 3e3;
|
|
1301
1296
|
function RegionGlobeIcon({ className: className2 }) {
|
|
1302
1297
|
const [index, setIndex] = (0, import_react11.useState)(0);
|
|
@@ -1314,29 +1309,29 @@ function RegionGlobeIcon({ className: className2 }) {
|
|
|
1314
1309
|
clearInterval(timer);
|
|
1315
1310
|
};
|
|
1316
1311
|
}, []);
|
|
1317
|
-
return /* @__PURE__ */ (0,
|
|
1312
|
+
return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("svg", { viewBox: "0 0 512 512", fill: "currentColor", className: className2, "aria-hidden": true, children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("path", { "data-testid": "region-globe-path", d: REGION_GLOBE_PATHS[REGION_GLOBES[index]] }) });
|
|
1318
1313
|
}
|
|
1319
1314
|
|
|
1320
1315
|
// src/genre-tree/treeMarkPath.ts
|
|
1321
1316
|
var TREE_MARK_PATH = "M3171 5598 c-5 -13 -5 -24 0 -26 5 -2 9 -16 9 -31 0 -25 -3 -28 -25 -23 l-25 4 0 -116 c0 -64 3 -116 8 -116 10 0 32 51 26 61 -3 5 -1 9 4 9 5 0 15 12 21 28 7 15 26 36 43 47 30 20 88 105 71 105 -4 0 -33 -21 -62 -47 l-54 -47 6 63 c4 35 7 72 7 82 0 10 9 19 23 22 16 3 13 5 -11 6 -25 1 -35 -4 -41 -21z M2893 5485 c8 -76 24 -100 71 -100 l36 0 0 53 c0 58 -15 69 -28 20 -8 -29 -10 -30 -16 -13 -15 43 -42 89 -55 93 -11 4 -13 -6 -8 -53z M2484 5438 c8 -70 49 -169 54 -131 2 12 10 27 18 33 17 15 19 84 3 129 -9 27 -16 31 -46 31 l-36 0 7 -62z M2625 5448 c-7 -22 -24 -121 -31 -179 l-6 -57 -27 11 c-15 5 -32 19 -37 31 -9 21 -88 86 -105 86 -39 0 38 -104 118 -158 17 -12 56 -59 86 -105 30 -45 67 -92 81 -104 14 -13 26 -30 26 -38 0 -13 -9 -11 -45 11 -67 39 -58 10 21 -66 67 -65 96 -110 108 -167 4 -17 13 -34 20 -36 20 -8 66 -186 75 -289 13 -161 -8 -272 -72 -365 -12 -18 -30 -33 -39 -33 -23 0 -53 33 -79 89 -25 54 -69 112 -121 162 -35 33 -38 40 -38 92 0 58 36 172 79 252 25 47 29 125 6 125 -19 0 -30 -22 -50 -100 -9 -35 -24 -78 -32 -94 l-16 -30 -19 24 -20 25 7 -58 c8 -62 0 -127 -16 -127 -19 0 -122 107 -166 172 -52 79 -68 150 -60 273 8 108 17 129 67 149 58 23 97 64 105 109 9 47 -5 49 -63 6 l-42 -30 15 35 c17 41 20 102 5 111 -18 11 -45 -4 -64 -36 -11 -19 -20 -60 -23 -110 -4 -54 -10 -79 -18 -79 -20 0 -27 28 -30 108 -2 40 -6 76 -9 79 -3 4 -6 51 -6 105 0 86 -3 101 -21 119 -27 27 -42 20 -53 -24 -7 -28 -5 -51 7 -90 9 -30 17 -76 17 -103 l0 -49 -29 51 c-29 49 -92 114 -111 114 -6 0 -10 -11 -10 -25 0 -14 5 -25 10 -25 6 0 10 -6 10 -13 0 -7 23 -44 51 -82 61 -84 59 -82 52 -57 -3 14 2 24 15 31 12 6 23 23 25 38 2 16 5 2 6 -29 1 -46 -2 -58 -14 -58 -21 0 -19 -13 10 -70 22 -44 25 -61 25 -165 l0 -116 -47 27 c-65 36 -142 118 -176 187 -15 31 -37 62 -49 68 -21 11 -21 10 -15 -41 l6 -52 -29 6 c-37 7 -39 -7 -4 -31 14 -10 53 -40 86 -68 92 -76 130 -104 163 -119 39 -19 101 -84 109 -116 10 -42 50 -88 217 -245 50 -47 94 -102 134 -167 33 -54 65 -98 71 -98 17 0 45 -79 51 -145 4 -47 0 -76 -20 -135 -14 -41 -39 -121 -56 -177 -18 -57 -35 -103 -40 -103 -4 0 -26 13 -49 30 -31 22 -50 49 -82 117 -99 209 -116 241 -185 337 -123 172 -123 173 -128 311 -5 140 -29 245 -57 245 -12 0 -20 -11 -24 -31 -9 -46 -7 -108 3 -127 14 -26 25 -162 14 -162 -20 0 -160 99 -192 135 -19 22 -42 58 -52 80 -10 23 -27 52 -37 66 -10 13 -26 38 -34 54 -9 17 -23 45 -33 64 -15 29 -16 40 -6 80 31 116 34 139 27 205 -7 57 -11 69 -28 74 -14 3 -32 30 -54 79 -21 46 -39 73 -47 70 -13 -5 -14 -15 -3 -65 l8 -33 -49 25 c-61 31 -93 40 -93 27 0 -13 43 -41 122 -79 47 -22 72 -41 83 -61 19 -38 19 -51 0 -51 -12 0 -15 -15 -16 -72 -1 -79 -12 -134 -22 -108 -3 8 -10 48 -16 89 -14 89 -25 111 -54 111 -38 0 -50 -15 -45 -54 4 -40 2 -42 -26 -21 -29 22 -36 19 -36 -20 0 -39 39 -85 125 -145 38 -27 62 -56 99 -120 45 -79 82 -177 70 -189 -2 -3 -42 3 -87 13 -45 10 -99 21 -119 26 -47 9 -103 51 -125 93 -24 44 -83 203 -94 252 -5 25 -4 59 3 91 14 68 3 140 -23 155 -12 6 -23 8 -27 5 -14 -15 -13 -115 2 -159 39 -116 0 -116 -70 1 -22 36 -31 42 -59 42 -20 0 -35 6 -39 15 -6 16 -56 21 -56 6 0 -5 23 -25 51 -44 53 -36 158 -156 188 -216 10 -20 26 -60 36 -88 11 -29 25 -53 32 -53 8 0 13 -12 13 -30 0 -26 -4 -30 -27 -31 l-28 -1 25 -7 c26 -8 177 -87 196 -102 5 -4 50 -18 100 -29 122 -29 277 -78 300 -95 10 -8 26 -15 34 -15 35 0 160 -166 160 -212 0 -22 -32 -24 -50 -4 -11 14 -100 46 -165 61 -16 3 -68 25 -115 48 -102 49 -163 56 -168 19 -9 -62 58 -104 178 -112 63 -5 103 -14 155 -37 39 -16 91 -38 117 -47 26 -9 74 -35 106 -56 52 -33 65 -48 96 -112 20 -40 39 -95 43 -122 6 -47 6 -48 -18 -41 -33 10 -69 33 -69 45 0 6 -10 10 -23 10 -13 0 -27 4 -32 9 -6 5 -27 14 -47 20 -20 7 -53 23 -73 37 -43 29 -45 29 -45 7 0 -26 80 -96 145 -127 119 -56 274 -185 311 -259 55 -107 104 -410 104 -640 0 -162 -22 -325 -45 -333 -25 -10 -72 25 -168 123 -129 131 -140 148 -182 274 -20 60 -50 142 -66 181 -16 39 -45 131 -65 202 -24 93 -55 173 -104 274 -77 158 -78 166 -32 256 31 64 27 129 -12 181 -31 40 -39 42 -65 18 -51 -49 -55 -120 -11 -208 37 -74 37 -85 3 -85 -36 0 -94 65 -137 154 -18 39 -37 80 -40 92 -3 11 -14 29 -24 40 -10 10 -28 35 -42 54 -13 19 -40 55 -61 80 -20 25 -41 63 -47 85 -6 22 -16 62 -23 89 -20 81 -95 147 -113 100 -18 -47 -6 -92 39 -147 25 -31 45 -61 45 -67 0 -15 -42 -3 -116 31 -94 44 -156 124 -184 235 -9 36 -13 41 -38 40 -39 -2 -144 113 -186 205 -31 66 -33 68 -53 54 -11 -8 -24 -11 -27 -7 -4 4 11 -24 33 -62 39 -67 43 -86 18 -86 -8 0 -8 3 1 9 11 6 9 9 -7 14 -11 3 -25 -1 -31 -7 -7 -10 0 -16 29 -24 39 -12 203 -147 215 -178 13 -34 4 -35 -48 -6 -64 37 -126 51 -126 30 0 -26 55 -67 125 -92 46 -16 80 -36 100 -58 l29 -33 -54 -3 c-79 -5 -203 14 -249 38 -47 24 -70 54 -105 140 -43 105 -115 163 -103 83 3 -21 9 -47 13 -57 4 -11 -15 4 -42 32 -62 64 -84 67 -84 14 0 -41 24 -76 61 -87 16 -6 18 -9 8 -15 -23 -15 15 -45 117 -91 52 -24 93 -48 91 -54 -10 -28 -150 -28 -190 0 -21 15 -47 5 -47 -17 0 -5 -10 -19 -22 -29 -23 -20 -23 -20 112 -14 174 8 208 8 430 0 l185 -7 84 -41 c115 -57 180 -118 225 -212 20 -41 36 -77 36 -80 0 -14 89 -126 150 -190 74 -78 120 -144 120 -175 0 -30 10 -33 -201 52 -94 38 -131 71 -218 195 -27 37 -59 77 -71 88 l-23 20 7 -40 c4 -22 12 -44 17 -49 13 -14 11 -26 -4 -26 -7 0 -29 21 -48 48 -33 45 -34 51 -39 159 -4 89 -9 116 -22 130 -17 16 -18 16 -18 0 0 -9 -7 -17 -16 -17 -14 0 -16 -9 -11 -62 3 -35 8 -74 12 -88 l7 -25 -25 27 c-41 44 -127 118 -137 118 -18 0 -10 -57 12 -85 18 -24 20 -32 10 -57 -10 -28 -9 -30 22 -43 18 -8 54 -19 79 -26 36 -9 60 -24 99 -66 80 -83 80 -83 1 -83 -80 0 -176 21 -236 51 -107 54 -234 169 -252 228 -4 14 -12 29 -17 35 -5 6 -18 25 -28 43 -24 40 -90 64 -116 42 -22 -18 -13 -84 17 -116 13 -13 42 -32 64 -42 22 -10 74 -53 115 -96 l75 -77 -75 5 c-135 8 -243 76 -336 207 -31 44 -65 87 -77 95 -37 26 -34 -9 7 -88 20 -39 34 -72 31 -75 -2 -2 -26 11 -52 31 -90 65 -143 83 -143 49 0 -32 71 -88 150 -117 41 -15 113 -47 159 -71 46 -24 99 -46 118 -50 18 -3 33 -12 33 -18 0 -12 -111 -46 -149 -46 -12 0 -29 -8 -39 -17 -10 -10 -27 -19 -37 -19 -11 -1 -45 -9 -75 -17 -58 -16 -110 -62 -110 -97 0 -39 116 -45 167 -9 11 8 34 31 52 51 28 32 50 43 144 74 145 47 222 48 404 5 70 -17 177 -38 237 -47 128 -19 202 -43 250 -79 18 -14 73 -42 122 -61 164 -66 208 -112 243 -251 36 -141 27 -167 -44 -123 -19 12 -63 23 -111 28 -117 13 -134 25 -275 193 -63 74 -193 151 -266 157 -29 2 -66 -1 -81 -7 -24 -10 -37 -9 -80 8 -66 26 -70 9 -11 -44 72 -65 119 -80 239 -78 60 1 109 -2 117 -8 6 -6 26 -35 42 -64 17 -30 46 -64 64 -77 19 -13 49 -40 67 -61 l34 -39 -79 3 c-57 3 -80 0 -83 -9 -3 -10 -7 -10 -18 -1 -8 6 -11 15 -8 20 3 5 0 9 -5 9 -16 0 -13 -16 6 -36 36 -36 78 -44 227 -44 119 0 152 -3 188 -19 56 -24 95 -64 125 -126 13 -27 35 -68 48 -90 14 -22 25 -53 25 -69 l0 -29 -107 5 c-131 6 -193 28 -290 100 -37 28 -82 56 -98 63 -75 32 -176 123 -277 247 -34 42 -122 98 -134 85 -5 -5 103 -138 184 -226 52 -57 46 -61 -49 -31 -87 28 -173 85 -325 214 -144 123 -189 151 -254 159 -25 2 -39 3 -32 0 6 -3 12 -16 12 -29 0 -17 -4 -23 -12 -19 -7 4 -1 -5 15 -19 15 -14 46 -30 70 -36 23 -6 60 -17 82 -25 l40 -13 -52 -1 c-49 -1 -53 -3 -53 -25 0 -28 28 -36 122 -36 54 0 62 -3 91 -32 l32 -33 -52 -3 c-88 -5 -75 -26 39 -62 130 -41 178 -63 206 -93 l22 -24 -20 -18 c-12 -11 -41 -20 -74 -23 -48 -4 -60 0 -116 32 -118 69 -241 96 -279 62 -13 -12 -40 -16 -104 -16 -48 0 -95 4 -105 9 -9 5 -34 16 -55 25 -20 9 -76 53 -122 97 -47 45 -88 79 -91 76 -12 -12 6 -54 41 -100 l36 -47 -74 0 c-88 0 -112 15 -78 49 26 26 21 39 -34 84 -87 73 -132 32 -50 -45 25 -23 45 -46 45 -50 0 -4 -21 2 -46 12 -45 20 -114 27 -114 12 0 -4 16 -22 35 -40 39 -38 78 -47 255 -61 164 -14 178 -17 172 -47 -2 -13 -2 -30 2 -39 5 -13 9 -13 40 2 19 9 33 20 30 25 -4 5 4 4 15 -4 21 -13 20 -15 -44 -74 -36 -33 -65 -66 -65 -72 0 -21 68 15 142 74 38 30 84 62 103 70 73 30 203 11 312 -46 32 -17 82 -33 111 -37 l53 -6 -28 -30 c-15 -16 -44 -40 -63 -52 -63 -42 -100 -82 -100 -111 0 -25 2 -26 37 -21 28 5 47 17 73 49 65 78 175 183 224 216 34 22 61 32 88 32 43 0 122 -36 152 -69 10 -11 39 -32 62 -46 43 -25 53 -46 36 -72 -11 -17 -200 -86 -232 -85 -28 1 -122 -47 -127 -65 -3 -8 14 -13 54 -15 l58 -3 -65 -44 c-36 -25 -68 -49 -71 -53 -11 -17 -115 -10 -188 12 -105 32 -112 11 -14 -39 l56 -28 -40 -6 c-52 -9 -96 0 -154 29 -31 15 -50 19 -60 13 -15 -10 -16 -10 44 -47 20 -13 37 -27 37 -31 0 -15 -144 -71 -205 -81 -33 -5 -85 -10 -116 -10 -32 0 -63 -6 -75 -14 -18 -13 -15 -15 34 -22 l53 -7 -31 -18 c-18 -12 -30 -27 -30 -40 0 -21 4 -21 61 -16 50 4 75 14 145 57 46 28 112 63 146 77 62 24 191 62 215 63 22 0 -47 -103 -107 -161 -42 -41 -60 -66 -65 -92 -10 -49 0 -60 47 -54 65 9 99 53 124 160 20 83 49 133 94 163 22 15 40 30 40 34 0 4 8 10 18 13 9 3 31 15 49 27 31 21 31 21 26 0 -3 -11 -21 -37 -40 -58 -43 -45 -72 -106 -73 -150 0 -39 18 -49 56 -30 38 18 63 64 75 137 13 82 40 142 89 194 22 24 40 49 40 54 0 6 24 21 53 34 49 22 63 23 237 20 193 -2 278 -14 348 -50 21 -11 44 -27 52 -36 7 -9 32 -27 55 -41 49 -28 138 -147 184 -243 16 -35 42 -114 57 -175 35 -147 31 -268 -14 -436 -17 -63 -37 -166 -45 -227 -12 -94 -21 -127 -54 -195 -22 -46 -52 -94 -67 -108 -15 -14 -46 -44 -68 -67 -23 -24 -47 -43 -53 -43 -7 0 -25 -12 -41 -26 -129 -121 -526 -267 -721 -268 -104 0 -109 -15 -19 -57 75 -35 67 -35 221 -10 125 21 235 27 235 13 0 -16 -66 -72 -85 -72 -24 0 -85 -36 -85 -49 0 -14 12 -19 58 -27 35 -5 42 -4 42 10 0 9 5 17 10 17 28 4 74 20 80 29 9 14 226 119 288 139 63 21 215 43 239 34 32 -12 12 -50 -52 -102 -36 -28 -73 -55 -83 -58 -17 -7 -66 -39 -92 -60 -8 -7 -38 -32 -67 -57 l-52 -45 42 -6 c36 -6 54 -1 122 33 44 22 120 56 169 76 112 45 222 107 289 164 46 40 84 62 107 62 18 0 130 -83 130 -96 0 -8 4 -14 10 -14 5 0 39 -26 75 -59 36 -32 96 -76 132 -97 36 -21 68 -46 71 -56 5 -19 21 -22 59 -12 18 5 20 9 10 19 -7 7 -69 71 -139 143 -147 149 -161 179 -80 168 136 -19 195 -39 378 -128 78 -37 147 -68 152 -68 6 0 15 -7 20 -16 8 -14 14 -15 46 -4 l38 12 -104 57 c-125 69 -148 84 -148 93 0 16 94 7 223 -22 74 -17 146 -30 160 -30 14 0 29 -4 32 -10 7 -11 54 6 115 43 l40 24 -38 1 c-22 1 -68 11 -103 21 -35 11 -107 30 -159 41 -131 31 -295 99 -406 171 -235 153 -355 366 -357 634 -1 211 65 343 285 568 117 119 206 167 368 198 153 29 267 59 328 86 80 35 166 44 264 27 148 -26 167 -38 251 -169 71 -110 136 -165 196 -165 26 0 31 4 31 23 -1 32 -28 62 -87 91 -39 20 -66 45 -118 112 -95 123 -95 135 -5 92 25 -12 77 -31 116 -43 56 -17 76 -19 97 -10 27 11 26 11 -25 29 -113 39 -138 49 -138 57 0 14 91 55 153 68 33 7 75 10 95 7 27 -4 31 -3 17 4 -19 8 -19 9 3 9 12 1 22 7 22 15 0 10 7 12 22 8 12 -3 17 -7 10 -10 -6 -2 -12 -10 -12 -18 0 -8 -6 -14 -12 -15 -27 -2 39 -17 80 -18 29 -1 42 3 42 13 0 20 -19 32 -67 45 -49 13 -53 22 -20 44 49 32 128 39 235 21 56 -9 112 -14 126 -10 26 6 96 69 96 86 0 6 -32 10 -77 10 -84 0 -126 -7 -118 -20 9 -14 -17 -24 -67 -24 -34 -1 -48 3 -48 13 0 8 -7 11 -20 8 -17 -4 -18 -2 -9 14 5 11 14 17 20 14 5 -4 9 0 9 8 0 8 16 35 35 60 35 45 35 46 14 57 -18 10 -23 8 -37 -12 -67 -95 -162 -167 -297 -225 -55 -23 -99 -47 -98 -53 2 -5 -6 -10 -18 -10 -27 0 -23 8 31 71 100 117 116 131 161 155 80 40 80 70 1 41 l-47 -18 36 38 c47 49 59 73 59 120 0 67 -24 80 -82 46 -49 -29 -76 -85 -89 -183 -10 -81 -9 -80 -89 -174 -20 -22 -43 -53 -53 -68 -28 -45 -89 -61 -217 -56 -70 2 -114 8 -118 15 -4 6 -28 13 -54 15 l-46 3 53 71 c51 68 100 104 140 104 50 0 125 73 125 122 0 30 0 31 -45 26 -28 -4 -59 -16 -82 -34 -30 -23 -35 -24 -28 -8 22 51 37 105 31 111 -13 13 -47 -34 -105 -146 -72 -138 -171 -248 -261 -292 -62 -30 -164 -44 -242 -34 -48 7 -50 8 -45 34 14 70 51 144 95 190 42 43 56 51 127 69 44 12 98 24 120 27 99 15 155 57 155 117 l0 31 -51 -5 c-40 -4 -58 -12 -87 -40 -56 -52 -66 -58 -131 -78 l-60 -18 10 27 c6 14 36 62 68 106 70 96 91 136 91 170 0 41 -18 29 -50 -35 -30 -59 -31 -60 -74 -60 -56 0 -71 -18 -101 -115 -23 -75 -43 -114 -72 -145 -8 -8 -41 -61 -73 -117 -35 -59 -75 -113 -95 -128 -37 -29 -177 -85 -210 -85 -35 0 -222 -134 -282 -202 -31 -35 -64 -64 -72 -66 -22 -4 -68 116 -88 223 -20 113 -5 256 37 340 37 76 124 182 195 238 140 110 221 137 416 137 136 0 171 6 186 28 9 15 2 17 -76 18 -47 0 -127 4 -178 9 -167 15 -274 -28 -423 -170 -72 -68 -114 -95 -128 -81 -12 12 17 138 44 194 64 132 229 243 439 298 182 46 319 21 425 -80 68 -65 144 -115 202 -135 119 -41 155 -32 72 17 -88 52 -224 144 -224 152 0 14 51 20 210 22 115 2 160 0 175 -10 19 -12 18 -13 -8 -9 -36 6 -45 -9 -11 -17 56 -15 117 -51 183 -110 66 -59 119 -86 169 -86 54 0 31 59 -35 90 -167 77 -176 82 -158 93 25 13 138 -8 201 -37 27 -13 67 -43 89 -66 50 -53 84 -70 134 -70 37 0 71 19 71 40 0 24 -62 57 -129 70 -40 7 -74 17 -77 22 -3 4 24 8 60 8 36 0 68 -4 71 -10 3 -5 26 -10 51 -10 50 0 57 15 23 46 -24 21 -113 25 -226 10 -50 -7 -65 -6 -77 7 -19 18 -100 37 -160 37 -74 0 -136 12 -136 26 0 17 11 23 53 28 32 4 83 29 97 47 8 10 71 40 99 47 28 7 159 8 309 1 50 -2 92 -1 92 4 0 4 14 7 30 7 23 0 30 -4 30 -20 0 -15 -7 -20 -25 -20 -42 0 -28 -17 30 -39 75 -28 103 -27 117 4 8 18 19 25 38 25 34 0 47 35 23 62 -24 27 -70 31 -190 18 -101 -11 -112 -10 -173 10 -36 12 -104 24 -152 27 -49 3 -88 9 -88 13 0 8 35 26 66 35 12 3 37 21 55 40 19 20 67 58 106 86 57 39 86 52 134 60 71 11 170 58 193 91 34 49 10 51 -66 5 -52 -31 -154 -65 -165 -54 -11 12 9 25 67 47 33 12 60 26 60 30 0 5 15 17 34 28 31 18 67 84 53 98 -15 15 -69 -17 -124 -75 -35 -36 -63 -63 -63 -58 0 4 14 31 30 60 43 77 39 180 -7 151 -39 -24 -56 -62 -63 -141 -7 -87 -27 -127 -98 -200 -50 -52 -120 -103 -139 -103 -8 0 -22 -8 -31 -17 -31 -31 -26 11 12 94 33 74 61 171 53 180 -3 2 -17 1 -32 -3 -38 -10 -65 -74 -75 -185 -9 -97 -31 -147 -79 -176 -31 -20 -81 -71 -81 -83 0 -5 -24 -16 -52 -26 -29 -9 -58 -24 -64 -32 -7 -9 -33 -17 -70 -19 l-59 -4 55 48 c120 105 133 126 66 103 -19 -6 -58 -36 -88 -66 -29 -30 -72 -64 -96 -76 -41 -19 -50 -20 -163 -9 -168 16 -237 52 -196 103 21 27 121 88 143 88 60 0 183 34 234 65 30 18 74 36 97 40 85 14 180 99 131 118 -16 5 -19 13 -14 33 7 25 5 25 -26 19 -52 -11 -83 -31 -122 -76 -54 -63 -94 -86 -197 -109 -52 -12 -102 -24 -111 -26 -28 -8 -22 22 10 44 15 11 35 34 45 51 16 27 16 31 2 31 -8 0 -18 -7 -22 -16 -8 -23 -23 2 -23 40 0 23 -3 27 -12 18 -14 -14 -42 -16 -33 -2 3 6 4 10 1 10 -9 0 -37 -61 -62 -133 -29 -84 -85 -162 -137 -189 -24 -12 -67 -21 -110 -24 -40 -2 -100 -6 -134 -9 l-62 -4 36 72 c20 39 48 84 62 98 29 29 86 122 96 157 9 32 -20 29 -42 -5 -17 -27 -128 -174 -222 -297 -45 -58 -101 -96 -141 -96 -48 0 -9 184 59 284 41 59 113 107 234 156 51 20 141 67 198 102 57 36 118 72 134 80 40 21 155 46 240 53 48 5 82 14 113 32 58 34 150 44 258 28 41 -6 57 -4 75 9 17 12 46 16 111 16 88 0 116 12 57 24 -17 3 -48 6 -69 6 -21 0 -43 6 -49 14 -14 17 -8 22 40 31 30 5 36 10 32 26 -4 13 0 19 12 19 23 0 95 44 129 79 34 35 30 67 -6 55 -13 -4 -31 -7 -41 -6 -11 0 -38 -25 -68 -64 -28 -35 -53 -64 -55 -64 -2 0 7 22 21 50 14 27 25 60 25 74 0 14 5 37 11 53 7 19 7 29 0 31 -6 2 -11 17 -11 33 0 16 -4 29 -10 29 -5 0 -10 -19 -10 -42 0 -50 -37 -158 -74 -222 -28 -48 -90 -86 -141 -86 l-29 0 36 38 c20 20 43 52 52 70 16 31 16 32 -5 32 -25 0 -94 -47 -109 -75 -19 -35 -161 -104 -245 -120 -42 -8 -85 -15 -96 -15 -18 0 -18 1 -2 35 9 19 20 35 25 35 4 0 8 6 8 13 0 7 13 34 30 60 30 48 75 77 182 117 58 21 112 66 176 146 26 31 57 57 84 69 124 52 167 75 177 93 17 33 -14 35 -71 6 -29 -14 -69 -32 -89 -39 l-38 -14 20 51 c11 28 24 59 29 68 10 19 -20 60 -45 60 -18 0 -21 46 -4 52 6 2 14 26 16 53 4 43 2 52 -16 63 -20 11 -21 10 -21 -25 -1 -209 -5 -248 -32 -305 -34 -73 -116 -188 -133 -188 -8 0 -20 -6 -27 -13 -7 -7 -29 -18 -48 -24 -19 -6 -52 -18 -72 -27 -34 -15 -38 -15 -38 -1 0 35 32 73 89 109 60 37 77 51 45 39 -14 -5 -14 -3 -3 14 7 13 9 28 4 39 -5 11 -7 24 -6 29 1 6 -19 -11 -44 -37 -25 -26 -45 -44 -45 -40 0 4 18 34 40 67 30 45 40 69 40 100 0 53 -11 67 -46 63 -22 -2 -34 -13 -53 -47 -14 -25 -26 -40 -29 -33 -2 7 -10 12 -17 12 -10 0 -14 -33 -17 -142 l-4 -143 -63 -127 c-39 -81 -74 -137 -94 -154 -51 -43 -167 -87 -167 -63 0 6 26 38 58 72 32 34 66 73 75 87 18 26 23 100 8 100 -5 0 -22 -19 -38 -42 -15 -23 -52 -60 -81 -82 -31 -25 -61 -59 -74 -85 -37 -75 -125 -156 -220 -201 -46 -22 -101 -43 -121 -47 -32 -5 -37 -3 -37 13 0 36 50 229 70 269 10 23 38 95 61 160 39 116 84 211 117 248 12 13 13 20 4 29 -9 9 -21 5 -49 -18 -58 -46 -166 -272 -249 -519 -37 -110 -73 -207 -80 -216 -8 -8 -14 -21 -14 -28 0 -8 -19 -54 -41 -105 -23 -50 -61 -146 -84 -212 -49 -144 -77 -193 -152 -274 -71 -77 -89 -77 -115 2 -11 33 -27 59 -36 62 -19 6 -21 27 -23 201 -2 197 49 394 151 580 33 61 72 135 86 165 118 253 140 288 273 462 87 112 121 167 121 195 0 37 -25 27 -75 -29 -42 -48 -45 -50 -38 -23 13 50 9 145 -8 156 -19 12 -30 7 -50 -22 -23 -33 -15 -116 12 -124 28 -9 35 -49 12 -73 -10 -11 -36 -45 -58 -76 -22 -31 -44 -56 -48 -56 -12 0 -3 78 17 160 8 36 15 84 16 107 0 23 4 44 9 47 4 3 11 37 14 75 3 39 14 86 26 109 26 50 80 97 94 83 16 -16 59 -13 85 5 30 21 52 66 52 109 0 33 -2 35 -32 35 -59 0 -78 -12 -118 -69 -21 -31 -55 -74 -74 -96 l-35 -40 -1 41 c0 23 7 60 15 83 15 43 92 151 124 173 20 14 55 77 48 85 -3 2 -8 -5 -12 -16 -7 -24 -35 -17 -35 9 0 23 -13 32 -35 24 -9 -4 -12 -9 -7 -13 17 -10 2 -62 -16 -59 -11 2 -30 -24 -61 -87 -34 -68 -46 -84 -49 -67 -2 12 -8 22 -13 22 -5 0 -9 -10 -9 -22 -1 -23 -1 -23 -16 -3 -9 11 -24 37 -34 58 -11 24 -20 34 -23 25 -3 -7 -6 25 -6 72 -1 105 -21 98 -26 -10 -3 -43 -9 -76 -16 -81 -10 -6 -10 -11 0 -23 14 -16 3 -22 -15 -8 -5 4 2 -2 15 -13 51 -41 78 -76 96 -128 26 -70 25 -187 -3 -292 -13 -49 -21 -109 -20 -155 0 -104 -54 -310 -81 -310 -6 0 -11 3 -11 8 -1 44 -24 191 -41 259 l-22 85 27 108 c30 123 34 211 10 231 -20 16 -40 5 -72 -42 -21 -30 -23 -42 -18 -97 3 -36 1 -60 -4 -57 -17 11 -34 81 -34 150 -1 64 2 76 39 140 22 39 45 84 52 100 17 43 16 92 -2 98 -17 7 -17 8 -44 -73 -12 -36 -34 -87 -50 -113 -33 -56 -41 -48 -41 39 0 41 -4 54 -15 54 -11 0 -15 -18 -17 -80 -2 -45 -7 -80 -13 -80 -5 0 -10 4 -10 8 0 5 -8 16 -18 26 -58 58 -70 132 -53 314 7 69 6 92 -3 92 -6 0 -13 -6 -16 -12z m321 -503 c3 -20 4 -39 0 -42 -3 -4 -6 6 -6 20 0 17 -5 27 -15 27 -16 0 -20 12 -8 23 14 14 22 6 29 -28z m-1006 -80 c0 -8 -9 -15 -19 -15 -29 0 -35 18 -9 23 13 2 24 5 26 6 1 0 2 -6 2 -14z m327 -27 c-3 -7 -5 -2 -5 12 0 14 2 19 5 13 2 -7 2 -19 0 -25z m-462 -358 c3 -5 1 -10 -4 -10 -6 0 -11 5 -11 10 0 6 2 10 4 10 3 0 8 -4 11 -10z m-835 -40 c-6 -11 -15 -20 -19 -20 -5 0 -7 9 -4 20 3 11 12 20 20 20 11 0 11 -4 3 -20z m864 -25 c3 -9 0 -15 -9 -15 -9 0 -15 -10 -16 -27 0 -27 -1 -27 -13 7 -10 25 -10 37 -2 42 18 12 33 9 40 -7z m-892 -863 c38 2 68 0 68 -4 0 -5 -33 -8 -73 -8 -49 0 -80 -5 -95 -16 -21 -14 -22 -14 -22 5 0 14 -6 21 -20 21 -11 0 -20 2 -20 4 0 2 -3 12 -6 21 -6 13 1 13 47 -5 40 -16 70 -21 121 -18z m3218 -91 c0 -10 -7 -21 -15 -25 -11 -4 -15 1 -15 19 0 16 6 25 15 25 8 0 15 -9 15 -19z m-3479 -32 c-14 -5 -30 -14 -37 -20 -8 -7 -13 -3 -17 11 -5 18 0 20 36 19 38 0 40 -1 18 -10z m3359 -572 c0 -7 -7 -22 -15 -33 -13 -17 -14 -16 -4 14 11 33 19 41 19 19z m-3345 -198 c7 -22 -7 -39 -33 -39 -10 0 -10 4 0 20 11 17 10 22 -2 30 -12 8 -11 10 7 10 13 0 24 -8 28 -21z m445 -37 c0 -23 -35 -8 -38 16 -3 21 -2 22 17 10 12 -7 21 -19 21 -26z m-310 -647 c-28 -30 -60 -33 -60 -7 0 26 9 32 48 32 l35 0 -23 -25z M3684 5414 c-14 -21 -16 -41 -10 -124 4 -62 2 -100 -3 -100 -9 0 -17 26 -25 84 -1 11 -8 22 -14 24 -9 3 -12 -27 -12 -105 0 -69 -6 -130 -16 -164 -24 -86 -24 -85 -33 -70 -6 9 -10 3 -14 -17 -4 -20 -23 -43 -59 -72 -29 -23 -54 -46 -54 -51 -1 -5 -3 -39 -4 -76 -1 -46 -4 -60 -9 -43 -6 21 -9 15 -20 -35 -16 -74 -29 -99 -97 -197 -35 -49 -54 -86 -54 -105 0 -31 59 -200 60 -171 0 9 6 21 14 25 13 7 13 16 0 68 -17 72 -12 78 75 93 106 19 127 33 145 95 20 70 65 111 186 172 83 42 89 47 75 62 -9 8 -14 23 -11 32 5 14 5 14 -6 1 -7 -8 -41 -25 -75 -37 -54 -19 -61 -19 -56 -5 10 26 43 72 91 126 46 53 77 104 68 114 -6 6 -95 -81 -143 -141 l-30 -38 -7 80 c-4 45 -5 89 -1 98 3 10 31 34 63 53 61 37 147 112 164 144 21 38 -53 8 -126 -52 -98 -80 -100 -81 -92 -46 12 47 54 133 81 166 14 16 25 42 25 56 l-1 27 -25 -30 -26 -30 6 53 c3 28 9 74 12 100 5 40 3 50 -10 55 -10 4 -22 -2 -32 -19z m-79 -654 c0 -125 0 -126 -33 -176 -22 -36 -56 -67 -109 -103 -42 -28 -82 -51 -90 -51 -20 0 -16 22 11 59 13 18 30 46 36 62 7 16 16 29 20 29 5 0 13 33 20 73 16 102 29 149 40 142 6 -4 10 -2 10 3 0 5 13 25 30 43 16 19 30 38 30 42 0 5 8 7 18 5 15 -3 17 -17 17 -128z M2287 5348 c-10 -10 -22 -16 -27 -13 -5 3 -8 -3 -8 -12 1 -10 -2 -37 -6 -59 -6 -32 -4 -43 7 -47 23 -9 67 61 67 105 0 44 -9 51 -33 26z M1853 5256 c4 -22 11 -42 17 -46 7 -4 14 -26 17 -49 3 -22 10 -41 15 -41 5 0 7 12 4 28 -3 15 -8 46 -11 69 -4 23 -16 49 -27 60 -21 18 -21 18 -15 -21z M1780 5267 c0 -47 15 -79 42 -93 l30 -16 -7 34 c-4 18 -12 44 -19 58 -12 28 -46 40 -46 17z M1960 5120 c0 -21 30 -70 49 -80 27 -14 31 -13 31 10 0 11 5 20 10 20 6 0 8 -11 4 -25 -6 -23 -4 -25 30 -25 20 0 36 4 36 8 0 18 -68 72 -109 87 -52 18 -51 18 -51 5z M4127 5076 c-4 -10 -7 -45 -7 -79 0 -42 -6 -70 -18 -88 -56 -85 -73 -107 -106 -138 -20 -19 -36 -39 -36 -43 0 -18 34 -6 62 23 29 28 34 30 84 24 41 -6 59 -3 83 11 37 22 44 37 28 59 -16 21 -72 22 -95 2 -21 -19 -32 -22 -32 -7 0 5 38 35 84 66 77 51 106 84 106 119 0 26 -43 16 -77 -17 l-33 -32 0 47 c0 34 -4 47 -14 47 -8 0 -16 5 -18 12 -3 7 -7 5 -11 -6z M1049 5043 c-8 -10 -9 -14 -2 -10 7 5 28 -18 57 -63 48 -74 62 -86 52 -45 -4 15 -2 25 4 25 15 0 -17 72 -41 93 -27 22 -53 22 -70 0z M3400 4964 c-14 -37 -12 -60 6 -75 14 -11 18 -10 30 6 19 26 18 81 -2 89 -23 9 -24 8 -34 -20z M3910 4933 c-29 -20 -40 -33 -40 -50 0 -33 63 6 75 45 8 26 -2 28 -35 5z M3401 4844 c0 -11 3 -14 6 -6 3 7 2 16 -1 19 -3 4 -6 -2 -5 -13z M4532 4829 c-8 -12 -9 -18 -3 -14 7 4 11 -8 12 -32 1 -21 4 -51 8 -68 6 -26 8 -22 13 29 5 39 3 67 -5 83 l-12 23 -13 -21z M1017 4820 c-8 -30 16 -52 65 -60 41 -6 45 -5 40 12 -5 20 -68 68 -88 68 -6 0 -14 -9 -17 -20z M2529 4778 c-11 -21 -7 -134 7 -185 8 -30 24 -19 24 17 0 16 7 35 15 44 18 17 20 70 4 115 -13 36 -33 40 -50 9z M830 4767 c0 -24 30 -116 40 -122 11 -7 1 92 -12 118 -10 20 -28 23 -28 4z M4660 4751 c0 -5 -9 -12 -19 -16 -23 -7 -101 -81 -101 -95 0 -26 50 -6 98 38 51 47 67 82 37 82 -8 0 -15 -4 -15 -9z M764 4719 c-7 -13 82 -106 92 -96 11 11 -9 43 -46 75 -27 23 -41 29 -46 21z M1887 4634 c-18 -18 -6 -91 21 -131 79 -118 125 -171 138 -159 10 9 8 18 -9 46 -12 19 -25 37 -29 38 -4 2 -8 25 -8 50 0 60 -15 115 -38 135 -20 19 -65 31 -75 21z M1030 4579 c0 -35 54 -169 68 -169 6 0 12 -8 12 -17 1 -17 2 -17 15 0 11 16 11 26 -5 71 -25 75 -47 114 -70 126 -17 9 -20 8 -20 -11z M697 4553 c19 -54 69 -92 112 -85 36 5 46 34 20 58 -11 9 -22 14 -25 11 -4 -4 -18 3 -32 13 -32 26 -84 28 -75 3z M1150 4486 c0 -36 52 -76 101 -76 47 0 57 29 12 32 -16 1 6 4 47 8 l75 6 -75 2 c-41 1 -85 8 -96 15 -12 6 -31 18 -43 25 -19 12 -21 11 -21 -12z M3909 4427 c-16 -27 -19 -51 -19 -149 0 -111 1 -118 20 -118 15 0 24 14 40 68 39 124 39 215 -1 225 -15 4 -25 -2 -40 -26z M4723 4375 c-30 -13 -33 -18 -33 -60 l0 -45 24 15 c27 18 49 48 60 83 9 26 -4 28 -51 7z M5002 4348 c-5 -7 -23 -40 -40 -73 -32 -65 -106 -146 -156 -172 -17 -9 -51 -21 -75 -28 -46 -11 -63 -28 -38 -38 7 -3 47 2 87 10 58 12 85 13 128 4 96 -19 162 -13 162 15 0 11 -19 14 -82 15 -46 0 -91 4 -101 8 -17 6 -17 8 2 25 11 10 44 25 73 32 34 8 43 13 27 13 -31 1 -44 24 -23 41 8 7 14 21 14 31 0 11 10 36 23 57 33 52 39 72 23 72 -7 0 -18 -6 -24 -12z M3632 4290 c-52 -37 -68 -69 -74 -145 -3 -33 -3 -54 0 -47 3 10 7 9 16 -4 12 -15 18 -14 79 15 69 33 101 66 95 98 -4 22 -37 30 -49 11 -6 -8 -7 10 -3 45 8 68 -2 72 -64 27z M5016 4271 c-11 -12 -16 -24 -12 -28 9 -9 39 22 34 37 -2 7 -10 4 -22 -9z M470 4264 c0 -9 8 -28 18 -42 10 -15 22 -33 27 -40 8 -15 -67 31 -102 62 -13 11 -23 14 -23 8 0 -7 -7 -12 -15 -12 -19 0 -19 -15 2 -50 20 -35 48 -48 118 -56 37 -5 55 -11 55 -20 0 -8 11 -14 25 -14 14 0 25 4 25 10 0 5 -22 43 -50 84 -49 73 -80 100 -80 70z M2382 4102 c-5 -9 -12 -42 -14 -72 -9 -96 18 -125 39 -43 17 66 17 120 -2 127 -8 3 -19 -2 -23 -12z M4235 3850 c36 -39 118 -80 162 -80 30 0 93 41 93 61 0 5 -14 15 -30 24 -25 13 -44 14 -107 6 -43 -5 -80 -6 -83 -1 -3 5 -19 12 -35 16 l-30 7 30 -33z M133 3667 c-19 -41 -15 -59 18 -86 30 -24 135 -55 151 -45 11 7 10 42 -2 49 -5 3 -10 11 -10 17 0 6 7 5 17 -3 12 -10 15 -10 9 -1 -13 22 -84 52 -125 52 -33 0 -40 4 -43 22 -3 21 -4 21 -15 -5z M5265 3631 c-16 -10 -43 -33 -60 -51 l-30 -32 83 4 c77 3 86 6 107 30 35 41 24 68 -29 68 -23 0 -54 -8 -71 -19z M400 3512 c0 -5 -53 -12 -117 -16 -64 -4 -120 -9 -125 -12 -16 -10 -8 -53 13 -65 51 -27 183 0 213 43 13 17 19 18 68 9 29 -5 66 -13 81 -16 22 -6 26 -4 21 9 -5 12 0 16 17 17 13 1 -3 7 -36 14 -106 22 -135 26 -135 17z M5090 3480 c0 -5 9 -10 20 -10 11 0 47 -13 80 -30 57 -29 121 -39 147 -22 22 14 19 45 -7 59 -30 15 -240 18 -240 3z M926 3272 c-12 -11 -6 -94 9 -122 16 -31 39 -47 86 -60 24 -7 29 -5 39 21 19 44 5 94 -34 124 -35 27 -90 47 -100 37z M500 3049 c0 -23 9 -62 20 -85 17 -33 30 -46 70 -62 34 -14 56 -32 70 -54 16 -28 109 -108 125 -108 3 0 5 7 5 15 0 12 7 14 28 9 15 -3 -8 11 -50 32 -42 20 -80 44 -83 53 -4 9 -9 46 -12 84 -5 61 -9 70 -41 98 -34 30 -59 43 -107 55 -24 6 -25 4 -25 -37z M5203 2779 c-18 -11 -35 -29 -38 -40 -7 -22 -20 -25 -32 -6 -8 13 -20 -26 -22 -74 -1 -30 25 -36 35 -7 4 15 9 17 20 7 8 -6 14 -18 14 -26 0 -11 7 -9 27 7 43 33 63 71 63 118 0 49 -14 53 -67 21z M5307 2622 c-34 -32 -86 -72 -115 -88 -51 -29 -61 -46 -29 -52 25 -5 198 81 229 114 15 16 30 41 33 57 7 25 5 27 -24 27 -25 0 -45 -13 -94 -58z M447 2652 c-10 -10 -15 -21 -12 -24 7 -7 75 24 75 34 0 15 -47 8 -63 -10z M263 2600 c-12 -5 -26 -18 -32 -28 -8 -15 -6 -24 13 -41 33 -31 84 -27 160 13 68 36 68 47 1 51 -16 1 -50 5 -75 8 -25 4 -55 3 -67 -3z M996 2540 c-37 -11 -102 -74 -115 -112 l-10 -28 58 0 c48 0 65 5 98 29 49 35 87 86 79 106 -6 17 -62 19 -110 5z M673 2324 c-43 -18 -42 -43 1 -88 33 -35 35 -36 114 -36 70 0 80 2 78 18 0 10 6 16 16 16 13 -1 9 8 -18 40 -19 22 -45 46 -57 53 -29 16 -94 15 -134 -3z M4790 2120 c-9 -17 -5 -20 43 -29 72 -15 166 -19 169 -9 2 5 11 6 21 3 20 -8 23 -35 5 -35 -7 -1 -2 -7 12 -15 29 -17 113 -20 141 -5 24 13 25 36 2 48 -10 5 -58 12 -108 15 -49 3 -117 12 -150 20 -110 28 -124 28 -135 7z M4881 2021 c6 -17 30 -50 53 -75 33 -36 49 -46 74 -46 25 0 32 4 32 19 0 25 -60 77 -99 86 -17 4 -36 15 -41 26 -17 30 -30 23 -19 -10z";
|
|
1322
1317
|
|
|
1323
1318
|
// src/genre-tree/TreeMarkIcon.tsx
|
|
1324
|
-
var
|
|
1319
|
+
var import_jsx_runtime23 = require("react/jsx-runtime");
|
|
1325
1320
|
function TreeMarkIcon({ className: className2 }) {
|
|
1326
|
-
return /* @__PURE__ */ (0,
|
|
1321
|
+
return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("svg", { viewBox: "0 0 551 567", fill: "currentColor", className: className2, "aria-hidden": true, children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("path", { transform: "translate(0 567) scale(0.1 -0.1)", d: TREE_MARK_PATH }) });
|
|
1327
1322
|
}
|
|
1328
1323
|
|
|
1329
1324
|
// src/genre-tree/GenrePlayActions.tsx
|
|
1330
|
-
var
|
|
1325
|
+
var import_jsx_runtime24 = require("react/jsx-runtime");
|
|
1331
1326
|
function PlayIcon({ kind }) {
|
|
1332
|
-
return /* @__PURE__ */ (0,
|
|
1333
|
-
kind === "tree" && /* @__PURE__ */ (0,
|
|
1334
|
-
kind === "map" && /* @__PURE__ */ (0,
|
|
1335
|
-
kind === "tree-map" && /* @__PURE__ */ (0,
|
|
1336
|
-
/* @__PURE__ */ (0,
|
|
1337
|
-
/* @__PURE__ */ (0,
|
|
1327
|
+
return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("span", { "aria-hidden": "true", className: "relative flex items-center justify-center w-5 h-5", children: [
|
|
1328
|
+
kind === "tree" && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(TreeMarkIcon, { className: "absolute -left-1.5 -top-1.5 w-8 h-8 opacity-35" }),
|
|
1329
|
+
kind === "map" && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(RegionGlobeIcon, { className: "absolute -left-1.5 -top-1.5 w-8 h-8 opacity-35" }),
|
|
1330
|
+
kind === "tree-map" && /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(import_jsx_runtime24.Fragment, { children: [
|
|
1331
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)(TreeMarkIcon, { className: "absolute -left-1.5 -top-1.5 w-8 h-8 opacity-35 [clip-path:inset(0_50%_0_0)]" }),
|
|
1332
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)(RegionGlobeIcon, { className: "absolute -left-1.5 -top-1.5 w-8 h-8 opacity-35 [clip-path:inset(0_0_0_50%)]" })
|
|
1338
1333
|
] }),
|
|
1339
|
-
/* @__PURE__ */ (0,
|
|
1334
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_lucide_react8.Play, { className: "relative w-5 h-5 fill-[var(--color-surface)]" })
|
|
1340
1335
|
] });
|
|
1341
1336
|
}
|
|
1342
1337
|
function playOptions(playlist) {
|
|
@@ -1352,13 +1347,13 @@ function playOptions(playlist) {
|
|
|
1352
1347
|
function GenrePlayActions({ genrePlaylist, playback }) {
|
|
1353
1348
|
const { isPlaying, setIsPlaying } = (0, import_player4.usePlayer)();
|
|
1354
1349
|
const options = playOptions(genrePlaylist);
|
|
1355
|
-
return /* @__PURE__ */ (0,
|
|
1350
|
+
return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_jsx_runtime24.Fragment, { children: options.map((option) => {
|
|
1356
1351
|
const isCurrent = playback.playing?.uuid === genrePlaylist.uuid && (option.selection === void 0 || playback.playing.selectionKey === "" || playback.playing.selectionKey === (0, import_genre_tree10.genreMusicSelectionKey)(option.selection).join());
|
|
1357
1352
|
const playing = isCurrent && isPlaying;
|
|
1358
|
-
return /* @__PURE__ */ (0,
|
|
1353
|
+
return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
1359
1354
|
import_ui7.ActionButton,
|
|
1360
1355
|
{
|
|
1361
|
-
icon: playing ? /* @__PURE__ */ (0,
|
|
1356
|
+
icon: playing ? /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_lucide_react8.Pause, { "aria-hidden": "true", className: "w-5 h-5" }) : /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(PlayIcon, { kind: option.icon }),
|
|
1362
1357
|
label: playing ? "Pause" : option.label,
|
|
1363
1358
|
caption: String(option.count),
|
|
1364
1359
|
disabled: option.count === 0,
|
|
@@ -1368,9 +1363,7 @@ function GenrePlayActions({ genrePlaylist, playback }) {
|
|
|
1368
1363
|
setIsPlaying(!isPlaying);
|
|
1369
1364
|
return;
|
|
1370
1365
|
}
|
|
1371
|
-
playback.play(genrePlaylist, option.selection)
|
|
1372
|
-
console.error("Failed to load genre playlist tracks:", error);
|
|
1373
|
-
});
|
|
1366
|
+
void playback.play(genrePlaylist, option.selection);
|
|
1374
1367
|
}
|
|
1375
1368
|
},
|
|
1376
1369
|
option.key
|
|
@@ -1384,7 +1377,7 @@ var import_genre_tree18 = require("@behindthemusictree/app-kit/genre-tree");
|
|
|
1384
1377
|
|
|
1385
1378
|
// src/genre-tree/ClampedText.tsx
|
|
1386
1379
|
var import_react12 = require("react");
|
|
1387
|
-
var
|
|
1380
|
+
var import_jsx_runtime25 = require("react/jsx-runtime");
|
|
1388
1381
|
function ClampedText({ children, className: className2 = "" }) {
|
|
1389
1382
|
const ref = (0, import_react12.useRef)(null);
|
|
1390
1383
|
const [expanded, setExpanded] = (0, import_react12.useState)(false);
|
|
@@ -1394,9 +1387,9 @@ function ClampedText({ children, className: className2 = "" }) {
|
|
|
1394
1387
|
if (!element || expanded) return;
|
|
1395
1388
|
setOverflows(element.scrollHeight > element.clientHeight);
|
|
1396
1389
|
}, [children, expanded]);
|
|
1397
|
-
return /* @__PURE__ */ (0,
|
|
1398
|
-
/* @__PURE__ */ (0,
|
|
1399
|
-
(overflows || expanded) && /* @__PURE__ */ (0,
|
|
1390
|
+
return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(import_jsx_runtime25.Fragment, { children: [
|
|
1391
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)("p", { ref, className: `${className2} ${expanded ? "" : "line-clamp-3"}`, children }),
|
|
1392
|
+
(overflows || expanded) && /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
|
|
1400
1393
|
"button",
|
|
1401
1394
|
{
|
|
1402
1395
|
type: "button",
|
|
@@ -1416,13 +1409,13 @@ var import_zod = require("zod");
|
|
|
1416
1409
|
var import_fa2 = require("react-icons/fa");
|
|
1417
1410
|
var import_ui8 = require("@behindthemusictree/ui");
|
|
1418
1411
|
var import_auth = require("@behindthemusictree/app-kit/auth");
|
|
1412
|
+
var import_transport2 = require("@behindthemusictree/app-kit/transport");
|
|
1419
1413
|
var import_transport3 = require("@behindthemusictree/app-kit/transport");
|
|
1420
1414
|
var import_transport4 = require("@behindthemusictree/app-kit/transport");
|
|
1421
|
-
var import_transport5 = require("@behindthemusictree/app-kit/transport");
|
|
1422
1415
|
var import_player5 = require("@behindthemusictree/app-kit/player");
|
|
1423
1416
|
var import_player6 = require("@behindthemusictree/app-kit/player");
|
|
1424
|
-
var
|
|
1425
|
-
var
|
|
1417
|
+
var import_popup3 = require("@behindthemusictree/app-kit/popup");
|
|
1418
|
+
var import_transport5 = require("@behindthemusictree/app-kit/transport");
|
|
1426
1419
|
var import_genre_tree12 = require("@behindthemusictree/app-kit/genre-tree");
|
|
1427
1420
|
var import_genre_tree13 = require("@behindthemusictree/app-kit/genre-tree");
|
|
1428
1421
|
var import_genre_tree14 = require("@behindthemusictree/app-kit/genre-tree");
|
|
@@ -1431,15 +1424,15 @@ var import_genre_tree16 = require("@behindthemusictree/app-kit/genre-tree");
|
|
|
1431
1424
|
|
|
1432
1425
|
// src/genre-tree/MusicBrainzRecordingLink.tsx
|
|
1433
1426
|
var import_genre_tree11 = require("@behindthemusictree/app-kit/genre-tree");
|
|
1434
|
-
var
|
|
1427
|
+
var import_jsx_runtime26 = require("react/jsx-runtime");
|
|
1435
1428
|
function MusicBrainzRecordingLink({
|
|
1436
1429
|
song,
|
|
1437
1430
|
children,
|
|
1438
1431
|
className: className2 = ""
|
|
1439
1432
|
}) {
|
|
1440
1433
|
const url = (0, import_genre_tree11.musicBrainzRecordingUrl)(song);
|
|
1441
|
-
if (!url) return /* @__PURE__ */ (0,
|
|
1442
|
-
return /* @__PURE__ */ (0,
|
|
1434
|
+
if (!url) return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(import_jsx_runtime26.Fragment, { children });
|
|
1435
|
+
return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
|
|
1443
1436
|
"a",
|
|
1444
1437
|
{
|
|
1445
1438
|
href: url,
|
|
@@ -1456,9 +1449,9 @@ function MusicBrainzRecordingLink({
|
|
|
1456
1449
|
// src/genre-tree/GenrePlaylistTracks.tsx
|
|
1457
1450
|
var import_genre_tree17 = require("@behindthemusictree/app-kit/genre-tree");
|
|
1458
1451
|
var import_track_noun = require("@behindthemusictree/app-kit/track-noun");
|
|
1459
|
-
var
|
|
1452
|
+
var import_jsx_runtime27 = require("react/jsx-runtime");
|
|
1460
1453
|
var CATALOGUE_PAGE_SIZE = 100;
|
|
1461
|
-
var SongPageSchema = (0,
|
|
1454
|
+
var SongPageSchema = (0, import_transport3.PaginatedResponseSchema)(import_genre_tree15.SongDetailedSchema).extend({
|
|
1462
1455
|
overallTotal: import_zod.z.number().nullable(),
|
|
1463
1456
|
page: import_zod.z.number().nullable(),
|
|
1464
1457
|
totalPages: import_zod.z.number().nullable()
|
|
@@ -1490,12 +1483,12 @@ function GenrePlaylistTracks({
|
|
|
1490
1483
|
const { fetchGenrePlaylistTracksPage, playNewTrackListFromGenrePlaylist, playNewTrackListFromArtist, playNewTrackListFromGenreCatalogue } = (0, import_genre_tree16.useTrackList)();
|
|
1491
1484
|
const { session, sessionRestored } = (0, import_auth.useSession)();
|
|
1492
1485
|
const { playerTrackObject, playState, handlePlayPauseAction } = (0, import_player5.usePlayer)();
|
|
1493
|
-
const { showPopup } = (0,
|
|
1486
|
+
const { showPopup } = (0, import_popup3.usePopup)();
|
|
1494
1487
|
const trackNoun = (0, import_track_noun.useTrackNoun)();
|
|
1495
1488
|
const uuid = genrePlaylist?.uuid;
|
|
1496
1489
|
const genreName = selectedGenreName ?? genrePlaylist?.name ?? "Genre";
|
|
1497
|
-
const { fetchBound } = (0,
|
|
1498
|
-
const playback = (0,
|
|
1490
|
+
const { fetchBound } = (0, import_transport2.usePlaybackFetch)(getBackendBaseUrl);
|
|
1491
|
+
const playback = (0, import_transport2.usePlaybackContext)();
|
|
1499
1492
|
const { data, isPending, isError, refetch, hasNextPage, isFetchingNextPage, fetchNextPage } = (0, import_react_query.useInfiniteQuery)({
|
|
1500
1493
|
queryKey: [...scope === "me" ? uuid ? import_genre_tree13.genrePlaylistQueryKeys.me.tracks(uuid) : ["missing-personal-genre-playlist", genreUuid] : artist ? [...import_genre_tree14.libraryQueryKeys.reference.songs.byGenre(getBackendBaseUrl(), genreUuid, selection), "artist", artist.uuid] : import_genre_tree14.libraryQueryKeys.reference.songs.byGenre(getBackendBaseUrl(), genreUuid, selection), ...playback.key ? [playback.key] : []],
|
|
1501
1494
|
queryFn: async ({ pageParam }) => {
|
|
@@ -1510,7 +1503,7 @@ function GenrePlaylistTracks({
|
|
|
1510
1503
|
{},
|
|
1511
1504
|
{ genre: genreUuid, ...(0, import_genre_tree12.genreMusicQueryParams)(selection), ...artist && { artist: artist.uuid }, pageSize: CATALOGUE_PAGE_SIZE, withTotal: false, ...pageParam && { cursor: pageParam } }
|
|
1512
1505
|
);
|
|
1513
|
-
const parsed = (0,
|
|
1506
|
+
const parsed = (0, import_transport4.parseWithLog)(SongPageSchema, response, "GenrePlaylistTracks");
|
|
1514
1507
|
return { tracks: parsed.results, total: parsed.overallTotal, nextPage: parsed.next ? nextCursor(parsed.next) : null };
|
|
1515
1508
|
},
|
|
1516
1509
|
initialPageParam: scope === "me" ? 1 : "",
|
|
@@ -1542,35 +1535,36 @@ function GenrePlaylistTracks({
|
|
|
1542
1535
|
}) : scope === "reference" ? playNewTrackListFromGenreCatalogue({ uuid: genreUuid, name: genreName }, scope, { startSongUuid, ...selection && { selection } }) : genrePlaylist ? playNewTrackListFromGenrePlaylist(genrePlaylist, scope, { startSongUuid }) : Promise.reject(new Error("Personal genre has no playlist"));
|
|
1543
1536
|
started.catch((error) => {
|
|
1544
1537
|
console.error("Failed to play genre playlist:", error);
|
|
1545
|
-
|
|
1538
|
+
if (error instanceof import_genre_tree16.TracksFailureAlreadyReportedError) return;
|
|
1539
|
+
showPopup(/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(InternalErrorPopup, { errorCode: error instanceof import_transport5.AppError ? error.code : import_transport5.ErrorCode.CLIENT_UNKNOWN }));
|
|
1546
1540
|
});
|
|
1547
1541
|
};
|
|
1548
|
-
return /* @__PURE__ */ (0,
|
|
1542
|
+
return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_ui8.PanelSection, { title: `${(0, import_track_noun.capitalize)(trackNoun.plural)}${total !== void 0 ? ` (${total})` : ""}`, children: /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { children: [
|
|
1549
1543
|
renderTracksToolbar?.(),
|
|
1550
|
-
scope === "me" && !genrePlaylist ? /* @__PURE__ */ (0,
|
|
1544
|
+
scope === "me" && !genrePlaylist ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("p", { children: "\u2014" }) : isPending ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_ui8.Skeleton, { className: "h-4 w-3/4", "aria-busy": "true" }) : isError && tracks.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("p", { role: "alert", children: [
|
|
1551
1545
|
"Couldn't load ",
|
|
1552
1546
|
trackNoun.plural,
|
|
1553
1547
|
".",
|
|
1554
1548
|
" ",
|
|
1555
|
-
/* @__PURE__ */ (0,
|
|
1556
|
-
] }) : tracks.length === 0 ? /* @__PURE__ */ (0,
|
|
1549
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)("button", { type: "button", className: "underline", onClick: () => void refetch(), children: "Retry" })
|
|
1550
|
+
] }) : tracks.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("p", { children: "\u2014" }) : /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("ul", { className: "mt-1 max-h-64 overflow-y-auto text-body [container-type:inline-size]", "aria-label": `${genreName} ${trackNoun.plural}`, children: [
|
|
1557
1551
|
tracks.map((track, index) => {
|
|
1558
1552
|
const label = track.artists?.length ? `${track.title} \u2014 ${track.artists.map((artist2) => artist2.name).join(", ")}` : track.title;
|
|
1559
1553
|
const isCurrent = playerTrackObject?.track.id === track.uuid;
|
|
1560
1554
|
const isPlaying = isCurrent && playState === import_player6.PlayStates.PLAYING;
|
|
1561
|
-
const text = /* @__PURE__ */ (0,
|
|
1562
|
-
/* @__PURE__ */ (0,
|
|
1563
|
-
track.artists?.length ? /* @__PURE__ */ (0,
|
|
1564
|
-
/* @__PURE__ */ (0,
|
|
1565
|
-
track.album && /* @__PURE__ */ (0,
|
|
1555
|
+
const text = /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("span", { className: TEXT_CELL, children: [
|
|
1556
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { className: TITLE_CELL, children: renderSongLink ? renderSongLink(track) : (0, import_genre_tree15.isSong)(track) ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(MusicBrainzRecordingLink, { song: track, className: "hover:underline focus-visible:underline", children: track.title }) : track.title }),
|
|
1557
|
+
track.artists?.length ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { className: SEPARATOR, children: " \u2014 " }) : null,
|
|
1558
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { className: COLUMN_CELL, children: track.artists?.length ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_genre_tree17.ArtistNames, { artists: track.artists, renderArtistLink }) : null }),
|
|
1559
|
+
track.album && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { className: ALBUM_CELL, children: track.album.name })
|
|
1566
1560
|
] });
|
|
1567
1561
|
const leading = renderSongLeading?.(track, index);
|
|
1568
1562
|
const actions = renderSongActions?.(track);
|
|
1569
1563
|
const isUnplayable = (0, import_genre_tree15.isSong)(track) && (0, import_genre_tree15.songUnplayableReason)(track) !== null;
|
|
1570
1564
|
if (isUnplayable) {
|
|
1571
|
-
return /* @__PURE__ */ (0,
|
|
1565
|
+
return /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("li", { className: "flex min-h-8 items-center gap-1 px-1 opacity-50", children: [
|
|
1572
1566
|
leading,
|
|
1573
|
-
/* @__PURE__ */ (0,
|
|
1567
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
|
|
1574
1568
|
"button",
|
|
1575
1569
|
{
|
|
1576
1570
|
type: "button",
|
|
@@ -1578,27 +1572,27 @@ function GenrePlaylistTracks({
|
|
|
1578
1572
|
"aria-disabled": "true",
|
|
1579
1573
|
"aria-label": label,
|
|
1580
1574
|
className: "flex h-6 w-6 shrink-0 items-center justify-center rounded-full opacity-0 cursor-not-allowed",
|
|
1581
|
-
children: /* @__PURE__ */ (0,
|
|
1575
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_fa2.FaPlay, { size: 10 })
|
|
1582
1576
|
}
|
|
1583
1577
|
),
|
|
1584
1578
|
text,
|
|
1585
1579
|
actions
|
|
1586
1580
|
] }, track.uuid);
|
|
1587
1581
|
}
|
|
1588
|
-
return /* @__PURE__ */ (0,
|
|
1582
|
+
return /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(
|
|
1589
1583
|
"li",
|
|
1590
1584
|
{
|
|
1591
1585
|
className: `group flex min-h-8 items-center gap-1 rounded px-1 hover:bg-[var(--color-neutral-100)] ${isCurrent ? "font-medium text-[var(--color-primary)]" : ""}`,
|
|
1592
1586
|
children: [
|
|
1593
1587
|
leading,
|
|
1594
|
-
/* @__PURE__ */ (0,
|
|
1588
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
|
|
1595
1589
|
"button",
|
|
1596
1590
|
{
|
|
1597
1591
|
type: "button",
|
|
1598
1592
|
"aria-label": `${isPlaying ? "Pause" : "Play"} ${label}`,
|
|
1599
1593
|
className: `flex h-6 w-6 shrink-0 items-center justify-center rounded-full cursor-pointer group-hover:opacity-100 focus-visible:opacity-100 ${isCurrent && playState !== import_player6.PlayStates.STOPPED ? "opacity-100" : "opacity-0 [@media(pointer:coarse)]:opacity-100"}`,
|
|
1600
1594
|
onClick: () => isCurrent ? handlePlayPauseAction() : play(track.uuid),
|
|
1601
|
-
children: isCurrent && playState === import_player6.PlayStates.LOADING ? /* @__PURE__ */ (0,
|
|
1595
|
+
children: isCurrent && playState === import_player6.PlayStates.LOADING ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_ui8.RingLoader, { size: 10 }) : isPlaying ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_fa2.FaPause, { size: 10 }) : /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_fa2.FaPlay, { size: 10 })
|
|
1602
1596
|
}
|
|
1603
1597
|
),
|
|
1604
1598
|
text,
|
|
@@ -1608,7 +1602,7 @@ function GenrePlaylistTracks({
|
|
|
1608
1602
|
track.uuid
|
|
1609
1603
|
);
|
|
1610
1604
|
}),
|
|
1611
|
-
hasNextPage && /* @__PURE__ */ (0,
|
|
1605
|
+
hasNextPage && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("li", { ref: setSentinel, "aria-hidden": "true", className: "h-4" })
|
|
1612
1606
|
] })
|
|
1613
1607
|
] }) });
|
|
1614
1608
|
}
|
|
@@ -1616,7 +1610,7 @@ function GenrePlaylistTracks({
|
|
|
1616
1610
|
// src/genre-tree/GenreDetailExtras.tsx
|
|
1617
1611
|
var import_track_noun2 = require("@behindthemusictree/app-kit/track-noun");
|
|
1618
1612
|
var import_si2 = require("react-icons/si");
|
|
1619
|
-
var
|
|
1613
|
+
var import_jsx_runtime28 = require("react/jsx-runtime");
|
|
1620
1614
|
function GenreDetailExtras({
|
|
1621
1615
|
genreUuid,
|
|
1622
1616
|
genrePlaylist,
|
|
@@ -1642,17 +1636,17 @@ function GenreDetailExtras({
|
|
|
1642
1636
|
criteriaOverviewSchema
|
|
1643
1637
|
);
|
|
1644
1638
|
if (isPending) {
|
|
1645
|
-
return /* @__PURE__ */ (0,
|
|
1646
|
-
/* @__PURE__ */ (0,
|
|
1639
|
+
return /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(import_jsx_runtime28.Fragment, { children: [
|
|
1640
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_ui9.PanelSection, { title: "Summary", children: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("div", { "aria-busy": "true", "data-testid": "genre-detail-extras-skeleton", children: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_ui9.Skeleton, { className: "h-4 w-3/4" }) }) }),
|
|
1647
1641
|
family
|
|
1648
1642
|
] });
|
|
1649
1643
|
}
|
|
1650
|
-
if (!overview) return /* @__PURE__ */ (0,
|
|
1644
|
+
if (!overview) return /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_jsx_runtime28.Fragment, { children: family });
|
|
1651
1645
|
const { summary, summarySourceUrl, essentialSongs } = overview;
|
|
1652
1646
|
const wikidataUrl = wikidataId ? `https://www.wikidata.org/wiki/${encodeURIComponent(wikidataId)}` : null;
|
|
1653
|
-
return /* @__PURE__ */ (0,
|
|
1654
|
-
(summarySourceUrl || wikidataUrl) && /* @__PURE__ */ (0,
|
|
1655
|
-
summarySourceUrl && /* @__PURE__ */ (0,
|
|
1647
|
+
return /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(import_jsx_runtime28.Fragment, { children: [
|
|
1648
|
+
(summarySourceUrl || wikidataUrl) && /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_ui9.PanelSection, { title: "Links", children: /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("div", { className: "flex flex-wrap gap-x-3 gap-y-1 text-caption text-[var(--color-text)]", children: [
|
|
1649
|
+
summarySourceUrl && /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(
|
|
1656
1650
|
"a",
|
|
1657
1651
|
{
|
|
1658
1652
|
href: summarySourceUrl,
|
|
@@ -1660,12 +1654,12 @@ function GenreDetailExtras({
|
|
|
1660
1654
|
rel: "noopener noreferrer",
|
|
1661
1655
|
className: "inline-flex items-center gap-1.5 text-[var(--color-text-muted)] hover:text-[var(--color-text)]",
|
|
1662
1656
|
children: [
|
|
1663
|
-
/* @__PURE__ */ (0,
|
|
1657
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_si2.SiWikipedia, { "aria-hidden": "true", className: "h-3.5 w-3.5" }),
|
|
1664
1658
|
"Wikipedia"
|
|
1665
1659
|
]
|
|
1666
1660
|
}
|
|
1667
1661
|
),
|
|
1668
|
-
wikidataUrl && /* @__PURE__ */ (0,
|
|
1662
|
+
wikidataUrl && /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(
|
|
1669
1663
|
"a",
|
|
1670
1664
|
{
|
|
1671
1665
|
href: wikidataUrl,
|
|
@@ -1673,17 +1667,17 @@ function GenreDetailExtras({
|
|
|
1673
1667
|
rel: "noopener noreferrer",
|
|
1674
1668
|
className: "inline-flex items-center gap-1.5 text-[var(--color-text-muted)] hover:text-[var(--color-text)]",
|
|
1675
1669
|
children: [
|
|
1676
|
-
/* @__PURE__ */ (0,
|
|
1670
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_si2.SiWikidata, { "aria-hidden": "true", className: "h-3.5 w-3.5" }),
|
|
1677
1671
|
"Wikidata"
|
|
1678
1672
|
]
|
|
1679
1673
|
}
|
|
1680
1674
|
)
|
|
1681
1675
|
] }) }),
|
|
1682
|
-
/* @__PURE__ */ (0,
|
|
1676
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_ui9.PanelSection, { title: "Summary", children: renderSummary ? renderSummary(overview) : /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(ClampedText, { className: "text-body text-[var(--color-text)]", children: summary ?? "\u2014" }, genreUuid) }),
|
|
1683
1677
|
family,
|
|
1684
1678
|
renderGenreDetailExtras?.(overview),
|
|
1685
|
-
(renderEssentialTracks || essentialSongs) && /* @__PURE__ */ (0,
|
|
1686
|
-
/* @__PURE__ */ (0,
|
|
1679
|
+
(renderEssentialTracks || essentialSongs) && /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_ui9.PanelSection, { title: `Essential ${trackNoun.plural}`, children: renderEssentialTracks ? renderEssentialTracks(overview) : essentialSongs && essentialSongs.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("ul", { className: "text-body text-[var(--color-text)]", children: essentialSongs.map((track) => /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("li", { className: "py-1", children: track.title }, track.uuid)) }) : /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("p", { className: "text-body text-[var(--color-text)]", children: "\u2014" }) }),
|
|
1680
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
|
|
1687
1681
|
GenrePlaylistTracks,
|
|
1688
1682
|
{
|
|
1689
1683
|
genreUuid,
|
|
@@ -1701,10 +1695,10 @@ function GenreDetailExtras({
|
|
|
1701
1695
|
}
|
|
1702
1696
|
|
|
1703
1697
|
// src/genre-tree/GenreInfoPanelBody.tsx
|
|
1704
|
-
var
|
|
1698
|
+
var import_jsx_runtime29 = require("react/jsx-runtime");
|
|
1705
1699
|
var import_react14 = require("react");
|
|
1706
1700
|
function GenreNodeActionBand({ genrePlaylist, playback, ...bandProps }) {
|
|
1707
|
-
return /* @__PURE__ */ (0,
|
|
1701
|
+
return /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(GenreActionBand, { ...bandProps, playActions: /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(GenrePlayActions, { genrePlaylist, playback }) });
|
|
1708
1702
|
}
|
|
1709
1703
|
function GenreInfoPanelBody({
|
|
1710
1704
|
toolbar,
|
|
@@ -1721,9 +1715,9 @@ function GenreInfoPanelBody({
|
|
|
1721
1715
|
}) {
|
|
1722
1716
|
const summary = scope === "reference" ? import_genre_tree19.GenreCatalogueCountsSchema.parse(genrePlaylist ?? catalogue) : void 0;
|
|
1723
1717
|
const selection = summary ? (0, import_genre_tree19.defaultGenreMusicSelection)(summary) : void 0;
|
|
1724
|
-
return /* @__PURE__ */ (0,
|
|
1718
|
+
return /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(import_jsx_runtime29.Fragment, { children: [
|
|
1725
1719
|
toolbar,
|
|
1726
|
-
genrePlaylist ? /* @__PURE__ */ (0,
|
|
1720
|
+
genrePlaylist ? /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(GenreNodeActionBand, { ...band, genrePlaylist, playback }) : /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(GenreActionBand, { ...band }),
|
|
1727
1721
|
/* @__PURE__ */ (0, import_react14.createElement)(
|
|
1728
1722
|
GenreDetailExtras,
|
|
1729
1723
|
{
|
|
@@ -1743,7 +1737,7 @@ function GenreInfoPanelBody({
|
|
|
1743
1737
|
}
|
|
1744
1738
|
|
|
1745
1739
|
// src/genre-tree/GenreDetailPanel.tsx
|
|
1746
|
-
var
|
|
1740
|
+
var import_jsx_runtime30 = require("react/jsx-runtime");
|
|
1747
1741
|
var RELATIVE_ITEM_COUNT = 1;
|
|
1748
1742
|
function toNode(genre, parentId) {
|
|
1749
1743
|
return {
|
|
@@ -1766,7 +1760,7 @@ function useGenreDetailContent({
|
|
|
1766
1760
|
trailing,
|
|
1767
1761
|
genrePlaylist: hostPlaylist,
|
|
1768
1762
|
expanded,
|
|
1769
|
-
|
|
1763
|
+
treeStyles
|
|
1770
1764
|
}) {
|
|
1771
1765
|
const { data: detail, isPending, isError } = (0, import_genre_tree20.useFetchGenreDetail)(genreUuid, scope, getBackendBaseUrl);
|
|
1772
1766
|
const defaultPlayback = useGenrePlaylistPlayback({ scope, genrePlaylists: [], artist: extras?.artist });
|
|
@@ -1774,19 +1768,12 @@ function useGenreDetailContent({
|
|
|
1774
1768
|
const view = (0, import_react15.useMemo)(() => {
|
|
1775
1769
|
if (!detail) return null;
|
|
1776
1770
|
const rootColor = (0, import_genre_tree_view4.getGenreTreeColor)(detail.root.wikidataId);
|
|
1777
|
-
const treeStyles = /* @__PURE__ */ new Map();
|
|
1778
|
-
if (treeRelations) {
|
|
1779
|
-
const drawn = [treeRelations, treeRelations.parentNode, ...treeRelations.childNodes, ...treeRelations.ancestorNodes];
|
|
1780
|
-
for (const entry of drawn) {
|
|
1781
|
-
if (entry) treeStyles.set(entry.node.id, { fill: entry.fill, textColor: entry.textColor });
|
|
1782
|
-
}
|
|
1783
|
-
}
|
|
1784
1771
|
const relative = (genre, parentId) => ({
|
|
1785
1772
|
node: toNode(genre, parentId),
|
|
1786
|
-
...treeStyles
|
|
1773
|
+
...treeStyles?.get(genre.uuid) ?? { fill: (0, import_genre_tree_view4.tintSurface)(rootColor), textColor: import_genre_tree_view4.TEXT_COLOR }
|
|
1787
1774
|
});
|
|
1788
1775
|
const ancestors2 = [...detail.ascendants].sort((a, b) => b.degree - a.degree);
|
|
1789
|
-
const own = treeStyles
|
|
1776
|
+
const own = treeStyles?.get(detail.uuid) ?? { fill: rootColor, textColor: (0, import_genre_tree_view4.getTextColorOnFill)(rootColor) };
|
|
1790
1777
|
return {
|
|
1791
1778
|
node: {
|
|
1792
1779
|
id: detail.uuid,
|
|
@@ -1803,23 +1790,23 @@ function useGenreDetailContent({
|
|
|
1803
1790
|
({ ascendant }, index) => relative(ascendant, index === 0 ? null : ancestors2[index - 1].ascendant.uuid)
|
|
1804
1791
|
)
|
|
1805
1792
|
};
|
|
1806
|
-
}, [detail, scope,
|
|
1793
|
+
}, [detail, scope, treeStyles]);
|
|
1807
1794
|
if (isError) return {
|
|
1808
1795
|
name: null,
|
|
1809
1796
|
title: "Genre unavailable",
|
|
1810
|
-
content: /* @__PURE__ */ (0,
|
|
1797
|
+
content: /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("p", { role: "alert", className: "text-body text-[var(--color-text)]", children: "This genre could not be loaded." })
|
|
1811
1798
|
};
|
|
1812
1799
|
if (isPending || !detail || !view) return {
|
|
1813
1800
|
name: null,
|
|
1814
1801
|
title: "Loading genre\u2026",
|
|
1815
|
-
content: /* @__PURE__ */ (0,
|
|
1816
|
-
/* @__PURE__ */ (0,
|
|
1817
|
-
/* @__PURE__ */ (0,
|
|
1818
|
-
/* @__PURE__ */ (0,
|
|
1802
|
+
content: /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("div", { className: "flex flex-col gap-3", "aria-busy": "true", "data-testid": "genre-detail-panel-skeleton", children: [
|
|
1803
|
+
/* @__PURE__ */ (0, import_jsx_runtime30.jsx)(import_ui10.Skeleton, { className: "h-6 w-2/3" }),
|
|
1804
|
+
/* @__PURE__ */ (0, import_jsx_runtime30.jsx)(import_ui10.Skeleton, { className: "h-4 w-full" }),
|
|
1805
|
+
/* @__PURE__ */ (0, import_jsx_runtime30.jsx)(import_ui10.Skeleton, { className: "h-4 w-3/4" })
|
|
1819
1806
|
] })
|
|
1820
1807
|
};
|
|
1821
1808
|
const selectGenre = (nodeId) => onSelectGenre(import_genre_tree20.GenreUuidSchema.parse(nodeId));
|
|
1822
|
-
const family = /* @__PURE__ */ (0,
|
|
1809
|
+
const family = /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
|
|
1823
1810
|
import_genre_tree_view4.GenreNodeFamily,
|
|
1824
1811
|
{
|
|
1825
1812
|
node: view.node,
|
|
@@ -1830,17 +1817,17 @@ function useGenreDetailContent({
|
|
|
1830
1817
|
onSelectNode: selectGenre
|
|
1831
1818
|
}
|
|
1832
1819
|
);
|
|
1833
|
-
const ancestors = /* @__PURE__ */ (0,
|
|
1820
|
+
const ancestors = /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(import_genre_tree_view4.GenreNodeAncestors, { ancestorNodes: view.ancestorNodes, onSelectNode: selectGenre });
|
|
1834
1821
|
return {
|
|
1835
1822
|
name: detail.name,
|
|
1836
1823
|
title: detail.name,
|
|
1837
1824
|
headerAccent: { background: view.fill, color: view.textColor },
|
|
1838
1825
|
aside: expanded ? ancestors : void 0,
|
|
1839
|
-
content: /* @__PURE__ */ (0,
|
|
1840
|
-
/* @__PURE__ */ (0,
|
|
1826
|
+
content: /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)(import_jsx_runtime30.Fragment, { children: [
|
|
1827
|
+
/* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
|
|
1841
1828
|
GenreInfoPanelBody,
|
|
1842
1829
|
{
|
|
1843
|
-
family: /* @__PURE__ */ (0,
|
|
1830
|
+
family: /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)(import_jsx_runtime30.Fragment, { children: [
|
|
1844
1831
|
family,
|
|
1845
1832
|
!expanded && ancestors
|
|
1846
1833
|
] }),
|
|
@@ -1884,7 +1871,7 @@ function GenreDetailPanel({
|
|
|
1884
1871
|
expanded,
|
|
1885
1872
|
band: { onZoomIn, shareUrl, shareTarget: shareUrl ? shareTarget : void 0 }
|
|
1886
1873
|
});
|
|
1887
|
-
return /* @__PURE__ */ (0,
|
|
1874
|
+
return /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
|
|
1888
1875
|
import_ui10.DetailPanel,
|
|
1889
1876
|
{
|
|
1890
1877
|
side: "left",
|
|
@@ -1897,7 +1884,7 @@ function GenreDetailPanel({
|
|
|
1897
1884
|
edgeTab,
|
|
1898
1885
|
aside: panel.aside,
|
|
1899
1886
|
titleInSearch,
|
|
1900
|
-
headerActions: onExpandedChange ? /* @__PURE__ */ (0,
|
|
1887
|
+
headerActions: onExpandedChange ? /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(import_ui10.IconButton, { "aria-label": expanded ? "Shrink panel" : "Extend panel", onClick: () => onExpandedChange(!expanded), children: expanded ? /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(import_lucide_react9.Minimize2, { "aria-hidden": "true", className: "h-4 w-4" }) : /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(import_lucide_react9.Maximize2, { "aria-hidden": "true", className: "h-4 w-4" }) }) : void 0,
|
|
1901
1888
|
children: panel.content
|
|
1902
1889
|
}
|
|
1903
1890
|
);
|
|
@@ -1906,7 +1893,7 @@ function GenreDetailPanel({
|
|
|
1906
1893
|
// src/genre-tree/ChangeParentPopup.tsx
|
|
1907
1894
|
var import_react16 = require("react");
|
|
1908
1895
|
var import_genre_tree21 = require("@behindthemusictree/app-kit/genre-tree");
|
|
1909
|
-
var
|
|
1896
|
+
var import_jsx_runtime31 = require("react/jsx-runtime");
|
|
1910
1897
|
function ChangeParentPopup({
|
|
1911
1898
|
genrePlaylist,
|
|
1912
1899
|
genrePlaylists,
|
|
@@ -1941,12 +1928,12 @@ function ChangeParentPopup({
|
|
|
1941
1928
|
window.addEventListener("keydown", handleKeyDown);
|
|
1942
1929
|
return () => window.removeEventListener("keydown", handleKeyDown);
|
|
1943
1930
|
}, [onClose]);
|
|
1944
|
-
return /* @__PURE__ */ (0,
|
|
1945
|
-
/* @__PURE__ */ (0,
|
|
1931
|
+
return /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)(BasePopup_default, { title: `Change parent of ${genrePlaylist.name}`, onClose, showCancelButton: true, fitContent: true, children: [
|
|
1932
|
+
/* @__PURE__ */ (0, import_jsx_runtime31.jsxs)("p", { className: "mb-3 text-body text-[var(--color-text-muted)]", children: [
|
|
1946
1933
|
"Current parent: ",
|
|
1947
1934
|
genrePlaylist.parent?.name ?? "none"
|
|
1948
1935
|
] }),
|
|
1949
|
-
/* @__PURE__ */ (0,
|
|
1936
|
+
/* @__PURE__ */ (0, import_jsx_runtime31.jsx)("div", { "aria-busy": isPending, className: isPending ? "pointer-events-none opacity-60" : void 0, children: /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
|
|
1950
1937
|
GenreSearch,
|
|
1951
1938
|
{
|
|
1952
1939
|
genrePlaylists: candidates,
|
|
@@ -1954,7 +1941,7 @@ function ChangeParentPopup({
|
|
|
1954
1941
|
placeholder: "Search a new parent\u2026"
|
|
1955
1942
|
}
|
|
1956
1943
|
) }),
|
|
1957
|
-
formErrors.length > 0 && /* @__PURE__ */ (0,
|
|
1944
|
+
formErrors.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("p", { role: "alert", className: "mt-3 text-body text-[var(--color-red-500)]", children: formErrors.map(({ message }) => message).join(" ") })
|
|
1958
1945
|
] });
|
|
1959
1946
|
}
|
|
1960
1947
|
|
|
@@ -1967,7 +1954,7 @@ var import_lucide_react10 = require("lucide-react");
|
|
|
1967
1954
|
var import_ui11 = require("@behindthemusictree/ui");
|
|
1968
1955
|
var import_genre_tree22 = require("@behindthemusictree/app-kit/genre-tree");
|
|
1969
1956
|
var import_player7 = require("@behindthemusictree/app-kit/player");
|
|
1970
|
-
var
|
|
1957
|
+
var import_jsx_runtime32 = require("react/jsx-runtime");
|
|
1971
1958
|
function ArtistActionBand({ artist, share }) {
|
|
1972
1959
|
const { trackList, playNewTrackListFromArtist } = (0, import_genre_tree22.useTrackList)();
|
|
1973
1960
|
const { isPlaying, setIsPlaying } = (0, import_player7.usePlayer)();
|
|
@@ -1983,11 +1970,11 @@ function ArtistActionBand({ artist, share }) {
|
|
|
1983
1970
|
console.error("Failed to load artist tracks:", error);
|
|
1984
1971
|
});
|
|
1985
1972
|
};
|
|
1986
|
-
return /* @__PURE__ */ (0,
|
|
1987
|
-
/* @__PURE__ */ (0,
|
|
1973
|
+
return /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(import_ui11.PanelBleed, { children: /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)(import_ui11.ActionBand, { children: [
|
|
1974
|
+
/* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
|
|
1988
1975
|
import_ui11.ActionButton,
|
|
1989
1976
|
{
|
|
1990
|
-
icon: playing ? /* @__PURE__ */ (0,
|
|
1977
|
+
icon: playing ? /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(import_lucide_react10.Pause, { "aria-hidden": "true", className: "w-5 h-5" }) : /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(import_lucide_react10.Play, { "aria-hidden": "true", className: "w-5 h-5" }),
|
|
1991
1978
|
label: playing ? "Pause" : "Play",
|
|
1992
1979
|
caption: String(artist.playableTracksCount),
|
|
1993
1980
|
disabled: artist.playableTracksCount === 0,
|
|
@@ -2006,7 +1993,7 @@ var import_ui13 = require("@behindthemusictree/ui");
|
|
|
2006
1993
|
var import_lucide_react11 = require("lucide-react");
|
|
2007
1994
|
var import_si3 = require("react-icons/si");
|
|
2008
1995
|
var import_ui12 = require("@behindthemusictree/ui");
|
|
2009
|
-
var
|
|
1996
|
+
var import_jsx_runtime33 = require("react/jsx-runtime");
|
|
2010
1997
|
var LINK_KINDS = {
|
|
2011
1998
|
official: { label: "Official website", Icon: import_lucide_react11.Globe },
|
|
2012
1999
|
wikipedia: { label: "Wikipedia", Icon: import_si3.SiWikipedia },
|
|
@@ -2043,7 +2030,7 @@ function artistLinks(artist) {
|
|
|
2043
2030
|
return links;
|
|
2044
2031
|
}
|
|
2045
2032
|
function ArtistLinks({ links }) {
|
|
2046
|
-
return /* @__PURE__ */ (0,
|
|
2033
|
+
return /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("ul", { className: "flex flex-wrap gap-1.5", children: links.map(({ key, url, Icon, label }) => /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(import_ui12.Chip, { href: url, icon: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(Icon, { className: "h-3.5 w-3.5 shrink-0", "aria-hidden": "true" }), children: label }) }, key)) });
|
|
2047
2034
|
}
|
|
2048
2035
|
|
|
2049
2036
|
// src/genre-tree/artist/formatYears.ts
|
|
@@ -2054,7 +2041,7 @@ function formatYears(beginYear, endYear, ended) {
|
|
|
2054
2041
|
}
|
|
2055
2042
|
|
|
2056
2043
|
// src/genre-tree/artist/ArtistHeader.tsx
|
|
2057
|
-
var
|
|
2044
|
+
var import_jsx_runtime34 = require("react/jsx-runtime");
|
|
2058
2045
|
var countryNames = new Intl.DisplayNames(["en"], { type: "region" });
|
|
2059
2046
|
function ArtistHeader({ artist }) {
|
|
2060
2047
|
const fields = [];
|
|
@@ -2064,35 +2051,35 @@ function ArtistHeader({ artist }) {
|
|
|
2064
2051
|
const years = formatYears(artist.beginYear, artist.endYear, artist.ended);
|
|
2065
2052
|
if (years) fields.push({ label: "Active", value: years });
|
|
2066
2053
|
const links = artistLinks(artist);
|
|
2067
|
-
if (links.length > 0) fields.push({ label: "Links", value: /* @__PURE__ */ (0,
|
|
2054
|
+
if (links.length > 0) fields.push({ label: "Links", value: /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(ArtistLinks, { links }) });
|
|
2068
2055
|
if (fields.length === 0) return null;
|
|
2069
|
-
return /* @__PURE__ */ (0,
|
|
2056
|
+
return /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(import_ui13.FieldList, { items: fields });
|
|
2070
2057
|
}
|
|
2071
2058
|
|
|
2072
2059
|
// src/genre-tree/artist/ArtistPhoto.tsx
|
|
2073
|
-
var
|
|
2060
|
+
var import_jsx_runtime35 = require("react/jsx-runtime");
|
|
2074
2061
|
function ExternalLink({ href, children }) {
|
|
2075
|
-
return /* @__PURE__ */ (0,
|
|
2062
|
+
return /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("a", { href, target: "_blank", rel: "noopener noreferrer", className: "underline-offset-2 hover:underline", children });
|
|
2076
2063
|
}
|
|
2077
2064
|
function ArtistPhoto({ image, name }) {
|
|
2078
|
-
return /* @__PURE__ */ (0,
|
|
2079
|
-
/* @__PURE__ */ (0,
|
|
2080
|
-
/* @__PURE__ */ (0,
|
|
2065
|
+
return /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("figure", { className: "flex flex-col gap-1.5", children: [
|
|
2066
|
+
/* @__PURE__ */ (0, import_jsx_runtime35.jsx)("img", { src: image.url, alt: name, className: "h-64 w-full object-contain bg-[var(--color-surface-muted)] rounded" }),
|
|
2067
|
+
/* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("figcaption", { className: "text-caption text-[var(--color-text-muted)]", children: [
|
|
2081
2068
|
"Photo: ",
|
|
2082
|
-
/* @__PURE__ */ (0,
|
|
2069
|
+
/* @__PURE__ */ (0, import_jsx_runtime35.jsx)(ExternalLink, { href: image.pageUrl, children: image.author ?? "Wikimedia Commons" }),
|
|
2083
2070
|
",",
|
|
2084
2071
|
" ",
|
|
2085
|
-
image.licenseUrl ? /* @__PURE__ */ (0,
|
|
2072
|
+
image.licenseUrl ? /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(ExternalLink, { href: image.licenseUrl, children: image.license }) : image.license
|
|
2086
2073
|
] })
|
|
2087
2074
|
] });
|
|
2088
2075
|
}
|
|
2089
2076
|
|
|
2090
2077
|
// src/genre-tree/artist/ArtistMembers.tsx
|
|
2091
2078
|
var import_ui14 = require("@behindthemusictree/ui");
|
|
2092
|
-
var
|
|
2079
|
+
var import_jsx_runtime36 = require("react/jsx-runtime");
|
|
2093
2080
|
function MembershipList({ title, memberships, renderArtistLink }) {
|
|
2094
2081
|
if (memberships.length === 0) return null;
|
|
2095
|
-
return /* @__PURE__ */ (0,
|
|
2082
|
+
return /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(import_ui14.PanelGroup, { title, children: /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("ul", { children: memberships.map((membership, index) => {
|
|
2096
2083
|
const details = [
|
|
2097
2084
|
formatYears(membership.beginYear, membership.endYear, membership.ended),
|
|
2098
2085
|
...membership.roles
|
|
@@ -2100,9 +2087,9 @@ function MembershipList({ title, memberships, renderArtistLink }) {
|
|
|
2100
2087
|
const detailsText = details.filter(Boolean).join(" \xB7 ");
|
|
2101
2088
|
return (
|
|
2102
2089
|
// A member can have several periods in the same group.
|
|
2103
|
-
/* @__PURE__ */ (0,
|
|
2104
|
-
/* @__PURE__ */ (0,
|
|
2105
|
-
detailsText && /* @__PURE__ */ (0,
|
|
2090
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("li", { className: "truncate py-0.5", title: detailsText || void 0, children: [
|
|
2091
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)("span", { className: "font-medium text-[var(--color-text)]", children: renderArtistLink(membership.artist) }),
|
|
2092
|
+
detailsText && /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("span", { className: "text-[var(--color-text-muted)]", children: [
|
|
2106
2093
|
" \u2014 ",
|
|
2107
2094
|
detailsText
|
|
2108
2095
|
] })
|
|
@@ -2113,9 +2100,9 @@ function MembershipList({ title, memberships, renderArtistLink }) {
|
|
|
2113
2100
|
function ArtistMembers({ title, memberships, renderArtistLink }) {
|
|
2114
2101
|
if (memberships.length === 0) return null;
|
|
2115
2102
|
const isCurrent = (membership) => !membership.ended && membership.endYear === null;
|
|
2116
|
-
return /* @__PURE__ */ (0,
|
|
2117
|
-
/* @__PURE__ */ (0,
|
|
2118
|
-
/* @__PURE__ */ (0,
|
|
2103
|
+
return /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)(import_ui14.PanelSection, { title, children: [
|
|
2104
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)(MembershipList, { title: "Current", memberships: memberships.filter(isCurrent), renderArtistLink }),
|
|
2105
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
|
|
2119
2106
|
MembershipList,
|
|
2120
2107
|
{
|
|
2121
2108
|
title: "Past",
|
|
@@ -2128,7 +2115,7 @@ function ArtistMembers({ title, memberships, renderArtistLink }) {
|
|
|
2128
2115
|
|
|
2129
2116
|
// src/genre-tree/artist/ArtistDiscography.tsx
|
|
2130
2117
|
var import_ui15 = require("@behindthemusictree/ui");
|
|
2131
|
-
var
|
|
2118
|
+
var import_jsx_runtime37 = require("react/jsx-runtime");
|
|
2132
2119
|
var GROUPS = ["Albums", "EPs", "Singles", "Live", "Compilations", "Other"];
|
|
2133
2120
|
var PRIMARY_GROUPS = { album: "Albums", ep: "EPs", single: "Singles" };
|
|
2134
2121
|
function discographyGroup({ primaryType, secondaryTypes }) {
|
|
@@ -2148,12 +2135,12 @@ function byYear(a, b) {
|
|
|
2148
2135
|
function ArtistDiscography({ albums }) {
|
|
2149
2136
|
if (albums.length === 0) return null;
|
|
2150
2137
|
const sorted = [...albums].sort(byYear);
|
|
2151
|
-
return /* @__PURE__ */ (0,
|
|
2138
|
+
return /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(import_ui15.PanelSection, { title: "Discography", children: GROUPS.map((group) => {
|
|
2152
2139
|
const groupAlbums = sorted.filter((album) => discographyGroup(album) === group);
|
|
2153
2140
|
if (groupAlbums.length === 0) return null;
|
|
2154
|
-
return /* @__PURE__ */ (0,
|
|
2155
|
-
/* @__PURE__ */ (0,
|
|
2156
|
-
/* @__PURE__ */ (0,
|
|
2141
|
+
return /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(import_ui15.PanelGroup, { title: group, children: /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("ul", { children: groupAlbums.map((album) => /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)("li", { className: "grid grid-cols-[2.5rem_minmax(0,1fr)] gap-2 py-0.5", children: [
|
|
2142
|
+
/* @__PURE__ */ (0, import_jsx_runtime37.jsx)("span", { className: "tabular-nums text-[var(--color-text-muted)]", children: album.year ?? "\u2014" }),
|
|
2143
|
+
/* @__PURE__ */ (0, import_jsx_runtime37.jsx)("span", { className: "truncate text-[var(--color-text)]", title: album.name, children: album.name })
|
|
2157
2144
|
] }, album.uuid)) }) }, group);
|
|
2158
2145
|
}) });
|
|
2159
2146
|
}
|
|
@@ -2161,11 +2148,10 @@ function ArtistDiscography({ albums }) {
|
|
|
2161
2148
|
// src/genre-tree/artist/ArtistSongs.tsx
|
|
2162
2149
|
var import_react17 = require("react");
|
|
2163
2150
|
var import_react_query2 = require("@tanstack/react-query");
|
|
2164
|
-
var import_lucide_react12 = require("lucide-react");
|
|
2165
2151
|
var import_ui16 = require("@behindthemusictree/ui");
|
|
2166
2152
|
var import_player11 = require("@behindthemusictree/app-kit/player");
|
|
2167
2153
|
var import_genre_tree26 = require("@behindthemusictree/app-kit/genre-tree");
|
|
2168
|
-
var
|
|
2154
|
+
var import_transport6 = require("@behindthemusictree/app-kit/transport");
|
|
2169
2155
|
|
|
2170
2156
|
// src/genre-tree/track-list-sidebar/TrackItem.tsx
|
|
2171
2157
|
var import_player10 = require("@behindthemusictree/app-kit/player");
|
|
@@ -2175,7 +2161,7 @@ var import_genre_tree23 = require("@behindthemusictree/app-kit/genre-tree");
|
|
|
2175
2161
|
var import_fa3 = require("react-icons/fa");
|
|
2176
2162
|
var import_player8 = require("@behindthemusictree/app-kit/player");
|
|
2177
2163
|
var import_player9 = require("@behindthemusictree/app-kit/player");
|
|
2178
|
-
var
|
|
2164
|
+
var import_jsx_runtime38 = require("react/jsx-runtime");
|
|
2179
2165
|
function TrackPositionPlayPause({
|
|
2180
2166
|
position,
|
|
2181
2167
|
uuid,
|
|
@@ -2189,14 +2175,14 @@ function TrackPositionPlayPause({
|
|
|
2189
2175
|
const isPlaying = isThisTrack && isConfirmedPlayable && playState === import_player9.PlayStates.PLAYING;
|
|
2190
2176
|
const isPaused = isThisTrack && isConfirmedPlayable && playState === import_player9.PlayStates.PAUSED;
|
|
2191
2177
|
const isCurrentTrackActive = isPlaying || isPaused;
|
|
2192
|
-
return /* @__PURE__ */ (0,
|
|
2178
|
+
return /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)(
|
|
2193
2179
|
"div",
|
|
2194
2180
|
{
|
|
2195
2181
|
className: "track-position-play-pause relative flex items-center justify-center gap-2 text-lg w-16 cursor-pointer",
|
|
2196
2182
|
style: { minWidth: "4rem", maxWidth: "4rem" },
|
|
2197
2183
|
onClick: handlePlayPauseClick,
|
|
2198
2184
|
children: [
|
|
2199
|
-
/* @__PURE__ */ (0,
|
|
2185
|
+
/* @__PURE__ */ (0, import_jsx_runtime38.jsx)("div", { className: "track-position-play-pause__status group-hover:hidden flex items-center justify-center", children: isAwaitingPlayback ? /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("span", { className: "track-position-play-pause__spinner", role: "status", "aria-label": "Loading track" }) : isCurrentTrackActive ? /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)(
|
|
2200
2186
|
"span",
|
|
2201
2187
|
{
|
|
2202
2188
|
className: "track-position-play-pause__bars",
|
|
@@ -2204,18 +2190,18 @@ function TrackPositionPlayPause({
|
|
|
2204
2190
|
role: "img",
|
|
2205
2191
|
"aria-label": isPlaying ? "Playing" : "Paused",
|
|
2206
2192
|
children: [
|
|
2207
|
-
/* @__PURE__ */ (0,
|
|
2208
|
-
/* @__PURE__ */ (0,
|
|
2209
|
-
/* @__PURE__ */ (0,
|
|
2193
|
+
/* @__PURE__ */ (0, import_jsx_runtime38.jsx)("span", { className: "track-position-play-pause__bar" }),
|
|
2194
|
+
/* @__PURE__ */ (0, import_jsx_runtime38.jsx)("span", { className: "track-position-play-pause__bar" }),
|
|
2195
|
+
/* @__PURE__ */ (0, import_jsx_runtime38.jsx)("span", { className: "track-position-play-pause__bar" })
|
|
2210
2196
|
]
|
|
2211
2197
|
}
|
|
2212
2198
|
) : position }),
|
|
2213
|
-
/* @__PURE__ */ (0,
|
|
2199
|
+
/* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
|
|
2214
2200
|
"div",
|
|
2215
2201
|
{
|
|
2216
2202
|
className: `hidden group-hover:flex items-center justify-center ${isCurrentTrackActive ? "" : "absolute inset-0"}`,
|
|
2217
2203
|
"aria-hidden": "true",
|
|
2218
|
-
children: isAwaitingPlayback ? /* @__PURE__ */ (0,
|
|
2204
|
+
children: isAwaitingPlayback ? /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("span", { className: "track-position-play-pause__spinner" }) : isPlaying ? /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(import_fa3.FaPause, {}) : /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(import_fa3.FaPlay, {})
|
|
2219
2205
|
}
|
|
2220
2206
|
)
|
|
2221
2207
|
]
|
|
@@ -2226,7 +2212,7 @@ function TrackPositionPlayPause({
|
|
|
2226
2212
|
// src/genre-tree/track-list-sidebar/TrackItem.tsx
|
|
2227
2213
|
var import_genre_tree24 = require("@behindthemusictree/app-kit/genre-tree");
|
|
2228
2214
|
var import_genre_tree25 = require("@behindthemusictree/app-kit/genre-tree");
|
|
2229
|
-
var
|
|
2215
|
+
var import_jsx_runtime39 = require("react/jsx-runtime");
|
|
2230
2216
|
function TrackItem({
|
|
2231
2217
|
track,
|
|
2232
2218
|
position,
|
|
@@ -2250,12 +2236,12 @@ function TrackItem({
|
|
|
2250
2236
|
loadTrackForPlayer(track.uuid);
|
|
2251
2237
|
}
|
|
2252
2238
|
};
|
|
2253
|
-
return /* @__PURE__ */ (0,
|
|
2239
|
+
return /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)(
|
|
2254
2240
|
"div",
|
|
2255
2241
|
{
|
|
2256
2242
|
className: `track-item flex h-14 text-[var(--color-text)] ${isUnplayable ? "opacity-50" : "hover:bg-[var(--color-surface-muted)] group"}`,
|
|
2257
2243
|
children: [
|
|
2258
|
-
isUnplayable ? /* @__PURE__ */ (0,
|
|
2244
|
+
isUnplayable ? /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
|
|
2259
2245
|
"div",
|
|
2260
2246
|
{
|
|
2261
2247
|
className: "flex items-center justify-center text-lg w-16",
|
|
@@ -2263,7 +2249,7 @@ function TrackItem({
|
|
|
2263
2249
|
"aria-disabled": "true",
|
|
2264
2250
|
children: position
|
|
2265
2251
|
}
|
|
2266
|
-
) : /* @__PURE__ */ (0,
|
|
2252
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
|
|
2267
2253
|
TrackPositionPlayPause,
|
|
2268
2254
|
{
|
|
2269
2255
|
position,
|
|
@@ -2272,12 +2258,12 @@ function TrackItem({
|
|
|
2272
2258
|
isSelected: selectedTrack?.uuid === track.uuid
|
|
2273
2259
|
}
|
|
2274
2260
|
),
|
|
2275
|
-
/* @__PURE__ */ (0,
|
|
2276
|
-
/* @__PURE__ */ (0,
|
|
2277
|
-
track.artists && track.artists.length > 0 ? /* @__PURE__ */ (0,
|
|
2261
|
+
/* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("div", { className: "title-artist-container flex flex-col items-start justify-center min-w-0 flex-1", children: [
|
|
2262
|
+
/* @__PURE__ */ (0, import_jsx_runtime39.jsx)("div", { className: "flex max-w-full items-center gap-2", children: /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("div", { className: "title text-lg font-bold text-[var(--color-text)] max-w-full truncate", children: renderSongLink ? renderSongLink(track) : (0, import_genre_tree24.isSong)(track) ? /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(MusicBrainzRecordingLink, { song: track, className: "hover:underline focus-visible:underline", children: track.title }) : track.title }) }),
|
|
2263
|
+
track.artists && track.artists.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("div", { className: "artist text-base max-w-full truncate text-[var(--color-text-muted)]", children: /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(import_genre_tree25.ArtistNames, { artists: track.artists, renderArtistLink }) }) : ""
|
|
2278
2264
|
] }),
|
|
2279
|
-
/* @__PURE__ */ (0,
|
|
2280
|
-
renderDuration && /* @__PURE__ */ (0,
|
|
2265
|
+
/* @__PURE__ */ (0, import_jsx_runtime39.jsx)("div", { className: "genre-name-container flex items-center justify-start w-[21.6%] min-w-0 shrink-0", children: track.genre ? /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("div", { className: "genre-name max-w-full whitespace-normal break-words p-1 text-caption font-bold", children: track.genre.name }) : "" }),
|
|
2266
|
+
renderDuration && /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
|
|
2281
2267
|
"div",
|
|
2282
2268
|
{
|
|
2283
2269
|
className: "duration flex text-base w-16 items-center justify-center",
|
|
@@ -2285,15 +2271,15 @@ function TrackItem({
|
|
|
2285
2271
|
children: renderDuration(track)
|
|
2286
2272
|
}
|
|
2287
2273
|
),
|
|
2288
|
-
renderActions && /* @__PURE__ */ (0,
|
|
2274
|
+
renderActions && /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("div", { className: "edit flex text-base w-6 items-center justify-center mr-2 cursor-pointer", children: renderActions(track) })
|
|
2289
2275
|
]
|
|
2290
2276
|
}
|
|
2291
2277
|
);
|
|
2292
2278
|
}
|
|
2293
2279
|
|
|
2294
2280
|
// src/genre-tree/artist/ArtistSongs.tsx
|
|
2295
|
-
var
|
|
2296
|
-
var SongPageSchema2 = (0,
|
|
2281
|
+
var import_jsx_runtime40 = require("react/jsx-runtime");
|
|
2282
|
+
var SongPageSchema2 = (0, import_transport6.PaginatedResponseSchema)(import_genre_tree26.SongDetailedSchema);
|
|
2297
2283
|
var SORTS = [
|
|
2298
2284
|
{ ordering: "title", label: "Title" },
|
|
2299
2285
|
{ ordering: "-albumYear", label: "Year" }
|
|
@@ -2303,7 +2289,7 @@ function ArtistSongs({ artist, getBackendBaseUrl, renderArtistLink, renderSongLi
|
|
|
2303
2289
|
const [ordering, setOrdering] = (0, import_react17.useState)("title");
|
|
2304
2290
|
const { playNewTrackListFromArtist } = (0, import_genre_tree26.useTrackList)();
|
|
2305
2291
|
const { playerTrackObject } = (0, import_player11.usePlayer)();
|
|
2306
|
-
const { data, isPending, isError } = (0,
|
|
2292
|
+
const { data, isPending, isError } = (0, import_transport6.usePlaybackQuery)({
|
|
2307
2293
|
getBackendBaseUrl,
|
|
2308
2294
|
queryKey: ["referenceSongs", "artist", artist.uuid, ordering, page],
|
|
2309
2295
|
queryFn: (fetchBound) => fetchBound(import_genre_tree26.libraryEndpoints.reference.songs.list(), true, false, void 0, {
|
|
@@ -2325,36 +2311,22 @@ function ArtistSongs({ artist, getBackendBaseUrl, renderArtistLink, renderSongLi
|
|
|
2325
2311
|
event.stopPropagation();
|
|
2326
2312
|
void play(song.uuid);
|
|
2327
2313
|
};
|
|
2328
|
-
return /* @__PURE__ */ (0,
|
|
2329
|
-
/* @__PURE__ */ (0,
|
|
2330
|
-
|
|
2331
|
-
|
|
2332
|
-
|
|
2333
|
-
|
|
2334
|
-
|
|
2335
|
-
|
|
2336
|
-
|
|
2337
|
-
/* @__PURE__ */ (0, import_jsx_runtime39.jsx)(import_lucide_react12.Play, { className: "h-3.5 w-3.5", "aria-hidden": "true" }),
|
|
2338
|
-
"Play all"
|
|
2339
|
-
]
|
|
2340
|
-
}
|
|
2341
|
-
),
|
|
2342
|
-
/* @__PURE__ */ (0, import_jsx_runtime39.jsx)("div", { role: "group", "aria-label": "Sort songs by", className: "flex gap-1 text-caption", children: SORTS.map((sort) => /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
|
|
2343
|
-
"button",
|
|
2344
|
-
{
|
|
2345
|
-
type: "button",
|
|
2346
|
-
"aria-pressed": ordering === sort.ordering,
|
|
2347
|
-
onClick: () => {
|
|
2348
|
-
setOrdering(sort.ordering);
|
|
2349
|
-
setPage(1);
|
|
2350
|
-
},
|
|
2351
|
-
className: "px-2.5 py-0.5 text-[var(--color-text)] rounded-full hover:bg-[var(--color-surface-muted)] aria-pressed:bg-gray-900 aria-pressed:text-white",
|
|
2352
|
-
children: sort.label
|
|
2314
|
+
return /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(import_ui16.PanelSection, { title: "Songs", children: isPending ? /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(import_ui16.Skeleton, { className: "h-14", "aria-busy": "true" }) : isError ? /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("p", { className: "text-red-600", children: "Could not load songs." }) : data.results.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("p", { className: "text-[var(--color-text-muted)]", children: "No songs yet." }) : /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)(import_jsx_runtime40.Fragment, { children: [
|
|
2315
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsx)("div", { className: "flex flex-wrap items-center justify-end gap-2 mb-2", children: /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("div", { role: "group", "aria-label": "Sort songs by", className: "flex gap-1 text-caption", children: SORTS.map((sort) => /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
|
|
2316
|
+
"button",
|
|
2317
|
+
{
|
|
2318
|
+
type: "button",
|
|
2319
|
+
"aria-pressed": ordering === sort.ordering,
|
|
2320
|
+
onClick: () => {
|
|
2321
|
+
setOrdering(sort.ordering);
|
|
2322
|
+
setPage(1);
|
|
2353
2323
|
},
|
|
2354
|
-
|
|
2355
|
-
|
|
2356
|
-
|
|
2357
|
-
|
|
2324
|
+
className: "px-2.5 py-0.5 text-[var(--color-text)] rounded-full hover:bg-[var(--color-surface-muted)] aria-pressed:bg-gray-900 aria-pressed:text-white",
|
|
2325
|
+
children: sort.label
|
|
2326
|
+
},
|
|
2327
|
+
sort.ordering
|
|
2328
|
+
)) }) }),
|
|
2329
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsx)("ul", { className: "overflow-hidden mb-2 bg-zinc-950 rounded-lg", children: data.results.map((song, index) => /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("li", { onClickCapture: (event) => handleRowClickCapture(event, song), children: /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
|
|
2358
2330
|
TrackItem,
|
|
2359
2331
|
{
|
|
2360
2332
|
track: song,
|
|
@@ -2363,12 +2335,12 @@ function ArtistSongs({ artist, getBackendBaseUrl, renderArtistLink, renderSongLi
|
|
|
2363
2335
|
renderSongLink
|
|
2364
2336
|
}
|
|
2365
2337
|
) }, song.uuid)) }),
|
|
2366
|
-
/* @__PURE__ */ (0,
|
|
2338
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsx)(import_ui16.Pagination, { currentPage: page, totalPages: data.totalPages, onPageChange: setPage })
|
|
2367
2339
|
] }) });
|
|
2368
2340
|
}
|
|
2369
2341
|
|
|
2370
2342
|
// src/genre-tree/artist/useArtistPanel.tsx
|
|
2371
|
-
var
|
|
2343
|
+
var import_jsx_runtime41 = require("react/jsx-runtime");
|
|
2372
2344
|
function useArtistPanel({
|
|
2373
2345
|
uuid,
|
|
2374
2346
|
scope,
|
|
@@ -2389,26 +2361,26 @@ function useArtistPanel({
|
|
|
2389
2361
|
return {
|
|
2390
2362
|
...panel,
|
|
2391
2363
|
title: "Artist",
|
|
2392
|
-
content: /* @__PURE__ */ (0,
|
|
2393
|
-
/* @__PURE__ */ (0,
|
|
2394
|
-
/* @__PURE__ */ (0,
|
|
2395
|
-
/* @__PURE__ */ (0,
|
|
2396
|
-
/* @__PURE__ */ (0,
|
|
2397
|
-
/* @__PURE__ */ (0,
|
|
2398
|
-
/* @__PURE__ */ (0,
|
|
2364
|
+
content: /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { "aria-busy": "true", className: "flex flex-col gap-2.5", children: [
|
|
2365
|
+
/* @__PURE__ */ (0, import_jsx_runtime41.jsx)(import_ui17.Skeleton, { className: "h-3 w-16" }),
|
|
2366
|
+
/* @__PURE__ */ (0, import_jsx_runtime41.jsx)(import_ui17.Skeleton, { className: "h-4 w-32" }),
|
|
2367
|
+
/* @__PURE__ */ (0, import_jsx_runtime41.jsx)(import_ui17.Skeleton, { className: "h-3 w-16" }),
|
|
2368
|
+
/* @__PURE__ */ (0, import_jsx_runtime41.jsx)(import_ui17.Skeleton, { className: "h-4 w-24" }),
|
|
2369
|
+
/* @__PURE__ */ (0, import_jsx_runtime41.jsx)(import_ui17.Skeleton, { className: "h-16 mt-2.5" }),
|
|
2370
|
+
/* @__PURE__ */ (0, import_jsx_runtime41.jsx)(import_ui17.Skeleton, { className: "h-16" })
|
|
2399
2371
|
] })
|
|
2400
2372
|
};
|
|
2401
2373
|
case "not-found":
|
|
2402
2374
|
return {
|
|
2403
2375
|
...panel,
|
|
2404
2376
|
title: "Artist not found",
|
|
2405
|
-
content: /* @__PURE__ */ (0,
|
|
2377
|
+
content: /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("p", { className: "text-[var(--color-text-muted)]", children: "This artist does not exist." })
|
|
2406
2378
|
};
|
|
2407
2379
|
case "error":
|
|
2408
2380
|
return {
|
|
2409
2381
|
...panel,
|
|
2410
2382
|
title: "Artist",
|
|
2411
|
-
content: /* @__PURE__ */ (0,
|
|
2383
|
+
content: /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("p", { className: "text-red-600", children: "Could not load this artist." })
|
|
2412
2384
|
};
|
|
2413
2385
|
case "success": {
|
|
2414
2386
|
const { artist } = result;
|
|
@@ -2417,19 +2389,19 @@ function useArtistPanel({
|
|
|
2417
2389
|
return {
|
|
2418
2390
|
...panel,
|
|
2419
2391
|
title: artist.name,
|
|
2420
|
-
content: /* @__PURE__ */ (0,
|
|
2421
|
-
/* @__PURE__ */ (0,
|
|
2392
|
+
content: /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)(import_jsx_runtime41.Fragment, { children: [
|
|
2393
|
+
/* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
|
|
2422
2394
|
ArtistActionBand,
|
|
2423
2395
|
{
|
|
2424
2396
|
artist,
|
|
2425
|
-
share: shareTarget && shareUrl ? /* @__PURE__ */ (0,
|
|
2397
|
+
share: shareTarget && shareUrl ? /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(ShareActionButton, { target: shareTarget, url: shareUrl }) : void 0
|
|
2426
2398
|
}
|
|
2427
2399
|
),
|
|
2428
|
-
artist.image && /* @__PURE__ */ (0,
|
|
2429
|
-
/* @__PURE__ */ (0,
|
|
2430
|
-
/* @__PURE__ */ (0,
|
|
2431
|
-
/* @__PURE__ */ (0,
|
|
2432
|
-
artist.tracksCount > 0 && /* @__PURE__ */ (0,
|
|
2400
|
+
artist.image && /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(ArtistPhoto, { image: artist.image, name: artist.name }),
|
|
2401
|
+
/* @__PURE__ */ (0, import_jsx_runtime41.jsx)(ArtistHeader, { artist }),
|
|
2402
|
+
/* @__PURE__ */ (0, import_jsx_runtime41.jsx)(ArtistMembers, { title: "Members", memberships: artist.members, renderArtistLink }),
|
|
2403
|
+
/* @__PURE__ */ (0, import_jsx_runtime41.jsx)(ArtistMembers, { title: "Member of", memberships: artist.memberOf, renderArtistLink }),
|
|
2404
|
+
artist.tracksCount > 0 && /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
|
|
2433
2405
|
ArtistSongs,
|
|
2434
2406
|
{
|
|
2435
2407
|
artist: { uuid: artist.uuid, name: artist.name },
|
|
@@ -2439,7 +2411,7 @@ function useArtistPanel({
|
|
|
2439
2411
|
}
|
|
2440
2412
|
)
|
|
2441
2413
|
] }),
|
|
2442
|
-
extraContent: artist.albums.length > 0 ? /* @__PURE__ */ (0,
|
|
2414
|
+
extraContent: artist.albums.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(ArtistDiscography, { albums: artist.albums }) : void 0
|
|
2443
2415
|
};
|
|
2444
2416
|
}
|
|
2445
2417
|
}
|
|
@@ -2451,11 +2423,11 @@ var import_genre_tree29 = require("@behindthemusictree/app-kit/genre-tree");
|
|
|
2451
2423
|
|
|
2452
2424
|
// src/genre-tree/song/SongPanelContent.tsx
|
|
2453
2425
|
var import_react18 = require("react");
|
|
2454
|
-
var
|
|
2426
|
+
var import_lucide_react12 = require("lucide-react");
|
|
2455
2427
|
var import_ui18 = require("@behindthemusictree/ui");
|
|
2456
2428
|
var import_player12 = require("@behindthemusictree/app-kit/player");
|
|
2457
2429
|
var import_genre_tree28 = require("@behindthemusictree/app-kit/genre-tree");
|
|
2458
|
-
var
|
|
2430
|
+
var import_jsx_runtime42 = require("react/jsx-runtime");
|
|
2459
2431
|
var numberFormat = new Intl.NumberFormat("en");
|
|
2460
2432
|
var dateFormat = new Intl.DateTimeFormat("en", { dateStyle: "medium" });
|
|
2461
2433
|
var externalLink = "text-[var(--color-primary)] hover:underline focus-visible:underline";
|
|
@@ -2463,27 +2435,27 @@ function SongHistory({ uuid, getBackendBaseUrl }) {
|
|
|
2463
2435
|
const [open, setOpen] = (0, import_react18.useState)(false);
|
|
2464
2436
|
const history = (0, import_genre_tree28.useSongHistory)(uuid, getBackendBaseUrl, open);
|
|
2465
2437
|
let body = null;
|
|
2466
|
-
if (history.status === "loading") body = /* @__PURE__ */ (0,
|
|
2467
|
-
else if (history.status === "error") body = /* @__PURE__ */ (0,
|
|
2438
|
+
if (history.status === "loading") body = /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(import_ui18.Skeleton, { className: "h-10", "aria-busy": "true" });
|
|
2439
|
+
else if (history.status === "error") body = /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("p", { className: "text-red-600", children: "Could not load the history." });
|
|
2468
2440
|
else if (history.status === "success")
|
|
2469
|
-
body = history.entries.length === 0 ? /* @__PURE__ */ (0,
|
|
2470
|
-
/* @__PURE__ */ (0,
|
|
2471
|
-
entry.oldValue !== null || entry.newValue !== null ? /* @__PURE__ */ (0,
|
|
2441
|
+
body = history.entries.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("p", { className: "text-[var(--color-text-muted)]", children: "No changes yet." }) : /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("ul", { className: "divide-y divide-[var(--color-border)]", children: history.entries.map((entry) => /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("li", { className: "py-1.5 text-body", children: [
|
|
2442
|
+
/* @__PURE__ */ (0, import_jsx_runtime42.jsx)("span", { className: "font-medium", children: entry.action }),
|
|
2443
|
+
entry.oldValue !== null || entry.newValue !== null ? /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("span", { className: "text-[var(--color-text-muted)]", children: [
|
|
2472
2444
|
" ",
|
|
2473
2445
|
"\u2014 ",
|
|
2474
2446
|
entry.oldValue ?? "none",
|
|
2475
2447
|
" \u2192 ",
|
|
2476
2448
|
entry.newValue ?? "none"
|
|
2477
2449
|
] }) : null,
|
|
2478
|
-
/* @__PURE__ */ (0,
|
|
2450
|
+
/* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("span", { className: "block text-caption text-[var(--color-text-muted)]", children: [
|
|
2479
2451
|
entry.actorPseudo ?? "Anonymous",
|
|
2480
2452
|
" \xB7 ",
|
|
2481
2453
|
dateFormat.format(new Date(entry.createdOn))
|
|
2482
2454
|
] })
|
|
2483
2455
|
] }, entry.uuid)) });
|
|
2484
|
-
return /* @__PURE__ */ (0,
|
|
2485
|
-
/* @__PURE__ */ (0,
|
|
2486
|
-
/* @__PURE__ */ (0,
|
|
2456
|
+
return /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(import_ui18.PanelBleed, { padded: true, className: "border-t border-[var(--color-border)]", children: /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("details", { onToggle: (event) => setOpen(event.currentTarget.open), className: "pb-2.5", children: [
|
|
2457
|
+
/* @__PURE__ */ (0, import_jsx_runtime42.jsx)("summary", { className: `mt-2.5 cursor-pointer ${import_ui18.PANEL_LABEL_CLASS}`, children: "History" }),
|
|
2458
|
+
/* @__PURE__ */ (0, import_jsx_runtime42.jsx)("div", { className: "mt-1.5", children: body })
|
|
2487
2459
|
] }) });
|
|
2488
2460
|
}
|
|
2489
2461
|
function SongPanelContent(props) {
|
|
@@ -2502,13 +2474,13 @@ function SongPanelContent(props) {
|
|
|
2502
2474
|
const genre = song.genre;
|
|
2503
2475
|
fields.push({
|
|
2504
2476
|
label: "Genre",
|
|
2505
|
-
value: onSelectGenre ? /* @__PURE__ */ (0,
|
|
2506
|
-
index > 0 && /* @__PURE__ */ (0,
|
|
2507
|
-
/* @__PURE__ */ (0,
|
|
2477
|
+
value: onSelectGenre ? /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("button", { type: "button", onClick: () => onSelectGenre(genre), className: "hover:underline", children: genre.name }) : path ? /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("span", { className: "flex flex-wrap items-center gap-x-1", children: path.map((genrePlaylist, index) => /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("span", { children: [
|
|
2478
|
+
index > 0 && /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("span", { "aria-hidden": "true", children: "\u203A " }),
|
|
2479
|
+
/* @__PURE__ */ (0, import_jsx_runtime42.jsx)("button", { type: "button", onClick: () => props.onSelectGenrePlaylist?.(genrePlaylist), className: "hover:underline", children: genrePlaylist.name })
|
|
2508
2480
|
] }, genrePlaylist.uuid)) }) : song.genre.name
|
|
2509
2481
|
});
|
|
2510
2482
|
} else {
|
|
2511
|
-
fields.push({ label: "Genre", value: /* @__PURE__ */ (0,
|
|
2483
|
+
fields.push({ label: "Genre", value: /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("span", { className: "text-[var(--color-text-muted)]", children: "No genre" }) });
|
|
2512
2484
|
}
|
|
2513
2485
|
if (song.firstReleaseYear) fields.push({ label: "First released", value: song.firstReleaseYear });
|
|
2514
2486
|
const viewCount = song.youtubeVideo?.viewCount;
|
|
@@ -2518,11 +2490,11 @@ function SongPanelContent(props) {
|
|
|
2518
2490
|
const links = [];
|
|
2519
2491
|
if (musicBrainzUrl)
|
|
2520
2492
|
links.push(
|
|
2521
|
-
/* @__PURE__ */ (0,
|
|
2493
|
+
/* @__PURE__ */ (0, import_jsx_runtime42.jsx)("a", { href: musicBrainzUrl, target: "_blank", rel: "noopener noreferrer", className: externalLink, children: "MusicBrainz" }, "mb")
|
|
2522
2494
|
);
|
|
2523
2495
|
if (song.youtubeVideo)
|
|
2524
2496
|
links.push(
|
|
2525
|
-
/* @__PURE__ */ (0,
|
|
2497
|
+
/* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
|
|
2526
2498
|
"a",
|
|
2527
2499
|
{
|
|
2528
2500
|
href: `https://www.youtube.com/watch?v=${encodeURIComponent(song.youtubeVideo.id)}`,
|
|
@@ -2537,31 +2509,31 @@ function SongPanelContent(props) {
|
|
|
2537
2509
|
if (links.length > 0)
|
|
2538
2510
|
fields.push({
|
|
2539
2511
|
label: "Links",
|
|
2540
|
-
value: /* @__PURE__ */ (0,
|
|
2512
|
+
value: /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("span", { className: "flex gap-3", children: links })
|
|
2541
2513
|
});
|
|
2542
|
-
return /* @__PURE__ */ (0,
|
|
2543
|
-
/* @__PURE__ */ (0,
|
|
2544
|
-
/* @__PURE__ */ (0,
|
|
2514
|
+
return /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)(import_jsx_runtime42.Fragment, { children: [
|
|
2515
|
+
/* @__PURE__ */ (0, import_jsx_runtime42.jsx)(import_ui18.PanelBleed, { children: /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)(import_ui18.ActionBand, { children: [
|
|
2516
|
+
/* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
|
|
2545
2517
|
import_ui18.ActionButton,
|
|
2546
2518
|
{
|
|
2547
|
-
icon: isPlaying ? /* @__PURE__ */ (0,
|
|
2519
|
+
icon: isPlaying ? /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(import_lucide_react12.Pause, { "aria-hidden": "true", className: "w-5 h-5" }) : /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(import_lucide_react12.Play, { "aria-hidden": "true", className: "w-5 h-5" }),
|
|
2548
2520
|
label: isPlaying ? "Pause" : "Play",
|
|
2549
2521
|
disabled: !!unplayableReason,
|
|
2550
2522
|
title: unplayableReason ?? void 0,
|
|
2551
2523
|
onClick: () => isCurrent ? handlePlayPauseAction() : playNewTrackListFromTrackUuid(song, scope)
|
|
2552
2524
|
}
|
|
2553
2525
|
),
|
|
2554
|
-
shareUrl && /* @__PURE__ */ (0,
|
|
2526
|
+
shareUrl && /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(ShareActionButton, { target: shareTarget, url: shareUrl })
|
|
2555
2527
|
] }) }),
|
|
2556
|
-
song.artists && song.artists.length > 0 && /* @__PURE__ */ (0,
|
|
2557
|
-
/* @__PURE__ */ (0,
|
|
2558
|
-
song.essentialGenres && song.essentialGenres.length > 0 && /* @__PURE__ */ (0,
|
|
2559
|
-
/* @__PURE__ */ (0,
|
|
2528
|
+
song.artists && song.artists.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("p", { className: "text-[var(--color-text-muted)]", children: /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(import_genre_tree28.ArtistNames, { artists: song.artists, renderArtistLink }) }),
|
|
2529
|
+
/* @__PURE__ */ (0, import_jsx_runtime42.jsx)(import_ui18.FieldList, { items: fields }),
|
|
2530
|
+
song.essentialGenres && song.essentialGenres.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(import_ui18.PanelSection, { title: "Essential in", children: /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("ul", { children: song.essentialGenres.map((genre) => /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("li", { className: "py-0.5", children: genre.name }, genre.uuid)) }) }),
|
|
2531
|
+
/* @__PURE__ */ (0, import_jsx_runtime42.jsx)(SongHistory, { uuid: song.uuid, getBackendBaseUrl })
|
|
2560
2532
|
] });
|
|
2561
2533
|
}
|
|
2562
2534
|
|
|
2563
2535
|
// src/genre-tree/song/useSongPanel.tsx
|
|
2564
|
-
var
|
|
2536
|
+
var import_jsx_runtime43 = require("react/jsx-runtime");
|
|
2565
2537
|
function useSongPanel({
|
|
2566
2538
|
uuid,
|
|
2567
2539
|
scope,
|
|
@@ -2582,24 +2554,24 @@ function useSongPanel({
|
|
|
2582
2554
|
return {
|
|
2583
2555
|
...panel,
|
|
2584
2556
|
title: "Song",
|
|
2585
|
-
content: /* @__PURE__ */ (0,
|
|
2586
|
-
/* @__PURE__ */ (0,
|
|
2587
|
-
/* @__PURE__ */ (0,
|
|
2588
|
-
/* @__PURE__ */ (0,
|
|
2589
|
-
/* @__PURE__ */ (0,
|
|
2557
|
+
content: /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("div", { "aria-busy": "true", className: "flex flex-col gap-2.5", children: [
|
|
2558
|
+
/* @__PURE__ */ (0, import_jsx_runtime43.jsx)(import_ui19.Skeleton, { className: "h-3 w-16" }),
|
|
2559
|
+
/* @__PURE__ */ (0, import_jsx_runtime43.jsx)(import_ui19.Skeleton, { className: "h-4 w-32" }),
|
|
2560
|
+
/* @__PURE__ */ (0, import_jsx_runtime43.jsx)(import_ui19.Skeleton, { className: "h-3 w-16" }),
|
|
2561
|
+
/* @__PURE__ */ (0, import_jsx_runtime43.jsx)(import_ui19.Skeleton, { className: "h-4 w-24" })
|
|
2590
2562
|
] })
|
|
2591
2563
|
};
|
|
2592
2564
|
case "not-found":
|
|
2593
2565
|
return {
|
|
2594
2566
|
...panel,
|
|
2595
2567
|
title: "Song not found",
|
|
2596
|
-
content: /* @__PURE__ */ (0,
|
|
2568
|
+
content: /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("p", { className: "text-[var(--color-text-muted)]", children: "This song does not exist." })
|
|
2597
2569
|
};
|
|
2598
2570
|
case "error":
|
|
2599
2571
|
return {
|
|
2600
2572
|
...panel,
|
|
2601
2573
|
title: "Song",
|
|
2602
|
-
content: /* @__PURE__ */ (0,
|
|
2574
|
+
content: /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("p", { className: "text-red-600", children: "Could not load this song." })
|
|
2603
2575
|
};
|
|
2604
2576
|
case "success": {
|
|
2605
2577
|
const { song } = result;
|
|
@@ -2607,7 +2579,7 @@ function useSongPanel({
|
|
|
2607
2579
|
return {
|
|
2608
2580
|
...panel,
|
|
2609
2581
|
title: song.title,
|
|
2610
|
-
content: /* @__PURE__ */ (0,
|
|
2582
|
+
content: /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
|
|
2611
2583
|
SongPanelContent,
|
|
2612
2584
|
{
|
|
2613
2585
|
song,
|
|
@@ -2660,12 +2632,12 @@ function useEntityPanel({
|
|
|
2660
2632
|
// src/genre-tree/SizeMetricToggle.tsx
|
|
2661
2633
|
var import_md = require("react-icons/md");
|
|
2662
2634
|
var import_ui20 = require("@behindthemusictree/ui");
|
|
2663
|
-
var
|
|
2635
|
+
var import_jsx_runtime44 = require("react/jsx-runtime");
|
|
2664
2636
|
function SizeMetricToggle({
|
|
2665
2637
|
value,
|
|
2666
2638
|
onChange
|
|
2667
2639
|
}) {
|
|
2668
|
-
return /* @__PURE__ */ (0,
|
|
2640
|
+
return /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
|
|
2669
2641
|
import_ui20.SegmentedControl,
|
|
2670
2642
|
{
|
|
2671
2643
|
variant: "floating",
|
|
@@ -2673,15 +2645,15 @@ function SizeMetricToggle({
|
|
|
2673
2645
|
value,
|
|
2674
2646
|
onChange,
|
|
2675
2647
|
options: [
|
|
2676
|
-
{ value: "songs", label: /* @__PURE__ */ (0,
|
|
2677
|
-
{ value: "views", label: /* @__PURE__ */ (0,
|
|
2648
|
+
{ value: "songs", label: /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(import_md.MdMusicNote, { size: 18, "aria-hidden": true }), "aria-label": "Size by songs", title: "Node size by song count" },
|
|
2649
|
+
{ value: "views", label: /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(import_md.MdVisibility, { size: 18, "aria-hidden": true }), "aria-label": "Size by views", title: "Node size by song views" }
|
|
2678
2650
|
]
|
|
2679
2651
|
}
|
|
2680
2652
|
);
|
|
2681
2653
|
}
|
|
2682
2654
|
|
|
2683
2655
|
// src/genre-tree/GenreTreeView.tsx
|
|
2684
|
-
var
|
|
2656
|
+
var import_jsx_runtime45 = require("react/jsx-runtime");
|
|
2685
2657
|
var NO_POP_ROOT_TITLE = "This genre tree has no 'Mainstream Pop' root yet";
|
|
2686
2658
|
var REGIONS_CLASS = "[--gtv-center-left:var(--layout-center-left)] [--gtv-center-right:var(--layout-center-right)] [--gtv-center-top:var(--layout-band-top)]";
|
|
2687
2659
|
var noop = () => {
|
|
@@ -2773,6 +2745,7 @@ function GenreTreeView({
|
|
|
2773
2745
|
isFetching: isTreeFetching,
|
|
2774
2746
|
genrePlaylistByNodeId,
|
|
2775
2747
|
visibleGenrePlaylists,
|
|
2748
|
+
focusUuids,
|
|
2776
2749
|
groupedGenrePlaylistsByRoot,
|
|
2777
2750
|
selectedGenreUuid,
|
|
2778
2751
|
selectGenre,
|
|
@@ -2832,14 +2805,14 @@ function GenreTreeView({
|
|
|
2832
2805
|
const openSongRef = (0, import_react19.useRef)(openSong);
|
|
2833
2806
|
openSongRef.current = openSong;
|
|
2834
2807
|
const resolvedRenderSongLink = (0, import_react19.useCallback)(
|
|
2835
|
-
(song) => renderSongLink ? renderSongLink(song) : /* @__PURE__ */ (0,
|
|
2808
|
+
(song) => renderSongLink ? renderSongLink(song) : /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("button", { type: "button", onClick: () => openSongRef.current(song.uuid), className: "hover:underline", children: song.title }),
|
|
2836
2809
|
[renderSongLink]
|
|
2837
2810
|
);
|
|
2838
2811
|
const [expandedSongUuid, setExpandedSongUuid] = (0, import_react19.useState)(null);
|
|
2839
2812
|
const [expandedArtistUuid, setExpandedArtistUuid] = (0, import_react19.useState)(null);
|
|
2840
2813
|
const artistBaseUrl = artistSearchBaseUrl ?? getBackendBaseUrl;
|
|
2841
2814
|
const songBaseUrl = getBackendBaseUrl;
|
|
2842
|
-
const resolvedRenderArtistLink = renderArtistLink ?? ((artist) => artist.isSpecialPurpose ? artist.name : /* @__PURE__ */ (0,
|
|
2815
|
+
const resolvedRenderArtistLink = renderArtistLink ?? ((artist) => artist.isSpecialPurpose ? artist.name : /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("button", { type: "button", onClick: () => openArtist(artist.uuid), className: "hover:underline", children: artist.name }));
|
|
2843
2816
|
const getGenrePath = (genre) => {
|
|
2844
2817
|
const path = [];
|
|
2845
2818
|
let current = visibleGenrePlaylists.find((playlist) => playlist.criteria?.uuid === genre.uuid);
|
|
@@ -2881,7 +2854,7 @@ function GenreTreeView({
|
|
|
2881
2854
|
selectGenrePlaylist(genrePlaylist2);
|
|
2882
2855
|
}
|
|
2883
2856
|
});
|
|
2884
|
-
const
|
|
2857
|
+
const otherPanel = overlayPanel ?? (selectedGenreUuid !== null ? void 0 : entityPanel);
|
|
2885
2858
|
const [uncontrolledCollapsed, setUncontrolledCollapsed] = (0, import_react19.useState)(false);
|
|
2886
2859
|
const [uncontrolledExpanded, setUncontrolledExpanded] = (0, import_react19.useState)(false);
|
|
2887
2860
|
const isCollapsed = collapsed ?? uncontrolledCollapsed;
|
|
@@ -2909,18 +2882,19 @@ function GenreTreeView({
|
|
|
2909
2882
|
const obscuredInset = (0, import_ui21.useObscuredInset)(panelRef);
|
|
2910
2883
|
const hostPanel = { obscuredInset, onNodeStyleResolverChange: handleNodeStyleResolverChange };
|
|
2911
2884
|
const nodeMetric = isArtistFiltered || !canSizeByViews ? "songs" : deferredSizeMetric;
|
|
2912
|
-
const treeNodes = (0, import_react19.useMemo)(() => toTreeNodes(visibleGenrePlaylists, nodeMetric), [visibleGenrePlaylists, nodeMetric]);
|
|
2885
|
+
const treeNodes = (0, import_react19.useMemo)(() => toTreeNodes(visibleGenrePlaylists, nodeMetric, focusUuids), [visibleGenrePlaylists, nodeMetric, focusUuids]);
|
|
2913
2886
|
const relations = (0, import_genre_tree_view5.useGenreNodeRelations)(
|
|
2914
2887
|
treeNodes,
|
|
2915
2888
|
!overlayPanel && hasSelectedGenreNode ? selectedNodeId : null,
|
|
2916
2889
|
resolveStyle
|
|
2917
2890
|
);
|
|
2891
|
+
const treeStyles = (0, import_react19.useMemo)(() => toGenreNodeStyles(relations, visibleGenrePlaylists), [relations, visibleGenrePlaylists]);
|
|
2918
2892
|
const [selectionHistory, setSelectionHistory] = (0, import_react19.useState)({ current: selectedGenreUuid, previous: null });
|
|
2919
2893
|
if (selectionHistory.current !== selectedGenreUuid) {
|
|
2920
2894
|
setSelectionHistory({ current: selectedGenreUuid, previous: selectionHistory.current ?? selectionHistory.previous });
|
|
2921
2895
|
}
|
|
2922
2896
|
const handlePrevious = selectionHistory.previous ? () => selectGenre(selectionHistory.previous) : void 0;
|
|
2923
|
-
const { showPopup, hidePopup } = (0,
|
|
2897
|
+
const { showPopup, hidePopup } = (0, import_popup4.usePopup)();
|
|
2924
2898
|
const reopenPanel = () => {
|
|
2925
2899
|
setUncontrolledCollapsed(false);
|
|
2926
2900
|
onCollapsedChange?.(false);
|
|
@@ -2960,7 +2934,7 @@ function GenreTreeView({
|
|
|
2960
2934
|
selectGenre(uuid);
|
|
2961
2935
|
},
|
|
2962
2936
|
expanded: isExpanded,
|
|
2963
|
-
|
|
2937
|
+
treeStyles,
|
|
2964
2938
|
playback,
|
|
2965
2939
|
genrePlaylist: selectedGenrePlaylist,
|
|
2966
2940
|
band: {
|
|
@@ -2971,7 +2945,7 @@ function GenreTreeView({
|
|
|
2971
2945
|
onAddChild: readOnly || !criteria ? void 0 : () => handleGenreCreationAction(criteria),
|
|
2972
2946
|
onRename: readOnly || !criteria ? void 0 : () => handleGenreRenameAction(criteria),
|
|
2973
2947
|
onChangeParent: readOnly || !genrePlaylist || !criteria ? void 0 : () => showPopup(
|
|
2974
|
-
/* @__PURE__ */ (0,
|
|
2948
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
|
|
2975
2949
|
ChangeParentPopup,
|
|
2976
2950
|
{
|
|
2977
2951
|
genrePlaylist: { ...genrePlaylist, criteria },
|
|
@@ -3005,15 +2979,15 @@ function GenreTreeView({
|
|
|
3005
2979
|
const isRotationControlled = controlledAllowWheelRotation !== void 0;
|
|
3006
2980
|
const allowWheelRotation = controlledAllowWheelRotation ?? internalAllowWheelRotation;
|
|
3007
2981
|
let activePanel = null;
|
|
3008
|
-
if (
|
|
2982
|
+
if (otherPanel) {
|
|
3009
2983
|
activePanel = {
|
|
3010
|
-
title:
|
|
3011
|
-
content:
|
|
3012
|
-
aside:
|
|
3013
|
-
expanded:
|
|
3014
|
-
onExpandedChange:
|
|
3015
|
-
onClose:
|
|
3016
|
-
|
|
2984
|
+
title: otherPanel.title,
|
|
2985
|
+
content: otherPanel.content,
|
|
2986
|
+
aside: otherPanel.extraContent,
|
|
2987
|
+
expanded: otherPanel.expanded ?? false,
|
|
2988
|
+
onExpandedChange: otherPanel.onExpandedChange,
|
|
2989
|
+
onClose: otherPanel.onClose,
|
|
2990
|
+
searchName: otherPanel.title
|
|
3017
2991
|
};
|
|
3018
2992
|
} else if (selectedGenreUuid) {
|
|
3019
2993
|
activePanel = {
|
|
@@ -3023,38 +2997,28 @@ function GenreTreeView({
|
|
|
3023
2997
|
expanded: isExpanded,
|
|
3024
2998
|
onExpandedChange: changeExpanded,
|
|
3025
2999
|
onClose: clearSelection,
|
|
3026
|
-
|
|
3000
|
+
searchName: genreContent.name,
|
|
3027
3001
|
headerAccent: genreContent.headerAccent
|
|
3028
3002
|
};
|
|
3029
|
-
} else if (builtInPanel) {
|
|
3030
|
-
activePanel = {
|
|
3031
|
-
title: builtInPanel.title,
|
|
3032
|
-
content: builtInPanel.content,
|
|
3033
|
-
aside: builtInPanel.extraContent,
|
|
3034
|
-
expanded: builtInPanel.expanded,
|
|
3035
|
-
onExpandedChange: builtInPanel.onExpandedChange,
|
|
3036
|
-
onClose: builtInPanel.onClose,
|
|
3037
|
-
titleInSearch: true
|
|
3038
|
-
};
|
|
3039
3003
|
}
|
|
3040
3004
|
const isPanelShown = activePanel !== null && (selectedGenreUuid !== null || isTreeReady);
|
|
3041
3005
|
const detailTab = placement === "regions" && activePanel?.onExpandedChange ? {
|
|
3042
3006
|
edge: activePanel.expanded ? { label: "Shrink panel", onClick: () => activePanel.onExpandedChange?.(false) } : isCollapsed ? null : { label: "Hide panel", onClick: () => changeCollapsed(true) },
|
|
3043
3007
|
center: activePanel.expanded ? null : isCollapsed ? { label: "Show panel", onClick: () => changeCollapsed(false) } : activePanel.onExpandedChange ? { label: "Extend panel", onClick: () => activePanel.onExpandedChange?.(true) } : null
|
|
3044
3008
|
} : void 0;
|
|
3045
|
-
const expandButton = placement === "default" && activePanel?.onExpandedChange ? /* @__PURE__ */ (0,
|
|
3009
|
+
const expandButton = placement === "default" && activePanel?.onExpandedChange ? /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
|
|
3046
3010
|
import_ui21.IconButton,
|
|
3047
3011
|
{
|
|
3048
3012
|
"aria-label": activePanel.expanded ? "Shrink panel" : "Extend panel",
|
|
3049
3013
|
style: activePanel.headerAccent && { color: "inherit" },
|
|
3050
3014
|
onClick: () => activePanel.onExpandedChange?.(!activePanel.expanded),
|
|
3051
|
-
children: activePanel.expanded ? /* @__PURE__ */ (0,
|
|
3015
|
+
children: activePanel.expanded ? /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(import_lucide_react14.Minimize2, { "aria-hidden": "true", className: "h-4 w-4" }) : /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(import_lucide_react14.Maximize2, { "aria-hidden": "true", className: "h-4 w-4" })
|
|
3052
3016
|
}
|
|
3053
3017
|
) : null;
|
|
3054
3018
|
const renderArtistFilter = () => {
|
|
3055
3019
|
if (isLoading || !filterArtist) return null;
|
|
3056
|
-
return /* @__PURE__ */ (0,
|
|
3057
|
-
/* @__PURE__ */ (0,
|
|
3020
|
+
return /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("span", { className: "inline-flex items-center overflow-hidden rounded-full bg-[var(--color-neutral-100)] text-body", children: [
|
|
3021
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
|
|
3058
3022
|
"button",
|
|
3059
3023
|
{
|
|
3060
3024
|
type: "button",
|
|
@@ -3066,7 +3030,7 @@ function GenreTreeView({
|
|
|
3066
3030
|
children: filterArtist.name
|
|
3067
3031
|
}
|
|
3068
3032
|
),
|
|
3069
|
-
/* @__PURE__ */ (0,
|
|
3033
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
|
|
3070
3034
|
"button",
|
|
3071
3035
|
{
|
|
3072
3036
|
type: "button",
|
|
@@ -3078,8 +3042,8 @@ function GenreTreeView({
|
|
|
3078
3042
|
)
|
|
3079
3043
|
] });
|
|
3080
3044
|
};
|
|
3081
|
-
const actions = /* @__PURE__ */ (0,
|
|
3082
|
-
!isLoading && !isError && /* @__PURE__ */ (0,
|
|
3045
|
+
const actions = /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)(import_jsx_runtime45.Fragment, { children: [
|
|
3046
|
+
!isLoading && !isError && /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
|
|
3083
3047
|
GenreTreeSearch,
|
|
3084
3048
|
{
|
|
3085
3049
|
artistBaseUrl,
|
|
@@ -3102,9 +3066,9 @@ function GenreTreeView({
|
|
|
3102
3066
|
if (songUuid) changeSong(null);
|
|
3103
3067
|
selectGenre(uuid);
|
|
3104
3068
|
},
|
|
3105
|
-
selectedName:
|
|
3069
|
+
selectedName: activePanel?.searchName ?? null,
|
|
3106
3070
|
onClear: activePanel?.onClose,
|
|
3107
|
-
showClear: activePanel
|
|
3071
|
+
showClear: activePanel !== null,
|
|
3108
3072
|
clearLabel: "Close panel",
|
|
3109
3073
|
onPrevious: handlePrevious,
|
|
3110
3074
|
onQueryChange: onSearchQueryChange,
|
|
@@ -3112,9 +3076,9 @@ function GenreTreeView({
|
|
|
3112
3076
|
extraGroups: extraSearchGroups
|
|
3113
3077
|
}
|
|
3114
3078
|
),
|
|
3115
|
-
!isLoading && !isError && filterArtist && /* @__PURE__ */ (0,
|
|
3116
|
-
/* @__PURE__ */ (0,
|
|
3117
|
-
!isLoading && !isError && !isControlled && /* @__PURE__ */ (0,
|
|
3079
|
+
!isLoading && !isError && filterArtist && /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("div", { className: "hidden w-full justify-center max-md:flex", children: renderArtistFilter() }),
|
|
3080
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("div", { className: "contents max-md:flex max-md:w-full max-md:items-center max-md:gap-2 max-md:overflow-x-auto max-md:[scrollbar-width:none] max-md:[&>*]:shrink-0", children: [
|
|
3081
|
+
!isLoading && !isError && !isControlled && /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
|
|
3118
3082
|
import_ui21.SegmentedControl,
|
|
3119
3083
|
{
|
|
3120
3084
|
"aria-label": "Tree view mode",
|
|
@@ -3128,13 +3092,13 @@ function GenreTreeView({
|
|
|
3128
3092
|
]
|
|
3129
3093
|
}
|
|
3130
3094
|
),
|
|
3131
|
-
!isLoading && !isError && showDisplayOptions && /* @__PURE__ */ (0,
|
|
3095
|
+
!isLoading && !isError && showDisplayOptions && /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
|
|
3132
3096
|
"div",
|
|
3133
3097
|
{
|
|
3134
3098
|
className: "flex items-center gap-1",
|
|
3135
3099
|
role: "group",
|
|
3136
3100
|
"aria-label": "Tree display options",
|
|
3137
|
-
children: !isRotationControlled && viewMode !== "stacked" && viewMode !== "outline" && /* @__PURE__ */ (0,
|
|
3101
|
+
children: !isRotationControlled && viewMode !== "stacked" && viewMode !== "outline" && /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
|
|
3138
3102
|
import_ui21.Button,
|
|
3139
3103
|
{
|
|
3140
3104
|
variant: allowWheelRotation ? "default" : "outline",
|
|
@@ -3145,52 +3109,53 @@ function GenreTreeView({
|
|
|
3145
3109
|
)
|
|
3146
3110
|
}
|
|
3147
3111
|
),
|
|
3148
|
-
!isLoading && !isError && !readOnly && showAddRoot && /* @__PURE__ */ (0,
|
|
3112
|
+
!isLoading && !isError && !readOnly && showAddRoot && /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
|
|
3149
3113
|
import_ui21.IconTextButton,
|
|
3150
3114
|
{
|
|
3151
|
-
icon:
|
|
3115
|
+
icon: import_lucide_react13.Plus,
|
|
3152
3116
|
text: "Add root",
|
|
3153
3117
|
onClick: () => handleGenreCreationAction(null)
|
|
3154
3118
|
}
|
|
3155
3119
|
)
|
|
3156
3120
|
] })
|
|
3157
3121
|
] });
|
|
3158
|
-
return /* @__PURE__ */ (0,
|
|
3122
|
+
return /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)(
|
|
3159
3123
|
"div",
|
|
3160
3124
|
{
|
|
3161
3125
|
"data-left-panel": isPanelShown && !isCollapsed ? void 0 : "hidden",
|
|
3162
3126
|
className: ["genre-tree-view relative flex flex-col h-full", placement === "regions" && REGIONS_CLASS, className2].filter(Boolean).join(" "),
|
|
3163
3127
|
children: [
|
|
3164
|
-
/* @__PURE__ */ (0,
|
|
3128
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
|
|
3165
3129
|
"div",
|
|
3166
3130
|
{
|
|
3167
3131
|
className: `actions-container absolute z-30 flex items-center gap-2 ${placement === "regions" ? "left-[calc(var(--layout-gutter)+var(--layout-panel-inset))] top-[calc(var(--layout-gutter)+var(--layout-panel-inset))] md:left-[var(--layout-panel-inset)] md:top-[var(--layout-panel-inset)] max-md:right-[calc(var(--layout-gutter)+var(--layout-panel-inset))] max-md:top-[var(--layout-band-top)] max-md:flex-col max-md:items-stretch" : "left-5 top-5"}`,
|
|
3168
3132
|
children: actions
|
|
3169
3133
|
}
|
|
3170
3134
|
),
|
|
3171
|
-
!isLoading && !isError && filterArtist && /* @__PURE__ */ (0,
|
|
3135
|
+
!isLoading && !isError && filterArtist && /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
|
|
3172
3136
|
"div",
|
|
3173
3137
|
{
|
|
3174
3138
|
className: `absolute left-1/2 z-30 hidden -translate-x-1/2 md:block ${placement === "regions" ? "top-[calc(var(--layout-gutter)+var(--layout-panel-inset))] md:top-[var(--layout-panel-inset)]" : "top-5"}`,
|
|
3175
3139
|
children: renderArtistFilter()
|
|
3176
3140
|
}
|
|
3177
3141
|
),
|
|
3178
|
-
/* @__PURE__ */ (0,
|
|
3179
|
-
!isLoading && !isError && viewMode === "outline" && floatingControlsLeading && /* @__PURE__ */ (0,
|
|
3180
|
-
isLoading ? /* @__PURE__ */ (0,
|
|
3142
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)("div", { className: "content-container flex-1 min-h-0 flex flex-row gap-4", children: /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("div", { className: "tree-view-container relative flex-1 min-w-0 flex flex-col h-full", children: [
|
|
3143
|
+
!isLoading && !isError && viewMode === "outline" && floatingControlsLeading && /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("div", { className: "absolute bottom-3 right-3 z-10", children: floatingControlsLeading }),
|
|
3144
|
+
isLoading ? /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(import_genre_tree_view5.GenreTreeViewSkeleton, { viewMode }) : isError ? /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("p", { role: "alert", className: "m-auto text-center", children: [
|
|
3181
3145
|
"Couldn't load the genre tree.",
|
|
3182
3146
|
" ",
|
|
3183
|
-
/* @__PURE__ */ (0,
|
|
3147
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)("button", { type: "button", className: "underline", onClick: refetch, children: "Retry" })
|
|
3184
3148
|
] }) : viewMode === "wheel" ? (
|
|
3185
3149
|
// The info panel's top edge aligns with the tree's; the search bar floats `--layout-panel-inset` below it,
|
|
3186
3150
|
// and the header inset (the bar's height plus that inset) extends the header's fill behind the bar,
|
|
3187
3151
|
// Google Maps style; the 8px bottom padding mirrors the inset above the bar, and the hidden title's height is zeroed.
|
|
3188
3152
|
// The panel's own Zoom in button is hidden: the search bar carries it.
|
|
3189
|
-
/* @__PURE__ */ (0,
|
|
3153
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)("div", { className: "tree-container search-overlay relative flex-1 w-full min-h-0 ", children: /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(GenreTreeWheelHandoff, { skeleton: /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(import_genre_tree_view5.GenreTreeWheelSkeleton, {}), onRevealedChange: setIsWheelRevealed, children: /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
|
|
3190
3154
|
GenrePlaylistTreeWheel,
|
|
3191
3155
|
{
|
|
3192
3156
|
scope,
|
|
3193
3157
|
genrePlaylists: visibleGenrePlaylists,
|
|
3158
|
+
focusUuids,
|
|
3194
3159
|
handleGenreCreationAction,
|
|
3195
3160
|
handleGenreRenameAction,
|
|
3196
3161
|
additionalActions,
|
|
@@ -3203,9 +3168,9 @@ function GenreTreeView({
|
|
|
3203
3168
|
allowWheelRotation,
|
|
3204
3169
|
sizeMetric: isArtistFiltered || !canSizeByViews ? "songs" : deferredSizeMetric,
|
|
3205
3170
|
busy,
|
|
3206
|
-
floatingControlsLeading: floatingControlsLeading || canSizeByViews ? /* @__PURE__ */ (0,
|
|
3171
|
+
floatingControlsLeading: floatingControlsLeading || canSizeByViews ? /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("div", { className: "flex items-center gap-2", children: [
|
|
3207
3172
|
floatingControlsLeading,
|
|
3208
|
-
canSizeByViews && /* @__PURE__ */ (0,
|
|
3173
|
+
canSizeByViews && /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(SizeMetricToggle, { value: sizeMetric, onChange: changeSizeMetric })
|
|
3209
3174
|
] }) : void 0,
|
|
3210
3175
|
defaultViewport,
|
|
3211
3176
|
viewportRestore,
|
|
@@ -3214,11 +3179,12 @@ function GenreTreeView({
|
|
|
3214
3179
|
) }) })
|
|
3215
3180
|
) : viewMode === "pop-core" ? (
|
|
3216
3181
|
// Same as the wheel: the header inset extends its fill behind the floating search bar, Google Maps style.
|
|
3217
|
-
/* @__PURE__ */ (0,
|
|
3182
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)("div", { className: "tree-container search-overlay relative flex-1 w-full min-h-0 ", children: /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(GenreTreeWheelHandoff, { skeleton: /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(import_genre_tree_view5.GenreTreeWheelSkeleton, {}), onRevealedChange: setIsWheelRevealed, children: /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
|
|
3218
3183
|
GenrePlaylistTreeWheelRadialPopCore,
|
|
3219
3184
|
{
|
|
3220
3185
|
scope,
|
|
3221
3186
|
genrePlaylists: visibleGenrePlaylists,
|
|
3187
|
+
focusUuids,
|
|
3222
3188
|
handleGenreCreationAction,
|
|
3223
3189
|
handleGenreRenameAction,
|
|
3224
3190
|
additionalActions,
|
|
@@ -3231,9 +3197,9 @@ function GenreTreeView({
|
|
|
3231
3197
|
allowWheelRotation,
|
|
3232
3198
|
sizeMetric: isArtistFiltered || !canSizeByViews ? "songs" : deferredSizeMetric,
|
|
3233
3199
|
busy,
|
|
3234
|
-
floatingControlsLeading: floatingControlsLeading || canSizeByViews ? /* @__PURE__ */ (0,
|
|
3200
|
+
floatingControlsLeading: floatingControlsLeading || canSizeByViews ? /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("div", { className: "flex items-center gap-2", children: [
|
|
3235
3201
|
floatingControlsLeading,
|
|
3236
|
-
canSizeByViews && /* @__PURE__ */ (0,
|
|
3202
|
+
canSizeByViews && /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(SizeMetricToggle, { value: sizeMetric, onChange: changeSizeMetric })
|
|
3237
3203
|
] }) : void 0,
|
|
3238
3204
|
defaultViewport,
|
|
3239
3205
|
viewportRestore,
|
|
@@ -3241,12 +3207,13 @@ function GenreTreeView({
|
|
|
3241
3207
|
...focus
|
|
3242
3208
|
}
|
|
3243
3209
|
) }) })
|
|
3244
|
-
) : viewMode === "outline" ? /* @__PURE__ */ (0,
|
|
3210
|
+
) : viewMode === "outline" ? /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("div", { className: "tree-container flex-1 min-h-0 w-full overflow-y-auto relative", children: /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
|
|
3245
3211
|
GenrePlaylistTreeWheelRadialPopCore,
|
|
3246
3212
|
{
|
|
3247
3213
|
outline: true,
|
|
3248
3214
|
scope,
|
|
3249
3215
|
genrePlaylists: visibleGenrePlaylists,
|
|
3216
|
+
focusUuids,
|
|
3250
3217
|
handleGenreCreationAction,
|
|
3251
3218
|
handleGenreRenameAction,
|
|
3252
3219
|
additionalActions,
|
|
@@ -3257,13 +3224,13 @@ function GenreTreeView({
|
|
|
3257
3224
|
selectedNodeId,
|
|
3258
3225
|
readOnly
|
|
3259
3226
|
}
|
|
3260
|
-
) }) : /* @__PURE__ */ (0,
|
|
3227
|
+
) }) : /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("div", { className: "tree-container relative flex flex-col gap-4 w-full pt-14 overflow-x-auto overflow-y-auto text-[var(--color-text)]", children: Object.entries(groupedGenrePlaylistsByRoot).map(
|
|
3261
3228
|
([uuid, genrePlaylistTreePerRoot]) => {
|
|
3262
|
-
return /* @__PURE__ */ (0,
|
|
3229
|
+
return /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
|
|
3263
3230
|
"div",
|
|
3264
3231
|
{
|
|
3265
3232
|
className: "tree-per-root-container relative shrink-0 h-[28rem] mt-2 mr-16 p-2 bg-[var(--color-neutral-100)] rounded-lg",
|
|
3266
|
-
children: /* @__PURE__ */ (0,
|
|
3233
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("div", { className: "graph-container relative z-10 h-full", children: /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
|
|
3267
3234
|
GenrePlaylistTreePerRoot,
|
|
3268
3235
|
{
|
|
3269
3236
|
scope,
|
|
@@ -3276,6 +3243,7 @@ function GenreTreeView({
|
|
|
3276
3243
|
onNodeHover: handleNodeHover,
|
|
3277
3244
|
...hostPanel,
|
|
3278
3245
|
playback,
|
|
3246
|
+
focusUuids,
|
|
3279
3247
|
selectedNodeId: uuid === selectedGenrePlaylist?.root.uuid ? selectedNodeId : null,
|
|
3280
3248
|
readOnly,
|
|
3281
3249
|
wheelZoom: "modifier",
|
|
@@ -3289,13 +3257,13 @@ function GenreTreeView({
|
|
|
3289
3257
|
);
|
|
3290
3258
|
}
|
|
3291
3259
|
) }),
|
|
3292
|
-
/* @__PURE__ */ (0,
|
|
3260
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
|
|
3293
3261
|
import_ui21.DetailPanel,
|
|
3294
3262
|
{
|
|
3295
3263
|
ref: panelRef,
|
|
3296
3264
|
side: "left",
|
|
3297
3265
|
title: activePanel?.title ?? "",
|
|
3298
|
-
titleInSearch:
|
|
3266
|
+
titleInSearch: !isLoading && !isError,
|
|
3299
3267
|
headerAccent: activePanel?.headerAccent,
|
|
3300
3268
|
headerActions: expandButton,
|
|
3301
3269
|
onClose: activePanel?.onClose ?? noop,
|
|
@@ -3304,8 +3272,7 @@ function GenreTreeView({
|
|
|
3304
3272
|
onExpandedChange: activePanel?.onExpandedChange,
|
|
3305
3273
|
aside: activePanel?.aside,
|
|
3306
3274
|
edgeTab: detailTab,
|
|
3307
|
-
|
|
3308
|
-
children: activePanel?.aside && !activePanel.expanded ? /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)(import_jsx_runtime44.Fragment, { children: [
|
|
3275
|
+
children: activePanel?.aside && !activePanel.expanded ? /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)(import_jsx_runtime45.Fragment, { children: [
|
|
3309
3276
|
activePanel.content,
|
|
3310
3277
|
activePanel.aside
|
|
3311
3278
|
] }) : activePanel?.content
|
|
@@ -3322,11 +3289,11 @@ var import_genre_tree_view6 = require("@behindthemusictree/genre-tree-view");
|
|
|
3322
3289
|
|
|
3323
3290
|
// src/genre-tree/track-list-sidebar/TrackListSidebar.tsx
|
|
3324
3291
|
var import_react20 = require("react");
|
|
3325
|
-
var
|
|
3292
|
+
var import_lucide_react15 = require("lucide-react");
|
|
3326
3293
|
var import_genre_tree31 = require("@behindthemusictree/app-kit/genre-tree");
|
|
3327
3294
|
var import_genre_tree32 = require("@behindthemusictree/app-kit/genre-tree");
|
|
3328
3295
|
var import_track_noun3 = require("@behindthemusictree/app-kit/track-noun");
|
|
3329
|
-
var
|
|
3296
|
+
var import_jsx_runtime46 = require("react/jsx-runtime");
|
|
3330
3297
|
var useBrowserLayoutEffect = typeof window === "undefined" ? import_react20.useEffect : import_react20.useLayoutEffect;
|
|
3331
3298
|
function TrackListSidebar({
|
|
3332
3299
|
className: className2 = "",
|
|
@@ -3428,25 +3395,25 @@ function TrackListSidebar({
|
|
|
3428
3395
|
}
|
|
3429
3396
|
};
|
|
3430
3397
|
const positionClasses = layout === "inline" ? "relative w-full flex h-full flex-col" : "fixed right-0 w-[50rem] flex flex-col";
|
|
3431
|
-
return trackList ? /* @__PURE__ */ (0,
|
|
3398
|
+
return trackList ? /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)(
|
|
3432
3399
|
"div",
|
|
3433
3400
|
{
|
|
3434
3401
|
"data-theme": "dark",
|
|
3435
3402
|
className: `track-list-sidebar ${positionClasses} rounded-2xl bg-[var(--color-surface)] pb-1 ${className2}`,
|
|
3436
3403
|
style: layout === "fixed" ? { top: "63.5px", maxHeight: "calc(100vh - 63.5px - 79px)" } : void 0,
|
|
3437
3404
|
children: [
|
|
3438
|
-
/* @__PURE__ */ (0,
|
|
3439
|
-
/* @__PURE__ */ (0,
|
|
3440
|
-
/* @__PURE__ */ (0,
|
|
3441
|
-
/* @__PURE__ */ (0,
|
|
3442
|
-
/* @__PURE__ */ (0,
|
|
3405
|
+
/* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("div", { className: "header flex h-16 items-center px-4 py-2 text-[var(--color-text)]", children: [
|
|
3406
|
+
/* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("div", { className: "min-w-0 flex flex-1 flex-col justify-center", children: [
|
|
3407
|
+
/* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("div", { className: "origin flex text-xl", children: [
|
|
3408
|
+
/* @__PURE__ */ (0, import_jsx_runtime46.jsx)("div", { className: "from h-auto flex flex-col justify-center items-center mr-2", children: "From" }),
|
|
3409
|
+
/* @__PURE__ */ (0, import_jsx_runtime46.jsx)("div", { className: "name-container flex flex-col justify-center items-center text-[var(--color-text)] font-bold pr-2 max-w-[27.5rem]", children: /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("div", { className: "name max-w-full truncate", children: trackList.origin.label }) })
|
|
3443
3410
|
] }),
|
|
3444
|
-
/* @__PURE__ */ (0,
|
|
3411
|
+
/* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("div", { className: "info flex items-center text-body text-[var(--color-text-muted)]", children: [
|
|
3445
3412
|
trackList.origin.type === import_genre_tree32.TrackListOriginType.GENRE_PLAYLIST ? "Genre \u2022 " : trackList.origin.type === import_genre_tree32.TrackListOriginType.ARTIST ? "Artist \u2022 " : `${trackNoun.singular} playlist \u2022 `,
|
|
3446
3413
|
`${trackList.total} ${trackList.total > 1 ? trackNoun.plural : trackNoun.singular}`
|
|
3447
3414
|
] })
|
|
3448
3415
|
] }),
|
|
3449
|
-
(isCollapsed && onExpand || !isCollapsed && onMinimize) && /* @__PURE__ */ (0,
|
|
3416
|
+
(isCollapsed && onExpand || !isCollapsed && onMinimize) && /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(
|
|
3450
3417
|
"button",
|
|
3451
3418
|
{
|
|
3452
3419
|
type: "button",
|
|
@@ -3455,11 +3422,11 @@ function TrackListSidebar({
|
|
|
3455
3422
|
"aria-expanded": !isCollapsed,
|
|
3456
3423
|
className: `ml-2 flex h-8 w-8 shrink-0 items-center justify-center rounded-md hover:bg-[var(--color-surface-muted)] ${isCollapsed ? "text-[var(--color-text-muted)]" : "text-white"}`,
|
|
3457
3424
|
onClick: isCollapsed ? onExpand : onMinimize,
|
|
3458
|
-
children: /* @__PURE__ */ (0,
|
|
3425
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(import_lucide_react15.ListMusic, { "aria-hidden": "true", className: "h-5 w-5" })
|
|
3459
3426
|
}
|
|
3460
3427
|
)
|
|
3461
3428
|
] }),
|
|
3462
|
-
!isCollapsed && /* @__PURE__ */ (0,
|
|
3429
|
+
!isCollapsed && /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)(
|
|
3463
3430
|
"ul",
|
|
3464
3431
|
{
|
|
3465
3432
|
ref: trackListRef,
|
|
@@ -3469,7 +3436,7 @@ function TrackListSidebar({
|
|
|
3469
3436
|
onPointerDown: markUserScrollIntent,
|
|
3470
3437
|
className: layout === "inline" ? "track-list flex-1 min-h-0 overflow-auto list-none p-0 m-0" : "track-list flex-1 min-h-0 overflow-auto list-none p-0 m-0",
|
|
3471
3438
|
children: [
|
|
3472
|
-
trackList.tracks.map((track, index) => /* @__PURE__ */ (0,
|
|
3439
|
+
trackList.tracks.map((track, index) => /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("li", { "data-track-uuid": track.uuid, children: /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(
|
|
3473
3440
|
TrackItem,
|
|
3474
3441
|
{
|
|
3475
3442
|
track,
|
|
@@ -3480,7 +3447,7 @@ function TrackListSidebar({
|
|
|
3480
3447
|
renderSongLink
|
|
3481
3448
|
}
|
|
3482
3449
|
) }, track.uuid)),
|
|
3483
|
-
hasMore && /* @__PURE__ */ (0,
|
|
3450
|
+
hasMore && /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("li", { ref: loadMoreSentinelRef, "aria-hidden": "true", className: "h-px" })
|
|
3484
3451
|
]
|
|
3485
3452
|
}
|
|
3486
3453
|
)
|
|
@@ -3497,10 +3464,10 @@ var import_genre_tree34 = require("@behindthemusictree/app-kit/genre-tree");
|
|
|
3497
3464
|
var import_ui22 = require("@behindthemusictree/ui");
|
|
3498
3465
|
|
|
3499
3466
|
// src/genre-tree/PlayerControls.tsx
|
|
3500
|
-
var
|
|
3467
|
+
var import_lucide_react16 = require("lucide-react");
|
|
3501
3468
|
var import_genre_tree33 = require("@behindthemusictree/app-kit/genre-tree");
|
|
3502
3469
|
var import_player13 = require("@behindthemusictree/app-kit/player");
|
|
3503
|
-
var
|
|
3470
|
+
var import_jsx_runtime47 = require("react/jsx-runtime");
|
|
3504
3471
|
function PlayerControls() {
|
|
3505
3472
|
const {
|
|
3506
3473
|
duration,
|
|
@@ -3519,15 +3486,15 @@ function PlayerControls() {
|
|
|
3519
3486
|
const safeDuration = Number.isFinite(duration) && duration > 0 ? duration : 0;
|
|
3520
3487
|
const safeCurrentTime = Number.isFinite(currentTime) ? Math.max(0, Math.min(currentTime, safeDuration)) : 0;
|
|
3521
3488
|
const isPlaying = playState === import_player13.PlayStates.PLAYING;
|
|
3522
|
-
return /* @__PURE__ */ (0,
|
|
3489
|
+
return /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)(
|
|
3523
3490
|
"section",
|
|
3524
3491
|
{
|
|
3525
3492
|
"aria-label": "Player controls",
|
|
3526
3493
|
className: "player-controls flex shrink-0 flex-col gap-2 border-b border-zinc-800 px-3 py-2 text-zinc-200",
|
|
3527
3494
|
children: [
|
|
3528
|
-
/* @__PURE__ */ (0,
|
|
3529
|
-
/* @__PURE__ */ (0,
|
|
3530
|
-
/* @__PURE__ */ (0,
|
|
3495
|
+
/* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("div", { className: "flex min-w-0 items-center gap-2 text-xs tabular-nums text-zinc-400", children: [
|
|
3496
|
+
/* @__PURE__ */ (0, import_jsx_runtime47.jsx)("span", { "aria-label": "Elapsed time", children: (0, import_genre_tree33.formatTime)(safeCurrentTime) }),
|
|
3497
|
+
/* @__PURE__ */ (0, import_jsx_runtime47.jsx)(
|
|
3531
3498
|
"input",
|
|
3532
3499
|
{
|
|
3533
3500
|
"aria-label": "Seek",
|
|
@@ -3541,11 +3508,11 @@ function PlayerControls() {
|
|
|
3541
3508
|
onChange: (event) => seekTo(Number(event.currentTarget.value))
|
|
3542
3509
|
}
|
|
3543
3510
|
),
|
|
3544
|
-
/* @__PURE__ */ (0,
|
|
3511
|
+
/* @__PURE__ */ (0, import_jsx_runtime47.jsx)("span", { "aria-label": "Duration", children: (0, import_genre_tree33.formatTime)(safeDuration) })
|
|
3545
3512
|
] }),
|
|
3546
|
-
/* @__PURE__ */ (0,
|
|
3547
|
-
/* @__PURE__ */ (0,
|
|
3548
|
-
/* @__PURE__ */ (0,
|
|
3513
|
+
/* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("div", { className: "grid min-h-9 grid-cols-[1fr_auto_1fr] items-center gap-3", children: [
|
|
3514
|
+
/* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("div", { className: "col-start-2 flex items-center justify-center gap-2", children: [
|
|
3515
|
+
/* @__PURE__ */ (0, import_jsx_runtime47.jsx)(
|
|
3549
3516
|
"button",
|
|
3550
3517
|
{
|
|
3551
3518
|
type: "button",
|
|
@@ -3554,10 +3521,10 @@ function PlayerControls() {
|
|
|
3554
3521
|
disabled: !isReady || !hasPreviousTrack,
|
|
3555
3522
|
onClick: playPreviousTrack,
|
|
3556
3523
|
className: "flex h-8 w-8 shrink-0 items-center justify-center rounded-full text-zinc-300 hover:bg-zinc-800 hover:text-white disabled:cursor-not-allowed disabled:opacity-40",
|
|
3557
|
-
children: /* @__PURE__ */ (0,
|
|
3524
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(import_lucide_react16.SkipBack, { "aria-hidden": "true", className: "h-4 w-4" })
|
|
3558
3525
|
}
|
|
3559
3526
|
),
|
|
3560
|
-
/* @__PURE__ */ (0,
|
|
3527
|
+
/* @__PURE__ */ (0, import_jsx_runtime47.jsx)(
|
|
3561
3528
|
"button",
|
|
3562
3529
|
{
|
|
3563
3530
|
type: "button",
|
|
@@ -3566,10 +3533,10 @@ function PlayerControls() {
|
|
|
3566
3533
|
disabled: !isReady,
|
|
3567
3534
|
onClick: handlePlayPauseAction,
|
|
3568
3535
|
className: "flex h-9 w-9 shrink-0 items-center justify-center rounded-full bg-white text-zinc-950 hover:bg-zinc-200 disabled:cursor-not-allowed disabled:opacity-40",
|
|
3569
|
-
children: isPlaying ? /* @__PURE__ */ (0,
|
|
3536
|
+
children: isPlaying ? /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(import_lucide_react16.Pause, { "aria-hidden": "true", className: "h-4 w-4", fill: "currentColor" }) : /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(import_lucide_react16.Play, { "aria-hidden": "true", className: "h-4 w-4", fill: "currentColor" })
|
|
3570
3537
|
}
|
|
3571
3538
|
),
|
|
3572
|
-
/* @__PURE__ */ (0,
|
|
3539
|
+
/* @__PURE__ */ (0, import_jsx_runtime47.jsx)(
|
|
3573
3540
|
"button",
|
|
3574
3541
|
{
|
|
3575
3542
|
type: "button",
|
|
@@ -3578,14 +3545,14 @@ function PlayerControls() {
|
|
|
3578
3545
|
disabled: !isReady || !hasNextTrack,
|
|
3579
3546
|
onClick: playNextTrack,
|
|
3580
3547
|
className: "flex h-8 w-8 shrink-0 items-center justify-center rounded-full text-zinc-300 hover:bg-zinc-800 hover:text-white disabled:cursor-not-allowed disabled:opacity-40",
|
|
3581
|
-
children: /* @__PURE__ */ (0,
|
|
3548
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(import_lucide_react16.SkipForward, { "aria-hidden": "true", className: "h-4 w-4" })
|
|
3582
3549
|
}
|
|
3583
3550
|
)
|
|
3584
3551
|
] }),
|
|
3585
|
-
/* @__PURE__ */ (0,
|
|
3586
|
-
volume === 0 ? /* @__PURE__ */ (0,
|
|
3587
|
-
/* @__PURE__ */ (0,
|
|
3588
|
-
/* @__PURE__ */ (0,
|
|
3552
|
+
/* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("label", { className: "col-start-3 flex w-[4.2rem] shrink-0 items-center gap-[0.35rem] justify-self-end text-zinc-400 sm:w-[4.9rem]", children: [
|
|
3553
|
+
volume === 0 ? /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(import_lucide_react16.VolumeX, { "aria-hidden": "true", className: "h-[0.7rem] w-[0.7rem] shrink-0" }) : /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(import_lucide_react16.Volume2, { "aria-hidden": "true", className: "h-[0.7rem] w-[0.7rem] shrink-0" }),
|
|
3554
|
+
/* @__PURE__ */ (0, import_jsx_runtime47.jsx)("span", { className: "sr-only", children: "Volume" }),
|
|
3555
|
+
/* @__PURE__ */ (0, import_jsx_runtime47.jsx)(
|
|
3589
3556
|
"input",
|
|
3590
3557
|
{
|
|
3591
3558
|
"aria-label": "Volume",
|
|
@@ -3607,7 +3574,7 @@ function PlayerControls() {
|
|
|
3607
3574
|
}
|
|
3608
3575
|
|
|
3609
3576
|
// src/genre-tree/PlayerPanel.tsx
|
|
3610
|
-
var
|
|
3577
|
+
var import_jsx_runtime48 = require("react/jsx-runtime");
|
|
3611
3578
|
var PANEL_ID = "player-panel";
|
|
3612
3579
|
var DEFAULT_EXTENDED_WIDTH = "calc(100vw - var(--layout-center-left) - var(--layout-gutter))";
|
|
3613
3580
|
function PlayerPanel({
|
|
@@ -3647,7 +3614,7 @@ function PlayerPanel({
|
|
|
3647
3614
|
onClick: () => setIsExtendRequested(true),
|
|
3648
3615
|
expanded: false
|
|
3649
3616
|
} : null;
|
|
3650
|
-
return /* @__PURE__ */ (0,
|
|
3617
|
+
return /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)(
|
|
3651
3618
|
"div",
|
|
3652
3619
|
{
|
|
3653
3620
|
id: PANEL_ID,
|
|
@@ -3660,7 +3627,7 @@ function PlayerPanel({
|
|
|
3660
3627
|
),
|
|
3661
3628
|
style: isExtended ? { width: extendedWidth } : void 0,
|
|
3662
3629
|
children: [
|
|
3663
|
-
/* @__PURE__ */ (0,
|
|
3630
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
|
|
3664
3631
|
import_ui22.PanelEdgeTab,
|
|
3665
3632
|
{
|
|
3666
3633
|
side: "right",
|
|
@@ -3670,7 +3637,7 @@ function PlayerPanel({
|
|
|
3670
3637
|
className: "absolute right-full top-1/2 -translate-y-1/2"
|
|
3671
3638
|
}
|
|
3672
3639
|
),
|
|
3673
|
-
/* @__PURE__ */ (0,
|
|
3640
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsxs)(
|
|
3674
3641
|
"div",
|
|
3675
3642
|
{
|
|
3676
3643
|
className: (0, import_tailwind_merge.twMerge)(
|
|
@@ -3678,20 +3645,20 @@ function PlayerPanel({
|
|
|
3678
3645
|
isExtended ? "flex-row" : "flex-col"
|
|
3679
3646
|
),
|
|
3680
3647
|
children: [
|
|
3681
|
-
/* @__PURE__ */ (0,
|
|
3682
|
-
/* @__PURE__ */ (0,
|
|
3683
|
-
/* @__PURE__ */ (0,
|
|
3684
|
-
/* @__PURE__ */ (0,
|
|
3685
|
-
playerTrackObject?.loadError && /* @__PURE__ */ (0,
|
|
3648
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("div", { className: "flex w-[var(--layout-right-w)] shrink-0 flex-col", children: [
|
|
3649
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)("div", { className: "flex shrink-0 items-center justify-between gap-2 border-b border-zinc-800 p-2", children: /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("span", { className: "min-w-0 truncate text-sm font-semibold", children: loadedTrackTitle || lastLoadedTrackTitle }) }),
|
|
3650
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("div", { className: "relative w-full shrink-0", children: [
|
|
3651
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)(import_player14.PlayerVideoSurface, { className: "aspect-video w-full bg-black" }),
|
|
3652
|
+
playerTrackObject?.loadError && /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("span", { className: "absolute bottom-2 left-2 right-2 text-xs text-red-400", children: [
|
|
3686
3653
|
playerTrackObject.loadError,
|
|
3687
|
-
/* @__PURE__ */ (0,
|
|
3654
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)("button", { type: "button", className: "ml-2 underline", onClick: () => {
|
|
3688
3655
|
void retryPlayback();
|
|
3689
3656
|
}, children: "Retry" })
|
|
3690
3657
|
] })
|
|
3691
3658
|
] }),
|
|
3692
|
-
/* @__PURE__ */ (0,
|
|
3659
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)(PlayerControls, {})
|
|
3693
3660
|
] }),
|
|
3694
|
-
/* @__PURE__ */ (0,
|
|
3661
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
|
|
3695
3662
|
TrackListSidebar,
|
|
3696
3663
|
{
|
|
3697
3664
|
layout: "inline",
|
|
@@ -3718,11 +3685,11 @@ function PlayerPanel({
|
|
|
3718
3685
|
var import_uuid = require("uuid");
|
|
3719
3686
|
var import_ai = require("react-icons/ai");
|
|
3720
3687
|
var import_genre_tree35 = require("@behindthemusictree/app-kit/genre-tree");
|
|
3721
|
-
var
|
|
3688
|
+
var import_jsx_runtime49 = require("react/jsx-runtime");
|
|
3722
3689
|
function Rating({ rating, handleChange }) {
|
|
3723
3690
|
const instanceId = (0, import_uuid.v4)();
|
|
3724
|
-
return /* @__PURE__ */ (0,
|
|
3725
|
-
/* @__PURE__ */ (0,
|
|
3691
|
+
return /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("div", { className: "flex items-center", children: [...Array(6)].map((_, i) => /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)("div", { className: `relative ${i === 0 ? "mr-4" : "mr-1"}`, children: [
|
|
3692
|
+
/* @__PURE__ */ (0, import_jsx_runtime49.jsx)(
|
|
3726
3693
|
"input",
|
|
3727
3694
|
{
|
|
3728
3695
|
id: `star-${instanceId}-${i}`,
|
|
@@ -3734,16 +3701,16 @@ function Rating({ rating, handleChange }) {
|
|
|
3734
3701
|
onChange: handleChange
|
|
3735
3702
|
}
|
|
3736
3703
|
),
|
|
3737
|
-
/* @__PURE__ */ (0,
|
|
3738
|
-
/* @__PURE__ */ (0,
|
|
3704
|
+
/* @__PURE__ */ (0, import_jsx_runtime49.jsx)("label", { htmlFor: `star-${instanceId}-${i}`, className: "cursor-pointer", children: i === 0 ? /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)("div", { className: "flex", children: [
|
|
3705
|
+
/* @__PURE__ */ (0, import_jsx_runtime49.jsx)(
|
|
3739
3706
|
import_ai.AiOutlineStar,
|
|
3740
3707
|
{
|
|
3741
3708
|
className: `w-7 h-7 absolute top-0 left-0 ${rating === import_genre_tree35.FORM_RATING_NULL_VALUE ? "text-[var(--color-accent-rating)]" : "text-[var(--color-text-muted)]"}`
|
|
3742
3709
|
}
|
|
3743
3710
|
),
|
|
3744
|
-
/* @__PURE__ */ (0,
|
|
3711
|
+
/* @__PURE__ */ (0, import_jsx_runtime49.jsx)("span", { className: "flex-grow w-8" }),
|
|
3745
3712
|
" "
|
|
3746
|
-
] }) : /* @__PURE__ */ (0,
|
|
3713
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(
|
|
3747
3714
|
import_ai.AiFillStar,
|
|
3748
3715
|
{
|
|
3749
3716
|
className: `w-7 h-7 absolute top-0 left-0 ${(rating ?? -1) >= i ? "text-[var(--color-accent-rating)]" : "text-[var(--color-text-muted)]"}`
|
|
@@ -3755,7 +3722,7 @@ function Rating({ rating, handleChange }) {
|
|
|
3755
3722
|
// src/genre-tree/EntityDetailPanel.tsx
|
|
3756
3723
|
var import_react22 = require("react");
|
|
3757
3724
|
var import_ui23 = require("@behindthemusictree/ui");
|
|
3758
|
-
var
|
|
3725
|
+
var import_jsx_runtime50 = require("react/jsx-runtime");
|
|
3759
3726
|
function EntityDetailPanel({
|
|
3760
3727
|
scope,
|
|
3761
3728
|
getBackendBaseUrl,
|
|
@@ -3778,8 +3745,8 @@ function EntityDetailPanel({
|
|
|
3778
3745
|
getBackendBaseUrl,
|
|
3779
3746
|
getArtistBackendBaseUrl,
|
|
3780
3747
|
getShareUrl,
|
|
3781
|
-
renderArtistLink: renderArtistLink ?? ((artist) => artist.isSpecialPurpose ? artist.name : /* @__PURE__ */ (0,
|
|
3782
|
-
renderSongLink: renderSongLink ?? ((song) => /* @__PURE__ */ (0,
|
|
3748
|
+
renderArtistLink: renderArtistLink ?? ((artist) => artist.isSpecialPurpose ? artist.name : /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("button", { type: "button", onClick: () => onArtistUuidChange(artist.uuid), className: "hover:underline", children: artist.name })),
|
|
3749
|
+
renderSongLink: renderSongLink ?? ((song) => /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("button", { type: "button", onClick: () => onSongUuidChange(song.uuid), className: "hover:underline", children: song.title })),
|
|
3783
3750
|
song: {
|
|
3784
3751
|
uuid: songUuid,
|
|
3785
3752
|
expanded: songUuid !== null && expandedSongUuid === songUuid,
|
|
@@ -3795,7 +3762,7 @@ function EntityDetailPanel({
|
|
|
3795
3762
|
...navigation
|
|
3796
3763
|
});
|
|
3797
3764
|
if (!panel) return null;
|
|
3798
|
-
return /* @__PURE__ */ (0,
|
|
3765
|
+
return /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(
|
|
3799
3766
|
import_ui23.DetailPanel,
|
|
3800
3767
|
{
|
|
3801
3768
|
side: "left",
|
|
@@ -3807,7 +3774,7 @@ function EntityDetailPanel({
|
|
|
3807
3774
|
onExpandedChange: panel.onExpandedChange,
|
|
3808
3775
|
aside: panel.extraContent,
|
|
3809
3776
|
edgeTab,
|
|
3810
|
-
children: panel.extraContent && !panel.expanded ? /* @__PURE__ */ (0,
|
|
3777
|
+
children: panel.extraContent && !panel.expanded ? /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)(import_jsx_runtime50.Fragment, { children: [
|
|
3811
3778
|
panel.content,
|
|
3812
3779
|
panel.extraContent
|
|
3813
3780
|
] }) : panel.content
|