@behindthemusictree/app-kit-ui 38.0.0 → 40.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-F7H5XPWU.js → chunk-I2TEOHVG.js} +635 -586
- package/dist/chunk-I2TEOHVG.js.map +1 -0
- package/dist/genre-tree/index.cjs +770 -724
- package/dist/genre-tree/index.cjs.map +1 -1
- package/dist/genre-tree/index.d.ts +24 -13
- package/dist/genre-tree/index.js +1 -1
- package/dist/index.cjs +765 -719
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +1 -1
- package/package.json +6 -6
- package/dist/chunk-F7H5XPWU.js.map +0 -1
|
@@ -48,14 +48,14 @@ __export(genre_tree_exports, {
|
|
|
48
48
|
module.exports = __toCommonJS(genre_tree_exports);
|
|
49
49
|
|
|
50
50
|
// src/genre-tree/GenreTreeView.tsx
|
|
51
|
-
var
|
|
51
|
+
var import_react19 = require("react");
|
|
52
52
|
var import_react_query3 = require("@tanstack/react-query");
|
|
53
|
-
var
|
|
54
|
-
var
|
|
55
|
-
var
|
|
53
|
+
var import_lucide_react14 = require("lucide-react");
|
|
54
|
+
var import_lucide_react15 = require("lucide-react");
|
|
55
|
+
var import_ui21 = require("@behindthemusictree/ui");
|
|
56
56
|
var import_genre_tree_view5 = require("@behindthemusictree/genre-tree-view");
|
|
57
|
-
var
|
|
58
|
-
var
|
|
57
|
+
var import_genre_tree30 = require("@behindthemusictree/app-kit/genre-tree");
|
|
58
|
+
var import_popup4 = require("@behindthemusictree/app-kit/popup");
|
|
59
59
|
|
|
60
60
|
// src/genre-tree/playlist-tree/size-metric.ts
|
|
61
61
|
var import_genre_tree = require("@behindthemusictree/app-kit/genre-tree");
|
|
@@ -69,7 +69,7 @@ var genrePlaylistSize = (genrePlaylist, metric) => {
|
|
|
69
69
|
};
|
|
70
70
|
|
|
71
71
|
// src/genre-tree/playlist-tree/toTreeNodes.ts
|
|
72
|
-
function toTreeNodes(genrePlaylists, sizeMetric) {
|
|
72
|
+
function toTreeNodes(genrePlaylists, sizeMetric, focusUuids) {
|
|
73
73
|
return genrePlaylists.map((genrePlaylist) => ({
|
|
74
74
|
id: genrePlaylist.uuid,
|
|
75
75
|
parentId: genrePlaylist.parent?.uuid ?? null,
|
|
@@ -80,7 +80,8 @@ function toTreeNodes(genrePlaylists, sizeMetric) {
|
|
|
80
80
|
side: genrePlaylist.criteria?.side ?? void 0,
|
|
81
81
|
wikidataId: genrePlaylist.criteria?.wikidataId ?? null,
|
|
82
82
|
umbrella: genrePlaylist.isUmbrella,
|
|
83
|
-
scene: genrePlaylist.scene ?? void 0
|
|
83
|
+
scene: genrePlaylist.scene ?? void 0,
|
|
84
|
+
muted: focusUuids ? !focusUuids.has(genrePlaylist.uuid) : void 0
|
|
84
85
|
}));
|
|
85
86
|
}
|
|
86
87
|
|
|
@@ -89,7 +90,12 @@ var import_genre_tree3 = require("@behindthemusictree/app-kit/genre-tree");
|
|
|
89
90
|
var import_react3 = require("react");
|
|
90
91
|
var import_genre_tree_view = require("@behindthemusictree/genre-tree-view");
|
|
91
92
|
var import_player = require("@behindthemusictree/app-kit/player");
|
|
93
|
+
|
|
94
|
+
// src/genre-tree/playlist-tree/useGenrePlaylistPlayback.tsx
|
|
95
|
+
var import_react2 = require("react");
|
|
96
|
+
var import_genre_tree2 = require("@behindthemusictree/app-kit/genre-tree");
|
|
92
97
|
var import_popup = require("@behindthemusictree/app-kit/popup");
|
|
98
|
+
var import_transport = require("@behindthemusictree/app-kit/transport");
|
|
93
99
|
|
|
94
100
|
// src/popup/InternalErrorPopup.tsx
|
|
95
101
|
var import_lucide_react2 = require("lucide-react");
|
|
@@ -305,38 +311,40 @@ function InternalErrorPopup({ errorCode, contactEmail, ...rest }) {
|
|
|
305
311
|
);
|
|
306
312
|
}
|
|
307
313
|
|
|
308
|
-
// src/genre-tree/playlist-tree/
|
|
309
|
-
var
|
|
310
|
-
|
|
311
|
-
// src/genre-tree/playlist-tree/useGenrePlaylistPlayback.ts
|
|
312
|
-
var import_react2 = require("react");
|
|
313
|
-
var import_genre_tree2 = require("@behindthemusictree/app-kit/genre-tree");
|
|
314
|
+
// src/genre-tree/playlist-tree/useGenrePlaylistPlayback.tsx
|
|
315
|
+
var import_jsx_runtime5 = require("react/jsx-runtime");
|
|
314
316
|
function useGenrePlaylistPlayback({
|
|
315
317
|
scope,
|
|
316
318
|
genrePlaylists,
|
|
317
319
|
artist = null
|
|
318
320
|
}) {
|
|
319
321
|
const { trackList, playNewTrackListFromGenrePlaylist } = (0, import_genre_tree2.useTrackList)();
|
|
322
|
+
const { showPopup } = (0, import_popup.usePopup)();
|
|
320
323
|
const origin = trackList?.origin;
|
|
321
|
-
const
|
|
324
|
+
const playing = (0, import_react2.useMemo)(() => {
|
|
322
325
|
if (!origin || origin.type !== import_genre_tree2.TrackListOriginType.GENRE_PLAYLIST || origin.scope !== scope) return null;
|
|
323
326
|
const playlistOrigin = origin;
|
|
324
327
|
if (playlistOrigin.artistUuid !== artist?.uuid) return null;
|
|
325
328
|
const playlist = genrePlaylists.find((item) => item.uuid === origin.uuid) ?? playlistOrigin.criteriaPlaylist;
|
|
326
329
|
const expected = scope === "reference" && playlist && !("criteria" in playlist && playlist.criteria === null) ? (0, import_genre_tree2.defaultGenreMusicSelection)(import_genre_tree2.GenreCatalogueCountsSchema.parse(playlist)) : void 0;
|
|
327
|
-
|
|
328
|
-
return origin.uuid;
|
|
330
|
+
return { uuid: origin.uuid, selectionKey: (0, import_genre_tree2.genreMusicSelectionKey)(playlistOrigin.selection ?? expected).join() };
|
|
329
331
|
}, [origin, artist, genrePlaylists, scope]);
|
|
330
|
-
const play = (0, import_react2.useCallback)(async (playlist) => {
|
|
332
|
+
const play = (0, import_react2.useCallback)(async (playlist, requested) => {
|
|
331
333
|
if (artist && !playlist.criteria) return;
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
334
|
+
try {
|
|
335
|
+
const selection = scope === "reference" && playlist.criteria !== null ? requested ?? (0, import_genre_tree2.defaultGenreMusicSelection)(import_genre_tree2.GenreCatalogueCountsSchema.parse(playlist)) : void 0;
|
|
336
|
+
await (selection || artist ? playNewTrackListFromGenrePlaylist(playlist, scope, { selection, ...artist && { artistUuid: artist.uuid } }) : playNewTrackListFromGenrePlaylist(playlist, scope));
|
|
337
|
+
} catch (error) {
|
|
338
|
+
console.error("Failed to load genre playlist tracks:", error);
|
|
339
|
+
if (error instanceof import_genre_tree2.TracksFailureAlreadyReportedError) return;
|
|
340
|
+
showPopup(/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(InternalErrorPopup, { errorCode: error instanceof import_transport.AppError ? error.code : import_transport.ErrorCode.CLIENT_UNKNOWN }));
|
|
341
|
+
}
|
|
342
|
+
}, [artist, scope, playNewTrackListFromGenrePlaylist, showPopup]);
|
|
343
|
+
return (0, import_react2.useMemo)(() => ({ playing, play }), [playing, play]);
|
|
336
344
|
}
|
|
337
345
|
|
|
338
346
|
// src/genre-tree/playlist-tree/TreePerRoot.tsx
|
|
339
|
-
var
|
|
347
|
+
var import_jsx_runtime6 = require("react/jsx-runtime");
|
|
340
348
|
function GenrePlaylistTreePerRoot({
|
|
341
349
|
scope,
|
|
342
350
|
className: className2,
|
|
@@ -355,24 +363,16 @@ function GenrePlaylistTreePerRoot({
|
|
|
355
363
|
viewportRestore,
|
|
356
364
|
onViewportChange,
|
|
357
365
|
playback,
|
|
366
|
+
focusUuids,
|
|
358
367
|
...hostPanel
|
|
359
368
|
}) {
|
|
360
369
|
const { isPlaying, setIsPlaying } = (0, import_player.usePlayer)();
|
|
361
370
|
const defaultPlayback = useGenrePlaylistPlayback({ scope, genrePlaylists: genrePlaylistTreePerRoot });
|
|
362
|
-
const {
|
|
363
|
-
const
|
|
371
|
+
const { playing, play } = playback ?? defaultPlayback;
|
|
372
|
+
const playingNodeId = playing?.uuid ?? null;
|
|
364
373
|
const nodes = (0, import_react3.useMemo)(
|
|
365
|
-
() => genrePlaylistTreePerRoot
|
|
366
|
-
|
|
367
|
-
parentId: genrePlaylist.parent?.uuid ?? null,
|
|
368
|
-
name: genrePlaylist.name,
|
|
369
|
-
itemCount: (0, import_genre_tree3.genrePlaylistTrackCount)(genrePlaylist),
|
|
370
|
-
actionable: Boolean(genrePlaylist.criteria),
|
|
371
|
-
side: genrePlaylist.criteria?.side ?? void 0,
|
|
372
|
-
wikidataId: genrePlaylist.criteria?.wikidataId ?? null,
|
|
373
|
-
umbrella: genrePlaylist.isUmbrella
|
|
374
|
-
})),
|
|
375
|
-
[genrePlaylistTreePerRoot]
|
|
374
|
+
() => toTreeNodes(genrePlaylistTreePerRoot, "songs", focusUuids),
|
|
375
|
+
[genrePlaylistTreePerRoot, focusUuids]
|
|
376
376
|
);
|
|
377
377
|
const handlePlayPause = (0, import_react3.useCallback)(
|
|
378
378
|
(nodeId) => {
|
|
@@ -385,18 +385,14 @@ function GenrePlaylistTreePerRoot({
|
|
|
385
385
|
if ((0, import_genre_tree3.genrePlaylistTrackCount)(genrePlaylist) === 0) {
|
|
386
386
|
return;
|
|
387
387
|
}
|
|
388
|
-
play(genrePlaylist)
|
|
389
|
-
console.error("Failed to load genre playlist tracks:", error);
|
|
390
|
-
showPopup(/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(InternalErrorPopup, { errorCode: import_transport.ErrorCode.CLIENT_UNKNOWN }));
|
|
391
|
-
});
|
|
388
|
+
void play(genrePlaylist);
|
|
392
389
|
},
|
|
393
390
|
[
|
|
394
391
|
genrePlaylistTreePerRoot,
|
|
395
392
|
playingNodeId,
|
|
396
393
|
isPlaying,
|
|
397
394
|
setIsPlaying,
|
|
398
|
-
play
|
|
399
|
-
showPopup
|
|
395
|
+
play
|
|
400
396
|
]
|
|
401
397
|
);
|
|
402
398
|
const handleAddChild = (0, import_react3.useCallback)(
|
|
@@ -419,7 +415,7 @@ function GenrePlaylistTreePerRoot({
|
|
|
419
415
|
if (confirm(`Are you sure you want to delete "${node.name}"?`)) {
|
|
420
416
|
}
|
|
421
417
|
}, []);
|
|
422
|
-
return /* @__PURE__ */ (0,
|
|
418
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
423
419
|
import_genre_tree_view.GenreTree,
|
|
424
420
|
{
|
|
425
421
|
className: className2,
|
|
@@ -450,9 +446,7 @@ var import_genre_tree4 = require("@behindthemusictree/app-kit/genre-tree");
|
|
|
450
446
|
var import_react4 = require("react");
|
|
451
447
|
var import_genre_tree_view2 = require("@behindthemusictree/genre-tree-view");
|
|
452
448
|
var import_player2 = require("@behindthemusictree/app-kit/player");
|
|
453
|
-
var
|
|
454
|
-
var import_transport2 = require("@behindthemusictree/app-kit/transport");
|
|
455
|
-
var import_jsx_runtime6 = require("react/jsx-runtime");
|
|
449
|
+
var import_jsx_runtime7 = require("react/jsx-runtime");
|
|
456
450
|
function GenrePlaylistTreeWheel({
|
|
457
451
|
scope,
|
|
458
452
|
className: className2,
|
|
@@ -473,23 +467,16 @@ function GenrePlaylistTreeWheel({
|
|
|
473
467
|
viewportRestore,
|
|
474
468
|
onViewportChange,
|
|
475
469
|
playback,
|
|
470
|
+
focusUuids,
|
|
476
471
|
...hostPanel
|
|
477
472
|
}) {
|
|
478
473
|
const { isPlaying, setIsPlaying } = (0, import_player2.usePlayer)();
|
|
479
474
|
const defaultPlayback = useGenrePlaylistPlayback({ scope, genrePlaylists });
|
|
480
|
-
const {
|
|
481
|
-
const
|
|
475
|
+
const { playing, play } = playback ?? defaultPlayback;
|
|
476
|
+
const playingNodeId = playing?.uuid ?? null;
|
|
482
477
|
const nodes = (0, import_react4.useMemo)(
|
|
483
|
-
() => genrePlaylists
|
|
484
|
-
|
|
485
|
-
parentId: genrePlaylist.parent?.uuid ?? null,
|
|
486
|
-
name: genrePlaylist.name,
|
|
487
|
-
itemCount: genrePlaylistSize(genrePlaylist, sizeMetric),
|
|
488
|
-
actionable: Boolean(genrePlaylist.criteria),
|
|
489
|
-
side: genrePlaylist.criteria?.side ?? void 0,
|
|
490
|
-
wikidataId: genrePlaylist.criteria?.wikidataId ?? null
|
|
491
|
-
})),
|
|
492
|
-
[genrePlaylists, sizeMetric]
|
|
478
|
+
() => toTreeNodes(genrePlaylists, sizeMetric, focusUuids),
|
|
479
|
+
[genrePlaylists, sizeMetric, focusUuids]
|
|
493
480
|
);
|
|
494
481
|
const handlePlayPause = (0, import_react4.useCallback)(
|
|
495
482
|
(nodeId) => {
|
|
@@ -502,18 +489,14 @@ function GenrePlaylistTreeWheel({
|
|
|
502
489
|
if ((0, import_genre_tree4.genrePlaylistTrackCount)(genrePlaylist) === 0) {
|
|
503
490
|
return;
|
|
504
491
|
}
|
|
505
|
-
play(genrePlaylist)
|
|
506
|
-
console.error("Failed to load genre playlist tracks:", error);
|
|
507
|
-
showPopup(/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(InternalErrorPopup, { errorCode: import_transport2.ErrorCode.CLIENT_UNKNOWN }));
|
|
508
|
-
});
|
|
492
|
+
void play(genrePlaylist);
|
|
509
493
|
},
|
|
510
494
|
[
|
|
511
495
|
genrePlaylists,
|
|
512
496
|
playingNodeId,
|
|
513
497
|
isPlaying,
|
|
514
498
|
setIsPlaying,
|
|
515
|
-
play
|
|
516
|
-
showPopup
|
|
499
|
+
play
|
|
517
500
|
]
|
|
518
501
|
);
|
|
519
502
|
const handleAddChild = (0, import_react4.useCallback)(
|
|
@@ -536,7 +519,7 @@ function GenrePlaylistTreeWheel({
|
|
|
536
519
|
if (confirm(`Are you sure you want to delete "${node.name}"?`)) {
|
|
537
520
|
}
|
|
538
521
|
}, []);
|
|
539
|
-
return /* @__PURE__ */ (0,
|
|
522
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
540
523
|
import_genre_tree_view2.GenreTreeWheel,
|
|
541
524
|
{
|
|
542
525
|
className: className2,
|
|
@@ -568,7 +551,7 @@ var import_genre_tree5 = require("@behindthemusictree/app-kit/genre-tree");
|
|
|
568
551
|
var import_react5 = require("react");
|
|
569
552
|
var import_genre_tree_view3 = require("@behindthemusictree/genre-tree-view");
|
|
570
553
|
var import_player3 = require("@behindthemusictree/app-kit/player");
|
|
571
|
-
var
|
|
554
|
+
var import_jsx_runtime8 = require("react/jsx-runtime");
|
|
572
555
|
function GenrePlaylistTreeWheelRadialPopCore(props) {
|
|
573
556
|
const {
|
|
574
557
|
scope,
|
|
@@ -599,8 +582,9 @@ function GenrePlaylistTreeWheelRadialPopCore(props) {
|
|
|
599
582
|
};
|
|
600
583
|
const { isPlaying, setIsPlaying } = (0, import_player3.usePlayer)();
|
|
601
584
|
const defaultPlayback = useGenrePlaylistPlayback({ scope, genrePlaylists });
|
|
602
|
-
const {
|
|
603
|
-
const
|
|
585
|
+
const { playing, play } = playback ?? defaultPlayback;
|
|
586
|
+
const playingNodeId = playing?.uuid ?? null;
|
|
587
|
+
const nodes = (0, import_react5.useMemo)(() => toTreeNodes(genrePlaylists, sizeMetric, props.focusUuids), [genrePlaylists, sizeMetric, props.focusUuids]);
|
|
604
588
|
const handlePlayPause = (0, import_react5.useCallback)(
|
|
605
589
|
(nodeId) => {
|
|
606
590
|
const genrePlaylist = genrePlaylists.find((g) => g.uuid === nodeId);
|
|
@@ -612,9 +596,7 @@ function GenrePlaylistTreeWheelRadialPopCore(props) {
|
|
|
612
596
|
if ((0, import_genre_tree5.genrePlaylistTrackCount)(genrePlaylist) === 0) {
|
|
613
597
|
return;
|
|
614
598
|
}
|
|
615
|
-
play(genrePlaylist)
|
|
616
|
-
console.error("Failed to load genre playlist tracks:", error);
|
|
617
|
-
});
|
|
599
|
+
void play(genrePlaylist);
|
|
618
600
|
},
|
|
619
601
|
[genrePlaylists, playingNodeId, isPlaying, setIsPlaying, play]
|
|
620
602
|
);
|
|
@@ -654,7 +636,7 @@ function GenrePlaylistTreeWheelRadialPopCore(props) {
|
|
|
654
636
|
onSelectedNodeChange,
|
|
655
637
|
...hostPanel
|
|
656
638
|
};
|
|
657
|
-
return outline ? /* @__PURE__ */ (0,
|
|
639
|
+
return outline ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_genre_tree_view3.GenreTreeOutline, { ...treeProps }) : /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
658
640
|
import_genre_tree_view3.GenreTreeWheelRadialPopCore,
|
|
659
641
|
{
|
|
660
642
|
...treeProps,
|
|
@@ -671,7 +653,7 @@ function GenrePlaylistTreeWheelRadialPopCore(props) {
|
|
|
671
653
|
|
|
672
654
|
// src/genre-tree/GenreTreeWheelHandoff.tsx
|
|
673
655
|
var import_react6 = require("react");
|
|
674
|
-
var
|
|
656
|
+
var import_jsx_runtime9 = require("react/jsx-runtime");
|
|
675
657
|
function GenreTreeWheelHandoff({ skeleton, children, onRevealedChange }) {
|
|
676
658
|
const [revealed, setRevealed] = (0, import_react6.useState)(false);
|
|
677
659
|
const onRevealedChangeRef = (0, import_react6.useRef)(onRevealedChange);
|
|
@@ -690,8 +672,8 @@ function GenreTreeWheelHandoff({ skeleton, children, onRevealedChange }) {
|
|
|
690
672
|
cancelAnimationFrame(innerFrame);
|
|
691
673
|
};
|
|
692
674
|
}, []);
|
|
693
|
-
return /* @__PURE__ */ (0,
|
|
694
|
-
/* @__PURE__ */ (0,
|
|
675
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "relative w-full h-full", children: [
|
|
676
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
695
677
|
"div",
|
|
696
678
|
{
|
|
697
679
|
className: "absolute inset-0 transition-opacity duration-150 ease-out",
|
|
@@ -700,7 +682,7 @@ function GenreTreeWheelHandoff({ skeleton, children, onRevealedChange }) {
|
|
|
700
682
|
children
|
|
701
683
|
}
|
|
702
684
|
),
|
|
703
|
-
!revealed && /* @__PURE__ */ (0,
|
|
685
|
+
!revealed && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "absolute inset-0", "aria-hidden": "true", children: skeleton })
|
|
704
686
|
] });
|
|
705
687
|
}
|
|
706
688
|
|
|
@@ -715,7 +697,7 @@ var import_genre_tree9 = require("@behindthemusictree/app-kit/genre-tree");
|
|
|
715
697
|
// src/genre-tree/search/SearchBox.tsx
|
|
716
698
|
var import_react7 = require("react");
|
|
717
699
|
var import_ui3 = require("@behindthemusictree/ui");
|
|
718
|
-
var
|
|
700
|
+
var import_jsx_runtime10 = require("react/jsx-runtime");
|
|
719
701
|
function SearchBox({
|
|
720
702
|
label,
|
|
721
703
|
placeholder,
|
|
@@ -737,7 +719,7 @@ function SearchBox({
|
|
|
737
719
|
groups.find((group) => group.key === groupKey)?.items.find((item) => item.key === itemKey)?.onSelect();
|
|
738
720
|
onPicked?.(groupKey, itemKey);
|
|
739
721
|
};
|
|
740
|
-
return /* @__PURE__ */ (0,
|
|
722
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: className2, onFocusCapture: onFocus, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
741
723
|
import_ui3.SearchCombobox,
|
|
742
724
|
{
|
|
743
725
|
ariaLabel: label,
|
|
@@ -769,7 +751,7 @@ var searchStatus = (state, count, noun) => state.isError ? SEARCH_FAILED_STATUS
|
|
|
769
751
|
|
|
770
752
|
// src/genre-tree/search/useArtistSearchGroup.tsx
|
|
771
753
|
var import_genre_tree6 = require("@behindthemusictree/app-kit/genre-tree");
|
|
772
|
-
var
|
|
754
|
+
var import_jsx_runtime11 = require("react/jsx-runtime");
|
|
773
755
|
function useArtistSearchGroup(getBaseUrl, text, onSelect, enabled = true) {
|
|
774
756
|
const search = (0, import_genre_tree6.useArtistSearch)(getBaseUrl, enabled ? text : "");
|
|
775
757
|
if (!enabled) return void 0;
|
|
@@ -778,15 +760,15 @@ function useArtistSearchGroup(getBaseUrl, text, onSelect, enabled = true) {
|
|
|
778
760
|
label: "Artists",
|
|
779
761
|
items: search.artists.map((artist) => ({
|
|
780
762
|
key: artist.uuid,
|
|
781
|
-
content: /* @__PURE__ */ (0,
|
|
782
|
-
/* @__PURE__ */ (0,
|
|
763
|
+
content: /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_jsx_runtime11.Fragment, { children: [
|
|
764
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("span", { className: "block truncate font-medium", children: [
|
|
783
765
|
artist.name,
|
|
784
|
-
artist.disambiguation && /* @__PURE__ */ (0,
|
|
766
|
+
artist.disambiguation && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("span", { className: "font-normal text-[var(--color-neutral-500)]", children: [
|
|
785
767
|
" \xB7 ",
|
|
786
768
|
artist.disambiguation
|
|
787
769
|
] })
|
|
788
770
|
] }),
|
|
789
|
-
artist.matchedAlias && /* @__PURE__ */ (0,
|
|
771
|
+
artist.matchedAlias && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("span", { className: "block truncate text-caption text-[var(--color-neutral-500)]", children: [
|
|
790
772
|
"also known as ",
|
|
791
773
|
artist.matchedAlias
|
|
792
774
|
] })
|
|
@@ -800,7 +782,7 @@ function useArtistSearchGroup(getBaseUrl, text, onSelect, enabled = true) {
|
|
|
800
782
|
|
|
801
783
|
// src/genre-tree/search/useSongSearchGroup.tsx
|
|
802
784
|
var import_genre_tree7 = require("@behindthemusictree/app-kit/genre-tree");
|
|
803
|
-
var
|
|
785
|
+
var import_jsx_runtime12 = require("react/jsx-runtime");
|
|
804
786
|
function useSongSearchGroup(getBaseUrl, text, onSelect, enabled = true) {
|
|
805
787
|
const search = (0, import_genre_tree7.useSongSearch)(getBaseUrl, enabled ? text : "");
|
|
806
788
|
if (!enabled) return void 0;
|
|
@@ -809,9 +791,9 @@ function useSongSearchGroup(getBaseUrl, text, onSelect, enabled = true) {
|
|
|
809
791
|
label: "Songs",
|
|
810
792
|
items: search.songs.map((song) => ({
|
|
811
793
|
key: song.uuid,
|
|
812
|
-
content: /* @__PURE__ */ (0,
|
|
813
|
-
/* @__PURE__ */ (0,
|
|
814
|
-
/* @__PURE__ */ (0,
|
|
794
|
+
content: /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("span", { className: (0, import_genre_tree7.isSongSearchResultPlayable)(song) ? void 0 : "opacity-60", children: [
|
|
795
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "block truncate font-medium", children: song.title }),
|
|
796
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "block truncate text-caption text-[var(--color-neutral-500)]", children: [song.artists.map((artist) => artist.name).join(", "), song.genre?.name ?? "No genre"].filter(Boolean).join(" \xB7 ") })
|
|
815
797
|
] }),
|
|
816
798
|
onSelect: () => onSelect(song)
|
|
817
799
|
})),
|
|
@@ -822,7 +804,7 @@ function useSongSearchGroup(getBaseUrl, text, onSelect, enabled = true) {
|
|
|
822
804
|
|
|
823
805
|
// src/genre-tree/search/useGenreRemoteSearchGroup.tsx
|
|
824
806
|
var import_genre_tree8 = require("@behindthemusictree/app-kit/genre-tree");
|
|
825
|
-
var
|
|
807
|
+
var import_jsx_runtime13 = require("react/jsx-runtime");
|
|
826
808
|
function useGenreRemoteSearchGroup(getBaseUrl, text, onSelect, { key = "genres", label = "Genres", filter, describe, ...options } = {}) {
|
|
827
809
|
const search = (0, import_genre_tree8.useGenreRemoteSearch)(getBaseUrl, text, options);
|
|
828
810
|
const genres = filter ? search.genres.filter(filter) : search.genres;
|
|
@@ -831,12 +813,12 @@ function useGenreRemoteSearchGroup(getBaseUrl, text, onSelect, { key = "genres",
|
|
|
831
813
|
label,
|
|
832
814
|
items: genres.map((genre) => ({
|
|
833
815
|
key: genre.uuid,
|
|
834
|
-
content: /* @__PURE__ */ (0,
|
|
835
|
-
/* @__PURE__ */ (0,
|
|
816
|
+
content: /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_jsx_runtime13.Fragment, { children: [
|
|
817
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("span", { className: "block truncate font-medium", children: [
|
|
836
818
|
genre.name,
|
|
837
|
-
genre.isUmbrella && /* @__PURE__ */ (0,
|
|
819
|
+
genre.isUmbrella && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "ml-2 text-caption font-normal italic text-[var(--color-text-muted)]", children: "umbrella" })
|
|
838
820
|
] }),
|
|
839
|
-
/* @__PURE__ */ (0,
|
|
821
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "block truncate text-caption text-[var(--color-neutral-500)]", children: describe?.(genre) ?? `${genre.treeName} \xB7 ${genre.root.name}` })
|
|
840
822
|
] }),
|
|
841
823
|
onSelect: () => onSelect(genre)
|
|
842
824
|
})),
|
|
@@ -846,7 +828,7 @@ function useGenreRemoteSearchGroup(getBaseUrl, text, onSelect, { key = "genres",
|
|
|
846
828
|
}
|
|
847
829
|
|
|
848
830
|
// src/genre-tree/GenreSearch.tsx
|
|
849
|
-
var
|
|
831
|
+
var import_jsx_runtime14 = require("react/jsx-runtime");
|
|
850
832
|
function GenreSearch({
|
|
851
833
|
genrePlaylists,
|
|
852
834
|
onSelect,
|
|
@@ -875,9 +857,9 @@ function GenreSearch({
|
|
|
875
857
|
label: hasExtras ? "Genres" : void 0,
|
|
876
858
|
items: results.map((genrePlaylist) => ({
|
|
877
859
|
key: genrePlaylist.uuid,
|
|
878
|
-
content: /* @__PURE__ */ (0,
|
|
860
|
+
content: /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_jsx_runtime14.Fragment, { children: [
|
|
879
861
|
genrePlaylist.name,
|
|
880
|
-
genrePlaylist.isUmbrella && /* @__PURE__ */ (0,
|
|
862
|
+
genrePlaylist.isUmbrella && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "ml-2 text-caption italic text-[var(--color-text-muted)]", children: "umbrella" })
|
|
881
863
|
] }),
|
|
882
864
|
onSelect: () => select(genrePlaylist)
|
|
883
865
|
}))
|
|
@@ -886,7 +868,7 @@ function GenreSearch({
|
|
|
886
868
|
(group) => active ? group : { ...group, items: [], status: "", loading: false }
|
|
887
869
|
)
|
|
888
870
|
];
|
|
889
|
-
return /* @__PURE__ */ (0,
|
|
871
|
+
return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: "genre-search w-[calc(var(--layout-detail-panel-w,25.5rem)-2*var(--layout-panel-inset,1rem))] shrink-0 max-md:w-full", children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
890
872
|
SearchBox,
|
|
891
873
|
{
|
|
892
874
|
label,
|
|
@@ -906,14 +888,14 @@ function GenreSearch({
|
|
|
906
888
|
clear();
|
|
907
889
|
onQueryChange?.("");
|
|
908
890
|
} : void 0,
|
|
909
|
-
leading: onPrevious && /* @__PURE__ */ (0,
|
|
891
|
+
leading: onPrevious && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("button", { type: "button", "aria-label": "Previous", title: "Previous", className: import_ui4.SEARCH_LEADING_BUTTON_CLASS, onClick: onPrevious, children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_lucide_react3.ArrowLeft, { "aria-hidden": "true", className: "h-4 w-4" }) }),
|
|
910
892
|
onFocus
|
|
911
893
|
}
|
|
912
894
|
) });
|
|
913
895
|
}
|
|
914
896
|
|
|
915
897
|
// src/genre-tree/GenreTreeSearch.tsx
|
|
916
|
-
var
|
|
898
|
+
var import_jsx_runtime15 = require("react/jsx-runtime");
|
|
917
899
|
function GenreTreeSearch({
|
|
918
900
|
artistBaseUrl,
|
|
919
901
|
songBaseUrl,
|
|
@@ -933,7 +915,7 @@ function GenreTreeSearch({
|
|
|
933
915
|
const deferredQuery = (0, import_react8.useDeferredValue)(query);
|
|
934
916
|
const artistGroup = useArtistSearchGroup(artistBaseUrl, deferredQuery, onArtistSelect, artistSearch);
|
|
935
917
|
const songGroup = useSongSearchGroup(songBaseUrl, deferredQuery, onSongSelect, songSearch);
|
|
936
|
-
const render = (hostGroups) => /* @__PURE__ */ (0,
|
|
918
|
+
const render = (hostGroups) => /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
937
919
|
GenreSearch,
|
|
938
920
|
{
|
|
939
921
|
...props,
|
|
@@ -948,27 +930,27 @@ function GenreTreeSearch({
|
|
|
948
930
|
extraGroups: [...extraGroups, ...hostGroups, artistGroup, songGroup].filter((group) => group !== void 0)
|
|
949
931
|
}
|
|
950
932
|
);
|
|
951
|
-
return SearchGroups ? /* @__PURE__ */ (0,
|
|
933
|
+
return SearchGroups ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(SearchGroups, { query: deferredQuery, focused, onSelectGenre, children: render }) : render([]);
|
|
952
934
|
}
|
|
953
935
|
|
|
954
936
|
// src/genre-tree/GenreDetailPanel.tsx
|
|
955
|
-
var
|
|
937
|
+
var import_react15 = require("react");
|
|
956
938
|
var import_genre_tree_view4 = require("@behindthemusictree/genre-tree-view");
|
|
957
|
-
var
|
|
958
|
-
var
|
|
959
|
-
var
|
|
939
|
+
var import_ui10 = require("@behindthemusictree/ui");
|
|
940
|
+
var import_lucide_react9 = require("lucide-react");
|
|
941
|
+
var import_genre_tree20 = require("@behindthemusictree/app-kit/genre-tree");
|
|
960
942
|
|
|
961
943
|
// src/genre-tree/GenreInfoPanelBody.tsx
|
|
962
|
-
var
|
|
963
|
-
var import_track_noun3 = require("@behindthemusictree/app-kit/track-noun");
|
|
964
|
-
var import_player6 = require("@behindthemusictree/app-kit/player");
|
|
944
|
+
var import_genre_tree19 = require("@behindthemusictree/app-kit/genre-tree");
|
|
965
945
|
|
|
966
946
|
// src/genre-tree/GenreActionBand.tsx
|
|
967
947
|
var import_lucide_react7 = require("lucide-react");
|
|
948
|
+
var import_ui6 = require("@behindthemusictree/ui");
|
|
968
949
|
|
|
969
950
|
// src/genre-tree/ShareActionButton.tsx
|
|
970
951
|
var import_lucide_react6 = require("lucide-react");
|
|
971
|
-
var
|
|
952
|
+
var import_ui5 = require("@behindthemusictree/ui");
|
|
953
|
+
var import_popup2 = require("@behindthemusictree/app-kit/popup");
|
|
972
954
|
|
|
973
955
|
// src/genre-tree/SharePopup.tsx
|
|
974
956
|
var import_react10 = require("react");
|
|
@@ -979,7 +961,7 @@ var import_si = require("react-icons/si");
|
|
|
979
961
|
// src/popup/Toast.tsx
|
|
980
962
|
var import_react9 = require("react");
|
|
981
963
|
var import_react_dom2 = require("react-dom");
|
|
982
|
-
var
|
|
964
|
+
var import_jsx_runtime16 = require("react/jsx-runtime");
|
|
983
965
|
function Toast({ message, onClose, durationMs = 2200 }) {
|
|
984
966
|
const [mounted, setMounted] = (0, import_react9.useState)(false);
|
|
985
967
|
(0, import_react9.useEffect)(() => {
|
|
@@ -989,7 +971,7 @@ function Toast({ message, onClose, durationMs = 2200 }) {
|
|
|
989
971
|
}, [durationMs, onClose]);
|
|
990
972
|
if (!mounted) return null;
|
|
991
973
|
return (0, import_react_dom2.createPortal)(
|
|
992
|
-
/* @__PURE__ */ (0,
|
|
974
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { className: "pointer-events-none fixed inset-x-0 bottom-8 z-[60] flex justify-center px-4", children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
993
975
|
"div",
|
|
994
976
|
{
|
|
995
977
|
role: "status",
|
|
@@ -1004,12 +986,12 @@ function Toast({ message, onClose, durationMs = 2200 }) {
|
|
|
1004
986
|
}
|
|
1005
987
|
|
|
1006
988
|
// src/genre-tree/ShareDestinationButton.tsx
|
|
1007
|
-
var
|
|
989
|
+
var import_jsx_runtime17 = require("react/jsx-runtime");
|
|
1008
990
|
var className = "group flex min-w-0 flex-1 flex-col items-center justify-center gap-1.5 rounded-xl px-2 py-2 text-caption text-[var(--color-text)] transition-colors hover:bg-[var(--color-surface-muted)] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-focus-ring)] disabled:cursor-not-allowed disabled:opacity-50";
|
|
1009
991
|
function Contents({ icon, label }) {
|
|
1010
|
-
return /* @__PURE__ */ (0,
|
|
1011
|
-
/* @__PURE__ */ (0,
|
|
1012
|
-
/* @__PURE__ */ (0,
|
|
992
|
+
return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(import_jsx_runtime17.Fragment, { children: [
|
|
993
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "flex h-12 w-12 items-center justify-center rounded-full bg-[var(--color-surface-muted)] transition-colors group-hover:bg-[var(--color-border)]", children: icon }),
|
|
994
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "max-w-full truncate", children: label })
|
|
1013
995
|
] });
|
|
1014
996
|
}
|
|
1015
997
|
function ShareDestinationButton({
|
|
@@ -1021,29 +1003,29 @@ function ShareDestinationButton({
|
|
|
1021
1003
|
ariaLabel
|
|
1022
1004
|
}) {
|
|
1023
1005
|
if (href) {
|
|
1024
|
-
return /* @__PURE__ */ (0,
|
|
1006
|
+
return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("a", { href, target: "_blank", rel: "noopener noreferrer", "aria-label": ariaLabel, className, children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Contents, { icon, label }) });
|
|
1025
1007
|
}
|
|
1026
|
-
return /* @__PURE__ */ (0,
|
|
1008
|
+
return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("button", { type: "button", onClick, disabled, "aria-label": ariaLabel, className, children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Contents, { icon, label }) });
|
|
1027
1009
|
}
|
|
1028
1010
|
|
|
1029
1011
|
// src/genre-tree/SharePreviewCard.tsx
|
|
1030
1012
|
var import_lucide_react4 = require("lucide-react");
|
|
1031
|
-
var
|
|
1013
|
+
var import_jsx_runtime18 = require("react/jsx-runtime");
|
|
1032
1014
|
function SharePreviewCard({ target, url }) {
|
|
1033
1015
|
const Icon = { genre: import_lucide_react4.Music2, artist: import_lucide_react4.UserRound, song: import_lucide_react4.Music }[target.kind];
|
|
1034
1016
|
const typeLabel = { genre: "Genre", artist: "Artist", song: "Song" }[target.kind];
|
|
1035
|
-
return /* @__PURE__ */ (0,
|
|
1036
|
-
/* @__PURE__ */ (0,
|
|
1037
|
-
/* @__PURE__ */ (0,
|
|
1038
|
-
/* @__PURE__ */ (0,
|
|
1039
|
-
/* @__PURE__ */ (0,
|
|
1040
|
-
/* @__PURE__ */ (0,
|
|
1017
|
+
return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: "rounded-3xl bg-[var(--color-surface-muted)] p-4", children: /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "flex min-h-32 overflow-hidden rounded-2xl bg-[var(--color-surface)] shadow-lg", children: [
|
|
1018
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: "flex w-28 shrink-0 items-center justify-center bg-[var(--color-primary)]/15 text-[var(--color-primary)]", children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Icon, { "aria-hidden": "true", className: "h-10 w-10" }) }),
|
|
1019
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "flex min-w-0 flex-1 flex-col justify-center gap-1 p-4", children: [
|
|
1020
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "text-caption font-medium uppercase tracking-wide text-[var(--color-text-muted)]", children: typeLabel }),
|
|
1021
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "truncate text-base font-semibold text-[var(--color-text)]", title: target.name, children: target.name }),
|
|
1022
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "truncate text-body text-[var(--color-primary)]", title: url, children: url })
|
|
1041
1023
|
] })
|
|
1042
1024
|
] }) });
|
|
1043
1025
|
}
|
|
1044
1026
|
|
|
1045
1027
|
// src/genre-tree/SharePopup.tsx
|
|
1046
|
-
var
|
|
1028
|
+
var import_jsx_runtime19 = require("react/jsx-runtime");
|
|
1047
1029
|
function resolveAbsoluteUrl(url) {
|
|
1048
1030
|
try {
|
|
1049
1031
|
const parsed = new URL(url, window.location.href);
|
|
@@ -1118,8 +1100,8 @@ function SharePopup({ target, url, onClose }) {
|
|
|
1118
1100
|
setShareError("Could not open the share options.");
|
|
1119
1101
|
}
|
|
1120
1102
|
};
|
|
1121
|
-
return /* @__PURE__ */ (0,
|
|
1122
|
-
/* @__PURE__ */ (0,
|
|
1103
|
+
return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(import_jsx_runtime19.Fragment, { children: [
|
|
1104
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
1123
1105
|
BasePopup_default,
|
|
1124
1106
|
{
|
|
1125
1107
|
title: "Share",
|
|
@@ -1134,88 +1116,83 @@ function SharePopup({ target, url, onClose }) {
|
|
|
1134
1116
|
titleTextClassName: "!text-xl !font-semibold !text-[var(--color-text)]",
|
|
1135
1117
|
closeButtonClassName: "!h-10 !w-10 !rounded-none !border-0 !bg-transparent !p-0 !text-[var(--color-text)] hover:!bg-transparent hover:!text-[var(--color-text)]",
|
|
1136
1118
|
contentClassName: "!rounded-none !bg-transparent !px-6 !pb-6 !pt-2",
|
|
1137
|
-
children: /* @__PURE__ */ (0,
|
|
1138
|
-
/* @__PURE__ */ (0,
|
|
1139
|
-
/* @__PURE__ */ (0,
|
|
1140
|
-
/* @__PURE__ */ (0,
|
|
1119
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "flex flex-col gap-4", children: [
|
|
1120
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(SharePreviewCard, { target, url: absoluteUrl || url }),
|
|
1121
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "grid grid-cols-3 gap-1 rounded-3xl bg-[var(--color-surface)] p-3 sm:grid-cols-4", children: [
|
|
1122
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
1141
1123
|
ShareDestinationButton,
|
|
1142
1124
|
{
|
|
1143
1125
|
label: "Copy Link",
|
|
1144
|
-
icon: /* @__PURE__ */ (0,
|
|
1126
|
+
icon: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_lucide_react5.Link2, { "aria-hidden": "true", className: "h-6 w-6" }),
|
|
1145
1127
|
onClick: () => void handleCopy(),
|
|
1146
1128
|
ariaLabel: "Copy link",
|
|
1147
1129
|
disabled: !absoluteUrl
|
|
1148
1130
|
}
|
|
1149
1131
|
),
|
|
1150
|
-
/* @__PURE__ */ (0,
|
|
1132
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
1151
1133
|
ShareDestinationButton,
|
|
1152
1134
|
{
|
|
1153
1135
|
label: "WhatsApp",
|
|
1154
|
-
icon: /* @__PURE__ */ (0,
|
|
1136
|
+
icon: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_fa.FaWhatsapp, { "aria-hidden": "true", className: "h-9 w-9 text-[#25D366]" }),
|
|
1155
1137
|
href: destinationUrls?.whatsapp,
|
|
1156
1138
|
ariaLabel: `Share ${target.name} via WhatsApp`,
|
|
1157
1139
|
disabled: !absoluteUrl
|
|
1158
1140
|
}
|
|
1159
1141
|
),
|
|
1160
|
-
/* @__PURE__ */ (0,
|
|
1142
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
1161
1143
|
ShareDestinationButton,
|
|
1162
1144
|
{
|
|
1163
1145
|
label: "Gmail",
|
|
1164
|
-
icon: /* @__PURE__ */ (0,
|
|
1146
|
+
icon: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_si.SiGmail, { "aria-hidden": "true", className: "h-8 w-8 text-[#EA4335]" }),
|
|
1165
1147
|
href: destinationUrls?.gmail,
|
|
1166
1148
|
ariaLabel: `Email ${target.name} with Gmail`,
|
|
1167
1149
|
disabled: !absoluteUrl
|
|
1168
1150
|
}
|
|
1169
1151
|
),
|
|
1170
|
-
canUseNativeShare && /* @__PURE__ */ (0,
|
|
1152
|
+
canUseNativeShare && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
1171
1153
|
ShareDestinationButton,
|
|
1172
1154
|
{
|
|
1173
1155
|
label: "More",
|
|
1174
|
-
icon: /* @__PURE__ */ (0,
|
|
1156
|
+
icon: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_lucide_react5.Share2, { "aria-hidden": "true", className: "h-6 w-6" }),
|
|
1175
1157
|
onClick: () => void handleNativeShare(),
|
|
1176
1158
|
ariaLabel: "More sharing options",
|
|
1177
1159
|
disabled: !absoluteUrl
|
|
1178
1160
|
}
|
|
1179
1161
|
)
|
|
1180
1162
|
] }),
|
|
1181
|
-
copyStatus === "failed" && /* @__PURE__ */ (0,
|
|
1182
|
-
shareError && /* @__PURE__ */ (0,
|
|
1163
|
+
copyStatus === "failed" && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("p", { role: "alert", className: "text-center text-body text-[var(--color-red-500)]", children: "Could not copy the link." }),
|
|
1164
|
+
shareError && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("p", { role: "alert", className: "text-center text-body text-[var(--color-red-500)]", children: shareError })
|
|
1183
1165
|
] })
|
|
1184
1166
|
}
|
|
1185
1167
|
),
|
|
1186
|
-
toastId > 0 && /* @__PURE__ */ (0,
|
|
1168
|
+
toastId > 0 && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(Toast, { message: "Link copied", onClose: dismissToast }, toastId)
|
|
1187
1169
|
] });
|
|
1188
1170
|
}
|
|
1189
1171
|
|
|
1190
1172
|
// src/genre-tree/ShareActionButton.tsx
|
|
1191
|
-
var
|
|
1173
|
+
var import_jsx_runtime20 = require("react/jsx-runtime");
|
|
1192
1174
|
function ShareActionButton({ target, url }) {
|
|
1193
|
-
const { showPopup, hidePopup } = (0,
|
|
1175
|
+
const { showPopup, hidePopup } = (0, import_popup2.usePopup)();
|
|
1194
1176
|
const openSharePopup = () => {
|
|
1195
|
-
showPopup(/* @__PURE__ */ (0,
|
|
1177
|
+
showPopup(/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(SharePopup, { target, url, onClose: hidePopup }));
|
|
1196
1178
|
};
|
|
1197
|
-
return /* @__PURE__ */ (0,
|
|
1198
|
-
|
|
1179
|
+
return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
1180
|
+
import_ui5.ActionButton,
|
|
1199
1181
|
{
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
className: "group flex flex-col items-center gap-1 w-16 text-caption text-center text-[var(--color-text)] focus-visible:outline-none",
|
|
1182
|
+
icon: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_lucide_react6.Share2, { "aria-hidden": "true", className: "w-5 h-5" }),
|
|
1183
|
+
label: "Share",
|
|
1203
1184
|
"aria-label": `Share ${target.name}`,
|
|
1204
1185
|
title: `Share ${target.name}`,
|
|
1205
|
-
|
|
1206
|
-
/* @__PURE__ */ (0, import_jsx_runtime19.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: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_lucide_react6.Share2, { "aria-hidden": "true", className: "w-5 h-5" }) }),
|
|
1207
|
-
"Share"
|
|
1208
|
-
]
|
|
1186
|
+
onClick: openSharePopup
|
|
1209
1187
|
}
|
|
1210
1188
|
);
|
|
1211
1189
|
}
|
|
1212
1190
|
|
|
1213
1191
|
// src/genre-tree/GenreActionBand.tsx
|
|
1214
|
-
var
|
|
1192
|
+
var import_jsx_runtime21 = require("react/jsx-runtime");
|
|
1215
1193
|
function GenreActionBand({
|
|
1216
1194
|
node,
|
|
1217
|
-
|
|
1218
|
-
isPlaying = false,
|
|
1195
|
+
playActions,
|
|
1219
1196
|
onZoomIn,
|
|
1220
1197
|
onAddChild,
|
|
1221
1198
|
onRename,
|
|
@@ -1229,36 +1206,28 @@ function GenreActionBand({
|
|
|
1229
1206
|
}) {
|
|
1230
1207
|
const items = [];
|
|
1231
1208
|
const adminItems = [];
|
|
1232
|
-
if (onPlayPause) {
|
|
1233
|
-
items.push({
|
|
1234
|
-
key: "play-pause",
|
|
1235
|
-
label: isPlaying ? "Pause" : "Play",
|
|
1236
|
-
icon: isPlaying ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_lucide_react7.Pause, { "aria-hidden": "true", className: "w-5 h-5" }) : /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_lucide_react7.Play, { "aria-hidden": "true", className: "w-5 h-5" }),
|
|
1237
|
-
onClick: onPlayPause
|
|
1238
|
-
});
|
|
1239
|
-
}
|
|
1240
1209
|
if (onZoomIn) {
|
|
1241
1210
|
items.push({
|
|
1242
1211
|
key: "zoom-in",
|
|
1243
1212
|
label: "Focus",
|
|
1244
|
-
icon: /* @__PURE__ */ (0,
|
|
1213
|
+
icon: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_lucide_react7.ZoomIn, { "aria-hidden": "true", className: "w-5 h-5" }),
|
|
1245
1214
|
onClick: onZoomIn
|
|
1246
1215
|
});
|
|
1247
1216
|
}
|
|
1248
1217
|
if (onAddChild) {
|
|
1249
|
-
adminItems.push({ key: "add-child", label: "Add", icon: /* @__PURE__ */ (0,
|
|
1218
|
+
adminItems.push({ key: "add-child", label: "Add", icon: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_lucide_react7.Plus, { "aria-hidden": "true", className: "w-5 h-5" }), onClick: onAddChild });
|
|
1250
1219
|
}
|
|
1251
1220
|
if (onRename) {
|
|
1252
|
-
adminItems.push({ key: "rename", label: "Rename", icon: /* @__PURE__ */ (0,
|
|
1221
|
+
adminItems.push({ key: "rename", label: "Rename", icon: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_lucide_react7.Pencil, { "aria-hidden": "true", className: "w-5 h-5" }), onClick: onRename });
|
|
1253
1222
|
}
|
|
1254
1223
|
if (onChangeParent) {
|
|
1255
|
-
adminItems.push({ key: "change-parent", label: "Parent", icon: /* @__PURE__ */ (0,
|
|
1224
|
+
adminItems.push({ key: "change-parent", label: "Parent", icon: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_lucide_react7.MoveUpRight, { "aria-hidden": "true", className: "w-5 h-5" }), onClick: onChangeParent });
|
|
1256
1225
|
}
|
|
1257
1226
|
if (onToggleSide) {
|
|
1258
1227
|
adminItems.push({
|
|
1259
1228
|
key: "toggle-side",
|
|
1260
1229
|
label: side === "pop" ? "Make core" : "Make pop",
|
|
1261
|
-
icon: /* @__PURE__ */ (0,
|
|
1230
|
+
icon: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_lucide_react7.ArrowLeftRight, { "aria-hidden": "true", className: "w-5 h-5" }),
|
|
1262
1231
|
onClick: onToggleSide,
|
|
1263
1232
|
disabled: !!toggleSideDisabledReason,
|
|
1264
1233
|
title: toggleSideDisabledReason
|
|
@@ -1273,60 +1242,139 @@ function GenreActionBand({
|
|
|
1273
1242
|
disabled: action.enabled ? !action.enabled(node) : false
|
|
1274
1243
|
});
|
|
1275
1244
|
}
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1245
|
+
const renderItems = (list) => list.map((item) => /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_ui6.ActionButton, { icon: item.icon, label: item.label, disabled: item.disabled, title: item.title, onClick: item.onClick }, item.key));
|
|
1246
|
+
if (!playActions && items.length === 0 && adminItems.length === 0 && !(shareTarget && shareUrl)) return null;
|
|
1247
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_ui6.PanelBleed, { children: /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
|
|
1248
|
+
import_ui6.ActionBand,
|
|
1279
1249
|
{
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
title: item.title,
|
|
1283
|
-
onClick: item.onClick,
|
|
1284
|
-
className: "group flex flex-col items-center gap-1 w-16 text-caption text-center text-[var(--color-text)] focus-visible:outline-none disabled:opacity-50",
|
|
1250
|
+
className: "genre-action-band",
|
|
1251
|
+
section: { title: "Admin", label: "Admin actions", children: renderItems(adminItems) },
|
|
1285
1252
|
children: [
|
|
1286
|
-
|
|
1287
|
-
|
|
1253
|
+
playActions,
|
|
1254
|
+
renderItems(items),
|
|
1255
|
+
shareTarget && shareUrl && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ShareActionButton, { target: shareTarget, url: shareUrl })
|
|
1288
1256
|
]
|
|
1289
|
-
}
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1257
|
+
}
|
|
1258
|
+
) });
|
|
1259
|
+
}
|
|
1260
|
+
|
|
1261
|
+
// src/genre-tree/GenrePlayActions.tsx
|
|
1262
|
+
var import_lucide_react8 = require("lucide-react");
|
|
1263
|
+
var import_ui7 = require("@behindthemusictree/ui");
|
|
1264
|
+
var import_genre_tree10 = require("@behindthemusictree/app-kit/genre-tree");
|
|
1265
|
+
var import_player4 = require("@behindthemusictree/app-kit/player");
|
|
1266
|
+
|
|
1267
|
+
// src/genre-tree/RegionGlobeIcon.tsx
|
|
1268
|
+
var import_react11 = require("react");
|
|
1269
|
+
|
|
1270
|
+
// src/genre-tree/regionGlobePaths.ts
|
|
1271
|
+
var REGION_GLOBE_PATHS = {
|
|
1272
|
+
africa: "M491.879,156.348c-19.45-45.96-51.89-85.017-92.734-112.614C358.3,16.13,308.964-0.008,256.004,0 c-35.306,0-69.02,7.163-99.654,20.122c-45.961,19.45-85.017,51.89-112.614,92.734C16.13,153.701-0.008,203.036,0,255.996 c0,35.306,7.163,69.02,20.122,99.654c19.45,45.961,51.882,85.017,92.735,112.614c40.844,27.605,90.18,43.743,143.147,43.735 c35.299,0,69.012-7.163,99.648-20.121c45.96-19.45,85.017-51.882,112.614-92.735c27.604-40.844,43.742-90.18,43.734-143.147 C512,220.698,504.837,186.984,491.879,156.348z M241.412,128.135c3.914-1.382,10.421,3.07,8.843,7.272 c-2.624,6.983,6.491,10.436,9.49,14.474c2.624,3.522,7.585,14.708-3.148,12.567c-5.094-1.015-6.866,5.234-13.623,1.313 c1.672-2.382,8.382-17.825,3.312-17.583C243.202,146.327,238.367,131.188,241.412,128.135z M233.812,142.281 C231.43,142.96,235.648,141.75,233.812,142.281c8.499-2.437,8.859,11.693,4.882,14.872c-8.303,6.617-8.654-0.328-7.241-5.96 C232.086,148.71,225.009,144.804,233.812,142.281z M48.445,168.331c5.914-13.966,13.224-27.199,21.708-39.572 c3.796-0.343,6.022-2.077,11.201-6.788c4.898,5.999,9.787,11.998,14.693,17.997c1.5,1.836-3.25,4.109-0.938,6.194 c2.921,2.632,4.999,2.75,8.053-0.875c2.008,3.632,4.007,7.272,6.015,10.905c-6.03,2.484-11.014,5.296-17.52,5.171 c-10.319-0.218-15.404-1.18-23.465,5.725c3.374,5.32,7.108,1.96,11.654,0c-2.07,6.093,0.914,14.842,7.897,15.802 c-3.078,2.96-6.163,5.913-9.233,8.874c-1.413,1.359-5.233-3.586-0.921-6.616c-1.57-1.203-4.835-2.562-6.764-3.015 c-0.618,7.194-7.491,2.984-10.53,7.522c-3.312,4.937,3.132,8.022-4.078,10.085c-12.084,3.452-8.655,15.88-17.872,23.019 c-0.952,0.742-3.358,2.203-5.678,3.835C35.322,206.184,40.712,186.641,48.445,168.331z M73.246,276.415 c-0.664-0.383-1.336-0.774-2.008-1.164c-0.468-2.203,5.586-1.289,6.374-0.657C79.464,276.071,73.745,276.321,73.246,276.415z M50.687,273.158c0.961,0.328,1.804,0.171,2.539-0.477c-0.938-0.758-1.945-1.414-3.008-1.96 c-0.875-3.484,18.575,2.672,15.818,4.226c-2,1.133-19.754,1.282-18.84-0.578c0.89-1.116,2.062-1.523,3.484-1.21 C49.5,272.712,50.203,272.978,50.687,273.158z M30.846,260.792c7.421,2.101,14.67,5.077,15.826,5.842 c0.305,0.211-2.733,1.437-1.758,1.765c0.985,0.227,1.906,0.586,2.796,1.055c0.875,0.726-12.068,3.663-11.31,0.695 c0.64-0.828,1.367-1.578,2.172-2.265c-0.149,0.203-3.766-1.781-7.656-3.609C30.877,263.12,30.877,261.948,30.846,260.792z M34.893,273.915c1.336-0.274,9.084,1.78,5.686,3.507c-1.148-0.164-2.296-0.336-3.437-0.508 C34.838,276.477,34.088,275.477,34.893,273.915z M167.386,365.564c-4.898,5.21-4.71,7.397-5.366,13.959 c-0.867,8.631-1.936,25.558-11.646,26.207c-15.982,1.062-20.544,14.216-25.082,26.69c-0.718,2-1.531,3.726-2.398,5.265 c-20.926-15.364-39.134-34.228-53.678-55.764c-15.63-23.152-27.042-49.336-33.213-77.502c2.265,1.031,3.171,3.312,3.179,5.663 c0,0.023,0,0.054,0,0.086c0.141-0.187,0.258-0.382,0.43-0.562c1.555-1.952,13.935-20.379,12.92-7.843 c6.999,1.445,6.038-3.921,11.154-4.772c5.499-0.914,6.788,7.108,12.201,5.39c9.498-3.023,10.186-1.555,15.411,6.288 c5.366,8.046,18.419,4.75,25.636,9.819c5.812,4.085,6.866,8.779,7.702,15.614c0.344,2.858,11.78,3.25,14.466,3.25 c2.867,0,2.429,4.062,3.655,5.6c1,1.258,5.07,0.797,6.374,0.968c6.592,0.829,14.076,2.632,19.466,6.687 C174.776,355.253,171.729,360.932,167.386,365.564z M195.304,92.75c1.585-0.336,4.342,2.726,5.248,2.125 c3.203-2.149,2.492-2.289,7.171-2.554c1.274-0.07,20.646,1.429,15.357,6.74c-0.007,0.008-0.007,0.008-0.007,0.008 c0,0.008,0,0.008-0.008,0.008c-7.452,7.436-13.256,4.96-21.988,4.96C197.318,104.037,187.977,94.265,195.304,92.75z M415.758,398.574c-3.179,10.991-2.187,13.771-12.842,17.474c-3.343-10.388-2.257-16.716-2.257-27.448 c0-0.367,14.552-13.873,16.169-15.802C421.984,382.646,418.766,388.177,415.758,398.574z M481.068,264.502 c-2.241-2.828-4.249-6.178-6.327-8.264c-4.491-4.491-16.732-0.938-23.738-1.882c-6.179-0.828-7.726,0.218-9.905-5.586 c-1.156-3.085-5.343,0.203-8.21,0.477c-8.694,0.82-12.56-13.334-20.575-8.803c2.578,4.038,10.365,16.24,13.584,17.31 c6.514,2.172,4.96-6.835,12.74-4.522c-0.618,2.366,0.281,5.155-0.375,7.514c22.738-5.748,3.14,23.129-6.905,20.981 c-2.75-0.594-1.695,3.5-4.601,4.343c-4.452,1.304-8.905,2.601-13.365,3.898c-5.648,1.648-10.654,5.758-13.842,0.297 c-7.428-12.724-12.263-28.401-21.621-38.658c-1.616-1.773-4.421-4.444-6.452-7.373c0.078,0.234,0.148,0.484,0.234,0.718 c-1.804-1.313-4.476-1.469-6.397-2.624c-2.321,6.444,6.491,15.021,10.177,20.285c4.75,6.781,5.882,16.154,10.882,22.575 c2.148,2.765,6.022,4.139,7.974,7.076c1.657,2.484,5.156,10.655,7.82,11.725c4.077,1.64,17.302-4.468,21.808-5.64 c-2.398,5.765-7.678,25.332-13.224,27.816c-10.6,4.75-13.278,9.03-20.113,18.677c-0.539,0.75-5.554,6.256-5.617,6.007 c1.266,4.944,2.531,9.888,3.789,14.832c0.936,3.664,2.336,20.138-0.485,20.966c-13.006,3.859-13.966,7.514-14.286,20.708 c-0.133,5.429-6.46,13.091-10.506,17.739c-5.936,6.819-10.545,15.99-19.715,17.263c-8.491,1.179-16.997,2.28-25.512,3.39 c0-6.881,0.633-9.397-3.694-14.583c-5.085-6.101-5.827-7.859-6.843-15.74c-1.141-8.905-11.92-21.231-9.428-29.058 c4.906-15.381,3.523-20.887-0.562-36.728c-1.226-4.773-7.186-7.343-8.413-11.803c-0.96-3.46,1.126-11.951,1.126-15.794 c-7.382,0.616-8.663,1.046-14.389-3.632c-4.694-3.835-9.194-0.352-14.747,1.445c-4.609,1.492-11.616-0.437-16.427-0.773 c-3.867-0.274-9.585,4.093-13.1,2.96c-7.413-2.39-18.2-21.575-23.309-27.644c-4.804-5.686-1.867-19.145-2.226-26.94 c-0.484-10.373,12.74-20.262,20.184-24.98c2.047-1.297,3.109-8.397,5.898-11.1c3.953-3.835,6.499-8.123,12.045-8.42 c9.764-0.516,20.903-5.335,31.026-6.764c5.632-0.797,11.272-1.594,16.912-2.39c2.328-0.329,6.475,8.389,0.758,10.1 c3.39,6.709,14.833,4.632,15.81,7.561c1.929,5.788,9.373,4.906,15.029,5.968c-0.782-14.225,10.88-3.976,17.746-2.047 c5.202,1.452,8.679-1.695,13.842-1.703c4.288-0.008,9.326,2.07,13.537,3.008c0.007,0.054,0.023,0.094,0.038,0.148 c0.07-0.328,0.157-0.656,0.29-0.984c2.812-7.03,4.178-11.21,4.178-18.724c-4.468,0.531-18.551,4.796-22.176,2.632 c-2.164-1.289-4.25-8.014-5.436-10.248c-2.062-3.906,0.687-3.859,4.265-6.194c12.318-8.03,26.535-2.484,39.892-5.366 c-1-4.85-3.57-7.178-7.14-10.154c-5.35-4.453-4.273-5.054-3.014-12.029c-3.508,1-7.015,2-10.53,3.007 c1.296,1.531,1.336,4.132,2.632,5.639c-8.828,6.148-6.359-5.163-12.404-6.006c-5.39-0.766-6.804,8.154-9.538,11.388 c-3.906,4.64,1.672,8.303-4.562,10.6c-4.351,1.602-7.241,5.577-12.217,3.952c3.664,2.024,5.882,4.976,4.882,9.022 c-1.453-0.798-3.468-0.641-4.882-1.5c0.727,1.984,0.298,4.444,1.125,6.381c-5.984-2.695-11.928-12.521-12.974-18.802 c-0.898-5.374-14.286-12.513-18.989-16.536c-7.577,8.288,13.286,12.63,15.224,19.739c-0.141-0.531-4.022,11.662-4.319,11.842 c-5.242,3.249-4.242-7.679-5.96-9.249c-5.147-4.671-15.669-19.348-21.254-14.825c-7.671,6.218-4.616-1.062-10.818,0.875 c-5.835,1.82-3.156,7.436-6.757,8.514c-9.662,2.898-2.382,5.866-8.155,10.678c-5.717,4.765-6.616,4.75-14.029,4.601 c-14.138-0.266-16.872-3.624-15.458-17.81c1.203-11.959,14.513-7.014,24.355-6.858c3.601,0.062,2.211-9.233,0.297-11.146 c-3.32-3.312-7.819-2.375-10.279-6.89c14.505-2.593,18.176-10.045,29.705-18.051c1.852-1.282,12.811-5.327,12.725-6.499 c-0.211-3.257-2.789-15.615,4.952-14.185c7.217,1.343-3.304,12.146,2.554,12.466c3.296,0.188,12.014,4.523,12.802,3.664 c4.648-5.07,10.162-3.164,16.92-2.992c2.335,0.062,5.46-11.146,6.452-13.513c8.279,8.366,6.725-2.53,5.632-7.522 c3.101,0.117,14.599,1.96,16.552-2.25c3.586-7.71-8.764-4.898-12.224-3.945c-4.085,1.11-11.778,2.039-13.349-4.327 c-0.508-2.085,4.304-12.279,6.272-13.318c5.617-2.976,7.617-5.991,1.946-10.623c-6.327-5.187-6.358,8.061-7.084,8.897 c-6.281,7.217-22.809,10.974-9.023,22.567c-4.382,0.984-6.014,3.179-6.147,7.084c-0.266,7.225,0.266,6.733-6.827,8.046 c-6.726,1.241-7.812-10.577-9.975-16.264c-4.929,5.21-15.006,14.271-19.169,2.258c-3.827-11.084,5.757-14.342,13.224-17.739 c6.351-2.882,12.646-15.802,16.95-21.387c2.531-3.273,0.43-5.117,4.234-8.257c3.788-3.116,6.96-3.483,11.826-4.577 c4.093-0.922,7.178-5.562,11.177-5.648c5.75-0.108,11.522,0.321,17.263,0.594c7.007,0.344,1.75,3.414,5.242,4.554 c5.218,1.71,10.428,3.421,15.638,5.124c5.718,1.875,17.763,6.96,13.521,12.795c-4.562,6.264-16.325-1.461-20.715-3.812 c-3.57,6.374,3.179,5.132,6.397,8.647c0.828,0.906-1.578,4.734-0.757,5.64c1.32,1.446,4.35,2.515,6.03,3.492 c5.108,2.953,3.077-8.1,1.125-6.124c2.726-2.765,4.663-2.765,9.014,0c0.641-5.827,7.257-7.913,12.037-5.265 c0.078-2.883,0.149-5.781,0.227-8.671c16.176,13.545,30.432,29.308,42.274,46.836c24.293,35.963,38.454,79.213,38.462,125.916 C481.248,258.847,481.177,261.683,481.068,264.502z M50.687,273.158c0,0,0,0-0.008,0C51.257,273.376,51.023,273.282,50.687,273.158z M432.998,199.451c0.226,1.078-5.476-4.804-5.928-5.444c-1.914-2.696-3.812-5.39-5.726-8.093 c5.89-0.257,7.695-4.014,7.523-9.389c-11.131,0-26.02,5.89-15.435,18.153c1.469,1.696,5.991,5.242,6.406,7.405 c0.305,1.578-4.391,2.858-3.906,5.32c1.586,7.904,3.742,7.17,11.428,9.725c1.952-0.141,4.163-1.555,6.022-2.25 c-1.304-2.819-4.178-6.725-4.514-9.787C428.764,204.247,433.756,203.106,432.998,199.451z",
|
|
1273
|
+
americas: "M491.875,156.347c-19.446-45.958-51.889-85.019-92.736-112.613C358.3,16.13,308.962-0.008,255.996,0 c-35.305,0-69.016,7.168-99.65,20.124C110.381,39.571,71.321,72.006,43.725,112.86C16.122,153.692-0.016,203.03,0,255.996 c-0.008,35.313,7.16,69.016,20.125,99.658c19.438,45.958,51.881,85.018,92.728,112.613C153.692,495.87,203.03,512.008,255.996,512 c35.305,0,69.016-7.168,99.649-20.125c45.966-19.446,85.018-51.882,112.621-92.736C495.87,358.308,512,308.97,512,255.996 C512,220.691,504.832,186.988,491.875,156.347z M374.27,351.228c-8.571,14.798-1.69,35.384-12.262,48.78 c-10.947,13.514-16.513,10.221-24.295,28.328c-0.853,2.36-14.742,31.917-18.211,23.122c3.054,7.854-0.383,15.66-10.357,16.274 c-7.95,0.47-2.233,5.071-4.704,8.252c-9.863,2.17-19.965,3.708-30.274,4.521c-6.928-25.299-10.74-54.6-10.565-62.972 c0.638-32.484-6.609-19.327-23.609-43.342c-11.616-16.513-21.91-34.803-21.304-55.733c-0.088,3.74,23.329-53.086,6.426-42.25 c-20.532,13.172-24.311-14.567-44.092-17.158c-10.102-1.339-7.16-11.768-18.49-9.982c-10.174,1.594-21.735-11.904-29.277-16.991 c-4.951-3.572-13.578-51.619-20.842-50.933c-10.373,0.383,7.598,33.049,3.835,34.142c-7.742,1.451-21.313-46.093-21.057-50.008 c0.39-12.63-0.83-19.75,7.527-30.251c3.245-4.226,21.718-20.475,19.773-26.304c-3.308-10.166-1.602-22.022-6.905-28.831 c4.681-3.739,9.504-7.311,14.487-10.677c10.31-6.968,21.249-13.076,32.675-18.282c1.332-0.04,2.663-0.096,3.97-0.239 c10.206-0.997,20.627-4.959,30.992-3.388c13.666,2.008,28.488,7.893,42.88,6.769c13.251-0.933,50.638-12.949,62-3.254 c5.015,4.306-56.443,21.72-58.396,30.043c-0.997,5.422,16.002,4.944,17.469,5.079c17.087,1.403-4.241,15.452,6.252,18.481 c16.114,3.891,27.738-56.338,41.205-24.844c5.502,13.06,24.406-8.547,26.543,7.566c2.153,16.951,18.426,22.684-11.506,24.885 c-28.073,2.28-4.864,14.726-23.186,22.811c-17.525,7.718-33.552,11.107-46.46,26.966c-14.559,17.987-15.954,17.389-21.671,40.408 c-3.15,12.565-19.678-8.842-13.371-16.696c-2.185,2.694-21.544-6.1-23.466-1.587c-3.755,8.706-13.961,4.035-21.982,9.369 c-10.142,6.706-20.077,28.44-9.927,38.63c8.125,8.101,36.095-17.884,37.618-9.01c1.196,6.786-9.919,11.601-8.706,18.387 c1.746,9.823,18.872-2.815,18.864,4.816c0.008,4.895-0.805,25.355,14.272,20.236c8.125-2.774,8.93,3.046,14.009,1.826 c6.96-1.683,10.07-10.963,18.275-9.752c9.766,1.427,20.714,6.371,30.074,9.13c15.213,4.504,14.535,17.214,31.463,19.821 c16.911,2.663,10.15,18.323,8.068,27.197C329.007,322.58,399.107,310.772,374.27,351.228z M440.711,127.133 c0.686,0.981,1.403,1.954,2.066,2.95c4.01,5.916,7.71,12.064,11.138,18.378c-1.443,0.494-2.806,0.893-3.851,1.012 c-4.417,0.558-11.585-3.301-12.685-4.959C436.493,143.191,439.468,131.726,440.711,127.133z M481.223,257.232 c-1.252-0.702-2.615-1.077-4.138-0.766c-5.518,1.1-26.471,6.618-34.189,5.509c-7.726-1.108-31.981-24.262-31.981-29.779 c0-5.51,1.101-26.471,3.301-29.78c2.209-3.309,14.336-18.426,18.753-25.036c4.409-6.625,11.027-15.436,16.544-16.544 c1.715-0.343,5.375-1.012,9.824-1.834c14.032,29.374,21.902,62.231,21.91,96.994C481.247,256.411,481.223,256.809,481.223,257.232z",
|
|
1274
|
+
asia: "M491.878,156.348C472.437,110.39,439.989,71.33,399.14,43.731C358.307,16.131,308.964-0.008,256,0 c-35.304,0-69.011,7.167-99.652,20.122C110.39,39.564,71.33,72.011,43.731,112.86C16.131,153.693-0.008,203.036,0,256 c0,35.304,7.167,69.02,20.122,99.653c19.442,45.957,51.889,85.016,92.738,112.616c40.832,27.6,90.176,43.74,143.14,43.731 c35.305,0,69.02-7.166,99.653-20.122c45.957-19.442,85.017-51.889,112.617-92.738c27.6-40.832,43.74-90.176,43.731-143.14 C512,220.697,504.842,186.98,491.878,156.348z M427.814,110.348c0.774,0.915,1.53,1.856,2.294,2.789 c-1.496-0.454-2.991-0.908-4.486-1.37C426.353,111.297,427.084,110.819,427.814,110.348z M382.832,101.182 C387.142,100.754,380.446,101.434,382.832,101.182c-1.798-0.126-3.159-0.858-4.066-2.177 C384.579,95.217,388.747,100.585,382.832,101.182z M290.917,81.127c1.613,4.142-9.956,0.277-11.216-0.336 c-0.739-0.739-1.294-1.58-1.663-2.52C278.021,79.203,290.388,79.749,290.917,81.127z M258.79,75.406 c2.823,0.958,14.022-1.572,14.383,1.722c0.673,6.049-3.99,0.058-4.956,0.058c-2.622,0,1.21,2.78,1.31,2.923 c-0.656-0.957-8.461-0.857-10.107-0.462C254.656,88.352,241.675,69.592,258.79,75.406z M271.711,87.026 c-3.108,1.142-8.443,0.168-11.754,0.168C253.808,85.58,276.718,85.194,271.711,87.026z M79.236,313.19 C79.06,315.812,79.346,311.544,79.236,313.19c0.042-0.663,1.126-5.755,2.084-6.049c1.513-0.453,4.613,6.999,4.487,8.041 C85.11,321.206,78.892,318.148,79.236,313.19z M136.15,339.169c-3.252-3.983-5.192-8.461-8.284-12.528 c-0.63-0.84-11.031-6.754-9.058-7.796c4.243-2.21,39.505,18.517,37.934,21.676c-0.152,0.303-7.889-6.797-9.847-5.52 c-1.302,0.848,2.689,3.932,2.689,5.419c2.016,1.033,7.149,8.646,2.932,8.872C147.862,349.545,138.872,342.512,136.15,339.169z M154.894,340.546c0.21,1.37-3.646-1.185-3.873-1.277C151.777,337.884,154.718,339.412,154.894,340.546z M151.92,353.208 c-3.898-2.487,12.569-0.554,13.459-0.487c3.252,0.243,11.418,0.076,13.552,3.974C179.569,357.862,155.574,355.544,151.92,353.208 C154.356,354.77,150.122,352.066,151.92,353.208z M188.686,317.644c4.125-4.201,8.839,3.235,9.174,2.932 c-2.596,2.369-6.486,6.94-1.252,9.671c3.932,2.058-4.672,3.537-4.672,4.268c0,2.966-4.771,10.795-7.814,12.014 c0.177-0.067-11.913-3.419-12.972-3.722c-2.638-0.764-3.445-8.082-5.058-10.426C166.093,328.036,184.51,321.895,188.686,317.644z M167.53,281.869c1.756-1.328,3.378-1.479,4.848-0.454C173.546,287.801,165.514,282.785,167.53,281.869z M195.718,306.864 c0.009-0.017,0.017-0.025,0.034-0.034c0.067-0.059,0.101-0.084,0.092-0.076c1.05-0.857,3.806-3.302,4.898-3.546 C203.716,302.529,193.676,308.502,195.718,306.864z M201.658,294.278c-0.563-3.353-0.151-3.974,0.093-6.68 c0.428-4.713,5.915-6.772,7.007-1.092c0.193,0.975-5.721,9.88-1.218,9.317c3.612-0.454,6.301-0.622,5.134,3.932 c-1.076-0.714-7.814-4.075-8.637-3.898c-0.798,0.168-3.36,8.746-6.049,7.939C199.162,304.151,201.809,295.95,201.658,294.278z M200.734,269.073c0.084-1.328,2.042-5.125,4.176-4.688c2.461,0.513-0.731,10.141-2.487,9.032c-1.26-1.193-1.823-2.639-1.689-4.335 C200.7,269.678,200.608,271.199,200.734,269.073z M213.479,300.403c0.016-0.008,0.016-0.016,0.034-0.016 c4.797-2.42,3.452,4.218,3.965,4.452C216.831,304.546,213.101,300.613,213.479,300.403z M218.184,308.04 C217.26,307.889,219.276,308.217,218.184,308.04c1.521,0.244,2.269,3.369,2.42,4.378c0.621,4.243,0.546,2.411-2.26,3.52 c-0.765,0.294,0.084,2.747-1.672,2.865c-0.84,0.05-5.436-0.908-3.948-2.672c3.091-3.663-5.663-0.815-5.663-1.134 c0-1.227,1.386-4.075,3.184-3.697C215.504,312.384,215.58,307.62,218.184,308.04z M223.435,335.086 c-1.311-1.748-0.118-6.075,1.159-7.512c-1.016,1.142,2.706,3.058,2.882,2.26C227.081,331.632,223.661,335.388,223.435,335.086z M230.03,343.202c-0.076-0.739-6.041-0.588-6.948-0.73C221.51,342.471,229.593,338.766,230.03,343.202z M223.704,262.839 c-3.907,0.89,0.816-2.747,1.664-2.823C226.518,259.907,223.914,262.554,223.704,262.839z M222.393,355.989 c1.529,3.941-8.503,4.672-9.906,5.008c1.076-0.261,7.284-2.588,7.898-4.26C220.494,356.426,221.612,353.964,222.393,355.989z M200.557,343.369c-2.243,1.227,0.21,5.831-2.16,6.066c-3.503,0.352-1.638-8.755-0.866-11.208 c3.798-11.998,9.352,4.495,12.469-3.47c-0.252,0.647-10.847-2.655-9.091-3.201c0.025-0.008,0.051-0.008,0.076-0.017 c2.89-0.873,12.997-3.184,15.408-2.596c0.571,0.134-6.662,10.132-10.636,9.83c4.798,0.369,2.705,7.419,0.941,9.351 c-0.63,0.689,4.411,2.646,3.722,3.117C207.993,352.914,197.574,345,200.557,343.369z M206.497,356.938 c0.597,0.303-2.731,1.025-3.159,1.109c-1.377,0.47-2.688,0.412-3.932-0.176C198.465,357.115,205.691,356.535,206.497,356.938z M199.297,358.946c-0.647,0.404-1.336,0.404-2.067,0C195.256,357.744,198.348,357.938,199.297,358.946z M205.548,300.05 c0,0,0,0-0.009,0c-0.025-0.025-0.051-0.042-0.076-0.058c0.017,0.008,0.034,0.025,0.058,0.041c-0.235-0.159-2.68-1.814-0.84-2.008 C207.278,297.757,205.582,300.076,205.548,300.05z M208.783,308.284c-2.798,0-3.016-4.05-3.134-5.621 C207.748,296.421,209.429,308.284,208.783,308.284z M209.975,358.132c0.74-0.387,8.208-2.403,7.704-1.613 c-0.471,0.748-8.838,4.604-9.679,2.924C208.228,358.527,208.883,358.09,209.975,358.132z M218.839,343.202c0.008,0,0.017,0,0.017,0 c-0.026,0-0.009,0-0.026,0c-1.142,0.051-1.622-0.328-1.403-1.143c2.445-1.126,3.344,1.303,1.429,1.143 C219.318,343.244,219.091,343.226,218.839,343.202z M209.707,304.738c-0.093-0.042-0.06-0.025-0.009-0.008 c-1.294-0.512-0.109-3.394,1.084-2.118C211.177,303.041,210.454,305.016,209.707,304.738z M212.244,305.528 c-0.084,0.68-0.605,3.453-1.84,3.453c-0.218-0.74-0.218-1.479,0-2.218C210.539,305.629,211.151,305.218,212.244,305.528z M202.355,305.184L202.355,305.184c-0.58,1.168-7.78,9.838-8.839,5.184C193.542,310.486,201.884,306.142,202.355,305.184z M194.903,356.737c-1.512,0.395-2.789,1.294-4.47,0.344C188.719,356.115,194.836,356.737,194.903,356.737z M187.451,356.325 c-0.992,0-0.446-0.656,0.268-0.739C188.442,355.502,188.35,356.325,187.451,356.325z M281.365,457.809 c-5.629,13.039-11.771-7.864-10.998-7.62C277.752,452.726,286.145,446.736,281.365,457.809z M293.849,421.691 c-1.949,5.721-3.814,11.728-7.343,16.845c-4.864,7.049-8.561,3.294-15.064,3.234c-3.723-0.034-2.849,2.866-6.916,1.278 c-2.285-0.899-5.402-1.597-7.444-2.916c2.521,1.63-4.394-9.427-3.764-5.411c-0.344-2.167-2.823-1.084-4.848-1.479 c1.093-1.386,1.042-3.537,2.151-4.915c-2.747-0.067-5.091,1.135-6.814,3.277c-7.738-9.561-14.93-10.452-27.372-7.327 c-2.882,0.723-8.604,5.361-10.208,5.361c-6.537,0-8.041-0.261-12.914,3.596c-3.344,2.646-11.703,0.84-12.678-3.596 c-0.446-2.016,3.218-4.797,3.226-6.89c0.008-1.327-3.84-2.596-4.31-3.94c-0.723-2.108,1-4.596-0.781-6.343 c-0.748-0.731-4.125-3.15-4.243-4.15c-0.151-1.319,2.874-2.731,2.874-4.386c0-2.336,0-4.663,0-6.999 c0-5.284,14.291-6.46,19.962-9.057c6.629-3.025,1.764-4.906,5.881-8.427c1.236-1.05,5.529,1.008,6.822,0 c0.739-0.571-0.218-3.36,0.781-4.478c1.412-1.562,7.796-8.108,8.284-1.874c0.286,3.697-0.067,3.402,3.99,3.402 c3.268,0-0.176-1.604,1.302-2.948c2.244-2.05,5-8.645,7.898-9.511c1.697-0.513,10.183,3.268,12.914,3.277 c-0.95,2.73-1.874,5.478-2.865,8.2c4.267,2.16,12.258,8.788,17.223,5.906c2.318-1.352,3.268-13.014,3.949-15.745 c2.881,4.453,7.83,7.755,9.519,12.09c2.579,6.604,6.864,6.83,10.729,12.233c3.604,5.016,6.906,9.864,9.906,15.199 C297.757,412.423,296.564,413.717,293.849,421.691z M237.466,240.155c1.05,1.444-3.789,8.956-4.907,6.982 c-0.772-1.37-0.982-4.73-1.554-6.428c-0.109-0.319-0.319-0.958,0-0.008C230.064,237.928,236.24,238.475,237.466,240.155z M267.989,202.381c3.991-0.008,4.168,5.125,8.604,3.772c-0.866,0.26,2.478,3.621-2.16,4.486c-2.916,0.529-6.965,3.73-10.166,1.63 c0.428,0.286,0.218,0.151,0.008,0.016c1.95,1.311-3.47,2.412-3.671,0.89C260.604,213.202,270.182,202.372,267.989,202.381z M268.569,177.066c0,0.092,1.604-2.21,2.252-3.176c-0.706,2.824,6.435,16.526,4.335,17.173c-1.31,0.404-3.101-2.134-3.596-1.529 c-2.209,2.697,1.74,6.83,0.479,7.973c0.319-0.286-2.958,0.723-3.772,1.193c0.017,0.152,0.042,0.236,0.067,0.236 c-0.335,0-0.302-0.093-0.067-0.236C268.023,196.458,268.712,178.62,268.569,177.066z M291.959,363.442 c-7.687,1.613-17.484-13.88-21.886-7.05c-3.151,4.89-16.854-2.201-17.409-0.083c0.782-2.992,5.84-0.933,2.579-5.294 c-2.805-3.756-6.351-3.546-10.897-4.201c-3.251-0.47-2.352-2.453-3.772-4.268c-0.874-1.117-1.832,1.958-2.689,1.639 c-0.118-0.042-4.848-6.982-4.848-7.209c5.864-7.688,7.494,2.764,10.771,4.1c6.612,2.697,6.704-4.73,13.098-1.806 c3.251,1.487,27.7,10.418,26.877,12.493c-0.428,0.496-0.949,0.874-1.571,1.118C283.382,354.77,291.144,363.618,291.959,363.442z M239.138,239.726c0-0.009,0-0.009,0-0.017c0.907-2.848,8.679-3.907,7.301-0.756C245.725,240.592,238.088,243.12,239.138,239.726z M261.218,221.948c0.008-0.176,3.126-11.066,4.722-8.15c1.756,3.218,0.95,19.433-2.874,21.769 c-0.991-0.084-1.352-0.597-1.076-1.538c0,2.05-13.325,5.05-13.14,5.234c-2.075-2.151,1.344-3.428-3.756-2.941 c0.075,0-11.309,1.487-7.746-0.546c3.798-2.168,7.074-2.714,11.527-2.798c3.646-0.067,3.319-5.276,5.94-5.511 c1.227-0.109,0.538,3.369,2.748,1.537C260.478,226.586,260.881,225.46,261.218,221.948z M292.53,351.729 c-2,0.488-7.343-2.218-5.478-2.453c-1.646,0.201-0.588,0.067,0.017-0.009c3.285-0.412,7.612-1.697,10.217-1.966 C299.899,347.041,293.539,351.486,292.53,351.729z M299.706,347.142c-0.513-0.538-0.908-1.134-1.16-1.806 C296.354,341.832,303.705,348.604,299.706,347.142z M376.371,386.555c-0.924-0.143-1.252-0.672-0.991-1.58 c0.984-2.823,3.059,1.033,3.386,1.37C377.968,386.412,377.169,386.488,376.371,386.555z M379.958,381.53 c-0.865,0,1.924-3.042,3.588-1.395C385.26,381.824,380.295,381.446,379.958,381.53z M397.502,128.882 c-4.588-0.865-3.108-4.159-6.713-4.462c-4.226-0.353-1.932,5.016-5.713,4c-13.897-3.73-0.63,5.469-4.882,9.612 c0.428-0.412-7.335-1.093-8.712-0.622c-2.815,0.966-6.738,1.622-9.108,3.352c-3.193,2.336-6.385,4.672-9.578,6.999 c-1.68,1.236-3.822-2.016-6.15-0.932c-2.731,1.269-8.78,0.513-10.595,1.697c-1.941,1.277-3.369,7.192-4.318,9.208 c-3.756,8.007-8.108,25.087-19.727,26.222c-0.572-4.79-5.957-24.718,3.73-25.752c7.747-0.84,18.82-12.014,16.728-19.845 c-7.771,0.311-3.847,4.739-7.183,6.235c-6.084,2.722-6.94-3.168-9.074-2.286c-6.377,2.655-6.974,2.454-8.284,8.755 c-0.487,2.336-8.847,0.774-11.107,0.689c-6.436-0.227-22.358-2.588-27.138,0.605c-7.427,4.957-14.854,9.914-22.282,14.871 c3.982,7.579,14.846,2.512,17.224,10.167c1.571,5.023-5.192,14.938-8.914,18.76c-3.664,3.772-7.335,7.545-11.006,11.318 c-3.512,3.612-3.991-0.488-7.352,1.411c-5.218,2.941-5.201,11.897-12.57,12.14c3.117,4.109,3.681,7.016,4.058,11.847 c0.378,4.89-3.243,4.487-8.007,6.192c-0.143-3.016-0.588-6.04,0-9.023c0.849-4.26-4.074-0.336-3.226-4.588 c1.47-7.385-7.906-3.201-11.846-2.134c0.302-2.134-0.412-4.444,0-6.561c-4.067,2.294-8.132,4.595-12.199,6.889 c3.688,3.185,6.284,7.276,11.838,4.587c0.571,4.075-3.126,4.537-6.814,6.562c5.142,3,5.436,9.83,6.948,14.779 c1.932,6.285-2.252,8.41-6.645,13.561c-4.672,5.478-5.655,6.982-12.746,8.931c-3.932,1.092-7.864,2.176-11.796,3.26 c-2,0.554-0.319,3.428-4.117,3.428c-0.982-6.73-8.847-1.386-11.258,1.512c-3.579,4.284,3.159,7.486,6.756,10.998 c9.653,9.436-3.874,15.123-10.931,19.962c-2.563-6.772-10.234-8.67-12.208-14.106c-2.689,9.838-3.285,10.074,4.033,17.568 c5.335,5.469,6.058,9.796,8.175,16.87c-4.31-1.966-9.377-2.907-11.073-7.142c-2.076-5.167-3.621-8.048-7.47-12.267 c-3.965-4.352-4.134-17.256-6.225-23.231c-1.555,1.168-4.201,1.118-5.747,2.294c-1.16-4.436-4.217-16.913-9.687-18.694 c-4.453-1.453-14.241,4.646-17.82,7.267c-4.721,3.47-15.476,8.226-15.636,14.09c-0.268,10.234-0.538,10.998-8.897,17.677 c-8.007-11.67-12.108-21.239-14.359-34.775c-7.662,3.755-11.872-6.578-16.509-10.821c-2.151-1.957-6.16-2.151-10.461-1.966 c-0.092-2.655-0.15-5.318-0.15-7.99c0-31.145,6.301-60.728,17.694-87.672c16.123-38.135,42.504-70.936,75.649-94.922 c2.142-0.05,4.251,0.286,6.326,1.294c4.025,1.966,9.368-4.974,15.392-2.924c-2.142-8.746,18.668-9.174,13.997,0.328 c4.537-1.336,8.486-3.184,13.208-2.487c7.746,1.126,5.578,2.403,4.529,9.368c-0.042,0.261-24.189,8.838-15.812,10.014 c8.108,1.143,15.132-4.327,23.542-3.713c9.687,0.698,14.005,4.89,24.424,5.184c-4.159-9.99,12.728-2.789,17.946-1.638 c-5.78,4.748,5.738,10.158,9.696,13.452c-0.143-7.301,14.871-5.973,21.6-5.629c3.706,0.194,1.983-6.638,6.57-5.839 c6.226,1.084,12.443,2.167,18.668,3.251c5.252,0.916,8.015-0.344,13.148,2.403c3.512,1.882,1.143,6.394,5.948,5.882 c3.42-0.362,11.595-2.806,14.048-0.362c3.655,3.638,1.597,7.814,7.596,9.805c1.352-6.663,12.871-6.612,18.66-4.924 c2.68,0.79,14.972,10.544,10.41-1.311c10.871,2.21,21.734,4.411,32.606,6.621c4.26,0.866,4.352,4.192,7.956,5.848 c2.344,1.076,8.856,0.748,12.2,1.966C413.851,126.9,403.425,130.008,397.502,128.882z M406.693,134.654 c0.176-0.588,0.362-1.176,0.546-1.764c1.429-1.412,9.62-1.546,10.814,0.428C419.136,135.108,407.441,135.293,406.693,134.654z M437.107,168.185c4.974-4.864,9.897-9.754,15.081-14.425c-10.149,0.513-12.468,2.932-14.358-6.562 c-2.151,1.31-4.31,2.621-6.461,3.932c-2.638-3.923-8.838-9.552-2.874-13.778c1.782-1.252,6.008,0.487,7.898-0.656 c1.832-1.1,3.293-6.008,4.31-7.873c-5.176-1.84-5.31,2.723-9.334,2.63c-3.881-0.092-9.258-3.293-12.922-4.596 c3.377-6.99,11.485-5.906,17.013-6.939c2.521,3.318,4.982,6.687,7.326,10.158c6.41,9.494,12.09,19.508,17.022,29.943 C453.406,164.791,445.156,170.715,437.107,168.185z M453.18,278.096c-1.051,0.194-1.673-1.747-0.236-1.747 C454.381,276.349,454.381,277.878,453.18,278.096z M457.011,283.785c-0.47-0.58-0.227-0.278-0.008-0.017 c-2.243-2.739-1.663-6.209,2.403-4.352C461.498,280.356,458.43,285.499,457.011,283.785z M231.005,240.701v0.008C231.055,240.86,231.089,240.945,231.005,240.701z M287.07,349.268c-0.008,0-0.008,0.009-0.017,0.009C287.608,349.2,287.414,349.226,287.07,349.268z"
|
|
1275
|
+
};
|
|
1276
|
+
var REGION_GLOBES = ["africa", "americas", "asia"];
|
|
1277
|
+
|
|
1278
|
+
// src/genre-tree/RegionGlobeIcon.tsx
|
|
1279
|
+
var import_jsx_runtime22 = require("react/jsx-runtime");
|
|
1280
|
+
var ROTATION_INTERVAL_MS = 3e3;
|
|
1281
|
+
function RegionGlobeIcon({ className: className2 }) {
|
|
1282
|
+
const [index, setIndex] = (0, import_react11.useState)(0);
|
|
1283
|
+
(0, import_react11.useEffect)(() => {
|
|
1284
|
+
const reducedMotion = window.matchMedia("(prefers-reduced-motion: reduce)");
|
|
1285
|
+
let timer;
|
|
1286
|
+
const sync = () => {
|
|
1287
|
+
clearInterval(timer);
|
|
1288
|
+
timer = reducedMotion.matches ? void 0 : setInterval(() => setIndex((i) => (i + 1) % REGION_GLOBES.length), ROTATION_INTERVAL_MS);
|
|
1289
|
+
};
|
|
1290
|
+
sync();
|
|
1291
|
+
reducedMotion.addEventListener("change", sync);
|
|
1292
|
+
return () => {
|
|
1293
|
+
reducedMotion.removeEventListener("change", sync);
|
|
1294
|
+
clearInterval(timer);
|
|
1295
|
+
};
|
|
1296
|
+
}, []);
|
|
1297
|
+
return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("svg", { viewBox: "0 0 512 512", fill: "currentColor", className: className2, "aria-hidden": true, children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("path", { "data-testid": "region-globe-path", d: REGION_GLOBE_PATHS[REGION_GLOBES[index]] }) });
|
|
1298
|
+
}
|
|
1299
|
+
|
|
1300
|
+
// src/genre-tree/treeMarkPath.ts
|
|
1301
|
+
var TREE_MARK_PATH = "M3171 5598 c-5 -13 -5 -24 0 -26 5 -2 9 -16 9 -31 0 -25 -3 -28 -25 -23 l-25 4 0 -116 c0 -64 3 -116 8 -116 10 0 32 51 26 61 -3 5 -1 9 4 9 5 0 15 12 21 28 7 15 26 36 43 47 30 20 88 105 71 105 -4 0 -33 -21 -62 -47 l-54 -47 6 63 c4 35 7 72 7 82 0 10 9 19 23 22 16 3 13 5 -11 6 -25 1 -35 -4 -41 -21z M2893 5485 c8 -76 24 -100 71 -100 l36 0 0 53 c0 58 -15 69 -28 20 -8 -29 -10 -30 -16 -13 -15 43 -42 89 -55 93 -11 4 -13 -6 -8 -53z M2484 5438 c8 -70 49 -169 54 -131 2 12 10 27 18 33 17 15 19 84 3 129 -9 27 -16 31 -46 31 l-36 0 7 -62z M2625 5448 c-7 -22 -24 -121 -31 -179 l-6 -57 -27 11 c-15 5 -32 19 -37 31 -9 21 -88 86 -105 86 -39 0 38 -104 118 -158 17 -12 56 -59 86 -105 30 -45 67 -92 81 -104 14 -13 26 -30 26 -38 0 -13 -9 -11 -45 11 -67 39 -58 10 21 -66 67 -65 96 -110 108 -167 4 -17 13 -34 20 -36 20 -8 66 -186 75 -289 13 -161 -8 -272 -72 -365 -12 -18 -30 -33 -39 -33 -23 0 -53 33 -79 89 -25 54 -69 112 -121 162 -35 33 -38 40 -38 92 0 58 36 172 79 252 25 47 29 125 6 125 -19 0 -30 -22 -50 -100 -9 -35 -24 -78 -32 -94 l-16 -30 -19 24 -20 25 7 -58 c8 -62 0 -127 -16 -127 -19 0 -122 107 -166 172 -52 79 -68 150 -60 273 8 108 17 129 67 149 58 23 97 64 105 109 9 47 -5 49 -63 6 l-42 -30 15 35 c17 41 20 102 5 111 -18 11 -45 -4 -64 -36 -11 -19 -20 -60 -23 -110 -4 -54 -10 -79 -18 -79 -20 0 -27 28 -30 108 -2 40 -6 76 -9 79 -3 4 -6 51 -6 105 0 86 -3 101 -21 119 -27 27 -42 20 -53 -24 -7 -28 -5 -51 7 -90 9 -30 17 -76 17 -103 l0 -49 -29 51 c-29 49 -92 114 -111 114 -6 0 -10 -11 -10 -25 0 -14 5 -25 10 -25 6 0 10 -6 10 -13 0 -7 23 -44 51 -82 61 -84 59 -82 52 -57 -3 14 2 24 15 31 12 6 23 23 25 38 2 16 5 2 6 -29 1 -46 -2 -58 -14 -58 -21 0 -19 -13 10 -70 22 -44 25 -61 25 -165 l0 -116 -47 27 c-65 36 -142 118 -176 187 -15 31 -37 62 -49 68 -21 11 -21 10 -15 -41 l6 -52 -29 6 c-37 7 -39 -7 -4 -31 14 -10 53 -40 86 -68 92 -76 130 -104 163 -119 39 -19 101 -84 109 -116 10 -42 50 -88 217 -245 50 -47 94 -102 134 -167 33 -54 65 -98 71 -98 17 0 45 -79 51 -145 4 -47 0 -76 -20 -135 -14 -41 -39 -121 -56 -177 -18 -57 -35 -103 -40 -103 -4 0 -26 13 -49 30 -31 22 -50 49 -82 117 -99 209 -116 241 -185 337 -123 172 -123 173 -128 311 -5 140 -29 245 -57 245 -12 0 -20 -11 -24 -31 -9 -46 -7 -108 3 -127 14 -26 25 -162 14 -162 -20 0 -160 99 -192 135 -19 22 -42 58 -52 80 -10 23 -27 52 -37 66 -10 13 -26 38 -34 54 -9 17 -23 45 -33 64 -15 29 -16 40 -6 80 31 116 34 139 27 205 -7 57 -11 69 -28 74 -14 3 -32 30 -54 79 -21 46 -39 73 -47 70 -13 -5 -14 -15 -3 -65 l8 -33 -49 25 c-61 31 -93 40 -93 27 0 -13 43 -41 122 -79 47 -22 72 -41 83 -61 19 -38 19 -51 0 -51 -12 0 -15 -15 -16 -72 -1 -79 -12 -134 -22 -108 -3 8 -10 48 -16 89 -14 89 -25 111 -54 111 -38 0 -50 -15 -45 -54 4 -40 2 -42 -26 -21 -29 22 -36 19 -36 -20 0 -39 39 -85 125 -145 38 -27 62 -56 99 -120 45 -79 82 -177 70 -189 -2 -3 -42 3 -87 13 -45 10 -99 21 -119 26 -47 9 -103 51 -125 93 -24 44 -83 203 -94 252 -5 25 -4 59 3 91 14 68 3 140 -23 155 -12 6 -23 8 -27 5 -14 -15 -13 -115 2 -159 39 -116 0 -116 -70 1 -22 36 -31 42 -59 42 -20 0 -35 6 -39 15 -6 16 -56 21 -56 6 0 -5 23 -25 51 -44 53 -36 158 -156 188 -216 10 -20 26 -60 36 -88 11 -29 25 -53 32 -53 8 0 13 -12 13 -30 0 -26 -4 -30 -27 -31 l-28 -1 25 -7 c26 -8 177 -87 196 -102 5 -4 50 -18 100 -29 122 -29 277 -78 300 -95 10 -8 26 -15 34 -15 35 0 160 -166 160 -212 0 -22 -32 -24 -50 -4 -11 14 -100 46 -165 61 -16 3 -68 25 -115 48 -102 49 -163 56 -168 19 -9 -62 58 -104 178 -112 63 -5 103 -14 155 -37 39 -16 91 -38 117 -47 26 -9 74 -35 106 -56 52 -33 65 -48 96 -112 20 -40 39 -95 43 -122 6 -47 6 -48 -18 -41 -33 10 -69 33 -69 45 0 6 -10 10 -23 10 -13 0 -27 4 -32 9 -6 5 -27 14 -47 20 -20 7 -53 23 -73 37 -43 29 -45 29 -45 7 0 -26 80 -96 145 -127 119 -56 274 -185 311 -259 55 -107 104 -410 104 -640 0 -162 -22 -325 -45 -333 -25 -10 -72 25 -168 123 -129 131 -140 148 -182 274 -20 60 -50 142 -66 181 -16 39 -45 131 -65 202 -24 93 -55 173 -104 274 -77 158 -78 166 -32 256 31 64 27 129 -12 181 -31 40 -39 42 -65 18 -51 -49 -55 -120 -11 -208 37 -74 37 -85 3 -85 -36 0 -94 65 -137 154 -18 39 -37 80 -40 92 -3 11 -14 29 -24 40 -10 10 -28 35 -42 54 -13 19 -40 55 -61 80 -20 25 -41 63 -47 85 -6 22 -16 62 -23 89 -20 81 -95 147 -113 100 -18 -47 -6 -92 39 -147 25 -31 45 -61 45 -67 0 -15 -42 -3 -116 31 -94 44 -156 124 -184 235 -9 36 -13 41 -38 40 -39 -2 -144 113 -186 205 -31 66 -33 68 -53 54 -11 -8 -24 -11 -27 -7 -4 4 11 -24 33 -62 39 -67 43 -86 18 -86 -8 0 -8 3 1 9 11 6 9 9 -7 14 -11 3 -25 -1 -31 -7 -7 -10 0 -16 29 -24 39 -12 203 -147 215 -178 13 -34 4 -35 -48 -6 -64 37 -126 51 -126 30 0 -26 55 -67 125 -92 46 -16 80 -36 100 -58 l29 -33 -54 -3 c-79 -5 -203 14 -249 38 -47 24 -70 54 -105 140 -43 105 -115 163 -103 83 3 -21 9 -47 13 -57 4 -11 -15 4 -42 32 -62 64 -84 67 -84 14 0 -41 24 -76 61 -87 16 -6 18 -9 8 -15 -23 -15 15 -45 117 -91 52 -24 93 -48 91 -54 -10 -28 -150 -28 -190 0 -21 15 -47 5 -47 -17 0 -5 -10 -19 -22 -29 -23 -20 -23 -20 112 -14 174 8 208 8 430 0 l185 -7 84 -41 c115 -57 180 -118 225 -212 20 -41 36 -77 36 -80 0 -14 89 -126 150 -190 74 -78 120 -144 120 -175 0 -30 10 -33 -201 52 -94 38 -131 71 -218 195 -27 37 -59 77 -71 88 l-23 20 7 -40 c4 -22 12 -44 17 -49 13 -14 11 -26 -4 -26 -7 0 -29 21 -48 48 -33 45 -34 51 -39 159 -4 89 -9 116 -22 130 -17 16 -18 16 -18 0 0 -9 -7 -17 -16 -17 -14 0 -16 -9 -11 -62 3 -35 8 -74 12 -88 l7 -25 -25 27 c-41 44 -127 118 -137 118 -18 0 -10 -57 12 -85 18 -24 20 -32 10 -57 -10 -28 -9 -30 22 -43 18 -8 54 -19 79 -26 36 -9 60 -24 99 -66 80 -83 80 -83 1 -83 -80 0 -176 21 -236 51 -107 54 -234 169 -252 228 -4 14 -12 29 -17 35 -5 6 -18 25 -28 43 -24 40 -90 64 -116 42 -22 -18 -13 -84 17 -116 13 -13 42 -32 64 -42 22 -10 74 -53 115 -96 l75 -77 -75 5 c-135 8 -243 76 -336 207 -31 44 -65 87 -77 95 -37 26 -34 -9 7 -88 20 -39 34 -72 31 -75 -2 -2 -26 11 -52 31 -90 65 -143 83 -143 49 0 -32 71 -88 150 -117 41 -15 113 -47 159 -71 46 -24 99 -46 118 -50 18 -3 33 -12 33 -18 0 -12 -111 -46 -149 -46 -12 0 -29 -8 -39 -17 -10 -10 -27 -19 -37 -19 -11 -1 -45 -9 -75 -17 -58 -16 -110 -62 -110 -97 0 -39 116 -45 167 -9 11 8 34 31 52 51 28 32 50 43 144 74 145 47 222 48 404 5 70 -17 177 -38 237 -47 128 -19 202 -43 250 -79 18 -14 73 -42 122 -61 164 -66 208 -112 243 -251 36 -141 27 -167 -44 -123 -19 12 -63 23 -111 28 -117 13 -134 25 -275 193 -63 74 -193 151 -266 157 -29 2 -66 -1 -81 -7 -24 -10 -37 -9 -80 8 -66 26 -70 9 -11 -44 72 -65 119 -80 239 -78 60 1 109 -2 117 -8 6 -6 26 -35 42 -64 17 -30 46 -64 64 -77 19 -13 49 -40 67 -61 l34 -39 -79 3 c-57 3 -80 0 -83 -9 -3 -10 -7 -10 -18 -1 -8 6 -11 15 -8 20 3 5 0 9 -5 9 -16 0 -13 -16 6 -36 36 -36 78 -44 227 -44 119 0 152 -3 188 -19 56 -24 95 -64 125 -126 13 -27 35 -68 48 -90 14 -22 25 -53 25 -69 l0 -29 -107 5 c-131 6 -193 28 -290 100 -37 28 -82 56 -98 63 -75 32 -176 123 -277 247 -34 42 -122 98 -134 85 -5 -5 103 -138 184 -226 52 -57 46 -61 -49 -31 -87 28 -173 85 -325 214 -144 123 -189 151 -254 159 -25 2 -39 3 -32 0 6 -3 12 -16 12 -29 0 -17 -4 -23 -12 -19 -7 4 -1 -5 15 -19 15 -14 46 -30 70 -36 23 -6 60 -17 82 -25 l40 -13 -52 -1 c-49 -1 -53 -3 -53 -25 0 -28 28 -36 122 -36 54 0 62 -3 91 -32 l32 -33 -52 -3 c-88 -5 -75 -26 39 -62 130 -41 178 -63 206 -93 l22 -24 -20 -18 c-12 -11 -41 -20 -74 -23 -48 -4 -60 0 -116 32 -118 69 -241 96 -279 62 -13 -12 -40 -16 -104 -16 -48 0 -95 4 -105 9 -9 5 -34 16 -55 25 -20 9 -76 53 -122 97 -47 45 -88 79 -91 76 -12 -12 6 -54 41 -100 l36 -47 -74 0 c-88 0 -112 15 -78 49 26 26 21 39 -34 84 -87 73 -132 32 -50 -45 25 -23 45 -46 45 -50 0 -4 -21 2 -46 12 -45 20 -114 27 -114 12 0 -4 16 -22 35 -40 39 -38 78 -47 255 -61 164 -14 178 -17 172 -47 -2 -13 -2 -30 2 -39 5 -13 9 -13 40 2 19 9 33 20 30 25 -4 5 4 4 15 -4 21 -13 20 -15 -44 -74 -36 -33 -65 -66 -65 -72 0 -21 68 15 142 74 38 30 84 62 103 70 73 30 203 11 312 -46 32 -17 82 -33 111 -37 l53 -6 -28 -30 c-15 -16 -44 -40 -63 -52 -63 -42 -100 -82 -100 -111 0 -25 2 -26 37 -21 28 5 47 17 73 49 65 78 175 183 224 216 34 22 61 32 88 32 43 0 122 -36 152 -69 10 -11 39 -32 62 -46 43 -25 53 -46 36 -72 -11 -17 -200 -86 -232 -85 -28 1 -122 -47 -127 -65 -3 -8 14 -13 54 -15 l58 -3 -65 -44 c-36 -25 -68 -49 -71 -53 -11 -17 -115 -10 -188 12 -105 32 -112 11 -14 -39 l56 -28 -40 -6 c-52 -9 -96 0 -154 29 -31 15 -50 19 -60 13 -15 -10 -16 -10 44 -47 20 -13 37 -27 37 -31 0 -15 -144 -71 -205 -81 -33 -5 -85 -10 -116 -10 -32 0 -63 -6 -75 -14 -18 -13 -15 -15 34 -22 l53 -7 -31 -18 c-18 -12 -30 -27 -30 -40 0 -21 4 -21 61 -16 50 4 75 14 145 57 46 28 112 63 146 77 62 24 191 62 215 63 22 0 -47 -103 -107 -161 -42 -41 -60 -66 -65 -92 -10 -49 0 -60 47 -54 65 9 99 53 124 160 20 83 49 133 94 163 22 15 40 30 40 34 0 4 8 10 18 13 9 3 31 15 49 27 31 21 31 21 26 0 -3 -11 -21 -37 -40 -58 -43 -45 -72 -106 -73 -150 0 -39 18 -49 56 -30 38 18 63 64 75 137 13 82 40 142 89 194 22 24 40 49 40 54 0 6 24 21 53 34 49 22 63 23 237 20 193 -2 278 -14 348 -50 21 -11 44 -27 52 -36 7 -9 32 -27 55 -41 49 -28 138 -147 184 -243 16 -35 42 -114 57 -175 35 -147 31 -268 -14 -436 -17 -63 -37 -166 -45 -227 -12 -94 -21 -127 -54 -195 -22 -46 -52 -94 -67 -108 -15 -14 -46 -44 -68 -67 -23 -24 -47 -43 -53 -43 -7 0 -25 -12 -41 -26 -129 -121 -526 -267 -721 -268 -104 0 -109 -15 -19 -57 75 -35 67 -35 221 -10 125 21 235 27 235 13 0 -16 -66 -72 -85 -72 -24 0 -85 -36 -85 -49 0 -14 12 -19 58 -27 35 -5 42 -4 42 10 0 9 5 17 10 17 28 4 74 20 80 29 9 14 226 119 288 139 63 21 215 43 239 34 32 -12 12 -50 -52 -102 -36 -28 -73 -55 -83 -58 -17 -7 -66 -39 -92 -60 -8 -7 -38 -32 -67 -57 l-52 -45 42 -6 c36 -6 54 -1 122 33 44 22 120 56 169 76 112 45 222 107 289 164 46 40 84 62 107 62 18 0 130 -83 130 -96 0 -8 4 -14 10 -14 5 0 39 -26 75 -59 36 -32 96 -76 132 -97 36 -21 68 -46 71 -56 5 -19 21 -22 59 -12 18 5 20 9 10 19 -7 7 -69 71 -139 143 -147 149 -161 179 -80 168 136 -19 195 -39 378 -128 78 -37 147 -68 152 -68 6 0 15 -7 20 -16 8 -14 14 -15 46 -4 l38 12 -104 57 c-125 69 -148 84 -148 93 0 16 94 7 223 -22 74 -17 146 -30 160 -30 14 0 29 -4 32 -10 7 -11 54 6 115 43 l40 24 -38 1 c-22 1 -68 11 -103 21 -35 11 -107 30 -159 41 -131 31 -295 99 -406 171 -235 153 -355 366 -357 634 -1 211 65 343 285 568 117 119 206 167 368 198 153 29 267 59 328 86 80 35 166 44 264 27 148 -26 167 -38 251 -169 71 -110 136 -165 196 -165 26 0 31 4 31 23 -1 32 -28 62 -87 91 -39 20 -66 45 -118 112 -95 123 -95 135 -5 92 25 -12 77 -31 116 -43 56 -17 76 -19 97 -10 27 11 26 11 -25 29 -113 39 -138 49 -138 57 0 14 91 55 153 68 33 7 75 10 95 7 27 -4 31 -3 17 4 -19 8 -19 9 3 9 12 1 22 7 22 15 0 10 7 12 22 8 12 -3 17 -7 10 -10 -6 -2 -12 -10 -12 -18 0 -8 -6 -14 -12 -15 -27 -2 39 -17 80 -18 29 -1 42 3 42 13 0 20 -19 32 -67 45 -49 13 -53 22 -20 44 49 32 128 39 235 21 56 -9 112 -14 126 -10 26 6 96 69 96 86 0 6 -32 10 -77 10 -84 0 -126 -7 -118 -20 9 -14 -17 -24 -67 -24 -34 -1 -48 3 -48 13 0 8 -7 11 -20 8 -17 -4 -18 -2 -9 14 5 11 14 17 20 14 5 -4 9 0 9 8 0 8 16 35 35 60 35 45 35 46 14 57 -18 10 -23 8 -37 -12 -67 -95 -162 -167 -297 -225 -55 -23 -99 -47 -98 -53 2 -5 -6 -10 -18 -10 -27 0 -23 8 31 71 100 117 116 131 161 155 80 40 80 70 1 41 l-47 -18 36 38 c47 49 59 73 59 120 0 67 -24 80 -82 46 -49 -29 -76 -85 -89 -183 -10 -81 -9 -80 -89 -174 -20 -22 -43 -53 -53 -68 -28 -45 -89 -61 -217 -56 -70 2 -114 8 -118 15 -4 6 -28 13 -54 15 l-46 3 53 71 c51 68 100 104 140 104 50 0 125 73 125 122 0 30 0 31 -45 26 -28 -4 -59 -16 -82 -34 -30 -23 -35 -24 -28 -8 22 51 37 105 31 111 -13 13 -47 -34 -105 -146 -72 -138 -171 -248 -261 -292 -62 -30 -164 -44 -242 -34 -48 7 -50 8 -45 34 14 70 51 144 95 190 42 43 56 51 127 69 44 12 98 24 120 27 99 15 155 57 155 117 l0 31 -51 -5 c-40 -4 -58 -12 -87 -40 -56 -52 -66 -58 -131 -78 l-60 -18 10 27 c6 14 36 62 68 106 70 96 91 136 91 170 0 41 -18 29 -50 -35 -30 -59 -31 -60 -74 -60 -56 0 -71 -18 -101 -115 -23 -75 -43 -114 -72 -145 -8 -8 -41 -61 -73 -117 -35 -59 -75 -113 -95 -128 -37 -29 -177 -85 -210 -85 -35 0 -222 -134 -282 -202 -31 -35 -64 -64 -72 -66 -22 -4 -68 116 -88 223 -20 113 -5 256 37 340 37 76 124 182 195 238 140 110 221 137 416 137 136 0 171 6 186 28 9 15 2 17 -76 18 -47 0 -127 4 -178 9 -167 15 -274 -28 -423 -170 -72 -68 -114 -95 -128 -81 -12 12 17 138 44 194 64 132 229 243 439 298 182 46 319 21 425 -80 68 -65 144 -115 202 -135 119 -41 155 -32 72 17 -88 52 -224 144 -224 152 0 14 51 20 210 22 115 2 160 0 175 -10 19 -12 18 -13 -8 -9 -36 6 -45 -9 -11 -17 56 -15 117 -51 183 -110 66 -59 119 -86 169 -86 54 0 31 59 -35 90 -167 77 -176 82 -158 93 25 13 138 -8 201 -37 27 -13 67 -43 89 -66 50 -53 84 -70 134 -70 37 0 71 19 71 40 0 24 -62 57 -129 70 -40 7 -74 17 -77 22 -3 4 24 8 60 8 36 0 68 -4 71 -10 3 -5 26 -10 51 -10 50 0 57 15 23 46 -24 21 -113 25 -226 10 -50 -7 -65 -6 -77 7 -19 18 -100 37 -160 37 -74 0 -136 12 -136 26 0 17 11 23 53 28 32 4 83 29 97 47 8 10 71 40 99 47 28 7 159 8 309 1 50 -2 92 -1 92 4 0 4 14 7 30 7 23 0 30 -4 30 -20 0 -15 -7 -20 -25 -20 -42 0 -28 -17 30 -39 75 -28 103 -27 117 4 8 18 19 25 38 25 34 0 47 35 23 62 -24 27 -70 31 -190 18 -101 -11 -112 -10 -173 10 -36 12 -104 24 -152 27 -49 3 -88 9 -88 13 0 8 35 26 66 35 12 3 37 21 55 40 19 20 67 58 106 86 57 39 86 52 134 60 71 11 170 58 193 91 34 49 10 51 -66 5 -52 -31 -154 -65 -165 -54 -11 12 9 25 67 47 33 12 60 26 60 30 0 5 15 17 34 28 31 18 67 84 53 98 -15 15 -69 -17 -124 -75 -35 -36 -63 -63 -63 -58 0 4 14 31 30 60 43 77 39 180 -7 151 -39 -24 -56 -62 -63 -141 -7 -87 -27 -127 -98 -200 -50 -52 -120 -103 -139 -103 -8 0 -22 -8 -31 -17 -31 -31 -26 11 12 94 33 74 61 171 53 180 -3 2 -17 1 -32 -3 -38 -10 -65 -74 -75 -185 -9 -97 -31 -147 -79 -176 -31 -20 -81 -71 -81 -83 0 -5 -24 -16 -52 -26 -29 -9 -58 -24 -64 -32 -7 -9 -33 -17 -70 -19 l-59 -4 55 48 c120 105 133 126 66 103 -19 -6 -58 -36 -88 -66 -29 -30 -72 -64 -96 -76 -41 -19 -50 -20 -163 -9 -168 16 -237 52 -196 103 21 27 121 88 143 88 60 0 183 34 234 65 30 18 74 36 97 40 85 14 180 99 131 118 -16 5 -19 13 -14 33 7 25 5 25 -26 19 -52 -11 -83 -31 -122 -76 -54 -63 -94 -86 -197 -109 -52 -12 -102 -24 -111 -26 -28 -8 -22 22 10 44 15 11 35 34 45 51 16 27 16 31 2 31 -8 0 -18 -7 -22 -16 -8 -23 -23 2 -23 40 0 23 -3 27 -12 18 -14 -14 -42 -16 -33 -2 3 6 4 10 1 10 -9 0 -37 -61 -62 -133 -29 -84 -85 -162 -137 -189 -24 -12 -67 -21 -110 -24 -40 -2 -100 -6 -134 -9 l-62 -4 36 72 c20 39 48 84 62 98 29 29 86 122 96 157 9 32 -20 29 -42 -5 -17 -27 -128 -174 -222 -297 -45 -58 -101 -96 -141 -96 -48 0 -9 184 59 284 41 59 113 107 234 156 51 20 141 67 198 102 57 36 118 72 134 80 40 21 155 46 240 53 48 5 82 14 113 32 58 34 150 44 258 28 41 -6 57 -4 75 9 17 12 46 16 111 16 88 0 116 12 57 24 -17 3 -48 6 -69 6 -21 0 -43 6 -49 14 -14 17 -8 22 40 31 30 5 36 10 32 26 -4 13 0 19 12 19 23 0 95 44 129 79 34 35 30 67 -6 55 -13 -4 -31 -7 -41 -6 -11 0 -38 -25 -68 -64 -28 -35 -53 -64 -55 -64 -2 0 7 22 21 50 14 27 25 60 25 74 0 14 5 37 11 53 7 19 7 29 0 31 -6 2 -11 17 -11 33 0 16 -4 29 -10 29 -5 0 -10 -19 -10 -42 0 -50 -37 -158 -74 -222 -28 -48 -90 -86 -141 -86 l-29 0 36 38 c20 20 43 52 52 70 16 31 16 32 -5 32 -25 0 -94 -47 -109 -75 -19 -35 -161 -104 -245 -120 -42 -8 -85 -15 -96 -15 -18 0 -18 1 -2 35 9 19 20 35 25 35 4 0 8 6 8 13 0 7 13 34 30 60 30 48 75 77 182 117 58 21 112 66 176 146 26 31 57 57 84 69 124 52 167 75 177 93 17 33 -14 35 -71 6 -29 -14 -69 -32 -89 -39 l-38 -14 20 51 c11 28 24 59 29 68 10 19 -20 60 -45 60 -18 0 -21 46 -4 52 6 2 14 26 16 53 4 43 2 52 -16 63 -20 11 -21 10 -21 -25 -1 -209 -5 -248 -32 -305 -34 -73 -116 -188 -133 -188 -8 0 -20 -6 -27 -13 -7 -7 -29 -18 -48 -24 -19 -6 -52 -18 -72 -27 -34 -15 -38 -15 -38 -1 0 35 32 73 89 109 60 37 77 51 45 39 -14 -5 -14 -3 -3 14 7 13 9 28 4 39 -5 11 -7 24 -6 29 1 6 -19 -11 -44 -37 -25 -26 -45 -44 -45 -40 0 4 18 34 40 67 30 45 40 69 40 100 0 53 -11 67 -46 63 -22 -2 -34 -13 -53 -47 -14 -25 -26 -40 -29 -33 -2 7 -10 12 -17 12 -10 0 -14 -33 -17 -142 l-4 -143 -63 -127 c-39 -81 -74 -137 -94 -154 -51 -43 -167 -87 -167 -63 0 6 26 38 58 72 32 34 66 73 75 87 18 26 23 100 8 100 -5 0 -22 -19 -38 -42 -15 -23 -52 -60 -81 -82 -31 -25 -61 -59 -74 -85 -37 -75 -125 -156 -220 -201 -46 -22 -101 -43 -121 -47 -32 -5 -37 -3 -37 13 0 36 50 229 70 269 10 23 38 95 61 160 39 116 84 211 117 248 12 13 13 20 4 29 -9 9 -21 5 -49 -18 -58 -46 -166 -272 -249 -519 -37 -110 -73 -207 -80 -216 -8 -8 -14 -21 -14 -28 0 -8 -19 -54 -41 -105 -23 -50 -61 -146 -84 -212 -49 -144 -77 -193 -152 -274 -71 -77 -89 -77 -115 2 -11 33 -27 59 -36 62 -19 6 -21 27 -23 201 -2 197 49 394 151 580 33 61 72 135 86 165 118 253 140 288 273 462 87 112 121 167 121 195 0 37 -25 27 -75 -29 -42 -48 -45 -50 -38 -23 13 50 9 145 -8 156 -19 12 -30 7 -50 -22 -23 -33 -15 -116 12 -124 28 -9 35 -49 12 -73 -10 -11 -36 -45 -58 -76 -22 -31 -44 -56 -48 -56 -12 0 -3 78 17 160 8 36 15 84 16 107 0 23 4 44 9 47 4 3 11 37 14 75 3 39 14 86 26 109 26 50 80 97 94 83 16 -16 59 -13 85 5 30 21 52 66 52 109 0 33 -2 35 -32 35 -59 0 -78 -12 -118 -69 -21 -31 -55 -74 -74 -96 l-35 -40 -1 41 c0 23 7 60 15 83 15 43 92 151 124 173 20 14 55 77 48 85 -3 2 -8 -5 -12 -16 -7 -24 -35 -17 -35 9 0 23 -13 32 -35 24 -9 -4 -12 -9 -7 -13 17 -10 2 -62 -16 -59 -11 2 -30 -24 -61 -87 -34 -68 -46 -84 -49 -67 -2 12 -8 22 -13 22 -5 0 -9 -10 -9 -22 -1 -23 -1 -23 -16 -3 -9 11 -24 37 -34 58 -11 24 -20 34 -23 25 -3 -7 -6 25 -6 72 -1 105 -21 98 -26 -10 -3 -43 -9 -76 -16 -81 -10 -6 -10 -11 0 -23 14 -16 3 -22 -15 -8 -5 4 2 -2 15 -13 51 -41 78 -76 96 -128 26 -70 25 -187 -3 -292 -13 -49 -21 -109 -20 -155 0 -104 -54 -310 -81 -310 -6 0 -11 3 -11 8 -1 44 -24 191 -41 259 l-22 85 27 108 c30 123 34 211 10 231 -20 16 -40 5 -72 -42 -21 -30 -23 -42 -18 -97 3 -36 1 -60 -4 -57 -17 11 -34 81 -34 150 -1 64 2 76 39 140 22 39 45 84 52 100 17 43 16 92 -2 98 -17 7 -17 8 -44 -73 -12 -36 -34 -87 -50 -113 -33 -56 -41 -48 -41 39 0 41 -4 54 -15 54 -11 0 -15 -18 -17 -80 -2 -45 -7 -80 -13 -80 -5 0 -10 4 -10 8 0 5 -8 16 -18 26 -58 58 -70 132 -53 314 7 69 6 92 -3 92 -6 0 -13 -6 -16 -12z m321 -503 c3 -20 4 -39 0 -42 -3 -4 -6 6 -6 20 0 17 -5 27 -15 27 -16 0 -20 12 -8 23 14 14 22 6 29 -28z m-1006 -80 c0 -8 -9 -15 -19 -15 -29 0 -35 18 -9 23 13 2 24 5 26 6 1 0 2 -6 2 -14z m327 -27 c-3 -7 -5 -2 -5 12 0 14 2 19 5 13 2 -7 2 -19 0 -25z m-462 -358 c3 -5 1 -10 -4 -10 -6 0 -11 5 -11 10 0 6 2 10 4 10 3 0 8 -4 11 -10z m-835 -40 c-6 -11 -15 -20 -19 -20 -5 0 -7 9 -4 20 3 11 12 20 20 20 11 0 11 -4 3 -20z m864 -25 c3 -9 0 -15 -9 -15 -9 0 -15 -10 -16 -27 0 -27 -1 -27 -13 7 -10 25 -10 37 -2 42 18 12 33 9 40 -7z m-892 -863 c38 2 68 0 68 -4 0 -5 -33 -8 -73 -8 -49 0 -80 -5 -95 -16 -21 -14 -22 -14 -22 5 0 14 -6 21 -20 21 -11 0 -20 2 -20 4 0 2 -3 12 -6 21 -6 13 1 13 47 -5 40 -16 70 -21 121 -18z m3218 -91 c0 -10 -7 -21 -15 -25 -11 -4 -15 1 -15 19 0 16 6 25 15 25 8 0 15 -9 15 -19z m-3479 -32 c-14 -5 -30 -14 -37 -20 -8 -7 -13 -3 -17 11 -5 18 0 20 36 19 38 0 40 -1 18 -10z m3359 -572 c0 -7 -7 -22 -15 -33 -13 -17 -14 -16 -4 14 11 33 19 41 19 19z m-3345 -198 c7 -22 -7 -39 -33 -39 -10 0 -10 4 0 20 11 17 10 22 -2 30 -12 8 -11 10 7 10 13 0 24 -8 28 -21z m445 -37 c0 -23 -35 -8 -38 16 -3 21 -2 22 17 10 12 -7 21 -19 21 -26z m-310 -647 c-28 -30 -60 -33 -60 -7 0 26 9 32 48 32 l35 0 -23 -25z M3684 5414 c-14 -21 -16 -41 -10 -124 4 -62 2 -100 -3 -100 -9 0 -17 26 -25 84 -1 11 -8 22 -14 24 -9 3 -12 -27 -12 -105 0 -69 -6 -130 -16 -164 -24 -86 -24 -85 -33 -70 -6 9 -10 3 -14 -17 -4 -20 -23 -43 -59 -72 -29 -23 -54 -46 -54 -51 -1 -5 -3 -39 -4 -76 -1 -46 -4 -60 -9 -43 -6 21 -9 15 -20 -35 -16 -74 -29 -99 -97 -197 -35 -49 -54 -86 -54 -105 0 -31 59 -200 60 -171 0 9 6 21 14 25 13 7 13 16 0 68 -17 72 -12 78 75 93 106 19 127 33 145 95 20 70 65 111 186 172 83 42 89 47 75 62 -9 8 -14 23 -11 32 5 14 5 14 -6 1 -7 -8 -41 -25 -75 -37 -54 -19 -61 -19 -56 -5 10 26 43 72 91 126 46 53 77 104 68 114 -6 6 -95 -81 -143 -141 l-30 -38 -7 80 c-4 45 -5 89 -1 98 3 10 31 34 63 53 61 37 147 112 164 144 21 38 -53 8 -126 -52 -98 -80 -100 -81 -92 -46 12 47 54 133 81 166 14 16 25 42 25 56 l-1 27 -25 -30 -26 -30 6 53 c3 28 9 74 12 100 5 40 3 50 -10 55 -10 4 -22 -2 -32 -19z m-79 -654 c0 -125 0 -126 -33 -176 -22 -36 -56 -67 -109 -103 -42 -28 -82 -51 -90 -51 -20 0 -16 22 11 59 13 18 30 46 36 62 7 16 16 29 20 29 5 0 13 33 20 73 16 102 29 149 40 142 6 -4 10 -2 10 3 0 5 13 25 30 43 16 19 30 38 30 42 0 5 8 7 18 5 15 -3 17 -17 17 -128z M2287 5348 c-10 -10 -22 -16 -27 -13 -5 3 -8 -3 -8 -12 1 -10 -2 -37 -6 -59 -6 -32 -4 -43 7 -47 23 -9 67 61 67 105 0 44 -9 51 -33 26z M1853 5256 c4 -22 11 -42 17 -46 7 -4 14 -26 17 -49 3 -22 10 -41 15 -41 5 0 7 12 4 28 -3 15 -8 46 -11 69 -4 23 -16 49 -27 60 -21 18 -21 18 -15 -21z M1780 5267 c0 -47 15 -79 42 -93 l30 -16 -7 34 c-4 18 -12 44 -19 58 -12 28 -46 40 -46 17z M1960 5120 c0 -21 30 -70 49 -80 27 -14 31 -13 31 10 0 11 5 20 10 20 6 0 8 -11 4 -25 -6 -23 -4 -25 30 -25 20 0 36 4 36 8 0 18 -68 72 -109 87 -52 18 -51 18 -51 5z M4127 5076 c-4 -10 -7 -45 -7 -79 0 -42 -6 -70 -18 -88 -56 -85 -73 -107 -106 -138 -20 -19 -36 -39 -36 -43 0 -18 34 -6 62 23 29 28 34 30 84 24 41 -6 59 -3 83 11 37 22 44 37 28 59 -16 21 -72 22 -95 2 -21 -19 -32 -22 -32 -7 0 5 38 35 84 66 77 51 106 84 106 119 0 26 -43 16 -77 -17 l-33 -32 0 47 c0 34 -4 47 -14 47 -8 0 -16 5 -18 12 -3 7 -7 5 -11 -6z M1049 5043 c-8 -10 -9 -14 -2 -10 7 5 28 -18 57 -63 48 -74 62 -86 52 -45 -4 15 -2 25 4 25 15 0 -17 72 -41 93 -27 22 -53 22 -70 0z M3400 4964 c-14 -37 -12 -60 6 -75 14 -11 18 -10 30 6 19 26 18 81 -2 89 -23 9 -24 8 -34 -20z M3910 4933 c-29 -20 -40 -33 -40 -50 0 -33 63 6 75 45 8 26 -2 28 -35 5z M3401 4844 c0 -11 3 -14 6 -6 3 7 2 16 -1 19 -3 4 -6 -2 -5 -13z M4532 4829 c-8 -12 -9 -18 -3 -14 7 4 11 -8 12 -32 1 -21 4 -51 8 -68 6 -26 8 -22 13 29 5 39 3 67 -5 83 l-12 23 -13 -21z M1017 4820 c-8 -30 16 -52 65 -60 41 -6 45 -5 40 12 -5 20 -68 68 -88 68 -6 0 -14 -9 -17 -20z M2529 4778 c-11 -21 -7 -134 7 -185 8 -30 24 -19 24 17 0 16 7 35 15 44 18 17 20 70 4 115 -13 36 -33 40 -50 9z M830 4767 c0 -24 30 -116 40 -122 11 -7 1 92 -12 118 -10 20 -28 23 -28 4z M4660 4751 c0 -5 -9 -12 -19 -16 -23 -7 -101 -81 -101 -95 0 -26 50 -6 98 38 51 47 67 82 37 82 -8 0 -15 -4 -15 -9z M764 4719 c-7 -13 82 -106 92 -96 11 11 -9 43 -46 75 -27 23 -41 29 -46 21z M1887 4634 c-18 -18 -6 -91 21 -131 79 -118 125 -171 138 -159 10 9 8 18 -9 46 -12 19 -25 37 -29 38 -4 2 -8 25 -8 50 0 60 -15 115 -38 135 -20 19 -65 31 -75 21z M1030 4579 c0 -35 54 -169 68 -169 6 0 12 -8 12 -17 1 -17 2 -17 15 0 11 16 11 26 -5 71 -25 75 -47 114 -70 126 -17 9 -20 8 -20 -11z M697 4553 c19 -54 69 -92 112 -85 36 5 46 34 20 58 -11 9 -22 14 -25 11 -4 -4 -18 3 -32 13 -32 26 -84 28 -75 3z M1150 4486 c0 -36 52 -76 101 -76 47 0 57 29 12 32 -16 1 6 4 47 8 l75 6 -75 2 c-41 1 -85 8 -96 15 -12 6 -31 18 -43 25 -19 12 -21 11 -21 -12z M3909 4427 c-16 -27 -19 -51 -19 -149 0 -111 1 -118 20 -118 15 0 24 14 40 68 39 124 39 215 -1 225 -15 4 -25 -2 -40 -26z M4723 4375 c-30 -13 -33 -18 -33 -60 l0 -45 24 15 c27 18 49 48 60 83 9 26 -4 28 -51 7z M5002 4348 c-5 -7 -23 -40 -40 -73 -32 -65 -106 -146 -156 -172 -17 -9 -51 -21 -75 -28 -46 -11 -63 -28 -38 -38 7 -3 47 2 87 10 58 12 85 13 128 4 96 -19 162 -13 162 15 0 11 -19 14 -82 15 -46 0 -91 4 -101 8 -17 6 -17 8 2 25 11 10 44 25 73 32 34 8 43 13 27 13 -31 1 -44 24 -23 41 8 7 14 21 14 31 0 11 10 36 23 57 33 52 39 72 23 72 -7 0 -18 -6 -24 -12z M3632 4290 c-52 -37 -68 -69 -74 -145 -3 -33 -3 -54 0 -47 3 10 7 9 16 -4 12 -15 18 -14 79 15 69 33 101 66 95 98 -4 22 -37 30 -49 11 -6 -8 -7 10 -3 45 8 68 -2 72 -64 27z M5016 4271 c-11 -12 -16 -24 -12 -28 9 -9 39 22 34 37 -2 7 -10 4 -22 -9z M470 4264 c0 -9 8 -28 18 -42 10 -15 22 -33 27 -40 8 -15 -67 31 -102 62 -13 11 -23 14 -23 8 0 -7 -7 -12 -15 -12 -19 0 -19 -15 2 -50 20 -35 48 -48 118 -56 37 -5 55 -11 55 -20 0 -8 11 -14 25 -14 14 0 25 4 25 10 0 5 -22 43 -50 84 -49 73 -80 100 -80 70z M2382 4102 c-5 -9 -12 -42 -14 -72 -9 -96 18 -125 39 -43 17 66 17 120 -2 127 -8 3 -19 -2 -23 -12z M4235 3850 c36 -39 118 -80 162 -80 30 0 93 41 93 61 0 5 -14 15 -30 24 -25 13 -44 14 -107 6 -43 -5 -80 -6 -83 -1 -3 5 -19 12 -35 16 l-30 7 30 -33z M133 3667 c-19 -41 -15 -59 18 -86 30 -24 135 -55 151 -45 11 7 10 42 -2 49 -5 3 -10 11 -10 17 0 6 7 5 17 -3 12 -10 15 -10 9 -1 -13 22 -84 52 -125 52 -33 0 -40 4 -43 22 -3 21 -4 21 -15 -5z M5265 3631 c-16 -10 -43 -33 -60 -51 l-30 -32 83 4 c77 3 86 6 107 30 35 41 24 68 -29 68 -23 0 -54 -8 -71 -19z M400 3512 c0 -5 -53 -12 -117 -16 -64 -4 -120 -9 -125 -12 -16 -10 -8 -53 13 -65 51 -27 183 0 213 43 13 17 19 18 68 9 29 -5 66 -13 81 -16 22 -6 26 -4 21 9 -5 12 0 16 17 17 13 1 -3 7 -36 14 -106 22 -135 26 -135 17z M5090 3480 c0 -5 9 -10 20 -10 11 0 47 -13 80 -30 57 -29 121 -39 147 -22 22 14 19 45 -7 59 -30 15 -240 18 -240 3z M926 3272 c-12 -11 -6 -94 9 -122 16 -31 39 -47 86 -60 24 -7 29 -5 39 21 19 44 5 94 -34 124 -35 27 -90 47 -100 37z M500 3049 c0 -23 9 -62 20 -85 17 -33 30 -46 70 -62 34 -14 56 -32 70 -54 16 -28 109 -108 125 -108 3 0 5 7 5 15 0 12 7 14 28 9 15 -3 -8 11 -50 32 -42 20 -80 44 -83 53 -4 9 -9 46 -12 84 -5 61 -9 70 -41 98 -34 30 -59 43 -107 55 -24 6 -25 4 -25 -37z M5203 2779 c-18 -11 -35 -29 -38 -40 -7 -22 -20 -25 -32 -6 -8 13 -20 -26 -22 -74 -1 -30 25 -36 35 -7 4 15 9 17 20 7 8 -6 14 -18 14 -26 0 -11 7 -9 27 7 43 33 63 71 63 118 0 49 -14 53 -67 21z M5307 2622 c-34 -32 -86 -72 -115 -88 -51 -29 -61 -46 -29 -52 25 -5 198 81 229 114 15 16 30 41 33 57 7 25 5 27 -24 27 -25 0 -45 -13 -94 -58z M447 2652 c-10 -10 -15 -21 -12 -24 7 -7 75 24 75 34 0 15 -47 8 -63 -10z M263 2600 c-12 -5 -26 -18 -32 -28 -8 -15 -6 -24 13 -41 33 -31 84 -27 160 13 68 36 68 47 1 51 -16 1 -50 5 -75 8 -25 4 -55 3 -67 -3z M996 2540 c-37 -11 -102 -74 -115 -112 l-10 -28 58 0 c48 0 65 5 98 29 49 35 87 86 79 106 -6 17 -62 19 -110 5z M673 2324 c-43 -18 -42 -43 1 -88 33 -35 35 -36 114 -36 70 0 80 2 78 18 0 10 6 16 16 16 13 -1 9 8 -18 40 -19 22 -45 46 -57 53 -29 16 -94 15 -134 -3z M4790 2120 c-9 -17 -5 -20 43 -29 72 -15 166 -19 169 -9 2 5 11 6 21 3 20 -8 23 -35 5 -35 -7 -1 -2 -7 12 -15 29 -17 113 -20 141 -5 24 13 25 36 2 48 -10 5 -58 12 -108 15 -49 3 -117 12 -150 20 -110 28 -124 28 -135 7z M4881 2021 c6 -17 30 -50 53 -75 33 -36 49 -46 74 -46 25 0 32 4 32 19 0 25 -60 77 -99 86 -17 4 -36 15 -41 26 -17 30 -30 23 -19 -10z";
|
|
1302
|
+
|
|
1303
|
+
// src/genre-tree/TreeMarkIcon.tsx
|
|
1304
|
+
var import_jsx_runtime23 = require("react/jsx-runtime");
|
|
1305
|
+
function TreeMarkIcon({ className: className2 }) {
|
|
1306
|
+
return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("svg", { viewBox: "0 0 551 567", fill: "currentColor", className: className2, "aria-hidden": true, children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("path", { transform: "translate(0 567) scale(0.1 -0.1)", d: TREE_MARK_PATH }) });
|
|
1307
|
+
}
|
|
1308
|
+
|
|
1309
|
+
// src/genre-tree/GenrePlayActions.tsx
|
|
1310
|
+
var import_jsx_runtime24 = require("react/jsx-runtime");
|
|
1311
|
+
function PlayIcon({ kind }) {
|
|
1312
|
+
return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("span", { "aria-hidden": "true", className: "relative flex items-center justify-center w-5 h-5", children: [
|
|
1313
|
+
kind === "tree" && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(TreeMarkIcon, { className: "absolute -left-1.5 -top-1.5 w-8 h-8 opacity-35" }),
|
|
1314
|
+
kind === "map" && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(RegionGlobeIcon, { className: "absolute -left-1.5 -top-1.5 w-8 h-8 opacity-35" }),
|
|
1315
|
+
kind === "tree-map" && /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(import_jsx_runtime24.Fragment, { children: [
|
|
1316
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)(TreeMarkIcon, { className: "absolute -left-1.5 -top-1.5 w-8 h-8 opacity-35 [clip-path:inset(0_50%_0_0)]" }),
|
|
1317
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)(RegionGlobeIcon, { className: "absolute -left-1.5 -top-1.5 w-8 h-8 opacity-35 [clip-path:inset(0_0_0_50%)]" })
|
|
1296
1318
|
] }),
|
|
1297
|
-
|
|
1298
|
-
"section",
|
|
1299
|
-
{
|
|
1300
|
-
"aria-label": "Admin actions",
|
|
1301
|
-
className: `px-3.5 py-3 ${items.length > 0 ? "border-t border-[var(--color-border)]" : ""}`,
|
|
1302
|
-
children: [
|
|
1303
|
-
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)("h3", { className: "mb-2 text-caption font-semibold uppercase tracking-wide text-[var(--color-text-muted)]", children: "Admin" }),
|
|
1304
|
-
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { className: "flex flex-wrap gap-1", children: renderItems(adminItems) })
|
|
1305
|
-
]
|
|
1306
|
-
}
|
|
1307
|
-
)
|
|
1319
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_lucide_react8.Play, { className: "relative w-5 h-5 fill-[var(--color-surface)]" })
|
|
1308
1320
|
] });
|
|
1309
1321
|
}
|
|
1322
|
+
function playOptions(playlist) {
|
|
1323
|
+
if (!("genreOnlyTracksCount" in playlist)) return [{ key: "all", label: "Play", icon: "play", count: playlist.tracksCount }];
|
|
1324
|
+
const direct = { key: "direct", label: "Genre", icon: "play", selection: { coverage: "genreOnly" }, count: (0, import_genre_tree10.genreMusicCount)(playlist, { coverage: "genreOnly" }) };
|
|
1325
|
+
const scopes = playlist.genreAndSubgenresTracksCount;
|
|
1326
|
+
const inclusive = (label, icon, subgenres) => {
|
|
1327
|
+
const selection = { coverage: "genreAndSubgenres", subgenres };
|
|
1328
|
+
return { key: subgenres, label, icon, selection, count: (0, import_genre_tree10.genreMusicCount)(playlist, selection) };
|
|
1329
|
+
};
|
|
1330
|
+
return "canonical" in scopes ? [direct, inclusive("Canonical", "tree", "canonical"), inclusive("Regional", "map", "regional"), inclusive("All", "tree-map", "all")] : [direct, inclusive("All", "map", "all")];
|
|
1331
|
+
}
|
|
1332
|
+
function GenrePlayActions({ genrePlaylist, playback }) {
|
|
1333
|
+
const { isPlaying, setIsPlaying } = (0, import_player4.usePlayer)();
|
|
1334
|
+
const options = playOptions(genrePlaylist);
|
|
1335
|
+
return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_jsx_runtime24.Fragment, { children: options.map((option) => {
|
|
1336
|
+
const isCurrent = playback.playing?.uuid === genrePlaylist.uuid && (option.selection === void 0 || playback.playing.selectionKey === "" || playback.playing.selectionKey === (0, import_genre_tree10.genreMusicSelectionKey)(option.selection).join());
|
|
1337
|
+
const playing = isCurrent && isPlaying;
|
|
1338
|
+
return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
1339
|
+
import_ui7.ActionButton,
|
|
1340
|
+
{
|
|
1341
|
+
icon: playing ? /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_lucide_react8.Pause, { "aria-hidden": "true", className: "w-5 h-5" }) : /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(PlayIcon, { kind: option.icon }),
|
|
1342
|
+
label: playing ? "Pause" : option.label,
|
|
1343
|
+
caption: String(option.count),
|
|
1344
|
+
disabled: option.count === 0,
|
|
1345
|
+
title: option.count === 0 ? "No playable songs" : void 0,
|
|
1346
|
+
onClick: () => {
|
|
1347
|
+
if (isCurrent) {
|
|
1348
|
+
setIsPlaying(!isPlaying);
|
|
1349
|
+
return;
|
|
1350
|
+
}
|
|
1351
|
+
void playback.play(genrePlaylist, option.selection);
|
|
1352
|
+
}
|
|
1353
|
+
},
|
|
1354
|
+
option.key
|
|
1355
|
+
);
|
|
1356
|
+
}) });
|
|
1357
|
+
}
|
|
1310
1358
|
|
|
1311
1359
|
// src/genre-tree/GenreDetailExtras.tsx
|
|
1312
|
-
var
|
|
1313
|
-
var
|
|
1360
|
+
var import_ui9 = require("@behindthemusictree/ui");
|
|
1361
|
+
var import_genre_tree18 = require("@behindthemusictree/app-kit/genre-tree");
|
|
1314
1362
|
|
|
1315
1363
|
// src/genre-tree/ClampedText.tsx
|
|
1316
|
-
var
|
|
1317
|
-
var
|
|
1364
|
+
var import_react12 = require("react");
|
|
1365
|
+
var import_jsx_runtime25 = require("react/jsx-runtime");
|
|
1318
1366
|
function ClampedText({ children, className: className2 = "" }) {
|
|
1319
|
-
const ref = (0,
|
|
1320
|
-
const [expanded, setExpanded] = (0,
|
|
1321
|
-
const [overflows, setOverflows] = (0,
|
|
1322
|
-
(0,
|
|
1367
|
+
const ref = (0, import_react12.useRef)(null);
|
|
1368
|
+
const [expanded, setExpanded] = (0, import_react12.useState)(false);
|
|
1369
|
+
const [overflows, setOverflows] = (0, import_react12.useState)(false);
|
|
1370
|
+
(0, import_react12.useLayoutEffect)(() => {
|
|
1323
1371
|
const element = ref.current;
|
|
1324
1372
|
if (!element || expanded) return;
|
|
1325
1373
|
setOverflows(element.scrollHeight > element.clientHeight);
|
|
1326
1374
|
}, [children, expanded]);
|
|
1327
|
-
return /* @__PURE__ */ (0,
|
|
1328
|
-
/* @__PURE__ */ (0,
|
|
1329
|
-
(overflows || expanded) && /* @__PURE__ */ (0,
|
|
1375
|
+
return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(import_jsx_runtime25.Fragment, { children: [
|
|
1376
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)("p", { ref, className: `${className2} ${expanded ? "" : "line-clamp-3"}`, children }),
|
|
1377
|
+
(overflows || expanded) && /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
|
|
1330
1378
|
"button",
|
|
1331
1379
|
{
|
|
1332
1380
|
type: "button",
|
|
@@ -1340,36 +1388,36 @@ function ClampedText({ children, className: className2 = "" }) {
|
|
|
1340
1388
|
}
|
|
1341
1389
|
|
|
1342
1390
|
// src/genre-tree/GenrePlaylistTracks.tsx
|
|
1343
|
-
var
|
|
1391
|
+
var import_react13 = require("react");
|
|
1344
1392
|
var import_react_query = require("@tanstack/react-query");
|
|
1345
1393
|
var import_zod = require("zod");
|
|
1346
1394
|
var import_fa2 = require("react-icons/fa");
|
|
1347
|
-
var
|
|
1395
|
+
var import_ui8 = require("@behindthemusictree/ui");
|
|
1348
1396
|
var import_auth = require("@behindthemusictree/app-kit/auth");
|
|
1397
|
+
var import_transport2 = require("@behindthemusictree/app-kit/transport");
|
|
1349
1398
|
var import_transport3 = require("@behindthemusictree/app-kit/transport");
|
|
1350
1399
|
var import_transport4 = require("@behindthemusictree/app-kit/transport");
|
|
1351
|
-
var import_transport5 = require("@behindthemusictree/app-kit/transport");
|
|
1352
|
-
var import_player4 = require("@behindthemusictree/app-kit/player");
|
|
1353
1400
|
var import_player5 = require("@behindthemusictree/app-kit/player");
|
|
1354
|
-
var
|
|
1355
|
-
var
|
|
1356
|
-
var
|
|
1401
|
+
var import_player6 = require("@behindthemusictree/app-kit/player");
|
|
1402
|
+
var import_popup3 = require("@behindthemusictree/app-kit/popup");
|
|
1403
|
+
var import_transport5 = require("@behindthemusictree/app-kit/transport");
|
|
1357
1404
|
var import_genre_tree12 = require("@behindthemusictree/app-kit/genre-tree");
|
|
1358
1405
|
var import_genre_tree13 = require("@behindthemusictree/app-kit/genre-tree");
|
|
1359
1406
|
var import_genre_tree14 = require("@behindthemusictree/app-kit/genre-tree");
|
|
1360
1407
|
var import_genre_tree15 = require("@behindthemusictree/app-kit/genre-tree");
|
|
1408
|
+
var import_genre_tree16 = require("@behindthemusictree/app-kit/genre-tree");
|
|
1361
1409
|
|
|
1362
1410
|
// src/genre-tree/MusicBrainzRecordingLink.tsx
|
|
1363
|
-
var
|
|
1364
|
-
var
|
|
1411
|
+
var import_genre_tree11 = require("@behindthemusictree/app-kit/genre-tree");
|
|
1412
|
+
var import_jsx_runtime26 = require("react/jsx-runtime");
|
|
1365
1413
|
function MusicBrainzRecordingLink({
|
|
1366
1414
|
song,
|
|
1367
1415
|
children,
|
|
1368
1416
|
className: className2 = ""
|
|
1369
1417
|
}) {
|
|
1370
|
-
const url = (0,
|
|
1371
|
-
if (!url) return /* @__PURE__ */ (0,
|
|
1372
|
-
return /* @__PURE__ */ (0,
|
|
1418
|
+
const url = (0, import_genre_tree11.musicBrainzRecordingUrl)(song);
|
|
1419
|
+
if (!url) return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(import_jsx_runtime26.Fragment, { children });
|
|
1420
|
+
return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
|
|
1373
1421
|
"a",
|
|
1374
1422
|
{
|
|
1375
1423
|
href: url,
|
|
@@ -1384,11 +1432,11 @@ function MusicBrainzRecordingLink({
|
|
|
1384
1432
|
}
|
|
1385
1433
|
|
|
1386
1434
|
// src/genre-tree/GenrePlaylistTracks.tsx
|
|
1387
|
-
var
|
|
1435
|
+
var import_genre_tree17 = require("@behindthemusictree/app-kit/genre-tree");
|
|
1388
1436
|
var import_track_noun = require("@behindthemusictree/app-kit/track-noun");
|
|
1389
|
-
var
|
|
1437
|
+
var import_jsx_runtime27 = require("react/jsx-runtime");
|
|
1390
1438
|
var CATALOGUE_PAGE_SIZE = 100;
|
|
1391
|
-
var SongPageSchema = (0,
|
|
1439
|
+
var SongPageSchema = (0, import_transport3.PaginatedResponseSchema)(import_genre_tree15.SongDetailedSchema).extend({
|
|
1392
1440
|
overallTotal: import_zod.z.number().nullable(),
|
|
1393
1441
|
page: import_zod.z.number().nullable(),
|
|
1394
1442
|
totalPages: import_zod.z.number().nullable()
|
|
@@ -1417,30 +1465,30 @@ function GenrePlaylistTracks({
|
|
|
1417
1465
|
renderTracksToolbar,
|
|
1418
1466
|
artist = null
|
|
1419
1467
|
}) {
|
|
1420
|
-
const { fetchGenrePlaylistTracksPage, playNewTrackListFromGenrePlaylist, playNewTrackListFromArtist, playNewTrackListFromGenreCatalogue } = (0,
|
|
1468
|
+
const { fetchGenrePlaylistTracksPage, playNewTrackListFromGenrePlaylist, playNewTrackListFromArtist, playNewTrackListFromGenreCatalogue } = (0, import_genre_tree16.useTrackList)();
|
|
1421
1469
|
const { session, sessionRestored } = (0, import_auth.useSession)();
|
|
1422
|
-
const { playerTrackObject, playState, handlePlayPauseAction } = (0,
|
|
1423
|
-
const { showPopup } = (0,
|
|
1470
|
+
const { playerTrackObject, playState, handlePlayPauseAction } = (0, import_player5.usePlayer)();
|
|
1471
|
+
const { showPopup } = (0, import_popup3.usePopup)();
|
|
1424
1472
|
const trackNoun = (0, import_track_noun.useTrackNoun)();
|
|
1425
1473
|
const uuid = genrePlaylist?.uuid;
|
|
1426
1474
|
const genreName = selectedGenreName ?? genrePlaylist?.name ?? "Genre";
|
|
1427
|
-
const { fetchBound } = (0,
|
|
1428
|
-
const playback = (0,
|
|
1475
|
+
const { fetchBound } = (0, import_transport2.usePlaybackFetch)(getBackendBaseUrl);
|
|
1476
|
+
const playback = (0, import_transport2.usePlaybackContext)();
|
|
1429
1477
|
const { data, isPending, isError, refetch, hasNextPage, isFetchingNextPage, fetchNextPage } = (0, import_react_query.useInfiniteQuery)({
|
|
1430
|
-
queryKey: [...scope === "me" ? uuid ?
|
|
1478
|
+
queryKey: [...scope === "me" ? uuid ? import_genre_tree13.genrePlaylistQueryKeys.me.tracks(uuid) : ["missing-personal-genre-playlist", genreUuid] : artist ? [...import_genre_tree14.libraryQueryKeys.reference.songs.byGenre(getBackendBaseUrl(), genreUuid, selection), "artist", artist.uuid] : import_genre_tree14.libraryQueryKeys.reference.songs.byGenre(getBackendBaseUrl(), genreUuid, selection), ...playback.key ? [playback.key] : []],
|
|
1431
1479
|
queryFn: async ({ pageParam }) => {
|
|
1432
1480
|
if (scope === "me") {
|
|
1433
1481
|
if (!uuid) throw new Error("Personal genre has no playlist");
|
|
1434
1482
|
return fetchGenrePlaylistTracksPage(uuid, scope, Number(pageParam));
|
|
1435
1483
|
}
|
|
1436
1484
|
const response = await fetchBound(
|
|
1437
|
-
|
|
1485
|
+
import_genre_tree14.libraryEndpoints.reference.songs.list(),
|
|
1438
1486
|
true,
|
|
1439
1487
|
false,
|
|
1440
1488
|
{},
|
|
1441
|
-
{ genre: genreUuid, ...(0,
|
|
1489
|
+
{ genre: genreUuid, ...(0, import_genre_tree12.genreMusicQueryParams)(selection), ...artist && { artist: artist.uuid }, pageSize: CATALOGUE_PAGE_SIZE, withTotal: false, ...pageParam && { cursor: pageParam } }
|
|
1442
1490
|
);
|
|
1443
|
-
const parsed = (0,
|
|
1491
|
+
const parsed = (0, import_transport4.parseWithLog)(SongPageSchema, response, "GenrePlaylistTracks");
|
|
1444
1492
|
return { tracks: parsed.results, total: parsed.overallTotal, nextPage: parsed.next ? nextCursor(parsed.next) : null };
|
|
1445
1493
|
},
|
|
1446
1494
|
initialPageParam: scope === "me" ? 1 : "",
|
|
@@ -1449,8 +1497,8 @@ function GenrePlaylistTracks({
|
|
|
1449
1497
|
retry: (failureCount, error) => failureCount < 1 && error instanceof DOMException && error.name === "AbortError",
|
|
1450
1498
|
retryDelay: 0
|
|
1451
1499
|
});
|
|
1452
|
-
const [sentinel, setSentinel] = (0,
|
|
1453
|
-
(0,
|
|
1500
|
+
const [sentinel, setSentinel] = (0, import_react13.useState)(null);
|
|
1501
|
+
(0, import_react13.useEffect)(() => {
|
|
1454
1502
|
if (!hasNextPage || isFetchingNextPage || !sentinel) return;
|
|
1455
1503
|
const observer = new IntersectionObserver((entries) => {
|
|
1456
1504
|
if (entries.some((entry) => entry.isIntersecting)) {
|
|
@@ -1472,35 +1520,36 @@ function GenrePlaylistTracks({
|
|
|
1472
1520
|
}) : scope === "reference" ? playNewTrackListFromGenreCatalogue({ uuid: genreUuid, name: genreName }, scope, { startSongUuid, ...selection && { selection } }) : genrePlaylist ? playNewTrackListFromGenrePlaylist(genrePlaylist, scope, { startSongUuid }) : Promise.reject(new Error("Personal genre has no playlist"));
|
|
1473
1521
|
started.catch((error) => {
|
|
1474
1522
|
console.error("Failed to play genre playlist:", error);
|
|
1475
|
-
|
|
1523
|
+
if (error instanceof import_genre_tree16.TracksFailureAlreadyReportedError) return;
|
|
1524
|
+
showPopup(/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(InternalErrorPopup, { errorCode: error instanceof import_transport5.AppError ? error.code : import_transport5.ErrorCode.CLIENT_UNKNOWN }));
|
|
1476
1525
|
});
|
|
1477
1526
|
};
|
|
1478
|
-
return /* @__PURE__ */ (0,
|
|
1527
|
+
return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_ui8.PanelSection, { title: `${(0, import_track_noun.capitalize)(trackNoun.plural)}${total !== void 0 ? ` (${total})` : ""}`, children: /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { children: [
|
|
1479
1528
|
renderTracksToolbar?.(),
|
|
1480
|
-
scope === "me" && !genrePlaylist ? /* @__PURE__ */ (0,
|
|
1529
|
+
scope === "me" && !genrePlaylist ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("p", { children: "\u2014" }) : isPending ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_ui8.Skeleton, { className: "h-4 w-3/4", "aria-busy": "true" }) : isError && tracks.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("p", { role: "alert", children: [
|
|
1481
1530
|
"Couldn't load ",
|
|
1482
1531
|
trackNoun.plural,
|
|
1483
1532
|
".",
|
|
1484
1533
|
" ",
|
|
1485
|
-
/* @__PURE__ */ (0,
|
|
1486
|
-
] }) : tracks.length === 0 ? /* @__PURE__ */ (0,
|
|
1534
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)("button", { type: "button", className: "underline", onClick: () => void refetch(), children: "Retry" })
|
|
1535
|
+
] }) : tracks.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("p", { children: "\u2014" }) : /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("ul", { className: "mt-1 max-h-64 overflow-y-auto text-body [container-type:inline-size]", "aria-label": `${genreName} ${trackNoun.plural}`, children: [
|
|
1487
1536
|
tracks.map((track, index) => {
|
|
1488
1537
|
const label = track.artists?.length ? `${track.title} \u2014 ${track.artists.map((artist2) => artist2.name).join(", ")}` : track.title;
|
|
1489
1538
|
const isCurrent = playerTrackObject?.track.id === track.uuid;
|
|
1490
|
-
const isPlaying = isCurrent && playState ===
|
|
1491
|
-
const text = /* @__PURE__ */ (0,
|
|
1492
|
-
/* @__PURE__ */ (0,
|
|
1493
|
-
track.artists?.length ? /* @__PURE__ */ (0,
|
|
1494
|
-
/* @__PURE__ */ (0,
|
|
1495
|
-
track.album && /* @__PURE__ */ (0,
|
|
1539
|
+
const isPlaying = isCurrent && playState === import_player6.PlayStates.PLAYING;
|
|
1540
|
+
const text = /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("span", { className: TEXT_CELL, children: [
|
|
1541
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { className: TITLE_CELL, children: renderSongLink ? renderSongLink(track) : (0, import_genre_tree15.isSong)(track) ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(MusicBrainzRecordingLink, { song: track, className: "hover:underline focus-visible:underline", children: track.title }) : track.title }),
|
|
1542
|
+
track.artists?.length ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { className: SEPARATOR, children: " \u2014 " }) : null,
|
|
1543
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { className: COLUMN_CELL, children: track.artists?.length ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_genre_tree17.ArtistNames, { artists: track.artists, renderArtistLink }) : null }),
|
|
1544
|
+
track.album && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { className: ALBUM_CELL, children: track.album.name })
|
|
1496
1545
|
] });
|
|
1497
1546
|
const leading = renderSongLeading?.(track, index);
|
|
1498
1547
|
const actions = renderSongActions?.(track);
|
|
1499
|
-
const isUnplayable = (0,
|
|
1548
|
+
const isUnplayable = (0, import_genre_tree15.isSong)(track) && (0, import_genre_tree15.songUnplayableReason)(track) !== null;
|
|
1500
1549
|
if (isUnplayable) {
|
|
1501
|
-
return /* @__PURE__ */ (0,
|
|
1550
|
+
return /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("li", { className: "flex min-h-8 items-center gap-1 px-1 opacity-50", children: [
|
|
1502
1551
|
leading,
|
|
1503
|
-
/* @__PURE__ */ (0,
|
|
1552
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
|
|
1504
1553
|
"button",
|
|
1505
1554
|
{
|
|
1506
1555
|
type: "button",
|
|
@@ -1508,27 +1557,27 @@ function GenrePlaylistTracks({
|
|
|
1508
1557
|
"aria-disabled": "true",
|
|
1509
1558
|
"aria-label": label,
|
|
1510
1559
|
className: "flex h-6 w-6 shrink-0 items-center justify-center rounded-full opacity-0 cursor-not-allowed",
|
|
1511
|
-
children: /* @__PURE__ */ (0,
|
|
1560
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_fa2.FaPlay, { size: 10 })
|
|
1512
1561
|
}
|
|
1513
1562
|
),
|
|
1514
1563
|
text,
|
|
1515
1564
|
actions
|
|
1516
1565
|
] }, track.uuid);
|
|
1517
1566
|
}
|
|
1518
|
-
return /* @__PURE__ */ (0,
|
|
1567
|
+
return /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(
|
|
1519
1568
|
"li",
|
|
1520
1569
|
{
|
|
1521
1570
|
className: `group flex min-h-8 items-center gap-1 rounded px-1 hover:bg-[var(--color-neutral-100)] ${isCurrent ? "font-medium text-[var(--color-primary)]" : ""}`,
|
|
1522
1571
|
children: [
|
|
1523
1572
|
leading,
|
|
1524
|
-
/* @__PURE__ */ (0,
|
|
1573
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
|
|
1525
1574
|
"button",
|
|
1526
1575
|
{
|
|
1527
1576
|
type: "button",
|
|
1528
1577
|
"aria-label": `${isPlaying ? "Pause" : "Play"} ${label}`,
|
|
1529
|
-
className: `flex h-6 w-6 shrink-0 items-center justify-center rounded-full cursor-pointer group-hover:opacity-100 focus-visible:opacity-100 ${isCurrent && playState !==
|
|
1578
|
+
className: `flex h-6 w-6 shrink-0 items-center justify-center rounded-full cursor-pointer group-hover:opacity-100 focus-visible:opacity-100 ${isCurrent && playState !== import_player6.PlayStates.STOPPED ? "opacity-100" : "opacity-0 [@media(pointer:coarse)]:opacity-100"}`,
|
|
1530
1579
|
onClick: () => isCurrent ? handlePlayPauseAction() : play(track.uuid),
|
|
1531
|
-
children: isCurrent && playState ===
|
|
1580
|
+
children: isCurrent && playState === import_player6.PlayStates.LOADING ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_ui8.RingLoader, { size: 10 }) : isPlaying ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_fa2.FaPause, { size: 10 }) : /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_fa2.FaPlay, { size: 10 })
|
|
1532
1581
|
}
|
|
1533
1582
|
),
|
|
1534
1583
|
text,
|
|
@@ -1538,7 +1587,7 @@ function GenrePlaylistTracks({
|
|
|
1538
1587
|
track.uuid
|
|
1539
1588
|
);
|
|
1540
1589
|
}),
|
|
1541
|
-
hasNextPage && /* @__PURE__ */ (0,
|
|
1590
|
+
hasNextPage && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("li", { ref: setSentinel, "aria-hidden": "true", className: "h-4" })
|
|
1542
1591
|
] })
|
|
1543
1592
|
] }) });
|
|
1544
1593
|
}
|
|
@@ -1546,7 +1595,7 @@ function GenrePlaylistTracks({
|
|
|
1546
1595
|
// src/genre-tree/GenreDetailExtras.tsx
|
|
1547
1596
|
var import_track_noun2 = require("@behindthemusictree/app-kit/track-noun");
|
|
1548
1597
|
var import_si2 = require("react-icons/si");
|
|
1549
|
-
var
|
|
1598
|
+
var import_jsx_runtime28 = require("react/jsx-runtime");
|
|
1550
1599
|
function GenreDetailExtras({
|
|
1551
1600
|
genreUuid,
|
|
1552
1601
|
genrePlaylist,
|
|
@@ -1565,24 +1614,24 @@ function GenreDetailExtras({
|
|
|
1565
1614
|
...trackSlots
|
|
1566
1615
|
}) {
|
|
1567
1616
|
const trackNoun = (0, import_track_noun2.useTrackNoun)();
|
|
1568
|
-
const { data: overview, isPending } = (0,
|
|
1617
|
+
const { data: overview, isPending } = (0, import_genre_tree18.useFetchGenreOverview)(
|
|
1569
1618
|
genreUuid,
|
|
1570
1619
|
scope,
|
|
1571
1620
|
getBackendBaseUrl,
|
|
1572
1621
|
criteriaOverviewSchema
|
|
1573
1622
|
);
|
|
1574
1623
|
if (isPending) {
|
|
1575
|
-
return /* @__PURE__ */ (0,
|
|
1576
|
-
/* @__PURE__ */ (0,
|
|
1624
|
+
return /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(import_jsx_runtime28.Fragment, { children: [
|
|
1625
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_ui9.PanelSection, { title: "Summary", children: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("div", { "aria-busy": "true", "data-testid": "genre-detail-extras-skeleton", children: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_ui9.Skeleton, { className: "h-4 w-3/4" }) }) }),
|
|
1577
1626
|
family
|
|
1578
1627
|
] });
|
|
1579
1628
|
}
|
|
1580
|
-
if (!overview) return /* @__PURE__ */ (0,
|
|
1629
|
+
if (!overview) return /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_jsx_runtime28.Fragment, { children: family });
|
|
1581
1630
|
const { summary, summarySourceUrl, essentialSongs } = overview;
|
|
1582
1631
|
const wikidataUrl = wikidataId ? `https://www.wikidata.org/wiki/${encodeURIComponent(wikidataId)}` : null;
|
|
1583
|
-
return /* @__PURE__ */ (0,
|
|
1584
|
-
(summarySourceUrl || wikidataUrl) && /* @__PURE__ */ (0,
|
|
1585
|
-
summarySourceUrl && /* @__PURE__ */ (0,
|
|
1632
|
+
return /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(import_jsx_runtime28.Fragment, { children: [
|
|
1633
|
+
(summarySourceUrl || wikidataUrl) && /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_ui9.PanelSection, { title: "Links", children: /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("div", { className: "flex flex-wrap gap-x-3 gap-y-1 text-caption text-[var(--color-text)]", children: [
|
|
1634
|
+
summarySourceUrl && /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(
|
|
1586
1635
|
"a",
|
|
1587
1636
|
{
|
|
1588
1637
|
href: summarySourceUrl,
|
|
@@ -1590,12 +1639,12 @@ function GenreDetailExtras({
|
|
|
1590
1639
|
rel: "noopener noreferrer",
|
|
1591
1640
|
className: "inline-flex items-center gap-1.5 text-[var(--color-text-muted)] hover:text-[var(--color-text)]",
|
|
1592
1641
|
children: [
|
|
1593
|
-
/* @__PURE__ */ (0,
|
|
1642
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_si2.SiWikipedia, { "aria-hidden": "true", className: "h-3.5 w-3.5" }),
|
|
1594
1643
|
"Wikipedia"
|
|
1595
1644
|
]
|
|
1596
1645
|
}
|
|
1597
1646
|
),
|
|
1598
|
-
wikidataUrl && /* @__PURE__ */ (0,
|
|
1647
|
+
wikidataUrl && /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(
|
|
1599
1648
|
"a",
|
|
1600
1649
|
{
|
|
1601
1650
|
href: wikidataUrl,
|
|
@@ -1603,17 +1652,17 @@ function GenreDetailExtras({
|
|
|
1603
1652
|
rel: "noopener noreferrer",
|
|
1604
1653
|
className: "inline-flex items-center gap-1.5 text-[var(--color-text-muted)] hover:text-[var(--color-text)]",
|
|
1605
1654
|
children: [
|
|
1606
|
-
/* @__PURE__ */ (0,
|
|
1655
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_si2.SiWikidata, { "aria-hidden": "true", className: "h-3.5 w-3.5" }),
|
|
1607
1656
|
"Wikidata"
|
|
1608
1657
|
]
|
|
1609
1658
|
}
|
|
1610
1659
|
)
|
|
1611
1660
|
] }) }),
|
|
1612
|
-
/* @__PURE__ */ (0,
|
|
1661
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_ui9.PanelSection, { title: "Summary", children: renderSummary ? renderSummary(overview) : /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(ClampedText, { className: "text-body text-[var(--color-text)]", children: summary ?? "\u2014" }, genreUuid) }),
|
|
1613
1662
|
family,
|
|
1614
1663
|
renderGenreDetailExtras?.(overview),
|
|
1615
|
-
(renderEssentialTracks || essentialSongs) && /* @__PURE__ */ (0,
|
|
1616
|
-
/* @__PURE__ */ (0,
|
|
1664
|
+
(renderEssentialTracks || essentialSongs) && /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_ui9.PanelSection, { title: `Essential ${trackNoun.plural}`, children: renderEssentialTracks ? renderEssentialTracks(overview) : essentialSongs && essentialSongs.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("ul", { className: "text-body text-[var(--color-text)]", children: essentialSongs.map((track) => /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("li", { className: "py-1", children: track.title }, track.uuid)) }) : /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("p", { className: "text-body text-[var(--color-text)]", children: "\u2014" }) }),
|
|
1665
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
|
|
1617
1666
|
GenrePlaylistTracks,
|
|
1618
1667
|
{
|
|
1619
1668
|
genreUuid,
|
|
@@ -1631,28 +1680,10 @@ function GenreDetailExtras({
|
|
|
1631
1680
|
}
|
|
1632
1681
|
|
|
1633
1682
|
// src/genre-tree/GenreInfoPanelBody.tsx
|
|
1634
|
-
var
|
|
1635
|
-
var
|
|
1683
|
+
var import_jsx_runtime29 = require("react/jsx-runtime");
|
|
1684
|
+
var import_react14 = require("react");
|
|
1636
1685
|
function GenreNodeActionBand({ genrePlaylist, playback, ...bandProps }) {
|
|
1637
|
-
|
|
1638
|
-
const isCurrentTrackList = playback.playingNodeId === genrePlaylist.uuid;
|
|
1639
|
-
const handlePlayPause = () => {
|
|
1640
|
-
if (isCurrentTrackList) {
|
|
1641
|
-
setIsPlaying(!isPlaying);
|
|
1642
|
-
return;
|
|
1643
|
-
}
|
|
1644
|
-
playback.play(genrePlaylist).catch((error) => {
|
|
1645
|
-
console.error("Failed to load genre playlist tracks:", error);
|
|
1646
|
-
});
|
|
1647
|
-
};
|
|
1648
|
-
return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
|
|
1649
|
-
GenreActionBand,
|
|
1650
|
-
{
|
|
1651
|
-
...bandProps,
|
|
1652
|
-
onPlayPause: ("genreOnlyTracksCount" in genrePlaylist ? (0, import_genre_tree18.genreMusicCount)(genrePlaylist) : genrePlaylist.tracksCount) > 0 ? handlePlayPause : void 0,
|
|
1653
|
-
isPlaying: isCurrentTrackList && isPlaying
|
|
1654
|
-
}
|
|
1655
|
-
);
|
|
1686
|
+
return /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(GenreActionBand, { ...bandProps, playActions: /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(GenrePlayActions, { genrePlaylist, playback }) });
|
|
1656
1687
|
}
|
|
1657
1688
|
function GenreInfoPanelBody({
|
|
1658
1689
|
toolbar,
|
|
@@ -1660,7 +1691,6 @@ function GenreInfoPanelBody({
|
|
|
1660
1691
|
genreUuid,
|
|
1661
1692
|
genrePlaylist,
|
|
1662
1693
|
catalogue,
|
|
1663
|
-
countsContext,
|
|
1664
1694
|
wikidataId,
|
|
1665
1695
|
scope,
|
|
1666
1696
|
getBackendBaseUrl,
|
|
@@ -1668,33 +1698,12 @@ function GenreInfoPanelBody({
|
|
|
1668
1698
|
band,
|
|
1669
1699
|
extras
|
|
1670
1700
|
}) {
|
|
1671
|
-
const
|
|
1672
|
-
const
|
|
1673
|
-
|
|
1674
|
-
const describeCounts = (counts) => {
|
|
1675
|
-
const scopes = counts.genreAndSubgenresTracksCount;
|
|
1676
|
-
return "canonical" in scopes ? `${counts.genreOnlyTracksCount} this genre only \xB7 ${scopes.canonical} with canonical subgenres \xB7 ${scopes.regional} with regional subgenres \xB7 ${scopes.all} with all subgenres` : `${counts.genreOnlyTracksCount} this genre only \xB7 ${scopes.all} with subgenres`;
|
|
1677
|
-
};
|
|
1678
|
-
return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(import_jsx_runtime25.Fragment, { children: [
|
|
1701
|
+
const summary = scope === "reference" ? import_genre_tree19.GenreCatalogueCountsSchema.parse(genrePlaylist ?? catalogue) : void 0;
|
|
1702
|
+
const selection = summary ? (0, import_genre_tree19.defaultGenreMusicSelection)(summary) : void 0;
|
|
1703
|
+
return /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(import_jsx_runtime29.Fragment, { children: [
|
|
1679
1704
|
toolbar,
|
|
1680
|
-
genrePlaylist ? /* @__PURE__ */ (0,
|
|
1681
|
-
|
|
1682
|
-
/* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("p", { children: [
|
|
1683
|
-
"Catalogue ",
|
|
1684
|
-
noun.plural,
|
|
1685
|
-
countsContext ? ` (${countsContext})` : "",
|
|
1686
|
-
": ",
|
|
1687
|
-
describeCounts(catalogue)
|
|
1688
|
-
] }),
|
|
1689
|
-
genrePlaylist && /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("p", { children: [
|
|
1690
|
-
"Playlist ",
|
|
1691
|
-
noun.plural,
|
|
1692
|
-
countsContext ? ` (${countsContext})` : "",
|
|
1693
|
-
": ",
|
|
1694
|
-
describeCounts(summary)
|
|
1695
|
-
] })
|
|
1696
|
-
] }),
|
|
1697
|
-
/* @__PURE__ */ (0, import_react13.createElement)(
|
|
1705
|
+
genrePlaylist ? /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(GenreNodeActionBand, { ...band, genrePlaylist, playback }) : /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(GenreActionBand, { ...band }),
|
|
1706
|
+
/* @__PURE__ */ (0, import_react14.createElement)(
|
|
1698
1707
|
GenreDetailExtras,
|
|
1699
1708
|
{
|
|
1700
1709
|
...extras,
|
|
@@ -1713,7 +1722,7 @@ function GenreInfoPanelBody({
|
|
|
1713
1722
|
}
|
|
1714
1723
|
|
|
1715
1724
|
// src/genre-tree/GenreDetailPanel.tsx
|
|
1716
|
-
var
|
|
1725
|
+
var import_jsx_runtime30 = require("react/jsx-runtime");
|
|
1717
1726
|
var RELATIVE_ITEM_COUNT = 1;
|
|
1718
1727
|
function toNode(genre, parentId) {
|
|
1719
1728
|
return {
|
|
@@ -1735,80 +1744,88 @@ function useGenreDetailContent({
|
|
|
1735
1744
|
playback: hostPlayback,
|
|
1736
1745
|
trailing,
|
|
1737
1746
|
genrePlaylist: hostPlaylist,
|
|
1738
|
-
expanded
|
|
1747
|
+
expanded,
|
|
1748
|
+
treeRelations
|
|
1739
1749
|
}) {
|
|
1740
|
-
const { data: detail, isPending, isError } = (0,
|
|
1750
|
+
const { data: detail, isPending, isError } = (0, import_genre_tree20.useFetchGenreDetail)(genreUuid, scope, getBackendBaseUrl);
|
|
1741
1751
|
const defaultPlayback = useGenrePlaylistPlayback({ scope, genrePlaylists: [], artist: extras?.artist });
|
|
1742
1752
|
const playback = hostPlayback ?? defaultPlayback;
|
|
1743
|
-
const view = (0,
|
|
1753
|
+
const view = (0, import_react15.useMemo)(() => {
|
|
1744
1754
|
if (!detail) return null;
|
|
1745
1755
|
const rootColor = (0, import_genre_tree_view4.getGenreTreeColor)(detail.root.wikidataId);
|
|
1756
|
+
const treeStyles = /* @__PURE__ */ new Map();
|
|
1757
|
+
if (treeRelations) {
|
|
1758
|
+
const drawn = [treeRelations, treeRelations.parentNode, ...treeRelations.childNodes, ...treeRelations.ancestorNodes];
|
|
1759
|
+
for (const entry of drawn) {
|
|
1760
|
+
if (entry) treeStyles.set(entry.node.id, { fill: entry.fill, textColor: entry.textColor });
|
|
1761
|
+
}
|
|
1762
|
+
}
|
|
1746
1763
|
const relative = (genre, parentId) => ({
|
|
1747
1764
|
node: toNode(genre, parentId),
|
|
1748
|
-
fill: (0, import_genre_tree_view4.tintSurface)(rootColor),
|
|
1749
|
-
textColor: import_genre_tree_view4.TEXT_COLOR
|
|
1765
|
+
...treeStyles.get(genre.uuid) ?? { fill: (0, import_genre_tree_view4.tintSurface)(rootColor), textColor: import_genre_tree_view4.TEXT_COLOR }
|
|
1750
1766
|
});
|
|
1751
1767
|
const ancestors2 = [...detail.ascendants].sort((a, b) => b.degree - a.degree);
|
|
1768
|
+
const own = treeStyles.get(detail.uuid) ?? { fill: rootColor, textColor: (0, import_genre_tree_view4.getTextColorOnFill)(rootColor) };
|
|
1752
1769
|
return {
|
|
1753
1770
|
node: {
|
|
1754
1771
|
id: detail.uuid,
|
|
1755
1772
|
parentId: detail.parent?.uuid ?? null,
|
|
1756
1773
|
name: detail.name,
|
|
1757
|
-
itemCount: scope === "reference" ? (0,
|
|
1774
|
+
itemCount: scope === "reference" ? (0, import_genre_tree20.genreMusicCount)(detail.criteriaPlaylist ? import_genre_tree20.GenrePlaylistSummarySchema.parse(detail.criteriaPlaylist) : import_genre_tree20.GenreCatalogueCountsSchema.parse(detail.catalogue)) : detail.tracksCount,
|
|
1758
1775
|
wikidataId: detail.wikidataId
|
|
1759
1776
|
},
|
|
1760
|
-
fill:
|
|
1777
|
+
fill: own.fill,
|
|
1778
|
+
textColor: own.textColor,
|
|
1761
1779
|
parentNode: detail.parent ? relative(detail.parent, null) : null,
|
|
1762
1780
|
childNodes: detail.children.map((child) => relative(child, detail.uuid)),
|
|
1763
1781
|
ancestorNodes: ancestors2.map(
|
|
1764
1782
|
({ ascendant }, index) => relative(ascendant, index === 0 ? null : ancestors2[index - 1].ascendant.uuid)
|
|
1765
1783
|
)
|
|
1766
1784
|
};
|
|
1767
|
-
}, [detail, scope]);
|
|
1785
|
+
}, [detail, scope, treeRelations]);
|
|
1768
1786
|
if (isError) return {
|
|
1769
1787
|
name: null,
|
|
1770
1788
|
title: "Genre unavailable",
|
|
1771
|
-
content: /* @__PURE__ */ (0,
|
|
1789
|
+
content: /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("p", { role: "alert", className: "text-body text-[var(--color-text)]", children: "This genre could not be loaded." })
|
|
1772
1790
|
};
|
|
1773
1791
|
if (isPending || !detail || !view) return {
|
|
1774
1792
|
name: null,
|
|
1775
1793
|
title: "Loading genre\u2026",
|
|
1776
|
-
content: /* @__PURE__ */ (0,
|
|
1777
|
-
/* @__PURE__ */ (0,
|
|
1778
|
-
/* @__PURE__ */ (0,
|
|
1779
|
-
/* @__PURE__ */ (0,
|
|
1794
|
+
content: /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("div", { className: "flex flex-col gap-3", "aria-busy": "true", "data-testid": "genre-detail-panel-skeleton", children: [
|
|
1795
|
+
/* @__PURE__ */ (0, import_jsx_runtime30.jsx)(import_ui10.Skeleton, { className: "h-6 w-2/3" }),
|
|
1796
|
+
/* @__PURE__ */ (0, import_jsx_runtime30.jsx)(import_ui10.Skeleton, { className: "h-4 w-full" }),
|
|
1797
|
+
/* @__PURE__ */ (0, import_jsx_runtime30.jsx)(import_ui10.Skeleton, { className: "h-4 w-3/4" })
|
|
1780
1798
|
] })
|
|
1781
1799
|
};
|
|
1782
|
-
const selectGenre = (nodeId) => onSelectGenre(
|
|
1783
|
-
const family = /* @__PURE__ */ (0,
|
|
1800
|
+
const selectGenre = (nodeId) => onSelectGenre(import_genre_tree20.GenreUuidSchema.parse(nodeId));
|
|
1801
|
+
const family = /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
|
|
1784
1802
|
import_genre_tree_view4.GenreNodeFamily,
|
|
1785
1803
|
{
|
|
1786
1804
|
node: view.node,
|
|
1787
1805
|
fill: view.fill,
|
|
1788
|
-
textColor:
|
|
1806
|
+
textColor: view.textColor,
|
|
1789
1807
|
parentNode: view.parentNode,
|
|
1790
1808
|
childNodes: view.childNodes,
|
|
1791
1809
|
onSelectNode: selectGenre
|
|
1792
1810
|
}
|
|
1793
1811
|
);
|
|
1794
|
-
const ancestors = /* @__PURE__ */ (0,
|
|
1812
|
+
const ancestors = /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(import_genre_tree_view4.GenreNodeAncestors, { ancestorNodes: view.ancestorNodes, onSelectNode: selectGenre });
|
|
1795
1813
|
return {
|
|
1796
1814
|
name: detail.name,
|
|
1797
1815
|
title: detail.name,
|
|
1798
|
-
headerAccent: { background: view.fill, color:
|
|
1816
|
+
headerAccent: { background: view.fill, color: view.textColor },
|
|
1799
1817
|
aside: expanded ? ancestors : void 0,
|
|
1800
|
-
content: /* @__PURE__ */ (0,
|
|
1801
|
-
/* @__PURE__ */ (0,
|
|
1818
|
+
content: /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)(import_jsx_runtime30.Fragment, { children: [
|
|
1819
|
+
/* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
|
|
1802
1820
|
GenreInfoPanelBody,
|
|
1803
1821
|
{
|
|
1804
|
-
family: /* @__PURE__ */ (0,
|
|
1822
|
+
family: /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)(import_jsx_runtime30.Fragment, { children: [
|
|
1805
1823
|
family,
|
|
1806
1824
|
!expanded && ancestors
|
|
1807
1825
|
] }),
|
|
1808
1826
|
genreUuid: detail.uuid,
|
|
1809
|
-
genrePlaylist: hostPlaylist ?? (detail.criteriaPlaylist === null ? null : scope === "reference" ? { ...
|
|
1827
|
+
genrePlaylist: hostPlaylist ?? (detail.criteriaPlaylist === null ? null : scope === "reference" ? { ...import_genre_tree20.GenrePlaylistSummarySchema.parse(detail.criteriaPlaylist), criteria: import_genre_tree20.CriteriaMinimumSchema.parse(detail) } : { ...detail.criteriaPlaylist, criteria: import_genre_tree20.CriteriaMinimumSchema.parse(detail), tracksCount: detail.tracksCount }),
|
|
1810
1828
|
catalogue: detail.catalogue,
|
|
1811
|
-
countsContext: !hostPlaylist && extras?.artist ? "all artists" : void 0,
|
|
1812
1829
|
wikidataId: detail.wikidataId,
|
|
1813
1830
|
scope,
|
|
1814
1831
|
getBackendBaseUrl,
|
|
@@ -1846,8 +1863,8 @@ function GenreDetailPanel({
|
|
|
1846
1863
|
expanded,
|
|
1847
1864
|
band: { onZoomIn, shareUrl, shareTarget: shareUrl ? shareTarget : void 0 }
|
|
1848
1865
|
});
|
|
1849
|
-
return /* @__PURE__ */ (0,
|
|
1850
|
-
|
|
1866
|
+
return /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
|
|
1867
|
+
import_ui10.DetailPanel,
|
|
1851
1868
|
{
|
|
1852
1869
|
side: "left",
|
|
1853
1870
|
title: panel.title,
|
|
@@ -1859,16 +1876,16 @@ function GenreDetailPanel({
|
|
|
1859
1876
|
edgeTab,
|
|
1860
1877
|
aside: panel.aside,
|
|
1861
1878
|
titleInSearch,
|
|
1862
|
-
headerActions: onExpandedChange ? /* @__PURE__ */ (0,
|
|
1879
|
+
headerActions: onExpandedChange ? /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(import_ui10.IconButton, { "aria-label": expanded ? "Shrink panel" : "Extend panel", onClick: () => onExpandedChange(!expanded), children: expanded ? /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(import_lucide_react9.Minimize2, { "aria-hidden": "true", className: "h-4 w-4" }) : /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(import_lucide_react9.Maximize2, { "aria-hidden": "true", className: "h-4 w-4" }) }) : void 0,
|
|
1863
1880
|
children: panel.content
|
|
1864
1881
|
}
|
|
1865
1882
|
);
|
|
1866
1883
|
}
|
|
1867
1884
|
|
|
1868
1885
|
// src/genre-tree/ChangeParentPopup.tsx
|
|
1869
|
-
var
|
|
1870
|
-
var
|
|
1871
|
-
var
|
|
1886
|
+
var import_react16 = require("react");
|
|
1887
|
+
var import_genre_tree21 = require("@behindthemusictree/app-kit/genre-tree");
|
|
1888
|
+
var import_jsx_runtime31 = require("react/jsx-runtime");
|
|
1872
1889
|
function ChangeParentPopup({
|
|
1873
1890
|
genrePlaylist,
|
|
1874
1891
|
genrePlaylists,
|
|
@@ -1877,9 +1894,9 @@ function ChangeParentPopup({
|
|
|
1877
1894
|
onClose,
|
|
1878
1895
|
onParentChanged
|
|
1879
1896
|
}) {
|
|
1880
|
-
const { mutate, isPending, formErrors } = (0,
|
|
1881
|
-
const candidates = (0,
|
|
1882
|
-
() => (0,
|
|
1897
|
+
const { mutate, isPending, formErrors } = (0, import_genre_tree21.useUpdateGenre)(scope, getBackendBaseUrl);
|
|
1898
|
+
const candidates = (0, import_react16.useMemo)(
|
|
1899
|
+
() => (0, import_genre_tree21.getReparentCandidates)(genrePlaylists, genrePlaylist.uuid),
|
|
1883
1900
|
[genrePlaylists, genrePlaylist.uuid]
|
|
1884
1901
|
);
|
|
1885
1902
|
const handleSelect = (newParent) => {
|
|
@@ -1896,19 +1913,19 @@ function ChangeParentPopup({
|
|
|
1896
1913
|
}
|
|
1897
1914
|
);
|
|
1898
1915
|
};
|
|
1899
|
-
(0,
|
|
1916
|
+
(0, import_react16.useEffect)(() => {
|
|
1900
1917
|
const handleKeyDown = (event) => {
|
|
1901
1918
|
if (event.key === "Escape") onClose();
|
|
1902
1919
|
};
|
|
1903
1920
|
window.addEventListener("keydown", handleKeyDown);
|
|
1904
1921
|
return () => window.removeEventListener("keydown", handleKeyDown);
|
|
1905
1922
|
}, [onClose]);
|
|
1906
|
-
return /* @__PURE__ */ (0,
|
|
1907
|
-
/* @__PURE__ */ (0,
|
|
1923
|
+
return /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)(BasePopup_default, { title: `Change parent of ${genrePlaylist.name}`, onClose, showCancelButton: true, fitContent: true, children: [
|
|
1924
|
+
/* @__PURE__ */ (0, import_jsx_runtime31.jsxs)("p", { className: "mb-3 text-body text-[var(--color-text-muted)]", children: [
|
|
1908
1925
|
"Current parent: ",
|
|
1909
1926
|
genrePlaylist.parent?.name ?? "none"
|
|
1910
1927
|
] }),
|
|
1911
|
-
/* @__PURE__ */ (0,
|
|
1928
|
+
/* @__PURE__ */ (0, import_jsx_runtime31.jsx)("div", { "aria-busy": isPending, className: isPending ? "pointer-events-none opacity-60" : void 0, children: /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
|
|
1912
1929
|
GenreSearch,
|
|
1913
1930
|
{
|
|
1914
1931
|
genrePlaylists: candidates,
|
|
@@ -1916,24 +1933,61 @@ function ChangeParentPopup({
|
|
|
1916
1933
|
placeholder: "Search a new parent\u2026"
|
|
1917
1934
|
}
|
|
1918
1935
|
) }),
|
|
1919
|
-
formErrors.length > 0 && /* @__PURE__ */ (0,
|
|
1936
|
+
formErrors.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("p", { role: "alert", className: "mt-3 text-body text-[var(--color-red-500)]", children: formErrors.map(({ message }) => message).join(" ") })
|
|
1920
1937
|
] });
|
|
1921
1938
|
}
|
|
1922
1939
|
|
|
1923
1940
|
// src/genre-tree/artist/useArtistPanel.tsx
|
|
1924
|
-
var
|
|
1925
|
-
var
|
|
1941
|
+
var import_ui17 = require("@behindthemusictree/ui");
|
|
1942
|
+
var import_genre_tree27 = require("@behindthemusictree/app-kit/genre-tree");
|
|
1943
|
+
|
|
1944
|
+
// src/genre-tree/artist/ArtistActionBand.tsx
|
|
1945
|
+
var import_lucide_react10 = require("lucide-react");
|
|
1946
|
+
var import_ui11 = require("@behindthemusictree/ui");
|
|
1947
|
+
var import_genre_tree22 = require("@behindthemusictree/app-kit/genre-tree");
|
|
1948
|
+
var import_player7 = require("@behindthemusictree/app-kit/player");
|
|
1949
|
+
var import_jsx_runtime32 = require("react/jsx-runtime");
|
|
1950
|
+
function ArtistActionBand({ artist, share }) {
|
|
1951
|
+
const { trackList, playNewTrackListFromArtist } = (0, import_genre_tree22.useTrackList)();
|
|
1952
|
+
const { isPlaying, setIsPlaying } = (0, import_player7.usePlayer)();
|
|
1953
|
+
const origin = trackList?.origin;
|
|
1954
|
+
const isCurrent = origin?.type === import_genre_tree22.TrackListOriginType.ARTIST && origin.uuid === artist.uuid;
|
|
1955
|
+
const playing = isCurrent && isPlaying;
|
|
1956
|
+
const handleClick = () => {
|
|
1957
|
+
if (isCurrent) {
|
|
1958
|
+
setIsPlaying(!isPlaying);
|
|
1959
|
+
return;
|
|
1960
|
+
}
|
|
1961
|
+
playNewTrackListFromArtist({ uuid: artist.uuid, name: artist.name }, "reference", { ordering: "title" }).catch((error) => {
|
|
1962
|
+
console.error("Failed to load artist tracks:", error);
|
|
1963
|
+
});
|
|
1964
|
+
};
|
|
1965
|
+
return /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(import_ui11.PanelBleed, { children: /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)(import_ui11.ActionBand, { children: [
|
|
1966
|
+
/* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
|
|
1967
|
+
import_ui11.ActionButton,
|
|
1968
|
+
{
|
|
1969
|
+
icon: playing ? /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(import_lucide_react10.Pause, { "aria-hidden": "true", className: "w-5 h-5" }) : /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(import_lucide_react10.Play, { "aria-hidden": "true", className: "w-5 h-5" }),
|
|
1970
|
+
label: playing ? "Pause" : "Play",
|
|
1971
|
+
caption: String(artist.playableTracksCount),
|
|
1972
|
+
disabled: artist.playableTracksCount === 0,
|
|
1973
|
+
title: artist.playableTracksCount === 0 ? "No playable songs" : void 0,
|
|
1974
|
+
onClick: handleClick
|
|
1975
|
+
}
|
|
1976
|
+
),
|
|
1977
|
+
share
|
|
1978
|
+
] }) });
|
|
1979
|
+
}
|
|
1926
1980
|
|
|
1927
1981
|
// src/genre-tree/artist/ArtistHeader.tsx
|
|
1928
|
-
var
|
|
1982
|
+
var import_ui13 = require("@behindthemusictree/ui");
|
|
1929
1983
|
|
|
1930
1984
|
// src/genre-tree/artist/ArtistLinks.tsx
|
|
1931
|
-
var
|
|
1985
|
+
var import_lucide_react11 = require("lucide-react");
|
|
1932
1986
|
var import_si3 = require("react-icons/si");
|
|
1933
|
-
var
|
|
1934
|
-
var
|
|
1987
|
+
var import_ui12 = require("@behindthemusictree/ui");
|
|
1988
|
+
var import_jsx_runtime33 = require("react/jsx-runtime");
|
|
1935
1989
|
var LINK_KINDS = {
|
|
1936
|
-
official: { label: "Official website", Icon:
|
|
1990
|
+
official: { label: "Official website", Icon: import_lucide_react11.Globe },
|
|
1937
1991
|
wikipedia: { label: "Wikipedia", Icon: import_si3.SiWikipedia },
|
|
1938
1992
|
wikidata: { label: "Wikidata", Icon: import_si3.SiWikidata },
|
|
1939
1993
|
spotify: { label: "Spotify", Icon: import_si3.SiSpotify },
|
|
@@ -1941,7 +1995,7 @@ var LINK_KINDS = {
|
|
|
1941
1995
|
bandcamp: { label: "Bandcamp", Icon: import_si3.SiBandcamp },
|
|
1942
1996
|
soundcloud: { label: "SoundCloud", Icon: import_si3.SiSoundcloud },
|
|
1943
1997
|
discogs: { label: "Discogs", Icon: import_si3.SiDiscogs },
|
|
1944
|
-
social: { label: "Social", Icon:
|
|
1998
|
+
social: { label: "Social", Icon: import_lucide_react11.Share2 }
|
|
1945
1999
|
};
|
|
1946
2000
|
function socialLabel(url) {
|
|
1947
2001
|
try {
|
|
@@ -1968,7 +2022,7 @@ function artistLinks(artist) {
|
|
|
1968
2022
|
return links;
|
|
1969
2023
|
}
|
|
1970
2024
|
function ArtistLinks({ links }) {
|
|
1971
|
-
return /* @__PURE__ */ (0,
|
|
2025
|
+
return /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("ul", { className: "flex flex-wrap gap-1.5", children: links.map(({ key, url, Icon, label }) => /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(import_ui12.Chip, { href: url, icon: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(Icon, { className: "h-3.5 w-3.5 shrink-0", "aria-hidden": "true" }), children: label }) }, key)) });
|
|
1972
2026
|
}
|
|
1973
2027
|
|
|
1974
2028
|
// src/genre-tree/artist/formatYears.ts
|
|
@@ -1979,7 +2033,7 @@ function formatYears(beginYear, endYear, ended) {
|
|
|
1979
2033
|
}
|
|
1980
2034
|
|
|
1981
2035
|
// src/genre-tree/artist/ArtistHeader.tsx
|
|
1982
|
-
var
|
|
2036
|
+
var import_jsx_runtime34 = require("react/jsx-runtime");
|
|
1983
2037
|
var countryNames = new Intl.DisplayNames(["en"], { type: "region" });
|
|
1984
2038
|
function ArtistHeader({ artist }) {
|
|
1985
2039
|
const fields = [];
|
|
@@ -1989,35 +2043,35 @@ function ArtistHeader({ artist }) {
|
|
|
1989
2043
|
const years = formatYears(artist.beginYear, artist.endYear, artist.ended);
|
|
1990
2044
|
if (years) fields.push({ label: "Active", value: years });
|
|
1991
2045
|
const links = artistLinks(artist);
|
|
1992
|
-
if (links.length > 0) fields.push({ label: "Links", value: /* @__PURE__ */ (0,
|
|
2046
|
+
if (links.length > 0) fields.push({ label: "Links", value: /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(ArtistLinks, { links }) });
|
|
1993
2047
|
if (fields.length === 0) return null;
|
|
1994
|
-
return /* @__PURE__ */ (0,
|
|
2048
|
+
return /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(import_ui13.FieldList, { items: fields });
|
|
1995
2049
|
}
|
|
1996
2050
|
|
|
1997
2051
|
// src/genre-tree/artist/ArtistPhoto.tsx
|
|
1998
|
-
var
|
|
2052
|
+
var import_jsx_runtime35 = require("react/jsx-runtime");
|
|
1999
2053
|
function ExternalLink({ href, children }) {
|
|
2000
|
-
return /* @__PURE__ */ (0,
|
|
2054
|
+
return /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("a", { href, target: "_blank", rel: "noopener noreferrer", className: "underline-offset-2 hover:underline", children });
|
|
2001
2055
|
}
|
|
2002
2056
|
function ArtistPhoto({ image, name }) {
|
|
2003
|
-
return /* @__PURE__ */ (0,
|
|
2004
|
-
/* @__PURE__ */ (0,
|
|
2005
|
-
/* @__PURE__ */ (0,
|
|
2057
|
+
return /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("figure", { className: "flex flex-col gap-1.5", children: [
|
|
2058
|
+
/* @__PURE__ */ (0, import_jsx_runtime35.jsx)("img", { src: image.url, alt: name, className: "h-64 w-full object-contain bg-[var(--color-surface-muted)] rounded" }),
|
|
2059
|
+
/* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("figcaption", { className: "text-caption text-[var(--color-text-muted)]", children: [
|
|
2006
2060
|
"Photo: ",
|
|
2007
|
-
/* @__PURE__ */ (0,
|
|
2061
|
+
/* @__PURE__ */ (0, import_jsx_runtime35.jsx)(ExternalLink, { href: image.pageUrl, children: image.author ?? "Wikimedia Commons" }),
|
|
2008
2062
|
",",
|
|
2009
2063
|
" ",
|
|
2010
|
-
image.licenseUrl ? /* @__PURE__ */ (0,
|
|
2064
|
+
image.licenseUrl ? /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(ExternalLink, { href: image.licenseUrl, children: image.license }) : image.license
|
|
2011
2065
|
] })
|
|
2012
2066
|
] });
|
|
2013
2067
|
}
|
|
2014
2068
|
|
|
2015
2069
|
// src/genre-tree/artist/ArtistMembers.tsx
|
|
2016
|
-
var
|
|
2017
|
-
var
|
|
2070
|
+
var import_ui14 = require("@behindthemusictree/ui");
|
|
2071
|
+
var import_jsx_runtime36 = require("react/jsx-runtime");
|
|
2018
2072
|
function MembershipList({ title, memberships, renderArtistLink }) {
|
|
2019
2073
|
if (memberships.length === 0) return null;
|
|
2020
|
-
return /* @__PURE__ */ (0,
|
|
2074
|
+
return /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(import_ui14.PanelGroup, { title, children: /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("ul", { children: memberships.map((membership, index) => {
|
|
2021
2075
|
const details = [
|
|
2022
2076
|
formatYears(membership.beginYear, membership.endYear, membership.ended),
|
|
2023
2077
|
...membership.roles
|
|
@@ -2025,9 +2079,9 @@ function MembershipList({ title, memberships, renderArtistLink }) {
|
|
|
2025
2079
|
const detailsText = details.filter(Boolean).join(" \xB7 ");
|
|
2026
2080
|
return (
|
|
2027
2081
|
// A member can have several periods in the same group.
|
|
2028
|
-
/* @__PURE__ */ (0,
|
|
2029
|
-
/* @__PURE__ */ (0,
|
|
2030
|
-
detailsText && /* @__PURE__ */ (0,
|
|
2082
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("li", { className: "truncate py-0.5", title: detailsText || void 0, children: [
|
|
2083
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)("span", { className: "font-medium text-[var(--color-text)]", children: renderArtistLink(membership.artist) }),
|
|
2084
|
+
detailsText && /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("span", { className: "text-[var(--color-text-muted)]", children: [
|
|
2031
2085
|
" \u2014 ",
|
|
2032
2086
|
detailsText
|
|
2033
2087
|
] })
|
|
@@ -2038,9 +2092,9 @@ function MembershipList({ title, memberships, renderArtistLink }) {
|
|
|
2038
2092
|
function ArtistMembers({ title, memberships, renderArtistLink }) {
|
|
2039
2093
|
if (memberships.length === 0) return null;
|
|
2040
2094
|
const isCurrent = (membership) => !membership.ended && membership.endYear === null;
|
|
2041
|
-
return /* @__PURE__ */ (0,
|
|
2042
|
-
/* @__PURE__ */ (0,
|
|
2043
|
-
/* @__PURE__ */ (0,
|
|
2095
|
+
return /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)(import_ui14.PanelSection, { title, children: [
|
|
2096
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)(MembershipList, { title: "Current", memberships: memberships.filter(isCurrent), renderArtistLink }),
|
|
2097
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
|
|
2044
2098
|
MembershipList,
|
|
2045
2099
|
{
|
|
2046
2100
|
title: "Past",
|
|
@@ -2052,8 +2106,8 @@ function ArtistMembers({ title, memberships, renderArtistLink }) {
|
|
|
2052
2106
|
}
|
|
2053
2107
|
|
|
2054
2108
|
// src/genre-tree/artist/ArtistDiscography.tsx
|
|
2055
|
-
var
|
|
2056
|
-
var
|
|
2109
|
+
var import_ui15 = require("@behindthemusictree/ui");
|
|
2110
|
+
var import_jsx_runtime37 = require("react/jsx-runtime");
|
|
2057
2111
|
var GROUPS = ["Albums", "EPs", "Singles", "Live", "Compilations", "Other"];
|
|
2058
2112
|
var PRIMARY_GROUPS = { album: "Albums", ep: "EPs", single: "Singles" };
|
|
2059
2113
|
function discographyGroup({ primaryType, secondaryTypes }) {
|
|
@@ -2073,55 +2127,55 @@ function byYear(a, b) {
|
|
|
2073
2127
|
function ArtistDiscography({ albums }) {
|
|
2074
2128
|
if (albums.length === 0) return null;
|
|
2075
2129
|
const sorted = [...albums].sort(byYear);
|
|
2076
|
-
return /* @__PURE__ */ (0,
|
|
2130
|
+
return /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(import_ui15.PanelSection, { title: "Discography", children: GROUPS.map((group) => {
|
|
2077
2131
|
const groupAlbums = sorted.filter((album) => discographyGroup(album) === group);
|
|
2078
2132
|
if (groupAlbums.length === 0) return null;
|
|
2079
|
-
return /* @__PURE__ */ (0,
|
|
2080
|
-
/* @__PURE__ */ (0,
|
|
2081
|
-
/* @__PURE__ */ (0,
|
|
2133
|
+
return /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(import_ui15.PanelGroup, { title: group, children: /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("ul", { children: groupAlbums.map((album) => /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)("li", { className: "grid grid-cols-[2.5rem_minmax(0,1fr)] gap-2 py-0.5", children: [
|
|
2134
|
+
/* @__PURE__ */ (0, import_jsx_runtime37.jsx)("span", { className: "tabular-nums text-[var(--color-text-muted)]", children: album.year ?? "\u2014" }),
|
|
2135
|
+
/* @__PURE__ */ (0, import_jsx_runtime37.jsx)("span", { className: "truncate text-[var(--color-text)]", title: album.name, children: album.name })
|
|
2082
2136
|
] }, album.uuid)) }) }, group);
|
|
2083
2137
|
}) });
|
|
2084
2138
|
}
|
|
2085
2139
|
|
|
2086
2140
|
// src/genre-tree/artist/ArtistSongs.tsx
|
|
2087
|
-
var
|
|
2141
|
+
var import_react17 = require("react");
|
|
2088
2142
|
var import_react_query2 = require("@tanstack/react-query");
|
|
2089
|
-
var
|
|
2090
|
-
var
|
|
2091
|
-
var
|
|
2092
|
-
var
|
|
2093
|
-
var
|
|
2143
|
+
var import_lucide_react12 = require("lucide-react");
|
|
2144
|
+
var import_ui16 = require("@behindthemusictree/ui");
|
|
2145
|
+
var import_player11 = require("@behindthemusictree/app-kit/player");
|
|
2146
|
+
var import_genre_tree26 = require("@behindthemusictree/app-kit/genre-tree");
|
|
2147
|
+
var import_transport6 = require("@behindthemusictree/app-kit/transport");
|
|
2094
2148
|
|
|
2095
2149
|
// src/genre-tree/track-list-sidebar/TrackItem.tsx
|
|
2096
|
-
var
|
|
2097
|
-
var
|
|
2150
|
+
var import_player10 = require("@behindthemusictree/app-kit/player");
|
|
2151
|
+
var import_genre_tree23 = require("@behindthemusictree/app-kit/genre-tree");
|
|
2098
2152
|
|
|
2099
2153
|
// src/genre-tree/TrackPositionPlayPause.tsx
|
|
2100
2154
|
var import_fa3 = require("react-icons/fa");
|
|
2101
|
-
var import_player7 = require("@behindthemusictree/app-kit/player");
|
|
2102
2155
|
var import_player8 = require("@behindthemusictree/app-kit/player");
|
|
2103
|
-
var
|
|
2156
|
+
var import_player9 = require("@behindthemusictree/app-kit/player");
|
|
2157
|
+
var import_jsx_runtime38 = require("react/jsx-runtime");
|
|
2104
2158
|
function TrackPositionPlayPause({
|
|
2105
2159
|
position,
|
|
2106
2160
|
uuid,
|
|
2107
2161
|
handlePlayPauseClick,
|
|
2108
2162
|
isSelected = false
|
|
2109
2163
|
}) {
|
|
2110
|
-
const { playerTrackObject, playbackConfirmedTrackId, playState, isLoading: isPlayerLoading } = (0,
|
|
2164
|
+
const { playerTrackObject, playbackConfirmedTrackId, playState, isLoading: isPlayerLoading } = (0, import_player8.usePlayer)();
|
|
2111
2165
|
const isThisTrack = playerTrackObject?.track.id === uuid;
|
|
2112
2166
|
const isConfirmedPlayable = playbackConfirmedTrackId === uuid;
|
|
2113
|
-
const isAwaitingPlayback = (isSelected || isThisTrack) && !isConfirmedPlayable && !(isThisTrack && playerTrackObject?.loadError) && (!isThisTrack || isPlayerLoading || playState ===
|
|
2114
|
-
const isPlaying = isThisTrack && isConfirmedPlayable && playState ===
|
|
2115
|
-
const isPaused = isThisTrack && isConfirmedPlayable && playState ===
|
|
2167
|
+
const isAwaitingPlayback = (isSelected || isThisTrack) && !isConfirmedPlayable && !(isThisTrack && playerTrackObject?.loadError) && (!isThisTrack || isPlayerLoading || playState === import_player9.PlayStates.LOADING || playState === import_player9.PlayStates.PLAYING);
|
|
2168
|
+
const isPlaying = isThisTrack && isConfirmedPlayable && playState === import_player9.PlayStates.PLAYING;
|
|
2169
|
+
const isPaused = isThisTrack && isConfirmedPlayable && playState === import_player9.PlayStates.PAUSED;
|
|
2116
2170
|
const isCurrentTrackActive = isPlaying || isPaused;
|
|
2117
|
-
return /* @__PURE__ */ (0,
|
|
2171
|
+
return /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)(
|
|
2118
2172
|
"div",
|
|
2119
2173
|
{
|
|
2120
2174
|
className: "track-position-play-pause relative flex items-center justify-center gap-2 text-lg w-16 cursor-pointer",
|
|
2121
2175
|
style: { minWidth: "4rem", maxWidth: "4rem" },
|
|
2122
2176
|
onClick: handlePlayPauseClick,
|
|
2123
2177
|
children: [
|
|
2124
|
-
/* @__PURE__ */ (0,
|
|
2178
|
+
/* @__PURE__ */ (0, import_jsx_runtime38.jsx)("div", { className: "track-position-play-pause__status group-hover:hidden flex items-center justify-center", children: isAwaitingPlayback ? /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("span", { className: "track-position-play-pause__spinner", role: "status", "aria-label": "Loading track" }) : isCurrentTrackActive ? /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)(
|
|
2125
2179
|
"span",
|
|
2126
2180
|
{
|
|
2127
2181
|
className: "track-position-play-pause__bars",
|
|
@@ -2129,18 +2183,18 @@ function TrackPositionPlayPause({
|
|
|
2129
2183
|
role: "img",
|
|
2130
2184
|
"aria-label": isPlaying ? "Playing" : "Paused",
|
|
2131
2185
|
children: [
|
|
2132
|
-
/* @__PURE__ */ (0,
|
|
2133
|
-
/* @__PURE__ */ (0,
|
|
2134
|
-
/* @__PURE__ */ (0,
|
|
2186
|
+
/* @__PURE__ */ (0, import_jsx_runtime38.jsx)("span", { className: "track-position-play-pause__bar" }),
|
|
2187
|
+
/* @__PURE__ */ (0, import_jsx_runtime38.jsx)("span", { className: "track-position-play-pause__bar" }),
|
|
2188
|
+
/* @__PURE__ */ (0, import_jsx_runtime38.jsx)("span", { className: "track-position-play-pause__bar" })
|
|
2135
2189
|
]
|
|
2136
2190
|
}
|
|
2137
2191
|
) : position }),
|
|
2138
|
-
/* @__PURE__ */ (0,
|
|
2192
|
+
/* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
|
|
2139
2193
|
"div",
|
|
2140
2194
|
{
|
|
2141
2195
|
className: `hidden group-hover:flex items-center justify-center ${isCurrentTrackActive ? "" : "absolute inset-0"}`,
|
|
2142
2196
|
"aria-hidden": "true",
|
|
2143
|
-
children: isAwaitingPlayback ? /* @__PURE__ */ (0,
|
|
2197
|
+
children: isAwaitingPlayback ? /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("span", { className: "track-position-play-pause__spinner" }) : isPlaying ? /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(import_fa3.FaPause, {}) : /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(import_fa3.FaPlay, {})
|
|
2144
2198
|
}
|
|
2145
2199
|
)
|
|
2146
2200
|
]
|
|
@@ -2149,9 +2203,9 @@ function TrackPositionPlayPause({
|
|
|
2149
2203
|
}
|
|
2150
2204
|
|
|
2151
2205
|
// src/genre-tree/track-list-sidebar/TrackItem.tsx
|
|
2152
|
-
var
|
|
2153
|
-
var
|
|
2154
|
-
var
|
|
2206
|
+
var import_genre_tree24 = require("@behindthemusictree/app-kit/genre-tree");
|
|
2207
|
+
var import_genre_tree25 = require("@behindthemusictree/app-kit/genre-tree");
|
|
2208
|
+
var import_jsx_runtime39 = require("react/jsx-runtime");
|
|
2155
2209
|
function TrackItem({
|
|
2156
2210
|
track,
|
|
2157
2211
|
position,
|
|
@@ -2160,12 +2214,12 @@ function TrackItem({
|
|
|
2160
2214
|
renderArtistLink,
|
|
2161
2215
|
renderSongLink
|
|
2162
2216
|
}) {
|
|
2163
|
-
const { handlePlayPauseAction, playerTrackObject, loadTrackForPlayer } = (0,
|
|
2164
|
-
const { trackList, selectedTrack, toTrackAtPosition, runtimeUnplayableTrackIds } = (0,
|
|
2217
|
+
const { handlePlayPauseAction, playerTrackObject, loadTrackForPlayer } = (0, import_player10.usePlayer)();
|
|
2218
|
+
const { trackList, selectedTrack, toTrackAtPosition, runtimeUnplayableTrackIds } = (0, import_genre_tree23.useTrackList)();
|
|
2165
2219
|
const scope = trackList?.origin?.scope ?? null;
|
|
2166
2220
|
const isCurrentTrack = playerTrackObject?.track.id === track.uuid;
|
|
2167
2221
|
const hasPlaybackError = isCurrentTrack && !!playerTrackObject?.loadError;
|
|
2168
|
-
const isUnplayable = hasPlaybackError || runtimeUnplayableTrackIds?.has(track.uuid) === true || (0,
|
|
2222
|
+
const isUnplayable = hasPlaybackError || runtimeUnplayableTrackIds?.has(track.uuid) === true || (0, import_genre_tree24.isSong)(track) && (0, import_genre_tree24.songUnplayableReason)(track) !== null;
|
|
2169
2223
|
const handlePlayPauseClick = (event) => {
|
|
2170
2224
|
event.stopPropagation();
|
|
2171
2225
|
if (isCurrentTrack) {
|
|
@@ -2175,12 +2229,12 @@ function TrackItem({
|
|
|
2175
2229
|
loadTrackForPlayer(track.uuid);
|
|
2176
2230
|
}
|
|
2177
2231
|
};
|
|
2178
|
-
return /* @__PURE__ */ (0,
|
|
2232
|
+
return /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)(
|
|
2179
2233
|
"div",
|
|
2180
2234
|
{
|
|
2181
2235
|
className: `track-item flex h-14 text-[var(--color-text)] ${isUnplayable ? "opacity-50" : "hover:bg-[var(--color-surface-muted)] group"}`,
|
|
2182
2236
|
children: [
|
|
2183
|
-
isUnplayable ? /* @__PURE__ */ (0,
|
|
2237
|
+
isUnplayable ? /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
|
|
2184
2238
|
"div",
|
|
2185
2239
|
{
|
|
2186
2240
|
className: "flex items-center justify-center text-lg w-16",
|
|
@@ -2188,7 +2242,7 @@ function TrackItem({
|
|
|
2188
2242
|
"aria-disabled": "true",
|
|
2189
2243
|
children: position
|
|
2190
2244
|
}
|
|
2191
|
-
) : /* @__PURE__ */ (0,
|
|
2245
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
|
|
2192
2246
|
TrackPositionPlayPause,
|
|
2193
2247
|
{
|
|
2194
2248
|
position,
|
|
@@ -2197,12 +2251,12 @@ function TrackItem({
|
|
|
2197
2251
|
isSelected: selectedTrack?.uuid === track.uuid
|
|
2198
2252
|
}
|
|
2199
2253
|
),
|
|
2200
|
-
/* @__PURE__ */ (0,
|
|
2201
|
-
/* @__PURE__ */ (0,
|
|
2202
|
-
track.artists && track.artists.length > 0 ? /* @__PURE__ */ (0,
|
|
2254
|
+
/* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("div", { className: "title-artist-container flex flex-col items-start justify-center min-w-0 flex-1", children: [
|
|
2255
|
+
/* @__PURE__ */ (0, import_jsx_runtime39.jsx)("div", { className: "flex max-w-full items-center gap-2", children: /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("div", { className: "title text-lg font-bold text-[var(--color-text)] max-w-full truncate", children: renderSongLink ? renderSongLink(track) : (0, import_genre_tree24.isSong)(track) ? /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(MusicBrainzRecordingLink, { song: track, className: "hover:underline focus-visible:underline", children: track.title }) : track.title }) }),
|
|
2256
|
+
track.artists && track.artists.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("div", { className: "artist text-base max-w-full truncate text-[var(--color-text-muted)]", children: /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(import_genre_tree25.ArtistNames, { artists: track.artists, renderArtistLink }) }) : ""
|
|
2203
2257
|
] }),
|
|
2204
|
-
/* @__PURE__ */ (0,
|
|
2205
|
-
renderDuration && /* @__PURE__ */ (0,
|
|
2258
|
+
/* @__PURE__ */ (0, import_jsx_runtime39.jsx)("div", { className: "genre-name-container flex items-center justify-start w-[21.6%] min-w-0 shrink-0", children: track.genre ? /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("div", { className: "genre-name max-w-full whitespace-normal break-words p-1 text-caption font-bold", children: track.genre.name }) : "" }),
|
|
2259
|
+
renderDuration && /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
|
|
2206
2260
|
"div",
|
|
2207
2261
|
{
|
|
2208
2262
|
className: "duration flex text-base w-16 items-center justify-center",
|
|
@@ -2210,28 +2264,28 @@ function TrackItem({
|
|
|
2210
2264
|
children: renderDuration(track)
|
|
2211
2265
|
}
|
|
2212
2266
|
),
|
|
2213
|
-
renderActions && /* @__PURE__ */ (0,
|
|
2267
|
+
renderActions && /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("div", { className: "edit flex text-base w-6 items-center justify-center mr-2 cursor-pointer", children: renderActions(track) })
|
|
2214
2268
|
]
|
|
2215
2269
|
}
|
|
2216
2270
|
);
|
|
2217
2271
|
}
|
|
2218
2272
|
|
|
2219
2273
|
// src/genre-tree/artist/ArtistSongs.tsx
|
|
2220
|
-
var
|
|
2221
|
-
var SongPageSchema2 = (0,
|
|
2274
|
+
var import_jsx_runtime40 = require("react/jsx-runtime");
|
|
2275
|
+
var SongPageSchema2 = (0, import_transport6.PaginatedResponseSchema)(import_genre_tree26.SongDetailedSchema);
|
|
2222
2276
|
var SORTS = [
|
|
2223
2277
|
{ ordering: "title", label: "Title" },
|
|
2224
2278
|
{ ordering: "-albumYear", label: "Year" }
|
|
2225
2279
|
];
|
|
2226
2280
|
function ArtistSongs({ artist, getBackendBaseUrl, renderArtistLink, renderSongLink }) {
|
|
2227
|
-
const [page, setPage] = (0,
|
|
2228
|
-
const [ordering, setOrdering] = (0,
|
|
2229
|
-
const { playNewTrackListFromArtist } = (0,
|
|
2230
|
-
const { playerTrackObject } = (0,
|
|
2231
|
-
const { data, isPending, isError } = (0,
|
|
2281
|
+
const [page, setPage] = (0, import_react17.useState)(1);
|
|
2282
|
+
const [ordering, setOrdering] = (0, import_react17.useState)("title");
|
|
2283
|
+
const { playNewTrackListFromArtist } = (0, import_genre_tree26.useTrackList)();
|
|
2284
|
+
const { playerTrackObject } = (0, import_player11.usePlayer)();
|
|
2285
|
+
const { data, isPending, isError } = (0, import_transport6.usePlaybackQuery)({
|
|
2232
2286
|
getBackendBaseUrl,
|
|
2233
2287
|
queryKey: ["referenceSongs", "artist", artist.uuid, ordering, page],
|
|
2234
|
-
queryFn: (fetchBound) => fetchBound(
|
|
2288
|
+
queryFn: (fetchBound) => fetchBound(import_genre_tree26.libraryEndpoints.reference.songs.list(), true, false, void 0, {
|
|
2235
2289
|
artist: artist.uuid,
|
|
2236
2290
|
ordering,
|
|
2237
2291
|
page
|
|
@@ -2246,25 +2300,25 @@ function ArtistSongs({ artist, getBackendBaseUrl, renderArtistLink, renderSongLi
|
|
|
2246
2300
|
});
|
|
2247
2301
|
const handleRowClickCapture = (event, song) => {
|
|
2248
2302
|
if (!(event.target instanceof Element) || !event.target.closest(".track-position-play-pause")) return;
|
|
2249
|
-
if (playerTrackObject?.track.id === song.uuid || (0,
|
|
2303
|
+
if (playerTrackObject?.track.id === song.uuid || (0, import_genre_tree26.songUnplayableReason)(song) !== null) return;
|
|
2250
2304
|
event.stopPropagation();
|
|
2251
2305
|
void play(song.uuid);
|
|
2252
2306
|
};
|
|
2253
|
-
return /* @__PURE__ */ (0,
|
|
2254
|
-
/* @__PURE__ */ (0,
|
|
2255
|
-
/* @__PURE__ */ (0,
|
|
2307
|
+
return /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(import_ui16.PanelSection, { title: "Songs", children: isPending ? /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(import_ui16.Skeleton, { className: "h-14", "aria-busy": "true" }) : isError ? /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("p", { className: "text-red-600", children: "Could not load songs." }) : data.results.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("p", { className: "text-[var(--color-text-muted)]", children: "No songs yet." }) : /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)(import_jsx_runtime40.Fragment, { children: [
|
|
2308
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("div", { className: "flex flex-wrap items-center justify-between gap-2 mb-2", children: [
|
|
2309
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsxs)(
|
|
2256
2310
|
"button",
|
|
2257
2311
|
{
|
|
2258
2312
|
type: "button",
|
|
2259
2313
|
onClick: () => void play(),
|
|
2260
2314
|
className: "flex w-fit items-center gap-1.5 px-3 py-1 text-caption font-medium bg-gray-900 text-white rounded-full hover:bg-gray-700",
|
|
2261
2315
|
children: [
|
|
2262
|
-
/* @__PURE__ */ (0,
|
|
2316
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsx)(import_lucide_react12.Play, { className: "h-3.5 w-3.5", "aria-hidden": "true" }),
|
|
2263
2317
|
"Play all"
|
|
2264
2318
|
]
|
|
2265
2319
|
}
|
|
2266
2320
|
),
|
|
2267
|
-
/* @__PURE__ */ (0,
|
|
2321
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsx)("div", { role: "group", "aria-label": "Sort songs by", className: "flex gap-1 text-caption", children: SORTS.map((sort) => /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
|
|
2268
2322
|
"button",
|
|
2269
2323
|
{
|
|
2270
2324
|
type: "button",
|
|
@@ -2279,7 +2333,7 @@ function ArtistSongs({ artist, getBackendBaseUrl, renderArtistLink, renderSongLi
|
|
|
2279
2333
|
sort.ordering
|
|
2280
2334
|
)) })
|
|
2281
2335
|
] }),
|
|
2282
|
-
/* @__PURE__ */ (0,
|
|
2336
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsx)("ul", { className: "overflow-hidden mb-2 bg-zinc-950 rounded-lg", children: data.results.map((song, index) => /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("li", { onClickCapture: (event) => handleRowClickCapture(event, song), children: /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
|
|
2283
2337
|
TrackItem,
|
|
2284
2338
|
{
|
|
2285
2339
|
track: song,
|
|
@@ -2288,12 +2342,12 @@ function ArtistSongs({ artist, getBackendBaseUrl, renderArtistLink, renderSongLi
|
|
|
2288
2342
|
renderSongLink
|
|
2289
2343
|
}
|
|
2290
2344
|
) }, song.uuid)) }),
|
|
2291
|
-
/* @__PURE__ */ (0,
|
|
2345
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsx)(import_ui16.Pagination, { currentPage: page, totalPages: data.totalPages, onPageChange: setPage })
|
|
2292
2346
|
] }) });
|
|
2293
2347
|
}
|
|
2294
2348
|
|
|
2295
2349
|
// src/genre-tree/artist/useArtistPanel.tsx
|
|
2296
|
-
var
|
|
2350
|
+
var import_jsx_runtime41 = require("react/jsx-runtime");
|
|
2297
2351
|
function useArtistPanel({
|
|
2298
2352
|
uuid,
|
|
2299
2353
|
scope,
|
|
@@ -2305,7 +2359,7 @@ function useArtistPanel({
|
|
|
2305
2359
|
onExpandedChange,
|
|
2306
2360
|
onClose
|
|
2307
2361
|
}) {
|
|
2308
|
-
const result = (0,
|
|
2362
|
+
const result = (0, import_genre_tree27.useArtist)(uuid, getBackendBaseUrl);
|
|
2309
2363
|
const panel = { expanded, onExpandedChange, onClose };
|
|
2310
2364
|
switch (result.status) {
|
|
2311
2365
|
case "idle":
|
|
@@ -2314,26 +2368,26 @@ function useArtistPanel({
|
|
|
2314
2368
|
return {
|
|
2315
2369
|
...panel,
|
|
2316
2370
|
title: "Artist",
|
|
2317
|
-
content: /* @__PURE__ */ (0,
|
|
2318
|
-
/* @__PURE__ */ (0,
|
|
2319
|
-
/* @__PURE__ */ (0,
|
|
2320
|
-
/* @__PURE__ */ (0,
|
|
2321
|
-
/* @__PURE__ */ (0,
|
|
2322
|
-
/* @__PURE__ */ (0,
|
|
2323
|
-
/* @__PURE__ */ (0,
|
|
2371
|
+
content: /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { "aria-busy": "true", className: "flex flex-col gap-2.5", children: [
|
|
2372
|
+
/* @__PURE__ */ (0, import_jsx_runtime41.jsx)(import_ui17.Skeleton, { className: "h-3 w-16" }),
|
|
2373
|
+
/* @__PURE__ */ (0, import_jsx_runtime41.jsx)(import_ui17.Skeleton, { className: "h-4 w-32" }),
|
|
2374
|
+
/* @__PURE__ */ (0, import_jsx_runtime41.jsx)(import_ui17.Skeleton, { className: "h-3 w-16" }),
|
|
2375
|
+
/* @__PURE__ */ (0, import_jsx_runtime41.jsx)(import_ui17.Skeleton, { className: "h-4 w-24" }),
|
|
2376
|
+
/* @__PURE__ */ (0, import_jsx_runtime41.jsx)(import_ui17.Skeleton, { className: "h-16 mt-2.5" }),
|
|
2377
|
+
/* @__PURE__ */ (0, import_jsx_runtime41.jsx)(import_ui17.Skeleton, { className: "h-16" })
|
|
2324
2378
|
] })
|
|
2325
2379
|
};
|
|
2326
2380
|
case "not-found":
|
|
2327
2381
|
return {
|
|
2328
2382
|
...panel,
|
|
2329
2383
|
title: "Artist not found",
|
|
2330
|
-
content: /* @__PURE__ */ (0,
|
|
2384
|
+
content: /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("p", { className: "text-[var(--color-text-muted)]", children: "This artist does not exist." })
|
|
2331
2385
|
};
|
|
2332
2386
|
case "error":
|
|
2333
2387
|
return {
|
|
2334
2388
|
...panel,
|
|
2335
2389
|
title: "Artist",
|
|
2336
|
-
content: /* @__PURE__ */ (0,
|
|
2390
|
+
content: /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("p", { className: "text-red-600", children: "Could not load this artist." })
|
|
2337
2391
|
};
|
|
2338
2392
|
case "success": {
|
|
2339
2393
|
const { artist } = result;
|
|
@@ -2342,13 +2396,19 @@ function useArtistPanel({
|
|
|
2342
2396
|
return {
|
|
2343
2397
|
...panel,
|
|
2344
2398
|
title: artist.name,
|
|
2345
|
-
content: /* @__PURE__ */ (0,
|
|
2346
|
-
|
|
2347
|
-
|
|
2348
|
-
|
|
2349
|
-
|
|
2350
|
-
|
|
2351
|
-
|
|
2399
|
+
content: /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)(import_jsx_runtime41.Fragment, { children: [
|
|
2400
|
+
/* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
|
|
2401
|
+
ArtistActionBand,
|
|
2402
|
+
{
|
|
2403
|
+
artist,
|
|
2404
|
+
share: shareTarget && shareUrl ? /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(ShareActionButton, { target: shareTarget, url: shareUrl }) : void 0
|
|
2405
|
+
}
|
|
2406
|
+
),
|
|
2407
|
+
artist.image && /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(ArtistPhoto, { image: artist.image, name: artist.name }),
|
|
2408
|
+
/* @__PURE__ */ (0, import_jsx_runtime41.jsx)(ArtistHeader, { artist }),
|
|
2409
|
+
/* @__PURE__ */ (0, import_jsx_runtime41.jsx)(ArtistMembers, { title: "Members", memberships: artist.members, renderArtistLink }),
|
|
2410
|
+
/* @__PURE__ */ (0, import_jsx_runtime41.jsx)(ArtistMembers, { title: "Member of", memberships: artist.memberOf, renderArtistLink }),
|
|
2411
|
+
artist.tracksCount > 0 && /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
|
|
2352
2412
|
ArtistSongs,
|
|
2353
2413
|
{
|
|
2354
2414
|
artist: { uuid: artist.uuid, name: artist.name },
|
|
@@ -2358,69 +2418,62 @@ function useArtistPanel({
|
|
|
2358
2418
|
}
|
|
2359
2419
|
)
|
|
2360
2420
|
] }),
|
|
2361
|
-
extraContent: artist.albums.length > 0 ? /* @__PURE__ */ (0,
|
|
2421
|
+
extraContent: artist.albums.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(ArtistDiscography, { albums: artist.albums }) : void 0
|
|
2362
2422
|
};
|
|
2363
2423
|
}
|
|
2364
2424
|
}
|
|
2365
2425
|
}
|
|
2366
2426
|
|
|
2367
2427
|
// src/genre-tree/song/useSongPanel.tsx
|
|
2368
|
-
var
|
|
2369
|
-
var
|
|
2428
|
+
var import_ui19 = require("@behindthemusictree/ui");
|
|
2429
|
+
var import_genre_tree29 = require("@behindthemusictree/app-kit/genre-tree");
|
|
2370
2430
|
|
|
2371
2431
|
// src/genre-tree/song/SongPanelContent.tsx
|
|
2372
|
-
var
|
|
2373
|
-
var
|
|
2374
|
-
var
|
|
2375
|
-
var
|
|
2376
|
-
var
|
|
2377
|
-
var
|
|
2432
|
+
var import_react18 = require("react");
|
|
2433
|
+
var import_lucide_react13 = require("lucide-react");
|
|
2434
|
+
var import_ui18 = require("@behindthemusictree/ui");
|
|
2435
|
+
var import_player12 = require("@behindthemusictree/app-kit/player");
|
|
2436
|
+
var import_genre_tree28 = require("@behindthemusictree/app-kit/genre-tree");
|
|
2437
|
+
var import_jsx_runtime42 = require("react/jsx-runtime");
|
|
2378
2438
|
var numberFormat = new Intl.NumberFormat("en");
|
|
2379
2439
|
var dateFormat = new Intl.DateTimeFormat("en", { dateStyle: "medium" });
|
|
2380
2440
|
var externalLink = "text-[var(--color-primary)] hover:underline focus-visible:underline";
|
|
2381
2441
|
function SongHistory({ uuid, getBackendBaseUrl }) {
|
|
2382
|
-
const [open, setOpen] = (0,
|
|
2383
|
-
const history = (0,
|
|
2442
|
+
const [open, setOpen] = (0, import_react18.useState)(false);
|
|
2443
|
+
const history = (0, import_genre_tree28.useSongHistory)(uuid, getBackendBaseUrl, open);
|
|
2384
2444
|
let body = null;
|
|
2385
|
-
if (history.status === "loading") body = /* @__PURE__ */ (0,
|
|
2386
|
-
else if (history.status === "error") body = /* @__PURE__ */ (0,
|
|
2445
|
+
if (history.status === "loading") body = /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(import_ui18.Skeleton, { className: "h-10", "aria-busy": "true" });
|
|
2446
|
+
else if (history.status === "error") body = /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("p", { className: "text-red-600", children: "Could not load the history." });
|
|
2387
2447
|
else if (history.status === "success")
|
|
2388
|
-
body = history.entries.length === 0 ? /* @__PURE__ */ (0,
|
|
2389
|
-
/* @__PURE__ */ (0,
|
|
2390
|
-
entry.oldValue !== null || entry.newValue !== null ? /* @__PURE__ */ (0,
|
|
2448
|
+
body = history.entries.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("p", { className: "text-[var(--color-text-muted)]", children: "No changes yet." }) : /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("ul", { className: "divide-y divide-[var(--color-border)]", children: history.entries.map((entry) => /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("li", { className: "py-1.5 text-body", children: [
|
|
2449
|
+
/* @__PURE__ */ (0, import_jsx_runtime42.jsx)("span", { className: "font-medium", children: entry.action }),
|
|
2450
|
+
entry.oldValue !== null || entry.newValue !== null ? /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("span", { className: "text-[var(--color-text-muted)]", children: [
|
|
2391
2451
|
" ",
|
|
2392
2452
|
"\u2014 ",
|
|
2393
2453
|
entry.oldValue ?? "none",
|
|
2394
2454
|
" \u2192 ",
|
|
2395
2455
|
entry.newValue ?? "none"
|
|
2396
2456
|
] }) : null,
|
|
2397
|
-
/* @__PURE__ */ (0,
|
|
2457
|
+
/* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("span", { className: "block text-caption text-[var(--color-text-muted)]", children: [
|
|
2398
2458
|
entry.actorPseudo ?? "Anonymous",
|
|
2399
2459
|
" \xB7 ",
|
|
2400
2460
|
dateFormat.format(new Date(entry.createdOn))
|
|
2401
2461
|
] })
|
|
2402
2462
|
] }, entry.uuid)) });
|
|
2403
|
-
return /* @__PURE__ */ (0,
|
|
2404
|
-
"
|
|
2405
|
-
{
|
|
2406
|
-
|
|
2407
|
-
className: "px-6 pb-2.5 mt-2.5 border-t border-[var(--color-border)]",
|
|
2408
|
-
children: [
|
|
2409
|
-
/* @__PURE__ */ (0, import_jsx_runtime37.jsx)("summary", { className: "mt-2.5 cursor-pointer text-[0.6875rem] font-semibold uppercase text-[var(--color-text-muted)]", children: "History" }),
|
|
2410
|
-
/* @__PURE__ */ (0, import_jsx_runtime37.jsx)("div", { className: "mt-1.5", children: body })
|
|
2411
|
-
]
|
|
2412
|
-
}
|
|
2413
|
-
);
|
|
2463
|
+
return /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(import_ui18.PanelBleed, { padded: true, className: "border-t border-[var(--color-border)]", children: /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("details", { onToggle: (event) => setOpen(event.currentTarget.open), className: "pb-2.5", children: [
|
|
2464
|
+
/* @__PURE__ */ (0, import_jsx_runtime42.jsx)("summary", { className: `mt-2.5 cursor-pointer ${import_ui18.PANEL_LABEL_CLASS}`, children: "History" }),
|
|
2465
|
+
/* @__PURE__ */ (0, import_jsx_runtime42.jsx)("div", { className: "mt-1.5", children: body })
|
|
2466
|
+
] }) });
|
|
2414
2467
|
}
|
|
2415
2468
|
function SongPanelContent(props) {
|
|
2416
2469
|
const { song, scope, getBackendBaseUrl, shareUrl, renderArtistLink } = props;
|
|
2417
|
-
const { playNewTrackListFromTrackUuid } = (0,
|
|
2418
|
-
const { playerTrackObject, playState, handlePlayPauseAction } = (0,
|
|
2419
|
-
const unplayableReason = (0,
|
|
2470
|
+
const { playNewTrackListFromTrackUuid } = (0, import_genre_tree28.useTrackList)();
|
|
2471
|
+
const { playerTrackObject, playState, handlePlayPauseAction } = (0, import_player12.usePlayer)();
|
|
2472
|
+
const unplayableReason = (0, import_genre_tree28.songUnplayableReason)(song);
|
|
2420
2473
|
const isCurrent = playerTrackObject?.track.id === song.uuid;
|
|
2421
|
-
const isPlaying = isCurrent && playState ===
|
|
2474
|
+
const isPlaying = isCurrent && playState === import_player12.PlayStates.PLAYING;
|
|
2422
2475
|
const shareTarget = { kind: "song", uuid: song.uuid, name: song.title, scope };
|
|
2423
|
-
const musicBrainzUrl = (0,
|
|
2476
|
+
const musicBrainzUrl = (0, import_genre_tree28.musicBrainzRecordingUrl)(song);
|
|
2424
2477
|
const fields = [];
|
|
2425
2478
|
if (song.genre) {
|
|
2426
2479
|
const path = props.genrePath && props.genrePath.length > 0 ? props.genrePath : null;
|
|
@@ -2428,13 +2481,13 @@ function SongPanelContent(props) {
|
|
|
2428
2481
|
const genre = song.genre;
|
|
2429
2482
|
fields.push({
|
|
2430
2483
|
label: "Genre",
|
|
2431
|
-
value: onSelectGenre ? /* @__PURE__ */ (0,
|
|
2432
|
-
index > 0 && /* @__PURE__ */ (0,
|
|
2433
|
-
/* @__PURE__ */ (0,
|
|
2484
|
+
value: onSelectGenre ? /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("button", { type: "button", onClick: () => onSelectGenre(genre), className: "hover:underline", children: genre.name }) : path ? /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("span", { className: "flex flex-wrap items-center gap-x-1", children: path.map((genrePlaylist, index) => /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("span", { children: [
|
|
2485
|
+
index > 0 && /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("span", { "aria-hidden": "true", children: "\u203A " }),
|
|
2486
|
+
/* @__PURE__ */ (0, import_jsx_runtime42.jsx)("button", { type: "button", onClick: () => props.onSelectGenrePlaylist?.(genrePlaylist), className: "hover:underline", children: genrePlaylist.name })
|
|
2434
2487
|
] }, genrePlaylist.uuid)) }) : song.genre.name
|
|
2435
2488
|
});
|
|
2436
2489
|
} else {
|
|
2437
|
-
fields.push({ label: "Genre", value: /* @__PURE__ */ (0,
|
|
2490
|
+
fields.push({ label: "Genre", value: /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("span", { className: "text-[var(--color-text-muted)]", children: "No genre" }) });
|
|
2438
2491
|
}
|
|
2439
2492
|
if (song.firstReleaseYear) fields.push({ label: "First released", value: song.firstReleaseYear });
|
|
2440
2493
|
const viewCount = song.youtubeVideo?.viewCount;
|
|
@@ -2444,11 +2497,11 @@ function SongPanelContent(props) {
|
|
|
2444
2497
|
const links = [];
|
|
2445
2498
|
if (musicBrainzUrl)
|
|
2446
2499
|
links.push(
|
|
2447
|
-
/* @__PURE__ */ (0,
|
|
2500
|
+
/* @__PURE__ */ (0, import_jsx_runtime42.jsx)("a", { href: musicBrainzUrl, target: "_blank", rel: "noopener noreferrer", className: externalLink, children: "MusicBrainz" }, "mb")
|
|
2448
2501
|
);
|
|
2449
2502
|
if (song.youtubeVideo)
|
|
2450
2503
|
links.push(
|
|
2451
|
-
/* @__PURE__ */ (0,
|
|
2504
|
+
/* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
|
|
2452
2505
|
"a",
|
|
2453
2506
|
{
|
|
2454
2507
|
href: `https://www.youtube.com/watch?v=${encodeURIComponent(song.youtubeVideo.id)}`,
|
|
@@ -2463,33 +2516,31 @@ function SongPanelContent(props) {
|
|
|
2463
2516
|
if (links.length > 0)
|
|
2464
2517
|
fields.push({
|
|
2465
2518
|
label: "Links",
|
|
2466
|
-
value: /* @__PURE__ */ (0,
|
|
2519
|
+
value: /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("span", { className: "flex gap-3", children: links })
|
|
2467
2520
|
});
|
|
2468
|
-
return /* @__PURE__ */ (0,
|
|
2469
|
-
/* @__PURE__ */ (0,
|
|
2470
|
-
|
|
2471
|
-
|
|
2521
|
+
return /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)(import_jsx_runtime42.Fragment, { children: [
|
|
2522
|
+
/* @__PURE__ */ (0, import_jsx_runtime42.jsx)(import_ui18.PanelBleed, { children: /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)(import_ui18.ActionBand, { children: [
|
|
2523
|
+
/* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
|
|
2524
|
+
import_ui18.ActionButton,
|
|
2472
2525
|
{
|
|
2473
|
-
|
|
2474
|
-
|
|
2475
|
-
|
|
2476
|
-
|
|
2477
|
-
|
|
2478
|
-
isPlaying ? "Pause" : "Play"
|
|
2479
|
-
]
|
|
2526
|
+
icon: isPlaying ? /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(import_lucide_react13.Pause, { "aria-hidden": "true", className: "w-5 h-5" }) : /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(import_lucide_react13.Play, { "aria-hidden": "true", className: "w-5 h-5" }),
|
|
2527
|
+
label: isPlaying ? "Pause" : "Play",
|
|
2528
|
+
disabled: !!unplayableReason,
|
|
2529
|
+
title: unplayableReason ?? void 0,
|
|
2530
|
+
onClick: () => isCurrent ? handlePlayPauseAction() : playNewTrackListFromTrackUuid(song, scope)
|
|
2480
2531
|
}
|
|
2481
2532
|
),
|
|
2482
|
-
shareUrl && /* @__PURE__ */ (0,
|
|
2533
|
+
shareUrl && /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(ShareActionButton, { target: shareTarget, url: shareUrl })
|
|
2483
2534
|
] }) }),
|
|
2484
|
-
song.artists && song.artists.length > 0 && /* @__PURE__ */ (0,
|
|
2485
|
-
/* @__PURE__ */ (0,
|
|
2486
|
-
song.essentialGenres && song.essentialGenres.length > 0 && /* @__PURE__ */ (0,
|
|
2487
|
-
/* @__PURE__ */ (0,
|
|
2535
|
+
song.artists && song.artists.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("p", { className: "text-[var(--color-text-muted)]", children: /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(import_genre_tree28.ArtistNames, { artists: song.artists, renderArtistLink }) }),
|
|
2536
|
+
/* @__PURE__ */ (0, import_jsx_runtime42.jsx)(import_ui18.FieldList, { items: fields }),
|
|
2537
|
+
song.essentialGenres && song.essentialGenres.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(import_ui18.PanelSection, { title: "Essential in", children: /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("ul", { children: song.essentialGenres.map((genre) => /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("li", { className: "py-0.5", children: genre.name }, genre.uuid)) }) }),
|
|
2538
|
+
/* @__PURE__ */ (0, import_jsx_runtime42.jsx)(SongHistory, { uuid: song.uuid, getBackendBaseUrl })
|
|
2488
2539
|
] });
|
|
2489
2540
|
}
|
|
2490
2541
|
|
|
2491
2542
|
// src/genre-tree/song/useSongPanel.tsx
|
|
2492
|
-
var
|
|
2543
|
+
var import_jsx_runtime43 = require("react/jsx-runtime");
|
|
2493
2544
|
function useSongPanel({
|
|
2494
2545
|
uuid,
|
|
2495
2546
|
scope,
|
|
@@ -2501,7 +2552,7 @@ function useSongPanel({
|
|
|
2501
2552
|
onClose,
|
|
2502
2553
|
...navigation
|
|
2503
2554
|
}) {
|
|
2504
|
-
const result = (0,
|
|
2555
|
+
const result = (0, import_genre_tree29.useSong)(uuid, getBackendBaseUrl);
|
|
2505
2556
|
const panel = { expanded, onExpandedChange, onClose };
|
|
2506
2557
|
switch (result.status) {
|
|
2507
2558
|
case "idle":
|
|
@@ -2510,24 +2561,24 @@ function useSongPanel({
|
|
|
2510
2561
|
return {
|
|
2511
2562
|
...panel,
|
|
2512
2563
|
title: "Song",
|
|
2513
|
-
content: /* @__PURE__ */ (0,
|
|
2514
|
-
/* @__PURE__ */ (0,
|
|
2515
|
-
/* @__PURE__ */ (0,
|
|
2516
|
-
/* @__PURE__ */ (0,
|
|
2517
|
-
/* @__PURE__ */ (0,
|
|
2564
|
+
content: /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("div", { "aria-busy": "true", className: "flex flex-col gap-2.5", children: [
|
|
2565
|
+
/* @__PURE__ */ (0, import_jsx_runtime43.jsx)(import_ui19.Skeleton, { className: "h-3 w-16" }),
|
|
2566
|
+
/* @__PURE__ */ (0, import_jsx_runtime43.jsx)(import_ui19.Skeleton, { className: "h-4 w-32" }),
|
|
2567
|
+
/* @__PURE__ */ (0, import_jsx_runtime43.jsx)(import_ui19.Skeleton, { className: "h-3 w-16" }),
|
|
2568
|
+
/* @__PURE__ */ (0, import_jsx_runtime43.jsx)(import_ui19.Skeleton, { className: "h-4 w-24" })
|
|
2518
2569
|
] })
|
|
2519
2570
|
};
|
|
2520
2571
|
case "not-found":
|
|
2521
2572
|
return {
|
|
2522
2573
|
...panel,
|
|
2523
2574
|
title: "Song not found",
|
|
2524
|
-
content: /* @__PURE__ */ (0,
|
|
2575
|
+
content: /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("p", { className: "text-[var(--color-text-muted)]", children: "This song does not exist." })
|
|
2525
2576
|
};
|
|
2526
2577
|
case "error":
|
|
2527
2578
|
return {
|
|
2528
2579
|
...panel,
|
|
2529
2580
|
title: "Song",
|
|
2530
|
-
content: /* @__PURE__ */ (0,
|
|
2581
|
+
content: /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("p", { className: "text-red-600", children: "Could not load this song." })
|
|
2531
2582
|
};
|
|
2532
2583
|
case "success": {
|
|
2533
2584
|
const { song } = result;
|
|
@@ -2535,7 +2586,7 @@ function useSongPanel({
|
|
|
2535
2586
|
return {
|
|
2536
2587
|
...panel,
|
|
2537
2588
|
title: song.title,
|
|
2538
|
-
content: /* @__PURE__ */ (0,
|
|
2589
|
+
content: /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
|
|
2539
2590
|
SongPanelContent,
|
|
2540
2591
|
{
|
|
2541
2592
|
song,
|
|
@@ -2587,29 +2638,29 @@ function useEntityPanel({
|
|
|
2587
2638
|
|
|
2588
2639
|
// src/genre-tree/SizeMetricToggle.tsx
|
|
2589
2640
|
var import_md = require("react-icons/md");
|
|
2590
|
-
var
|
|
2591
|
-
var
|
|
2641
|
+
var import_ui20 = require("@behindthemusictree/ui");
|
|
2642
|
+
var import_jsx_runtime44 = require("react/jsx-runtime");
|
|
2592
2643
|
function SizeMetricToggle({
|
|
2593
2644
|
value,
|
|
2594
2645
|
onChange
|
|
2595
2646
|
}) {
|
|
2596
|
-
return /* @__PURE__ */ (0,
|
|
2597
|
-
|
|
2647
|
+
return /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
|
|
2648
|
+
import_ui20.SegmentedControl,
|
|
2598
2649
|
{
|
|
2599
2650
|
variant: "floating",
|
|
2600
2651
|
"aria-label": "Size nodes by",
|
|
2601
2652
|
value,
|
|
2602
2653
|
onChange,
|
|
2603
2654
|
options: [
|
|
2604
|
-
{ value: "songs", label: /* @__PURE__ */ (0,
|
|
2605
|
-
{ value: "views", label: /* @__PURE__ */ (0,
|
|
2655
|
+
{ value: "songs", label: /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(import_md.MdMusicNote, { size: 18, "aria-hidden": true }), "aria-label": "Size by songs", title: "Node size by song count" },
|
|
2656
|
+
{ value: "views", label: /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(import_md.MdVisibility, { size: 18, "aria-hidden": true }), "aria-label": "Size by views", title: "Node size by song views" }
|
|
2606
2657
|
]
|
|
2607
2658
|
}
|
|
2608
2659
|
);
|
|
2609
2660
|
}
|
|
2610
2661
|
|
|
2611
2662
|
// src/genre-tree/GenreTreeView.tsx
|
|
2612
|
-
var
|
|
2663
|
+
var import_jsx_runtime45 = require("react/jsx-runtime");
|
|
2613
2664
|
var NO_POP_ROOT_TITLE = "This genre tree has no 'Mainstream Pop' root yet";
|
|
2614
2665
|
var REGIONS_CLASS = "[--gtv-center-left:var(--layout-center-left)] [--gtv-center-right:var(--layout-center-right)] [--gtv-center-top:var(--layout-band-top)]";
|
|
2615
2666
|
var noop = () => {
|
|
@@ -2671,21 +2722,21 @@ function GenreTreeView({
|
|
|
2671
2722
|
placement = "default",
|
|
2672
2723
|
...focus
|
|
2673
2724
|
}) {
|
|
2674
|
-
const getShareUrlRef = (0,
|
|
2725
|
+
const getShareUrlRef = (0, import_react19.useRef)(getShareUrl);
|
|
2675
2726
|
getShareUrlRef.current = getShareUrl;
|
|
2676
|
-
const [internalArtistUuid, setInternalArtistUuid] = (0,
|
|
2727
|
+
const [internalArtistUuid, setInternalArtistUuid] = (0, import_react19.useState)(null);
|
|
2677
2728
|
const isArtistControlled = controlledArtistUuid !== void 0;
|
|
2678
2729
|
const artistUuid = isArtistControlled ? controlledArtistUuid : internalArtistUuid;
|
|
2679
|
-
const [internalSongUuid, setInternalSongUuid] = (0,
|
|
2730
|
+
const [internalSongUuid, setInternalSongUuid] = (0, import_react19.useState)(null);
|
|
2680
2731
|
const isSongControlled = controlledSongUuid !== void 0;
|
|
2681
2732
|
const songUuid = isSongControlled ? controlledSongUuid : internalSongUuid;
|
|
2682
2733
|
const changeSong = (uuid) => {
|
|
2683
2734
|
if (!isSongControlled) setInternalSongUuid(uuid);
|
|
2684
2735
|
onSongUuidChange?.(uuid);
|
|
2685
2736
|
};
|
|
2686
|
-
const [internalSizeMetric, setInternalSizeMetric] = (0,
|
|
2737
|
+
const [internalSizeMetric, setInternalSizeMetric] = (0, import_react19.useState)("songs");
|
|
2687
2738
|
const sizeMetric = controlledSizeMetric ?? internalSizeMetric;
|
|
2688
|
-
const deferredSizeMetric = (0,
|
|
2739
|
+
const deferredSizeMetric = (0, import_react19.useDeferredValue)(sizeMetric);
|
|
2689
2740
|
const changeSizeMetric = (metric) => {
|
|
2690
2741
|
if (controlledSizeMetric === void 0) setInternalSizeMetric(metric);
|
|
2691
2742
|
onSizeMetricChange?.(metric);
|
|
@@ -2701,6 +2752,7 @@ function GenreTreeView({
|
|
|
2701
2752
|
isFetching: isTreeFetching,
|
|
2702
2753
|
genrePlaylistByNodeId,
|
|
2703
2754
|
visibleGenrePlaylists,
|
|
2755
|
+
focusUuids,
|
|
2704
2756
|
groupedGenrePlaylistsByRoot,
|
|
2705
2757
|
selectedGenreUuid,
|
|
2706
2758
|
selectGenre,
|
|
@@ -2716,7 +2768,7 @@ function GenreTreeView({
|
|
|
2716
2768
|
allowWheelRotation: internalAllowWheelRotation,
|
|
2717
2769
|
toggleWheelRotation,
|
|
2718
2770
|
onNodeHover: handleNodeHover
|
|
2719
|
-
} = (0,
|
|
2771
|
+
} = (0, import_genre_tree30.useGenreTreeViewState)({
|
|
2720
2772
|
scope,
|
|
2721
2773
|
getBackendBaseUrl,
|
|
2722
2774
|
viewMode: controlledViewMode,
|
|
@@ -2726,7 +2778,7 @@ function GenreTreeView({
|
|
|
2726
2778
|
artistUuid
|
|
2727
2779
|
});
|
|
2728
2780
|
const restoreRevision = viewportRestore?.revision;
|
|
2729
|
-
const [stackedRestoreOwner, setStackedRestoreOwner] = (0,
|
|
2781
|
+
const [stackedRestoreOwner, setStackedRestoreOwner] = (0, import_react19.useState)({ revision: restoreRevision, rootUuid: selectedGenrePlaylist?.root.uuid });
|
|
2730
2782
|
let restoreRootUuid = stackedRestoreOwner.rootUuid;
|
|
2731
2783
|
if (stackedRestoreOwner.revision !== restoreRevision) {
|
|
2732
2784
|
restoreRootUuid = selectedGenrePlaylist?.root.uuid;
|
|
@@ -2735,14 +2787,14 @@ function GenreTreeView({
|
|
|
2735
2787
|
restoreRootUuid = selectedGenrePlaylist.root.uuid;
|
|
2736
2788
|
setStackedRestoreOwner({ revision: restoreRevision, rootUuid: restoreRootUuid });
|
|
2737
2789
|
}
|
|
2738
|
-
const isGenreUpdating = (0, import_react_query3.useIsMutating)({ mutationKey:
|
|
2739
|
-
const { mutate: updateGenre } = (0,
|
|
2790
|
+
const isGenreUpdating = (0, import_react_query3.useIsMutating)({ mutationKey: import_genre_tree30.genreUpdateMutationKey }) > 0;
|
|
2791
|
+
const { mutate: updateGenre } = (0, import_genre_tree30.useUpdateGenre)(scope, getBackendBaseUrl);
|
|
2740
2792
|
const busy = deferredSizeMetric !== sizeMetric || isTreeFetching || isGenreUpdating;
|
|
2741
2793
|
const isArtistFiltered = artistUuid !== null;
|
|
2742
2794
|
const canSizeByViews = !isArtistFiltered && hasViewsCount(visibleGenrePlaylists);
|
|
2743
|
-
const artistResult = (0,
|
|
2795
|
+
const artistResult = (0, import_genre_tree30.useArtist)(artistUuid, artistSearchBaseUrl ?? getBackendBaseUrl);
|
|
2744
2796
|
const filterArtistName = artistResult.status === "success" ? artistResult.artist.name : null;
|
|
2745
|
-
const filterArtist = (0,
|
|
2797
|
+
const filterArtist = (0, import_react19.useMemo)(
|
|
2746
2798
|
() => artistUuid !== null && filterArtistName !== null ? { uuid: artistUuid, name: filterArtistName } : null,
|
|
2747
2799
|
[artistUuid, filterArtistName]
|
|
2748
2800
|
);
|
|
@@ -2757,17 +2809,17 @@ function GenreTreeView({
|
|
|
2757
2809
|
if (selectedGenreUuid !== null) clearSelection();
|
|
2758
2810
|
changeSong(uuid);
|
|
2759
2811
|
};
|
|
2760
|
-
const openSongRef = (0,
|
|
2812
|
+
const openSongRef = (0, import_react19.useRef)(openSong);
|
|
2761
2813
|
openSongRef.current = openSong;
|
|
2762
|
-
const resolvedRenderSongLink = (0,
|
|
2763
|
-
(song) => renderSongLink ? renderSongLink(song) : /* @__PURE__ */ (0,
|
|
2814
|
+
const resolvedRenderSongLink = (0, import_react19.useCallback)(
|
|
2815
|
+
(song) => renderSongLink ? renderSongLink(song) : /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("button", { type: "button", onClick: () => openSongRef.current(song.uuid), className: "hover:underline", children: song.title }),
|
|
2764
2816
|
[renderSongLink]
|
|
2765
2817
|
);
|
|
2766
|
-
const [expandedSongUuid, setExpandedSongUuid] = (0,
|
|
2767
|
-
const [expandedArtistUuid, setExpandedArtistUuid] = (0,
|
|
2818
|
+
const [expandedSongUuid, setExpandedSongUuid] = (0, import_react19.useState)(null);
|
|
2819
|
+
const [expandedArtistUuid, setExpandedArtistUuid] = (0, import_react19.useState)(null);
|
|
2768
2820
|
const artistBaseUrl = artistSearchBaseUrl ?? getBackendBaseUrl;
|
|
2769
2821
|
const songBaseUrl = getBackendBaseUrl;
|
|
2770
|
-
const resolvedRenderArtistLink = renderArtistLink ?? ((artist) => artist.isSpecialPurpose ? artist.name : /* @__PURE__ */ (0,
|
|
2822
|
+
const resolvedRenderArtistLink = renderArtistLink ?? ((artist) => artist.isSpecialPurpose ? artist.name : /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("button", { type: "button", onClick: () => openArtist(artist.uuid), className: "hover:underline", children: artist.name }));
|
|
2771
2823
|
const getGenrePath = (genre) => {
|
|
2772
2824
|
const path = [];
|
|
2773
2825
|
let current = visibleGenrePlaylists.find((playlist) => playlist.criteria?.uuid === genre.uuid);
|
|
@@ -2809,9 +2861,9 @@ function GenreTreeView({
|
|
|
2809
2861
|
selectGenrePlaylist(genrePlaylist2);
|
|
2810
2862
|
}
|
|
2811
2863
|
});
|
|
2812
|
-
const
|
|
2813
|
-
const [uncontrolledCollapsed, setUncontrolledCollapsed] = (0,
|
|
2814
|
-
const [uncontrolledExpanded, setUncontrolledExpanded] = (0,
|
|
2864
|
+
const otherPanel = overlayPanel ?? (selectedGenreUuid !== null ? void 0 : entityPanel);
|
|
2865
|
+
const [uncontrolledCollapsed, setUncontrolledCollapsed] = (0, import_react19.useState)(false);
|
|
2866
|
+
const [uncontrolledExpanded, setUncontrolledExpanded] = (0, import_react19.useState)(false);
|
|
2815
2867
|
const isCollapsed = collapsed ?? uncontrolledCollapsed;
|
|
2816
2868
|
const isExpanded = expanded ?? uncontrolledExpanded;
|
|
2817
2869
|
const changeCollapsed = (next) => {
|
|
@@ -2822,33 +2874,33 @@ function GenreTreeView({
|
|
|
2822
2874
|
setUncontrolledExpanded(next);
|
|
2823
2875
|
onExpandedChange?.(next);
|
|
2824
2876
|
};
|
|
2825
|
-
(0,
|
|
2877
|
+
(0, import_react19.useEffect)(() => {
|
|
2826
2878
|
setUncontrolledCollapsed(false);
|
|
2827
2879
|
}, [selectedGenreUuid, artistUuid, songUuid]);
|
|
2828
|
-
const [isWheelRevealed, setIsWheelRevealed] = (0,
|
|
2880
|
+
const [isWheelRevealed, setIsWheelRevealed] = (0, import_react19.useState)(false);
|
|
2829
2881
|
const usesHandoff = viewMode === "wheel" || viewMode === "pop-core";
|
|
2830
2882
|
const isTreeReady = !isLoading && !isError && (!usesHandoff || isWheelRevealed);
|
|
2831
|
-
const [resolveStyle, setResolveStyle] = (0,
|
|
2832
|
-
const handleNodeStyleResolverChange = (0,
|
|
2883
|
+
const [resolveStyle, setResolveStyle] = (0, import_react19.useState)(null);
|
|
2884
|
+
const handleNodeStyleResolverChange = (0, import_react19.useCallback)(
|
|
2833
2885
|
(resolver) => setResolveStyle(() => resolver),
|
|
2834
2886
|
[]
|
|
2835
2887
|
);
|
|
2836
|
-
const panelRef = (0,
|
|
2837
|
-
const obscuredInset = (0,
|
|
2888
|
+
const panelRef = (0, import_react19.useRef)(null);
|
|
2889
|
+
const obscuredInset = (0, import_ui21.useObscuredInset)(panelRef);
|
|
2838
2890
|
const hostPanel = { obscuredInset, onNodeStyleResolverChange: handleNodeStyleResolverChange };
|
|
2839
2891
|
const nodeMetric = isArtistFiltered || !canSizeByViews ? "songs" : deferredSizeMetric;
|
|
2840
|
-
const treeNodes = (0,
|
|
2892
|
+
const treeNodes = (0, import_react19.useMemo)(() => toTreeNodes(visibleGenrePlaylists, nodeMetric, focusUuids), [visibleGenrePlaylists, nodeMetric, focusUuids]);
|
|
2841
2893
|
const relations = (0, import_genre_tree_view5.useGenreNodeRelations)(
|
|
2842
2894
|
treeNodes,
|
|
2843
2895
|
!overlayPanel && hasSelectedGenreNode ? selectedNodeId : null,
|
|
2844
2896
|
resolveStyle
|
|
2845
2897
|
);
|
|
2846
|
-
const [selectionHistory, setSelectionHistory] = (0,
|
|
2898
|
+
const [selectionHistory, setSelectionHistory] = (0, import_react19.useState)({ current: selectedGenreUuid, previous: null });
|
|
2847
2899
|
if (selectionHistory.current !== selectedGenreUuid) {
|
|
2848
2900
|
setSelectionHistory({ current: selectedGenreUuid, previous: selectionHistory.current ?? selectionHistory.previous });
|
|
2849
2901
|
}
|
|
2850
2902
|
const handlePrevious = selectionHistory.previous ? () => selectGenre(selectionHistory.previous) : void 0;
|
|
2851
|
-
const { showPopup, hidePopup } = (0,
|
|
2903
|
+
const { showPopup, hidePopup } = (0, import_popup4.usePopup)();
|
|
2852
2904
|
const reopenPanel = () => {
|
|
2853
2905
|
setUncontrolledCollapsed(false);
|
|
2854
2906
|
onCollapsedChange?.(false);
|
|
@@ -2869,7 +2921,7 @@ function GenreTreeView({
|
|
|
2869
2921
|
const handleGenreSearchZoomIn = () => {
|
|
2870
2922
|
if (selectedUuid) focus.onFocusGenreChange?.(selectedUuid, "zoom-in");
|
|
2871
2923
|
};
|
|
2872
|
-
const zoomInRef = (0,
|
|
2924
|
+
const zoomInRef = (0, import_react19.useRef)(void 0);
|
|
2873
2925
|
zoomInRef.current = canZoomIn ? handleGenreSearchZoomIn : void 0;
|
|
2874
2926
|
const genrePlaylist = selectedGenrePlaylist;
|
|
2875
2927
|
const criteria = genrePlaylist?.criteria;
|
|
@@ -2888,6 +2940,7 @@ function GenreTreeView({
|
|
|
2888
2940
|
selectGenre(uuid);
|
|
2889
2941
|
},
|
|
2890
2942
|
expanded: isExpanded,
|
|
2943
|
+
treeRelations: relations,
|
|
2891
2944
|
playback,
|
|
2892
2945
|
genrePlaylist: selectedGenrePlaylist,
|
|
2893
2946
|
band: {
|
|
@@ -2898,7 +2951,7 @@ function GenreTreeView({
|
|
|
2898
2951
|
onAddChild: readOnly || !criteria ? void 0 : () => handleGenreCreationAction(criteria),
|
|
2899
2952
|
onRename: readOnly || !criteria ? void 0 : () => handleGenreRenameAction(criteria),
|
|
2900
2953
|
onChangeParent: readOnly || !genrePlaylist || !criteria ? void 0 : () => showPopup(
|
|
2901
|
-
/* @__PURE__ */ (0,
|
|
2954
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
|
|
2902
2955
|
ChangeParentPopup,
|
|
2903
2956
|
{
|
|
2904
2957
|
genrePlaylist: { ...genrePlaylist, criteria },
|
|
@@ -2932,15 +2985,15 @@ function GenreTreeView({
|
|
|
2932
2985
|
const isRotationControlled = controlledAllowWheelRotation !== void 0;
|
|
2933
2986
|
const allowWheelRotation = controlledAllowWheelRotation ?? internalAllowWheelRotation;
|
|
2934
2987
|
let activePanel = null;
|
|
2935
|
-
if (
|
|
2988
|
+
if (otherPanel) {
|
|
2936
2989
|
activePanel = {
|
|
2937
|
-
title:
|
|
2938
|
-
content:
|
|
2939
|
-
aside:
|
|
2940
|
-
expanded:
|
|
2941
|
-
onExpandedChange:
|
|
2942
|
-
onClose:
|
|
2943
|
-
|
|
2990
|
+
title: otherPanel.title,
|
|
2991
|
+
content: otherPanel.content,
|
|
2992
|
+
aside: otherPanel.extraContent,
|
|
2993
|
+
expanded: otherPanel.expanded ?? false,
|
|
2994
|
+
onExpandedChange: otherPanel.onExpandedChange,
|
|
2995
|
+
onClose: otherPanel.onClose,
|
|
2996
|
+
searchName: otherPanel.title
|
|
2944
2997
|
};
|
|
2945
2998
|
} else if (selectedGenreUuid) {
|
|
2946
2999
|
activePanel = {
|
|
@@ -2950,18 +3003,8 @@ function GenreTreeView({
|
|
|
2950
3003
|
expanded: isExpanded,
|
|
2951
3004
|
onExpandedChange: changeExpanded,
|
|
2952
3005
|
onClose: clearSelection,
|
|
2953
|
-
|
|
2954
|
-
headerAccent:
|
|
2955
|
-
};
|
|
2956
|
-
} else if (builtInPanel) {
|
|
2957
|
-
activePanel = {
|
|
2958
|
-
title: builtInPanel.title,
|
|
2959
|
-
content: builtInPanel.content,
|
|
2960
|
-
aside: builtInPanel.extraContent,
|
|
2961
|
-
expanded: builtInPanel.expanded,
|
|
2962
|
-
onExpandedChange: builtInPanel.onExpandedChange,
|
|
2963
|
-
onClose: builtInPanel.onClose,
|
|
2964
|
-
titleInSearch: true
|
|
3006
|
+
searchName: genreContent.name,
|
|
3007
|
+
headerAccent: genreContent.headerAccent
|
|
2965
3008
|
};
|
|
2966
3009
|
}
|
|
2967
3010
|
const isPanelShown = activePanel !== null && (selectedGenreUuid !== null || isTreeReady);
|
|
@@ -2969,19 +3012,19 @@ function GenreTreeView({
|
|
|
2969
3012
|
edge: activePanel.expanded ? { label: "Shrink panel", onClick: () => activePanel.onExpandedChange?.(false) } : isCollapsed ? null : { label: "Hide panel", onClick: () => changeCollapsed(true) },
|
|
2970
3013
|
center: activePanel.expanded ? null : isCollapsed ? { label: "Show panel", onClick: () => changeCollapsed(false) } : activePanel.onExpandedChange ? { label: "Extend panel", onClick: () => activePanel.onExpandedChange?.(true) } : null
|
|
2971
3014
|
} : void 0;
|
|
2972
|
-
const expandButton = placement === "default" && activePanel?.onExpandedChange ? /* @__PURE__ */ (0,
|
|
2973
|
-
|
|
3015
|
+
const expandButton = placement === "default" && activePanel?.onExpandedChange ? /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
|
|
3016
|
+
import_ui21.IconButton,
|
|
2974
3017
|
{
|
|
2975
3018
|
"aria-label": activePanel.expanded ? "Shrink panel" : "Extend panel",
|
|
2976
3019
|
style: activePanel.headerAccent && { color: "inherit" },
|
|
2977
3020
|
onClick: () => activePanel.onExpandedChange?.(!activePanel.expanded),
|
|
2978
|
-
children: activePanel.expanded ? /* @__PURE__ */ (0,
|
|
3021
|
+
children: activePanel.expanded ? /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(import_lucide_react15.Minimize2, { "aria-hidden": "true", className: "h-4 w-4" }) : /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(import_lucide_react15.Maximize2, { "aria-hidden": "true", className: "h-4 w-4" })
|
|
2979
3022
|
}
|
|
2980
3023
|
) : null;
|
|
2981
3024
|
const renderArtistFilter = () => {
|
|
2982
3025
|
if (isLoading || !filterArtist) return null;
|
|
2983
|
-
return /* @__PURE__ */ (0,
|
|
2984
|
-
/* @__PURE__ */ (0,
|
|
3026
|
+
return /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("span", { className: "inline-flex items-center overflow-hidden rounded-full bg-[var(--color-neutral-100)] text-body", children: [
|
|
3027
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
|
|
2985
3028
|
"button",
|
|
2986
3029
|
{
|
|
2987
3030
|
type: "button",
|
|
@@ -2993,7 +3036,7 @@ function GenreTreeView({
|
|
|
2993
3036
|
children: filterArtist.name
|
|
2994
3037
|
}
|
|
2995
3038
|
),
|
|
2996
|
-
/* @__PURE__ */ (0,
|
|
3039
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
|
|
2997
3040
|
"button",
|
|
2998
3041
|
{
|
|
2999
3042
|
type: "button",
|
|
@@ -3005,8 +3048,8 @@ function GenreTreeView({
|
|
|
3005
3048
|
)
|
|
3006
3049
|
] });
|
|
3007
3050
|
};
|
|
3008
|
-
const actions = /* @__PURE__ */ (0,
|
|
3009
|
-
!isLoading && !isError && /* @__PURE__ */ (0,
|
|
3051
|
+
const actions = /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)(import_jsx_runtime45.Fragment, { children: [
|
|
3052
|
+
!isLoading && !isError && /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
|
|
3010
3053
|
GenreTreeSearch,
|
|
3011
3054
|
{
|
|
3012
3055
|
artistBaseUrl,
|
|
@@ -3029,9 +3072,9 @@ function GenreTreeView({
|
|
|
3029
3072
|
if (songUuid) changeSong(null);
|
|
3030
3073
|
selectGenre(uuid);
|
|
3031
3074
|
},
|
|
3032
|
-
selectedName:
|
|
3075
|
+
selectedName: activePanel?.searchName ?? null,
|
|
3033
3076
|
onClear: activePanel?.onClose,
|
|
3034
|
-
showClear: activePanel
|
|
3077
|
+
showClear: activePanel !== null,
|
|
3035
3078
|
clearLabel: "Close panel",
|
|
3036
3079
|
onPrevious: handlePrevious,
|
|
3037
3080
|
onQueryChange: onSearchQueryChange,
|
|
@@ -3039,10 +3082,10 @@ function GenreTreeView({
|
|
|
3039
3082
|
extraGroups: extraSearchGroups
|
|
3040
3083
|
}
|
|
3041
3084
|
),
|
|
3042
|
-
!isLoading && !isError && filterArtist && /* @__PURE__ */ (0,
|
|
3043
|
-
/* @__PURE__ */ (0,
|
|
3044
|
-
!isLoading && !isError && !isControlled && /* @__PURE__ */ (0,
|
|
3045
|
-
|
|
3085
|
+
!isLoading && !isError && filterArtist && /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("div", { className: "hidden w-full justify-center max-md:flex", children: renderArtistFilter() }),
|
|
3086
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("div", { className: "contents max-md:flex max-md:w-full max-md:items-center max-md:gap-2 max-md:overflow-x-auto max-md:[scrollbar-width:none] max-md:[&>*]:shrink-0", children: [
|
|
3087
|
+
!isLoading && !isError && !isControlled && /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
|
|
3088
|
+
import_ui21.SegmentedControl,
|
|
3046
3089
|
{
|
|
3047
3090
|
"aria-label": "Tree view mode",
|
|
3048
3091
|
value: viewMode,
|
|
@@ -3055,14 +3098,14 @@ function GenreTreeView({
|
|
|
3055
3098
|
]
|
|
3056
3099
|
}
|
|
3057
3100
|
),
|
|
3058
|
-
!isLoading && !isError && showDisplayOptions && /* @__PURE__ */ (0,
|
|
3101
|
+
!isLoading && !isError && showDisplayOptions && /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
|
|
3059
3102
|
"div",
|
|
3060
3103
|
{
|
|
3061
3104
|
className: "flex items-center gap-1",
|
|
3062
3105
|
role: "group",
|
|
3063
3106
|
"aria-label": "Tree display options",
|
|
3064
|
-
children: !isRotationControlled && viewMode !== "stacked" && viewMode !== "outline" && /* @__PURE__ */ (0,
|
|
3065
|
-
|
|
3107
|
+
children: !isRotationControlled && viewMode !== "stacked" && viewMode !== "outline" && /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
|
|
3108
|
+
import_ui21.Button,
|
|
3066
3109
|
{
|
|
3067
3110
|
variant: allowWheelRotation ? "default" : "outline",
|
|
3068
3111
|
size: "sm",
|
|
@@ -3072,52 +3115,53 @@ function GenreTreeView({
|
|
|
3072
3115
|
)
|
|
3073
3116
|
}
|
|
3074
3117
|
),
|
|
3075
|
-
!isLoading && !isError && !readOnly && showAddRoot && /* @__PURE__ */ (0,
|
|
3076
|
-
|
|
3118
|
+
!isLoading && !isError && !readOnly && showAddRoot && /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
|
|
3119
|
+
import_ui21.IconTextButton,
|
|
3077
3120
|
{
|
|
3078
|
-
icon:
|
|
3121
|
+
icon: import_lucide_react14.Plus,
|
|
3079
3122
|
text: "Add root",
|
|
3080
3123
|
onClick: () => handleGenreCreationAction(null)
|
|
3081
3124
|
}
|
|
3082
3125
|
)
|
|
3083
3126
|
] })
|
|
3084
3127
|
] });
|
|
3085
|
-
return /* @__PURE__ */ (0,
|
|
3128
|
+
return /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)(
|
|
3086
3129
|
"div",
|
|
3087
3130
|
{
|
|
3088
3131
|
"data-left-panel": isPanelShown && !isCollapsed ? void 0 : "hidden",
|
|
3089
3132
|
className: ["genre-tree-view relative flex flex-col h-full", placement === "regions" && REGIONS_CLASS, className2].filter(Boolean).join(" "),
|
|
3090
3133
|
children: [
|
|
3091
|
-
/* @__PURE__ */ (0,
|
|
3134
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
|
|
3092
3135
|
"div",
|
|
3093
3136
|
{
|
|
3094
3137
|
className: `actions-container absolute z-30 flex items-center gap-2 ${placement === "regions" ? "left-[calc(var(--layout-gutter)+var(--layout-panel-inset))] top-[calc(var(--layout-gutter)+var(--layout-panel-inset))] md:left-[var(--layout-panel-inset)] md:top-[var(--layout-panel-inset)] max-md:right-[calc(var(--layout-gutter)+var(--layout-panel-inset))] max-md:top-[var(--layout-band-top)] max-md:flex-col max-md:items-stretch" : "left-5 top-5"}`,
|
|
3095
3138
|
children: actions
|
|
3096
3139
|
}
|
|
3097
3140
|
),
|
|
3098
|
-
!isLoading && !isError && filterArtist && /* @__PURE__ */ (0,
|
|
3141
|
+
!isLoading && !isError && filterArtist && /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
|
|
3099
3142
|
"div",
|
|
3100
3143
|
{
|
|
3101
3144
|
className: `absolute left-1/2 z-30 hidden -translate-x-1/2 md:block ${placement === "regions" ? "top-[calc(var(--layout-gutter)+var(--layout-panel-inset))] md:top-[var(--layout-panel-inset)]" : "top-5"}`,
|
|
3102
3145
|
children: renderArtistFilter()
|
|
3103
3146
|
}
|
|
3104
3147
|
),
|
|
3105
|
-
/* @__PURE__ */ (0,
|
|
3106
|
-
!isLoading && !isError && viewMode === "outline" && floatingControlsLeading && /* @__PURE__ */ (0,
|
|
3107
|
-
isLoading ? /* @__PURE__ */ (0,
|
|
3148
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)("div", { className: "content-container flex-1 min-h-0 flex flex-row gap-4", children: /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("div", { className: "tree-view-container relative flex-1 min-w-0 flex flex-col h-full", children: [
|
|
3149
|
+
!isLoading && !isError && viewMode === "outline" && floatingControlsLeading && /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("div", { className: "absolute bottom-3 right-3 z-10", children: floatingControlsLeading }),
|
|
3150
|
+
isLoading ? /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(import_genre_tree_view5.GenreTreeViewSkeleton, { viewMode }) : isError ? /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("p", { role: "alert", className: "m-auto text-center", children: [
|
|
3108
3151
|
"Couldn't load the genre tree.",
|
|
3109
3152
|
" ",
|
|
3110
|
-
/* @__PURE__ */ (0,
|
|
3153
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)("button", { type: "button", className: "underline", onClick: refetch, children: "Retry" })
|
|
3111
3154
|
] }) : viewMode === "wheel" ? (
|
|
3112
3155
|
// The info panel's top edge aligns with the tree's; the search bar floats `--layout-panel-inset` below it,
|
|
3113
3156
|
// and the header inset (the bar's height plus that inset) extends the header's fill behind the bar,
|
|
3114
3157
|
// Google Maps style; the 8px bottom padding mirrors the inset above the bar, and the hidden title's height is zeroed.
|
|
3115
3158
|
// The panel's own Zoom in button is hidden: the search bar carries it.
|
|
3116
|
-
/* @__PURE__ */ (0,
|
|
3159
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)("div", { className: "tree-container search-overlay relative flex-1 w-full min-h-0 ", children: /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(GenreTreeWheelHandoff, { skeleton: /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(import_genre_tree_view5.GenreTreeWheelSkeleton, {}), onRevealedChange: setIsWheelRevealed, children: /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
|
|
3117
3160
|
GenrePlaylistTreeWheel,
|
|
3118
3161
|
{
|
|
3119
3162
|
scope,
|
|
3120
3163
|
genrePlaylists: visibleGenrePlaylists,
|
|
3164
|
+
focusUuids,
|
|
3121
3165
|
handleGenreCreationAction,
|
|
3122
3166
|
handleGenreRenameAction,
|
|
3123
3167
|
additionalActions,
|
|
@@ -3130,9 +3174,9 @@ function GenreTreeView({
|
|
|
3130
3174
|
allowWheelRotation,
|
|
3131
3175
|
sizeMetric: isArtistFiltered || !canSizeByViews ? "songs" : deferredSizeMetric,
|
|
3132
3176
|
busy,
|
|
3133
|
-
floatingControlsLeading: floatingControlsLeading || canSizeByViews ? /* @__PURE__ */ (0,
|
|
3177
|
+
floatingControlsLeading: floatingControlsLeading || canSizeByViews ? /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("div", { className: "flex items-center gap-2", children: [
|
|
3134
3178
|
floatingControlsLeading,
|
|
3135
|
-
canSizeByViews && /* @__PURE__ */ (0,
|
|
3179
|
+
canSizeByViews && /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(SizeMetricToggle, { value: sizeMetric, onChange: changeSizeMetric })
|
|
3136
3180
|
] }) : void 0,
|
|
3137
3181
|
defaultViewport,
|
|
3138
3182
|
viewportRestore,
|
|
@@ -3141,11 +3185,12 @@ function GenreTreeView({
|
|
|
3141
3185
|
) }) })
|
|
3142
3186
|
) : viewMode === "pop-core" ? (
|
|
3143
3187
|
// Same as the wheel: the header inset extends its fill behind the floating search bar, Google Maps style.
|
|
3144
|
-
/* @__PURE__ */ (0,
|
|
3188
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)("div", { className: "tree-container search-overlay relative flex-1 w-full min-h-0 ", children: /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(GenreTreeWheelHandoff, { skeleton: /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(import_genre_tree_view5.GenreTreeWheelSkeleton, {}), onRevealedChange: setIsWheelRevealed, children: /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
|
|
3145
3189
|
GenrePlaylistTreeWheelRadialPopCore,
|
|
3146
3190
|
{
|
|
3147
3191
|
scope,
|
|
3148
3192
|
genrePlaylists: visibleGenrePlaylists,
|
|
3193
|
+
focusUuids,
|
|
3149
3194
|
handleGenreCreationAction,
|
|
3150
3195
|
handleGenreRenameAction,
|
|
3151
3196
|
additionalActions,
|
|
@@ -3158,9 +3203,9 @@ function GenreTreeView({
|
|
|
3158
3203
|
allowWheelRotation,
|
|
3159
3204
|
sizeMetric: isArtistFiltered || !canSizeByViews ? "songs" : deferredSizeMetric,
|
|
3160
3205
|
busy,
|
|
3161
|
-
floatingControlsLeading: floatingControlsLeading || canSizeByViews ? /* @__PURE__ */ (0,
|
|
3206
|
+
floatingControlsLeading: floatingControlsLeading || canSizeByViews ? /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("div", { className: "flex items-center gap-2", children: [
|
|
3162
3207
|
floatingControlsLeading,
|
|
3163
|
-
canSizeByViews && /* @__PURE__ */ (0,
|
|
3208
|
+
canSizeByViews && /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(SizeMetricToggle, { value: sizeMetric, onChange: changeSizeMetric })
|
|
3164
3209
|
] }) : void 0,
|
|
3165
3210
|
defaultViewport,
|
|
3166
3211
|
viewportRestore,
|
|
@@ -3168,12 +3213,13 @@ function GenreTreeView({
|
|
|
3168
3213
|
...focus
|
|
3169
3214
|
}
|
|
3170
3215
|
) }) })
|
|
3171
|
-
) : viewMode === "outline" ? /* @__PURE__ */ (0,
|
|
3216
|
+
) : viewMode === "outline" ? /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("div", { className: "tree-container flex-1 min-h-0 w-full overflow-y-auto relative", children: /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
|
|
3172
3217
|
GenrePlaylistTreeWheelRadialPopCore,
|
|
3173
3218
|
{
|
|
3174
3219
|
outline: true,
|
|
3175
3220
|
scope,
|
|
3176
3221
|
genrePlaylists: visibleGenrePlaylists,
|
|
3222
|
+
focusUuids,
|
|
3177
3223
|
handleGenreCreationAction,
|
|
3178
3224
|
handleGenreRenameAction,
|
|
3179
3225
|
additionalActions,
|
|
@@ -3184,13 +3230,13 @@ function GenreTreeView({
|
|
|
3184
3230
|
selectedNodeId,
|
|
3185
3231
|
readOnly
|
|
3186
3232
|
}
|
|
3187
|
-
) }) : /* @__PURE__ */ (0,
|
|
3233
|
+
) }) : /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("div", { className: "tree-container relative flex flex-col gap-4 w-full pt-14 overflow-x-auto overflow-y-auto text-[var(--color-text)]", children: Object.entries(groupedGenrePlaylistsByRoot).map(
|
|
3188
3234
|
([uuid, genrePlaylistTreePerRoot]) => {
|
|
3189
|
-
return /* @__PURE__ */ (0,
|
|
3235
|
+
return /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
|
|
3190
3236
|
"div",
|
|
3191
3237
|
{
|
|
3192
3238
|
className: "tree-per-root-container relative shrink-0 h-[28rem] mt-2 mr-16 p-2 bg-[var(--color-neutral-100)] rounded-lg",
|
|
3193
|
-
children: /* @__PURE__ */ (0,
|
|
3239
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("div", { className: "graph-container relative z-10 h-full", children: /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
|
|
3194
3240
|
GenrePlaylistTreePerRoot,
|
|
3195
3241
|
{
|
|
3196
3242
|
scope,
|
|
@@ -3203,6 +3249,7 @@ function GenreTreeView({
|
|
|
3203
3249
|
onNodeHover: handleNodeHover,
|
|
3204
3250
|
...hostPanel,
|
|
3205
3251
|
playback,
|
|
3252
|
+
focusUuids,
|
|
3206
3253
|
selectedNodeId: uuid === selectedGenrePlaylist?.root.uuid ? selectedNodeId : null,
|
|
3207
3254
|
readOnly,
|
|
3208
3255
|
wheelZoom: "modifier",
|
|
@@ -3216,13 +3263,13 @@ function GenreTreeView({
|
|
|
3216
3263
|
);
|
|
3217
3264
|
}
|
|
3218
3265
|
) }),
|
|
3219
|
-
/* @__PURE__ */ (0,
|
|
3220
|
-
|
|
3266
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
|
|
3267
|
+
import_ui21.DetailPanel,
|
|
3221
3268
|
{
|
|
3222
3269
|
ref: panelRef,
|
|
3223
3270
|
side: "left",
|
|
3224
3271
|
title: activePanel?.title ?? "",
|
|
3225
|
-
titleInSearch:
|
|
3272
|
+
titleInSearch: !isLoading && !isError,
|
|
3226
3273
|
headerAccent: activePanel?.headerAccent,
|
|
3227
3274
|
headerActions: expandButton,
|
|
3228
3275
|
onClose: activePanel?.onClose ?? noop,
|
|
@@ -3231,8 +3278,7 @@ function GenreTreeView({
|
|
|
3231
3278
|
onExpandedChange: activePanel?.onExpandedChange,
|
|
3232
3279
|
aside: activePanel?.aside,
|
|
3233
3280
|
edgeTab: detailTab,
|
|
3234
|
-
|
|
3235
|
-
children: activePanel?.aside && !activePanel.expanded ? /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)(import_jsx_runtime40.Fragment, { children: [
|
|
3281
|
+
children: activePanel?.aside && !activePanel.expanded ? /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)(import_jsx_runtime45.Fragment, { children: [
|
|
3236
3282
|
activePanel.content,
|
|
3237
3283
|
activePanel.aside
|
|
3238
3284
|
] }) : activePanel?.content
|
|
@@ -3248,13 +3294,13 @@ function GenreTreeView({
|
|
|
3248
3294
|
var import_genre_tree_view6 = require("@behindthemusictree/genre-tree-view");
|
|
3249
3295
|
|
|
3250
3296
|
// src/genre-tree/track-list-sidebar/TrackListSidebar.tsx
|
|
3251
|
-
var
|
|
3252
|
-
var
|
|
3253
|
-
var
|
|
3254
|
-
var
|
|
3255
|
-
var
|
|
3256
|
-
var
|
|
3257
|
-
var useBrowserLayoutEffect = typeof window === "undefined" ?
|
|
3297
|
+
var import_react20 = require("react");
|
|
3298
|
+
var import_lucide_react16 = require("lucide-react");
|
|
3299
|
+
var import_genre_tree31 = require("@behindthemusictree/app-kit/genre-tree");
|
|
3300
|
+
var import_genre_tree32 = require("@behindthemusictree/app-kit/genre-tree");
|
|
3301
|
+
var import_track_noun3 = require("@behindthemusictree/app-kit/track-noun");
|
|
3302
|
+
var import_jsx_runtime46 = require("react/jsx-runtime");
|
|
3303
|
+
var useBrowserLayoutEffect = typeof window === "undefined" ? import_react20.useEffect : import_react20.useLayoutEffect;
|
|
3258
3304
|
function TrackListSidebar({
|
|
3259
3305
|
className: className2 = "",
|
|
3260
3306
|
renderDuration,
|
|
@@ -3266,18 +3312,18 @@ function TrackListSidebar({
|
|
|
3266
3312
|
renderArtistLink,
|
|
3267
3313
|
renderSongLink
|
|
3268
3314
|
}) {
|
|
3269
|
-
const { trackList, loadMore, autoAdvanceScrollRequest } = (0,
|
|
3270
|
-
const trackNoun = (0,
|
|
3271
|
-
const trackListRef = (0,
|
|
3272
|
-
const previousOriginRef = (0,
|
|
3273
|
-
const handledAutoAdvanceRequestIdRef = (0,
|
|
3274
|
-
const shouldFollowPlaybackRef = (0,
|
|
3275
|
-
const programmaticScrollTopRef = (0,
|
|
3276
|
-
const userScrollIntentRef = (0,
|
|
3277
|
-
const userScrollIntentTimerRef = (0,
|
|
3278
|
-
const loadMoreSentinelRef = (0,
|
|
3315
|
+
const { trackList, loadMore, autoAdvanceScrollRequest } = (0, import_genre_tree31.useTrackList)();
|
|
3316
|
+
const trackNoun = (0, import_track_noun3.useTrackNoun)();
|
|
3317
|
+
const trackListRef = (0, import_react20.useRef)(null);
|
|
3318
|
+
const previousOriginRef = (0, import_react20.useRef)(trackList?.origin ?? null);
|
|
3319
|
+
const handledAutoAdvanceRequestIdRef = (0, import_react20.useRef)(null);
|
|
3320
|
+
const shouldFollowPlaybackRef = (0, import_react20.useRef)(true);
|
|
3321
|
+
const programmaticScrollTopRef = (0, import_react20.useRef)(null);
|
|
3322
|
+
const userScrollIntentRef = (0, import_react20.useRef)(false);
|
|
3323
|
+
const userScrollIntentTimerRef = (0, import_react20.useRef)(null);
|
|
3324
|
+
const loadMoreSentinelRef = (0, import_react20.useRef)(null);
|
|
3279
3325
|
const hasMore = !!trackList && trackList.nextPage !== null;
|
|
3280
|
-
(0,
|
|
3326
|
+
(0, import_react20.useEffect)(() => {
|
|
3281
3327
|
const sentinel = loadMoreSentinelRef.current;
|
|
3282
3328
|
if (!hasMore || !sentinel) return;
|
|
3283
3329
|
const observer = new IntersectionObserver((entries) => {
|
|
@@ -3297,11 +3343,11 @@ function TrackListSidebar({
|
|
|
3297
3343
|
programmaticScrollTopRef.current = null;
|
|
3298
3344
|
if (trackListRef.current) trackListRef.current.scrollTop = 0;
|
|
3299
3345
|
}, [trackList?.origin]);
|
|
3300
|
-
(0,
|
|
3346
|
+
(0, import_react20.useEffect)(() => {
|
|
3301
3347
|
const list = trackListRef.current;
|
|
3302
3348
|
if (!isCollapsed && list?.scrollTop === 0) shouldFollowPlaybackRef.current = true;
|
|
3303
3349
|
}, [isCollapsed]);
|
|
3304
|
-
(0,
|
|
3350
|
+
(0, import_react20.useEffect)(
|
|
3305
3351
|
() => () => {
|
|
3306
3352
|
if (userScrollIntentTimerRef.current !== null) clearTimeout(userScrollIntentTimerRef.current);
|
|
3307
3353
|
},
|
|
@@ -3355,25 +3401,25 @@ function TrackListSidebar({
|
|
|
3355
3401
|
}
|
|
3356
3402
|
};
|
|
3357
3403
|
const positionClasses = layout === "inline" ? "relative w-full flex h-full flex-col" : "fixed right-0 w-[50rem] flex flex-col";
|
|
3358
|
-
return trackList ? /* @__PURE__ */ (0,
|
|
3404
|
+
return trackList ? /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)(
|
|
3359
3405
|
"div",
|
|
3360
3406
|
{
|
|
3361
3407
|
"data-theme": "dark",
|
|
3362
3408
|
className: `track-list-sidebar ${positionClasses} rounded-2xl bg-[var(--color-surface)] pb-1 ${className2}`,
|
|
3363
3409
|
style: layout === "fixed" ? { top: "63.5px", maxHeight: "calc(100vh - 63.5px - 79px)" } : void 0,
|
|
3364
3410
|
children: [
|
|
3365
|
-
/* @__PURE__ */ (0,
|
|
3366
|
-
/* @__PURE__ */ (0,
|
|
3367
|
-
/* @__PURE__ */ (0,
|
|
3368
|
-
/* @__PURE__ */ (0,
|
|
3369
|
-
/* @__PURE__ */ (0,
|
|
3411
|
+
/* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("div", { className: "header flex h-16 items-center px-4 py-2 text-[var(--color-text)]", children: [
|
|
3412
|
+
/* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("div", { className: "min-w-0 flex flex-1 flex-col justify-center", children: [
|
|
3413
|
+
/* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("div", { className: "origin flex text-xl", children: [
|
|
3414
|
+
/* @__PURE__ */ (0, import_jsx_runtime46.jsx)("div", { className: "from h-auto flex flex-col justify-center items-center mr-2", children: "From" }),
|
|
3415
|
+
/* @__PURE__ */ (0, import_jsx_runtime46.jsx)("div", { className: "name-container flex flex-col justify-center items-center text-[var(--color-text)] font-bold pr-2 max-w-[27.5rem]", children: /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("div", { className: "name max-w-full truncate", children: trackList.origin.label }) })
|
|
3370
3416
|
] }),
|
|
3371
|
-
/* @__PURE__ */ (0,
|
|
3372
|
-
trackList.origin.type ===
|
|
3417
|
+
/* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("div", { className: "info flex items-center text-body text-[var(--color-text-muted)]", children: [
|
|
3418
|
+
trackList.origin.type === import_genre_tree32.TrackListOriginType.GENRE_PLAYLIST ? "Genre \u2022 " : trackList.origin.type === import_genre_tree32.TrackListOriginType.ARTIST ? "Artist \u2022 " : `${trackNoun.singular} playlist \u2022 `,
|
|
3373
3419
|
`${trackList.total} ${trackList.total > 1 ? trackNoun.plural : trackNoun.singular}`
|
|
3374
3420
|
] })
|
|
3375
3421
|
] }),
|
|
3376
|
-
(isCollapsed && onExpand || !isCollapsed && onMinimize) && /* @__PURE__ */ (0,
|
|
3422
|
+
(isCollapsed && onExpand || !isCollapsed && onMinimize) && /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(
|
|
3377
3423
|
"button",
|
|
3378
3424
|
{
|
|
3379
3425
|
type: "button",
|
|
@@ -3382,11 +3428,11 @@ function TrackListSidebar({
|
|
|
3382
3428
|
"aria-expanded": !isCollapsed,
|
|
3383
3429
|
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"}`,
|
|
3384
3430
|
onClick: isCollapsed ? onExpand : onMinimize,
|
|
3385
|
-
children: /* @__PURE__ */ (0,
|
|
3431
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(import_lucide_react16.ListMusic, { "aria-hidden": "true", className: "h-5 w-5" })
|
|
3386
3432
|
}
|
|
3387
3433
|
)
|
|
3388
3434
|
] }),
|
|
3389
|
-
!isCollapsed && /* @__PURE__ */ (0,
|
|
3435
|
+
!isCollapsed && /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)(
|
|
3390
3436
|
"ul",
|
|
3391
3437
|
{
|
|
3392
3438
|
ref: trackListRef,
|
|
@@ -3396,7 +3442,7 @@ function TrackListSidebar({
|
|
|
3396
3442
|
onPointerDown: markUserScrollIntent,
|
|
3397
3443
|
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",
|
|
3398
3444
|
children: [
|
|
3399
|
-
trackList.tracks.map((track, index) => /* @__PURE__ */ (0,
|
|
3445
|
+
trackList.tracks.map((track, index) => /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("li", { "data-track-uuid": track.uuid, children: /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(
|
|
3400
3446
|
TrackItem,
|
|
3401
3447
|
{
|
|
3402
3448
|
track,
|
|
@@ -3407,7 +3453,7 @@ function TrackListSidebar({
|
|
|
3407
3453
|
renderSongLink
|
|
3408
3454
|
}
|
|
3409
3455
|
) }, track.uuid)),
|
|
3410
|
-
hasMore && /* @__PURE__ */ (0,
|
|
3456
|
+
hasMore && /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("li", { ref: loadMoreSentinelRef, "aria-hidden": "true", className: "h-px" })
|
|
3411
3457
|
]
|
|
3412
3458
|
}
|
|
3413
3459
|
)
|
|
@@ -3417,17 +3463,17 @@ function TrackListSidebar({
|
|
|
3417
3463
|
}
|
|
3418
3464
|
|
|
3419
3465
|
// src/genre-tree/PlayerPanel.tsx
|
|
3420
|
-
var
|
|
3466
|
+
var import_react21 = require("react");
|
|
3421
3467
|
var import_tailwind_merge = require("tailwind-merge");
|
|
3422
|
-
var
|
|
3423
|
-
var
|
|
3424
|
-
var
|
|
3468
|
+
var import_player14 = require("@behindthemusictree/app-kit/player");
|
|
3469
|
+
var import_genre_tree34 = require("@behindthemusictree/app-kit/genre-tree");
|
|
3470
|
+
var import_ui22 = require("@behindthemusictree/ui");
|
|
3425
3471
|
|
|
3426
3472
|
// src/genre-tree/PlayerControls.tsx
|
|
3427
|
-
var
|
|
3428
|
-
var
|
|
3429
|
-
var
|
|
3430
|
-
var
|
|
3473
|
+
var import_lucide_react17 = require("lucide-react");
|
|
3474
|
+
var import_genre_tree33 = require("@behindthemusictree/app-kit/genre-tree");
|
|
3475
|
+
var import_player13 = require("@behindthemusictree/app-kit/player");
|
|
3476
|
+
var import_jsx_runtime47 = require("react/jsx-runtime");
|
|
3431
3477
|
function PlayerControls() {
|
|
3432
3478
|
const {
|
|
3433
3479
|
duration,
|
|
@@ -3438,23 +3484,23 @@ function PlayerControls() {
|
|
|
3438
3484
|
seekTo,
|
|
3439
3485
|
setVolume,
|
|
3440
3486
|
volume
|
|
3441
|
-
} = (0,
|
|
3442
|
-
const { hasNextTrack, hasPreviousTrack, playNextTrack, playPreviousTrack } = (0,
|
|
3443
|
-
const currentTime = (0,
|
|
3444
|
-
const isBusy = isLoading || playState ===
|
|
3487
|
+
} = (0, import_player13.usePlayer)();
|
|
3488
|
+
const { hasNextTrack, hasPreviousTrack, playNextTrack, playPreviousTrack } = (0, import_genre_tree33.useTrackList)();
|
|
3489
|
+
const currentTime = (0, import_player13.useCurrentTime)();
|
|
3490
|
+
const isBusy = isLoading || playState === import_player13.PlayStates.LOADING;
|
|
3445
3491
|
const isReady = !!playerTrackObject?.isReady && !isBusy && !playerTrackObject.loadError;
|
|
3446
3492
|
const safeDuration = Number.isFinite(duration) && duration > 0 ? duration : 0;
|
|
3447
3493
|
const safeCurrentTime = Number.isFinite(currentTime) ? Math.max(0, Math.min(currentTime, safeDuration)) : 0;
|
|
3448
|
-
const isPlaying = playState ===
|
|
3449
|
-
return /* @__PURE__ */ (0,
|
|
3494
|
+
const isPlaying = playState === import_player13.PlayStates.PLAYING;
|
|
3495
|
+
return /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)(
|
|
3450
3496
|
"section",
|
|
3451
3497
|
{
|
|
3452
3498
|
"aria-label": "Player controls",
|
|
3453
3499
|
className: "player-controls flex shrink-0 flex-col gap-2 border-b border-zinc-800 px-3 py-2 text-zinc-200",
|
|
3454
3500
|
children: [
|
|
3455
|
-
/* @__PURE__ */ (0,
|
|
3456
|
-
/* @__PURE__ */ (0,
|
|
3457
|
-
/* @__PURE__ */ (0,
|
|
3501
|
+
/* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("div", { className: "flex min-w-0 items-center gap-2 text-xs tabular-nums text-zinc-400", children: [
|
|
3502
|
+
/* @__PURE__ */ (0, import_jsx_runtime47.jsx)("span", { "aria-label": "Elapsed time", children: (0, import_genre_tree33.formatTime)(safeCurrentTime) }),
|
|
3503
|
+
/* @__PURE__ */ (0, import_jsx_runtime47.jsx)(
|
|
3458
3504
|
"input",
|
|
3459
3505
|
{
|
|
3460
3506
|
"aria-label": "Seek",
|
|
@@ -3468,11 +3514,11 @@ function PlayerControls() {
|
|
|
3468
3514
|
onChange: (event) => seekTo(Number(event.currentTarget.value))
|
|
3469
3515
|
}
|
|
3470
3516
|
),
|
|
3471
|
-
/* @__PURE__ */ (0,
|
|
3517
|
+
/* @__PURE__ */ (0, import_jsx_runtime47.jsx)("span", { "aria-label": "Duration", children: (0, import_genre_tree33.formatTime)(safeDuration) })
|
|
3472
3518
|
] }),
|
|
3473
|
-
/* @__PURE__ */ (0,
|
|
3474
|
-
/* @__PURE__ */ (0,
|
|
3475
|
-
/* @__PURE__ */ (0,
|
|
3519
|
+
/* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("div", { className: "grid min-h-9 grid-cols-[1fr_auto_1fr] items-center gap-3", children: [
|
|
3520
|
+
/* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("div", { className: "col-start-2 flex items-center justify-center gap-2", children: [
|
|
3521
|
+
/* @__PURE__ */ (0, import_jsx_runtime47.jsx)(
|
|
3476
3522
|
"button",
|
|
3477
3523
|
{
|
|
3478
3524
|
type: "button",
|
|
@@ -3481,10 +3527,10 @@ function PlayerControls() {
|
|
|
3481
3527
|
disabled: !isReady || !hasPreviousTrack,
|
|
3482
3528
|
onClick: playPreviousTrack,
|
|
3483
3529
|
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",
|
|
3484
|
-
children: /* @__PURE__ */ (0,
|
|
3530
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(import_lucide_react17.SkipBack, { "aria-hidden": "true", className: "h-4 w-4" })
|
|
3485
3531
|
}
|
|
3486
3532
|
),
|
|
3487
|
-
/* @__PURE__ */ (0,
|
|
3533
|
+
/* @__PURE__ */ (0, import_jsx_runtime47.jsx)(
|
|
3488
3534
|
"button",
|
|
3489
3535
|
{
|
|
3490
3536
|
type: "button",
|
|
@@ -3493,10 +3539,10 @@ function PlayerControls() {
|
|
|
3493
3539
|
disabled: !isReady,
|
|
3494
3540
|
onClick: handlePlayPauseAction,
|
|
3495
3541
|
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",
|
|
3496
|
-
children: isPlaying ? /* @__PURE__ */ (0,
|
|
3542
|
+
children: isPlaying ? /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(import_lucide_react17.Pause, { "aria-hidden": "true", className: "h-4 w-4", fill: "currentColor" }) : /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(import_lucide_react17.Play, { "aria-hidden": "true", className: "h-4 w-4", fill: "currentColor" })
|
|
3497
3543
|
}
|
|
3498
3544
|
),
|
|
3499
|
-
/* @__PURE__ */ (0,
|
|
3545
|
+
/* @__PURE__ */ (0, import_jsx_runtime47.jsx)(
|
|
3500
3546
|
"button",
|
|
3501
3547
|
{
|
|
3502
3548
|
type: "button",
|
|
@@ -3505,14 +3551,14 @@ function PlayerControls() {
|
|
|
3505
3551
|
disabled: !isReady || !hasNextTrack,
|
|
3506
3552
|
onClick: playNextTrack,
|
|
3507
3553
|
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",
|
|
3508
|
-
children: /* @__PURE__ */ (0,
|
|
3554
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(import_lucide_react17.SkipForward, { "aria-hidden": "true", className: "h-4 w-4" })
|
|
3509
3555
|
}
|
|
3510
3556
|
)
|
|
3511
3557
|
] }),
|
|
3512
|
-
/* @__PURE__ */ (0,
|
|
3513
|
-
volume === 0 ? /* @__PURE__ */ (0,
|
|
3514
|
-
/* @__PURE__ */ (0,
|
|
3515
|
-
/* @__PURE__ */ (0,
|
|
3558
|
+
/* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("label", { className: "col-start-3 flex w-[4.2rem] shrink-0 items-center gap-[0.35rem] justify-self-end text-zinc-400 sm:w-[4.9rem]", children: [
|
|
3559
|
+
volume === 0 ? /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(import_lucide_react17.VolumeX, { "aria-hidden": "true", className: "h-[0.7rem] w-[0.7rem] shrink-0" }) : /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(import_lucide_react17.Volume2, { "aria-hidden": "true", className: "h-[0.7rem] w-[0.7rem] shrink-0" }),
|
|
3560
|
+
/* @__PURE__ */ (0, import_jsx_runtime47.jsx)("span", { className: "sr-only", children: "Volume" }),
|
|
3561
|
+
/* @__PURE__ */ (0, import_jsx_runtime47.jsx)(
|
|
3516
3562
|
"input",
|
|
3517
3563
|
{
|
|
3518
3564
|
"aria-label": "Volume",
|
|
@@ -3534,7 +3580,7 @@ function PlayerControls() {
|
|
|
3534
3580
|
}
|
|
3535
3581
|
|
|
3536
3582
|
// src/genre-tree/PlayerPanel.tsx
|
|
3537
|
-
var
|
|
3583
|
+
var import_jsx_runtime48 = require("react/jsx-runtime");
|
|
3538
3584
|
var PANEL_ID = "player-panel";
|
|
3539
3585
|
var DEFAULT_EXTENDED_WIDTH = "calc(100vw - var(--layout-center-left) - var(--layout-gutter))";
|
|
3540
3586
|
function PlayerPanel({
|
|
@@ -3546,14 +3592,14 @@ function PlayerPanel({
|
|
|
3546
3592
|
renderArtistLink,
|
|
3547
3593
|
renderSongLink
|
|
3548
3594
|
}) {
|
|
3549
|
-
const { playerTrackObject, retryPlayback } = (0,
|
|
3550
|
-
const { toggleTrackListSidebar, isTrackListSidebarVisible } = (0,
|
|
3551
|
-
const [lastLoadedTrackTitle, setLastLoadedTrackTitle] = (0,
|
|
3595
|
+
const { playerTrackObject, retryPlayback } = (0, import_player14.usePlayer)();
|
|
3596
|
+
const { toggleTrackListSidebar, isTrackListSidebarVisible } = (0, import_genre_tree34.useTrackListSidebarVisibility)();
|
|
3597
|
+
const [lastLoadedTrackTitle, setLastLoadedTrackTitle] = (0, import_react21.useState)("");
|
|
3552
3598
|
const loadedTrackTitle = playerTrackObject?.track.title;
|
|
3553
|
-
(0,
|
|
3599
|
+
(0, import_react21.useEffect)(() => {
|
|
3554
3600
|
if (loadedTrackTitle) setLastLoadedTrackTitle(loadedTrackTitle);
|
|
3555
3601
|
}, [loadedTrackTitle]);
|
|
3556
|
-
const [uncontrolledExtended, setUncontrolledExtended] = (0,
|
|
3602
|
+
const [uncontrolledExtended, setUncontrolledExtended] = (0, import_react21.useState)(false);
|
|
3557
3603
|
const isExtendRequested = expanded ?? uncontrolledExtended;
|
|
3558
3604
|
const setIsExtendRequested = (next) => {
|
|
3559
3605
|
setUncontrolledExtended(next);
|
|
@@ -3574,7 +3620,7 @@ function PlayerPanel({
|
|
|
3574
3620
|
onClick: () => setIsExtendRequested(true),
|
|
3575
3621
|
expanded: false
|
|
3576
3622
|
} : null;
|
|
3577
|
-
return /* @__PURE__ */ (0,
|
|
3623
|
+
return /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)(
|
|
3578
3624
|
"div",
|
|
3579
3625
|
{
|
|
3580
3626
|
id: PANEL_ID,
|
|
@@ -3587,8 +3633,8 @@ function PlayerPanel({
|
|
|
3587
3633
|
),
|
|
3588
3634
|
style: isExtended ? { width: extendedWidth } : void 0,
|
|
3589
3635
|
children: [
|
|
3590
|
-
/* @__PURE__ */ (0,
|
|
3591
|
-
|
|
3636
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
|
|
3637
|
+
import_ui22.PanelEdgeTab,
|
|
3592
3638
|
{
|
|
3593
3639
|
side: "right",
|
|
3594
3640
|
edge: tabEdge,
|
|
@@ -3597,7 +3643,7 @@ function PlayerPanel({
|
|
|
3597
3643
|
className: "absolute right-full top-1/2 -translate-y-1/2"
|
|
3598
3644
|
}
|
|
3599
3645
|
),
|
|
3600
|
-
/* @__PURE__ */ (0,
|
|
3646
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsxs)(
|
|
3601
3647
|
"div",
|
|
3602
3648
|
{
|
|
3603
3649
|
className: (0, import_tailwind_merge.twMerge)(
|
|
@@ -3605,20 +3651,20 @@ function PlayerPanel({
|
|
|
3605
3651
|
isExtended ? "flex-row" : "flex-col"
|
|
3606
3652
|
),
|
|
3607
3653
|
children: [
|
|
3608
|
-
/* @__PURE__ */ (0,
|
|
3609
|
-
/* @__PURE__ */ (0,
|
|
3610
|
-
/* @__PURE__ */ (0,
|
|
3611
|
-
/* @__PURE__ */ (0,
|
|
3612
|
-
playerTrackObject?.loadError && /* @__PURE__ */ (0,
|
|
3654
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("div", { className: "flex w-[var(--layout-right-w)] shrink-0 flex-col", children: [
|
|
3655
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)("div", { className: "flex shrink-0 items-center justify-between gap-2 border-b border-zinc-800 p-2", children: /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("span", { className: "min-w-0 truncate text-sm font-semibold", children: loadedTrackTitle || lastLoadedTrackTitle }) }),
|
|
3656
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("div", { className: "relative w-full shrink-0", children: [
|
|
3657
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)(import_player14.PlayerVideoSurface, { className: "aspect-video w-full bg-black" }),
|
|
3658
|
+
playerTrackObject?.loadError && /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("span", { className: "absolute bottom-2 left-2 right-2 text-xs text-red-400", children: [
|
|
3613
3659
|
playerTrackObject.loadError,
|
|
3614
|
-
/* @__PURE__ */ (0,
|
|
3660
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)("button", { type: "button", className: "ml-2 underline", onClick: () => {
|
|
3615
3661
|
void retryPlayback();
|
|
3616
3662
|
}, children: "Retry" })
|
|
3617
3663
|
] })
|
|
3618
3664
|
] }),
|
|
3619
|
-
/* @__PURE__ */ (0,
|
|
3665
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)(PlayerControls, {})
|
|
3620
3666
|
] }),
|
|
3621
|
-
/* @__PURE__ */ (0,
|
|
3667
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
|
|
3622
3668
|
TrackListSidebar,
|
|
3623
3669
|
{
|
|
3624
3670
|
layout: "inline",
|
|
@@ -3644,33 +3690,33 @@ function PlayerPanel({
|
|
|
3644
3690
|
// src/genre-tree/Rating.tsx
|
|
3645
3691
|
var import_uuid = require("uuid");
|
|
3646
3692
|
var import_ai = require("react-icons/ai");
|
|
3647
|
-
var
|
|
3648
|
-
var
|
|
3693
|
+
var import_genre_tree35 = require("@behindthemusictree/app-kit/genre-tree");
|
|
3694
|
+
var import_jsx_runtime49 = require("react/jsx-runtime");
|
|
3649
3695
|
function Rating({ rating, handleChange }) {
|
|
3650
3696
|
const instanceId = (0, import_uuid.v4)();
|
|
3651
|
-
return /* @__PURE__ */ (0,
|
|
3652
|
-
/* @__PURE__ */ (0,
|
|
3697
|
+
return /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("div", { className: "flex items-center", children: [...Array(6)].map((_, i) => /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)("div", { className: `relative ${i === 0 ? "mr-4" : "mr-1"}`, children: [
|
|
3698
|
+
/* @__PURE__ */ (0, import_jsx_runtime49.jsx)(
|
|
3653
3699
|
"input",
|
|
3654
3700
|
{
|
|
3655
3701
|
id: `star-${instanceId}-${i}`,
|
|
3656
3702
|
className: "w-6 h-6 opacity-0",
|
|
3657
3703
|
type: "radio",
|
|
3658
3704
|
name: "rating",
|
|
3659
|
-
value: i === 0 ?
|
|
3705
|
+
value: i === 0 ? import_genre_tree35.FORM_RATING_NULL_VALUE : i,
|
|
3660
3706
|
checked: rating === (i === 0 ? null : i),
|
|
3661
3707
|
onChange: handleChange
|
|
3662
3708
|
}
|
|
3663
3709
|
),
|
|
3664
|
-
/* @__PURE__ */ (0,
|
|
3665
|
-
/* @__PURE__ */ (0,
|
|
3710
|
+
/* @__PURE__ */ (0, import_jsx_runtime49.jsx)("label", { htmlFor: `star-${instanceId}-${i}`, className: "cursor-pointer", children: i === 0 ? /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)("div", { className: "flex", children: [
|
|
3711
|
+
/* @__PURE__ */ (0, import_jsx_runtime49.jsx)(
|
|
3666
3712
|
import_ai.AiOutlineStar,
|
|
3667
3713
|
{
|
|
3668
|
-
className: `w-7 h-7 absolute top-0 left-0 ${rating ===
|
|
3714
|
+
className: `w-7 h-7 absolute top-0 left-0 ${rating === import_genre_tree35.FORM_RATING_NULL_VALUE ? "text-[var(--color-accent-rating)]" : "text-[var(--color-text-muted)]"}`
|
|
3669
3715
|
}
|
|
3670
3716
|
),
|
|
3671
|
-
/* @__PURE__ */ (0,
|
|
3717
|
+
/* @__PURE__ */ (0, import_jsx_runtime49.jsx)("span", { className: "flex-grow w-8" }),
|
|
3672
3718
|
" "
|
|
3673
|
-
] }) : /* @__PURE__ */ (0,
|
|
3719
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(
|
|
3674
3720
|
import_ai.AiFillStar,
|
|
3675
3721
|
{
|
|
3676
3722
|
className: `w-7 h-7 absolute top-0 left-0 ${(rating ?? -1) >= i ? "text-[var(--color-accent-rating)]" : "text-[var(--color-text-muted)]"}`
|
|
@@ -3680,9 +3726,9 @@ function Rating({ rating, handleChange }) {
|
|
|
3680
3726
|
}
|
|
3681
3727
|
|
|
3682
3728
|
// src/genre-tree/EntityDetailPanel.tsx
|
|
3683
|
-
var
|
|
3684
|
-
var
|
|
3685
|
-
var
|
|
3729
|
+
var import_react22 = require("react");
|
|
3730
|
+
var import_ui23 = require("@behindthemusictree/ui");
|
|
3731
|
+
var import_jsx_runtime50 = require("react/jsx-runtime");
|
|
3686
3732
|
function EntityDetailPanel({
|
|
3687
3733
|
scope,
|
|
3688
3734
|
getBackendBaseUrl,
|
|
@@ -3698,15 +3744,15 @@ function EntityDetailPanel({
|
|
|
3698
3744
|
edgeTab,
|
|
3699
3745
|
...navigation
|
|
3700
3746
|
}) {
|
|
3701
|
-
const [expandedSongUuid, setExpandedSongUuid] = (0,
|
|
3702
|
-
const [expandedArtistUuid, setExpandedArtistUuid] = (0,
|
|
3747
|
+
const [expandedSongUuid, setExpandedSongUuid] = (0, import_react22.useState)(null);
|
|
3748
|
+
const [expandedArtistUuid, setExpandedArtistUuid] = (0, import_react22.useState)(null);
|
|
3703
3749
|
const panel = useEntityPanel({
|
|
3704
3750
|
scope,
|
|
3705
3751
|
getBackendBaseUrl,
|
|
3706
3752
|
getArtistBackendBaseUrl,
|
|
3707
3753
|
getShareUrl,
|
|
3708
|
-
renderArtistLink: renderArtistLink ?? ((artist) => artist.isSpecialPurpose ? artist.name : /* @__PURE__ */ (0,
|
|
3709
|
-
renderSongLink: renderSongLink ?? ((song) => /* @__PURE__ */ (0,
|
|
3754
|
+
renderArtistLink: renderArtistLink ?? ((artist) => artist.isSpecialPurpose ? artist.name : /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("button", { type: "button", onClick: () => onArtistUuidChange(artist.uuid), className: "hover:underline", children: artist.name })),
|
|
3755
|
+
renderSongLink: renderSongLink ?? ((song) => /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("button", { type: "button", onClick: () => onSongUuidChange(song.uuid), className: "hover:underline", children: song.title })),
|
|
3710
3756
|
song: {
|
|
3711
3757
|
uuid: songUuid,
|
|
3712
3758
|
expanded: songUuid !== null && expandedSongUuid === songUuid,
|
|
@@ -3722,8 +3768,8 @@ function EntityDetailPanel({
|
|
|
3722
3768
|
...navigation
|
|
3723
3769
|
});
|
|
3724
3770
|
if (!panel) return null;
|
|
3725
|
-
return /* @__PURE__ */ (0,
|
|
3726
|
-
|
|
3771
|
+
return /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(
|
|
3772
|
+
import_ui23.DetailPanel,
|
|
3727
3773
|
{
|
|
3728
3774
|
side: "left",
|
|
3729
3775
|
title: panel.title,
|
|
@@ -3734,7 +3780,7 @@ function EntityDetailPanel({
|
|
|
3734
3780
|
onExpandedChange: panel.onExpandedChange,
|
|
3735
3781
|
aside: panel.extraContent,
|
|
3736
3782
|
edgeTab,
|
|
3737
|
-
children: panel.extraContent && !panel.expanded ? /* @__PURE__ */ (0,
|
|
3783
|
+
children: panel.extraContent && !panel.expanded ? /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)(import_jsx_runtime50.Fragment, { children: [
|
|
3738
3784
|
panel.content,
|
|
3739
3785
|
panel.extraContent
|
|
3740
3786
|
] }) : panel.content
|