@behindthemusictree/app-kit-ui 30.0.0 → 31.0.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-2HE2HDFA.js → chunk-AQASG5KT.js} +476 -528
- package/dist/chunk-AQASG5KT.js.map +1 -0
- package/dist/genre-tree/index.cjs +512 -570
- package/dist/genre-tree/index.cjs.map +1 -1
- package/dist/genre-tree/index.d.ts +35 -38
- package/dist/genre-tree/index.js +3 -7
- package/dist/index.cjs +512 -570
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +3 -7
- package/package.json +6 -6
- package/dist/chunk-2HE2HDFA.js.map +0 -1
|
@@ -30,20 +30,19 @@ __export(genre_tree_exports, {
|
|
|
30
30
|
GenreTreeView: () => GenreTreeView,
|
|
31
31
|
GenreTreeViewSkeleton: () => import_genre_tree_view6.GenreTreeViewSkeleton,
|
|
32
32
|
GenreTreeWheelSkeleton: () => import_genre_tree_view6.GenreTreeWheelSkeleton,
|
|
33
|
-
PanelEdgeTab: () => PanelEdgeTab,
|
|
34
33
|
PlayerPanel: () => PlayerPanel,
|
|
35
34
|
Rating: () => Rating,
|
|
36
35
|
TrackItem: () => TrackItem,
|
|
37
36
|
TrackListSidebar: () => TrackListSidebar,
|
|
38
37
|
TrackPositionPlayPause: () => TrackPositionPlayPause,
|
|
39
|
-
useGenrePlaylistPlayback: () => useGenrePlaylistPlayback
|
|
40
|
-
useLeftDetailPanelLayout: () => useLeftDetailPanelLayout
|
|
38
|
+
useGenrePlaylistPlayback: () => useGenrePlaylistPlayback
|
|
41
39
|
});
|
|
42
40
|
module.exports = __toCommonJS(genre_tree_exports);
|
|
43
41
|
|
|
44
42
|
// src/genre-tree/GenreTreeView.tsx
|
|
45
|
-
var
|
|
43
|
+
var import_react16 = require("react");
|
|
46
44
|
var import_react_query3 = require("@tanstack/react-query");
|
|
45
|
+
var import_lucide_react11 = require("lucide-react");
|
|
47
46
|
var import_lucide_react12 = require("lucide-react");
|
|
48
47
|
var import_ui15 = require("@behindthemusictree/ui");
|
|
49
48
|
var import_genre_tree_view4 = require("@behindthemusictree/genre-tree-view");
|
|
@@ -51,6 +50,32 @@ var import_genre_tree18 = require("@behindthemusictree/app-kit/genre-tree");
|
|
|
51
50
|
var import_genre_tree19 = require("@behindthemusictree/app-kit/genre-tree");
|
|
52
51
|
var import_popup5 = require("@behindthemusictree/app-kit/popup");
|
|
53
52
|
|
|
53
|
+
// src/genre-tree/playlist-tree/size-metric.ts
|
|
54
|
+
var hasViewsCount = (genrePlaylists) => genrePlaylists.every((genrePlaylist) => genrePlaylist.viewsCount !== void 0);
|
|
55
|
+
var genrePlaylistSize = (genrePlaylist, metric) => {
|
|
56
|
+
if (metric === "songs") return genrePlaylist.tracksCount;
|
|
57
|
+
if (genrePlaylist.viewsCount === void 0) {
|
|
58
|
+
throw new Error(`Genre playlist ${genrePlaylist.uuid} has no viewsCount to size by views`);
|
|
59
|
+
}
|
|
60
|
+
return genrePlaylist.viewsCount;
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
// src/genre-tree/playlist-tree/toTreeNodes.ts
|
|
64
|
+
function toTreeNodes(genrePlaylists, sizeMetric) {
|
|
65
|
+
return genrePlaylists.map((genrePlaylist) => ({
|
|
66
|
+
id: genrePlaylist.uuid,
|
|
67
|
+
parentId: genrePlaylist.parent?.uuid ?? null,
|
|
68
|
+
name: genrePlaylist.name,
|
|
69
|
+
itemCount: genrePlaylistSize(genrePlaylist, sizeMetric),
|
|
70
|
+
actionable: Boolean(genrePlaylist.criteria),
|
|
71
|
+
detached: !genrePlaylist.criteria,
|
|
72
|
+
side: genrePlaylist.criteria?.side ?? void 0,
|
|
73
|
+
wikidataId: genrePlaylist.criteria?.wikidataId ?? null,
|
|
74
|
+
umbrella: genrePlaylist.isUmbrella,
|
|
75
|
+
scene: genrePlaylist.scene ?? void 0
|
|
76
|
+
}));
|
|
77
|
+
}
|
|
78
|
+
|
|
54
79
|
// src/genre-tree/playlist-tree/TreePerRoot.tsx
|
|
55
80
|
var import_react3 = require("react");
|
|
56
81
|
var import_genre_tree_view = require("@behindthemusictree/genre-tree-view");
|
|
@@ -303,7 +328,6 @@ function useGenrePlaylistPlayback({
|
|
|
303
328
|
}
|
|
304
329
|
|
|
305
330
|
// src/genre-tree/playlist-tree/TreePerRoot.tsx
|
|
306
|
-
var import_track_noun = require("@behindthemusictree/app-kit/track-noun");
|
|
307
331
|
var import_jsx_runtime5 = require("react/jsx-runtime");
|
|
308
332
|
function GenrePlaylistTreePerRoot({
|
|
309
333
|
scope,
|
|
@@ -315,24 +339,19 @@ function GenrePlaylistTreePerRoot({
|
|
|
315
339
|
additionalActions,
|
|
316
340
|
onNodeClick,
|
|
317
341
|
onNodeHover,
|
|
318
|
-
renderInfoPanelBody,
|
|
319
342
|
selectedNodeId,
|
|
320
343
|
onSelectedNodeChange,
|
|
321
|
-
hideInfoPanelClose,
|
|
322
|
-
hideInfoPanelTitle,
|
|
323
344
|
readOnly = false,
|
|
324
|
-
showToolbar,
|
|
325
345
|
wheelZoom,
|
|
326
346
|
defaultViewport,
|
|
327
347
|
viewportRestore,
|
|
328
348
|
onViewportChange,
|
|
329
349
|
playback,
|
|
330
|
-
...
|
|
350
|
+
...hostPanel
|
|
331
351
|
}) {
|
|
332
352
|
const { isPlaying, setIsPlaying } = (0, import_player.usePlayer)();
|
|
333
353
|
const defaultPlayback = useGenrePlaylistPlayback({ scope, genrePlaylists: genrePlaylistTreePerRoot });
|
|
334
354
|
const { playingNodeId, play } = playback ?? defaultPlayback;
|
|
335
|
-
const trackNoun = (0, import_track_noun.useTrackNoun)();
|
|
336
355
|
const { showPopup } = (0, import_popup.usePopup)();
|
|
337
356
|
const nodes = (0, import_react3.useMemo)(
|
|
338
357
|
() => genrePlaylistTreePerRoot.map((genrePlaylist) => ({
|
|
@@ -397,7 +416,6 @@ function GenrePlaylistTreePerRoot({
|
|
|
397
416
|
{
|
|
398
417
|
className: className2,
|
|
399
418
|
nodes,
|
|
400
|
-
itemCountLabel: `${(0, import_track_noun.capitalize)(trackNoun.singular)} count`,
|
|
401
419
|
rootColor: (0, import_genre_tree_view.getGenreTreeColor)(rootUuid),
|
|
402
420
|
playingNodeId,
|
|
403
421
|
playState: isPlaying ? "playing" : "paused",
|
|
@@ -408,18 +426,13 @@ function GenrePlaylistTreePerRoot({
|
|
|
408
426
|
additionalActions,
|
|
409
427
|
onNodeClick,
|
|
410
428
|
onNodeHover,
|
|
411
|
-
renderInfoPanelBody,
|
|
412
429
|
selectedNodeId,
|
|
413
430
|
onSelectedNodeChange,
|
|
414
|
-
hideInfoPanelClose,
|
|
415
|
-
hideInfoPanelTitle,
|
|
416
|
-
showToolbar,
|
|
417
431
|
wheelZoom,
|
|
418
432
|
defaultViewport,
|
|
419
433
|
viewportRestore,
|
|
420
434
|
onViewportChange,
|
|
421
|
-
...
|
|
422
|
-
readOnly
|
|
435
|
+
...hostPanel
|
|
423
436
|
}
|
|
424
437
|
);
|
|
425
438
|
}
|
|
@@ -430,19 +443,6 @@ var import_genre_tree_view2 = require("@behindthemusictree/genre-tree-view");
|
|
|
430
443
|
var import_player2 = require("@behindthemusictree/app-kit/player");
|
|
431
444
|
var import_popup2 = require("@behindthemusictree/app-kit/popup");
|
|
432
445
|
var import_transport2 = require("@behindthemusictree/app-kit/transport");
|
|
433
|
-
|
|
434
|
-
// src/genre-tree/playlist-tree/size-metric.ts
|
|
435
|
-
var hasViewsCount = (genrePlaylists) => genrePlaylists.every((genrePlaylist) => genrePlaylist.viewsCount !== void 0);
|
|
436
|
-
var genrePlaylistSize = (genrePlaylist, metric) => {
|
|
437
|
-
if (metric === "songs") return genrePlaylist.tracksCount;
|
|
438
|
-
if (genrePlaylist.viewsCount === void 0) {
|
|
439
|
-
throw new Error(`Genre playlist ${genrePlaylist.uuid} has no viewsCount to size by views`);
|
|
440
|
-
}
|
|
441
|
-
return genrePlaylist.viewsCount;
|
|
442
|
-
};
|
|
443
|
-
|
|
444
|
-
// src/genre-tree/playlist-tree/TreeWheel.tsx
|
|
445
|
-
var import_track_noun2 = require("@behindthemusictree/app-kit/track-noun");
|
|
446
446
|
var import_jsx_runtime6 = require("react/jsx-runtime");
|
|
447
447
|
function GenrePlaylistTreeWheel({
|
|
448
448
|
scope,
|
|
@@ -453,14 +453,10 @@ function GenrePlaylistTreeWheel({
|
|
|
453
453
|
additionalActions,
|
|
454
454
|
onNodeClick,
|
|
455
455
|
onNodeHover,
|
|
456
|
-
renderInfoPanelBody,
|
|
457
456
|
selectedNodeId,
|
|
458
457
|
onSelectedNodeChange,
|
|
459
|
-
hideInfoPanelClose,
|
|
460
|
-
hideInfoPanelTitle,
|
|
461
458
|
readOnly = false,
|
|
462
459
|
allowWheelRotation,
|
|
463
|
-
showToolbar,
|
|
464
460
|
sizeMetric = "songs",
|
|
465
461
|
floatingControlsLeading,
|
|
466
462
|
busy,
|
|
@@ -468,12 +464,11 @@ function GenrePlaylistTreeWheel({
|
|
|
468
464
|
viewportRestore,
|
|
469
465
|
onViewportChange,
|
|
470
466
|
playback,
|
|
471
|
-
...
|
|
467
|
+
...hostPanel
|
|
472
468
|
}) {
|
|
473
469
|
const { isPlaying, setIsPlaying } = (0, import_player2.usePlayer)();
|
|
474
470
|
const defaultPlayback = useGenrePlaylistPlayback({ scope, genrePlaylists });
|
|
475
471
|
const { playingNodeId, play } = playback ?? defaultPlayback;
|
|
476
|
-
const trackNoun = (0, import_track_noun2.useTrackNoun)();
|
|
477
472
|
const { showPopup } = (0, import_popup2.usePopup)();
|
|
478
473
|
const nodes = (0, import_react4.useMemo)(
|
|
479
474
|
() => genrePlaylists.map((genrePlaylist) => ({
|
|
@@ -537,7 +532,6 @@ function GenrePlaylistTreeWheel({
|
|
|
537
532
|
{
|
|
538
533
|
className: className2,
|
|
539
534
|
nodes,
|
|
540
|
-
itemCountLabel: sizeMetric === "views" ? "Views" : `${(0, import_track_noun2.capitalize)(trackNoun.singular)} count`,
|
|
541
535
|
playingNodeId,
|
|
542
536
|
playState: isPlaying ? "playing" : "paused",
|
|
543
537
|
onPlayPause: handlePlayPause,
|
|
@@ -547,20 +541,15 @@ function GenrePlaylistTreeWheel({
|
|
|
547
541
|
additionalActions,
|
|
548
542
|
onNodeClick,
|
|
549
543
|
onNodeHover,
|
|
550
|
-
renderInfoPanelBody,
|
|
551
544
|
selectedNodeId,
|
|
552
545
|
onSelectedNodeChange,
|
|
553
|
-
hideInfoPanelClose,
|
|
554
|
-
hideInfoPanelTitle,
|
|
555
546
|
allowWheelRotation,
|
|
556
|
-
showToolbar,
|
|
557
547
|
floatingControlsLeading,
|
|
558
548
|
busy,
|
|
559
549
|
defaultViewport,
|
|
560
550
|
viewportRestore,
|
|
561
551
|
onViewportChange,
|
|
562
|
-
...
|
|
563
|
-
readOnly
|
|
552
|
+
...hostPanel
|
|
564
553
|
}
|
|
565
554
|
);
|
|
566
555
|
}
|
|
@@ -569,7 +558,6 @@ function GenrePlaylistTreeWheel({
|
|
|
569
558
|
var import_react5 = require("react");
|
|
570
559
|
var import_genre_tree_view3 = require("@behindthemusictree/genre-tree-view");
|
|
571
560
|
var import_player3 = require("@behindthemusictree/app-kit/player");
|
|
572
|
-
var import_track_noun3 = require("@behindthemusictree/app-kit/track-noun");
|
|
573
561
|
var import_jsx_runtime7 = require("react/jsx-runtime");
|
|
574
562
|
function GenrePlaylistTreeWheelRadialPopCore(props) {
|
|
575
563
|
const {
|
|
@@ -581,14 +569,10 @@ function GenrePlaylistTreeWheelRadialPopCore(props) {
|
|
|
581
569
|
additionalActions,
|
|
582
570
|
onNodeClick,
|
|
583
571
|
onNodeHover,
|
|
584
|
-
renderInfoPanelBody,
|
|
585
572
|
selectedNodeId,
|
|
586
573
|
onSelectedNodeChange,
|
|
587
|
-
hideInfoPanelClose,
|
|
588
|
-
hideInfoPanelTitle,
|
|
589
574
|
readOnly = false,
|
|
590
575
|
allowWheelRotation,
|
|
591
|
-
showToolbar,
|
|
592
576
|
sizeMetric = "songs",
|
|
593
577
|
floatingControlsLeading,
|
|
594
578
|
busy,
|
|
@@ -599,33 +583,14 @@ function GenrePlaylistTreeWheelRadialPopCore(props) {
|
|
|
599
583
|
playback
|
|
600
584
|
} = props;
|
|
601
585
|
const focus = props;
|
|
602
|
-
const
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
onExpandedChange: props.onExpandedChange,
|
|
606
|
-
collapsed: props.collapsed,
|
|
607
|
-
hideExpandButton: props.hideExpandButton,
|
|
608
|
-
overlayPanel: props.overlayPanel
|
|
586
|
+
const hostPanel = {
|
|
587
|
+
obscuredInset: props.obscuredInset,
|
|
588
|
+
onNodeStyleResolverChange: props.onNodeStyleResolverChange
|
|
609
589
|
};
|
|
610
590
|
const { isPlaying, setIsPlaying } = (0, import_player3.usePlayer)();
|
|
611
591
|
const defaultPlayback = useGenrePlaylistPlayback({ scope, genrePlaylists });
|
|
612
592
|
const { playingNodeId, play } = playback ?? defaultPlayback;
|
|
613
|
-
const
|
|
614
|
-
const nodes = (0, import_react5.useMemo)(
|
|
615
|
-
() => genrePlaylists.map((genrePlaylist) => ({
|
|
616
|
-
id: genrePlaylist.uuid,
|
|
617
|
-
parentId: genrePlaylist.parent?.uuid ?? null,
|
|
618
|
-
name: genrePlaylist.name,
|
|
619
|
-
itemCount: genrePlaylistSize(genrePlaylist, sizeMetric),
|
|
620
|
-
actionable: Boolean(genrePlaylist.criteria),
|
|
621
|
-
detached: !genrePlaylist.criteria,
|
|
622
|
-
side: genrePlaylist.criteria?.side ?? void 0,
|
|
623
|
-
wikidataId: genrePlaylist.criteria?.wikidataId ?? null,
|
|
624
|
-
umbrella: genrePlaylist.isUmbrella,
|
|
625
|
-
scene: genrePlaylist.scene ?? void 0
|
|
626
|
-
})),
|
|
627
|
-
[genrePlaylists, sizeMetric]
|
|
628
|
-
);
|
|
593
|
+
const nodes = (0, import_react5.useMemo)(() => toTreeNodes(genrePlaylists, sizeMetric), [genrePlaylists, sizeMetric]);
|
|
629
594
|
const handlePlayPause = (0, import_react5.useCallback)(
|
|
630
595
|
(nodeId) => {
|
|
631
596
|
const genrePlaylist = genrePlaylists.find((g) => g.uuid === nodeId);
|
|
@@ -666,7 +631,6 @@ function GenrePlaylistTreeWheelRadialPopCore(props) {
|
|
|
666
631
|
const treeProps = {
|
|
667
632
|
className: className2,
|
|
668
633
|
nodes,
|
|
669
|
-
itemCountLabel: sizeMetric === "views" ? "Views" : `${(0, import_track_noun3.capitalize)(trackNoun.singular)} count`,
|
|
670
634
|
playingNodeId,
|
|
671
635
|
playState: isPlaying ? "playing" : "paused",
|
|
672
636
|
onPlayPause: handlePlayPause,
|
|
@@ -676,14 +640,9 @@ function GenrePlaylistTreeWheelRadialPopCore(props) {
|
|
|
676
640
|
additionalActions,
|
|
677
641
|
onNodeClick,
|
|
678
642
|
onNodeHover,
|
|
679
|
-
renderInfoPanelBody,
|
|
680
643
|
selectedNodeId,
|
|
681
644
|
onSelectedNodeChange,
|
|
682
|
-
|
|
683
|
-
hideInfoPanelTitle,
|
|
684
|
-
showToolbar,
|
|
685
|
-
...infoPanelCuration,
|
|
686
|
-
readOnly
|
|
645
|
+
...hostPanel
|
|
687
646
|
};
|
|
688
647
|
return outline ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_genre_tree_view3.GenreTreeOutline, { ...treeProps }) : /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
689
648
|
import_genre_tree_view3.GenreTreeWheelRadialPopCore,
|
|
@@ -803,7 +762,7 @@ function GenreSearch({
|
|
|
803
762
|
type: "button",
|
|
804
763
|
"aria-label": "Previous",
|
|
805
764
|
title: "Previous",
|
|
806
|
-
className: "genre-search-previous absolute left-2 top-1/2 z-10
|
|
765
|
+
className: "genre-search-previous absolute left-2 top-1/2 z-10 flex items-center justify-center p-1.5 [@media(pointer:coarse)]:min-h-[var(--layout-touch-target)] [@media(pointer:coarse)]:min-w-[var(--layout-touch-target)] text-[var(--color-text-muted)] rounded-full -translate-y-1/2 hover:bg-[var(--color-surface-muted)] hover:text-[var(--color-text)]",
|
|
807
766
|
onClick: onPrevious,
|
|
808
767
|
children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_lucide_react3.ArrowLeft, { "aria-hidden": "true", className: "w-4 h-4" })
|
|
809
768
|
}
|
|
@@ -825,7 +784,7 @@ function GenreSearch({
|
|
|
825
784
|
onPick: handlePick,
|
|
826
785
|
status,
|
|
827
786
|
loading: loading ? "Searching\u2026" : void 0,
|
|
828
|
-
inputClassName:
|
|
787
|
+
inputClassName: `h-[var(--layout-search-h,3rem)] ${onPrevious ? "pl-11" : "pl-6"} pr-20 text-base transition-[padding] duration-200 ease-out motion-reduce:transition-none bg-[var(--color-surface)] border-[var(--color-border)] rounded-full shadow-md`,
|
|
829
788
|
className: "genre-search-results z-40 rounded-xl shadow-md",
|
|
830
789
|
listClassName: "max-h-[min(20rem,50dvh)]",
|
|
831
790
|
optionClassName: "[@media(pointer:coarse)]:min-h-[var(--layout-touch-target)]"
|
|
@@ -1289,7 +1248,7 @@ function MusicBrainzRecordingLink({
|
|
|
1289
1248
|
|
|
1290
1249
|
// src/genre-tree/GenrePlaylistTracks.tsx
|
|
1291
1250
|
var import_genre_tree8 = require("@behindthemusictree/app-kit/genre-tree");
|
|
1292
|
-
var
|
|
1251
|
+
var import_track_noun = require("@behindthemusictree/app-kit/track-noun");
|
|
1293
1252
|
var import_jsx_runtime18 = require("react/jsx-runtime");
|
|
1294
1253
|
var CATALOGUE_PAGE_SIZE = 100;
|
|
1295
1254
|
var SongPageSchema = (0, import_transport4.PaginatedResponseSchema)(import_genre_tree6.SongDetailedSchema).extend({
|
|
@@ -1323,7 +1282,7 @@ function GenrePlaylistTracks({
|
|
|
1323
1282
|
const { session, sessionRestored } = (0, import_auth.useSession)();
|
|
1324
1283
|
const { playerTrackObject, playState, handlePlayPauseAction } = (0, import_player4.usePlayer)();
|
|
1325
1284
|
const { showPopup } = (0, import_popup4.usePopup)();
|
|
1326
|
-
const trackNoun = (0,
|
|
1285
|
+
const trackNoun = (0, import_track_noun.useTrackNoun)();
|
|
1327
1286
|
const { uuid } = genrePlaylist;
|
|
1328
1287
|
const { fetch } = (0, import_transport3.useFetchWrapper)(getBackendBaseUrl);
|
|
1329
1288
|
const { data, isPending, isError, refetch, hasNextPage, isFetchingNextPage, fetchNextPage } = (0, import_react_query.useInfiniteQuery)({
|
|
@@ -1368,7 +1327,7 @@ function GenrePlaylistTracks({
|
|
|
1368
1327
|
};
|
|
1369
1328
|
return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "gtv-info-panel-children", children: [
|
|
1370
1329
|
/* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("span", { className: "gtv-info-panel-children-title", children: [
|
|
1371
|
-
(0,
|
|
1330
|
+
(0, import_track_noun.capitalize)(trackNoun.plural),
|
|
1372
1331
|
total !== void 0 && ` (${total})`
|
|
1373
1332
|
] }),
|
|
1374
1333
|
renderTracksToolbar?.(),
|
|
@@ -1439,7 +1398,7 @@ function GenrePlaylistTracks({
|
|
|
1439
1398
|
}
|
|
1440
1399
|
|
|
1441
1400
|
// src/genre-tree/GenreDetailExtras.tsx
|
|
1442
|
-
var
|
|
1401
|
+
var import_track_noun2 = require("@behindthemusictree/app-kit/track-noun");
|
|
1443
1402
|
var import_si2 = require("react-icons/si");
|
|
1444
1403
|
var import_jsx_runtime19 = require("react/jsx-runtime");
|
|
1445
1404
|
function GenreDetailExtras({
|
|
@@ -1457,7 +1416,7 @@ function GenreDetailExtras({
|
|
|
1457
1416
|
family,
|
|
1458
1417
|
...trackSlots
|
|
1459
1418
|
}) {
|
|
1460
|
-
const trackNoun = (0,
|
|
1419
|
+
const trackNoun = (0, import_track_noun2.useTrackNoun)();
|
|
1461
1420
|
const { data: overview, isPending } = (0, import_genre_tree9.useFetchGenreOverview)(
|
|
1462
1421
|
genreUuid,
|
|
1463
1422
|
scope,
|
|
@@ -1591,66 +1550,10 @@ function GenreInfoPanelBody({
|
|
|
1591
1550
|
] });
|
|
1592
1551
|
}
|
|
1593
1552
|
|
|
1594
|
-
// src/genre-tree/PanelEdgeTab.tsx
|
|
1595
|
-
var import_lucide_react8 = require("lucide-react");
|
|
1596
|
-
var import_tailwind_merge = require("tailwind-merge");
|
|
1597
|
-
var import_jsx_runtime21 = require("react/jsx-runtime");
|
|
1598
|
-
var buttonClassName = "flex h-12 w-full items-center justify-center p-0 text-[var(--color-text-muted)] hover:bg-[var(--color-surface-muted)] hover:text-[var(--color-text)] focus-visible:outline focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-[var(--color-primary)]";
|
|
1599
|
-
function PanelEdgeTab({ side, edge, center, controls, className: className2 }) {
|
|
1600
|
-
if (!edge && !center) return null;
|
|
1601
|
-
const isLeft = side === "left";
|
|
1602
|
-
const EdgeIcon = isLeft ? import_lucide_react8.ChevronLeft : import_lucide_react8.ChevronRight;
|
|
1603
|
-
const CenterIcon = isLeft ? import_lucide_react8.ChevronRight : import_lucide_react8.ChevronLeft;
|
|
1604
|
-
const renderButton = (action, icon) => /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
1605
|
-
"button",
|
|
1606
|
-
{
|
|
1607
|
-
type: "button",
|
|
1608
|
-
"aria-label": action.label,
|
|
1609
|
-
title: action.label,
|
|
1610
|
-
"aria-controls": controls,
|
|
1611
|
-
"aria-expanded": action.expanded,
|
|
1612
|
-
className: buttonClassName,
|
|
1613
|
-
onClick: action.onClick,
|
|
1614
|
-
children: icon
|
|
1615
|
-
}
|
|
1616
|
-
);
|
|
1617
|
-
const edgeButton = edge && renderButton(edge, /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(EdgeIcon, { "aria-hidden": "true", className: "h-5 w-5" }));
|
|
1618
|
-
const centerButton = center && renderButton(center, /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(CenterIcon, { "aria-hidden": "true", className: "h-5 w-5" }));
|
|
1619
|
-
const buttons = isLeft ? [edgeButton, centerButton] : [centerButton, edgeButton];
|
|
1620
|
-
return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
|
|
1621
|
-
"div",
|
|
1622
|
-
{
|
|
1623
|
-
className: (0, import_tailwind_merge.twMerge)(
|
|
1624
|
-
"panel-edge-tab flex w-[var(--layout-edge-tab-w)] flex-col overflow-hidden bg-[var(--color-surface)] shadow-[0_1px_2px_rgba(60,64,67,0.3),0_2px_6px_2px_rgba(60,64,67,0.15)] [clip-path:inset(-0.5rem_-0.5rem_-0.5rem_0)]",
|
|
1625
|
-
isLeft ? "rounded-r-lg" : "rounded-l-lg [clip-path:inset(-0.5rem_0_-0.5rem_-0.5rem)]",
|
|
1626
|
-
className2
|
|
1627
|
-
),
|
|
1628
|
-
children: [
|
|
1629
|
-
buttons[0],
|
|
1630
|
-
buttons[0] && buttons[1] && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { role: "presentation", className: "h-px shrink-0 bg-[var(--color-border)]" }),
|
|
1631
|
-
buttons[1]
|
|
1632
|
-
]
|
|
1633
|
-
}
|
|
1634
|
-
);
|
|
1635
|
-
}
|
|
1636
|
-
|
|
1637
|
-
// src/genre-tree/useLeftDetailPanelLayout.ts
|
|
1638
|
-
var import_react13 = require("react");
|
|
1639
|
-
function useLeftDetailPanelLayout(isPanelShown, enabled = true) {
|
|
1640
|
-
(0, import_react13.useEffect)(() => {
|
|
1641
|
-
if (!enabled || isPanelShown) return void 0;
|
|
1642
|
-
const root = document.documentElement;
|
|
1643
|
-
root.style.setProperty("--layout-left-w", "0px");
|
|
1644
|
-
return () => {
|
|
1645
|
-
root.style.removeProperty("--layout-left-w");
|
|
1646
|
-
};
|
|
1647
|
-
}, [enabled, isPanelShown]);
|
|
1648
|
-
}
|
|
1649
|
-
|
|
1650
1553
|
// src/genre-tree/ChangeParentPopup.tsx
|
|
1651
|
-
var
|
|
1554
|
+
var import_react13 = require("react");
|
|
1652
1555
|
var import_genre_tree10 = require("@behindthemusictree/app-kit/genre-tree");
|
|
1653
|
-
var
|
|
1556
|
+
var import_jsx_runtime21 = require("react/jsx-runtime");
|
|
1654
1557
|
function ChangeParentPopup({
|
|
1655
1558
|
genrePlaylist,
|
|
1656
1559
|
genrePlaylists,
|
|
@@ -1660,7 +1563,7 @@ function ChangeParentPopup({
|
|
|
1660
1563
|
onParentChanged
|
|
1661
1564
|
}) {
|
|
1662
1565
|
const { mutate, isPending, formErrors } = (0, import_genre_tree10.useUpdateGenre)(scope, getBackendBaseUrl);
|
|
1663
|
-
const candidates = (0,
|
|
1566
|
+
const candidates = (0, import_react13.useMemo)(
|
|
1664
1567
|
() => (0, import_genre_tree10.getReparentCandidates)(genrePlaylists, genrePlaylist.uuid),
|
|
1665
1568
|
[genrePlaylists, genrePlaylist.uuid]
|
|
1666
1569
|
);
|
|
@@ -1678,19 +1581,19 @@ function ChangeParentPopup({
|
|
|
1678
1581
|
}
|
|
1679
1582
|
);
|
|
1680
1583
|
};
|
|
1681
|
-
(0,
|
|
1584
|
+
(0, import_react13.useEffect)(() => {
|
|
1682
1585
|
const handleKeyDown = (event) => {
|
|
1683
1586
|
if (event.key === "Escape") onClose();
|
|
1684
1587
|
};
|
|
1685
1588
|
window.addEventListener("keydown", handleKeyDown);
|
|
1686
1589
|
return () => window.removeEventListener("keydown", handleKeyDown);
|
|
1687
1590
|
}, [onClose]);
|
|
1688
|
-
return /* @__PURE__ */ (0,
|
|
1689
|
-
/* @__PURE__ */ (0,
|
|
1591
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(BasePopup_default, { title: `Change parent of ${genrePlaylist.name}`, onClose, showCancelButton: true, fitContent: true, children: [
|
|
1592
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("p", { className: "mb-3 text-sm text-[var(--color-text-muted)]", children: [
|
|
1690
1593
|
"Current parent: ",
|
|
1691
1594
|
genrePlaylist.parent?.name ?? "none"
|
|
1692
1595
|
] }),
|
|
1693
|
-
/* @__PURE__ */ (0,
|
|
1596
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { "aria-busy": isPending, className: isPending ? "pointer-events-none opacity-60" : void 0, children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
1694
1597
|
GenreSearch,
|
|
1695
1598
|
{
|
|
1696
1599
|
genrePlaylists: candidates,
|
|
@@ -1698,7 +1601,7 @@ function ChangeParentPopup({
|
|
|
1698
1601
|
placeholder: "Search a new parent\u2026"
|
|
1699
1602
|
}
|
|
1700
1603
|
) }),
|
|
1701
|
-
formErrors.length > 0 && /* @__PURE__ */ (0,
|
|
1604
|
+
formErrors.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("p", { role: "alert", className: "mt-3 text-sm text-[var(--color-red-500)]", children: formErrors.map(({ message }) => message).join(" ") })
|
|
1702
1605
|
] });
|
|
1703
1606
|
}
|
|
1704
1607
|
|
|
@@ -1710,12 +1613,12 @@ var import_genre_tree15 = require("@behindthemusictree/app-kit/genre-tree");
|
|
|
1710
1613
|
var import_ui7 = require("@behindthemusictree/ui");
|
|
1711
1614
|
|
|
1712
1615
|
// src/genre-tree/artist/ArtistLinks.tsx
|
|
1713
|
-
var
|
|
1616
|
+
var import_lucide_react8 = require("lucide-react");
|
|
1714
1617
|
var import_si3 = require("react-icons/si");
|
|
1715
1618
|
var import_ui6 = require("@behindthemusictree/ui");
|
|
1716
|
-
var
|
|
1619
|
+
var import_jsx_runtime22 = require("react/jsx-runtime");
|
|
1717
1620
|
var LINK_KINDS = {
|
|
1718
|
-
official: { label: "Official website", Icon:
|
|
1621
|
+
official: { label: "Official website", Icon: import_lucide_react8.Globe },
|
|
1719
1622
|
wikipedia: { label: "Wikipedia", Icon: import_si3.SiWikipedia },
|
|
1720
1623
|
wikidata: { label: "Wikidata", Icon: import_si3.SiWikidata },
|
|
1721
1624
|
spotify: { label: "Spotify", Icon: import_si3.SiSpotify },
|
|
@@ -1723,7 +1626,7 @@ var LINK_KINDS = {
|
|
|
1723
1626
|
bandcamp: { label: "Bandcamp", Icon: import_si3.SiBandcamp },
|
|
1724
1627
|
soundcloud: { label: "SoundCloud", Icon: import_si3.SiSoundcloud },
|
|
1725
1628
|
discogs: { label: "Discogs", Icon: import_si3.SiDiscogs },
|
|
1726
|
-
social: { label: "Social", Icon:
|
|
1629
|
+
social: { label: "Social", Icon: import_lucide_react8.Share2 }
|
|
1727
1630
|
};
|
|
1728
1631
|
function socialLabel(url) {
|
|
1729
1632
|
try {
|
|
@@ -1750,7 +1653,7 @@ function artistLinks(artist) {
|
|
|
1750
1653
|
return links;
|
|
1751
1654
|
}
|
|
1752
1655
|
function ArtistLinks({ links }) {
|
|
1753
|
-
return /* @__PURE__ */ (0,
|
|
1656
|
+
return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("ul", { className: "flex flex-wrap gap-1.5", children: links.map(({ key, url, Icon, label }) => /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_ui6.Chip, { href: url, icon: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(Icon, { className: "h-3.5 w-3.5 shrink-0", "aria-hidden": "true" }), children: label }) }, key)) });
|
|
1754
1657
|
}
|
|
1755
1658
|
|
|
1756
1659
|
// src/genre-tree/artist/formatYears.ts
|
|
@@ -1761,7 +1664,7 @@ function formatYears(beginYear, endYear, ended) {
|
|
|
1761
1664
|
}
|
|
1762
1665
|
|
|
1763
1666
|
// src/genre-tree/artist/ArtistHeader.tsx
|
|
1764
|
-
var
|
|
1667
|
+
var import_jsx_runtime23 = require("react/jsx-runtime");
|
|
1765
1668
|
var countryNames = new Intl.DisplayNames(["en"], { type: "region" });
|
|
1766
1669
|
function ArtistHeader({ artist }) {
|
|
1767
1670
|
const fields = [];
|
|
@@ -1771,35 +1674,35 @@ function ArtistHeader({ artist }) {
|
|
|
1771
1674
|
const years = formatYears(artist.beginYear, artist.endYear, artist.ended);
|
|
1772
1675
|
if (years) fields.push({ label: "Active", value: years });
|
|
1773
1676
|
const links = artistLinks(artist);
|
|
1774
|
-
if (links.length > 0) fields.push({ label: "Links", value: /* @__PURE__ */ (0,
|
|
1677
|
+
if (links.length > 0) fields.push({ label: "Links", value: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(ArtistLinks, { links }) });
|
|
1775
1678
|
if (fields.length === 0) return null;
|
|
1776
|
-
return /* @__PURE__ */ (0,
|
|
1679
|
+
return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_ui7.FieldList, { items: fields });
|
|
1777
1680
|
}
|
|
1778
1681
|
|
|
1779
1682
|
// src/genre-tree/artist/ArtistPhoto.tsx
|
|
1780
|
-
var
|
|
1683
|
+
var import_jsx_runtime24 = require("react/jsx-runtime");
|
|
1781
1684
|
function ExternalLink({ href, children }) {
|
|
1782
|
-
return /* @__PURE__ */ (0,
|
|
1685
|
+
return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("a", { href, target: "_blank", rel: "noopener noreferrer", className: "underline-offset-2 hover:underline", children });
|
|
1783
1686
|
}
|
|
1784
1687
|
function ArtistPhoto({ image, name }) {
|
|
1785
|
-
return /* @__PURE__ */ (0,
|
|
1786
|
-
/* @__PURE__ */ (0,
|
|
1787
|
-
/* @__PURE__ */ (0,
|
|
1688
|
+
return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("figure", { className: "flex flex-col gap-1.5 px-6 py-2.5", children: [
|
|
1689
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)("img", { src: image.url, alt: name, className: "h-64 w-full object-contain bg-[var(--color-surface-muted)] rounded" }),
|
|
1690
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("figcaption", { className: "text-xs text-[var(--color-text-muted)]", children: [
|
|
1788
1691
|
"Photo: ",
|
|
1789
|
-
/* @__PURE__ */ (0,
|
|
1692
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)(ExternalLink, { href: image.pageUrl, children: image.author ?? "Wikimedia Commons" }),
|
|
1790
1693
|
",",
|
|
1791
1694
|
" ",
|
|
1792
|
-
image.licenseUrl ? /* @__PURE__ */ (0,
|
|
1695
|
+
image.licenseUrl ? /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(ExternalLink, { href: image.licenseUrl, children: image.license }) : image.license
|
|
1793
1696
|
] })
|
|
1794
1697
|
] });
|
|
1795
1698
|
}
|
|
1796
1699
|
|
|
1797
1700
|
// src/genre-tree/artist/ArtistMembers.tsx
|
|
1798
1701
|
var import_ui8 = require("@behindthemusictree/ui");
|
|
1799
|
-
var
|
|
1702
|
+
var import_jsx_runtime25 = require("react/jsx-runtime");
|
|
1800
1703
|
function MembershipList({ title, memberships, renderArtistLink }) {
|
|
1801
1704
|
if (memberships.length === 0) return null;
|
|
1802
|
-
return /* @__PURE__ */ (0,
|
|
1705
|
+
return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_ui8.PanelGroup, { title, children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("ul", { children: memberships.map((membership, index) => {
|
|
1803
1706
|
const details = [
|
|
1804
1707
|
formatYears(membership.beginYear, membership.endYear, membership.ended),
|
|
1805
1708
|
...membership.roles
|
|
@@ -1807,9 +1710,9 @@ function MembershipList({ title, memberships, renderArtistLink }) {
|
|
|
1807
1710
|
const detailsText = details.filter(Boolean).join(" \xB7 ");
|
|
1808
1711
|
return (
|
|
1809
1712
|
// A member can have several periods in the same group.
|
|
1810
|
-
/* @__PURE__ */ (0,
|
|
1811
|
-
/* @__PURE__ */ (0,
|
|
1812
|
-
detailsText && /* @__PURE__ */ (0,
|
|
1713
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("li", { className: "truncate py-0.5", title: detailsText || void 0, children: [
|
|
1714
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { className: "font-medium text-[var(--color-text)]", children: renderArtistLink(membership.artist) }),
|
|
1715
|
+
detailsText && /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("span", { className: "text-[var(--color-text-muted)]", children: [
|
|
1813
1716
|
" \u2014 ",
|
|
1814
1717
|
detailsText
|
|
1815
1718
|
] })
|
|
@@ -1820,9 +1723,9 @@ function MembershipList({ title, memberships, renderArtistLink }) {
|
|
|
1820
1723
|
function ArtistMembers({ title, memberships, renderArtistLink }) {
|
|
1821
1724
|
if (memberships.length === 0) return null;
|
|
1822
1725
|
const isCurrent = (membership) => !membership.ended && membership.endYear === null;
|
|
1823
|
-
return /* @__PURE__ */ (0,
|
|
1824
|
-
/* @__PURE__ */ (0,
|
|
1825
|
-
/* @__PURE__ */ (0,
|
|
1726
|
+
return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(import_ui8.PanelSection, { title, children: [
|
|
1727
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)(MembershipList, { title: "Current", memberships: memberships.filter(isCurrent), renderArtistLink }),
|
|
1728
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
|
|
1826
1729
|
MembershipList,
|
|
1827
1730
|
{
|
|
1828
1731
|
title: "Past",
|
|
@@ -1835,7 +1738,7 @@ function ArtistMembers({ title, memberships, renderArtistLink }) {
|
|
|
1835
1738
|
|
|
1836
1739
|
// src/genre-tree/artist/ArtistDiscography.tsx
|
|
1837
1740
|
var import_ui9 = require("@behindthemusictree/ui");
|
|
1838
|
-
var
|
|
1741
|
+
var import_jsx_runtime26 = require("react/jsx-runtime");
|
|
1839
1742
|
var GROUPS = ["Albums", "EPs", "Singles", "Live", "Compilations", "Other"];
|
|
1840
1743
|
var PRIMARY_GROUPS = { album: "Albums", ep: "EPs", single: "Singles" };
|
|
1841
1744
|
function discographyGroup({ primaryType, secondaryTypes }) {
|
|
@@ -1855,20 +1758,20 @@ function byYear(a, b) {
|
|
|
1855
1758
|
function ArtistDiscography({ albums }) {
|
|
1856
1759
|
if (albums.length === 0) return null;
|
|
1857
1760
|
const sorted = [...albums].sort(byYear);
|
|
1858
|
-
return /* @__PURE__ */ (0,
|
|
1761
|
+
return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(import_ui9.PanelSection, { title: "Discography", children: GROUPS.map((group) => {
|
|
1859
1762
|
const groupAlbums = sorted.filter((album) => discographyGroup(album) === group);
|
|
1860
1763
|
if (groupAlbums.length === 0) return null;
|
|
1861
|
-
return /* @__PURE__ */ (0,
|
|
1862
|
-
/* @__PURE__ */ (0,
|
|
1863
|
-
/* @__PURE__ */ (0,
|
|
1764
|
+
return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(import_ui9.PanelGroup, { title: group, children: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("ul", { children: groupAlbums.map((album) => /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("li", { className: "grid grid-cols-[2.5rem_minmax(0,1fr)] gap-2 py-0.5", children: [
|
|
1765
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { className: "tabular-nums text-[var(--color-text-muted)]", children: album.year ?? "\u2014" }),
|
|
1766
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { className: "truncate text-[var(--color-text)]", title: album.name, children: album.name })
|
|
1864
1767
|
] }, album.uuid)) }) }, group);
|
|
1865
1768
|
}) });
|
|
1866
1769
|
}
|
|
1867
1770
|
|
|
1868
1771
|
// src/genre-tree/artist/ArtistSongs.tsx
|
|
1869
|
-
var
|
|
1772
|
+
var import_react14 = require("react");
|
|
1870
1773
|
var import_react_query2 = require("@tanstack/react-query");
|
|
1871
|
-
var
|
|
1774
|
+
var import_lucide_react9 = require("lucide-react");
|
|
1872
1775
|
var import_ui10 = require("@behindthemusictree/ui");
|
|
1873
1776
|
var import_player10 = require("@behindthemusictree/app-kit/player");
|
|
1874
1777
|
var import_genre_tree14 = require("@behindthemusictree/app-kit/genre-tree");
|
|
@@ -1882,7 +1785,7 @@ var import_genre_tree11 = require("@behindthemusictree/app-kit/genre-tree");
|
|
|
1882
1785
|
var import_fa3 = require("react-icons/fa");
|
|
1883
1786
|
var import_player7 = require("@behindthemusictree/app-kit/player");
|
|
1884
1787
|
var import_player8 = require("@behindthemusictree/app-kit/player");
|
|
1885
|
-
var
|
|
1788
|
+
var import_jsx_runtime27 = require("react/jsx-runtime");
|
|
1886
1789
|
function TrackPositionPlayPause({
|
|
1887
1790
|
position,
|
|
1888
1791
|
uuid,
|
|
@@ -1896,14 +1799,14 @@ function TrackPositionPlayPause({
|
|
|
1896
1799
|
const isPlaying = isThisTrack && isConfirmedPlayable && playState === import_player8.PlayStates.PLAYING;
|
|
1897
1800
|
const isPaused = isThisTrack && isConfirmedPlayable && playState === import_player8.PlayStates.PAUSED;
|
|
1898
1801
|
const isCurrentTrackActive = isPlaying || isPaused;
|
|
1899
|
-
return /* @__PURE__ */ (0,
|
|
1802
|
+
return /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(
|
|
1900
1803
|
"div",
|
|
1901
1804
|
{
|
|
1902
1805
|
className: "track-position-play-pause relative flex items-center justify-center gap-2 text-lg w-16 cursor-pointer",
|
|
1903
1806
|
style: { minWidth: "4rem", maxWidth: "4rem" },
|
|
1904
1807
|
onClick: handlePlayPauseClick,
|
|
1905
1808
|
children: [
|
|
1906
|
-
/* @__PURE__ */ (0,
|
|
1809
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { className: "track-position-play-pause__status group-hover:hidden flex items-center justify-center", children: isAwaitingPlayback ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { className: "track-position-play-pause__spinner", role: "status", "aria-label": "Loading track" }) : isCurrentTrackActive ? /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(
|
|
1907
1810
|
"span",
|
|
1908
1811
|
{
|
|
1909
1812
|
className: "track-position-play-pause__bars",
|
|
@@ -1911,18 +1814,18 @@ function TrackPositionPlayPause({
|
|
|
1911
1814
|
role: "img",
|
|
1912
1815
|
"aria-label": isPlaying ? "Playing" : "Paused",
|
|
1913
1816
|
children: [
|
|
1914
|
-
/* @__PURE__ */ (0,
|
|
1915
|
-
/* @__PURE__ */ (0,
|
|
1916
|
-
/* @__PURE__ */ (0,
|
|
1817
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { className: "track-position-play-pause__bar" }),
|
|
1818
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { className: "track-position-play-pause__bar" }),
|
|
1819
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { className: "track-position-play-pause__bar" })
|
|
1917
1820
|
]
|
|
1918
1821
|
}
|
|
1919
1822
|
) : position }),
|
|
1920
|
-
/* @__PURE__ */ (0,
|
|
1823
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
|
|
1921
1824
|
"div",
|
|
1922
1825
|
{
|
|
1923
1826
|
className: `hidden group-hover:flex items-center justify-center ${isCurrentTrackActive ? "" : "absolute inset-0"}`,
|
|
1924
1827
|
"aria-hidden": "true",
|
|
1925
|
-
children: isAwaitingPlayback ? /* @__PURE__ */ (0,
|
|
1828
|
+
children: isAwaitingPlayback ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { className: "track-position-play-pause__spinner" }) : isPlaying ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_fa3.FaPause, {}) : /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_fa3.FaPlay, {})
|
|
1926
1829
|
}
|
|
1927
1830
|
)
|
|
1928
1831
|
]
|
|
@@ -1933,7 +1836,7 @@ function TrackPositionPlayPause({
|
|
|
1933
1836
|
// src/genre-tree/track-list-sidebar/TrackItem.tsx
|
|
1934
1837
|
var import_genre_tree12 = require("@behindthemusictree/app-kit/genre-tree");
|
|
1935
1838
|
var import_genre_tree13 = require("@behindthemusictree/app-kit/genre-tree");
|
|
1936
|
-
var
|
|
1839
|
+
var import_jsx_runtime28 = require("react/jsx-runtime");
|
|
1937
1840
|
function TrackItem({
|
|
1938
1841
|
track,
|
|
1939
1842
|
position,
|
|
@@ -1957,12 +1860,12 @@ function TrackItem({
|
|
|
1957
1860
|
loadTrackForPlayer(track.uuid);
|
|
1958
1861
|
}
|
|
1959
1862
|
};
|
|
1960
|
-
return /* @__PURE__ */ (0,
|
|
1863
|
+
return /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(
|
|
1961
1864
|
"div",
|
|
1962
1865
|
{
|
|
1963
1866
|
className: `track-item flex h-14 text-[var(--color-text)] ${isUnplayable ? "opacity-50" : "hover:bg-[var(--color-surface-muted)] group"}`,
|
|
1964
1867
|
children: [
|
|
1965
|
-
isUnplayable ? /* @__PURE__ */ (0,
|
|
1868
|
+
isUnplayable ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
|
|
1966
1869
|
"div",
|
|
1967
1870
|
{
|
|
1968
1871
|
className: "flex items-center justify-center text-lg w-16",
|
|
@@ -1970,7 +1873,7 @@ function TrackItem({
|
|
|
1970
1873
|
"aria-disabled": "true",
|
|
1971
1874
|
children: position
|
|
1972
1875
|
}
|
|
1973
|
-
) : /* @__PURE__ */ (0,
|
|
1876
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
|
|
1974
1877
|
TrackPositionPlayPause,
|
|
1975
1878
|
{
|
|
1976
1879
|
position,
|
|
@@ -1979,12 +1882,12 @@ function TrackItem({
|
|
|
1979
1882
|
isSelected: selectedTrack?.uuid === track.uuid
|
|
1980
1883
|
}
|
|
1981
1884
|
),
|
|
1982
|
-
/* @__PURE__ */ (0,
|
|
1983
|
-
/* @__PURE__ */ (0,
|
|
1984
|
-
track.artists && track.artists.length > 0 ? /* @__PURE__ */ (0,
|
|
1885
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("div", { className: "title-artist-container flex flex-col items-start justify-center min-w-0 flex-1", children: [
|
|
1886
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)("div", { className: "flex max-w-full items-center gap-2", children: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("div", { className: "title text-lg font-bold text-[var(--color-text)] max-w-full truncate", children: renderSongLink ? renderSongLink(track) : (0, import_genre_tree12.isSong)(track) ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(MusicBrainzRecordingLink, { song: track, className: "hover:underline focus-visible:underline", children: track.title }) : track.title }) }),
|
|
1887
|
+
track.artists && track.artists.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("div", { className: "artist text-base max-w-full truncate text-[var(--color-text-muted)]", children: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_genre_tree13.ArtistNames, { artists: track.artists, renderArtistLink }) }) : ""
|
|
1985
1888
|
] }),
|
|
1986
|
-
/* @__PURE__ */ (0,
|
|
1987
|
-
renderDuration && /* @__PURE__ */ (0,
|
|
1889
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.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_runtime28.jsx)("div", { className: "genre-name max-w-full whitespace-normal break-words p-1 text-xs font-bold", children: track.genre.name }) : "" }),
|
|
1890
|
+
renderDuration && /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
|
|
1988
1891
|
"div",
|
|
1989
1892
|
{
|
|
1990
1893
|
className: "duration flex text-base w-16 items-center justify-center",
|
|
@@ -1992,22 +1895,22 @@ function TrackItem({
|
|
|
1992
1895
|
children: renderDuration(track)
|
|
1993
1896
|
}
|
|
1994
1897
|
),
|
|
1995
|
-
renderActions && /* @__PURE__ */ (0,
|
|
1898
|
+
renderActions && /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("div", { className: "edit flex text-base w-6 items-center justify-center mr-2 cursor-pointer", children: renderActions(track) })
|
|
1996
1899
|
]
|
|
1997
1900
|
}
|
|
1998
1901
|
);
|
|
1999
1902
|
}
|
|
2000
1903
|
|
|
2001
1904
|
// src/genre-tree/artist/ArtistSongs.tsx
|
|
2002
|
-
var
|
|
1905
|
+
var import_jsx_runtime29 = require("react/jsx-runtime");
|
|
2003
1906
|
var SongPageSchema2 = (0, import_transport7.PaginatedResponseSchema)(import_genre_tree14.SongDetailedSchema);
|
|
2004
1907
|
var SORTS = [
|
|
2005
1908
|
{ ordering: "title", label: "Title" },
|
|
2006
1909
|
{ ordering: "-albumYear", label: "Year" }
|
|
2007
1910
|
];
|
|
2008
1911
|
function ArtistSongs({ artist, getBackendBaseUrl, renderArtistLink, renderSongLink }) {
|
|
2009
|
-
const [page, setPage] = (0,
|
|
2010
|
-
const [ordering, setOrdering] = (0,
|
|
1912
|
+
const [page, setPage] = (0, import_react14.useState)(1);
|
|
1913
|
+
const [ordering, setOrdering] = (0, import_react14.useState)("title");
|
|
2011
1914
|
const { fetch } = (0, import_transport7.useFetchWrapper)(getBackendBaseUrl);
|
|
2012
1915
|
const { playNewTrackListFromArtist } = (0, import_genre_tree14.useTrackList)();
|
|
2013
1916
|
const { playerTrackObject } = (0, import_player10.usePlayer)();
|
|
@@ -2032,21 +1935,21 @@ function ArtistSongs({ artist, getBackendBaseUrl, renderArtistLink, renderSongLi
|
|
|
2032
1935
|
event.stopPropagation();
|
|
2033
1936
|
void play(song.uuid);
|
|
2034
1937
|
};
|
|
2035
|
-
return /* @__PURE__ */ (0,
|
|
2036
|
-
/* @__PURE__ */ (0,
|
|
2037
|
-
/* @__PURE__ */ (0,
|
|
1938
|
+
return /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(import_ui10.PanelSection, { title: "Songs", children: isPending ? /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(import_ui10.Skeleton, { className: "h-14", "aria-busy": "true" }) : isError ? /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("p", { className: "text-red-600", children: "Could not load songs." }) : data.results.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("p", { className: "text-[var(--color-text-muted)]", children: "No songs yet." }) : /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(import_jsx_runtime29.Fragment, { children: [
|
|
1939
|
+
/* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("div", { className: "flex flex-wrap items-center justify-between gap-2 mb-2", children: [
|
|
1940
|
+
/* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(
|
|
2038
1941
|
"button",
|
|
2039
1942
|
{
|
|
2040
1943
|
type: "button",
|
|
2041
1944
|
onClick: () => void play(),
|
|
2042
1945
|
className: "flex w-fit items-center gap-1.5 px-3 py-1 text-xs font-medium bg-gray-900 text-white rounded-full hover:bg-gray-700",
|
|
2043
1946
|
children: [
|
|
2044
|
-
/* @__PURE__ */ (0,
|
|
1947
|
+
/* @__PURE__ */ (0, import_jsx_runtime29.jsx)(import_lucide_react9.Play, { className: "h-3.5 w-3.5", "aria-hidden": "true" }),
|
|
2045
1948
|
"Play all"
|
|
2046
1949
|
]
|
|
2047
1950
|
}
|
|
2048
1951
|
),
|
|
2049
|
-
/* @__PURE__ */ (0,
|
|
1952
|
+
/* @__PURE__ */ (0, import_jsx_runtime29.jsx)("div", { role: "group", "aria-label": "Sort songs by", className: "flex gap-1 text-xs", children: SORTS.map((sort) => /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
|
|
2050
1953
|
"button",
|
|
2051
1954
|
{
|
|
2052
1955
|
type: "button",
|
|
@@ -2061,7 +1964,7 @@ function ArtistSongs({ artist, getBackendBaseUrl, renderArtistLink, renderSongLi
|
|
|
2061
1964
|
sort.ordering
|
|
2062
1965
|
)) })
|
|
2063
1966
|
] }),
|
|
2064
|
-
/* @__PURE__ */ (0,
|
|
1967
|
+
/* @__PURE__ */ (0, import_jsx_runtime29.jsx)("ul", { className: "overflow-hidden mb-2 bg-zinc-950 rounded-lg", children: data.results.map((song, index) => /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("li", { onClickCapture: (event) => handleRowClickCapture(event, song), children: /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
|
|
2065
1968
|
TrackItem,
|
|
2066
1969
|
{
|
|
2067
1970
|
track: song,
|
|
@@ -2070,12 +1973,12 @@ function ArtistSongs({ artist, getBackendBaseUrl, renderArtistLink, renderSongLi
|
|
|
2070
1973
|
renderSongLink
|
|
2071
1974
|
}
|
|
2072
1975
|
) }, song.uuid)) }),
|
|
2073
|
-
/* @__PURE__ */ (0,
|
|
1976
|
+
/* @__PURE__ */ (0, import_jsx_runtime29.jsx)(import_ui10.Pagination, { currentPage: page, totalPages: data.totalPages, onPageChange: setPage })
|
|
2074
1977
|
] }) });
|
|
2075
1978
|
}
|
|
2076
1979
|
|
|
2077
1980
|
// src/genre-tree/artist/useArtistPanel.tsx
|
|
2078
|
-
var
|
|
1981
|
+
var import_jsx_runtime30 = require("react/jsx-runtime");
|
|
2079
1982
|
function useArtistPanel({
|
|
2080
1983
|
uuid,
|
|
2081
1984
|
scope,
|
|
@@ -2096,26 +1999,26 @@ function useArtistPanel({
|
|
|
2096
1999
|
return {
|
|
2097
2000
|
...panel,
|
|
2098
2001
|
title: "Artist",
|
|
2099
|
-
content: /* @__PURE__ */ (0,
|
|
2100
|
-
/* @__PURE__ */ (0,
|
|
2101
|
-
/* @__PURE__ */ (0,
|
|
2102
|
-
/* @__PURE__ */ (0,
|
|
2103
|
-
/* @__PURE__ */ (0,
|
|
2104
|
-
/* @__PURE__ */ (0,
|
|
2105
|
-
/* @__PURE__ */ (0,
|
|
2002
|
+
content: /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("div", { "aria-busy": "true", className: "flex flex-col gap-2.5 px-6 py-2.5", children: [
|
|
2003
|
+
/* @__PURE__ */ (0, import_jsx_runtime30.jsx)(import_ui11.Skeleton, { className: "h-3 w-16" }),
|
|
2004
|
+
/* @__PURE__ */ (0, import_jsx_runtime30.jsx)(import_ui11.Skeleton, { className: "h-4 w-32" }),
|
|
2005
|
+
/* @__PURE__ */ (0, import_jsx_runtime30.jsx)(import_ui11.Skeleton, { className: "h-3 w-16" }),
|
|
2006
|
+
/* @__PURE__ */ (0, import_jsx_runtime30.jsx)(import_ui11.Skeleton, { className: "h-4 w-24" }),
|
|
2007
|
+
/* @__PURE__ */ (0, import_jsx_runtime30.jsx)(import_ui11.Skeleton, { className: "h-16 mt-2.5" }),
|
|
2008
|
+
/* @__PURE__ */ (0, import_jsx_runtime30.jsx)(import_ui11.Skeleton, { className: "h-16" })
|
|
2106
2009
|
] })
|
|
2107
2010
|
};
|
|
2108
2011
|
case "not-found":
|
|
2109
2012
|
return {
|
|
2110
2013
|
...panel,
|
|
2111
2014
|
title: "Artist not found",
|
|
2112
|
-
content: /* @__PURE__ */ (0,
|
|
2015
|
+
content: /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("p", { className: "px-6 py-2.5 text-[var(--color-text-muted)]", children: "This artist does not exist." })
|
|
2113
2016
|
};
|
|
2114
2017
|
case "error":
|
|
2115
2018
|
return {
|
|
2116
2019
|
...panel,
|
|
2117
2020
|
title: "Artist",
|
|
2118
|
-
content: /* @__PURE__ */ (0,
|
|
2021
|
+
content: /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("p", { className: "px-6 py-2.5 text-red-600", children: "Could not load this artist." })
|
|
2119
2022
|
};
|
|
2120
2023
|
case "success": {
|
|
2121
2024
|
const { artist } = result;
|
|
@@ -2124,13 +2027,13 @@ function useArtistPanel({
|
|
|
2124
2027
|
return {
|
|
2125
2028
|
...panel,
|
|
2126
2029
|
title: artist.name,
|
|
2127
|
-
content: /* @__PURE__ */ (0,
|
|
2128
|
-
shareUrl && /* @__PURE__ */ (0,
|
|
2129
|
-
artist.image && /* @__PURE__ */ (0,
|
|
2130
|
-
/* @__PURE__ */ (0,
|
|
2131
|
-
/* @__PURE__ */ (0,
|
|
2132
|
-
/* @__PURE__ */ (0,
|
|
2133
|
-
artist.tracksCount > 0 && /* @__PURE__ */ (0,
|
|
2030
|
+
content: /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)(import_jsx_runtime30.Fragment, { children: [
|
|
2031
|
+
shareUrl && /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("div", { className: "genre-action-band border-b border-[var(--color-border)]", children: /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("div", { className: "flex flex-wrap gap-1 px-3.5 py-3", children: shareTarget && /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(ShareActionButton, { target: shareTarget, url: shareUrl }) }) }),
|
|
2032
|
+
artist.image && /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(ArtistPhoto, { image: artist.image, name: artist.name }),
|
|
2033
|
+
/* @__PURE__ */ (0, import_jsx_runtime30.jsx)(ArtistHeader, { artist }),
|
|
2034
|
+
/* @__PURE__ */ (0, import_jsx_runtime30.jsx)(ArtistMembers, { title: "Members", memberships: artist.members, renderArtistLink }),
|
|
2035
|
+
/* @__PURE__ */ (0, import_jsx_runtime30.jsx)(ArtistMembers, { title: "Member of", memberships: artist.memberOf, renderArtistLink }),
|
|
2036
|
+
artist.tracksCount > 0 && /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
|
|
2134
2037
|
ArtistSongs,
|
|
2135
2038
|
{
|
|
2136
2039
|
artist: { uuid: artist.uuid, name: artist.name },
|
|
@@ -2140,7 +2043,7 @@ function useArtistPanel({
|
|
|
2140
2043
|
}
|
|
2141
2044
|
)
|
|
2142
2045
|
] }),
|
|
2143
|
-
extraContent: artist.albums.length > 0 ? /* @__PURE__ */ (0,
|
|
2046
|
+
extraContent: artist.albums.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(ArtistDiscography, { albums: artist.albums }) : void 0
|
|
2144
2047
|
};
|
|
2145
2048
|
}
|
|
2146
2049
|
}
|
|
@@ -2151,45 +2054,45 @@ var import_ui13 = require("@behindthemusictree/ui");
|
|
|
2151
2054
|
var import_genre_tree17 = require("@behindthemusictree/app-kit/genre-tree");
|
|
2152
2055
|
|
|
2153
2056
|
// src/genre-tree/song/SongPanelContent.tsx
|
|
2154
|
-
var
|
|
2155
|
-
var
|
|
2057
|
+
var import_react15 = require("react");
|
|
2058
|
+
var import_lucide_react10 = require("lucide-react");
|
|
2156
2059
|
var import_ui12 = require("@behindthemusictree/ui");
|
|
2157
2060
|
var import_player11 = require("@behindthemusictree/app-kit/player");
|
|
2158
2061
|
var import_genre_tree16 = require("@behindthemusictree/app-kit/genre-tree");
|
|
2159
|
-
var
|
|
2062
|
+
var import_jsx_runtime31 = require("react/jsx-runtime");
|
|
2160
2063
|
var numberFormat = new Intl.NumberFormat("en");
|
|
2161
2064
|
var dateFormat = new Intl.DateTimeFormat("en", { dateStyle: "medium" });
|
|
2162
2065
|
var externalLink = "text-[var(--color-primary)] hover:underline focus-visible:underline";
|
|
2163
2066
|
function SongHistory({ uuid, getBackendBaseUrl }) {
|
|
2164
|
-
const [open, setOpen] = (0,
|
|
2067
|
+
const [open, setOpen] = (0, import_react15.useState)(false);
|
|
2165
2068
|
const history = (0, import_genre_tree16.useSongHistory)(uuid, getBackendBaseUrl, open);
|
|
2166
2069
|
let body = null;
|
|
2167
|
-
if (history.status === "loading") body = /* @__PURE__ */ (0,
|
|
2168
|
-
else if (history.status === "error") body = /* @__PURE__ */ (0,
|
|
2070
|
+
if (history.status === "loading") body = /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(import_ui12.Skeleton, { className: "h-10", "aria-busy": "true" });
|
|
2071
|
+
else if (history.status === "error") body = /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("p", { className: "text-red-600", children: "Could not load the history." });
|
|
2169
2072
|
else if (history.status === "success")
|
|
2170
|
-
body = history.entries.length === 0 ? /* @__PURE__ */ (0,
|
|
2171
|
-
/* @__PURE__ */ (0,
|
|
2172
|
-
entry.oldValue !== null || entry.newValue !== null ? /* @__PURE__ */ (0,
|
|
2073
|
+
body = history.entries.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("p", { className: "text-[var(--color-text-muted)]", children: "No changes yet." }) : /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("ul", { className: "divide-y divide-[var(--color-border)]", children: history.entries.map((entry) => /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)("li", { className: "py-1.5 text-sm", children: [
|
|
2074
|
+
/* @__PURE__ */ (0, import_jsx_runtime31.jsx)("span", { className: "font-medium", children: entry.action }),
|
|
2075
|
+
entry.oldValue !== null || entry.newValue !== null ? /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)("span", { className: "text-[var(--color-text-muted)]", children: [
|
|
2173
2076
|
" ",
|
|
2174
2077
|
"\u2014 ",
|
|
2175
2078
|
entry.oldValue ?? "none",
|
|
2176
2079
|
" \u2192 ",
|
|
2177
2080
|
entry.newValue ?? "none"
|
|
2178
2081
|
] }) : null,
|
|
2179
|
-
/* @__PURE__ */ (0,
|
|
2082
|
+
/* @__PURE__ */ (0, import_jsx_runtime31.jsxs)("span", { className: "block text-xs text-[var(--color-text-muted)]", children: [
|
|
2180
2083
|
entry.actorPseudo ?? "Anonymous",
|
|
2181
2084
|
" \xB7 ",
|
|
2182
2085
|
dateFormat.format(new Date(entry.createdOn))
|
|
2183
2086
|
] })
|
|
2184
2087
|
] }, entry.uuid)) });
|
|
2185
|
-
return /* @__PURE__ */ (0,
|
|
2088
|
+
return /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)(
|
|
2186
2089
|
"details",
|
|
2187
2090
|
{
|
|
2188
2091
|
onToggle: (event) => setOpen(event.currentTarget.open),
|
|
2189
2092
|
className: "px-6 pb-2.5 mt-2.5 border-t border-[var(--color-border)]",
|
|
2190
2093
|
children: [
|
|
2191
|
-
/* @__PURE__ */ (0,
|
|
2192
|
-
/* @__PURE__ */ (0,
|
|
2094
|
+
/* @__PURE__ */ (0, import_jsx_runtime31.jsx)("summary", { className: "mt-2.5 cursor-pointer text-[0.6875rem] font-semibold uppercase text-[var(--color-text-muted)]", children: "History" }),
|
|
2095
|
+
/* @__PURE__ */ (0, import_jsx_runtime31.jsx)("div", { className: "mt-1.5", children: body })
|
|
2193
2096
|
]
|
|
2194
2097
|
}
|
|
2195
2098
|
);
|
|
@@ -2215,13 +2118,13 @@ function SongPanelContent({
|
|
|
2215
2118
|
const path = genrePath.length > 0 ? genrePath : null;
|
|
2216
2119
|
fields.push({
|
|
2217
2120
|
label: "Genre",
|
|
2218
|
-
value: path ? /* @__PURE__ */ (0,
|
|
2219
|
-
index > 0 && /* @__PURE__ */ (0,
|
|
2220
|
-
/* @__PURE__ */ (0,
|
|
2121
|
+
value: path ? /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("span", { className: "flex flex-wrap items-center gap-x-1", children: path.map((genrePlaylist, index) => /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)("span", { children: [
|
|
2122
|
+
index > 0 && /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("span", { "aria-hidden": "true", children: "\u203A " }),
|
|
2123
|
+
/* @__PURE__ */ (0, import_jsx_runtime31.jsx)("button", { type: "button", onClick: () => onSelectGenre(genrePlaylist), className: "hover:underline", children: genrePlaylist.name })
|
|
2221
2124
|
] }, genrePlaylist.uuid)) }) : song.genre.name
|
|
2222
2125
|
});
|
|
2223
2126
|
} else {
|
|
2224
|
-
fields.push({ label: "Genre", value: /* @__PURE__ */ (0,
|
|
2127
|
+
fields.push({ label: "Genre", value: /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("span", { className: "text-[var(--color-text-muted)]", children: "No genre" }) });
|
|
2225
2128
|
}
|
|
2226
2129
|
if (song.firstReleaseYear) fields.push({ label: "First released", value: song.firstReleaseYear });
|
|
2227
2130
|
const viewCount = song.youtubeVideo?.viewCount;
|
|
@@ -2231,11 +2134,11 @@ function SongPanelContent({
|
|
|
2231
2134
|
const links = [];
|
|
2232
2135
|
if (musicBrainzUrl)
|
|
2233
2136
|
links.push(
|
|
2234
|
-
/* @__PURE__ */ (0,
|
|
2137
|
+
/* @__PURE__ */ (0, import_jsx_runtime31.jsx)("a", { href: musicBrainzUrl, target: "_blank", rel: "noopener noreferrer", className: externalLink, children: "MusicBrainz" }, "mb")
|
|
2235
2138
|
);
|
|
2236
2139
|
if (song.youtubeVideo)
|
|
2237
2140
|
links.push(
|
|
2238
|
-
/* @__PURE__ */ (0,
|
|
2141
|
+
/* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
|
|
2239
2142
|
"a",
|
|
2240
2143
|
{
|
|
2241
2144
|
href: `https://www.youtube.com/watch?v=${encodeURIComponent(song.youtubeVideo.id)}`,
|
|
@@ -2250,33 +2153,33 @@ function SongPanelContent({
|
|
|
2250
2153
|
if (links.length > 0)
|
|
2251
2154
|
fields.push({
|
|
2252
2155
|
label: "Links",
|
|
2253
|
-
value: /* @__PURE__ */ (0,
|
|
2156
|
+
value: /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("span", { className: "flex gap-3", children: links })
|
|
2254
2157
|
});
|
|
2255
|
-
return /* @__PURE__ */ (0,
|
|
2256
|
-
/* @__PURE__ */ (0,
|
|
2257
|
-
unplayableReason ? /* @__PURE__ */ (0,
|
|
2158
|
+
return /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)(import_jsx_runtime31.Fragment, { children: [
|
|
2159
|
+
/* @__PURE__ */ (0, import_jsx_runtime31.jsx)("div", { className: "genre-action-band border-b border-[var(--color-border)]", children: /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)("div", { className: "flex flex-wrap gap-1 px-3.5 py-3", children: [
|
|
2160
|
+
unplayableReason ? /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("p", { className: "flex items-center px-2.5 text-sm text-[var(--color-text-muted)]", children: unplayableReason }) : /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)(
|
|
2258
2161
|
"button",
|
|
2259
2162
|
{
|
|
2260
2163
|
type: "button",
|
|
2261
2164
|
onClick: () => isCurrent ? handlePlayPauseAction() : playNewTrackListFromTrackUuid(song, scope),
|
|
2262
2165
|
className: "group flex flex-col items-center gap-1 w-16 text-xs text-center text-[var(--color-text)] focus-visible:outline-none",
|
|
2263
2166
|
children: [
|
|
2264
|
-
/* @__PURE__ */ (0,
|
|
2167
|
+
/* @__PURE__ */ (0, import_jsx_runtime31.jsx)("span", { className: "flex items-center justify-center w-10 h-10 rounded-full group-focus-visible:ring-2 group-focus-visible:ring-[var(--color-focus-ring)] bg-[var(--color-surface-muted)] transition-colors group-hover:bg-[var(--color-border)]", children: isPlaying ? /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(import_lucide_react10.Pause, { "aria-hidden": "true", className: "w-5 h-5" }) : /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(import_lucide_react10.Play, { "aria-hidden": "true", className: "w-5 h-5" }) }),
|
|
2265
2168
|
isPlaying ? "Pause" : "Play"
|
|
2266
2169
|
]
|
|
2267
2170
|
}
|
|
2268
2171
|
),
|
|
2269
|
-
shareUrl && /* @__PURE__ */ (0,
|
|
2172
|
+
shareUrl && /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(ShareActionButton, { target: shareTarget, url: shareUrl })
|
|
2270
2173
|
] }) }),
|
|
2271
|
-
song.artists && song.artists.length > 0 && /* @__PURE__ */ (0,
|
|
2272
|
-
/* @__PURE__ */ (0,
|
|
2273
|
-
song.essentialGenres && song.essentialGenres.length > 0 && /* @__PURE__ */ (0,
|
|
2274
|
-
/* @__PURE__ */ (0,
|
|
2174
|
+
song.artists && song.artists.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("p", { className: "px-6 pt-2.5 text-[var(--color-text-muted)]", children: /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(import_genre_tree16.ArtistNames, { artists: song.artists, renderArtistLink }) }),
|
|
2175
|
+
/* @__PURE__ */ (0, import_jsx_runtime31.jsx)(import_ui12.FieldList, { items: fields }),
|
|
2176
|
+
song.essentialGenres && song.essentialGenres.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(import_ui12.PanelSection, { title: "Essential in", children: /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("ul", { children: song.essentialGenres.map((genre) => /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("li", { className: "py-0.5", children: genre.name }, genre.uuid)) }) }),
|
|
2177
|
+
/* @__PURE__ */ (0, import_jsx_runtime31.jsx)(SongHistory, { uuid: song.uuid, getBackendBaseUrl })
|
|
2275
2178
|
] });
|
|
2276
2179
|
}
|
|
2277
2180
|
|
|
2278
2181
|
// src/genre-tree/song/useSongPanel.tsx
|
|
2279
|
-
var
|
|
2182
|
+
var import_jsx_runtime32 = require("react/jsx-runtime");
|
|
2280
2183
|
function useSongPanel({
|
|
2281
2184
|
uuid,
|
|
2282
2185
|
scope,
|
|
@@ -2298,24 +2201,24 @@ function useSongPanel({
|
|
|
2298
2201
|
return {
|
|
2299
2202
|
...panel,
|
|
2300
2203
|
title: "Song",
|
|
2301
|
-
content: /* @__PURE__ */ (0,
|
|
2302
|
-
/* @__PURE__ */ (0,
|
|
2303
|
-
/* @__PURE__ */ (0,
|
|
2304
|
-
/* @__PURE__ */ (0,
|
|
2305
|
-
/* @__PURE__ */ (0,
|
|
2204
|
+
content: /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("div", { "aria-busy": "true", className: "flex flex-col gap-2.5 px-6 py-2.5", children: [
|
|
2205
|
+
/* @__PURE__ */ (0, import_jsx_runtime32.jsx)(import_ui13.Skeleton, { className: "h-3 w-16" }),
|
|
2206
|
+
/* @__PURE__ */ (0, import_jsx_runtime32.jsx)(import_ui13.Skeleton, { className: "h-4 w-32" }),
|
|
2207
|
+
/* @__PURE__ */ (0, import_jsx_runtime32.jsx)(import_ui13.Skeleton, { className: "h-3 w-16" }),
|
|
2208
|
+
/* @__PURE__ */ (0, import_jsx_runtime32.jsx)(import_ui13.Skeleton, { className: "h-4 w-24" })
|
|
2306
2209
|
] })
|
|
2307
2210
|
};
|
|
2308
2211
|
case "not-found":
|
|
2309
2212
|
return {
|
|
2310
2213
|
...panel,
|
|
2311
2214
|
title: "Song not found",
|
|
2312
|
-
content: /* @__PURE__ */ (0,
|
|
2215
|
+
content: /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("p", { className: "px-6 py-2.5 text-[var(--color-text-muted)]", children: "This song does not exist." })
|
|
2313
2216
|
};
|
|
2314
2217
|
case "error":
|
|
2315
2218
|
return {
|
|
2316
2219
|
...panel,
|
|
2317
2220
|
title: "Song",
|
|
2318
|
-
content: /* @__PURE__ */ (0,
|
|
2221
|
+
content: /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("p", { className: "px-6 py-2.5 text-red-600", children: "Could not load this song." })
|
|
2319
2222
|
};
|
|
2320
2223
|
case "success": {
|
|
2321
2224
|
const { song } = result;
|
|
@@ -2323,7 +2226,7 @@ function useSongPanel({
|
|
|
2323
2226
|
return {
|
|
2324
2227
|
...panel,
|
|
2325
2228
|
title: song.title,
|
|
2326
|
-
content: /* @__PURE__ */ (0,
|
|
2229
|
+
content: /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
|
|
2327
2230
|
SongPanelContent,
|
|
2328
2231
|
{
|
|
2329
2232
|
song,
|
|
@@ -2343,12 +2246,12 @@ function useSongPanel({
|
|
|
2343
2246
|
// src/genre-tree/SizeMetricToggle.tsx
|
|
2344
2247
|
var import_md = require("react-icons/md");
|
|
2345
2248
|
var import_ui14 = require("@behindthemusictree/ui");
|
|
2346
|
-
var
|
|
2249
|
+
var import_jsx_runtime33 = require("react/jsx-runtime");
|
|
2347
2250
|
function SizeMetricToggle({
|
|
2348
2251
|
value,
|
|
2349
2252
|
onChange
|
|
2350
2253
|
}) {
|
|
2351
|
-
return /* @__PURE__ */ (0,
|
|
2254
|
+
return /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
|
|
2352
2255
|
import_ui14.SegmentedControl,
|
|
2353
2256
|
{
|
|
2354
2257
|
variant: "floating",
|
|
@@ -2356,26 +2259,19 @@ function SizeMetricToggle({
|
|
|
2356
2259
|
value,
|
|
2357
2260
|
onChange,
|
|
2358
2261
|
options: [
|
|
2359
|
-
{ value: "songs", label: /* @__PURE__ */ (0,
|
|
2360
|
-
{ value: "views", label: /* @__PURE__ */ (0,
|
|
2262
|
+
{ value: "songs", label: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(import_md.MdMusicNote, { size: 18, "aria-hidden": true }), "aria-label": "Size by songs", title: "Node size by song count" },
|
|
2263
|
+
{ value: "views", label: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(import_md.MdVisibility, { size: 18, "aria-hidden": true }), "aria-label": "Size by views", title: "Node size by song views" }
|
|
2361
2264
|
]
|
|
2362
2265
|
}
|
|
2363
2266
|
);
|
|
2364
2267
|
}
|
|
2365
2268
|
|
|
2366
2269
|
// src/genre-tree/GenreTreeView.tsx
|
|
2367
|
-
var
|
|
2368
|
-
var PREVIOUS_BUTTON_CSS = `
|
|
2369
|
-
.genre-tree-view .search-overlay .gtv-info-panel-previous { display: none; }
|
|
2370
|
-
.genre-tree-view:has(.search-overlay .gtv-info-panel-previous) .genre-search input { padding-left: 2.75rem; }
|
|
2371
|
-
.genre-tree-view:has(.search-overlay .gtv-info-panel-previous) .genre-search-previous { display: flex; }
|
|
2372
|
-
@keyframes genre-tree-view-previous-in { from { opacity: 0; transform: translate(-0.5rem, -50%); } to { opacity: 1; transform: translate(0, -50%); } }
|
|
2373
|
-
@media (prefers-reduced-motion: no-preference) {
|
|
2374
|
-
.genre-search-previous { animation: genre-tree-view-previous-in 200ms ease-out; }
|
|
2375
|
-
}
|
|
2376
|
-
`;
|
|
2270
|
+
var import_jsx_runtime34 = require("react/jsx-runtime");
|
|
2377
2271
|
var NO_POP_ROOT_TITLE = "This genre tree has no 'Mainstream Pop' root yet";
|
|
2378
|
-
var REGIONS_CLASS = "[--gtv-center-left:var(--layout-center-left)] [--gtv-center-right:var(--layout-center-right)] [--gtv-center-top:var(--layout-band-top)]
|
|
2272
|
+
var REGIONS_CLASS = "[--gtv-center-left:var(--layout-center-left)] [--gtv-center-right:var(--layout-center-right)] [--gtv-center-top:var(--layout-band-top)]";
|
|
2273
|
+
var noop = () => {
|
|
2274
|
+
};
|
|
2379
2275
|
function GenreTreeView({
|
|
2380
2276
|
scope,
|
|
2381
2277
|
handleGenreCreationAction,
|
|
@@ -2429,21 +2325,21 @@ function GenreTreeView({
|
|
|
2429
2325
|
placement = "default",
|
|
2430
2326
|
...focus
|
|
2431
2327
|
}) {
|
|
2432
|
-
const getShareUrlRef = (0,
|
|
2328
|
+
const getShareUrlRef = (0, import_react16.useRef)(getShareUrl);
|
|
2433
2329
|
getShareUrlRef.current = getShareUrl;
|
|
2434
|
-
const [internalArtistUuid, setInternalArtistUuid] = (0,
|
|
2330
|
+
const [internalArtistUuid, setInternalArtistUuid] = (0, import_react16.useState)(null);
|
|
2435
2331
|
const isArtistControlled = controlledArtistUuid !== void 0;
|
|
2436
2332
|
const artistUuid = isArtistControlled ? controlledArtistUuid : internalArtistUuid;
|
|
2437
|
-
const [internalSongUuid, setInternalSongUuid] = (0,
|
|
2333
|
+
const [internalSongUuid, setInternalSongUuid] = (0, import_react16.useState)(null);
|
|
2438
2334
|
const isSongControlled = controlledSongUuid !== void 0;
|
|
2439
2335
|
const songUuid = isSongControlled ? controlledSongUuid : internalSongUuid;
|
|
2440
2336
|
const changeSong = (uuid) => {
|
|
2441
2337
|
if (!isSongControlled) setInternalSongUuid(uuid);
|
|
2442
2338
|
onSongUuidChange?.(uuid);
|
|
2443
2339
|
};
|
|
2444
|
-
const [internalSizeMetric, setInternalSizeMetric] = (0,
|
|
2340
|
+
const [internalSizeMetric, setInternalSizeMetric] = (0, import_react16.useState)("songs");
|
|
2445
2341
|
const sizeMetric = controlledSizeMetric ?? internalSizeMetric;
|
|
2446
|
-
const deferredSizeMetric = (0,
|
|
2342
|
+
const deferredSizeMetric = (0, import_react16.useDeferredValue)(sizeMetric);
|
|
2447
2343
|
const changeSizeMetric = (metric) => {
|
|
2448
2344
|
if (controlledSizeMetric === void 0) setInternalSizeMetric(metric);
|
|
2449
2345
|
onSizeMetricChange?.(metric);
|
|
@@ -2480,7 +2376,7 @@ function GenreTreeView({
|
|
|
2480
2376
|
artistUuid
|
|
2481
2377
|
});
|
|
2482
2378
|
const restoreRevision = viewportRestore?.revision;
|
|
2483
|
-
const [stackedRestoreOwner, setStackedRestoreOwner] = (0,
|
|
2379
|
+
const [stackedRestoreOwner, setStackedRestoreOwner] = (0, import_react16.useState)({ revision: restoreRevision, rootUuid: selectedGenrePlaylist?.root.uuid });
|
|
2484
2380
|
let restoreRootUuid = stackedRestoreOwner.rootUuid;
|
|
2485
2381
|
if (stackedRestoreOwner.revision !== restoreRevision) {
|
|
2486
2382
|
restoreRootUuid = selectedGenrePlaylist?.root.uuid;
|
|
@@ -2496,7 +2392,7 @@ function GenreTreeView({
|
|
|
2496
2392
|
const canSizeByViews = !isArtistFiltered && hasViewsCount(visibleGenrePlaylists);
|
|
2497
2393
|
const artistResult = (0, import_genre_tree19.useArtist)(artistUuid, artistSearchBaseUrl ?? getBackendBaseUrl);
|
|
2498
2394
|
const filterArtistName = artistResult.status === "success" ? artistResult.artist.name : null;
|
|
2499
|
-
const filterArtist = (0,
|
|
2395
|
+
const filterArtist = (0, import_react16.useMemo)(
|
|
2500
2396
|
() => artistUuid !== null && filterArtistName !== null ? { uuid: artistUuid, name: filterArtistName } : null,
|
|
2501
2397
|
[artistUuid, filterArtistName]
|
|
2502
2398
|
);
|
|
@@ -2511,14 +2407,14 @@ function GenreTreeView({
|
|
|
2511
2407
|
if (selectedNodeId !== null) clearSelection();
|
|
2512
2408
|
changeSong(uuid);
|
|
2513
2409
|
};
|
|
2514
|
-
const openSongRef = (0,
|
|
2410
|
+
const openSongRef = (0, import_react16.useRef)(openSong);
|
|
2515
2411
|
openSongRef.current = openSong;
|
|
2516
|
-
const resolvedRenderSongLink = (0,
|
|
2517
|
-
(song) => renderSongLink ? renderSongLink(song) : /* @__PURE__ */ (0,
|
|
2412
|
+
const resolvedRenderSongLink = (0, import_react16.useCallback)(
|
|
2413
|
+
(song) => renderSongLink ? renderSongLink(song) : /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("button", { type: "button", onClick: () => openSongRef.current(song.uuid), className: "hover:underline", children: song.title }),
|
|
2518
2414
|
[renderSongLink]
|
|
2519
2415
|
);
|
|
2520
|
-
const [expandedSongUuid, setExpandedSongUuid] = (0,
|
|
2521
|
-
const [expandedArtistUuid, setExpandedArtistUuid] = (0,
|
|
2416
|
+
const [expandedSongUuid, setExpandedSongUuid] = (0, import_react16.useState)(null);
|
|
2417
|
+
const [expandedArtistUuid, setExpandedArtistUuid] = (0, import_react16.useState)(null);
|
|
2522
2418
|
const artistBaseUrl = artistSearchBaseUrl ?? getBackendBaseUrl;
|
|
2523
2419
|
const songBaseUrl = getBackendBaseUrl;
|
|
2524
2420
|
const artistPanel = useArtistPanel({
|
|
@@ -2526,7 +2422,7 @@ function GenreTreeView({
|
|
|
2526
2422
|
scope,
|
|
2527
2423
|
getBackendBaseUrl: artistBaseUrl,
|
|
2528
2424
|
getShareUrl: getShareUrlRef.current,
|
|
2529
|
-
renderArtistLink: renderArtistLink ?? ((artist) => artist.isSpecialPurpose ? artist.name : /* @__PURE__ */ (0,
|
|
2425
|
+
renderArtistLink: renderArtistLink ?? ((artist) => artist.isSpecialPurpose ? artist.name : /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("button", { type: "button", onClick: () => openArtist(artist.uuid), className: "hover:underline", children: artist.name })),
|
|
2530
2426
|
expanded: controlledArtistExpanded ?? (artistUuid !== null && expandedArtistUuid === artistUuid),
|
|
2531
2427
|
onExpandedChange: (on) => {
|
|
2532
2428
|
if (controlledArtistExpanded === void 0) setExpandedArtistUuid(on ? artistUuid : null);
|
|
@@ -2535,7 +2431,7 @@ function GenreTreeView({
|
|
|
2535
2431
|
renderSongLink: resolvedRenderSongLink,
|
|
2536
2432
|
onClose: () => changeArtist(null)
|
|
2537
2433
|
});
|
|
2538
|
-
const resolvedRenderArtistLink = renderArtistLink ?? ((artist) => artist.isSpecialPurpose ? artist.name : /* @__PURE__ */ (0,
|
|
2434
|
+
const resolvedRenderArtistLink = renderArtistLink ?? ((artist) => artist.isSpecialPurpose ? artist.name : /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("button", { type: "button", onClick: () => openArtist(artist.uuid), className: "hover:underline", children: artist.name }));
|
|
2539
2435
|
const getGenrePath = (genre) => {
|
|
2540
2436
|
const path = [];
|
|
2541
2437
|
let current = visibleGenrePlaylists.find((playlist) => playlist.criteria?.uuid === genre.uuid);
|
|
@@ -2567,9 +2463,8 @@ function GenreTreeView({
|
|
|
2567
2463
|
const builtInSongPanel = overlayPanel || hasSelectedGenreNode ? void 0 : songPanel;
|
|
2568
2464
|
const builtInArtistPanel = overlayPanel || hasSelectedGenreNode || builtInSongPanel ? void 0 : artistPanel;
|
|
2569
2465
|
const builtInPanel = builtInSongPanel ?? builtInArtistPanel;
|
|
2570
|
-
const
|
|
2571
|
-
const [
|
|
2572
|
-
const [uncontrolledExpanded, setUncontrolledExpanded] = (0, import_react17.useState)(false);
|
|
2466
|
+
const [uncontrolledCollapsed, setUncontrolledCollapsed] = (0, import_react16.useState)(false);
|
|
2467
|
+
const [uncontrolledExpanded, setUncontrolledExpanded] = (0, import_react16.useState)(false);
|
|
2573
2468
|
const isCollapsed = collapsed ?? uncontrolledCollapsed;
|
|
2574
2469
|
const isExpanded = expanded ?? uncontrolledExpanded;
|
|
2575
2470
|
const changeCollapsed = (next) => {
|
|
@@ -2580,55 +2475,56 @@ function GenreTreeView({
|
|
|
2580
2475
|
setUncontrolledExpanded(next);
|
|
2581
2476
|
onExpandedChange?.(next);
|
|
2582
2477
|
};
|
|
2583
|
-
(0,
|
|
2478
|
+
(0, import_react16.useEffect)(() => {
|
|
2584
2479
|
setUncontrolledCollapsed(false);
|
|
2585
2480
|
}, [selectedNodeId, artistUuid, songUuid]);
|
|
2586
|
-
const
|
|
2587
|
-
useLeftDetailPanelLayout(!isDetailHidden, placement === "regions");
|
|
2588
|
-
const detailOverlay = placement === "regions" && activeOverlayPanel?.onExpandedChange ? activeOverlayPanel : void 0;
|
|
2589
|
-
const detailExpanded = detailOverlay ? !!detailOverlay.expanded : isExpanded;
|
|
2590
|
-
const onDetailExpandedChange = detailOverlay ? detailOverlay.onExpandedChange : changeExpanded;
|
|
2591
|
-
const infoPanelCuration = {
|
|
2592
|
-
renderDangerZone,
|
|
2593
|
-
expanded: placement === "regions" ? isExpanded : expanded,
|
|
2594
|
-
onExpandedChange: placement === "regions" ? changeExpanded : onExpandedChange,
|
|
2595
|
-
collapsed: placement === "regions" ? isCollapsed : void 0,
|
|
2596
|
-
hideExpandButton: placement === "regions" ? true : void 0,
|
|
2597
|
-
overlayPanel: detailOverlay ? { ...detailOverlay, collapsed: isCollapsed, hideExpandButton: true } : activeOverlayPanel
|
|
2598
|
-
};
|
|
2599
|
-
const [isWheelRevealed, setIsWheelRevealed] = (0, import_react17.useState)(false);
|
|
2481
|
+
const [isWheelRevealed, setIsWheelRevealed] = (0, import_react16.useState)(false);
|
|
2600
2482
|
const usesHandoff = viewMode === "wheel" || viewMode === "pop-core";
|
|
2601
2483
|
const isTreeReady = !isLoading && (!usesHandoff || isWheelRevealed);
|
|
2602
|
-
const
|
|
2603
|
-
const
|
|
2604
|
-
|
|
2605
|
-
|
|
2606
|
-
|
|
2607
|
-
|
|
2608
|
-
|
|
2609
|
-
|
|
2610
|
-
|
|
2611
|
-
|
|
2612
|
-
|
|
2613
|
-
|
|
2614
|
-
|
|
2484
|
+
const [resolveStyle, setResolveStyle] = (0, import_react16.useState)(null);
|
|
2485
|
+
const handleNodeStyleResolverChange = (0, import_react16.useCallback)(
|
|
2486
|
+
(resolver) => setResolveStyle(() => resolver),
|
|
2487
|
+
[]
|
|
2488
|
+
);
|
|
2489
|
+
const panelRef = (0, import_react16.useRef)(null);
|
|
2490
|
+
const obscuredInset = (0, import_ui15.useObscuredInset)(panelRef);
|
|
2491
|
+
const hostPanel = { obscuredInset, onNodeStyleResolverChange: handleNodeStyleResolverChange };
|
|
2492
|
+
const nodeMetric = isArtistFiltered || !canSizeByViews ? "songs" : deferredSizeMetric;
|
|
2493
|
+
const treeNodes = (0, import_react16.useMemo)(() => toTreeNodes(visibleGenrePlaylists, nodeMetric), [visibleGenrePlaylists, nodeMetric]);
|
|
2494
|
+
const relations = (0, import_genre_tree_view4.useGenreNodeRelations)(
|
|
2495
|
+
treeNodes,
|
|
2496
|
+
!overlayPanel && hasSelectedGenreNode ? selectedNodeId : null,
|
|
2497
|
+
resolveStyle
|
|
2498
|
+
);
|
|
2499
|
+
const [selectionHistory, setSelectionHistory] = (0, import_react16.useState)({
|
|
2500
|
+
current: selectedNodeId,
|
|
2501
|
+
previous: null
|
|
2502
|
+
});
|
|
2503
|
+
if (selectionHistory.current !== selectedNodeId) {
|
|
2504
|
+
setSelectionHistory({
|
|
2505
|
+
current: selectedNodeId,
|
|
2506
|
+
previous: selectionHistory.current ?? selectionHistory.previous
|
|
2507
|
+
});
|
|
2508
|
+
}
|
|
2509
|
+
const previousPlaylist = selectionHistory.previous !== null && selectionHistory.previous !== selectedNodeId ? genrePlaylistByNodeId.get(selectionHistory.previous) : void 0;
|
|
2510
|
+
const handlePrevious = previousPlaylist && visibleGenrePlaylists.includes(previousPlaylist) ? () => handleGenreSearchSelect(previousPlaylist) : void 0;
|
|
2615
2511
|
const { showPopup, hidePopup } = (0, import_popup5.usePopup)();
|
|
2616
|
-
const [searchText, setSearchText] = (0,
|
|
2512
|
+
const [searchText, setSearchText] = (0, import_react16.useState)("");
|
|
2617
2513
|
const artistSearchResult = (0, import_genre_tree18.useArtistSearch)(artistBaseUrl, artistSearch ? searchText : "");
|
|
2618
2514
|
const artistGroup = artistSearch ? {
|
|
2619
2515
|
key: "artists",
|
|
2620
2516
|
label: "Artists",
|
|
2621
2517
|
items: artistSearchResult.artists.map((artist) => ({
|
|
2622
2518
|
key: artist.uuid,
|
|
2623
|
-
content: /* @__PURE__ */ (0,
|
|
2624
|
-
/* @__PURE__ */ (0,
|
|
2519
|
+
content: /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)(import_jsx_runtime34.Fragment, { children: [
|
|
2520
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("span", { className: "block truncate font-medium", children: [
|
|
2625
2521
|
artist.name,
|
|
2626
|
-
artist.disambiguation && /* @__PURE__ */ (0,
|
|
2522
|
+
artist.disambiguation && /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("span", { className: "font-normal text-[var(--color-neutral-500)]", children: [
|
|
2627
2523
|
" \xB7 ",
|
|
2628
2524
|
artist.disambiguation
|
|
2629
2525
|
] })
|
|
2630
2526
|
] }),
|
|
2631
|
-
artist.matchedAlias && /* @__PURE__ */ (0,
|
|
2527
|
+
artist.matchedAlias && /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("span", { className: "block truncate text-xs text-[var(--color-neutral-500)]", children: [
|
|
2632
2528
|
"also known as ",
|
|
2633
2529
|
artist.matchedAlias
|
|
2634
2530
|
] })
|
|
@@ -2647,9 +2543,9 @@ function GenreTreeView({
|
|
|
2647
2543
|
label: "Songs",
|
|
2648
2544
|
items: songSearchResult.songs.map((song) => ({
|
|
2649
2545
|
key: song.uuid,
|
|
2650
|
-
content: /* @__PURE__ */ (0,
|
|
2651
|
-
/* @__PURE__ */ (0,
|
|
2652
|
-
/* @__PURE__ */ (0,
|
|
2546
|
+
content: /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("span", { className: (0, import_genre_tree18.isSongSearchResultPlayable)(song) ? void 0 : "opacity-60", children: [
|
|
2547
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsx)("span", { className: "block truncate font-medium", children: song.title }),
|
|
2548
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsx)("span", { className: "block truncate text-xs text-[var(--color-neutral-500)]", children: [song.artists.map((artist) => artist.name).join(", "), song.genre?.name ?? "No genre"].filter(Boolean).join(" \xB7 ") })
|
|
2653
2549
|
] }),
|
|
2654
2550
|
onSelect: () => {
|
|
2655
2551
|
openSong(song.uuid);
|
|
@@ -2675,36 +2571,49 @@ function GenreTreeView({
|
|
|
2675
2571
|
const handleGenreSearchZoomIn = () => {
|
|
2676
2572
|
if (selectedUuid) focus.onFocusGenreChange?.(selectedUuid, "zoom-in");
|
|
2677
2573
|
};
|
|
2678
|
-
const zoomInRef = (0,
|
|
2574
|
+
const zoomInRef = (0, import_react16.useRef)(void 0);
|
|
2679
2575
|
zoomInRef.current = canZoomIn ? handleGenreSearchZoomIn : void 0;
|
|
2680
|
-
const
|
|
2681
|
-
|
|
2682
|
-
|
|
2683
|
-
|
|
2684
|
-
|
|
2685
|
-
|
|
2686
|
-
|
|
2687
|
-
|
|
2688
|
-
|
|
2689
|
-
|
|
2690
|
-
|
|
2691
|
-
|
|
2692
|
-
|
|
2693
|
-
|
|
2694
|
-
|
|
2695
|
-
|
|
2696
|
-
|
|
2697
|
-
|
|
2698
|
-
|
|
2699
|
-
|
|
2700
|
-
|
|
2701
|
-
|
|
2702
|
-
|
|
2703
|
-
|
|
2704
|
-
|
|
2576
|
+
const selectGenreFromPanel = (nodeId) => {
|
|
2577
|
+
const genrePlaylist = genrePlaylistByNodeId.get(nodeId);
|
|
2578
|
+
if (genrePlaylist) handleGenreSearchSelect(genrePlaylist);
|
|
2579
|
+
};
|
|
2580
|
+
const renderGenreBody = (relation) => {
|
|
2581
|
+
const { node } = relation;
|
|
2582
|
+
const family = /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
|
|
2583
|
+
import_genre_tree_view4.GenreNodeFamily,
|
|
2584
|
+
{
|
|
2585
|
+
node,
|
|
2586
|
+
fill: relation.fill,
|
|
2587
|
+
textColor: relation.textColor,
|
|
2588
|
+
parentNode: relation.parentNode,
|
|
2589
|
+
childNodes: relation.childNodes,
|
|
2590
|
+
onSelectNode: selectGenreFromPanel
|
|
2591
|
+
}
|
|
2592
|
+
);
|
|
2593
|
+
const ancestors = /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(import_genre_tree_view4.GenreNodeAncestors, { ancestorNodes: relation.ancestorNodes, onSelectNode: selectGenreFromPanel });
|
|
2594
|
+
const genrePlaylist = genrePlaylistByNodeId.get(node.id);
|
|
2595
|
+
const criteria = genrePlaylist?.criteria;
|
|
2596
|
+
if (!genrePlaylist || !criteria) return { primary: family, aside: ancestors };
|
|
2597
|
+
const genreUuid = criteria.uuid;
|
|
2598
|
+
const parentPlaylist = visibleGenrePlaylists.find(({ uuid }) => uuid === genrePlaylist.parent?.uuid);
|
|
2599
|
+
const canToggleSide = !readOnly && parentPlaylist !== void 0 && parentPlaylist.parent === null;
|
|
2600
|
+
const side = criteria.side ?? "core";
|
|
2601
|
+
const shareTarget = {
|
|
2602
|
+
kind: "genre",
|
|
2603
|
+
genrePlaylistUuid: genrePlaylist.uuid,
|
|
2604
|
+
name: criteria.name,
|
|
2605
|
+
scope,
|
|
2606
|
+
artistUuid
|
|
2607
|
+
};
|
|
2608
|
+
const shareUrl = getShareUrlRef.current?.(shareTarget) ?? void 0;
|
|
2609
|
+
const popSibling = canToggleSide && side === "core" ? visibleGenrePlaylists.find(
|
|
2610
|
+
(sibling) => sibling.parent?.uuid === parentPlaylist.uuid && sibling.uuid !== genrePlaylist.uuid && sibling.criteria?.side === "pop"
|
|
2611
|
+
) : void 0;
|
|
2612
|
+
return {
|
|
2613
|
+
primary: /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)(import_jsx_runtime34.Fragment, { children: [
|
|
2614
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
|
|
2705
2615
|
GenreInfoPanelBody,
|
|
2706
2616
|
{
|
|
2707
|
-
toolbar,
|
|
2708
2617
|
family,
|
|
2709
2618
|
genreUuid,
|
|
2710
2619
|
genrePlaylist,
|
|
@@ -2720,7 +2629,7 @@ function GenreTreeView({
|
|
|
2720
2629
|
onAddChild: readOnly ? void 0 : () => handleGenreCreationAction(criteria),
|
|
2721
2630
|
onRename: readOnly ? void 0 : () => handleGenreRenameAction(criteria),
|
|
2722
2631
|
onChangeParent: readOnly ? void 0 : () => showPopup(
|
|
2723
|
-
/* @__PURE__ */ (0,
|
|
2632
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
|
|
2724
2633
|
ChangeParentPopup,
|
|
2725
2634
|
{
|
|
2726
2635
|
genrePlaylist: { ...genrePlaylist, criteria },
|
|
@@ -2751,49 +2660,65 @@ function GenreTreeView({
|
|
|
2751
2660
|
}
|
|
2752
2661
|
}
|
|
2753
2662
|
),
|
|
2754
|
-
|
|
2755
|
-
}
|
|
2756
|
-
|
|
2757
|
-
|
|
2758
|
-
|
|
2759
|
-
additionalActions,
|
|
2760
|
-
readOnly,
|
|
2761
|
-
handleGenreCreationAction,
|
|
2762
|
-
handleGenreRenameAction,
|
|
2763
|
-
showPopup,
|
|
2764
|
-
hidePopup,
|
|
2765
|
-
onParentChanged,
|
|
2766
|
-
visibleGenrePlaylists,
|
|
2767
|
-
updateGenre,
|
|
2768
|
-
playback,
|
|
2769
|
-
filterArtist,
|
|
2770
|
-
scope,
|
|
2771
|
-
getBackendBaseUrl,
|
|
2772
|
-
criteriaOverviewSchema,
|
|
2773
|
-
renderGenreDetailExtras,
|
|
2774
|
-
renderArtistLink,
|
|
2775
|
-
resolvedRenderSongLink,
|
|
2776
|
-
renderSummary,
|
|
2777
|
-
renderEssentialTracks,
|
|
2778
|
-
renderSongLeading,
|
|
2779
|
-
renderSongActions,
|
|
2780
|
-
renderTracksToolbar
|
|
2781
|
-
]
|
|
2782
|
-
);
|
|
2663
|
+
renderDangerZone?.(node)
|
|
2664
|
+
] }),
|
|
2665
|
+
aside: ancestors
|
|
2666
|
+
};
|
|
2667
|
+
};
|
|
2783
2668
|
const isRotationControlled = controlledAllowWheelRotation !== void 0;
|
|
2784
2669
|
const allowWheelRotation = controlledAllowWheelRotation ?? internalAllowWheelRotation;
|
|
2785
|
-
|
|
2786
|
-
|
|
2670
|
+
let activePanel = null;
|
|
2671
|
+
if (overlayPanel) {
|
|
2672
|
+
activePanel = {
|
|
2673
|
+
title: overlayPanel.title,
|
|
2674
|
+
content: overlayPanel.content,
|
|
2675
|
+
aside: overlayPanel.extraContent,
|
|
2676
|
+
expanded: overlayPanel.expanded ?? false,
|
|
2677
|
+
onExpandedChange: overlayPanel.onExpandedChange,
|
|
2678
|
+
onClose: overlayPanel.onClose,
|
|
2679
|
+
compact: false
|
|
2680
|
+
};
|
|
2681
|
+
} else if (relations) {
|
|
2682
|
+
const { primary, aside } = renderGenreBody(relations);
|
|
2683
|
+
activePanel = {
|
|
2684
|
+
title: relations.node.name,
|
|
2685
|
+
content: primary,
|
|
2686
|
+
aside,
|
|
2687
|
+
expanded: isExpanded,
|
|
2688
|
+
onExpandedChange: changeExpanded,
|
|
2689
|
+
onClose: clearSelection,
|
|
2690
|
+
compact: true,
|
|
2691
|
+
headerAccent: { background: relations.fill, color: relations.textColor }
|
|
2692
|
+
};
|
|
2693
|
+
} else if (builtInPanel) {
|
|
2694
|
+
activePanel = {
|
|
2695
|
+
title: builtInPanel.title,
|
|
2696
|
+
content: builtInPanel.content,
|
|
2697
|
+
aside: builtInPanel.extraContent,
|
|
2698
|
+
expanded: builtInPanel.expanded,
|
|
2699
|
+
onExpandedChange: builtInPanel.onExpandedChange,
|
|
2700
|
+
onClose: builtInPanel.onClose,
|
|
2701
|
+
compact: true
|
|
2702
|
+
};
|
|
2703
|
+
}
|
|
2704
|
+
const isPanelShown = isTreeReady && activePanel !== null;
|
|
2705
|
+
const detailTab = placement === "regions" && activePanel?.onExpandedChange ? {
|
|
2706
|
+
edge: activePanel.expanded ? { label: "Shrink panel", onClick: () => activePanel.onExpandedChange?.(false) } : isCollapsed ? null : { label: "Hide panel", onClick: () => changeCollapsed(true) },
|
|
2707
|
+
center: activePanel.expanded ? null : isCollapsed ? { label: "Show panel", onClick: () => changeCollapsed(false) } : activePanel.onExpandedChange ? { label: "Extend panel", onClick: () => activePanel.onExpandedChange?.(true) } : null
|
|
2708
|
+
} : void 0;
|
|
2709
|
+
const expandButton = placement === "default" && activePanel?.onExpandedChange ? /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
|
|
2710
|
+
import_ui15.IconButton,
|
|
2787
2711
|
{
|
|
2788
|
-
|
|
2789
|
-
|
|
2790
|
-
|
|
2712
|
+
"aria-label": activePanel.expanded ? "Shrink panel" : "Extend panel",
|
|
2713
|
+
style: activePanel.headerAccent && { color: "inherit" },
|
|
2714
|
+
onClick: () => activePanel.onExpandedChange?.(!activePanel.expanded),
|
|
2715
|
+
children: activePanel.expanded ? /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(import_lucide_react12.Minimize2, { "aria-hidden": "true", className: "h-4 w-4" }) : /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(import_lucide_react12.Maximize2, { "aria-hidden": "true", className: "h-4 w-4" })
|
|
2791
2716
|
}
|
|
2792
2717
|
) : null;
|
|
2793
2718
|
const renderArtistFilter = () => {
|
|
2794
2719
|
if (isLoading || !filterArtist) return null;
|
|
2795
|
-
return /* @__PURE__ */ (0,
|
|
2796
|
-
/* @__PURE__ */ (0,
|
|
2720
|
+
return /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("span", { className: "inline-flex items-center overflow-hidden rounded-full bg-[var(--color-neutral-100)] text-sm", children: [
|
|
2721
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
|
|
2797
2722
|
"button",
|
|
2798
2723
|
{
|
|
2799
2724
|
type: "button",
|
|
@@ -2805,7 +2730,7 @@ function GenreTreeView({
|
|
|
2805
2730
|
children: filterArtist.name
|
|
2806
2731
|
}
|
|
2807
2732
|
),
|
|
2808
|
-
/* @__PURE__ */ (0,
|
|
2733
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
|
|
2809
2734
|
"button",
|
|
2810
2735
|
{
|
|
2811
2736
|
type: "button",
|
|
@@ -2817,22 +2742,22 @@ function GenreTreeView({
|
|
|
2817
2742
|
)
|
|
2818
2743
|
] });
|
|
2819
2744
|
};
|
|
2820
|
-
const actions = /* @__PURE__ */ (0,
|
|
2821
|
-
!isLoading && /* @__PURE__ */ (0,
|
|
2745
|
+
const actions = /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)(import_jsx_runtime34.Fragment, { children: [
|
|
2746
|
+
!isLoading && /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
|
|
2822
2747
|
GenreSearch,
|
|
2823
2748
|
{
|
|
2824
2749
|
genrePlaylists: visibleGenrePlaylists,
|
|
2825
2750
|
onSelect: handleGenreSearchSelect,
|
|
2826
|
-
selectedName: selectedGenrePlaylist?.name ?? builtInPanel?.title
|
|
2751
|
+
selectedName: selectedGenrePlaylist?.name ?? (typeof builtInPanel?.title === "string" ? builtInPanel.title : null),
|
|
2827
2752
|
onClear: builtInSongPanel ? () => changeSong(null) : builtInArtistPanel ? () => changeArtist(null) : handleGenreSearchClear,
|
|
2828
2753
|
onPrevious: handlePrevious,
|
|
2829
2754
|
onQueryChange: artistSearch || songSearch ? setSearchText : void 0,
|
|
2830
2755
|
extraGroups
|
|
2831
2756
|
}
|
|
2832
2757
|
),
|
|
2833
|
-
!isLoading && filterArtist && /* @__PURE__ */ (0,
|
|
2834
|
-
/* @__PURE__ */ (0,
|
|
2835
|
-
!isLoading && !isControlled && /* @__PURE__ */ (0,
|
|
2758
|
+
!isLoading && filterArtist && /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("div", { className: "hidden w-full justify-center max-md:flex", children: renderArtistFilter() }),
|
|
2759
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.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: [
|
|
2760
|
+
!isLoading && !isControlled && /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
|
|
2836
2761
|
import_ui15.SegmentedControl,
|
|
2837
2762
|
{
|
|
2838
2763
|
"aria-label": "Tree view mode",
|
|
@@ -2846,13 +2771,13 @@ function GenreTreeView({
|
|
|
2846
2771
|
]
|
|
2847
2772
|
}
|
|
2848
2773
|
),
|
|
2849
|
-
!isLoading && showDisplayOptions && /* @__PURE__ */ (0,
|
|
2774
|
+
!isLoading && showDisplayOptions && /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
|
|
2850
2775
|
"div",
|
|
2851
2776
|
{
|
|
2852
2777
|
className: "flex items-center gap-1",
|
|
2853
2778
|
role: "group",
|
|
2854
2779
|
"aria-label": "Tree display options",
|
|
2855
|
-
children: !isRotationControlled && viewMode !== "stacked" && viewMode !== "outline" && /* @__PURE__ */ (0,
|
|
2780
|
+
children: !isRotationControlled && viewMode !== "stacked" && viewMode !== "outline" && /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
|
|
2856
2781
|
import_ui15.Button,
|
|
2857
2782
|
{
|
|
2858
2783
|
variant: allowWheelRotation ? "default" : "outline",
|
|
@@ -2863,52 +2788,44 @@ function GenreTreeView({
|
|
|
2863
2788
|
)
|
|
2864
2789
|
}
|
|
2865
2790
|
),
|
|
2866
|
-
!isLoading && !readOnly && showAddRoot && /* @__PURE__ */ (0,
|
|
2791
|
+
!isLoading && !readOnly && showAddRoot && /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
|
|
2867
2792
|
import_ui15.IconTextButton,
|
|
2868
2793
|
{
|
|
2869
|
-
icon:
|
|
2794
|
+
icon: import_lucide_react11.Plus,
|
|
2870
2795
|
text: "Add root",
|
|
2871
2796
|
onClick: () => handleGenreCreationAction(null)
|
|
2872
2797
|
}
|
|
2873
2798
|
)
|
|
2874
2799
|
] })
|
|
2875
2800
|
] });
|
|
2876
|
-
return /* @__PURE__ */ (0,
|
|
2801
|
+
return /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)(
|
|
2877
2802
|
"div",
|
|
2878
2803
|
{
|
|
2879
|
-
|
|
2804
|
+
"data-left-panel": isPanelShown && !isCollapsed ? void 0 : "hidden",
|
|
2880
2805
|
className: ["genre-tree-view relative flex flex-col h-full", placement === "regions" && REGIONS_CLASS, className2].filter(Boolean).join(" "),
|
|
2881
2806
|
children: [
|
|
2882
|
-
/* @__PURE__ */ (0,
|
|
2883
|
-
/* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
|
|
2807
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
|
|
2884
2808
|
"div",
|
|
2885
2809
|
{
|
|
2886
2810
|
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))] 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"}`,
|
|
2887
2811
|
children: actions
|
|
2888
2812
|
}
|
|
2889
2813
|
),
|
|
2890
|
-
!isLoading && filterArtist && /* @__PURE__ */ (0,
|
|
2814
|
+
!isLoading && filterArtist && /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
|
|
2891
2815
|
"div",
|
|
2892
2816
|
{
|
|
2893
2817
|
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))]" : "top-5"}`,
|
|
2894
2818
|
children: renderArtistFilter()
|
|
2895
2819
|
}
|
|
2896
2820
|
),
|
|
2897
|
-
|
|
2898
|
-
"div",
|
|
2899
|
-
{
|
|
2900
|
-
className: `absolute top-1/2 z-30 -translate-y-1/2 max-md:hidden transition-[opacity,visibility] duration-150 ease-out ${isTreeReady ? "opacity-100" : "pointer-events-none invisible opacity-0"} ${detailExpanded ? "right-[calc(var(--layout-center-right)-var(--layout-edge-tab-w))]" : isCollapsed ? "left-0" : "left-[calc(var(--layout-gutter)+var(--layout-left-w))]"}`,
|
|
2901
|
-
children: detailTab
|
|
2902
|
-
}
|
|
2903
|
-
),
|
|
2904
|
-
/* @__PURE__ */ (0, import_jsx_runtime35.jsx)("div", { className: "content-container flex-1 min-h-0 flex flex-row gap-4", children: /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("div", { className: "tree-view-container relative flex-1 min-w-0 flex flex-col h-full", children: [
|
|
2905
|
-
!isLoading && viewMode === "outline" && floatingControlsLeading && /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("div", { className: "absolute bottom-3 right-3 z-10", children: floatingControlsLeading }),
|
|
2906
|
-
isLoading ? /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(import_genre_tree_view4.GenreTreeViewSkeleton, { viewMode }) : viewMode === "wheel" ? (
|
|
2821
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsx)("div", { className: "content-container flex-1 min-h-0 flex flex-row gap-4", children: /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("div", { className: "tree-view-container relative flex-1 min-w-0 flex flex-col h-full", children: [
|
|
2822
|
+
!isLoading && viewMode === "outline" && floatingControlsLeading && /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("div", { className: "absolute bottom-3 right-3 z-10", children: floatingControlsLeading }),
|
|
2823
|
+
isLoading ? /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(import_genre_tree_view4.GenreTreeViewSkeleton, { viewMode }) : viewMode === "wheel" ? (
|
|
2907
2824
|
// The info panel's top edge aligns with the tree's; the search bar floats `--layout-panel-inset` below it,
|
|
2908
2825
|
// and the header inset (the bar's height plus that inset) extends the header's fill behind the bar,
|
|
2909
2826
|
// Google Maps style; the 8px bottom padding mirrors the inset above the bar, and the hidden title's height is zeroed.
|
|
2910
2827
|
// The panel's own Zoom in button is hidden: the search bar carries it.
|
|
2911
|
-
/* @__PURE__ */ (0,
|
|
2828
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsx)("div", { className: "tree-container search-overlay relative flex-1 w-full min-h-0 ", children: /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(GenreTreeWheelHandoff, { skeleton: /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(import_genre_tree_view4.GenreTreeWheelSkeleton, {}), onRevealedChange: setIsWheelRevealed, children: /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
|
|
2912
2829
|
GenrePlaylistTreeWheel,
|
|
2913
2830
|
{
|
|
2914
2831
|
scope,
|
|
@@ -2917,29 +2834,26 @@ function GenreTreeView({
|
|
|
2917
2834
|
handleGenreRenameAction,
|
|
2918
2835
|
additionalActions,
|
|
2919
2836
|
onSelectedNodeChange: handleSelectedNodeChange,
|
|
2920
|
-
hideInfoPanelClose: true,
|
|
2921
|
-
hideInfoPanelTitle: true,
|
|
2922
2837
|
onNodeHover: handleNodeHover,
|
|
2923
|
-
|
|
2838
|
+
...hostPanel,
|
|
2924
2839
|
playback,
|
|
2925
2840
|
selectedNodeId,
|
|
2926
2841
|
readOnly,
|
|
2927
2842
|
allowWheelRotation,
|
|
2928
2843
|
sizeMetric: isArtistFiltered || !canSizeByViews ? "songs" : deferredSizeMetric,
|
|
2929
2844
|
busy,
|
|
2930
|
-
floatingControlsLeading: floatingControlsLeading || canSizeByViews ? /* @__PURE__ */ (0,
|
|
2845
|
+
floatingControlsLeading: floatingControlsLeading || canSizeByViews ? /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("div", { className: "flex items-center gap-2", children: [
|
|
2931
2846
|
floatingControlsLeading,
|
|
2932
|
-
canSizeByViews && /* @__PURE__ */ (0,
|
|
2847
|
+
canSizeByViews && /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(SizeMetricToggle, { value: sizeMetric, onChange: changeSizeMetric })
|
|
2933
2848
|
] }) : void 0,
|
|
2934
2849
|
defaultViewport,
|
|
2935
2850
|
viewportRestore,
|
|
2936
|
-
onViewportChange
|
|
2937
|
-
...infoPanelCuration
|
|
2851
|
+
onViewportChange
|
|
2938
2852
|
}
|
|
2939
2853
|
) }) })
|
|
2940
2854
|
) : viewMode === "pop-core" ? (
|
|
2941
2855
|
// Same as the wheel: the header inset extends its fill behind the floating search bar, Google Maps style.
|
|
2942
|
-
/* @__PURE__ */ (0,
|
|
2856
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsx)("div", { className: "tree-container search-overlay relative flex-1 w-full min-h-0 ", children: /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(GenreTreeWheelHandoff, { skeleton: /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(import_genre_tree_view4.GenreTreeWheelSkeleton, {}), onRevealedChange: setIsWheelRevealed, children: /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
|
|
2943
2857
|
GenrePlaylistTreeWheelRadialPopCore,
|
|
2944
2858
|
{
|
|
2945
2859
|
scope,
|
|
@@ -2948,28 +2862,25 @@ function GenreTreeView({
|
|
|
2948
2862
|
handleGenreRenameAction,
|
|
2949
2863
|
additionalActions,
|
|
2950
2864
|
onSelectedNodeChange: handleSelectedNodeChange,
|
|
2951
|
-
hideInfoPanelClose: true,
|
|
2952
|
-
hideInfoPanelTitle: true,
|
|
2953
2865
|
onNodeHover: handleNodeHover,
|
|
2954
|
-
|
|
2866
|
+
...hostPanel,
|
|
2955
2867
|
playback,
|
|
2956
2868
|
selectedNodeId,
|
|
2957
2869
|
readOnly,
|
|
2958
2870
|
allowWheelRotation,
|
|
2959
2871
|
sizeMetric: isArtistFiltered || !canSizeByViews ? "songs" : deferredSizeMetric,
|
|
2960
2872
|
busy,
|
|
2961
|
-
floatingControlsLeading: floatingControlsLeading || canSizeByViews ? /* @__PURE__ */ (0,
|
|
2873
|
+
floatingControlsLeading: floatingControlsLeading || canSizeByViews ? /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("div", { className: "flex items-center gap-2", children: [
|
|
2962
2874
|
floatingControlsLeading,
|
|
2963
|
-
canSizeByViews && /* @__PURE__ */ (0,
|
|
2875
|
+
canSizeByViews && /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(SizeMetricToggle, { value: sizeMetric, onChange: changeSizeMetric })
|
|
2964
2876
|
] }) : void 0,
|
|
2965
2877
|
defaultViewport,
|
|
2966
2878
|
viewportRestore,
|
|
2967
2879
|
onViewportChange,
|
|
2968
|
-
...infoPanelCuration,
|
|
2969
2880
|
...focus
|
|
2970
2881
|
}
|
|
2971
2882
|
) }) })
|
|
2972
|
-
) : viewMode === "outline" ? /* @__PURE__ */ (0,
|
|
2883
|
+
) : viewMode === "outline" ? /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("div", { className: "tree-container flex-1 min-h-0 w-full overflow-y-auto relative", children: /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
|
|
2973
2884
|
GenrePlaylistTreeWheelRadialPopCore,
|
|
2974
2885
|
{
|
|
2975
2886
|
outline: true,
|
|
@@ -2979,22 +2890,19 @@ function GenreTreeView({
|
|
|
2979
2890
|
handleGenreRenameAction,
|
|
2980
2891
|
additionalActions,
|
|
2981
2892
|
onSelectedNodeChange: handleSelectedNodeChange,
|
|
2982
|
-
hideInfoPanelClose: true,
|
|
2983
|
-
hideInfoPanelTitle: true,
|
|
2984
2893
|
onNodeHover: handleNodeHover,
|
|
2985
|
-
|
|
2894
|
+
...hostPanel,
|
|
2986
2895
|
playback,
|
|
2987
2896
|
selectedNodeId,
|
|
2988
|
-
readOnly
|
|
2989
|
-
...infoPanelCuration
|
|
2897
|
+
readOnly
|
|
2990
2898
|
}
|
|
2991
|
-
) }) : /* @__PURE__ */ (0,
|
|
2992
|
-
([uuid, genrePlaylistTreePerRoot]
|
|
2993
|
-
return /* @__PURE__ */ (0,
|
|
2899
|
+
) }) : /* @__PURE__ */ (0, import_jsx_runtime34.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(
|
|
2900
|
+
([uuid, genrePlaylistTreePerRoot]) => {
|
|
2901
|
+
return /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
|
|
2994
2902
|
"div",
|
|
2995
2903
|
{
|
|
2996
2904
|
className: "tree-per-root-container relative shrink-0 h-[28rem] mt-2 mr-16 p-2 bg-[var(--color-neutral-100)] rounded-lg",
|
|
2997
|
-
children: /* @__PURE__ */ (0,
|
|
2905
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("div", { className: "graph-container relative z-10 h-full", children: /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
|
|
2998
2906
|
GenrePlaylistTreePerRoot,
|
|
2999
2907
|
{
|
|
3000
2908
|
scope,
|
|
@@ -3004,26 +2912,45 @@ function GenreTreeView({
|
|
|
3004
2912
|
handleGenreRenameAction,
|
|
3005
2913
|
additionalActions,
|
|
3006
2914
|
onSelectedNodeChange: handleSelectedNodeChange,
|
|
3007
|
-
hideInfoPanelClose: true,
|
|
3008
|
-
hideInfoPanelTitle: true,
|
|
3009
2915
|
onNodeHover: handleNodeHover,
|
|
3010
|
-
|
|
2916
|
+
...hostPanel,
|
|
3011
2917
|
playback,
|
|
3012
2918
|
selectedNodeId: uuid === selectedGenrePlaylist?.root.uuid ? selectedNodeId : null,
|
|
3013
2919
|
readOnly,
|
|
3014
2920
|
wheelZoom: "modifier",
|
|
3015
2921
|
defaultViewport: uuid === selectedGenrePlaylist?.root.uuid ? defaultViewport : void 0,
|
|
3016
2922
|
viewportRestore: uuid === selectedGenrePlaylist?.root.uuid && uuid === restoreRootUuid ? viewportRestore : void 0,
|
|
3017
|
-
onViewportChange: uuid === selectedGenrePlaylist?.root.uuid ? onViewportChange : void 0
|
|
3018
|
-
...infoPanelCuration,
|
|
3019
|
-
overlayPanel: rootIndex === 0 ? activeOverlayPanel : void 0
|
|
2923
|
+
onViewportChange: uuid === selectedGenrePlaylist?.root.uuid ? onViewportChange : void 0
|
|
3020
2924
|
}
|
|
3021
2925
|
) })
|
|
3022
2926
|
},
|
|
3023
2927
|
uuid
|
|
3024
2928
|
);
|
|
3025
2929
|
}
|
|
3026
|
-
) })
|
|
2930
|
+
) }),
|
|
2931
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
|
|
2932
|
+
import_ui15.DetailPanel,
|
|
2933
|
+
{
|
|
2934
|
+
ref: panelRef,
|
|
2935
|
+
side: "left",
|
|
2936
|
+
title: activePanel?.title ?? "",
|
|
2937
|
+
hideTitle: activePanel?.compact,
|
|
2938
|
+
hideClose: activePanel?.compact,
|
|
2939
|
+
headerAccent: activePanel?.headerAccent,
|
|
2940
|
+
headerActions: expandButton,
|
|
2941
|
+
onClose: activePanel?.onClose ?? noop,
|
|
2942
|
+
collapsed: isCollapsed || !isTreeReady || !activePanel,
|
|
2943
|
+
expanded: activePanel?.expanded,
|
|
2944
|
+
onExpandedChange: activePanel?.onExpandedChange,
|
|
2945
|
+
aside: activePanel?.aside,
|
|
2946
|
+
edgeTab: detailTab,
|
|
2947
|
+
headerClassName: activePanel?.compact ? "pt-[calc(var(--layout-search-h)+var(--layout-panel-inset)+0.5rem)]" : void 0,
|
|
2948
|
+
children: activePanel?.aside && !activePanel.expanded ? /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)(import_jsx_runtime34.Fragment, { children: [
|
|
2949
|
+
activePanel.content,
|
|
2950
|
+
activePanel.aside
|
|
2951
|
+
] }) : activePanel?.content
|
|
2952
|
+
}
|
|
2953
|
+
)
|
|
3027
2954
|
] }) })
|
|
3028
2955
|
]
|
|
3029
2956
|
}
|
|
@@ -3031,12 +2958,12 @@ function GenreTreeView({
|
|
|
3031
2958
|
}
|
|
3032
2959
|
|
|
3033
2960
|
// src/genre-tree/GenreDetailPanel.tsx
|
|
3034
|
-
var
|
|
2961
|
+
var import_react17 = require("react");
|
|
3035
2962
|
var import_genre_tree_view5 = require("@behindthemusictree/genre-tree-view");
|
|
3036
2963
|
var import_ui16 = require("@behindthemusictree/ui");
|
|
2964
|
+
var import_lucide_react13 = require("lucide-react");
|
|
3037
2965
|
var import_genre_tree20 = require("@behindthemusictree/app-kit/genre-tree");
|
|
3038
|
-
var
|
|
3039
|
-
var ITEM_COUNT_LABEL = "Songs";
|
|
2966
|
+
var import_jsx_runtime35 = require("react/jsx-runtime");
|
|
3040
2967
|
var RELATIVE_ITEM_COUNT = 1;
|
|
3041
2968
|
function toNode(genre, parentId) {
|
|
3042
2969
|
return {
|
|
@@ -3060,11 +2987,12 @@ function GenreDetailPanel({
|
|
|
3060
2987
|
collapsed,
|
|
3061
2988
|
expanded,
|
|
3062
2989
|
onExpandedChange,
|
|
2990
|
+
edgeTab,
|
|
3063
2991
|
extras
|
|
3064
2992
|
}) {
|
|
3065
2993
|
const { data: detail, isPending, isError } = (0, import_genre_tree20.useFetchGenreDetail)(genreUuid, scope, getBackendBaseUrl);
|
|
3066
2994
|
const playback = useGenrePlaylistPlayback({ scope, genrePlaylists: [] });
|
|
3067
|
-
const view = (0,
|
|
2995
|
+
const view = (0, import_react17.useMemo)(() => {
|
|
3068
2996
|
if (!detail) return null;
|
|
3069
2997
|
const rootColor = (0, import_genre_tree_view5.getGenreTreeColor)(detail.root.wikidataId);
|
|
3070
2998
|
const relative = (genre, parentId) => ({
|
|
@@ -3072,7 +3000,7 @@ function GenreDetailPanel({
|
|
|
3072
3000
|
fill: (0, import_genre_tree_view5.tintSurface)(rootColor),
|
|
3073
3001
|
textColor: import_genre_tree_view5.TEXT_COLOR
|
|
3074
3002
|
});
|
|
3075
|
-
const
|
|
3003
|
+
const ancestors2 = [...detail.ascendants].sort((a, b) => b.degree - a.degree);
|
|
3076
3004
|
return {
|
|
3077
3005
|
node: {
|
|
3078
3006
|
id: detail.uuid,
|
|
@@ -3084,57 +3012,72 @@ function GenreDetailPanel({
|
|
|
3084
3012
|
fill: rootColor,
|
|
3085
3013
|
parentNode: detail.parent ? relative(detail.parent, null) : null,
|
|
3086
3014
|
childNodes: detail.children.map((child) => relative(child, detail.uuid)),
|
|
3087
|
-
ancestorNodes:
|
|
3088
|
-
({ ascendant }, index) => relative(ascendant, index === 0 ? null :
|
|
3015
|
+
ancestorNodes: ancestors2.map(
|
|
3016
|
+
({ ascendant }, index) => relative(ascendant, index === 0 ? null : ancestors2[index - 1].ascendant.uuid)
|
|
3089
3017
|
)
|
|
3090
3018
|
};
|
|
3091
3019
|
}, [detail]);
|
|
3092
3020
|
if (isError) {
|
|
3093
|
-
return /* @__PURE__ */ (0,
|
|
3021
|
+
return /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("div", { role: "alert", className: "p-4 text-sm text-[var(--color-text)]", children: "This genre could not be loaded." });
|
|
3094
3022
|
}
|
|
3095
3023
|
if (isPending || !detail || !view) {
|
|
3096
|
-
return /* @__PURE__ */ (0,
|
|
3097
|
-
/* @__PURE__ */ (0,
|
|
3098
|
-
/* @__PURE__ */ (0,
|
|
3099
|
-
/* @__PURE__ */ (0,
|
|
3024
|
+
return /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("div", { className: "flex flex-col gap-3 p-4", "aria-busy": "true", "data-testid": "genre-detail-panel-skeleton", children: [
|
|
3025
|
+
/* @__PURE__ */ (0, import_jsx_runtime35.jsx)(import_ui16.Skeleton, { className: "h-6 w-2/3" }),
|
|
3026
|
+
/* @__PURE__ */ (0, import_jsx_runtime35.jsx)(import_ui16.Skeleton, { className: "h-4 w-full" }),
|
|
3027
|
+
/* @__PURE__ */ (0, import_jsx_runtime35.jsx)(import_ui16.Skeleton, { className: "h-4 w-3/4" })
|
|
3100
3028
|
] });
|
|
3101
3029
|
}
|
|
3102
|
-
const
|
|
3103
|
-
|
|
3104
|
-
|
|
3105
|
-
{
|
|
3106
|
-
toolbar: sections.toolbar,
|
|
3107
|
-
family: sections.family,
|
|
3108
|
-
genreUuid: detail.uuid,
|
|
3109
|
-
genrePlaylist: { ...detail.criteriaPlaylist, tracksCount: detail.tracksCount },
|
|
3110
|
-
wikidataId: detail.wikidataId,
|
|
3111
|
-
scope,
|
|
3112
|
-
getBackendBaseUrl,
|
|
3113
|
-
playback,
|
|
3114
|
-
band: { node, onZoomIn, shareUrl, shareTarget: shareUrl ? shareTarget : void 0 },
|
|
3115
|
-
extras
|
|
3116
|
-
}
|
|
3117
|
-
),
|
|
3118
|
-
aside: null
|
|
3119
|
-
});
|
|
3120
|
-
return /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
|
|
3121
|
-
import_genre_tree_view5.InfoPanel,
|
|
3030
|
+
const selectGenre = (nodeId) => onSelectGenre(nodeId);
|
|
3031
|
+
const family = /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
|
|
3032
|
+
import_genre_tree_view5.GenreNodeFamily,
|
|
3122
3033
|
{
|
|
3123
3034
|
node: view.node,
|
|
3124
3035
|
fill: view.fill,
|
|
3125
3036
|
textColor: import_genre_tree_view5.ACCENT_TEXT_COLOR,
|
|
3126
3037
|
parentNode: view.parentNode,
|
|
3127
3038
|
childNodes: view.childNodes,
|
|
3128
|
-
|
|
3039
|
+
onSelectNode: selectGenre
|
|
3040
|
+
}
|
|
3041
|
+
);
|
|
3042
|
+
const ancestors = /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(import_genre_tree_view5.GenreNodeAncestors, { ancestorNodes: view.ancestorNodes, onSelectNode: selectGenre });
|
|
3043
|
+
return /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)(
|
|
3044
|
+
import_ui16.DetailPanel,
|
|
3045
|
+
{
|
|
3129
3046
|
side: "left",
|
|
3047
|
+
title: view.node.name,
|
|
3048
|
+
headerAccent: { background: view.fill, color: import_genre_tree_view5.ACCENT_TEXT_COLOR },
|
|
3049
|
+
headerActions: onExpandedChange ? /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
|
|
3050
|
+
import_ui16.IconButton,
|
|
3051
|
+
{
|
|
3052
|
+
"aria-label": expanded ? "Shrink panel" : "Extend panel",
|
|
3053
|
+
style: { color: "inherit" },
|
|
3054
|
+
onClick: () => onExpandedChange(!expanded),
|
|
3055
|
+
children: expanded ? /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(import_lucide_react13.Minimize2, { "aria-hidden": "true", className: "h-4 w-4" }) : /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(import_lucide_react13.Maximize2, { "aria-hidden": "true", className: "h-4 w-4" })
|
|
3056
|
+
}
|
|
3057
|
+
) : void 0,
|
|
3130
3058
|
onClose,
|
|
3131
|
-
|
|
3132
|
-
itemCountLabel: ITEM_COUNT_LABEL,
|
|
3133
|
-
renderInfoPanelBody: renderBody,
|
|
3059
|
+
collapsed,
|
|
3134
3060
|
expanded,
|
|
3135
3061
|
onExpandedChange,
|
|
3136
|
-
|
|
3137
|
-
|
|
3062
|
+
edgeTab,
|
|
3063
|
+
aside: ancestors,
|
|
3064
|
+
children: [
|
|
3065
|
+
/* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
|
|
3066
|
+
GenreInfoPanelBody,
|
|
3067
|
+
{
|
|
3068
|
+
family,
|
|
3069
|
+
genreUuid: detail.uuid,
|
|
3070
|
+
genrePlaylist: { ...detail.criteriaPlaylist, tracksCount: detail.tracksCount },
|
|
3071
|
+
wikidataId: detail.wikidataId,
|
|
3072
|
+
scope,
|
|
3073
|
+
getBackendBaseUrl,
|
|
3074
|
+
playback,
|
|
3075
|
+
band: { node: view.node, onZoomIn, shareUrl, shareTarget: shareUrl ? shareTarget : void 0 },
|
|
3076
|
+
extras
|
|
3077
|
+
}
|
|
3078
|
+
),
|
|
3079
|
+
!expanded && ancestors
|
|
3080
|
+
]
|
|
3138
3081
|
}
|
|
3139
3082
|
);
|
|
3140
3083
|
}
|
|
@@ -3143,13 +3086,13 @@ function GenreDetailPanel({
|
|
|
3143
3086
|
var import_genre_tree_view6 = require("@behindthemusictree/genre-tree-view");
|
|
3144
3087
|
|
|
3145
3088
|
// src/genre-tree/track-list-sidebar/TrackListSidebar.tsx
|
|
3146
|
-
var
|
|
3147
|
-
var
|
|
3089
|
+
var import_react18 = require("react");
|
|
3090
|
+
var import_lucide_react14 = require("lucide-react");
|
|
3148
3091
|
var import_genre_tree21 = require("@behindthemusictree/app-kit/genre-tree");
|
|
3149
3092
|
var import_genre_tree22 = require("@behindthemusictree/app-kit/genre-tree");
|
|
3150
|
-
var
|
|
3151
|
-
var
|
|
3152
|
-
var useBrowserLayoutEffect = typeof window === "undefined" ?
|
|
3093
|
+
var import_track_noun3 = require("@behindthemusictree/app-kit/track-noun");
|
|
3094
|
+
var import_jsx_runtime36 = require("react/jsx-runtime");
|
|
3095
|
+
var useBrowserLayoutEffect = typeof window === "undefined" ? import_react18.useEffect : import_react18.useLayoutEffect;
|
|
3153
3096
|
function TrackListSidebar({
|
|
3154
3097
|
className: className2 = "",
|
|
3155
3098
|
renderDuration,
|
|
@@ -3162,17 +3105,17 @@ function TrackListSidebar({
|
|
|
3162
3105
|
renderSongLink
|
|
3163
3106
|
}) {
|
|
3164
3107
|
const { trackList, loadMore, autoAdvanceScrollRequest } = (0, import_genre_tree21.useTrackList)();
|
|
3165
|
-
const trackNoun = (0,
|
|
3166
|
-
const trackListRef = (0,
|
|
3167
|
-
const previousOriginRef = (0,
|
|
3168
|
-
const handledAutoAdvanceRequestIdRef = (0,
|
|
3169
|
-
const shouldFollowPlaybackRef = (0,
|
|
3170
|
-
const programmaticScrollTopRef = (0,
|
|
3171
|
-
const userScrollIntentRef = (0,
|
|
3172
|
-
const userScrollIntentTimerRef = (0,
|
|
3173
|
-
const loadMoreSentinelRef = (0,
|
|
3108
|
+
const trackNoun = (0, import_track_noun3.useTrackNoun)();
|
|
3109
|
+
const trackListRef = (0, import_react18.useRef)(null);
|
|
3110
|
+
const previousOriginRef = (0, import_react18.useRef)(trackList?.origin ?? null);
|
|
3111
|
+
const handledAutoAdvanceRequestIdRef = (0, import_react18.useRef)(null);
|
|
3112
|
+
const shouldFollowPlaybackRef = (0, import_react18.useRef)(true);
|
|
3113
|
+
const programmaticScrollTopRef = (0, import_react18.useRef)(null);
|
|
3114
|
+
const userScrollIntentRef = (0, import_react18.useRef)(false);
|
|
3115
|
+
const userScrollIntentTimerRef = (0, import_react18.useRef)(null);
|
|
3116
|
+
const loadMoreSentinelRef = (0, import_react18.useRef)(null);
|
|
3174
3117
|
const hasMore = !!trackList && trackList.nextPage !== null;
|
|
3175
|
-
(0,
|
|
3118
|
+
(0, import_react18.useEffect)(() => {
|
|
3176
3119
|
const sentinel = loadMoreSentinelRef.current;
|
|
3177
3120
|
if (!hasMore || !sentinel) return;
|
|
3178
3121
|
const observer = new IntersectionObserver((entries) => {
|
|
@@ -3192,11 +3135,11 @@ function TrackListSidebar({
|
|
|
3192
3135
|
programmaticScrollTopRef.current = null;
|
|
3193
3136
|
if (trackListRef.current) trackListRef.current.scrollTop = 0;
|
|
3194
3137
|
}, [trackList?.origin]);
|
|
3195
|
-
(0,
|
|
3138
|
+
(0, import_react18.useEffect)(() => {
|
|
3196
3139
|
const list = trackListRef.current;
|
|
3197
3140
|
if (!isCollapsed && list?.scrollTop === 0) shouldFollowPlaybackRef.current = true;
|
|
3198
3141
|
}, [isCollapsed]);
|
|
3199
|
-
(0,
|
|
3142
|
+
(0, import_react18.useEffect)(
|
|
3200
3143
|
() => () => {
|
|
3201
3144
|
if (userScrollIntentTimerRef.current !== null) clearTimeout(userScrollIntentTimerRef.current);
|
|
3202
3145
|
},
|
|
@@ -3250,25 +3193,25 @@ function TrackListSidebar({
|
|
|
3250
3193
|
}
|
|
3251
3194
|
};
|
|
3252
3195
|
const positionClasses = layout === "inline" ? "relative w-full flex h-full flex-col" : "fixed right-0 w-[50rem] flex flex-col";
|
|
3253
|
-
return trackList ? /* @__PURE__ */ (0,
|
|
3196
|
+
return trackList ? /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)(
|
|
3254
3197
|
"div",
|
|
3255
3198
|
{
|
|
3256
3199
|
"data-theme": "dark",
|
|
3257
3200
|
className: `track-list-sidebar ${positionClasses} rounded-2xl bg-[var(--color-surface)] pb-1 ${className2}`,
|
|
3258
3201
|
style: layout === "fixed" ? { top: "63.5px", maxHeight: "calc(100vh - 63.5px - 79px)" } : void 0,
|
|
3259
3202
|
children: [
|
|
3260
|
-
/* @__PURE__ */ (0,
|
|
3261
|
-
/* @__PURE__ */ (0,
|
|
3262
|
-
/* @__PURE__ */ (0,
|
|
3263
|
-
/* @__PURE__ */ (0,
|
|
3264
|
-
/* @__PURE__ */ (0,
|
|
3203
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("div", { className: "header flex h-16 items-center px-4 py-2 text-[var(--color-text)]", children: [
|
|
3204
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("div", { className: "min-w-0 flex flex-1 flex-col justify-center", children: [
|
|
3205
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("div", { className: "origin flex text-xl", children: [
|
|
3206
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)("div", { className: "from h-auto flex flex-col justify-center items-center mr-2", children: "From" }),
|
|
3207
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.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_runtime36.jsx)("div", { className: "name max-w-full truncate", children: trackList.origin.label }) })
|
|
3265
3208
|
] }),
|
|
3266
|
-
/* @__PURE__ */ (0,
|
|
3209
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("div", { className: "info flex items-center text-sm text-[var(--color-text-muted)]", children: [
|
|
3267
3210
|
trackList.origin.type === import_genre_tree22.TrackListOriginType.GENRE_PLAYLIST ? "Genre \u2022 " : trackList.origin.type === import_genre_tree22.TrackListOriginType.ARTIST ? "Artist \u2022 " : `${trackNoun.singular} playlist \u2022 `,
|
|
3268
3211
|
`${trackList.total} ${trackList.total > 1 ? trackNoun.plural : trackNoun.singular}`
|
|
3269
3212
|
] })
|
|
3270
3213
|
] }),
|
|
3271
|
-
(isCollapsed && onExpand || !isCollapsed && onMinimize) && /* @__PURE__ */ (0,
|
|
3214
|
+
(isCollapsed && onExpand || !isCollapsed && onMinimize) && /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
|
|
3272
3215
|
"button",
|
|
3273
3216
|
{
|
|
3274
3217
|
type: "button",
|
|
@@ -3277,11 +3220,11 @@ function TrackListSidebar({
|
|
|
3277
3220
|
"aria-expanded": !isCollapsed,
|
|
3278
3221
|
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"}`,
|
|
3279
3222
|
onClick: isCollapsed ? onExpand : onMinimize,
|
|
3280
|
-
children: /* @__PURE__ */ (0,
|
|
3223
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(import_lucide_react14.ListMusic, { "aria-hidden": "true", className: "h-5 w-5" })
|
|
3281
3224
|
}
|
|
3282
3225
|
)
|
|
3283
3226
|
] }),
|
|
3284
|
-
!isCollapsed && /* @__PURE__ */ (0,
|
|
3227
|
+
!isCollapsed && /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)(
|
|
3285
3228
|
"ul",
|
|
3286
3229
|
{
|
|
3287
3230
|
ref: trackListRef,
|
|
@@ -3291,7 +3234,7 @@ function TrackListSidebar({
|
|
|
3291
3234
|
onPointerDown: markUserScrollIntent,
|
|
3292
3235
|
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",
|
|
3293
3236
|
children: [
|
|
3294
|
-
trackList.tracks.map((track, index) => /* @__PURE__ */ (0,
|
|
3237
|
+
trackList.tracks.map((track, index) => /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("li", { "data-track-uuid": track.uuid, children: /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
|
|
3295
3238
|
TrackItem,
|
|
3296
3239
|
{
|
|
3297
3240
|
track,
|
|
@@ -3302,7 +3245,7 @@ function TrackListSidebar({
|
|
|
3302
3245
|
renderSongLink
|
|
3303
3246
|
}
|
|
3304
3247
|
) }, track.uuid)),
|
|
3305
|
-
hasMore && /* @__PURE__ */ (0,
|
|
3248
|
+
hasMore && /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("li", { ref: loadMoreSentinelRef, "aria-hidden": "true", className: "h-px" })
|
|
3306
3249
|
]
|
|
3307
3250
|
}
|
|
3308
3251
|
)
|
|
@@ -3312,16 +3255,17 @@ function TrackListSidebar({
|
|
|
3312
3255
|
}
|
|
3313
3256
|
|
|
3314
3257
|
// src/genre-tree/PlayerPanel.tsx
|
|
3315
|
-
var
|
|
3316
|
-
var
|
|
3258
|
+
var import_react19 = require("react");
|
|
3259
|
+
var import_tailwind_merge = require("tailwind-merge");
|
|
3317
3260
|
var import_player13 = require("@behindthemusictree/app-kit/player");
|
|
3318
3261
|
var import_genre_tree24 = require("@behindthemusictree/app-kit/genre-tree");
|
|
3262
|
+
var import_ui17 = require("@behindthemusictree/ui");
|
|
3319
3263
|
|
|
3320
3264
|
// src/genre-tree/PlayerControls.tsx
|
|
3321
|
-
var
|
|
3265
|
+
var import_lucide_react15 = require("lucide-react");
|
|
3322
3266
|
var import_genre_tree23 = require("@behindthemusictree/app-kit/genre-tree");
|
|
3323
3267
|
var import_player12 = require("@behindthemusictree/app-kit/player");
|
|
3324
|
-
var
|
|
3268
|
+
var import_jsx_runtime37 = require("react/jsx-runtime");
|
|
3325
3269
|
function PlayerControls() {
|
|
3326
3270
|
const {
|
|
3327
3271
|
duration,
|
|
@@ -3340,15 +3284,15 @@ function PlayerControls() {
|
|
|
3340
3284
|
const safeDuration = Number.isFinite(duration) && duration > 0 ? duration : 0;
|
|
3341
3285
|
const safeCurrentTime = Number.isFinite(currentTime) ? Math.max(0, Math.min(currentTime, safeDuration)) : 0;
|
|
3342
3286
|
const isPlaying = playState === import_player12.PlayStates.PLAYING;
|
|
3343
|
-
return /* @__PURE__ */ (0,
|
|
3287
|
+
return /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)(
|
|
3344
3288
|
"section",
|
|
3345
3289
|
{
|
|
3346
3290
|
"aria-label": "Player controls",
|
|
3347
3291
|
className: "player-controls flex shrink-0 flex-col gap-2 border-b border-zinc-800 px-3 py-2 text-zinc-200",
|
|
3348
3292
|
children: [
|
|
3349
|
-
/* @__PURE__ */ (0,
|
|
3350
|
-
/* @__PURE__ */ (0,
|
|
3351
|
-
/* @__PURE__ */ (0,
|
|
3293
|
+
/* @__PURE__ */ (0, import_jsx_runtime37.jsxs)("div", { className: "flex min-w-0 items-center gap-2 text-xs tabular-nums text-zinc-400", children: [
|
|
3294
|
+
/* @__PURE__ */ (0, import_jsx_runtime37.jsx)("span", { "aria-label": "Elapsed time", children: (0, import_genre_tree23.formatTime)(safeCurrentTime) }),
|
|
3295
|
+
/* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
|
|
3352
3296
|
"input",
|
|
3353
3297
|
{
|
|
3354
3298
|
"aria-label": "Seek",
|
|
@@ -3362,11 +3306,11 @@ function PlayerControls() {
|
|
|
3362
3306
|
onChange: (event) => seekTo(Number(event.currentTarget.value))
|
|
3363
3307
|
}
|
|
3364
3308
|
),
|
|
3365
|
-
/* @__PURE__ */ (0,
|
|
3309
|
+
/* @__PURE__ */ (0, import_jsx_runtime37.jsx)("span", { "aria-label": "Duration", children: (0, import_genre_tree23.formatTime)(safeDuration) })
|
|
3366
3310
|
] }),
|
|
3367
|
-
/* @__PURE__ */ (0,
|
|
3368
|
-
/* @__PURE__ */ (0,
|
|
3369
|
-
/* @__PURE__ */ (0,
|
|
3311
|
+
/* @__PURE__ */ (0, import_jsx_runtime37.jsxs)("div", { className: "grid min-h-9 grid-cols-[1fr_auto_1fr] items-center gap-3", children: [
|
|
3312
|
+
/* @__PURE__ */ (0, import_jsx_runtime37.jsxs)("div", { className: "col-start-2 flex items-center justify-center gap-2", children: [
|
|
3313
|
+
/* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
|
|
3370
3314
|
"button",
|
|
3371
3315
|
{
|
|
3372
3316
|
type: "button",
|
|
@@ -3375,10 +3319,10 @@ function PlayerControls() {
|
|
|
3375
3319
|
disabled: !isReady || !hasPreviousTrack,
|
|
3376
3320
|
onClick: playPreviousTrack,
|
|
3377
3321
|
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",
|
|
3378
|
-
children: /* @__PURE__ */ (0,
|
|
3322
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(import_lucide_react15.SkipBack, { "aria-hidden": "true", className: "h-4 w-4" })
|
|
3379
3323
|
}
|
|
3380
3324
|
),
|
|
3381
|
-
/* @__PURE__ */ (0,
|
|
3325
|
+
/* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
|
|
3382
3326
|
"button",
|
|
3383
3327
|
{
|
|
3384
3328
|
type: "button",
|
|
@@ -3387,10 +3331,10 @@ function PlayerControls() {
|
|
|
3387
3331
|
disabled: !isReady,
|
|
3388
3332
|
onClick: handlePlayPauseAction,
|
|
3389
3333
|
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",
|
|
3390
|
-
children: isPlaying ? /* @__PURE__ */ (0,
|
|
3334
|
+
children: isPlaying ? /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(import_lucide_react15.Pause, { "aria-hidden": "true", className: "h-4 w-4", fill: "currentColor" }) : /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(import_lucide_react15.Play, { "aria-hidden": "true", className: "h-4 w-4", fill: "currentColor" })
|
|
3391
3335
|
}
|
|
3392
3336
|
),
|
|
3393
|
-
/* @__PURE__ */ (0,
|
|
3337
|
+
/* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
|
|
3394
3338
|
"button",
|
|
3395
3339
|
{
|
|
3396
3340
|
type: "button",
|
|
@@ -3399,14 +3343,14 @@ function PlayerControls() {
|
|
|
3399
3343
|
disabled: !isReady || !hasNextTrack,
|
|
3400
3344
|
onClick: playNextTrack,
|
|
3401
3345
|
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",
|
|
3402
|
-
children: /* @__PURE__ */ (0,
|
|
3346
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(import_lucide_react15.SkipForward, { "aria-hidden": "true", className: "h-4 w-4" })
|
|
3403
3347
|
}
|
|
3404
3348
|
)
|
|
3405
3349
|
] }),
|
|
3406
|
-
/* @__PURE__ */ (0,
|
|
3407
|
-
volume === 0 ? /* @__PURE__ */ (0,
|
|
3408
|
-
/* @__PURE__ */ (0,
|
|
3409
|
-
/* @__PURE__ */ (0,
|
|
3350
|
+
/* @__PURE__ */ (0, import_jsx_runtime37.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: [
|
|
3351
|
+
volume === 0 ? /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(import_lucide_react15.VolumeX, { "aria-hidden": "true", className: "h-[0.7rem] w-[0.7rem] shrink-0" }) : /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(import_lucide_react15.Volume2, { "aria-hidden": "true", className: "h-[0.7rem] w-[0.7rem] shrink-0" }),
|
|
3352
|
+
/* @__PURE__ */ (0, import_jsx_runtime37.jsx)("span", { className: "sr-only", children: "Volume" }),
|
|
3353
|
+
/* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
|
|
3410
3354
|
"input",
|
|
3411
3355
|
{
|
|
3412
3356
|
"aria-label": "Volume",
|
|
@@ -3428,7 +3372,7 @@ function PlayerControls() {
|
|
|
3428
3372
|
}
|
|
3429
3373
|
|
|
3430
3374
|
// src/genre-tree/PlayerPanel.tsx
|
|
3431
|
-
var
|
|
3375
|
+
var import_jsx_runtime38 = require("react/jsx-runtime");
|
|
3432
3376
|
var PANEL_ID = "player-panel";
|
|
3433
3377
|
var DEFAULT_EXTENDED_WIDTH = "calc(100vw - var(--layout-center-left) - var(--layout-gutter))";
|
|
3434
3378
|
function PlayerPanel({
|
|
@@ -3442,12 +3386,12 @@ function PlayerPanel({
|
|
|
3442
3386
|
}) {
|
|
3443
3387
|
const { playerTrackObject } = (0, import_player13.usePlayer)();
|
|
3444
3388
|
const { toggleTrackListSidebar, isTrackListSidebarVisible } = (0, import_genre_tree24.useTrackListSidebarVisibility)();
|
|
3445
|
-
const [lastLoadedTrackTitle, setLastLoadedTrackTitle] = (0,
|
|
3389
|
+
const [lastLoadedTrackTitle, setLastLoadedTrackTitle] = (0, import_react19.useState)("");
|
|
3446
3390
|
const loadedTrackTitle = playerTrackObject?.track.title;
|
|
3447
|
-
(0,
|
|
3391
|
+
(0, import_react19.useEffect)(() => {
|
|
3448
3392
|
if (loadedTrackTitle) setLastLoadedTrackTitle(loadedTrackTitle);
|
|
3449
3393
|
}, [loadedTrackTitle]);
|
|
3450
|
-
const [uncontrolledExtended, setUncontrolledExtended] = (0,
|
|
3394
|
+
const [uncontrolledExtended, setUncontrolledExtended] = (0, import_react19.useState)(false);
|
|
3451
3395
|
const isExtendRequested = expanded ?? uncontrolledExtended;
|
|
3452
3396
|
const setIsExtendRequested = (next) => {
|
|
3453
3397
|
setUncontrolledExtended(next);
|
|
@@ -3468,11 +3412,11 @@ function PlayerPanel({
|
|
|
3468
3412
|
onClick: () => setIsExtendRequested(true),
|
|
3469
3413
|
expanded: false
|
|
3470
3414
|
} : null;
|
|
3471
|
-
return /* @__PURE__ */ (0,
|
|
3415
|
+
return /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)(
|
|
3472
3416
|
"div",
|
|
3473
3417
|
{
|
|
3474
3418
|
id: PANEL_ID,
|
|
3475
|
-
className: (0,
|
|
3419
|
+
className: (0, import_tailwind_merge.twMerge)(
|
|
3476
3420
|
"fixed right-[var(--layout-gutter)] top-[var(--layout-band-top)] z-40 max-h-[calc(100vh-var(--layout-band-top)-3.5rem)]",
|
|
3477
3421
|
!isExtended && "w-[var(--layout-right-w)]",
|
|
3478
3422
|
isTrackListSidebarVisible && "h-[calc(100vh-var(--layout-band-top)-3.5rem)]",
|
|
@@ -3481,8 +3425,8 @@ function PlayerPanel({
|
|
|
3481
3425
|
),
|
|
3482
3426
|
style: isExtended ? { width: extendedWidth } : void 0,
|
|
3483
3427
|
children: [
|
|
3484
|
-
/* @__PURE__ */ (0,
|
|
3485
|
-
PanelEdgeTab,
|
|
3428
|
+
/* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
|
|
3429
|
+
import_ui17.PanelEdgeTab,
|
|
3486
3430
|
{
|
|
3487
3431
|
side: "right",
|
|
3488
3432
|
edge: tabEdge,
|
|
@@ -3491,30 +3435,30 @@ function PlayerPanel({
|
|
|
3491
3435
|
className: "absolute right-full top-1/2 -translate-y-1/2"
|
|
3492
3436
|
}
|
|
3493
3437
|
),
|
|
3494
|
-
/* @__PURE__ */ (0,
|
|
3438
|
+
/* @__PURE__ */ (0, import_jsx_runtime38.jsxs)(
|
|
3495
3439
|
"div",
|
|
3496
3440
|
{
|
|
3497
|
-
className: (0,
|
|
3441
|
+
className: (0, import_tailwind_merge.twMerge)(
|
|
3498
3442
|
"flex h-full max-h-[inherit] overflow-hidden rounded-[var(--radius-panel,1rem)] bg-zinc-950 text-zinc-100 shadow-[0_1px_2px_rgba(0,0,0,0.5),0_2px_6px_2px_rgba(0,0,0,0.3)]",
|
|
3499
3443
|
isExtended ? "flex-row" : "flex-col"
|
|
3500
3444
|
),
|
|
3501
3445
|
children: [
|
|
3502
|
-
/* @__PURE__ */ (0,
|
|
3503
|
-
/* @__PURE__ */ (0,
|
|
3504
|
-
/* @__PURE__ */ (0,
|
|
3505
|
-
/* @__PURE__ */ (0,
|
|
3506
|
-
playerTrackObject?.loadError && /* @__PURE__ */ (0,
|
|
3446
|
+
/* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("div", { className: "flex w-[var(--layout-right-w)] shrink-0 flex-col", children: [
|
|
3447
|
+
/* @__PURE__ */ (0, import_jsx_runtime38.jsx)("div", { className: "flex shrink-0 items-center justify-between gap-2 border-b border-zinc-800 p-2", children: /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("span", { className: "min-w-0 truncate text-sm font-semibold", children: loadedTrackTitle || lastLoadedTrackTitle }) }),
|
|
3448
|
+
/* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("div", { className: "relative w-full shrink-0", children: [
|
|
3449
|
+
/* @__PURE__ */ (0, import_jsx_runtime38.jsx)(import_player13.PlayerVideoSurface, { className: "aspect-video w-full bg-black" }),
|
|
3450
|
+
playerTrackObject?.loadError && /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("span", { className: "absolute bottom-2 left-2 right-2 text-xs text-red-400", children: playerTrackObject.loadError })
|
|
3507
3451
|
] }),
|
|
3508
|
-
/* @__PURE__ */ (0,
|
|
3452
|
+
/* @__PURE__ */ (0, import_jsx_runtime38.jsx)(PlayerControls, {})
|
|
3509
3453
|
] }),
|
|
3510
|
-
/* @__PURE__ */ (0,
|
|
3454
|
+
/* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
|
|
3511
3455
|
TrackListSidebar,
|
|
3512
3456
|
{
|
|
3513
3457
|
layout: "inline",
|
|
3514
3458
|
isCollapsed: !isTrackListSidebarVisible,
|
|
3515
3459
|
onExpand: toggleTrackListSidebar,
|
|
3516
3460
|
onMinimize: hideSongList,
|
|
3517
|
-
className: (0,
|
|
3461
|
+
className: (0, import_tailwind_merge.twMerge)(
|
|
3518
3462
|
"min-h-0 min-w-0 flex-1",
|
|
3519
3463
|
isExtended && "border-l border-zinc-800"
|
|
3520
3464
|
),
|
|
@@ -3534,11 +3478,11 @@ function PlayerPanel({
|
|
|
3534
3478
|
var import_uuid = require("uuid");
|
|
3535
3479
|
var import_ai = require("react-icons/ai");
|
|
3536
3480
|
var import_genre_tree25 = require("@behindthemusictree/app-kit/genre-tree");
|
|
3537
|
-
var
|
|
3481
|
+
var import_jsx_runtime39 = require("react/jsx-runtime");
|
|
3538
3482
|
function Rating({ rating, handleChange }) {
|
|
3539
3483
|
const instanceId = (0, import_uuid.v4)();
|
|
3540
|
-
return /* @__PURE__ */ (0,
|
|
3541
|
-
/* @__PURE__ */ (0,
|
|
3484
|
+
return /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("div", { className: "flex items-center", children: [...Array(6)].map((_, i) => /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("div", { className: `relative ${i === 0 ? "mr-4" : "mr-1"}`, children: [
|
|
3485
|
+
/* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
|
|
3542
3486
|
"input",
|
|
3543
3487
|
{
|
|
3544
3488
|
id: `star-${instanceId}-${i}`,
|
|
@@ -3550,16 +3494,16 @@ function Rating({ rating, handleChange }) {
|
|
|
3550
3494
|
onChange: handleChange
|
|
3551
3495
|
}
|
|
3552
3496
|
),
|
|
3553
|
-
/* @__PURE__ */ (0,
|
|
3554
|
-
/* @__PURE__ */ (0,
|
|
3497
|
+
/* @__PURE__ */ (0, import_jsx_runtime39.jsx)("label", { htmlFor: `star-${instanceId}-${i}`, className: "cursor-pointer", children: i === 0 ? /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("div", { className: "flex", children: [
|
|
3498
|
+
/* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
|
|
3555
3499
|
import_ai.AiOutlineStar,
|
|
3556
3500
|
{
|
|
3557
3501
|
className: `w-7 h-7 absolute top-0 left-0 ${rating === import_genre_tree25.FORM_RATING_NULL_VALUE ? "text-[var(--color-accent-rating)]" : "text-[var(--color-text-muted)]"}`
|
|
3558
3502
|
}
|
|
3559
3503
|
),
|
|
3560
|
-
/* @__PURE__ */ (0,
|
|
3504
|
+
/* @__PURE__ */ (0, import_jsx_runtime39.jsx)("span", { className: "flex-grow w-8" }),
|
|
3561
3505
|
" "
|
|
3562
|
-
] }) : /* @__PURE__ */ (0,
|
|
3506
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
|
|
3563
3507
|
import_ai.AiFillStar,
|
|
3564
3508
|
{
|
|
3565
3509
|
className: `w-7 h-7 absolute top-0 left-0 ${(rating ?? -1) >= i ? "text-[var(--color-accent-rating)]" : "text-[var(--color-text-muted)]"}`
|
|
@@ -3579,13 +3523,11 @@ function Rating({ rating, handleChange }) {
|
|
|
3579
3523
|
GenreTreeView,
|
|
3580
3524
|
GenreTreeViewSkeleton,
|
|
3581
3525
|
GenreTreeWheelSkeleton,
|
|
3582
|
-
PanelEdgeTab,
|
|
3583
3526
|
PlayerPanel,
|
|
3584
3527
|
Rating,
|
|
3585
3528
|
TrackItem,
|
|
3586
3529
|
TrackListSidebar,
|
|
3587
3530
|
TrackPositionPlayPause,
|
|
3588
|
-
useGenrePlaylistPlayback
|
|
3589
|
-
useLeftDetailPanelLayout
|
|
3531
|
+
useGenrePlaylistPlayback
|
|
3590
3532
|
});
|
|
3591
3533
|
//# sourceMappingURL=index.cjs.map
|