@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
package/dist/index.cjs
CHANGED
|
@@ -589,14 +589,14 @@ function AuthCallbackHandler({ renderStatus, ...options }) {
|
|
|
589
589
|
}
|
|
590
590
|
|
|
591
591
|
// src/genre-tree/GenreTreeView.tsx
|
|
592
|
-
var
|
|
592
|
+
var import_react19 = require("react");
|
|
593
593
|
var import_react_query3 = require("@tanstack/react-query");
|
|
594
|
-
var
|
|
595
|
-
var
|
|
596
|
-
var
|
|
594
|
+
var import_lucide_react18 = require("lucide-react");
|
|
595
|
+
var import_lucide_react19 = require("lucide-react");
|
|
596
|
+
var import_ui24 = require("@behindthemusictree/ui");
|
|
597
597
|
var import_genre_tree_view5 = require("@behindthemusictree/genre-tree-view");
|
|
598
|
-
var
|
|
599
|
-
var
|
|
598
|
+
var import_genre_tree30 = require("@behindthemusictree/app-kit/genre-tree");
|
|
599
|
+
var import_popup5 = require("@behindthemusictree/app-kit/popup");
|
|
600
600
|
|
|
601
601
|
// src/genre-tree/playlist-tree/size-metric.ts
|
|
602
602
|
var import_genre_tree = require("@behindthemusictree/app-kit/genre-tree");
|
|
@@ -610,7 +610,7 @@ var genrePlaylistSize = (genrePlaylist, metric) => {
|
|
|
610
610
|
};
|
|
611
611
|
|
|
612
612
|
// src/genre-tree/playlist-tree/toTreeNodes.ts
|
|
613
|
-
function toTreeNodes(genrePlaylists, sizeMetric) {
|
|
613
|
+
function toTreeNodes(genrePlaylists, sizeMetric, focusUuids) {
|
|
614
614
|
return genrePlaylists.map((genrePlaylist) => ({
|
|
615
615
|
id: genrePlaylist.uuid,
|
|
616
616
|
parentId: genrePlaylist.parent?.uuid ?? null,
|
|
@@ -621,7 +621,8 @@ function toTreeNodes(genrePlaylists, sizeMetric) {
|
|
|
621
621
|
side: genrePlaylist.criteria?.side ?? void 0,
|
|
622
622
|
wikidataId: genrePlaylist.criteria?.wikidataId ?? null,
|
|
623
623
|
umbrella: genrePlaylist.isUmbrella,
|
|
624
|
-
scene: genrePlaylist.scene ?? void 0
|
|
624
|
+
scene: genrePlaylist.scene ?? void 0,
|
|
625
|
+
muted: focusUuids ? !focusUuids.has(genrePlaylist.uuid) : void 0
|
|
625
626
|
}));
|
|
626
627
|
}
|
|
627
628
|
|
|
@@ -630,38 +631,45 @@ var import_genre_tree3 = require("@behindthemusictree/app-kit/genre-tree");
|
|
|
630
631
|
var import_react4 = require("react");
|
|
631
632
|
var import_genre_tree_view = require("@behindthemusictree/genre-tree-view");
|
|
632
633
|
var import_player = require("@behindthemusictree/app-kit/player");
|
|
633
|
-
var import_popup2 = require("@behindthemusictree/app-kit/popup");
|
|
634
|
-
var import_transport3 = require("@behindthemusictree/app-kit/transport");
|
|
635
634
|
|
|
636
|
-
// src/genre-tree/playlist-tree/useGenrePlaylistPlayback.
|
|
635
|
+
// src/genre-tree/playlist-tree/useGenrePlaylistPlayback.tsx
|
|
637
636
|
var import_react3 = require("react");
|
|
638
637
|
var import_genre_tree2 = require("@behindthemusictree/app-kit/genre-tree");
|
|
638
|
+
var import_popup2 = require("@behindthemusictree/app-kit/popup");
|
|
639
|
+
var import_transport3 = require("@behindthemusictree/app-kit/transport");
|
|
640
|
+
var import_jsx_runtime12 = require("react/jsx-runtime");
|
|
639
641
|
function useGenrePlaylistPlayback({
|
|
640
642
|
scope,
|
|
641
643
|
genrePlaylists,
|
|
642
644
|
artist = null
|
|
643
645
|
}) {
|
|
644
646
|
const { trackList, playNewTrackListFromGenrePlaylist } = (0, import_genre_tree2.useTrackList)();
|
|
647
|
+
const { showPopup } = (0, import_popup2.usePopup)();
|
|
645
648
|
const origin = trackList?.origin;
|
|
646
|
-
const
|
|
649
|
+
const playing = (0, import_react3.useMemo)(() => {
|
|
647
650
|
if (!origin || origin.type !== import_genre_tree2.TrackListOriginType.GENRE_PLAYLIST || origin.scope !== scope) return null;
|
|
648
651
|
const playlistOrigin = origin;
|
|
649
652
|
if (playlistOrigin.artistUuid !== artist?.uuid) return null;
|
|
650
653
|
const playlist = genrePlaylists.find((item) => item.uuid === origin.uuid) ?? playlistOrigin.criteriaPlaylist;
|
|
651
654
|
const expected = scope === "reference" && playlist && !("criteria" in playlist && playlist.criteria === null) ? (0, import_genre_tree2.defaultGenreMusicSelection)(import_genre_tree2.GenreCatalogueCountsSchema.parse(playlist)) : void 0;
|
|
652
|
-
|
|
653
|
-
return origin.uuid;
|
|
655
|
+
return { uuid: origin.uuid, selectionKey: (0, import_genre_tree2.genreMusicSelectionKey)(playlistOrigin.selection ?? expected).join() };
|
|
654
656
|
}, [origin, artist, genrePlaylists, scope]);
|
|
655
|
-
const play = (0, import_react3.useCallback)(async (playlist) => {
|
|
657
|
+
const play = (0, import_react3.useCallback)(async (playlist, requested) => {
|
|
656
658
|
if (artist && !playlist.criteria) return;
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
659
|
+
try {
|
|
660
|
+
const selection = scope === "reference" && playlist.criteria !== null ? requested ?? (0, import_genre_tree2.defaultGenreMusicSelection)(import_genre_tree2.GenreCatalogueCountsSchema.parse(playlist)) : void 0;
|
|
661
|
+
await (selection || artist ? playNewTrackListFromGenrePlaylist(playlist, scope, { selection, ...artist && { artistUuid: artist.uuid } }) : playNewTrackListFromGenrePlaylist(playlist, scope));
|
|
662
|
+
} catch (error) {
|
|
663
|
+
console.error("Failed to load genre playlist tracks:", error);
|
|
664
|
+
if (error instanceof import_genre_tree2.TracksFailureAlreadyReportedError) return;
|
|
665
|
+
showPopup(/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(InternalErrorPopup, { errorCode: error instanceof import_transport3.AppError ? error.code : import_transport3.ErrorCode.CLIENT_UNKNOWN }));
|
|
666
|
+
}
|
|
667
|
+
}, [artist, scope, playNewTrackListFromGenrePlaylist, showPopup]);
|
|
668
|
+
return (0, import_react3.useMemo)(() => ({ playing, play }), [playing, play]);
|
|
661
669
|
}
|
|
662
670
|
|
|
663
671
|
// src/genre-tree/playlist-tree/TreePerRoot.tsx
|
|
664
|
-
var
|
|
672
|
+
var import_jsx_runtime13 = require("react/jsx-runtime");
|
|
665
673
|
function GenrePlaylistTreePerRoot({
|
|
666
674
|
scope,
|
|
667
675
|
className: className2,
|
|
@@ -680,24 +688,16 @@ function GenrePlaylistTreePerRoot({
|
|
|
680
688
|
viewportRestore,
|
|
681
689
|
onViewportChange,
|
|
682
690
|
playback,
|
|
691
|
+
focusUuids,
|
|
683
692
|
...hostPanel
|
|
684
693
|
}) {
|
|
685
694
|
const { isPlaying, setIsPlaying } = (0, import_player.usePlayer)();
|
|
686
695
|
const defaultPlayback = useGenrePlaylistPlayback({ scope, genrePlaylists: genrePlaylistTreePerRoot });
|
|
687
|
-
const {
|
|
688
|
-
const
|
|
696
|
+
const { playing, play } = playback ?? defaultPlayback;
|
|
697
|
+
const playingNodeId = playing?.uuid ?? null;
|
|
689
698
|
const nodes = (0, import_react4.useMemo)(
|
|
690
|
-
() => genrePlaylistTreePerRoot
|
|
691
|
-
|
|
692
|
-
parentId: genrePlaylist.parent?.uuid ?? null,
|
|
693
|
-
name: genrePlaylist.name,
|
|
694
|
-
itemCount: (0, import_genre_tree3.genrePlaylistTrackCount)(genrePlaylist),
|
|
695
|
-
actionable: Boolean(genrePlaylist.criteria),
|
|
696
|
-
side: genrePlaylist.criteria?.side ?? void 0,
|
|
697
|
-
wikidataId: genrePlaylist.criteria?.wikidataId ?? null,
|
|
698
|
-
umbrella: genrePlaylist.isUmbrella
|
|
699
|
-
})),
|
|
700
|
-
[genrePlaylistTreePerRoot]
|
|
699
|
+
() => toTreeNodes(genrePlaylistTreePerRoot, "songs", focusUuids),
|
|
700
|
+
[genrePlaylistTreePerRoot, focusUuids]
|
|
701
701
|
);
|
|
702
702
|
const handlePlayPause = (0, import_react4.useCallback)(
|
|
703
703
|
(nodeId) => {
|
|
@@ -710,18 +710,14 @@ function GenrePlaylistTreePerRoot({
|
|
|
710
710
|
if ((0, import_genre_tree3.genrePlaylistTrackCount)(genrePlaylist) === 0) {
|
|
711
711
|
return;
|
|
712
712
|
}
|
|
713
|
-
play(genrePlaylist)
|
|
714
|
-
console.error("Failed to load genre playlist tracks:", error);
|
|
715
|
-
showPopup(/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(InternalErrorPopup, { errorCode: import_transport3.ErrorCode.CLIENT_UNKNOWN }));
|
|
716
|
-
});
|
|
713
|
+
void play(genrePlaylist);
|
|
717
714
|
},
|
|
718
715
|
[
|
|
719
716
|
genrePlaylistTreePerRoot,
|
|
720
717
|
playingNodeId,
|
|
721
718
|
isPlaying,
|
|
722
719
|
setIsPlaying,
|
|
723
|
-
play
|
|
724
|
-
showPopup
|
|
720
|
+
play
|
|
725
721
|
]
|
|
726
722
|
);
|
|
727
723
|
const handleAddChild = (0, import_react4.useCallback)(
|
|
@@ -744,7 +740,7 @@ function GenrePlaylistTreePerRoot({
|
|
|
744
740
|
if (confirm(`Are you sure you want to delete "${node.name}"?`)) {
|
|
745
741
|
}
|
|
746
742
|
}, []);
|
|
747
|
-
return /* @__PURE__ */ (0,
|
|
743
|
+
return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
748
744
|
import_genre_tree_view.GenreTree,
|
|
749
745
|
{
|
|
750
746
|
className: className2,
|
|
@@ -775,9 +771,7 @@ var import_genre_tree4 = require("@behindthemusictree/app-kit/genre-tree");
|
|
|
775
771
|
var import_react5 = require("react");
|
|
776
772
|
var import_genre_tree_view2 = require("@behindthemusictree/genre-tree-view");
|
|
777
773
|
var import_player2 = require("@behindthemusictree/app-kit/player");
|
|
778
|
-
var
|
|
779
|
-
var import_transport4 = require("@behindthemusictree/app-kit/transport");
|
|
780
|
-
var import_jsx_runtime13 = require("react/jsx-runtime");
|
|
774
|
+
var import_jsx_runtime14 = require("react/jsx-runtime");
|
|
781
775
|
function GenrePlaylistTreeWheel({
|
|
782
776
|
scope,
|
|
783
777
|
className: className2,
|
|
@@ -798,23 +792,16 @@ function GenrePlaylistTreeWheel({
|
|
|
798
792
|
viewportRestore,
|
|
799
793
|
onViewportChange,
|
|
800
794
|
playback,
|
|
795
|
+
focusUuids,
|
|
801
796
|
...hostPanel
|
|
802
797
|
}) {
|
|
803
798
|
const { isPlaying, setIsPlaying } = (0, import_player2.usePlayer)();
|
|
804
799
|
const defaultPlayback = useGenrePlaylistPlayback({ scope, genrePlaylists });
|
|
805
|
-
const {
|
|
806
|
-
const
|
|
800
|
+
const { playing, play } = playback ?? defaultPlayback;
|
|
801
|
+
const playingNodeId = playing?.uuid ?? null;
|
|
807
802
|
const nodes = (0, import_react5.useMemo)(
|
|
808
|
-
() => genrePlaylists
|
|
809
|
-
|
|
810
|
-
parentId: genrePlaylist.parent?.uuid ?? null,
|
|
811
|
-
name: genrePlaylist.name,
|
|
812
|
-
itemCount: genrePlaylistSize(genrePlaylist, sizeMetric),
|
|
813
|
-
actionable: Boolean(genrePlaylist.criteria),
|
|
814
|
-
side: genrePlaylist.criteria?.side ?? void 0,
|
|
815
|
-
wikidataId: genrePlaylist.criteria?.wikidataId ?? null
|
|
816
|
-
})),
|
|
817
|
-
[genrePlaylists, sizeMetric]
|
|
803
|
+
() => toTreeNodes(genrePlaylists, sizeMetric, focusUuids),
|
|
804
|
+
[genrePlaylists, sizeMetric, focusUuids]
|
|
818
805
|
);
|
|
819
806
|
const handlePlayPause = (0, import_react5.useCallback)(
|
|
820
807
|
(nodeId) => {
|
|
@@ -827,18 +814,14 @@ function GenrePlaylistTreeWheel({
|
|
|
827
814
|
if ((0, import_genre_tree4.genrePlaylistTrackCount)(genrePlaylist) === 0) {
|
|
828
815
|
return;
|
|
829
816
|
}
|
|
830
|
-
play(genrePlaylist)
|
|
831
|
-
console.error("Failed to load genre playlist tracks:", error);
|
|
832
|
-
showPopup(/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(InternalErrorPopup, { errorCode: import_transport4.ErrorCode.CLIENT_UNKNOWN }));
|
|
833
|
-
});
|
|
817
|
+
void play(genrePlaylist);
|
|
834
818
|
},
|
|
835
819
|
[
|
|
836
820
|
genrePlaylists,
|
|
837
821
|
playingNodeId,
|
|
838
822
|
isPlaying,
|
|
839
823
|
setIsPlaying,
|
|
840
|
-
play
|
|
841
|
-
showPopup
|
|
824
|
+
play
|
|
842
825
|
]
|
|
843
826
|
);
|
|
844
827
|
const handleAddChild = (0, import_react5.useCallback)(
|
|
@@ -861,7 +844,7 @@ function GenrePlaylistTreeWheel({
|
|
|
861
844
|
if (confirm(`Are you sure you want to delete "${node.name}"?`)) {
|
|
862
845
|
}
|
|
863
846
|
}, []);
|
|
864
|
-
return /* @__PURE__ */ (0,
|
|
847
|
+
return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
865
848
|
import_genre_tree_view2.GenreTreeWheel,
|
|
866
849
|
{
|
|
867
850
|
className: className2,
|
|
@@ -893,7 +876,7 @@ var import_genre_tree5 = require("@behindthemusictree/app-kit/genre-tree");
|
|
|
893
876
|
var import_react6 = require("react");
|
|
894
877
|
var import_genre_tree_view3 = require("@behindthemusictree/genre-tree-view");
|
|
895
878
|
var import_player3 = require("@behindthemusictree/app-kit/player");
|
|
896
|
-
var
|
|
879
|
+
var import_jsx_runtime15 = require("react/jsx-runtime");
|
|
897
880
|
function GenrePlaylistTreeWheelRadialPopCore(props) {
|
|
898
881
|
const {
|
|
899
882
|
scope,
|
|
@@ -924,8 +907,9 @@ function GenrePlaylistTreeWheelRadialPopCore(props) {
|
|
|
924
907
|
};
|
|
925
908
|
const { isPlaying, setIsPlaying } = (0, import_player3.usePlayer)();
|
|
926
909
|
const defaultPlayback = useGenrePlaylistPlayback({ scope, genrePlaylists });
|
|
927
|
-
const {
|
|
928
|
-
const
|
|
910
|
+
const { playing, play } = playback ?? defaultPlayback;
|
|
911
|
+
const playingNodeId = playing?.uuid ?? null;
|
|
912
|
+
const nodes = (0, import_react6.useMemo)(() => toTreeNodes(genrePlaylists, sizeMetric, props.focusUuids), [genrePlaylists, sizeMetric, props.focusUuids]);
|
|
929
913
|
const handlePlayPause = (0, import_react6.useCallback)(
|
|
930
914
|
(nodeId) => {
|
|
931
915
|
const genrePlaylist = genrePlaylists.find((g) => g.uuid === nodeId);
|
|
@@ -937,9 +921,7 @@ function GenrePlaylistTreeWheelRadialPopCore(props) {
|
|
|
937
921
|
if ((0, import_genre_tree5.genrePlaylistTrackCount)(genrePlaylist) === 0) {
|
|
938
922
|
return;
|
|
939
923
|
}
|
|
940
|
-
play(genrePlaylist)
|
|
941
|
-
console.error("Failed to load genre playlist tracks:", error);
|
|
942
|
-
});
|
|
924
|
+
void play(genrePlaylist);
|
|
943
925
|
},
|
|
944
926
|
[genrePlaylists, playingNodeId, isPlaying, setIsPlaying, play]
|
|
945
927
|
);
|
|
@@ -979,7 +961,7 @@ function GenrePlaylistTreeWheelRadialPopCore(props) {
|
|
|
979
961
|
onSelectedNodeChange,
|
|
980
962
|
...hostPanel
|
|
981
963
|
};
|
|
982
|
-
return outline ? /* @__PURE__ */ (0,
|
|
964
|
+
return outline ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_genre_tree_view3.GenreTreeOutline, { ...treeProps }) : /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
983
965
|
import_genre_tree_view3.GenreTreeWheelRadialPopCore,
|
|
984
966
|
{
|
|
985
967
|
...treeProps,
|
|
@@ -996,7 +978,7 @@ function GenrePlaylistTreeWheelRadialPopCore(props) {
|
|
|
996
978
|
|
|
997
979
|
// src/genre-tree/GenreTreeWheelHandoff.tsx
|
|
998
980
|
var import_react7 = require("react");
|
|
999
|
-
var
|
|
981
|
+
var import_jsx_runtime16 = require("react/jsx-runtime");
|
|
1000
982
|
function GenreTreeWheelHandoff({ skeleton, children, onRevealedChange }) {
|
|
1001
983
|
const [revealed, setRevealed] = (0, import_react7.useState)(false);
|
|
1002
984
|
const onRevealedChangeRef = (0, import_react7.useRef)(onRevealedChange);
|
|
@@ -1015,8 +997,8 @@ function GenreTreeWheelHandoff({ skeleton, children, onRevealedChange }) {
|
|
|
1015
997
|
cancelAnimationFrame(innerFrame);
|
|
1016
998
|
};
|
|
1017
999
|
}, []);
|
|
1018
|
-
return /* @__PURE__ */ (0,
|
|
1019
|
-
/* @__PURE__ */ (0,
|
|
1000
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "relative w-full h-full", children: [
|
|
1001
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
1020
1002
|
"div",
|
|
1021
1003
|
{
|
|
1022
1004
|
className: "absolute inset-0 transition-opacity duration-150 ease-out",
|
|
@@ -1025,7 +1007,7 @@ function GenreTreeWheelHandoff({ skeleton, children, onRevealedChange }) {
|
|
|
1025
1007
|
children
|
|
1026
1008
|
}
|
|
1027
1009
|
),
|
|
1028
|
-
!revealed && /* @__PURE__ */ (0,
|
|
1010
|
+
!revealed && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { className: "absolute inset-0", "aria-hidden": "true", children: skeleton })
|
|
1029
1011
|
] });
|
|
1030
1012
|
}
|
|
1031
1013
|
|
|
@@ -1040,7 +1022,7 @@ var import_genre_tree9 = require("@behindthemusictree/app-kit/genre-tree");
|
|
|
1040
1022
|
// src/genre-tree/search/SearchBox.tsx
|
|
1041
1023
|
var import_react8 = require("react");
|
|
1042
1024
|
var import_ui6 = require("@behindthemusictree/ui");
|
|
1043
|
-
var
|
|
1025
|
+
var import_jsx_runtime17 = require("react/jsx-runtime");
|
|
1044
1026
|
function SearchBox({
|
|
1045
1027
|
label,
|
|
1046
1028
|
placeholder,
|
|
@@ -1062,7 +1044,7 @@ function SearchBox({
|
|
|
1062
1044
|
groups.find((group) => group.key === groupKey)?.items.find((item) => item.key === itemKey)?.onSelect();
|
|
1063
1045
|
onPicked?.(groupKey, itemKey);
|
|
1064
1046
|
};
|
|
1065
|
-
return /* @__PURE__ */ (0,
|
|
1047
|
+
return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { className: className2, onFocusCapture: onFocus, children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
1066
1048
|
import_ui6.SearchCombobox,
|
|
1067
1049
|
{
|
|
1068
1050
|
ariaLabel: label,
|
|
@@ -1094,7 +1076,7 @@ var searchStatus = (state, count, noun) => state.isError ? SEARCH_FAILED_STATUS
|
|
|
1094
1076
|
|
|
1095
1077
|
// src/genre-tree/search/useArtistSearchGroup.tsx
|
|
1096
1078
|
var import_genre_tree6 = require("@behindthemusictree/app-kit/genre-tree");
|
|
1097
|
-
var
|
|
1079
|
+
var import_jsx_runtime18 = require("react/jsx-runtime");
|
|
1098
1080
|
function useArtistSearchGroup(getBaseUrl, text, onSelect, enabled = true) {
|
|
1099
1081
|
const search = (0, import_genre_tree6.useArtistSearch)(getBaseUrl, enabled ? text : "");
|
|
1100
1082
|
if (!enabled) return void 0;
|
|
@@ -1103,15 +1085,15 @@ function useArtistSearchGroup(getBaseUrl, text, onSelect, enabled = true) {
|
|
|
1103
1085
|
label: "Artists",
|
|
1104
1086
|
items: search.artists.map((artist) => ({
|
|
1105
1087
|
key: artist.uuid,
|
|
1106
|
-
content: /* @__PURE__ */ (0,
|
|
1107
|
-
/* @__PURE__ */ (0,
|
|
1088
|
+
content: /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(import_jsx_runtime18.Fragment, { children: [
|
|
1089
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("span", { className: "block truncate font-medium", children: [
|
|
1108
1090
|
artist.name,
|
|
1109
|
-
artist.disambiguation && /* @__PURE__ */ (0,
|
|
1091
|
+
artist.disambiguation && /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("span", { className: "font-normal text-[var(--color-neutral-500)]", children: [
|
|
1110
1092
|
" \xB7 ",
|
|
1111
1093
|
artist.disambiguation
|
|
1112
1094
|
] })
|
|
1113
1095
|
] }),
|
|
1114
|
-
artist.matchedAlias && /* @__PURE__ */ (0,
|
|
1096
|
+
artist.matchedAlias && /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("span", { className: "block truncate text-caption text-[var(--color-neutral-500)]", children: [
|
|
1115
1097
|
"also known as ",
|
|
1116
1098
|
artist.matchedAlias
|
|
1117
1099
|
] })
|
|
@@ -1125,7 +1107,7 @@ function useArtistSearchGroup(getBaseUrl, text, onSelect, enabled = true) {
|
|
|
1125
1107
|
|
|
1126
1108
|
// src/genre-tree/search/useSongSearchGroup.tsx
|
|
1127
1109
|
var import_genre_tree7 = require("@behindthemusictree/app-kit/genre-tree");
|
|
1128
|
-
var
|
|
1110
|
+
var import_jsx_runtime19 = require("react/jsx-runtime");
|
|
1129
1111
|
function useSongSearchGroup(getBaseUrl, text, onSelect, enabled = true) {
|
|
1130
1112
|
const search = (0, import_genre_tree7.useSongSearch)(getBaseUrl, enabled ? text : "");
|
|
1131
1113
|
if (!enabled) return void 0;
|
|
@@ -1134,9 +1116,9 @@ function useSongSearchGroup(getBaseUrl, text, onSelect, enabled = true) {
|
|
|
1134
1116
|
label: "Songs",
|
|
1135
1117
|
items: search.songs.map((song) => ({
|
|
1136
1118
|
key: song.uuid,
|
|
1137
|
-
content: /* @__PURE__ */ (0,
|
|
1138
|
-
/* @__PURE__ */ (0,
|
|
1139
|
-
/* @__PURE__ */ (0,
|
|
1119
|
+
content: /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("span", { className: (0, import_genre_tree7.isSongSearchResultPlayable)(song) ? void 0 : "opacity-60", children: [
|
|
1120
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "block truncate font-medium", children: song.title }),
|
|
1121
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.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 ") })
|
|
1140
1122
|
] }),
|
|
1141
1123
|
onSelect: () => onSelect(song)
|
|
1142
1124
|
})),
|
|
@@ -1147,7 +1129,7 @@ function useSongSearchGroup(getBaseUrl, text, onSelect, enabled = true) {
|
|
|
1147
1129
|
|
|
1148
1130
|
// src/genre-tree/search/useGenreRemoteSearchGroup.tsx
|
|
1149
1131
|
var import_genre_tree8 = require("@behindthemusictree/app-kit/genre-tree");
|
|
1150
|
-
var
|
|
1132
|
+
var import_jsx_runtime20 = require("react/jsx-runtime");
|
|
1151
1133
|
function useGenreRemoteSearchGroup(getBaseUrl, text, onSelect, { key = "genres", label = "Genres", filter, describe, ...options } = {}) {
|
|
1152
1134
|
const search = (0, import_genre_tree8.useGenreRemoteSearch)(getBaseUrl, text, options);
|
|
1153
1135
|
const genres = filter ? search.genres.filter(filter) : search.genres;
|
|
@@ -1156,12 +1138,12 @@ function useGenreRemoteSearchGroup(getBaseUrl, text, onSelect, { key = "genres",
|
|
|
1156
1138
|
label,
|
|
1157
1139
|
items: genres.map((genre) => ({
|
|
1158
1140
|
key: genre.uuid,
|
|
1159
|
-
content: /* @__PURE__ */ (0,
|
|
1160
|
-
/* @__PURE__ */ (0,
|
|
1141
|
+
content: /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(import_jsx_runtime20.Fragment, { children: [
|
|
1142
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("span", { className: "block truncate font-medium", children: [
|
|
1161
1143
|
genre.name,
|
|
1162
|
-
genre.isUmbrella && /* @__PURE__ */ (0,
|
|
1144
|
+
genre.isUmbrella && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "ml-2 text-caption font-normal italic text-[var(--color-text-muted)]", children: "umbrella" })
|
|
1163
1145
|
] }),
|
|
1164
|
-
/* @__PURE__ */ (0,
|
|
1146
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "block truncate text-caption text-[var(--color-neutral-500)]", children: describe?.(genre) ?? `${genre.treeName} \xB7 ${genre.root.name}` })
|
|
1165
1147
|
] }),
|
|
1166
1148
|
onSelect: () => onSelect(genre)
|
|
1167
1149
|
})),
|
|
@@ -1171,7 +1153,7 @@ function useGenreRemoteSearchGroup(getBaseUrl, text, onSelect, { key = "genres",
|
|
|
1171
1153
|
}
|
|
1172
1154
|
|
|
1173
1155
|
// src/genre-tree/GenreSearch.tsx
|
|
1174
|
-
var
|
|
1156
|
+
var import_jsx_runtime21 = require("react/jsx-runtime");
|
|
1175
1157
|
function GenreSearch({
|
|
1176
1158
|
genrePlaylists,
|
|
1177
1159
|
onSelect,
|
|
@@ -1200,9 +1182,9 @@ function GenreSearch({
|
|
|
1200
1182
|
label: hasExtras ? "Genres" : void 0,
|
|
1201
1183
|
items: results.map((genrePlaylist) => ({
|
|
1202
1184
|
key: genrePlaylist.uuid,
|
|
1203
|
-
content: /* @__PURE__ */ (0,
|
|
1185
|
+
content: /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(import_jsx_runtime21.Fragment, { children: [
|
|
1204
1186
|
genrePlaylist.name,
|
|
1205
|
-
genrePlaylist.isUmbrella && /* @__PURE__ */ (0,
|
|
1187
|
+
genrePlaylist.isUmbrella && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { className: "ml-2 text-caption italic text-[var(--color-text-muted)]", children: "umbrella" })
|
|
1206
1188
|
] }),
|
|
1207
1189
|
onSelect: () => select(genrePlaylist)
|
|
1208
1190
|
}))
|
|
@@ -1211,7 +1193,7 @@ function GenreSearch({
|
|
|
1211
1193
|
(group) => active ? group : { ...group, items: [], status: "", loading: false }
|
|
1212
1194
|
)
|
|
1213
1195
|
];
|
|
1214
|
-
return /* @__PURE__ */ (0,
|
|
1196
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.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_runtime21.jsx)(
|
|
1215
1197
|
SearchBox,
|
|
1216
1198
|
{
|
|
1217
1199
|
label,
|
|
@@ -1231,14 +1213,14 @@ function GenreSearch({
|
|
|
1231
1213
|
clear();
|
|
1232
1214
|
onQueryChange?.("");
|
|
1233
1215
|
} : void 0,
|
|
1234
|
-
leading: onPrevious && /* @__PURE__ */ (0,
|
|
1216
|
+
leading: onPrevious && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("button", { type: "button", "aria-label": "Previous", title: "Previous", className: import_ui7.SEARCH_LEADING_BUTTON_CLASS, onClick: onPrevious, children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_lucide_react7.ArrowLeft, { "aria-hidden": "true", className: "h-4 w-4" }) }),
|
|
1235
1217
|
onFocus
|
|
1236
1218
|
}
|
|
1237
1219
|
) });
|
|
1238
1220
|
}
|
|
1239
1221
|
|
|
1240
1222
|
// src/genre-tree/GenreTreeSearch.tsx
|
|
1241
|
-
var
|
|
1223
|
+
var import_jsx_runtime22 = require("react/jsx-runtime");
|
|
1242
1224
|
function GenreTreeSearch({
|
|
1243
1225
|
artistBaseUrl,
|
|
1244
1226
|
songBaseUrl,
|
|
@@ -1258,7 +1240,7 @@ function GenreTreeSearch({
|
|
|
1258
1240
|
const deferredQuery = (0, import_react9.useDeferredValue)(query);
|
|
1259
1241
|
const artistGroup = useArtistSearchGroup(artistBaseUrl, deferredQuery, onArtistSelect, artistSearch);
|
|
1260
1242
|
const songGroup = useSongSearchGroup(songBaseUrl, deferredQuery, onSongSelect, songSearch);
|
|
1261
|
-
const render = (hostGroups) => /* @__PURE__ */ (0,
|
|
1243
|
+
const render = (hostGroups) => /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
1262
1244
|
GenreSearch,
|
|
1263
1245
|
{
|
|
1264
1246
|
...props,
|
|
@@ -1273,27 +1255,27 @@ function GenreTreeSearch({
|
|
|
1273
1255
|
extraGroups: [...extraGroups, ...hostGroups, artistGroup, songGroup].filter((group) => group !== void 0)
|
|
1274
1256
|
}
|
|
1275
1257
|
);
|
|
1276
|
-
return SearchGroups ? /* @__PURE__ */ (0,
|
|
1258
|
+
return SearchGroups ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(SearchGroups, { query: deferredQuery, focused, onSelectGenre, children: render }) : render([]);
|
|
1277
1259
|
}
|
|
1278
1260
|
|
|
1279
1261
|
// src/genre-tree/GenreDetailPanel.tsx
|
|
1280
|
-
var
|
|
1262
|
+
var import_react15 = require("react");
|
|
1281
1263
|
var import_genre_tree_view4 = require("@behindthemusictree/genre-tree-view");
|
|
1282
|
-
var
|
|
1283
|
-
var
|
|
1284
|
-
var
|
|
1264
|
+
var import_ui13 = require("@behindthemusictree/ui");
|
|
1265
|
+
var import_lucide_react13 = require("lucide-react");
|
|
1266
|
+
var import_genre_tree20 = require("@behindthemusictree/app-kit/genre-tree");
|
|
1285
1267
|
|
|
1286
1268
|
// src/genre-tree/GenreInfoPanelBody.tsx
|
|
1287
|
-
var
|
|
1288
|
-
var import_track_noun4 = require("@behindthemusictree/app-kit/track-noun");
|
|
1289
|
-
var import_player6 = require("@behindthemusictree/app-kit/player");
|
|
1269
|
+
var import_genre_tree19 = require("@behindthemusictree/app-kit/genre-tree");
|
|
1290
1270
|
|
|
1291
1271
|
// src/genre-tree/GenreActionBand.tsx
|
|
1292
1272
|
var import_lucide_react11 = require("lucide-react");
|
|
1273
|
+
var import_ui9 = require("@behindthemusictree/ui");
|
|
1293
1274
|
|
|
1294
1275
|
// src/genre-tree/ShareActionButton.tsx
|
|
1295
1276
|
var import_lucide_react10 = require("lucide-react");
|
|
1296
|
-
var
|
|
1277
|
+
var import_ui8 = require("@behindthemusictree/ui");
|
|
1278
|
+
var import_popup3 = require("@behindthemusictree/app-kit/popup");
|
|
1297
1279
|
|
|
1298
1280
|
// src/genre-tree/SharePopup.tsx
|
|
1299
1281
|
var import_react10 = require("react");
|
|
@@ -1302,12 +1284,12 @@ var import_fa3 = require("react-icons/fa");
|
|
|
1302
1284
|
var import_si = require("react-icons/si");
|
|
1303
1285
|
|
|
1304
1286
|
// src/genre-tree/ShareDestinationButton.tsx
|
|
1305
|
-
var
|
|
1287
|
+
var import_jsx_runtime23 = require("react/jsx-runtime");
|
|
1306
1288
|
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";
|
|
1307
1289
|
function Contents({ icon, label }) {
|
|
1308
|
-
return /* @__PURE__ */ (0,
|
|
1309
|
-
/* @__PURE__ */ (0,
|
|
1310
|
-
/* @__PURE__ */ (0,
|
|
1290
|
+
return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(import_jsx_runtime23.Fragment, { children: [
|
|
1291
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.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 }),
|
|
1292
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { className: "max-w-full truncate", children: label })
|
|
1311
1293
|
] });
|
|
1312
1294
|
}
|
|
1313
1295
|
function ShareDestinationButton({
|
|
@@ -1319,29 +1301,29 @@ function ShareDestinationButton({
|
|
|
1319
1301
|
ariaLabel
|
|
1320
1302
|
}) {
|
|
1321
1303
|
if (href) {
|
|
1322
|
-
return /* @__PURE__ */ (0,
|
|
1304
|
+
return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("a", { href, target: "_blank", rel: "noopener noreferrer", "aria-label": ariaLabel, className, children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(Contents, { icon, label }) });
|
|
1323
1305
|
}
|
|
1324
|
-
return /* @__PURE__ */ (0,
|
|
1306
|
+
return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("button", { type: "button", onClick, disabled, "aria-label": ariaLabel, className, children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(Contents, { icon, label }) });
|
|
1325
1307
|
}
|
|
1326
1308
|
|
|
1327
1309
|
// src/genre-tree/SharePreviewCard.tsx
|
|
1328
1310
|
var import_lucide_react8 = require("lucide-react");
|
|
1329
|
-
var
|
|
1311
|
+
var import_jsx_runtime24 = require("react/jsx-runtime");
|
|
1330
1312
|
function SharePreviewCard({ target, url }) {
|
|
1331
1313
|
const Icon = { genre: import_lucide_react8.Music2, artist: import_lucide_react8.UserRound, song: import_lucide_react8.Music }[target.kind];
|
|
1332
1314
|
const typeLabel = { genre: "Genre", artist: "Artist", song: "Song" }[target.kind];
|
|
1333
|
-
return /* @__PURE__ */ (0,
|
|
1334
|
-
/* @__PURE__ */ (0,
|
|
1335
|
-
/* @__PURE__ */ (0,
|
|
1336
|
-
/* @__PURE__ */ (0,
|
|
1337
|
-
/* @__PURE__ */ (0,
|
|
1338
|
-
/* @__PURE__ */ (0,
|
|
1315
|
+
return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { className: "rounded-3xl bg-[var(--color-surface-muted)] p-4", children: /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { className: "flex min-h-32 overflow-hidden rounded-2xl bg-[var(--color-surface)] shadow-lg", children: [
|
|
1316
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.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_runtime24.jsx)(Icon, { "aria-hidden": "true", className: "h-10 w-10" }) }),
|
|
1317
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { className: "flex min-w-0 flex-1 flex-col justify-center gap-1 p-4", children: [
|
|
1318
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)("span", { className: "text-caption font-medium uppercase tracking-wide text-[var(--color-text-muted)]", children: typeLabel }),
|
|
1319
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)("span", { className: "truncate text-base font-semibold text-[var(--color-text)]", title: target.name, children: target.name }),
|
|
1320
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)("span", { className: "truncate text-body text-[var(--color-primary)]", title: url, children: url })
|
|
1339
1321
|
] })
|
|
1340
1322
|
] }) });
|
|
1341
1323
|
}
|
|
1342
1324
|
|
|
1343
1325
|
// src/genre-tree/SharePopup.tsx
|
|
1344
|
-
var
|
|
1326
|
+
var import_jsx_runtime25 = require("react/jsx-runtime");
|
|
1345
1327
|
function resolveAbsoluteUrl(url) {
|
|
1346
1328
|
try {
|
|
1347
1329
|
const parsed = new URL(url, window.location.href);
|
|
@@ -1416,8 +1398,8 @@ function SharePopup({ target, url, onClose }) {
|
|
|
1416
1398
|
setShareError("Could not open the share options.");
|
|
1417
1399
|
}
|
|
1418
1400
|
};
|
|
1419
|
-
return /* @__PURE__ */ (0,
|
|
1420
|
-
/* @__PURE__ */ (0,
|
|
1401
|
+
return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(import_jsx_runtime25.Fragment, { children: [
|
|
1402
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
|
|
1421
1403
|
BasePopup_default,
|
|
1422
1404
|
{
|
|
1423
1405
|
title: "Share",
|
|
@@ -1432,88 +1414,83 @@ function SharePopup({ target, url, onClose }) {
|
|
|
1432
1414
|
titleTextClassName: "!text-xl !font-semibold !text-[var(--color-text)]",
|
|
1433
1415
|
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)]",
|
|
1434
1416
|
contentClassName: "!rounded-none !bg-transparent !px-6 !pb-6 !pt-2",
|
|
1435
|
-
children: /* @__PURE__ */ (0,
|
|
1436
|
-
/* @__PURE__ */ (0,
|
|
1437
|
-
/* @__PURE__ */ (0,
|
|
1438
|
-
/* @__PURE__ */ (0,
|
|
1417
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "flex flex-col gap-4", children: [
|
|
1418
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)(SharePreviewCard, { target, url: absoluteUrl || url }),
|
|
1419
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "grid grid-cols-3 gap-1 rounded-3xl bg-[var(--color-surface)] p-3 sm:grid-cols-4", children: [
|
|
1420
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
|
|
1439
1421
|
ShareDestinationButton,
|
|
1440
1422
|
{
|
|
1441
1423
|
label: "Copy Link",
|
|
1442
|
-
icon: /* @__PURE__ */ (0,
|
|
1424
|
+
icon: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_lucide_react9.Link2, { "aria-hidden": "true", className: "h-6 w-6" }),
|
|
1443
1425
|
onClick: () => void handleCopy(),
|
|
1444
1426
|
ariaLabel: "Copy link",
|
|
1445
1427
|
disabled: !absoluteUrl
|
|
1446
1428
|
}
|
|
1447
1429
|
),
|
|
1448
|
-
/* @__PURE__ */ (0,
|
|
1430
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
|
|
1449
1431
|
ShareDestinationButton,
|
|
1450
1432
|
{
|
|
1451
1433
|
label: "WhatsApp",
|
|
1452
|
-
icon: /* @__PURE__ */ (0,
|
|
1434
|
+
icon: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_fa3.FaWhatsapp, { "aria-hidden": "true", className: "h-9 w-9 text-[#25D366]" }),
|
|
1453
1435
|
href: destinationUrls?.whatsapp,
|
|
1454
1436
|
ariaLabel: `Share ${target.name} via WhatsApp`,
|
|
1455
1437
|
disabled: !absoluteUrl
|
|
1456
1438
|
}
|
|
1457
1439
|
),
|
|
1458
|
-
/* @__PURE__ */ (0,
|
|
1440
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
|
|
1459
1441
|
ShareDestinationButton,
|
|
1460
1442
|
{
|
|
1461
1443
|
label: "Gmail",
|
|
1462
|
-
icon: /* @__PURE__ */ (0,
|
|
1444
|
+
icon: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_si.SiGmail, { "aria-hidden": "true", className: "h-8 w-8 text-[#EA4335]" }),
|
|
1463
1445
|
href: destinationUrls?.gmail,
|
|
1464
1446
|
ariaLabel: `Email ${target.name} with Gmail`,
|
|
1465
1447
|
disabled: !absoluteUrl
|
|
1466
1448
|
}
|
|
1467
1449
|
),
|
|
1468
|
-
canUseNativeShare && /* @__PURE__ */ (0,
|
|
1450
|
+
canUseNativeShare && /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
|
|
1469
1451
|
ShareDestinationButton,
|
|
1470
1452
|
{
|
|
1471
1453
|
label: "More",
|
|
1472
|
-
icon: /* @__PURE__ */ (0,
|
|
1454
|
+
icon: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_lucide_react9.Share2, { "aria-hidden": "true", className: "h-6 w-6" }),
|
|
1473
1455
|
onClick: () => void handleNativeShare(),
|
|
1474
1456
|
ariaLabel: "More sharing options",
|
|
1475
1457
|
disabled: !absoluteUrl
|
|
1476
1458
|
}
|
|
1477
1459
|
)
|
|
1478
1460
|
] }),
|
|
1479
|
-
copyStatus === "failed" && /* @__PURE__ */ (0,
|
|
1480
|
-
shareError && /* @__PURE__ */ (0,
|
|
1461
|
+
copyStatus === "failed" && /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("p", { role: "alert", className: "text-center text-body text-[var(--color-red-500)]", children: "Could not copy the link." }),
|
|
1462
|
+
shareError && /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("p", { role: "alert", className: "text-center text-body text-[var(--color-red-500)]", children: shareError })
|
|
1481
1463
|
] })
|
|
1482
1464
|
}
|
|
1483
1465
|
),
|
|
1484
|
-
toastId > 0 && /* @__PURE__ */ (0,
|
|
1466
|
+
toastId > 0 && /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(Toast, { message: "Link copied", onClose: dismissToast }, toastId)
|
|
1485
1467
|
] });
|
|
1486
1468
|
}
|
|
1487
1469
|
|
|
1488
1470
|
// src/genre-tree/ShareActionButton.tsx
|
|
1489
|
-
var
|
|
1471
|
+
var import_jsx_runtime26 = require("react/jsx-runtime");
|
|
1490
1472
|
function ShareActionButton({ target, url }) {
|
|
1491
|
-
const { showPopup, hidePopup } = (0,
|
|
1473
|
+
const { showPopup, hidePopup } = (0, import_popup3.usePopup)();
|
|
1492
1474
|
const openSharePopup = () => {
|
|
1493
|
-
showPopup(/* @__PURE__ */ (0,
|
|
1475
|
+
showPopup(/* @__PURE__ */ (0, import_jsx_runtime26.jsx)(SharePopup, { target, url, onClose: hidePopup }));
|
|
1494
1476
|
};
|
|
1495
|
-
return /* @__PURE__ */ (0,
|
|
1496
|
-
|
|
1477
|
+
return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
|
|
1478
|
+
import_ui8.ActionButton,
|
|
1497
1479
|
{
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
className: "group flex flex-col items-center gap-1 w-16 text-caption text-center text-[var(--color-text)] focus-visible:outline-none",
|
|
1480
|
+
icon: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(import_lucide_react10.Share2, { "aria-hidden": "true", className: "w-5 h-5" }),
|
|
1481
|
+
label: "Share",
|
|
1501
1482
|
"aria-label": `Share ${target.name}`,
|
|
1502
1483
|
title: `Share ${target.name}`,
|
|
1503
|
-
|
|
1504
|
-
/* @__PURE__ */ (0, import_jsx_runtime25.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_runtime25.jsx)(import_lucide_react10.Share2, { "aria-hidden": "true", className: "w-5 h-5" }) }),
|
|
1505
|
-
"Share"
|
|
1506
|
-
]
|
|
1484
|
+
onClick: openSharePopup
|
|
1507
1485
|
}
|
|
1508
1486
|
);
|
|
1509
1487
|
}
|
|
1510
1488
|
|
|
1511
1489
|
// src/genre-tree/GenreActionBand.tsx
|
|
1512
|
-
var
|
|
1490
|
+
var import_jsx_runtime27 = require("react/jsx-runtime");
|
|
1513
1491
|
function GenreActionBand({
|
|
1514
1492
|
node,
|
|
1515
|
-
|
|
1516
|
-
isPlaying = false,
|
|
1493
|
+
playActions,
|
|
1517
1494
|
onZoomIn,
|
|
1518
1495
|
onAddChild,
|
|
1519
1496
|
onRename,
|
|
@@ -1527,36 +1504,28 @@ function GenreActionBand({
|
|
|
1527
1504
|
}) {
|
|
1528
1505
|
const items = [];
|
|
1529
1506
|
const adminItems = [];
|
|
1530
|
-
if (onPlayPause) {
|
|
1531
|
-
items.push({
|
|
1532
|
-
key: "play-pause",
|
|
1533
|
-
label: isPlaying ? "Pause" : "Play",
|
|
1534
|
-
icon: isPlaying ? /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(import_lucide_react11.Pause, { "aria-hidden": "true", className: "w-5 h-5" }) : /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(import_lucide_react11.Play, { "aria-hidden": "true", className: "w-5 h-5" }),
|
|
1535
|
-
onClick: onPlayPause
|
|
1536
|
-
});
|
|
1537
|
-
}
|
|
1538
1507
|
if (onZoomIn) {
|
|
1539
1508
|
items.push({
|
|
1540
1509
|
key: "zoom-in",
|
|
1541
1510
|
label: "Focus",
|
|
1542
|
-
icon: /* @__PURE__ */ (0,
|
|
1511
|
+
icon: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_lucide_react11.ZoomIn, { "aria-hidden": "true", className: "w-5 h-5" }),
|
|
1543
1512
|
onClick: onZoomIn
|
|
1544
1513
|
});
|
|
1545
1514
|
}
|
|
1546
1515
|
if (onAddChild) {
|
|
1547
|
-
adminItems.push({ key: "add-child", label: "Add", icon: /* @__PURE__ */ (0,
|
|
1516
|
+
adminItems.push({ key: "add-child", label: "Add", icon: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_lucide_react11.Plus, { "aria-hidden": "true", className: "w-5 h-5" }), onClick: onAddChild });
|
|
1548
1517
|
}
|
|
1549
1518
|
if (onRename) {
|
|
1550
|
-
adminItems.push({ key: "rename", label: "Rename", icon: /* @__PURE__ */ (0,
|
|
1519
|
+
adminItems.push({ key: "rename", label: "Rename", icon: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_lucide_react11.Pencil, { "aria-hidden": "true", className: "w-5 h-5" }), onClick: onRename });
|
|
1551
1520
|
}
|
|
1552
1521
|
if (onChangeParent) {
|
|
1553
|
-
adminItems.push({ key: "change-parent", label: "Parent", icon: /* @__PURE__ */ (0,
|
|
1522
|
+
adminItems.push({ key: "change-parent", label: "Parent", icon: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_lucide_react11.MoveUpRight, { "aria-hidden": "true", className: "w-5 h-5" }), onClick: onChangeParent });
|
|
1554
1523
|
}
|
|
1555
1524
|
if (onToggleSide) {
|
|
1556
1525
|
adminItems.push({
|
|
1557
1526
|
key: "toggle-side",
|
|
1558
1527
|
label: side === "pop" ? "Make core" : "Make pop",
|
|
1559
|
-
icon: /* @__PURE__ */ (0,
|
|
1528
|
+
icon: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_lucide_react11.ArrowLeftRight, { "aria-hidden": "true", className: "w-5 h-5" }),
|
|
1560
1529
|
onClick: onToggleSide,
|
|
1561
1530
|
disabled: !!toggleSideDisabledReason,
|
|
1562
1531
|
title: toggleSideDisabledReason
|
|
@@ -1571,60 +1540,139 @@ function GenreActionBand({
|
|
|
1571
1540
|
disabled: action.enabled ? !action.enabled(node) : false
|
|
1572
1541
|
});
|
|
1573
1542
|
}
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1543
|
+
const renderItems = (list) => list.map((item) => /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_ui9.ActionButton, { icon: item.icon, label: item.label, disabled: item.disabled, title: item.title, onClick: item.onClick }, item.key));
|
|
1544
|
+
if (!playActions && items.length === 0 && adminItems.length === 0 && !(shareTarget && shareUrl)) return null;
|
|
1545
|
+
return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_ui9.PanelBleed, { children: /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(
|
|
1546
|
+
import_ui9.ActionBand,
|
|
1577
1547
|
{
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
title: item.title,
|
|
1581
|
-
onClick: item.onClick,
|
|
1582
|
-
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",
|
|
1548
|
+
className: "genre-action-band",
|
|
1549
|
+
section: { title: "Admin", label: "Admin actions", children: renderItems(adminItems) },
|
|
1583
1550
|
children: [
|
|
1584
|
-
|
|
1585
|
-
|
|
1551
|
+
playActions,
|
|
1552
|
+
renderItems(items),
|
|
1553
|
+
shareTarget && shareUrl && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(ShareActionButton, { target: shareTarget, url: shareUrl })
|
|
1586
1554
|
]
|
|
1587
|
-
}
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1555
|
+
}
|
|
1556
|
+
) });
|
|
1557
|
+
}
|
|
1558
|
+
|
|
1559
|
+
// src/genre-tree/GenrePlayActions.tsx
|
|
1560
|
+
var import_lucide_react12 = require("lucide-react");
|
|
1561
|
+
var import_ui10 = require("@behindthemusictree/ui");
|
|
1562
|
+
var import_genre_tree10 = require("@behindthemusictree/app-kit/genre-tree");
|
|
1563
|
+
var import_player4 = require("@behindthemusictree/app-kit/player");
|
|
1564
|
+
|
|
1565
|
+
// src/genre-tree/RegionGlobeIcon.tsx
|
|
1566
|
+
var import_react11 = require("react");
|
|
1567
|
+
|
|
1568
|
+
// src/genre-tree/regionGlobePaths.ts
|
|
1569
|
+
var REGION_GLOBE_PATHS = {
|
|
1570
|
+
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",
|
|
1571
|
+
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",
|
|
1572
|
+
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"
|
|
1573
|
+
};
|
|
1574
|
+
var REGION_GLOBES = ["africa", "americas", "asia"];
|
|
1575
|
+
|
|
1576
|
+
// src/genre-tree/RegionGlobeIcon.tsx
|
|
1577
|
+
var import_jsx_runtime28 = require("react/jsx-runtime");
|
|
1578
|
+
var ROTATION_INTERVAL_MS = 3e3;
|
|
1579
|
+
function RegionGlobeIcon({ className: className2 }) {
|
|
1580
|
+
const [index, setIndex] = (0, import_react11.useState)(0);
|
|
1581
|
+
(0, import_react11.useEffect)(() => {
|
|
1582
|
+
const reducedMotion = window.matchMedia("(prefers-reduced-motion: reduce)");
|
|
1583
|
+
let timer;
|
|
1584
|
+
const sync = () => {
|
|
1585
|
+
clearInterval(timer);
|
|
1586
|
+
timer = reducedMotion.matches ? void 0 : setInterval(() => setIndex((i) => (i + 1) % REGION_GLOBES.length), ROTATION_INTERVAL_MS);
|
|
1587
|
+
};
|
|
1588
|
+
sync();
|
|
1589
|
+
reducedMotion.addEventListener("change", sync);
|
|
1590
|
+
return () => {
|
|
1591
|
+
reducedMotion.removeEventListener("change", sync);
|
|
1592
|
+
clearInterval(timer);
|
|
1593
|
+
};
|
|
1594
|
+
}, []);
|
|
1595
|
+
return /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("svg", { viewBox: "0 0 512 512", fill: "currentColor", className: className2, "aria-hidden": true, children: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("path", { "data-testid": "region-globe-path", d: REGION_GLOBE_PATHS[REGION_GLOBES[index]] }) });
|
|
1596
|
+
}
|
|
1597
|
+
|
|
1598
|
+
// src/genre-tree/treeMarkPath.ts
|
|
1599
|
+
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";
|
|
1600
|
+
|
|
1601
|
+
// src/genre-tree/TreeMarkIcon.tsx
|
|
1602
|
+
var import_jsx_runtime29 = require("react/jsx-runtime");
|
|
1603
|
+
function TreeMarkIcon({ className: className2 }) {
|
|
1604
|
+
return /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("svg", { viewBox: "0 0 551 567", fill: "currentColor", className: className2, "aria-hidden": true, children: /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("path", { transform: "translate(0 567) scale(0.1 -0.1)", d: TREE_MARK_PATH }) });
|
|
1605
|
+
}
|
|
1606
|
+
|
|
1607
|
+
// src/genre-tree/GenrePlayActions.tsx
|
|
1608
|
+
var import_jsx_runtime30 = require("react/jsx-runtime");
|
|
1609
|
+
function PlayIcon({ kind }) {
|
|
1610
|
+
return /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("span", { "aria-hidden": "true", className: "relative flex items-center justify-center w-5 h-5", children: [
|
|
1611
|
+
kind === "tree" && /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(TreeMarkIcon, { className: "absolute -left-1.5 -top-1.5 w-8 h-8 opacity-35" }),
|
|
1612
|
+
kind === "map" && /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(RegionGlobeIcon, { className: "absolute -left-1.5 -top-1.5 w-8 h-8 opacity-35" }),
|
|
1613
|
+
kind === "tree-map" && /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)(import_jsx_runtime30.Fragment, { children: [
|
|
1614
|
+
/* @__PURE__ */ (0, import_jsx_runtime30.jsx)(TreeMarkIcon, { className: "absolute -left-1.5 -top-1.5 w-8 h-8 opacity-35 [clip-path:inset(0_50%_0_0)]" }),
|
|
1615
|
+
/* @__PURE__ */ (0, import_jsx_runtime30.jsx)(RegionGlobeIcon, { className: "absolute -left-1.5 -top-1.5 w-8 h-8 opacity-35 [clip-path:inset(0_0_0_50%)]" })
|
|
1594
1616
|
] }),
|
|
1595
|
-
|
|
1596
|
-
"section",
|
|
1597
|
-
{
|
|
1598
|
-
"aria-label": "Admin actions",
|
|
1599
|
-
className: `px-3.5 py-3 ${items.length > 0 ? "border-t border-[var(--color-border)]" : ""}`,
|
|
1600
|
-
children: [
|
|
1601
|
-
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)("h3", { className: "mb-2 text-caption font-semibold uppercase tracking-wide text-[var(--color-text-muted)]", children: "Admin" }),
|
|
1602
|
-
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { className: "flex flex-wrap gap-1", children: renderItems(adminItems) })
|
|
1603
|
-
]
|
|
1604
|
-
}
|
|
1605
|
-
)
|
|
1617
|
+
/* @__PURE__ */ (0, import_jsx_runtime30.jsx)(import_lucide_react12.Play, { className: "relative w-5 h-5 fill-[var(--color-surface)]" })
|
|
1606
1618
|
] });
|
|
1607
1619
|
}
|
|
1620
|
+
function playOptions(playlist) {
|
|
1621
|
+
if (!("genreOnlyTracksCount" in playlist)) return [{ key: "all", label: "Play", icon: "play", count: playlist.tracksCount }];
|
|
1622
|
+
const direct = { key: "direct", label: "Genre", icon: "play", selection: { coverage: "genreOnly" }, count: (0, import_genre_tree10.genreMusicCount)(playlist, { coverage: "genreOnly" }) };
|
|
1623
|
+
const scopes = playlist.genreAndSubgenresTracksCount;
|
|
1624
|
+
const inclusive = (label, icon, subgenres) => {
|
|
1625
|
+
const selection = { coverage: "genreAndSubgenres", subgenres };
|
|
1626
|
+
return { key: subgenres, label, icon, selection, count: (0, import_genre_tree10.genreMusicCount)(playlist, selection) };
|
|
1627
|
+
};
|
|
1628
|
+
return "canonical" in scopes ? [direct, inclusive("Canonical", "tree", "canonical"), inclusive("Regional", "map", "regional"), inclusive("All", "tree-map", "all")] : [direct, inclusive("All", "map", "all")];
|
|
1629
|
+
}
|
|
1630
|
+
function GenrePlayActions({ genrePlaylist, playback }) {
|
|
1631
|
+
const { isPlaying, setIsPlaying } = (0, import_player4.usePlayer)();
|
|
1632
|
+
const options = playOptions(genrePlaylist);
|
|
1633
|
+
return /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(import_jsx_runtime30.Fragment, { children: options.map((option) => {
|
|
1634
|
+
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());
|
|
1635
|
+
const playing = isCurrent && isPlaying;
|
|
1636
|
+
return /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
|
|
1637
|
+
import_ui10.ActionButton,
|
|
1638
|
+
{
|
|
1639
|
+
icon: playing ? /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(import_lucide_react12.Pause, { "aria-hidden": "true", className: "w-5 h-5" }) : /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(PlayIcon, { kind: option.icon }),
|
|
1640
|
+
label: playing ? "Pause" : option.label,
|
|
1641
|
+
caption: String(option.count),
|
|
1642
|
+
disabled: option.count === 0,
|
|
1643
|
+
title: option.count === 0 ? "No playable songs" : void 0,
|
|
1644
|
+
onClick: () => {
|
|
1645
|
+
if (isCurrent) {
|
|
1646
|
+
setIsPlaying(!isPlaying);
|
|
1647
|
+
return;
|
|
1648
|
+
}
|
|
1649
|
+
void playback.play(genrePlaylist, option.selection);
|
|
1650
|
+
}
|
|
1651
|
+
},
|
|
1652
|
+
option.key
|
|
1653
|
+
);
|
|
1654
|
+
}) });
|
|
1655
|
+
}
|
|
1608
1656
|
|
|
1609
1657
|
// src/genre-tree/GenreDetailExtras.tsx
|
|
1610
|
-
var
|
|
1611
|
-
var
|
|
1658
|
+
var import_ui12 = require("@behindthemusictree/ui");
|
|
1659
|
+
var import_genre_tree18 = require("@behindthemusictree/app-kit/genre-tree");
|
|
1612
1660
|
|
|
1613
1661
|
// src/genre-tree/ClampedText.tsx
|
|
1614
|
-
var
|
|
1615
|
-
var
|
|
1662
|
+
var import_react12 = require("react");
|
|
1663
|
+
var import_jsx_runtime31 = require("react/jsx-runtime");
|
|
1616
1664
|
function ClampedText({ children, className: className2 = "" }) {
|
|
1617
|
-
const ref = (0,
|
|
1618
|
-
const [expanded, setExpanded] = (0,
|
|
1619
|
-
const [overflows, setOverflows] = (0,
|
|
1620
|
-
(0,
|
|
1665
|
+
const ref = (0, import_react12.useRef)(null);
|
|
1666
|
+
const [expanded, setExpanded] = (0, import_react12.useState)(false);
|
|
1667
|
+
const [overflows, setOverflows] = (0, import_react12.useState)(false);
|
|
1668
|
+
(0, import_react12.useLayoutEffect)(() => {
|
|
1621
1669
|
const element = ref.current;
|
|
1622
1670
|
if (!element || expanded) return;
|
|
1623
1671
|
setOverflows(element.scrollHeight > element.clientHeight);
|
|
1624
1672
|
}, [children, expanded]);
|
|
1625
|
-
return /* @__PURE__ */ (0,
|
|
1626
|
-
/* @__PURE__ */ (0,
|
|
1627
|
-
(overflows || expanded) && /* @__PURE__ */ (0,
|
|
1673
|
+
return /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)(import_jsx_runtime31.Fragment, { children: [
|
|
1674
|
+
/* @__PURE__ */ (0, import_jsx_runtime31.jsx)("p", { ref, className: `${className2} ${expanded ? "" : "line-clamp-3"}`, children }),
|
|
1675
|
+
(overflows || expanded) && /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
|
|
1628
1676
|
"button",
|
|
1629
1677
|
{
|
|
1630
1678
|
type: "button",
|
|
@@ -1638,36 +1686,36 @@ function ClampedText({ children, className: className2 = "" }) {
|
|
|
1638
1686
|
}
|
|
1639
1687
|
|
|
1640
1688
|
// src/genre-tree/GenrePlaylistTracks.tsx
|
|
1641
|
-
var
|
|
1689
|
+
var import_react13 = require("react");
|
|
1642
1690
|
var import_react_query = require("@tanstack/react-query");
|
|
1643
1691
|
var import_zod = require("zod");
|
|
1644
1692
|
var import_fa4 = require("react-icons/fa");
|
|
1645
|
-
var
|
|
1693
|
+
var import_ui11 = require("@behindthemusictree/ui");
|
|
1646
1694
|
var import_auth2 = require("@behindthemusictree/app-kit/auth");
|
|
1695
|
+
var import_transport4 = require("@behindthemusictree/app-kit/transport");
|
|
1647
1696
|
var import_transport5 = require("@behindthemusictree/app-kit/transport");
|
|
1648
1697
|
var import_transport6 = require("@behindthemusictree/app-kit/transport");
|
|
1649
|
-
var import_transport7 = require("@behindthemusictree/app-kit/transport");
|
|
1650
|
-
var import_player4 = require("@behindthemusictree/app-kit/player");
|
|
1651
1698
|
var import_player5 = require("@behindthemusictree/app-kit/player");
|
|
1652
|
-
var
|
|
1653
|
-
var
|
|
1654
|
-
var
|
|
1699
|
+
var import_player6 = require("@behindthemusictree/app-kit/player");
|
|
1700
|
+
var import_popup4 = require("@behindthemusictree/app-kit/popup");
|
|
1701
|
+
var import_transport7 = require("@behindthemusictree/app-kit/transport");
|
|
1655
1702
|
var import_genre_tree12 = require("@behindthemusictree/app-kit/genre-tree");
|
|
1656
1703
|
var import_genre_tree13 = require("@behindthemusictree/app-kit/genre-tree");
|
|
1657
1704
|
var import_genre_tree14 = require("@behindthemusictree/app-kit/genre-tree");
|
|
1658
1705
|
var import_genre_tree15 = require("@behindthemusictree/app-kit/genre-tree");
|
|
1706
|
+
var import_genre_tree16 = require("@behindthemusictree/app-kit/genre-tree");
|
|
1659
1707
|
|
|
1660
1708
|
// src/genre-tree/MusicBrainzRecordingLink.tsx
|
|
1661
|
-
var
|
|
1662
|
-
var
|
|
1709
|
+
var import_genre_tree11 = require("@behindthemusictree/app-kit/genre-tree");
|
|
1710
|
+
var import_jsx_runtime32 = require("react/jsx-runtime");
|
|
1663
1711
|
function MusicBrainzRecordingLink({
|
|
1664
1712
|
song,
|
|
1665
1713
|
children,
|
|
1666
1714
|
className: className2 = ""
|
|
1667
1715
|
}) {
|
|
1668
|
-
const url = (0,
|
|
1669
|
-
if (!url) return /* @__PURE__ */ (0,
|
|
1670
|
-
return /* @__PURE__ */ (0,
|
|
1716
|
+
const url = (0, import_genre_tree11.musicBrainzRecordingUrl)(song);
|
|
1717
|
+
if (!url) return /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(import_jsx_runtime32.Fragment, { children });
|
|
1718
|
+
return /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
|
|
1671
1719
|
"a",
|
|
1672
1720
|
{
|
|
1673
1721
|
href: url,
|
|
@@ -1682,11 +1730,11 @@ function MusicBrainzRecordingLink({
|
|
|
1682
1730
|
}
|
|
1683
1731
|
|
|
1684
1732
|
// src/genre-tree/GenrePlaylistTracks.tsx
|
|
1685
|
-
var
|
|
1733
|
+
var import_genre_tree17 = require("@behindthemusictree/app-kit/genre-tree");
|
|
1686
1734
|
var import_track_noun2 = require("@behindthemusictree/app-kit/track-noun");
|
|
1687
|
-
var
|
|
1735
|
+
var import_jsx_runtime33 = require("react/jsx-runtime");
|
|
1688
1736
|
var CATALOGUE_PAGE_SIZE = 100;
|
|
1689
|
-
var SongPageSchema = (0,
|
|
1737
|
+
var SongPageSchema = (0, import_transport5.PaginatedResponseSchema)(import_genre_tree15.SongDetailedSchema).extend({
|
|
1690
1738
|
overallTotal: import_zod.z.number().nullable(),
|
|
1691
1739
|
page: import_zod.z.number().nullable(),
|
|
1692
1740
|
totalPages: import_zod.z.number().nullable()
|
|
@@ -1715,30 +1763,30 @@ function GenrePlaylistTracks({
|
|
|
1715
1763
|
renderTracksToolbar,
|
|
1716
1764
|
artist = null
|
|
1717
1765
|
}) {
|
|
1718
|
-
const { fetchGenrePlaylistTracksPage, playNewTrackListFromGenrePlaylist, playNewTrackListFromArtist, playNewTrackListFromGenreCatalogue } = (0,
|
|
1766
|
+
const { fetchGenrePlaylistTracksPage, playNewTrackListFromGenrePlaylist, playNewTrackListFromArtist, playNewTrackListFromGenreCatalogue } = (0, import_genre_tree16.useTrackList)();
|
|
1719
1767
|
const { session, sessionRestored } = (0, import_auth2.useSession)();
|
|
1720
|
-
const { playerTrackObject, playState, handlePlayPauseAction } = (0,
|
|
1721
|
-
const { showPopup } = (0,
|
|
1768
|
+
const { playerTrackObject, playState, handlePlayPauseAction } = (0, import_player5.usePlayer)();
|
|
1769
|
+
const { showPopup } = (0, import_popup4.usePopup)();
|
|
1722
1770
|
const trackNoun = (0, import_track_noun2.useTrackNoun)();
|
|
1723
1771
|
const uuid = genrePlaylist?.uuid;
|
|
1724
1772
|
const genreName = selectedGenreName ?? genrePlaylist?.name ?? "Genre";
|
|
1725
|
-
const { fetchBound } = (0,
|
|
1726
|
-
const playback = (0,
|
|
1773
|
+
const { fetchBound } = (0, import_transport4.usePlaybackFetch)(getBackendBaseUrl);
|
|
1774
|
+
const playback = (0, import_transport4.usePlaybackContext)();
|
|
1727
1775
|
const { data, isPending, isError, refetch, hasNextPage, isFetchingNextPage, fetchNextPage } = (0, import_react_query.useInfiniteQuery)({
|
|
1728
|
-
queryKey: [...scope === "me" ? uuid ?
|
|
1776
|
+
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] : []],
|
|
1729
1777
|
queryFn: async ({ pageParam }) => {
|
|
1730
1778
|
if (scope === "me") {
|
|
1731
1779
|
if (!uuid) throw new Error("Personal genre has no playlist");
|
|
1732
1780
|
return fetchGenrePlaylistTracksPage(uuid, scope, Number(pageParam));
|
|
1733
1781
|
}
|
|
1734
1782
|
const response = await fetchBound(
|
|
1735
|
-
|
|
1783
|
+
import_genre_tree14.libraryEndpoints.reference.songs.list(),
|
|
1736
1784
|
true,
|
|
1737
1785
|
false,
|
|
1738
1786
|
{},
|
|
1739
|
-
{ genre: genreUuid, ...(0,
|
|
1787
|
+
{ genre: genreUuid, ...(0, import_genre_tree12.genreMusicQueryParams)(selection), ...artist && { artist: artist.uuid }, pageSize: CATALOGUE_PAGE_SIZE, withTotal: false, ...pageParam && { cursor: pageParam } }
|
|
1740
1788
|
);
|
|
1741
|
-
const parsed = (0,
|
|
1789
|
+
const parsed = (0, import_transport6.parseWithLog)(SongPageSchema, response, "GenrePlaylistTracks");
|
|
1742
1790
|
return { tracks: parsed.results, total: parsed.overallTotal, nextPage: parsed.next ? nextCursor(parsed.next) : null };
|
|
1743
1791
|
},
|
|
1744
1792
|
initialPageParam: scope === "me" ? 1 : "",
|
|
@@ -1747,8 +1795,8 @@ function GenrePlaylistTracks({
|
|
|
1747
1795
|
retry: (failureCount, error) => failureCount < 1 && error instanceof DOMException && error.name === "AbortError",
|
|
1748
1796
|
retryDelay: 0
|
|
1749
1797
|
});
|
|
1750
|
-
const [sentinel, setSentinel] = (0,
|
|
1751
|
-
(0,
|
|
1798
|
+
const [sentinel, setSentinel] = (0, import_react13.useState)(null);
|
|
1799
|
+
(0, import_react13.useEffect)(() => {
|
|
1752
1800
|
if (!hasNextPage || isFetchingNextPage || !sentinel) return;
|
|
1753
1801
|
const observer = new IntersectionObserver((entries) => {
|
|
1754
1802
|
if (entries.some((entry) => entry.isIntersecting)) {
|
|
@@ -1770,35 +1818,36 @@ function GenrePlaylistTracks({
|
|
|
1770
1818
|
}) : 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"));
|
|
1771
1819
|
started.catch((error) => {
|
|
1772
1820
|
console.error("Failed to play genre playlist:", error);
|
|
1773
|
-
|
|
1821
|
+
if (error instanceof import_genre_tree16.TracksFailureAlreadyReportedError) return;
|
|
1822
|
+
showPopup(/* @__PURE__ */ (0, import_jsx_runtime33.jsx)(InternalErrorPopup, { errorCode: error instanceof import_transport7.AppError ? error.code : import_transport7.ErrorCode.CLIENT_UNKNOWN }));
|
|
1774
1823
|
});
|
|
1775
1824
|
};
|
|
1776
|
-
return /* @__PURE__ */ (0,
|
|
1825
|
+
return /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(import_ui11.PanelSection, { title: `${(0, import_track_noun2.capitalize)(trackNoun.plural)}${total !== void 0 ? ` (${total})` : ""}`, children: /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("div", { children: [
|
|
1777
1826
|
renderTracksToolbar?.(),
|
|
1778
|
-
scope === "me" && !genrePlaylist ? /* @__PURE__ */ (0,
|
|
1827
|
+
scope === "me" && !genrePlaylist ? /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("p", { children: "\u2014" }) : isPending ? /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(import_ui11.Skeleton, { className: "h-4 w-3/4", "aria-busy": "true" }) : isError && tracks.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("p", { role: "alert", children: [
|
|
1779
1828
|
"Couldn't load ",
|
|
1780
1829
|
trackNoun.plural,
|
|
1781
1830
|
".",
|
|
1782
1831
|
" ",
|
|
1783
|
-
/* @__PURE__ */ (0,
|
|
1784
|
-
] }) : tracks.length === 0 ? /* @__PURE__ */ (0,
|
|
1832
|
+
/* @__PURE__ */ (0, import_jsx_runtime33.jsx)("button", { type: "button", className: "underline", onClick: () => void refetch(), children: "Retry" })
|
|
1833
|
+
] }) : tracks.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("p", { children: "\u2014" }) : /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("ul", { className: "mt-1 max-h-64 overflow-y-auto text-body [container-type:inline-size]", "aria-label": `${genreName} ${trackNoun.plural}`, children: [
|
|
1785
1834
|
tracks.map((track, index) => {
|
|
1786
1835
|
const label = track.artists?.length ? `${track.title} \u2014 ${track.artists.map((artist2) => artist2.name).join(", ")}` : track.title;
|
|
1787
1836
|
const isCurrent = playerTrackObject?.track.id === track.uuid;
|
|
1788
|
-
const isPlaying = isCurrent && playState ===
|
|
1789
|
-
const text = /* @__PURE__ */ (0,
|
|
1790
|
-
/* @__PURE__ */ (0,
|
|
1791
|
-
track.artists?.length ? /* @__PURE__ */ (0,
|
|
1792
|
-
/* @__PURE__ */ (0,
|
|
1793
|
-
track.album && /* @__PURE__ */ (0,
|
|
1837
|
+
const isPlaying = isCurrent && playState === import_player6.PlayStates.PLAYING;
|
|
1838
|
+
const text = /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("span", { className: TEXT_CELL, children: [
|
|
1839
|
+
/* @__PURE__ */ (0, import_jsx_runtime33.jsx)("span", { className: TITLE_CELL, children: renderSongLink ? renderSongLink(track) : (0, import_genre_tree15.isSong)(track) ? /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(MusicBrainzRecordingLink, { song: track, className: "hover:underline focus-visible:underline", children: track.title }) : track.title }),
|
|
1840
|
+
track.artists?.length ? /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("span", { className: SEPARATOR, children: " \u2014 " }) : null,
|
|
1841
|
+
/* @__PURE__ */ (0, import_jsx_runtime33.jsx)("span", { className: COLUMN_CELL, children: track.artists?.length ? /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(import_genre_tree17.ArtistNames, { artists: track.artists, renderArtistLink }) : null }),
|
|
1842
|
+
track.album && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("span", { className: ALBUM_CELL, children: track.album.name })
|
|
1794
1843
|
] });
|
|
1795
1844
|
const leading = renderSongLeading?.(track, index);
|
|
1796
1845
|
const actions = renderSongActions?.(track);
|
|
1797
|
-
const isUnplayable = (0,
|
|
1846
|
+
const isUnplayable = (0, import_genre_tree15.isSong)(track) && (0, import_genre_tree15.songUnplayableReason)(track) !== null;
|
|
1798
1847
|
if (isUnplayable) {
|
|
1799
|
-
return /* @__PURE__ */ (0,
|
|
1848
|
+
return /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("li", { className: "flex min-h-8 items-center gap-1 px-1 opacity-50", children: [
|
|
1800
1849
|
leading,
|
|
1801
|
-
/* @__PURE__ */ (0,
|
|
1850
|
+
/* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
|
|
1802
1851
|
"button",
|
|
1803
1852
|
{
|
|
1804
1853
|
type: "button",
|
|
@@ -1806,27 +1855,27 @@ function GenrePlaylistTracks({
|
|
|
1806
1855
|
"aria-disabled": "true",
|
|
1807
1856
|
"aria-label": label,
|
|
1808
1857
|
className: "flex h-6 w-6 shrink-0 items-center justify-center rounded-full opacity-0 cursor-not-allowed",
|
|
1809
|
-
children: /* @__PURE__ */ (0,
|
|
1858
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(import_fa4.FaPlay, { size: 10 })
|
|
1810
1859
|
}
|
|
1811
1860
|
),
|
|
1812
1861
|
text,
|
|
1813
1862
|
actions
|
|
1814
1863
|
] }, track.uuid);
|
|
1815
1864
|
}
|
|
1816
|
-
return /* @__PURE__ */ (0,
|
|
1865
|
+
return /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(
|
|
1817
1866
|
"li",
|
|
1818
1867
|
{
|
|
1819
1868
|
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)]" : ""}`,
|
|
1820
1869
|
children: [
|
|
1821
1870
|
leading,
|
|
1822
|
-
/* @__PURE__ */ (0,
|
|
1871
|
+
/* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
|
|
1823
1872
|
"button",
|
|
1824
1873
|
{
|
|
1825
1874
|
type: "button",
|
|
1826
1875
|
"aria-label": `${isPlaying ? "Pause" : "Play"} ${label}`,
|
|
1827
|
-
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 !==
|
|
1876
|
+
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"}`,
|
|
1828
1877
|
onClick: () => isCurrent ? handlePlayPauseAction() : play(track.uuid),
|
|
1829
|
-
children: isCurrent && playState ===
|
|
1878
|
+
children: isCurrent && playState === import_player6.PlayStates.LOADING ? /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(import_ui11.RingLoader, { size: 10 }) : isPlaying ? /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(import_fa4.FaPause, { size: 10 }) : /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(import_fa4.FaPlay, { size: 10 })
|
|
1830
1879
|
}
|
|
1831
1880
|
),
|
|
1832
1881
|
text,
|
|
@@ -1836,7 +1885,7 @@ function GenrePlaylistTracks({
|
|
|
1836
1885
|
track.uuid
|
|
1837
1886
|
);
|
|
1838
1887
|
}),
|
|
1839
|
-
hasNextPage && /* @__PURE__ */ (0,
|
|
1888
|
+
hasNextPage && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("li", { ref: setSentinel, "aria-hidden": "true", className: "h-4" })
|
|
1840
1889
|
] })
|
|
1841
1890
|
] }) });
|
|
1842
1891
|
}
|
|
@@ -1844,7 +1893,7 @@ function GenrePlaylistTracks({
|
|
|
1844
1893
|
// src/genre-tree/GenreDetailExtras.tsx
|
|
1845
1894
|
var import_track_noun3 = require("@behindthemusictree/app-kit/track-noun");
|
|
1846
1895
|
var import_si2 = require("react-icons/si");
|
|
1847
|
-
var
|
|
1896
|
+
var import_jsx_runtime34 = require("react/jsx-runtime");
|
|
1848
1897
|
function GenreDetailExtras({
|
|
1849
1898
|
genreUuid,
|
|
1850
1899
|
genrePlaylist,
|
|
@@ -1863,24 +1912,24 @@ function GenreDetailExtras({
|
|
|
1863
1912
|
...trackSlots
|
|
1864
1913
|
}) {
|
|
1865
1914
|
const trackNoun = (0, import_track_noun3.useTrackNoun)();
|
|
1866
|
-
const { data: overview, isPending } = (0,
|
|
1915
|
+
const { data: overview, isPending } = (0, import_genre_tree18.useFetchGenreOverview)(
|
|
1867
1916
|
genreUuid,
|
|
1868
1917
|
scope,
|
|
1869
1918
|
getBackendBaseUrl,
|
|
1870
1919
|
criteriaOverviewSchema
|
|
1871
1920
|
);
|
|
1872
1921
|
if (isPending) {
|
|
1873
|
-
return /* @__PURE__ */ (0,
|
|
1874
|
-
/* @__PURE__ */ (0,
|
|
1922
|
+
return /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)(import_jsx_runtime34.Fragment, { children: [
|
|
1923
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsx)(import_ui12.PanelSection, { title: "Summary", children: /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("div", { "aria-busy": "true", "data-testid": "genre-detail-extras-skeleton", children: /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(import_ui12.Skeleton, { className: "h-4 w-3/4" }) }) }),
|
|
1875
1924
|
family
|
|
1876
1925
|
] });
|
|
1877
1926
|
}
|
|
1878
|
-
if (!overview) return /* @__PURE__ */ (0,
|
|
1927
|
+
if (!overview) return /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(import_jsx_runtime34.Fragment, { children: family });
|
|
1879
1928
|
const { summary, summarySourceUrl, essentialSongs } = overview;
|
|
1880
1929
|
const wikidataUrl = wikidataId ? `https://www.wikidata.org/wiki/${encodeURIComponent(wikidataId)}` : null;
|
|
1881
|
-
return /* @__PURE__ */ (0,
|
|
1882
|
-
(summarySourceUrl || wikidataUrl) && /* @__PURE__ */ (0,
|
|
1883
|
-
summarySourceUrl && /* @__PURE__ */ (0,
|
|
1930
|
+
return /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)(import_jsx_runtime34.Fragment, { children: [
|
|
1931
|
+
(summarySourceUrl || wikidataUrl) && /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(import_ui12.PanelSection, { title: "Links", children: /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("div", { className: "flex flex-wrap gap-x-3 gap-y-1 text-caption text-[var(--color-text)]", children: [
|
|
1932
|
+
summarySourceUrl && /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)(
|
|
1884
1933
|
"a",
|
|
1885
1934
|
{
|
|
1886
1935
|
href: summarySourceUrl,
|
|
@@ -1888,12 +1937,12 @@ function GenreDetailExtras({
|
|
|
1888
1937
|
rel: "noopener noreferrer",
|
|
1889
1938
|
className: "inline-flex items-center gap-1.5 text-[var(--color-text-muted)] hover:text-[var(--color-text)]",
|
|
1890
1939
|
children: [
|
|
1891
|
-
/* @__PURE__ */ (0,
|
|
1940
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsx)(import_si2.SiWikipedia, { "aria-hidden": "true", className: "h-3.5 w-3.5" }),
|
|
1892
1941
|
"Wikipedia"
|
|
1893
1942
|
]
|
|
1894
1943
|
}
|
|
1895
1944
|
),
|
|
1896
|
-
wikidataUrl && /* @__PURE__ */ (0,
|
|
1945
|
+
wikidataUrl && /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)(
|
|
1897
1946
|
"a",
|
|
1898
1947
|
{
|
|
1899
1948
|
href: wikidataUrl,
|
|
@@ -1901,17 +1950,17 @@ function GenreDetailExtras({
|
|
|
1901
1950
|
rel: "noopener noreferrer",
|
|
1902
1951
|
className: "inline-flex items-center gap-1.5 text-[var(--color-text-muted)] hover:text-[var(--color-text)]",
|
|
1903
1952
|
children: [
|
|
1904
|
-
/* @__PURE__ */ (0,
|
|
1953
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsx)(import_si2.SiWikidata, { "aria-hidden": "true", className: "h-3.5 w-3.5" }),
|
|
1905
1954
|
"Wikidata"
|
|
1906
1955
|
]
|
|
1907
1956
|
}
|
|
1908
1957
|
)
|
|
1909
1958
|
] }) }),
|
|
1910
|
-
/* @__PURE__ */ (0,
|
|
1959
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsx)(import_ui12.PanelSection, { title: "Summary", children: renderSummary ? renderSummary(overview) : /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(ClampedText, { className: "text-body text-[var(--color-text)]", children: summary ?? "\u2014" }, genreUuid) }),
|
|
1911
1960
|
family,
|
|
1912
1961
|
renderGenreDetailExtras?.(overview),
|
|
1913
|
-
(renderEssentialTracks || essentialSongs) && /* @__PURE__ */ (0,
|
|
1914
|
-
/* @__PURE__ */ (0,
|
|
1962
|
+
(renderEssentialTracks || essentialSongs) && /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(import_ui12.PanelSection, { title: `Essential ${trackNoun.plural}`, children: renderEssentialTracks ? renderEssentialTracks(overview) : essentialSongs && essentialSongs.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("ul", { className: "text-body text-[var(--color-text)]", children: essentialSongs.map((track) => /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("li", { className: "py-1", children: track.title }, track.uuid)) }) : /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("p", { className: "text-body text-[var(--color-text)]", children: "\u2014" }) }),
|
|
1963
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
|
|
1915
1964
|
GenrePlaylistTracks,
|
|
1916
1965
|
{
|
|
1917
1966
|
genreUuid,
|
|
@@ -1929,28 +1978,10 @@ function GenreDetailExtras({
|
|
|
1929
1978
|
}
|
|
1930
1979
|
|
|
1931
1980
|
// src/genre-tree/GenreInfoPanelBody.tsx
|
|
1932
|
-
var
|
|
1933
|
-
var
|
|
1981
|
+
var import_jsx_runtime35 = require("react/jsx-runtime");
|
|
1982
|
+
var import_react14 = require("react");
|
|
1934
1983
|
function GenreNodeActionBand({ genrePlaylist, playback, ...bandProps }) {
|
|
1935
|
-
|
|
1936
|
-
const isCurrentTrackList = playback.playingNodeId === genrePlaylist.uuid;
|
|
1937
|
-
const handlePlayPause = () => {
|
|
1938
|
-
if (isCurrentTrackList) {
|
|
1939
|
-
setIsPlaying(!isPlaying);
|
|
1940
|
-
return;
|
|
1941
|
-
}
|
|
1942
|
-
playback.play(genrePlaylist).catch((error) => {
|
|
1943
|
-
console.error("Failed to load genre playlist tracks:", error);
|
|
1944
|
-
});
|
|
1945
|
-
};
|
|
1946
|
-
return /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
|
|
1947
|
-
GenreActionBand,
|
|
1948
|
-
{
|
|
1949
|
-
...bandProps,
|
|
1950
|
-
onPlayPause: ("genreOnlyTracksCount" in genrePlaylist ? (0, import_genre_tree18.genreMusicCount)(genrePlaylist) : genrePlaylist.tracksCount) > 0 ? handlePlayPause : void 0,
|
|
1951
|
-
isPlaying: isCurrentTrackList && isPlaying
|
|
1952
|
-
}
|
|
1953
|
-
);
|
|
1984
|
+
return /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(GenreActionBand, { ...bandProps, playActions: /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(GenrePlayActions, { genrePlaylist, playback }) });
|
|
1954
1985
|
}
|
|
1955
1986
|
function GenreInfoPanelBody({
|
|
1956
1987
|
toolbar,
|
|
@@ -1958,7 +1989,6 @@ function GenreInfoPanelBody({
|
|
|
1958
1989
|
genreUuid,
|
|
1959
1990
|
genrePlaylist,
|
|
1960
1991
|
catalogue,
|
|
1961
|
-
countsContext,
|
|
1962
1992
|
wikidataId,
|
|
1963
1993
|
scope,
|
|
1964
1994
|
getBackendBaseUrl,
|
|
@@ -1966,33 +1996,12 @@ function GenreInfoPanelBody({
|
|
|
1966
1996
|
band,
|
|
1967
1997
|
extras
|
|
1968
1998
|
}) {
|
|
1969
|
-
const
|
|
1970
|
-
const
|
|
1971
|
-
|
|
1972
|
-
const describeCounts = (counts) => {
|
|
1973
|
-
const scopes = counts.genreAndSubgenresTracksCount;
|
|
1974
|
-
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`;
|
|
1975
|
-
};
|
|
1976
|
-
return /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)(import_jsx_runtime31.Fragment, { children: [
|
|
1999
|
+
const summary = scope === "reference" ? import_genre_tree19.GenreCatalogueCountsSchema.parse(genrePlaylist ?? catalogue) : void 0;
|
|
2000
|
+
const selection = summary ? (0, import_genre_tree19.defaultGenreMusicSelection)(summary) : void 0;
|
|
2001
|
+
return /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)(import_jsx_runtime35.Fragment, { children: [
|
|
1977
2002
|
toolbar,
|
|
1978
|
-
genrePlaylist ? /* @__PURE__ */ (0,
|
|
1979
|
-
|
|
1980
|
-
/* @__PURE__ */ (0, import_jsx_runtime31.jsxs)("p", { children: [
|
|
1981
|
-
"Catalogue ",
|
|
1982
|
-
noun.plural,
|
|
1983
|
-
countsContext ? ` (${countsContext})` : "",
|
|
1984
|
-
": ",
|
|
1985
|
-
describeCounts(catalogue)
|
|
1986
|
-
] }),
|
|
1987
|
-
genrePlaylist && /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)("p", { children: [
|
|
1988
|
-
"Playlist ",
|
|
1989
|
-
noun.plural,
|
|
1990
|
-
countsContext ? ` (${countsContext})` : "",
|
|
1991
|
-
": ",
|
|
1992
|
-
describeCounts(summary)
|
|
1993
|
-
] })
|
|
1994
|
-
] }),
|
|
1995
|
-
/* @__PURE__ */ (0, import_react13.createElement)(
|
|
2003
|
+
genrePlaylist ? /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(GenreNodeActionBand, { ...band, genrePlaylist, playback }) : /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(GenreActionBand, { ...band }),
|
|
2004
|
+
/* @__PURE__ */ (0, import_react14.createElement)(
|
|
1996
2005
|
GenreDetailExtras,
|
|
1997
2006
|
{
|
|
1998
2007
|
...extras,
|
|
@@ -2011,7 +2020,7 @@ function GenreInfoPanelBody({
|
|
|
2011
2020
|
}
|
|
2012
2021
|
|
|
2013
2022
|
// src/genre-tree/GenreDetailPanel.tsx
|
|
2014
|
-
var
|
|
2023
|
+
var import_jsx_runtime36 = require("react/jsx-runtime");
|
|
2015
2024
|
var RELATIVE_ITEM_COUNT = 1;
|
|
2016
2025
|
function toNode(genre, parentId) {
|
|
2017
2026
|
return {
|
|
@@ -2033,80 +2042,88 @@ function useGenreDetailContent({
|
|
|
2033
2042
|
playback: hostPlayback,
|
|
2034
2043
|
trailing,
|
|
2035
2044
|
genrePlaylist: hostPlaylist,
|
|
2036
|
-
expanded
|
|
2045
|
+
expanded,
|
|
2046
|
+
treeRelations
|
|
2037
2047
|
}) {
|
|
2038
|
-
const { data: detail, isPending, isError } = (0,
|
|
2048
|
+
const { data: detail, isPending, isError } = (0, import_genre_tree20.useFetchGenreDetail)(genreUuid, scope, getBackendBaseUrl);
|
|
2039
2049
|
const defaultPlayback = useGenrePlaylistPlayback({ scope, genrePlaylists: [], artist: extras?.artist });
|
|
2040
2050
|
const playback = hostPlayback ?? defaultPlayback;
|
|
2041
|
-
const view = (0,
|
|
2051
|
+
const view = (0, import_react15.useMemo)(() => {
|
|
2042
2052
|
if (!detail) return null;
|
|
2043
2053
|
const rootColor = (0, import_genre_tree_view4.getGenreTreeColor)(detail.root.wikidataId);
|
|
2054
|
+
const treeStyles = /* @__PURE__ */ new Map();
|
|
2055
|
+
if (treeRelations) {
|
|
2056
|
+
const drawn = [treeRelations, treeRelations.parentNode, ...treeRelations.childNodes, ...treeRelations.ancestorNodes];
|
|
2057
|
+
for (const entry of drawn) {
|
|
2058
|
+
if (entry) treeStyles.set(entry.node.id, { fill: entry.fill, textColor: entry.textColor });
|
|
2059
|
+
}
|
|
2060
|
+
}
|
|
2044
2061
|
const relative = (genre, parentId) => ({
|
|
2045
2062
|
node: toNode(genre, parentId),
|
|
2046
|
-
fill: (0, import_genre_tree_view4.tintSurface)(rootColor),
|
|
2047
|
-
textColor: import_genre_tree_view4.TEXT_COLOR
|
|
2063
|
+
...treeStyles.get(genre.uuid) ?? { fill: (0, import_genre_tree_view4.tintSurface)(rootColor), textColor: import_genre_tree_view4.TEXT_COLOR }
|
|
2048
2064
|
});
|
|
2049
2065
|
const ancestors2 = [...detail.ascendants].sort((a, b) => b.degree - a.degree);
|
|
2066
|
+
const own = treeStyles.get(detail.uuid) ?? { fill: rootColor, textColor: (0, import_genre_tree_view4.getTextColorOnFill)(rootColor) };
|
|
2050
2067
|
return {
|
|
2051
2068
|
node: {
|
|
2052
2069
|
id: detail.uuid,
|
|
2053
2070
|
parentId: detail.parent?.uuid ?? null,
|
|
2054
2071
|
name: detail.name,
|
|
2055
|
-
itemCount: scope === "reference" ? (0,
|
|
2072
|
+
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,
|
|
2056
2073
|
wikidataId: detail.wikidataId
|
|
2057
2074
|
},
|
|
2058
|
-
fill:
|
|
2075
|
+
fill: own.fill,
|
|
2076
|
+
textColor: own.textColor,
|
|
2059
2077
|
parentNode: detail.parent ? relative(detail.parent, null) : null,
|
|
2060
2078
|
childNodes: detail.children.map((child) => relative(child, detail.uuid)),
|
|
2061
2079
|
ancestorNodes: ancestors2.map(
|
|
2062
2080
|
({ ascendant }, index) => relative(ascendant, index === 0 ? null : ancestors2[index - 1].ascendant.uuid)
|
|
2063
2081
|
)
|
|
2064
2082
|
};
|
|
2065
|
-
}, [detail, scope]);
|
|
2083
|
+
}, [detail, scope, treeRelations]);
|
|
2066
2084
|
if (isError) return {
|
|
2067
2085
|
name: null,
|
|
2068
2086
|
title: "Genre unavailable",
|
|
2069
|
-
content: /* @__PURE__ */ (0,
|
|
2087
|
+
content: /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("p", { role: "alert", className: "text-body text-[var(--color-text)]", children: "This genre could not be loaded." })
|
|
2070
2088
|
};
|
|
2071
2089
|
if (isPending || !detail || !view) return {
|
|
2072
2090
|
name: null,
|
|
2073
2091
|
title: "Loading genre\u2026",
|
|
2074
|
-
content: /* @__PURE__ */ (0,
|
|
2075
|
-
/* @__PURE__ */ (0,
|
|
2076
|
-
/* @__PURE__ */ (0,
|
|
2077
|
-
/* @__PURE__ */ (0,
|
|
2092
|
+
content: /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("div", { className: "flex flex-col gap-3", "aria-busy": "true", "data-testid": "genre-detail-panel-skeleton", children: [
|
|
2093
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)(import_ui13.Skeleton, { className: "h-6 w-2/3" }),
|
|
2094
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)(import_ui13.Skeleton, { className: "h-4 w-full" }),
|
|
2095
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)(import_ui13.Skeleton, { className: "h-4 w-3/4" })
|
|
2078
2096
|
] })
|
|
2079
2097
|
};
|
|
2080
|
-
const selectGenre = (nodeId) => onSelectGenre(
|
|
2081
|
-
const family = /* @__PURE__ */ (0,
|
|
2098
|
+
const selectGenre = (nodeId) => onSelectGenre(import_genre_tree20.GenreUuidSchema.parse(nodeId));
|
|
2099
|
+
const family = /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
|
|
2082
2100
|
import_genre_tree_view4.GenreNodeFamily,
|
|
2083
2101
|
{
|
|
2084
2102
|
node: view.node,
|
|
2085
2103
|
fill: view.fill,
|
|
2086
|
-
textColor:
|
|
2104
|
+
textColor: view.textColor,
|
|
2087
2105
|
parentNode: view.parentNode,
|
|
2088
2106
|
childNodes: view.childNodes,
|
|
2089
2107
|
onSelectNode: selectGenre
|
|
2090
2108
|
}
|
|
2091
2109
|
);
|
|
2092
|
-
const ancestors = /* @__PURE__ */ (0,
|
|
2110
|
+
const ancestors = /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(import_genre_tree_view4.GenreNodeAncestors, { ancestorNodes: view.ancestorNodes, onSelectNode: selectGenre });
|
|
2093
2111
|
return {
|
|
2094
2112
|
name: detail.name,
|
|
2095
2113
|
title: detail.name,
|
|
2096
|
-
headerAccent: { background: view.fill, color:
|
|
2114
|
+
headerAccent: { background: view.fill, color: view.textColor },
|
|
2097
2115
|
aside: expanded ? ancestors : void 0,
|
|
2098
|
-
content: /* @__PURE__ */ (0,
|
|
2099
|
-
/* @__PURE__ */ (0,
|
|
2116
|
+
content: /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)(import_jsx_runtime36.Fragment, { children: [
|
|
2117
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
|
|
2100
2118
|
GenreInfoPanelBody,
|
|
2101
2119
|
{
|
|
2102
|
-
family: /* @__PURE__ */ (0,
|
|
2120
|
+
family: /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)(import_jsx_runtime36.Fragment, { children: [
|
|
2103
2121
|
family,
|
|
2104
2122
|
!expanded && ancestors
|
|
2105
2123
|
] }),
|
|
2106
2124
|
genreUuid: detail.uuid,
|
|
2107
|
-
genrePlaylist: hostPlaylist ?? (detail.criteriaPlaylist === null ? null : scope === "reference" ? { ...
|
|
2125
|
+
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 }),
|
|
2108
2126
|
catalogue: detail.catalogue,
|
|
2109
|
-
countsContext: !hostPlaylist && extras?.artist ? "all artists" : void 0,
|
|
2110
2127
|
wikidataId: detail.wikidataId,
|
|
2111
2128
|
scope,
|
|
2112
2129
|
getBackendBaseUrl,
|
|
@@ -2144,8 +2161,8 @@ function GenreDetailPanel({
|
|
|
2144
2161
|
expanded,
|
|
2145
2162
|
band: { onZoomIn, shareUrl, shareTarget: shareUrl ? shareTarget : void 0 }
|
|
2146
2163
|
});
|
|
2147
|
-
return /* @__PURE__ */ (0,
|
|
2148
|
-
|
|
2164
|
+
return /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
|
|
2165
|
+
import_ui13.DetailPanel,
|
|
2149
2166
|
{
|
|
2150
2167
|
side: "left",
|
|
2151
2168
|
title: panel.title,
|
|
@@ -2157,16 +2174,16 @@ function GenreDetailPanel({
|
|
|
2157
2174
|
edgeTab,
|
|
2158
2175
|
aside: panel.aside,
|
|
2159
2176
|
titleInSearch,
|
|
2160
|
-
headerActions: onExpandedChange ? /* @__PURE__ */ (0,
|
|
2177
|
+
headerActions: onExpandedChange ? /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(import_ui13.IconButton, { "aria-label": expanded ? "Shrink panel" : "Extend panel", onClick: () => onExpandedChange(!expanded), children: expanded ? /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(import_lucide_react13.Minimize2, { "aria-hidden": "true", className: "h-4 w-4" }) : /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(import_lucide_react13.Maximize2, { "aria-hidden": "true", className: "h-4 w-4" }) }) : void 0,
|
|
2161
2178
|
children: panel.content
|
|
2162
2179
|
}
|
|
2163
2180
|
);
|
|
2164
2181
|
}
|
|
2165
2182
|
|
|
2166
2183
|
// src/genre-tree/ChangeParentPopup.tsx
|
|
2167
|
-
var
|
|
2168
|
-
var
|
|
2169
|
-
var
|
|
2184
|
+
var import_react16 = require("react");
|
|
2185
|
+
var import_genre_tree21 = require("@behindthemusictree/app-kit/genre-tree");
|
|
2186
|
+
var import_jsx_runtime37 = require("react/jsx-runtime");
|
|
2170
2187
|
function ChangeParentPopup({
|
|
2171
2188
|
genrePlaylist,
|
|
2172
2189
|
genrePlaylists,
|
|
@@ -2175,9 +2192,9 @@ function ChangeParentPopup({
|
|
|
2175
2192
|
onClose,
|
|
2176
2193
|
onParentChanged
|
|
2177
2194
|
}) {
|
|
2178
|
-
const { mutate, isPending, formErrors } = (0,
|
|
2179
|
-
const candidates = (0,
|
|
2180
|
-
() => (0,
|
|
2195
|
+
const { mutate, isPending, formErrors } = (0, import_genre_tree21.useUpdateGenre)(scope, getBackendBaseUrl);
|
|
2196
|
+
const candidates = (0, import_react16.useMemo)(
|
|
2197
|
+
() => (0, import_genre_tree21.getReparentCandidates)(genrePlaylists, genrePlaylist.uuid),
|
|
2181
2198
|
[genrePlaylists, genrePlaylist.uuid]
|
|
2182
2199
|
);
|
|
2183
2200
|
const handleSelect = (newParent) => {
|
|
@@ -2194,19 +2211,19 @@ function ChangeParentPopup({
|
|
|
2194
2211
|
}
|
|
2195
2212
|
);
|
|
2196
2213
|
};
|
|
2197
|
-
(0,
|
|
2214
|
+
(0, import_react16.useEffect)(() => {
|
|
2198
2215
|
const handleKeyDown = (event) => {
|
|
2199
2216
|
if (event.key === "Escape") onClose();
|
|
2200
2217
|
};
|
|
2201
2218
|
window.addEventListener("keydown", handleKeyDown);
|
|
2202
2219
|
return () => window.removeEventListener("keydown", handleKeyDown);
|
|
2203
2220
|
}, [onClose]);
|
|
2204
|
-
return /* @__PURE__ */ (0,
|
|
2205
|
-
/* @__PURE__ */ (0,
|
|
2221
|
+
return /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)(BasePopup_default, { title: `Change parent of ${genrePlaylist.name}`, onClose, showCancelButton: true, fitContent: true, children: [
|
|
2222
|
+
/* @__PURE__ */ (0, import_jsx_runtime37.jsxs)("p", { className: "mb-3 text-body text-[var(--color-text-muted)]", children: [
|
|
2206
2223
|
"Current parent: ",
|
|
2207
2224
|
genrePlaylist.parent?.name ?? "none"
|
|
2208
2225
|
] }),
|
|
2209
|
-
/* @__PURE__ */ (0,
|
|
2226
|
+
/* @__PURE__ */ (0, import_jsx_runtime37.jsx)("div", { "aria-busy": isPending, className: isPending ? "pointer-events-none opacity-60" : void 0, children: /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
|
|
2210
2227
|
GenreSearch,
|
|
2211
2228
|
{
|
|
2212
2229
|
genrePlaylists: candidates,
|
|
@@ -2214,24 +2231,61 @@ function ChangeParentPopup({
|
|
|
2214
2231
|
placeholder: "Search a new parent\u2026"
|
|
2215
2232
|
}
|
|
2216
2233
|
) }),
|
|
2217
|
-
formErrors.length > 0 && /* @__PURE__ */ (0,
|
|
2234
|
+
formErrors.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("p", { role: "alert", className: "mt-3 text-body text-[var(--color-red-500)]", children: formErrors.map(({ message }) => message).join(" ") })
|
|
2218
2235
|
] });
|
|
2219
2236
|
}
|
|
2220
2237
|
|
|
2221
2238
|
// src/genre-tree/artist/useArtistPanel.tsx
|
|
2222
|
-
var
|
|
2223
|
-
var
|
|
2239
|
+
var import_ui20 = require("@behindthemusictree/ui");
|
|
2240
|
+
var import_genre_tree27 = require("@behindthemusictree/app-kit/genre-tree");
|
|
2241
|
+
|
|
2242
|
+
// src/genre-tree/artist/ArtistActionBand.tsx
|
|
2243
|
+
var import_lucide_react14 = require("lucide-react");
|
|
2244
|
+
var import_ui14 = require("@behindthemusictree/ui");
|
|
2245
|
+
var import_genre_tree22 = require("@behindthemusictree/app-kit/genre-tree");
|
|
2246
|
+
var import_player7 = require("@behindthemusictree/app-kit/player");
|
|
2247
|
+
var import_jsx_runtime38 = require("react/jsx-runtime");
|
|
2248
|
+
function ArtistActionBand({ artist, share }) {
|
|
2249
|
+
const { trackList, playNewTrackListFromArtist } = (0, import_genre_tree22.useTrackList)();
|
|
2250
|
+
const { isPlaying, setIsPlaying } = (0, import_player7.usePlayer)();
|
|
2251
|
+
const origin = trackList?.origin;
|
|
2252
|
+
const isCurrent = origin?.type === import_genre_tree22.TrackListOriginType.ARTIST && origin.uuid === artist.uuid;
|
|
2253
|
+
const playing = isCurrent && isPlaying;
|
|
2254
|
+
const handleClick = () => {
|
|
2255
|
+
if (isCurrent) {
|
|
2256
|
+
setIsPlaying(!isPlaying);
|
|
2257
|
+
return;
|
|
2258
|
+
}
|
|
2259
|
+
playNewTrackListFromArtist({ uuid: artist.uuid, name: artist.name }, "reference", { ordering: "title" }).catch((error) => {
|
|
2260
|
+
console.error("Failed to load artist tracks:", error);
|
|
2261
|
+
});
|
|
2262
|
+
};
|
|
2263
|
+
return /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(import_ui14.PanelBleed, { children: /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)(import_ui14.ActionBand, { children: [
|
|
2264
|
+
/* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
|
|
2265
|
+
import_ui14.ActionButton,
|
|
2266
|
+
{
|
|
2267
|
+
icon: playing ? /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(import_lucide_react14.Pause, { "aria-hidden": "true", className: "w-5 h-5" }) : /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(import_lucide_react14.Play, { "aria-hidden": "true", className: "w-5 h-5" }),
|
|
2268
|
+
label: playing ? "Pause" : "Play",
|
|
2269
|
+
caption: String(artist.playableTracksCount),
|
|
2270
|
+
disabled: artist.playableTracksCount === 0,
|
|
2271
|
+
title: artist.playableTracksCount === 0 ? "No playable songs" : void 0,
|
|
2272
|
+
onClick: handleClick
|
|
2273
|
+
}
|
|
2274
|
+
),
|
|
2275
|
+
share
|
|
2276
|
+
] }) });
|
|
2277
|
+
}
|
|
2224
2278
|
|
|
2225
2279
|
// src/genre-tree/artist/ArtistHeader.tsx
|
|
2226
|
-
var
|
|
2280
|
+
var import_ui16 = require("@behindthemusictree/ui");
|
|
2227
2281
|
|
|
2228
2282
|
// src/genre-tree/artist/ArtistLinks.tsx
|
|
2229
|
-
var
|
|
2283
|
+
var import_lucide_react15 = require("lucide-react");
|
|
2230
2284
|
var import_si3 = require("react-icons/si");
|
|
2231
|
-
var
|
|
2232
|
-
var
|
|
2285
|
+
var import_ui15 = require("@behindthemusictree/ui");
|
|
2286
|
+
var import_jsx_runtime39 = require("react/jsx-runtime");
|
|
2233
2287
|
var LINK_KINDS = {
|
|
2234
|
-
official: { label: "Official website", Icon:
|
|
2288
|
+
official: { label: "Official website", Icon: import_lucide_react15.Globe },
|
|
2235
2289
|
wikipedia: { label: "Wikipedia", Icon: import_si3.SiWikipedia },
|
|
2236
2290
|
wikidata: { label: "Wikidata", Icon: import_si3.SiWikidata },
|
|
2237
2291
|
spotify: { label: "Spotify", Icon: import_si3.SiSpotify },
|
|
@@ -2239,7 +2293,7 @@ var LINK_KINDS = {
|
|
|
2239
2293
|
bandcamp: { label: "Bandcamp", Icon: import_si3.SiBandcamp },
|
|
2240
2294
|
soundcloud: { label: "SoundCloud", Icon: import_si3.SiSoundcloud },
|
|
2241
2295
|
discogs: { label: "Discogs", Icon: import_si3.SiDiscogs },
|
|
2242
|
-
social: { label: "Social", Icon:
|
|
2296
|
+
social: { label: "Social", Icon: import_lucide_react15.Share2 }
|
|
2243
2297
|
};
|
|
2244
2298
|
function socialLabel(url) {
|
|
2245
2299
|
try {
|
|
@@ -2266,7 +2320,7 @@ function artistLinks(artist) {
|
|
|
2266
2320
|
return links;
|
|
2267
2321
|
}
|
|
2268
2322
|
function ArtistLinks({ links }) {
|
|
2269
|
-
return /* @__PURE__ */ (0,
|
|
2323
|
+
return /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("ul", { className: "flex flex-wrap gap-1.5", children: links.map(({ key, url, Icon, label }) => /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(import_ui15.Chip, { href: url, icon: /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(Icon, { className: "h-3.5 w-3.5 shrink-0", "aria-hidden": "true" }), children: label }) }, key)) });
|
|
2270
2324
|
}
|
|
2271
2325
|
|
|
2272
2326
|
// src/genre-tree/artist/formatYears.ts
|
|
@@ -2277,7 +2331,7 @@ function formatYears(beginYear, endYear, ended) {
|
|
|
2277
2331
|
}
|
|
2278
2332
|
|
|
2279
2333
|
// src/genre-tree/artist/ArtistHeader.tsx
|
|
2280
|
-
var
|
|
2334
|
+
var import_jsx_runtime40 = require("react/jsx-runtime");
|
|
2281
2335
|
var countryNames = new Intl.DisplayNames(["en"], { type: "region" });
|
|
2282
2336
|
function ArtistHeader({ artist }) {
|
|
2283
2337
|
const fields = [];
|
|
@@ -2287,35 +2341,35 @@ function ArtistHeader({ artist }) {
|
|
|
2287
2341
|
const years = formatYears(artist.beginYear, artist.endYear, artist.ended);
|
|
2288
2342
|
if (years) fields.push({ label: "Active", value: years });
|
|
2289
2343
|
const links = artistLinks(artist);
|
|
2290
|
-
if (links.length > 0) fields.push({ label: "Links", value: /* @__PURE__ */ (0,
|
|
2344
|
+
if (links.length > 0) fields.push({ label: "Links", value: /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(ArtistLinks, { links }) });
|
|
2291
2345
|
if (fields.length === 0) return null;
|
|
2292
|
-
return /* @__PURE__ */ (0,
|
|
2346
|
+
return /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(import_ui16.FieldList, { items: fields });
|
|
2293
2347
|
}
|
|
2294
2348
|
|
|
2295
2349
|
// src/genre-tree/artist/ArtistPhoto.tsx
|
|
2296
|
-
var
|
|
2350
|
+
var import_jsx_runtime41 = require("react/jsx-runtime");
|
|
2297
2351
|
function ExternalLink({ href, children }) {
|
|
2298
|
-
return /* @__PURE__ */ (0,
|
|
2352
|
+
return /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("a", { href, target: "_blank", rel: "noopener noreferrer", className: "underline-offset-2 hover:underline", children });
|
|
2299
2353
|
}
|
|
2300
2354
|
function ArtistPhoto({ image, name }) {
|
|
2301
|
-
return /* @__PURE__ */ (0,
|
|
2302
|
-
/* @__PURE__ */ (0,
|
|
2303
|
-
/* @__PURE__ */ (0,
|
|
2355
|
+
return /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("figure", { className: "flex flex-col gap-1.5", children: [
|
|
2356
|
+
/* @__PURE__ */ (0, import_jsx_runtime41.jsx)("img", { src: image.url, alt: name, className: "h-64 w-full object-contain bg-[var(--color-surface-muted)] rounded" }),
|
|
2357
|
+
/* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("figcaption", { className: "text-caption text-[var(--color-text-muted)]", children: [
|
|
2304
2358
|
"Photo: ",
|
|
2305
|
-
/* @__PURE__ */ (0,
|
|
2359
|
+
/* @__PURE__ */ (0, import_jsx_runtime41.jsx)(ExternalLink, { href: image.pageUrl, children: image.author ?? "Wikimedia Commons" }),
|
|
2306
2360
|
",",
|
|
2307
2361
|
" ",
|
|
2308
|
-
image.licenseUrl ? /* @__PURE__ */ (0,
|
|
2362
|
+
image.licenseUrl ? /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(ExternalLink, { href: image.licenseUrl, children: image.license }) : image.license
|
|
2309
2363
|
] })
|
|
2310
2364
|
] });
|
|
2311
2365
|
}
|
|
2312
2366
|
|
|
2313
2367
|
// src/genre-tree/artist/ArtistMembers.tsx
|
|
2314
|
-
var
|
|
2315
|
-
var
|
|
2368
|
+
var import_ui17 = require("@behindthemusictree/ui");
|
|
2369
|
+
var import_jsx_runtime42 = require("react/jsx-runtime");
|
|
2316
2370
|
function MembershipList({ title, memberships, renderArtistLink }) {
|
|
2317
2371
|
if (memberships.length === 0) return null;
|
|
2318
|
-
return /* @__PURE__ */ (0,
|
|
2372
|
+
return /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(import_ui17.PanelGroup, { title, children: /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("ul", { children: memberships.map((membership, index) => {
|
|
2319
2373
|
const details = [
|
|
2320
2374
|
formatYears(membership.beginYear, membership.endYear, membership.ended),
|
|
2321
2375
|
...membership.roles
|
|
@@ -2323,9 +2377,9 @@ function MembershipList({ title, memberships, renderArtistLink }) {
|
|
|
2323
2377
|
const detailsText = details.filter(Boolean).join(" \xB7 ");
|
|
2324
2378
|
return (
|
|
2325
2379
|
// A member can have several periods in the same group.
|
|
2326
|
-
/* @__PURE__ */ (0,
|
|
2327
|
-
/* @__PURE__ */ (0,
|
|
2328
|
-
detailsText && /* @__PURE__ */ (0,
|
|
2380
|
+
/* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("li", { className: "truncate py-0.5", title: detailsText || void 0, children: [
|
|
2381
|
+
/* @__PURE__ */ (0, import_jsx_runtime42.jsx)("span", { className: "font-medium text-[var(--color-text)]", children: renderArtistLink(membership.artist) }),
|
|
2382
|
+
detailsText && /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("span", { className: "text-[var(--color-text-muted)]", children: [
|
|
2329
2383
|
" \u2014 ",
|
|
2330
2384
|
detailsText
|
|
2331
2385
|
] })
|
|
@@ -2336,9 +2390,9 @@ function MembershipList({ title, memberships, renderArtistLink }) {
|
|
|
2336
2390
|
function ArtistMembers({ title, memberships, renderArtistLink }) {
|
|
2337
2391
|
if (memberships.length === 0) return null;
|
|
2338
2392
|
const isCurrent = (membership) => !membership.ended && membership.endYear === null;
|
|
2339
|
-
return /* @__PURE__ */ (0,
|
|
2340
|
-
/* @__PURE__ */ (0,
|
|
2341
|
-
/* @__PURE__ */ (0,
|
|
2393
|
+
return /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)(import_ui17.PanelSection, { title, children: [
|
|
2394
|
+
/* @__PURE__ */ (0, import_jsx_runtime42.jsx)(MembershipList, { title: "Current", memberships: memberships.filter(isCurrent), renderArtistLink }),
|
|
2395
|
+
/* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
|
|
2342
2396
|
MembershipList,
|
|
2343
2397
|
{
|
|
2344
2398
|
title: "Past",
|
|
@@ -2350,8 +2404,8 @@ function ArtistMembers({ title, memberships, renderArtistLink }) {
|
|
|
2350
2404
|
}
|
|
2351
2405
|
|
|
2352
2406
|
// src/genre-tree/artist/ArtistDiscography.tsx
|
|
2353
|
-
var
|
|
2354
|
-
var
|
|
2407
|
+
var import_ui18 = require("@behindthemusictree/ui");
|
|
2408
|
+
var import_jsx_runtime43 = require("react/jsx-runtime");
|
|
2355
2409
|
var GROUPS = ["Albums", "EPs", "Singles", "Live", "Compilations", "Other"];
|
|
2356
2410
|
var PRIMARY_GROUPS = { album: "Albums", ep: "EPs", single: "Singles" };
|
|
2357
2411
|
function discographyGroup({ primaryType, secondaryTypes }) {
|
|
@@ -2371,55 +2425,55 @@ function byYear(a, b) {
|
|
|
2371
2425
|
function ArtistDiscography({ albums }) {
|
|
2372
2426
|
if (albums.length === 0) return null;
|
|
2373
2427
|
const sorted = [...albums].sort(byYear);
|
|
2374
|
-
return /* @__PURE__ */ (0,
|
|
2428
|
+
return /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(import_ui18.PanelSection, { title: "Discography", children: GROUPS.map((group) => {
|
|
2375
2429
|
const groupAlbums = sorted.filter((album) => discographyGroup(album) === group);
|
|
2376
2430
|
if (groupAlbums.length === 0) return null;
|
|
2377
|
-
return /* @__PURE__ */ (0,
|
|
2378
|
-
/* @__PURE__ */ (0,
|
|
2379
|
-
/* @__PURE__ */ (0,
|
|
2431
|
+
return /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(import_ui18.PanelGroup, { title: group, children: /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("ul", { children: groupAlbums.map((album) => /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("li", { className: "grid grid-cols-[2.5rem_minmax(0,1fr)] gap-2 py-0.5", children: [
|
|
2432
|
+
/* @__PURE__ */ (0, import_jsx_runtime43.jsx)("span", { className: "tabular-nums text-[var(--color-text-muted)]", children: album.year ?? "\u2014" }),
|
|
2433
|
+
/* @__PURE__ */ (0, import_jsx_runtime43.jsx)("span", { className: "truncate text-[var(--color-text)]", title: album.name, children: album.name })
|
|
2380
2434
|
] }, album.uuid)) }) }, group);
|
|
2381
2435
|
}) });
|
|
2382
2436
|
}
|
|
2383
2437
|
|
|
2384
2438
|
// src/genre-tree/artist/ArtistSongs.tsx
|
|
2385
|
-
var
|
|
2439
|
+
var import_react17 = require("react");
|
|
2386
2440
|
var import_react_query2 = require("@tanstack/react-query");
|
|
2387
|
-
var
|
|
2388
|
-
var
|
|
2389
|
-
var
|
|
2390
|
-
var
|
|
2391
|
-
var
|
|
2441
|
+
var import_lucide_react16 = require("lucide-react");
|
|
2442
|
+
var import_ui19 = require("@behindthemusictree/ui");
|
|
2443
|
+
var import_player11 = require("@behindthemusictree/app-kit/player");
|
|
2444
|
+
var import_genre_tree26 = require("@behindthemusictree/app-kit/genre-tree");
|
|
2445
|
+
var import_transport8 = require("@behindthemusictree/app-kit/transport");
|
|
2392
2446
|
|
|
2393
2447
|
// src/genre-tree/track-list-sidebar/TrackItem.tsx
|
|
2394
|
-
var
|
|
2395
|
-
var
|
|
2448
|
+
var import_player10 = require("@behindthemusictree/app-kit/player");
|
|
2449
|
+
var import_genre_tree23 = require("@behindthemusictree/app-kit/genre-tree");
|
|
2396
2450
|
|
|
2397
2451
|
// src/genre-tree/TrackPositionPlayPause.tsx
|
|
2398
2452
|
var import_fa5 = require("react-icons/fa");
|
|
2399
|
-
var import_player7 = require("@behindthemusictree/app-kit/player");
|
|
2400
2453
|
var import_player8 = require("@behindthemusictree/app-kit/player");
|
|
2401
|
-
var
|
|
2454
|
+
var import_player9 = require("@behindthemusictree/app-kit/player");
|
|
2455
|
+
var import_jsx_runtime44 = require("react/jsx-runtime");
|
|
2402
2456
|
function TrackPositionPlayPause({
|
|
2403
2457
|
position,
|
|
2404
2458
|
uuid,
|
|
2405
2459
|
handlePlayPauseClick,
|
|
2406
2460
|
isSelected = false
|
|
2407
2461
|
}) {
|
|
2408
|
-
const { playerTrackObject, playbackConfirmedTrackId, playState, isLoading: isPlayerLoading } = (0,
|
|
2462
|
+
const { playerTrackObject, playbackConfirmedTrackId, playState, isLoading: isPlayerLoading } = (0, import_player8.usePlayer)();
|
|
2409
2463
|
const isThisTrack = playerTrackObject?.track.id === uuid;
|
|
2410
2464
|
const isConfirmedPlayable = playbackConfirmedTrackId === uuid;
|
|
2411
|
-
const isAwaitingPlayback = (isSelected || isThisTrack) && !isConfirmedPlayable && !(isThisTrack && playerTrackObject?.loadError) && (!isThisTrack || isPlayerLoading || playState ===
|
|
2412
|
-
const isPlaying = isThisTrack && isConfirmedPlayable && playState ===
|
|
2413
|
-
const isPaused = isThisTrack && isConfirmedPlayable && playState ===
|
|
2465
|
+
const isAwaitingPlayback = (isSelected || isThisTrack) && !isConfirmedPlayable && !(isThisTrack && playerTrackObject?.loadError) && (!isThisTrack || isPlayerLoading || playState === import_player9.PlayStates.LOADING || playState === import_player9.PlayStates.PLAYING);
|
|
2466
|
+
const isPlaying = isThisTrack && isConfirmedPlayable && playState === import_player9.PlayStates.PLAYING;
|
|
2467
|
+
const isPaused = isThisTrack && isConfirmedPlayable && playState === import_player9.PlayStates.PAUSED;
|
|
2414
2468
|
const isCurrentTrackActive = isPlaying || isPaused;
|
|
2415
|
-
return /* @__PURE__ */ (0,
|
|
2469
|
+
return /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)(
|
|
2416
2470
|
"div",
|
|
2417
2471
|
{
|
|
2418
2472
|
className: "track-position-play-pause relative flex items-center justify-center gap-2 text-lg w-16 cursor-pointer",
|
|
2419
2473
|
style: { minWidth: "4rem", maxWidth: "4rem" },
|
|
2420
2474
|
onClick: handlePlayPauseClick,
|
|
2421
2475
|
children: [
|
|
2422
|
-
/* @__PURE__ */ (0,
|
|
2476
|
+
/* @__PURE__ */ (0, import_jsx_runtime44.jsx)("div", { className: "track-position-play-pause__status group-hover:hidden flex items-center justify-center", children: isAwaitingPlayback ? /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("span", { className: "track-position-play-pause__spinner", role: "status", "aria-label": "Loading track" }) : isCurrentTrackActive ? /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)(
|
|
2423
2477
|
"span",
|
|
2424
2478
|
{
|
|
2425
2479
|
className: "track-position-play-pause__bars",
|
|
@@ -2427,18 +2481,18 @@ function TrackPositionPlayPause({
|
|
|
2427
2481
|
role: "img",
|
|
2428
2482
|
"aria-label": isPlaying ? "Playing" : "Paused",
|
|
2429
2483
|
children: [
|
|
2430
|
-
/* @__PURE__ */ (0,
|
|
2431
|
-
/* @__PURE__ */ (0,
|
|
2432
|
-
/* @__PURE__ */ (0,
|
|
2484
|
+
/* @__PURE__ */ (0, import_jsx_runtime44.jsx)("span", { className: "track-position-play-pause__bar" }),
|
|
2485
|
+
/* @__PURE__ */ (0, import_jsx_runtime44.jsx)("span", { className: "track-position-play-pause__bar" }),
|
|
2486
|
+
/* @__PURE__ */ (0, import_jsx_runtime44.jsx)("span", { className: "track-position-play-pause__bar" })
|
|
2433
2487
|
]
|
|
2434
2488
|
}
|
|
2435
2489
|
) : position }),
|
|
2436
|
-
/* @__PURE__ */ (0,
|
|
2490
|
+
/* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
|
|
2437
2491
|
"div",
|
|
2438
2492
|
{
|
|
2439
2493
|
className: `hidden group-hover:flex items-center justify-center ${isCurrentTrackActive ? "" : "absolute inset-0"}`,
|
|
2440
2494
|
"aria-hidden": "true",
|
|
2441
|
-
children: isAwaitingPlayback ? /* @__PURE__ */ (0,
|
|
2495
|
+
children: isAwaitingPlayback ? /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("span", { className: "track-position-play-pause__spinner" }) : isPlaying ? /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(import_fa5.FaPause, {}) : /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(import_fa5.FaPlay, {})
|
|
2442
2496
|
}
|
|
2443
2497
|
)
|
|
2444
2498
|
]
|
|
@@ -2447,9 +2501,9 @@ function TrackPositionPlayPause({
|
|
|
2447
2501
|
}
|
|
2448
2502
|
|
|
2449
2503
|
// src/genre-tree/track-list-sidebar/TrackItem.tsx
|
|
2450
|
-
var
|
|
2451
|
-
var
|
|
2452
|
-
var
|
|
2504
|
+
var import_genre_tree24 = require("@behindthemusictree/app-kit/genre-tree");
|
|
2505
|
+
var import_genre_tree25 = require("@behindthemusictree/app-kit/genre-tree");
|
|
2506
|
+
var import_jsx_runtime45 = require("react/jsx-runtime");
|
|
2453
2507
|
function TrackItem({
|
|
2454
2508
|
track,
|
|
2455
2509
|
position,
|
|
@@ -2458,12 +2512,12 @@ function TrackItem({
|
|
|
2458
2512
|
renderArtistLink,
|
|
2459
2513
|
renderSongLink
|
|
2460
2514
|
}) {
|
|
2461
|
-
const { handlePlayPauseAction, playerTrackObject, loadTrackForPlayer } = (0,
|
|
2462
|
-
const { trackList, selectedTrack, toTrackAtPosition, runtimeUnplayableTrackIds } = (0,
|
|
2515
|
+
const { handlePlayPauseAction, playerTrackObject, loadTrackForPlayer } = (0, import_player10.usePlayer)();
|
|
2516
|
+
const { trackList, selectedTrack, toTrackAtPosition, runtimeUnplayableTrackIds } = (0, import_genre_tree23.useTrackList)();
|
|
2463
2517
|
const scope = trackList?.origin?.scope ?? null;
|
|
2464
2518
|
const isCurrentTrack = playerTrackObject?.track.id === track.uuid;
|
|
2465
2519
|
const hasPlaybackError = isCurrentTrack && !!playerTrackObject?.loadError;
|
|
2466
|
-
const isUnplayable = hasPlaybackError || runtimeUnplayableTrackIds?.has(track.uuid) === true || (0,
|
|
2520
|
+
const isUnplayable = hasPlaybackError || runtimeUnplayableTrackIds?.has(track.uuid) === true || (0, import_genre_tree24.isSong)(track) && (0, import_genre_tree24.songUnplayableReason)(track) !== null;
|
|
2467
2521
|
const handlePlayPauseClick = (event) => {
|
|
2468
2522
|
event.stopPropagation();
|
|
2469
2523
|
if (isCurrentTrack) {
|
|
@@ -2473,12 +2527,12 @@ function TrackItem({
|
|
|
2473
2527
|
loadTrackForPlayer(track.uuid);
|
|
2474
2528
|
}
|
|
2475
2529
|
};
|
|
2476
|
-
return /* @__PURE__ */ (0,
|
|
2530
|
+
return /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)(
|
|
2477
2531
|
"div",
|
|
2478
2532
|
{
|
|
2479
2533
|
className: `track-item flex h-14 text-[var(--color-text)] ${isUnplayable ? "opacity-50" : "hover:bg-[var(--color-surface-muted)] group"}`,
|
|
2480
2534
|
children: [
|
|
2481
|
-
isUnplayable ? /* @__PURE__ */ (0,
|
|
2535
|
+
isUnplayable ? /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
|
|
2482
2536
|
"div",
|
|
2483
2537
|
{
|
|
2484
2538
|
className: "flex items-center justify-center text-lg w-16",
|
|
@@ -2486,7 +2540,7 @@ function TrackItem({
|
|
|
2486
2540
|
"aria-disabled": "true",
|
|
2487
2541
|
children: position
|
|
2488
2542
|
}
|
|
2489
|
-
) : /* @__PURE__ */ (0,
|
|
2543
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
|
|
2490
2544
|
TrackPositionPlayPause,
|
|
2491
2545
|
{
|
|
2492
2546
|
position,
|
|
@@ -2495,12 +2549,12 @@ function TrackItem({
|
|
|
2495
2549
|
isSelected: selectedTrack?.uuid === track.uuid
|
|
2496
2550
|
}
|
|
2497
2551
|
),
|
|
2498
|
-
/* @__PURE__ */ (0,
|
|
2499
|
-
/* @__PURE__ */ (0,
|
|
2500
|
-
track.artists && track.artists.length > 0 ? /* @__PURE__ */ (0,
|
|
2552
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("div", { className: "title-artist-container flex flex-col items-start justify-center min-w-0 flex-1", children: [
|
|
2553
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)("div", { className: "flex max-w-full items-center gap-2", children: /* @__PURE__ */ (0, import_jsx_runtime45.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_runtime45.jsx)(MusicBrainzRecordingLink, { song: track, className: "hover:underline focus-visible:underline", children: track.title }) : track.title }) }),
|
|
2554
|
+
track.artists && track.artists.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("div", { className: "artist text-base max-w-full truncate text-[var(--color-text-muted)]", children: /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(import_genre_tree25.ArtistNames, { artists: track.artists, renderArtistLink }) }) : ""
|
|
2501
2555
|
] }),
|
|
2502
|
-
/* @__PURE__ */ (0,
|
|
2503
|
-
renderDuration && /* @__PURE__ */ (0,
|
|
2556
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.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_runtime45.jsx)("div", { className: "genre-name max-w-full whitespace-normal break-words p-1 text-caption font-bold", children: track.genre.name }) : "" }),
|
|
2557
|
+
renderDuration && /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
|
|
2504
2558
|
"div",
|
|
2505
2559
|
{
|
|
2506
2560
|
className: "duration flex text-base w-16 items-center justify-center",
|
|
@@ -2508,28 +2562,28 @@ function TrackItem({
|
|
|
2508
2562
|
children: renderDuration(track)
|
|
2509
2563
|
}
|
|
2510
2564
|
),
|
|
2511
|
-
renderActions && /* @__PURE__ */ (0,
|
|
2565
|
+
renderActions && /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("div", { className: "edit flex text-base w-6 items-center justify-center mr-2 cursor-pointer", children: renderActions(track) })
|
|
2512
2566
|
]
|
|
2513
2567
|
}
|
|
2514
2568
|
);
|
|
2515
2569
|
}
|
|
2516
2570
|
|
|
2517
2571
|
// src/genre-tree/artist/ArtistSongs.tsx
|
|
2518
|
-
var
|
|
2519
|
-
var SongPageSchema2 = (0,
|
|
2572
|
+
var import_jsx_runtime46 = require("react/jsx-runtime");
|
|
2573
|
+
var SongPageSchema2 = (0, import_transport8.PaginatedResponseSchema)(import_genre_tree26.SongDetailedSchema);
|
|
2520
2574
|
var SORTS = [
|
|
2521
2575
|
{ ordering: "title", label: "Title" },
|
|
2522
2576
|
{ ordering: "-albumYear", label: "Year" }
|
|
2523
2577
|
];
|
|
2524
2578
|
function ArtistSongs({ artist, getBackendBaseUrl, renderArtistLink, renderSongLink }) {
|
|
2525
|
-
const [page, setPage] = (0,
|
|
2526
|
-
const [ordering, setOrdering] = (0,
|
|
2527
|
-
const { playNewTrackListFromArtist } = (0,
|
|
2528
|
-
const { playerTrackObject } = (0,
|
|
2529
|
-
const { data, isPending, isError } = (0,
|
|
2579
|
+
const [page, setPage] = (0, import_react17.useState)(1);
|
|
2580
|
+
const [ordering, setOrdering] = (0, import_react17.useState)("title");
|
|
2581
|
+
const { playNewTrackListFromArtist } = (0, import_genre_tree26.useTrackList)();
|
|
2582
|
+
const { playerTrackObject } = (0, import_player11.usePlayer)();
|
|
2583
|
+
const { data, isPending, isError } = (0, import_transport8.usePlaybackQuery)({
|
|
2530
2584
|
getBackendBaseUrl,
|
|
2531
2585
|
queryKey: ["referenceSongs", "artist", artist.uuid, ordering, page],
|
|
2532
|
-
queryFn: (fetchBound) => fetchBound(
|
|
2586
|
+
queryFn: (fetchBound) => fetchBound(import_genre_tree26.libraryEndpoints.reference.songs.list(), true, false, void 0, {
|
|
2533
2587
|
artist: artist.uuid,
|
|
2534
2588
|
ordering,
|
|
2535
2589
|
page
|
|
@@ -2544,25 +2598,25 @@ function ArtistSongs({ artist, getBackendBaseUrl, renderArtistLink, renderSongLi
|
|
|
2544
2598
|
});
|
|
2545
2599
|
const handleRowClickCapture = (event, song) => {
|
|
2546
2600
|
if (!(event.target instanceof Element) || !event.target.closest(".track-position-play-pause")) return;
|
|
2547
|
-
if (playerTrackObject?.track.id === song.uuid || (0,
|
|
2601
|
+
if (playerTrackObject?.track.id === song.uuid || (0, import_genre_tree26.songUnplayableReason)(song) !== null) return;
|
|
2548
2602
|
event.stopPropagation();
|
|
2549
2603
|
void play(song.uuid);
|
|
2550
2604
|
};
|
|
2551
|
-
return /* @__PURE__ */ (0,
|
|
2552
|
-
/* @__PURE__ */ (0,
|
|
2553
|
-
/* @__PURE__ */ (0,
|
|
2605
|
+
return /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(import_ui19.PanelSection, { title: "Songs", children: isPending ? /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(import_ui19.Skeleton, { className: "h-14", "aria-busy": "true" }) : isError ? /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("p", { className: "text-red-600", children: "Could not load songs." }) : data.results.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("p", { className: "text-[var(--color-text-muted)]", children: "No songs yet." }) : /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)(import_jsx_runtime46.Fragment, { children: [
|
|
2606
|
+
/* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("div", { className: "flex flex-wrap items-center justify-between gap-2 mb-2", children: [
|
|
2607
|
+
/* @__PURE__ */ (0, import_jsx_runtime46.jsxs)(
|
|
2554
2608
|
"button",
|
|
2555
2609
|
{
|
|
2556
2610
|
type: "button",
|
|
2557
2611
|
onClick: () => void play(),
|
|
2558
2612
|
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",
|
|
2559
2613
|
children: [
|
|
2560
|
-
/* @__PURE__ */ (0,
|
|
2614
|
+
/* @__PURE__ */ (0, import_jsx_runtime46.jsx)(import_lucide_react16.Play, { className: "h-3.5 w-3.5", "aria-hidden": "true" }),
|
|
2561
2615
|
"Play all"
|
|
2562
2616
|
]
|
|
2563
2617
|
}
|
|
2564
2618
|
),
|
|
2565
|
-
/* @__PURE__ */ (0,
|
|
2619
|
+
/* @__PURE__ */ (0, import_jsx_runtime46.jsx)("div", { role: "group", "aria-label": "Sort songs by", className: "flex gap-1 text-caption", children: SORTS.map((sort) => /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(
|
|
2566
2620
|
"button",
|
|
2567
2621
|
{
|
|
2568
2622
|
type: "button",
|
|
@@ -2577,7 +2631,7 @@ function ArtistSongs({ artist, getBackendBaseUrl, renderArtistLink, renderSongLi
|
|
|
2577
2631
|
sort.ordering
|
|
2578
2632
|
)) })
|
|
2579
2633
|
] }),
|
|
2580
|
-
/* @__PURE__ */ (0,
|
|
2634
|
+
/* @__PURE__ */ (0, import_jsx_runtime46.jsx)("ul", { className: "overflow-hidden mb-2 bg-zinc-950 rounded-lg", children: data.results.map((song, index) => /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("li", { onClickCapture: (event) => handleRowClickCapture(event, song), children: /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(
|
|
2581
2635
|
TrackItem,
|
|
2582
2636
|
{
|
|
2583
2637
|
track: song,
|
|
@@ -2586,12 +2640,12 @@ function ArtistSongs({ artist, getBackendBaseUrl, renderArtistLink, renderSongLi
|
|
|
2586
2640
|
renderSongLink
|
|
2587
2641
|
}
|
|
2588
2642
|
) }, song.uuid)) }),
|
|
2589
|
-
/* @__PURE__ */ (0,
|
|
2643
|
+
/* @__PURE__ */ (0, import_jsx_runtime46.jsx)(import_ui19.Pagination, { currentPage: page, totalPages: data.totalPages, onPageChange: setPage })
|
|
2590
2644
|
] }) });
|
|
2591
2645
|
}
|
|
2592
2646
|
|
|
2593
2647
|
// src/genre-tree/artist/useArtistPanel.tsx
|
|
2594
|
-
var
|
|
2648
|
+
var import_jsx_runtime47 = require("react/jsx-runtime");
|
|
2595
2649
|
function useArtistPanel({
|
|
2596
2650
|
uuid,
|
|
2597
2651
|
scope,
|
|
@@ -2603,7 +2657,7 @@ function useArtistPanel({
|
|
|
2603
2657
|
onExpandedChange,
|
|
2604
2658
|
onClose
|
|
2605
2659
|
}) {
|
|
2606
|
-
const result = (0,
|
|
2660
|
+
const result = (0, import_genre_tree27.useArtist)(uuid, getBackendBaseUrl);
|
|
2607
2661
|
const panel = { expanded, onExpandedChange, onClose };
|
|
2608
2662
|
switch (result.status) {
|
|
2609
2663
|
case "idle":
|
|
@@ -2612,26 +2666,26 @@ function useArtistPanel({
|
|
|
2612
2666
|
return {
|
|
2613
2667
|
...panel,
|
|
2614
2668
|
title: "Artist",
|
|
2615
|
-
content: /* @__PURE__ */ (0,
|
|
2616
|
-
/* @__PURE__ */ (0,
|
|
2617
|
-
/* @__PURE__ */ (0,
|
|
2618
|
-
/* @__PURE__ */ (0,
|
|
2619
|
-
/* @__PURE__ */ (0,
|
|
2620
|
-
/* @__PURE__ */ (0,
|
|
2621
|
-
/* @__PURE__ */ (0,
|
|
2669
|
+
content: /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("div", { "aria-busy": "true", className: "flex flex-col gap-2.5", children: [
|
|
2670
|
+
/* @__PURE__ */ (0, import_jsx_runtime47.jsx)(import_ui20.Skeleton, { className: "h-3 w-16" }),
|
|
2671
|
+
/* @__PURE__ */ (0, import_jsx_runtime47.jsx)(import_ui20.Skeleton, { className: "h-4 w-32" }),
|
|
2672
|
+
/* @__PURE__ */ (0, import_jsx_runtime47.jsx)(import_ui20.Skeleton, { className: "h-3 w-16" }),
|
|
2673
|
+
/* @__PURE__ */ (0, import_jsx_runtime47.jsx)(import_ui20.Skeleton, { className: "h-4 w-24" }),
|
|
2674
|
+
/* @__PURE__ */ (0, import_jsx_runtime47.jsx)(import_ui20.Skeleton, { className: "h-16 mt-2.5" }),
|
|
2675
|
+
/* @__PURE__ */ (0, import_jsx_runtime47.jsx)(import_ui20.Skeleton, { className: "h-16" })
|
|
2622
2676
|
] })
|
|
2623
2677
|
};
|
|
2624
2678
|
case "not-found":
|
|
2625
2679
|
return {
|
|
2626
2680
|
...panel,
|
|
2627
2681
|
title: "Artist not found",
|
|
2628
|
-
content: /* @__PURE__ */ (0,
|
|
2682
|
+
content: /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("p", { className: "text-[var(--color-text-muted)]", children: "This artist does not exist." })
|
|
2629
2683
|
};
|
|
2630
2684
|
case "error":
|
|
2631
2685
|
return {
|
|
2632
2686
|
...panel,
|
|
2633
2687
|
title: "Artist",
|
|
2634
|
-
content: /* @__PURE__ */ (0,
|
|
2688
|
+
content: /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("p", { className: "text-red-600", children: "Could not load this artist." })
|
|
2635
2689
|
};
|
|
2636
2690
|
case "success": {
|
|
2637
2691
|
const { artist } = result;
|
|
@@ -2640,13 +2694,19 @@ function useArtistPanel({
|
|
|
2640
2694
|
return {
|
|
2641
2695
|
...panel,
|
|
2642
2696
|
title: artist.name,
|
|
2643
|
-
content: /* @__PURE__ */ (0,
|
|
2644
|
-
|
|
2645
|
-
|
|
2646
|
-
|
|
2647
|
-
|
|
2648
|
-
|
|
2649
|
-
|
|
2697
|
+
content: /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)(import_jsx_runtime47.Fragment, { children: [
|
|
2698
|
+
/* @__PURE__ */ (0, import_jsx_runtime47.jsx)(
|
|
2699
|
+
ArtistActionBand,
|
|
2700
|
+
{
|
|
2701
|
+
artist,
|
|
2702
|
+
share: shareTarget && shareUrl ? /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(ShareActionButton, { target: shareTarget, url: shareUrl }) : void 0
|
|
2703
|
+
}
|
|
2704
|
+
),
|
|
2705
|
+
artist.image && /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(ArtistPhoto, { image: artist.image, name: artist.name }),
|
|
2706
|
+
/* @__PURE__ */ (0, import_jsx_runtime47.jsx)(ArtistHeader, { artist }),
|
|
2707
|
+
/* @__PURE__ */ (0, import_jsx_runtime47.jsx)(ArtistMembers, { title: "Members", memberships: artist.members, renderArtistLink }),
|
|
2708
|
+
/* @__PURE__ */ (0, import_jsx_runtime47.jsx)(ArtistMembers, { title: "Member of", memberships: artist.memberOf, renderArtistLink }),
|
|
2709
|
+
artist.tracksCount > 0 && /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(
|
|
2650
2710
|
ArtistSongs,
|
|
2651
2711
|
{
|
|
2652
2712
|
artist: { uuid: artist.uuid, name: artist.name },
|
|
@@ -2656,69 +2716,62 @@ function useArtistPanel({
|
|
|
2656
2716
|
}
|
|
2657
2717
|
)
|
|
2658
2718
|
] }),
|
|
2659
|
-
extraContent: artist.albums.length > 0 ? /* @__PURE__ */ (0,
|
|
2719
|
+
extraContent: artist.albums.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(ArtistDiscography, { albums: artist.albums }) : void 0
|
|
2660
2720
|
};
|
|
2661
2721
|
}
|
|
2662
2722
|
}
|
|
2663
2723
|
}
|
|
2664
2724
|
|
|
2665
2725
|
// src/genre-tree/song/useSongPanel.tsx
|
|
2666
|
-
var
|
|
2667
|
-
var
|
|
2726
|
+
var import_ui22 = require("@behindthemusictree/ui");
|
|
2727
|
+
var import_genre_tree29 = require("@behindthemusictree/app-kit/genre-tree");
|
|
2668
2728
|
|
|
2669
2729
|
// src/genre-tree/song/SongPanelContent.tsx
|
|
2670
|
-
var
|
|
2671
|
-
var
|
|
2672
|
-
var
|
|
2673
|
-
var
|
|
2674
|
-
var
|
|
2675
|
-
var
|
|
2730
|
+
var import_react18 = require("react");
|
|
2731
|
+
var import_lucide_react17 = require("lucide-react");
|
|
2732
|
+
var import_ui21 = require("@behindthemusictree/ui");
|
|
2733
|
+
var import_player12 = require("@behindthemusictree/app-kit/player");
|
|
2734
|
+
var import_genre_tree28 = require("@behindthemusictree/app-kit/genre-tree");
|
|
2735
|
+
var import_jsx_runtime48 = require("react/jsx-runtime");
|
|
2676
2736
|
var numberFormat = new Intl.NumberFormat("en");
|
|
2677
2737
|
var dateFormat = new Intl.DateTimeFormat("en", { dateStyle: "medium" });
|
|
2678
2738
|
var externalLink = "text-[var(--color-primary)] hover:underline focus-visible:underline";
|
|
2679
2739
|
function SongHistory({ uuid, getBackendBaseUrl }) {
|
|
2680
|
-
const [open, setOpen] = (0,
|
|
2681
|
-
const history = (0,
|
|
2740
|
+
const [open, setOpen] = (0, import_react18.useState)(false);
|
|
2741
|
+
const history = (0, import_genre_tree28.useSongHistory)(uuid, getBackendBaseUrl, open);
|
|
2682
2742
|
let body = null;
|
|
2683
|
-
if (history.status === "loading") body = /* @__PURE__ */ (0,
|
|
2684
|
-
else if (history.status === "error") body = /* @__PURE__ */ (0,
|
|
2743
|
+
if (history.status === "loading") body = /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(import_ui21.Skeleton, { className: "h-10", "aria-busy": "true" });
|
|
2744
|
+
else if (history.status === "error") body = /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("p", { className: "text-red-600", children: "Could not load the history." });
|
|
2685
2745
|
else if (history.status === "success")
|
|
2686
|
-
body = history.entries.length === 0 ? /* @__PURE__ */ (0,
|
|
2687
|
-
/* @__PURE__ */ (0,
|
|
2688
|
-
entry.oldValue !== null || entry.newValue !== null ? /* @__PURE__ */ (0,
|
|
2746
|
+
body = history.entries.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("p", { className: "text-[var(--color-text-muted)]", children: "No changes yet." }) : /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("ul", { className: "divide-y divide-[var(--color-border)]", children: history.entries.map((entry) => /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("li", { className: "py-1.5 text-body", children: [
|
|
2747
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)("span", { className: "font-medium", children: entry.action }),
|
|
2748
|
+
entry.oldValue !== null || entry.newValue !== null ? /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("span", { className: "text-[var(--color-text-muted)]", children: [
|
|
2689
2749
|
" ",
|
|
2690
2750
|
"\u2014 ",
|
|
2691
2751
|
entry.oldValue ?? "none",
|
|
2692
2752
|
" \u2192 ",
|
|
2693
2753
|
entry.newValue ?? "none"
|
|
2694
2754
|
] }) : null,
|
|
2695
|
-
/* @__PURE__ */ (0,
|
|
2755
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("span", { className: "block text-caption text-[var(--color-text-muted)]", children: [
|
|
2696
2756
|
entry.actorPseudo ?? "Anonymous",
|
|
2697
2757
|
" \xB7 ",
|
|
2698
2758
|
dateFormat.format(new Date(entry.createdOn))
|
|
2699
2759
|
] })
|
|
2700
2760
|
] }, entry.uuid)) });
|
|
2701
|
-
return /* @__PURE__ */ (0,
|
|
2702
|
-
"
|
|
2703
|
-
{
|
|
2704
|
-
|
|
2705
|
-
className: "px-6 pb-2.5 mt-2.5 border-t border-[var(--color-border)]",
|
|
2706
|
-
children: [
|
|
2707
|
-
/* @__PURE__ */ (0, import_jsx_runtime43.jsx)("summary", { className: "mt-2.5 cursor-pointer text-[0.6875rem] font-semibold uppercase text-[var(--color-text-muted)]", children: "History" }),
|
|
2708
|
-
/* @__PURE__ */ (0, import_jsx_runtime43.jsx)("div", { className: "mt-1.5", children: body })
|
|
2709
|
-
]
|
|
2710
|
-
}
|
|
2711
|
-
);
|
|
2761
|
+
return /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(import_ui21.PanelBleed, { padded: true, className: "border-t border-[var(--color-border)]", children: /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("details", { onToggle: (event) => setOpen(event.currentTarget.open), className: "pb-2.5", children: [
|
|
2762
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)("summary", { className: `mt-2.5 cursor-pointer ${import_ui21.PANEL_LABEL_CLASS}`, children: "History" }),
|
|
2763
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)("div", { className: "mt-1.5", children: body })
|
|
2764
|
+
] }) });
|
|
2712
2765
|
}
|
|
2713
2766
|
function SongPanelContent(props) {
|
|
2714
2767
|
const { song, scope, getBackendBaseUrl, shareUrl, renderArtistLink } = props;
|
|
2715
|
-
const { playNewTrackListFromTrackUuid } = (0,
|
|
2716
|
-
const { playerTrackObject, playState, handlePlayPauseAction } = (0,
|
|
2717
|
-
const unplayableReason = (0,
|
|
2768
|
+
const { playNewTrackListFromTrackUuid } = (0, import_genre_tree28.useTrackList)();
|
|
2769
|
+
const { playerTrackObject, playState, handlePlayPauseAction } = (0, import_player12.usePlayer)();
|
|
2770
|
+
const unplayableReason = (0, import_genre_tree28.songUnplayableReason)(song);
|
|
2718
2771
|
const isCurrent = playerTrackObject?.track.id === song.uuid;
|
|
2719
|
-
const isPlaying = isCurrent && playState ===
|
|
2772
|
+
const isPlaying = isCurrent && playState === import_player12.PlayStates.PLAYING;
|
|
2720
2773
|
const shareTarget = { kind: "song", uuid: song.uuid, name: song.title, scope };
|
|
2721
|
-
const musicBrainzUrl = (0,
|
|
2774
|
+
const musicBrainzUrl = (0, import_genre_tree28.musicBrainzRecordingUrl)(song);
|
|
2722
2775
|
const fields = [];
|
|
2723
2776
|
if (song.genre) {
|
|
2724
2777
|
const path = props.genrePath && props.genrePath.length > 0 ? props.genrePath : null;
|
|
@@ -2726,13 +2779,13 @@ function SongPanelContent(props) {
|
|
|
2726
2779
|
const genre = song.genre;
|
|
2727
2780
|
fields.push({
|
|
2728
2781
|
label: "Genre",
|
|
2729
|
-
value: onSelectGenre ? /* @__PURE__ */ (0,
|
|
2730
|
-
index > 0 && /* @__PURE__ */ (0,
|
|
2731
|
-
/* @__PURE__ */ (0,
|
|
2782
|
+
value: onSelectGenre ? /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("button", { type: "button", onClick: () => onSelectGenre(genre), className: "hover:underline", children: genre.name }) : path ? /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("span", { className: "flex flex-wrap items-center gap-x-1", children: path.map((genrePlaylist, index) => /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("span", { children: [
|
|
2783
|
+
index > 0 && /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("span", { "aria-hidden": "true", children: "\u203A " }),
|
|
2784
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)("button", { type: "button", onClick: () => props.onSelectGenrePlaylist?.(genrePlaylist), className: "hover:underline", children: genrePlaylist.name })
|
|
2732
2785
|
] }, genrePlaylist.uuid)) }) : song.genre.name
|
|
2733
2786
|
});
|
|
2734
2787
|
} else {
|
|
2735
|
-
fields.push({ label: "Genre", value: /* @__PURE__ */ (0,
|
|
2788
|
+
fields.push({ label: "Genre", value: /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("span", { className: "text-[var(--color-text-muted)]", children: "No genre" }) });
|
|
2736
2789
|
}
|
|
2737
2790
|
if (song.firstReleaseYear) fields.push({ label: "First released", value: song.firstReleaseYear });
|
|
2738
2791
|
const viewCount = song.youtubeVideo?.viewCount;
|
|
@@ -2742,11 +2795,11 @@ function SongPanelContent(props) {
|
|
|
2742
2795
|
const links = [];
|
|
2743
2796
|
if (musicBrainzUrl)
|
|
2744
2797
|
links.push(
|
|
2745
|
-
/* @__PURE__ */ (0,
|
|
2798
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)("a", { href: musicBrainzUrl, target: "_blank", rel: "noopener noreferrer", className: externalLink, children: "MusicBrainz" }, "mb")
|
|
2746
2799
|
);
|
|
2747
2800
|
if (song.youtubeVideo)
|
|
2748
2801
|
links.push(
|
|
2749
|
-
/* @__PURE__ */ (0,
|
|
2802
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
|
|
2750
2803
|
"a",
|
|
2751
2804
|
{
|
|
2752
2805
|
href: `https://www.youtube.com/watch?v=${encodeURIComponent(song.youtubeVideo.id)}`,
|
|
@@ -2761,33 +2814,31 @@ function SongPanelContent(props) {
|
|
|
2761
2814
|
if (links.length > 0)
|
|
2762
2815
|
fields.push({
|
|
2763
2816
|
label: "Links",
|
|
2764
|
-
value: /* @__PURE__ */ (0,
|
|
2817
|
+
value: /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("span", { className: "flex gap-3", children: links })
|
|
2765
2818
|
});
|
|
2766
|
-
return /* @__PURE__ */ (0,
|
|
2767
|
-
/* @__PURE__ */ (0,
|
|
2768
|
-
|
|
2769
|
-
|
|
2819
|
+
return /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)(import_jsx_runtime48.Fragment, { children: [
|
|
2820
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)(import_ui21.PanelBleed, { children: /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)(import_ui21.ActionBand, { children: [
|
|
2821
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
|
|
2822
|
+
import_ui21.ActionButton,
|
|
2770
2823
|
{
|
|
2771
|
-
|
|
2772
|
-
|
|
2773
|
-
|
|
2774
|
-
|
|
2775
|
-
|
|
2776
|
-
isPlaying ? "Pause" : "Play"
|
|
2777
|
-
]
|
|
2824
|
+
icon: isPlaying ? /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(import_lucide_react17.Pause, { "aria-hidden": "true", className: "w-5 h-5" }) : /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(import_lucide_react17.Play, { "aria-hidden": "true", className: "w-5 h-5" }),
|
|
2825
|
+
label: isPlaying ? "Pause" : "Play",
|
|
2826
|
+
disabled: !!unplayableReason,
|
|
2827
|
+
title: unplayableReason ?? void 0,
|
|
2828
|
+
onClick: () => isCurrent ? handlePlayPauseAction() : playNewTrackListFromTrackUuid(song, scope)
|
|
2778
2829
|
}
|
|
2779
2830
|
),
|
|
2780
|
-
shareUrl && /* @__PURE__ */ (0,
|
|
2831
|
+
shareUrl && /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(ShareActionButton, { target: shareTarget, url: shareUrl })
|
|
2781
2832
|
] }) }),
|
|
2782
|
-
song.artists && song.artists.length > 0 && /* @__PURE__ */ (0,
|
|
2783
|
-
/* @__PURE__ */ (0,
|
|
2784
|
-
song.essentialGenres && song.essentialGenres.length > 0 && /* @__PURE__ */ (0,
|
|
2785
|
-
/* @__PURE__ */ (0,
|
|
2833
|
+
song.artists && song.artists.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("p", { className: "text-[var(--color-text-muted)]", children: /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(import_genre_tree28.ArtistNames, { artists: song.artists, renderArtistLink }) }),
|
|
2834
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)(import_ui21.FieldList, { items: fields }),
|
|
2835
|
+
song.essentialGenres && song.essentialGenres.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(import_ui21.PanelSection, { title: "Essential in", children: /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("ul", { children: song.essentialGenres.map((genre) => /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("li", { className: "py-0.5", children: genre.name }, genre.uuid)) }) }),
|
|
2836
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)(SongHistory, { uuid: song.uuid, getBackendBaseUrl })
|
|
2786
2837
|
] });
|
|
2787
2838
|
}
|
|
2788
2839
|
|
|
2789
2840
|
// src/genre-tree/song/useSongPanel.tsx
|
|
2790
|
-
var
|
|
2841
|
+
var import_jsx_runtime49 = require("react/jsx-runtime");
|
|
2791
2842
|
function useSongPanel({
|
|
2792
2843
|
uuid,
|
|
2793
2844
|
scope,
|
|
@@ -2799,7 +2850,7 @@ function useSongPanel({
|
|
|
2799
2850
|
onClose,
|
|
2800
2851
|
...navigation
|
|
2801
2852
|
}) {
|
|
2802
|
-
const result = (0,
|
|
2853
|
+
const result = (0, import_genre_tree29.useSong)(uuid, getBackendBaseUrl);
|
|
2803
2854
|
const panel = { expanded, onExpandedChange, onClose };
|
|
2804
2855
|
switch (result.status) {
|
|
2805
2856
|
case "idle":
|
|
@@ -2808,24 +2859,24 @@ function useSongPanel({
|
|
|
2808
2859
|
return {
|
|
2809
2860
|
...panel,
|
|
2810
2861
|
title: "Song",
|
|
2811
|
-
content: /* @__PURE__ */ (0,
|
|
2812
|
-
/* @__PURE__ */ (0,
|
|
2813
|
-
/* @__PURE__ */ (0,
|
|
2814
|
-
/* @__PURE__ */ (0,
|
|
2815
|
-
/* @__PURE__ */ (0,
|
|
2862
|
+
content: /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)("div", { "aria-busy": "true", className: "flex flex-col gap-2.5", children: [
|
|
2863
|
+
/* @__PURE__ */ (0, import_jsx_runtime49.jsx)(import_ui22.Skeleton, { className: "h-3 w-16" }),
|
|
2864
|
+
/* @__PURE__ */ (0, import_jsx_runtime49.jsx)(import_ui22.Skeleton, { className: "h-4 w-32" }),
|
|
2865
|
+
/* @__PURE__ */ (0, import_jsx_runtime49.jsx)(import_ui22.Skeleton, { className: "h-3 w-16" }),
|
|
2866
|
+
/* @__PURE__ */ (0, import_jsx_runtime49.jsx)(import_ui22.Skeleton, { className: "h-4 w-24" })
|
|
2816
2867
|
] })
|
|
2817
2868
|
};
|
|
2818
2869
|
case "not-found":
|
|
2819
2870
|
return {
|
|
2820
2871
|
...panel,
|
|
2821
2872
|
title: "Song not found",
|
|
2822
|
-
content: /* @__PURE__ */ (0,
|
|
2873
|
+
content: /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("p", { className: "text-[var(--color-text-muted)]", children: "This song does not exist." })
|
|
2823
2874
|
};
|
|
2824
2875
|
case "error":
|
|
2825
2876
|
return {
|
|
2826
2877
|
...panel,
|
|
2827
2878
|
title: "Song",
|
|
2828
|
-
content: /* @__PURE__ */ (0,
|
|
2879
|
+
content: /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("p", { className: "text-red-600", children: "Could not load this song." })
|
|
2829
2880
|
};
|
|
2830
2881
|
case "success": {
|
|
2831
2882
|
const { song } = result;
|
|
@@ -2833,7 +2884,7 @@ function useSongPanel({
|
|
|
2833
2884
|
return {
|
|
2834
2885
|
...panel,
|
|
2835
2886
|
title: song.title,
|
|
2836
|
-
content: /* @__PURE__ */ (0,
|
|
2887
|
+
content: /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(
|
|
2837
2888
|
SongPanelContent,
|
|
2838
2889
|
{
|
|
2839
2890
|
song,
|
|
@@ -2885,29 +2936,29 @@ function useEntityPanel({
|
|
|
2885
2936
|
|
|
2886
2937
|
// src/genre-tree/SizeMetricToggle.tsx
|
|
2887
2938
|
var import_md2 = require("react-icons/md");
|
|
2888
|
-
var
|
|
2889
|
-
var
|
|
2939
|
+
var import_ui23 = require("@behindthemusictree/ui");
|
|
2940
|
+
var import_jsx_runtime50 = require("react/jsx-runtime");
|
|
2890
2941
|
function SizeMetricToggle({
|
|
2891
2942
|
value,
|
|
2892
2943
|
onChange
|
|
2893
2944
|
}) {
|
|
2894
|
-
return /* @__PURE__ */ (0,
|
|
2895
|
-
|
|
2945
|
+
return /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(
|
|
2946
|
+
import_ui23.SegmentedControl,
|
|
2896
2947
|
{
|
|
2897
2948
|
variant: "floating",
|
|
2898
2949
|
"aria-label": "Size nodes by",
|
|
2899
2950
|
value,
|
|
2900
2951
|
onChange,
|
|
2901
2952
|
options: [
|
|
2902
|
-
{ value: "songs", label: /* @__PURE__ */ (0,
|
|
2903
|
-
{ value: "views", label: /* @__PURE__ */ (0,
|
|
2953
|
+
{ value: "songs", label: /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(import_md2.MdMusicNote, { size: 18, "aria-hidden": true }), "aria-label": "Size by songs", title: "Node size by song count" },
|
|
2954
|
+
{ value: "views", label: /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(import_md2.MdVisibility, { size: 18, "aria-hidden": true }), "aria-label": "Size by views", title: "Node size by song views" }
|
|
2904
2955
|
]
|
|
2905
2956
|
}
|
|
2906
2957
|
);
|
|
2907
2958
|
}
|
|
2908
2959
|
|
|
2909
2960
|
// src/genre-tree/GenreTreeView.tsx
|
|
2910
|
-
var
|
|
2961
|
+
var import_jsx_runtime51 = require("react/jsx-runtime");
|
|
2911
2962
|
var NO_POP_ROOT_TITLE = "This genre tree has no 'Mainstream Pop' root yet";
|
|
2912
2963
|
var REGIONS_CLASS = "[--gtv-center-left:var(--layout-center-left)] [--gtv-center-right:var(--layout-center-right)] [--gtv-center-top:var(--layout-band-top)]";
|
|
2913
2964
|
var noop = () => {
|
|
@@ -2969,21 +3020,21 @@ function GenreTreeView({
|
|
|
2969
3020
|
placement = "default",
|
|
2970
3021
|
...focus
|
|
2971
3022
|
}) {
|
|
2972
|
-
const getShareUrlRef = (0,
|
|
3023
|
+
const getShareUrlRef = (0, import_react19.useRef)(getShareUrl);
|
|
2973
3024
|
getShareUrlRef.current = getShareUrl;
|
|
2974
|
-
const [internalArtistUuid, setInternalArtistUuid] = (0,
|
|
3025
|
+
const [internalArtistUuid, setInternalArtistUuid] = (0, import_react19.useState)(null);
|
|
2975
3026
|
const isArtistControlled = controlledArtistUuid !== void 0;
|
|
2976
3027
|
const artistUuid = isArtistControlled ? controlledArtistUuid : internalArtistUuid;
|
|
2977
|
-
const [internalSongUuid, setInternalSongUuid] = (0,
|
|
3028
|
+
const [internalSongUuid, setInternalSongUuid] = (0, import_react19.useState)(null);
|
|
2978
3029
|
const isSongControlled = controlledSongUuid !== void 0;
|
|
2979
3030
|
const songUuid = isSongControlled ? controlledSongUuid : internalSongUuid;
|
|
2980
3031
|
const changeSong = (uuid) => {
|
|
2981
3032
|
if (!isSongControlled) setInternalSongUuid(uuid);
|
|
2982
3033
|
onSongUuidChange?.(uuid);
|
|
2983
3034
|
};
|
|
2984
|
-
const [internalSizeMetric, setInternalSizeMetric] = (0,
|
|
3035
|
+
const [internalSizeMetric, setInternalSizeMetric] = (0, import_react19.useState)("songs");
|
|
2985
3036
|
const sizeMetric = controlledSizeMetric ?? internalSizeMetric;
|
|
2986
|
-
const deferredSizeMetric = (0,
|
|
3037
|
+
const deferredSizeMetric = (0, import_react19.useDeferredValue)(sizeMetric);
|
|
2987
3038
|
const changeSizeMetric = (metric) => {
|
|
2988
3039
|
if (controlledSizeMetric === void 0) setInternalSizeMetric(metric);
|
|
2989
3040
|
onSizeMetricChange?.(metric);
|
|
@@ -2999,6 +3050,7 @@ function GenreTreeView({
|
|
|
2999
3050
|
isFetching: isTreeFetching,
|
|
3000
3051
|
genrePlaylistByNodeId,
|
|
3001
3052
|
visibleGenrePlaylists,
|
|
3053
|
+
focusUuids,
|
|
3002
3054
|
groupedGenrePlaylistsByRoot,
|
|
3003
3055
|
selectedGenreUuid,
|
|
3004
3056
|
selectGenre,
|
|
@@ -3014,7 +3066,7 @@ function GenreTreeView({
|
|
|
3014
3066
|
allowWheelRotation: internalAllowWheelRotation,
|
|
3015
3067
|
toggleWheelRotation,
|
|
3016
3068
|
onNodeHover: handleNodeHover
|
|
3017
|
-
} = (0,
|
|
3069
|
+
} = (0, import_genre_tree30.useGenreTreeViewState)({
|
|
3018
3070
|
scope,
|
|
3019
3071
|
getBackendBaseUrl,
|
|
3020
3072
|
viewMode: controlledViewMode,
|
|
@@ -3024,7 +3076,7 @@ function GenreTreeView({
|
|
|
3024
3076
|
artistUuid
|
|
3025
3077
|
});
|
|
3026
3078
|
const restoreRevision = viewportRestore?.revision;
|
|
3027
|
-
const [stackedRestoreOwner, setStackedRestoreOwner] = (0,
|
|
3079
|
+
const [stackedRestoreOwner, setStackedRestoreOwner] = (0, import_react19.useState)({ revision: restoreRevision, rootUuid: selectedGenrePlaylist?.root.uuid });
|
|
3028
3080
|
let restoreRootUuid = stackedRestoreOwner.rootUuid;
|
|
3029
3081
|
if (stackedRestoreOwner.revision !== restoreRevision) {
|
|
3030
3082
|
restoreRootUuid = selectedGenrePlaylist?.root.uuid;
|
|
@@ -3033,14 +3085,14 @@ function GenreTreeView({
|
|
|
3033
3085
|
restoreRootUuid = selectedGenrePlaylist.root.uuid;
|
|
3034
3086
|
setStackedRestoreOwner({ revision: restoreRevision, rootUuid: restoreRootUuid });
|
|
3035
3087
|
}
|
|
3036
|
-
const isGenreUpdating = (0, import_react_query3.useIsMutating)({ mutationKey:
|
|
3037
|
-
const { mutate: updateGenre } = (0,
|
|
3088
|
+
const isGenreUpdating = (0, import_react_query3.useIsMutating)({ mutationKey: import_genre_tree30.genreUpdateMutationKey }) > 0;
|
|
3089
|
+
const { mutate: updateGenre } = (0, import_genre_tree30.useUpdateGenre)(scope, getBackendBaseUrl);
|
|
3038
3090
|
const busy = deferredSizeMetric !== sizeMetric || isTreeFetching || isGenreUpdating;
|
|
3039
3091
|
const isArtistFiltered = artistUuid !== null;
|
|
3040
3092
|
const canSizeByViews = !isArtistFiltered && hasViewsCount(visibleGenrePlaylists);
|
|
3041
|
-
const artistResult = (0,
|
|
3093
|
+
const artistResult = (0, import_genre_tree30.useArtist)(artistUuid, artistSearchBaseUrl ?? getBackendBaseUrl);
|
|
3042
3094
|
const filterArtistName = artistResult.status === "success" ? artistResult.artist.name : null;
|
|
3043
|
-
const filterArtist = (0,
|
|
3095
|
+
const filterArtist = (0, import_react19.useMemo)(
|
|
3044
3096
|
() => artistUuid !== null && filterArtistName !== null ? { uuid: artistUuid, name: filterArtistName } : null,
|
|
3045
3097
|
[artistUuid, filterArtistName]
|
|
3046
3098
|
);
|
|
@@ -3055,17 +3107,17 @@ function GenreTreeView({
|
|
|
3055
3107
|
if (selectedGenreUuid !== null) clearSelection();
|
|
3056
3108
|
changeSong(uuid);
|
|
3057
3109
|
};
|
|
3058
|
-
const openSongRef = (0,
|
|
3110
|
+
const openSongRef = (0, import_react19.useRef)(openSong);
|
|
3059
3111
|
openSongRef.current = openSong;
|
|
3060
|
-
const resolvedRenderSongLink = (0,
|
|
3061
|
-
(song) => renderSongLink ? renderSongLink(song) : /* @__PURE__ */ (0,
|
|
3112
|
+
const resolvedRenderSongLink = (0, import_react19.useCallback)(
|
|
3113
|
+
(song) => renderSongLink ? renderSongLink(song) : /* @__PURE__ */ (0, import_jsx_runtime51.jsx)("button", { type: "button", onClick: () => openSongRef.current(song.uuid), className: "hover:underline", children: song.title }),
|
|
3062
3114
|
[renderSongLink]
|
|
3063
3115
|
);
|
|
3064
|
-
const [expandedSongUuid, setExpandedSongUuid] = (0,
|
|
3065
|
-
const [expandedArtistUuid, setExpandedArtistUuid] = (0,
|
|
3116
|
+
const [expandedSongUuid, setExpandedSongUuid] = (0, import_react19.useState)(null);
|
|
3117
|
+
const [expandedArtistUuid, setExpandedArtistUuid] = (0, import_react19.useState)(null);
|
|
3066
3118
|
const artistBaseUrl = artistSearchBaseUrl ?? getBackendBaseUrl;
|
|
3067
3119
|
const songBaseUrl = getBackendBaseUrl;
|
|
3068
|
-
const resolvedRenderArtistLink = renderArtistLink ?? ((artist) => artist.isSpecialPurpose ? artist.name : /* @__PURE__ */ (0,
|
|
3120
|
+
const resolvedRenderArtistLink = renderArtistLink ?? ((artist) => artist.isSpecialPurpose ? artist.name : /* @__PURE__ */ (0, import_jsx_runtime51.jsx)("button", { type: "button", onClick: () => openArtist(artist.uuid), className: "hover:underline", children: artist.name }));
|
|
3069
3121
|
const getGenrePath = (genre) => {
|
|
3070
3122
|
const path = [];
|
|
3071
3123
|
let current = visibleGenrePlaylists.find((playlist) => playlist.criteria?.uuid === genre.uuid);
|
|
@@ -3107,9 +3159,9 @@ function GenreTreeView({
|
|
|
3107
3159
|
selectGenrePlaylist(genrePlaylist2);
|
|
3108
3160
|
}
|
|
3109
3161
|
});
|
|
3110
|
-
const
|
|
3111
|
-
const [uncontrolledCollapsed, setUncontrolledCollapsed] = (0,
|
|
3112
|
-
const [uncontrolledExpanded, setUncontrolledExpanded] = (0,
|
|
3162
|
+
const otherPanel = overlayPanel ?? (selectedGenreUuid !== null ? void 0 : entityPanel);
|
|
3163
|
+
const [uncontrolledCollapsed, setUncontrolledCollapsed] = (0, import_react19.useState)(false);
|
|
3164
|
+
const [uncontrolledExpanded, setUncontrolledExpanded] = (0, import_react19.useState)(false);
|
|
3113
3165
|
const isCollapsed = collapsed ?? uncontrolledCollapsed;
|
|
3114
3166
|
const isExpanded = expanded ?? uncontrolledExpanded;
|
|
3115
3167
|
const changeCollapsed = (next) => {
|
|
@@ -3120,33 +3172,33 @@ function GenreTreeView({
|
|
|
3120
3172
|
setUncontrolledExpanded(next);
|
|
3121
3173
|
onExpandedChange?.(next);
|
|
3122
3174
|
};
|
|
3123
|
-
(0,
|
|
3175
|
+
(0, import_react19.useEffect)(() => {
|
|
3124
3176
|
setUncontrolledCollapsed(false);
|
|
3125
3177
|
}, [selectedGenreUuid, artistUuid, songUuid]);
|
|
3126
|
-
const [isWheelRevealed, setIsWheelRevealed] = (0,
|
|
3178
|
+
const [isWheelRevealed, setIsWheelRevealed] = (0, import_react19.useState)(false);
|
|
3127
3179
|
const usesHandoff = viewMode === "wheel" || viewMode === "pop-core";
|
|
3128
3180
|
const isTreeReady = !isLoading && !isError && (!usesHandoff || isWheelRevealed);
|
|
3129
|
-
const [resolveStyle, setResolveStyle] = (0,
|
|
3130
|
-
const handleNodeStyleResolverChange = (0,
|
|
3181
|
+
const [resolveStyle, setResolveStyle] = (0, import_react19.useState)(null);
|
|
3182
|
+
const handleNodeStyleResolverChange = (0, import_react19.useCallback)(
|
|
3131
3183
|
(resolver) => setResolveStyle(() => resolver),
|
|
3132
3184
|
[]
|
|
3133
3185
|
);
|
|
3134
|
-
const panelRef = (0,
|
|
3135
|
-
const obscuredInset = (0,
|
|
3186
|
+
const panelRef = (0, import_react19.useRef)(null);
|
|
3187
|
+
const obscuredInset = (0, import_ui24.useObscuredInset)(panelRef);
|
|
3136
3188
|
const hostPanel = { obscuredInset, onNodeStyleResolverChange: handleNodeStyleResolverChange };
|
|
3137
3189
|
const nodeMetric = isArtistFiltered || !canSizeByViews ? "songs" : deferredSizeMetric;
|
|
3138
|
-
const treeNodes = (0,
|
|
3190
|
+
const treeNodes = (0, import_react19.useMemo)(() => toTreeNodes(visibleGenrePlaylists, nodeMetric, focusUuids), [visibleGenrePlaylists, nodeMetric, focusUuids]);
|
|
3139
3191
|
const relations = (0, import_genre_tree_view5.useGenreNodeRelations)(
|
|
3140
3192
|
treeNodes,
|
|
3141
3193
|
!overlayPanel && hasSelectedGenreNode ? selectedNodeId : null,
|
|
3142
3194
|
resolveStyle
|
|
3143
3195
|
);
|
|
3144
|
-
const [selectionHistory, setSelectionHistory] = (0,
|
|
3196
|
+
const [selectionHistory, setSelectionHistory] = (0, import_react19.useState)({ current: selectedGenreUuid, previous: null });
|
|
3145
3197
|
if (selectionHistory.current !== selectedGenreUuid) {
|
|
3146
3198
|
setSelectionHistory({ current: selectedGenreUuid, previous: selectionHistory.current ?? selectionHistory.previous });
|
|
3147
3199
|
}
|
|
3148
3200
|
const handlePrevious = selectionHistory.previous ? () => selectGenre(selectionHistory.previous) : void 0;
|
|
3149
|
-
const { showPopup, hidePopup } = (0,
|
|
3201
|
+
const { showPopup, hidePopup } = (0, import_popup5.usePopup)();
|
|
3150
3202
|
const reopenPanel = () => {
|
|
3151
3203
|
setUncontrolledCollapsed(false);
|
|
3152
3204
|
onCollapsedChange?.(false);
|
|
@@ -3167,7 +3219,7 @@ function GenreTreeView({
|
|
|
3167
3219
|
const handleGenreSearchZoomIn = () => {
|
|
3168
3220
|
if (selectedUuid) focus.onFocusGenreChange?.(selectedUuid, "zoom-in");
|
|
3169
3221
|
};
|
|
3170
|
-
const zoomInRef = (0,
|
|
3222
|
+
const zoomInRef = (0, import_react19.useRef)(void 0);
|
|
3171
3223
|
zoomInRef.current = canZoomIn ? handleGenreSearchZoomIn : void 0;
|
|
3172
3224
|
const genrePlaylist = selectedGenrePlaylist;
|
|
3173
3225
|
const criteria = genrePlaylist?.criteria;
|
|
@@ -3186,6 +3238,7 @@ function GenreTreeView({
|
|
|
3186
3238
|
selectGenre(uuid);
|
|
3187
3239
|
},
|
|
3188
3240
|
expanded: isExpanded,
|
|
3241
|
+
treeRelations: relations,
|
|
3189
3242
|
playback,
|
|
3190
3243
|
genrePlaylist: selectedGenrePlaylist,
|
|
3191
3244
|
band: {
|
|
@@ -3196,7 +3249,7 @@ function GenreTreeView({
|
|
|
3196
3249
|
onAddChild: readOnly || !criteria ? void 0 : () => handleGenreCreationAction(criteria),
|
|
3197
3250
|
onRename: readOnly || !criteria ? void 0 : () => handleGenreRenameAction(criteria),
|
|
3198
3251
|
onChangeParent: readOnly || !genrePlaylist || !criteria ? void 0 : () => showPopup(
|
|
3199
|
-
/* @__PURE__ */ (0,
|
|
3252
|
+
/* @__PURE__ */ (0, import_jsx_runtime51.jsx)(
|
|
3200
3253
|
ChangeParentPopup,
|
|
3201
3254
|
{
|
|
3202
3255
|
genrePlaylist: { ...genrePlaylist, criteria },
|
|
@@ -3230,15 +3283,15 @@ function GenreTreeView({
|
|
|
3230
3283
|
const isRotationControlled = controlledAllowWheelRotation !== void 0;
|
|
3231
3284
|
const allowWheelRotation = controlledAllowWheelRotation ?? internalAllowWheelRotation;
|
|
3232
3285
|
let activePanel = null;
|
|
3233
|
-
if (
|
|
3286
|
+
if (otherPanel) {
|
|
3234
3287
|
activePanel = {
|
|
3235
|
-
title:
|
|
3236
|
-
content:
|
|
3237
|
-
aside:
|
|
3238
|
-
expanded:
|
|
3239
|
-
onExpandedChange:
|
|
3240
|
-
onClose:
|
|
3241
|
-
|
|
3288
|
+
title: otherPanel.title,
|
|
3289
|
+
content: otherPanel.content,
|
|
3290
|
+
aside: otherPanel.extraContent,
|
|
3291
|
+
expanded: otherPanel.expanded ?? false,
|
|
3292
|
+
onExpandedChange: otherPanel.onExpandedChange,
|
|
3293
|
+
onClose: otherPanel.onClose,
|
|
3294
|
+
searchName: otherPanel.title
|
|
3242
3295
|
};
|
|
3243
3296
|
} else if (selectedGenreUuid) {
|
|
3244
3297
|
activePanel = {
|
|
@@ -3248,18 +3301,8 @@ function GenreTreeView({
|
|
|
3248
3301
|
expanded: isExpanded,
|
|
3249
3302
|
onExpandedChange: changeExpanded,
|
|
3250
3303
|
onClose: clearSelection,
|
|
3251
|
-
|
|
3252
|
-
headerAccent:
|
|
3253
|
-
};
|
|
3254
|
-
} else if (builtInPanel) {
|
|
3255
|
-
activePanel = {
|
|
3256
|
-
title: builtInPanel.title,
|
|
3257
|
-
content: builtInPanel.content,
|
|
3258
|
-
aside: builtInPanel.extraContent,
|
|
3259
|
-
expanded: builtInPanel.expanded,
|
|
3260
|
-
onExpandedChange: builtInPanel.onExpandedChange,
|
|
3261
|
-
onClose: builtInPanel.onClose,
|
|
3262
|
-
titleInSearch: true
|
|
3304
|
+
searchName: genreContent.name,
|
|
3305
|
+
headerAccent: genreContent.headerAccent
|
|
3263
3306
|
};
|
|
3264
3307
|
}
|
|
3265
3308
|
const isPanelShown = activePanel !== null && (selectedGenreUuid !== null || isTreeReady);
|
|
@@ -3267,19 +3310,19 @@ function GenreTreeView({
|
|
|
3267
3310
|
edge: activePanel.expanded ? { label: "Shrink panel", onClick: () => activePanel.onExpandedChange?.(false) } : isCollapsed ? null : { label: "Hide panel", onClick: () => changeCollapsed(true) },
|
|
3268
3311
|
center: activePanel.expanded ? null : isCollapsed ? { label: "Show panel", onClick: () => changeCollapsed(false) } : activePanel.onExpandedChange ? { label: "Extend panel", onClick: () => activePanel.onExpandedChange?.(true) } : null
|
|
3269
3312
|
} : void 0;
|
|
3270
|
-
const expandButton = placement === "default" && activePanel?.onExpandedChange ? /* @__PURE__ */ (0,
|
|
3271
|
-
|
|
3313
|
+
const expandButton = placement === "default" && activePanel?.onExpandedChange ? /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(
|
|
3314
|
+
import_ui24.IconButton,
|
|
3272
3315
|
{
|
|
3273
3316
|
"aria-label": activePanel.expanded ? "Shrink panel" : "Extend panel",
|
|
3274
3317
|
style: activePanel.headerAccent && { color: "inherit" },
|
|
3275
3318
|
onClick: () => activePanel.onExpandedChange?.(!activePanel.expanded),
|
|
3276
|
-
children: activePanel.expanded ? /* @__PURE__ */ (0,
|
|
3319
|
+
children: activePanel.expanded ? /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(import_lucide_react19.Minimize2, { "aria-hidden": "true", className: "h-4 w-4" }) : /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(import_lucide_react19.Maximize2, { "aria-hidden": "true", className: "h-4 w-4" })
|
|
3277
3320
|
}
|
|
3278
3321
|
) : null;
|
|
3279
3322
|
const renderArtistFilter = () => {
|
|
3280
3323
|
if (isLoading || !filterArtist) return null;
|
|
3281
|
-
return /* @__PURE__ */ (0,
|
|
3282
|
-
/* @__PURE__ */ (0,
|
|
3324
|
+
return /* @__PURE__ */ (0, import_jsx_runtime51.jsxs)("span", { className: "inline-flex items-center overflow-hidden rounded-full bg-[var(--color-neutral-100)] text-body", children: [
|
|
3325
|
+
/* @__PURE__ */ (0, import_jsx_runtime51.jsx)(
|
|
3283
3326
|
"button",
|
|
3284
3327
|
{
|
|
3285
3328
|
type: "button",
|
|
@@ -3291,7 +3334,7 @@ function GenreTreeView({
|
|
|
3291
3334
|
children: filterArtist.name
|
|
3292
3335
|
}
|
|
3293
3336
|
),
|
|
3294
|
-
/* @__PURE__ */ (0,
|
|
3337
|
+
/* @__PURE__ */ (0, import_jsx_runtime51.jsx)(
|
|
3295
3338
|
"button",
|
|
3296
3339
|
{
|
|
3297
3340
|
type: "button",
|
|
@@ -3303,8 +3346,8 @@ function GenreTreeView({
|
|
|
3303
3346
|
)
|
|
3304
3347
|
] });
|
|
3305
3348
|
};
|
|
3306
|
-
const actions = /* @__PURE__ */ (0,
|
|
3307
|
-
!isLoading && !isError && /* @__PURE__ */ (0,
|
|
3349
|
+
const actions = /* @__PURE__ */ (0, import_jsx_runtime51.jsxs)(import_jsx_runtime51.Fragment, { children: [
|
|
3350
|
+
!isLoading && !isError && /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(
|
|
3308
3351
|
GenreTreeSearch,
|
|
3309
3352
|
{
|
|
3310
3353
|
artistBaseUrl,
|
|
@@ -3327,9 +3370,9 @@ function GenreTreeView({
|
|
|
3327
3370
|
if (songUuid) changeSong(null);
|
|
3328
3371
|
selectGenre(uuid);
|
|
3329
3372
|
},
|
|
3330
|
-
selectedName:
|
|
3373
|
+
selectedName: activePanel?.searchName ?? null,
|
|
3331
3374
|
onClear: activePanel?.onClose,
|
|
3332
|
-
showClear: activePanel
|
|
3375
|
+
showClear: activePanel !== null,
|
|
3333
3376
|
clearLabel: "Close panel",
|
|
3334
3377
|
onPrevious: handlePrevious,
|
|
3335
3378
|
onQueryChange: onSearchQueryChange,
|
|
@@ -3337,10 +3380,10 @@ function GenreTreeView({
|
|
|
3337
3380
|
extraGroups: extraSearchGroups
|
|
3338
3381
|
}
|
|
3339
3382
|
),
|
|
3340
|
-
!isLoading && !isError && filterArtist && /* @__PURE__ */ (0,
|
|
3341
|
-
/* @__PURE__ */ (0,
|
|
3342
|
-
!isLoading && !isError && !isControlled && /* @__PURE__ */ (0,
|
|
3343
|
-
|
|
3383
|
+
!isLoading && !isError && filterArtist && /* @__PURE__ */ (0, import_jsx_runtime51.jsx)("div", { className: "hidden w-full justify-center max-md:flex", children: renderArtistFilter() }),
|
|
3384
|
+
/* @__PURE__ */ (0, import_jsx_runtime51.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: [
|
|
3385
|
+
!isLoading && !isError && !isControlled && /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(
|
|
3386
|
+
import_ui24.SegmentedControl,
|
|
3344
3387
|
{
|
|
3345
3388
|
"aria-label": "Tree view mode",
|
|
3346
3389
|
value: viewMode,
|
|
@@ -3353,14 +3396,14 @@ function GenreTreeView({
|
|
|
3353
3396
|
]
|
|
3354
3397
|
}
|
|
3355
3398
|
),
|
|
3356
|
-
!isLoading && !isError && showDisplayOptions && /* @__PURE__ */ (0,
|
|
3399
|
+
!isLoading && !isError && showDisplayOptions && /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(
|
|
3357
3400
|
"div",
|
|
3358
3401
|
{
|
|
3359
3402
|
className: "flex items-center gap-1",
|
|
3360
3403
|
role: "group",
|
|
3361
3404
|
"aria-label": "Tree display options",
|
|
3362
|
-
children: !isRotationControlled && viewMode !== "stacked" && viewMode !== "outline" && /* @__PURE__ */ (0,
|
|
3363
|
-
|
|
3405
|
+
children: !isRotationControlled && viewMode !== "stacked" && viewMode !== "outline" && /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(
|
|
3406
|
+
import_ui24.Button,
|
|
3364
3407
|
{
|
|
3365
3408
|
variant: allowWheelRotation ? "default" : "outline",
|
|
3366
3409
|
size: "sm",
|
|
@@ -3370,52 +3413,53 @@ function GenreTreeView({
|
|
|
3370
3413
|
)
|
|
3371
3414
|
}
|
|
3372
3415
|
),
|
|
3373
|
-
!isLoading && !isError && !readOnly && showAddRoot && /* @__PURE__ */ (0,
|
|
3374
|
-
|
|
3416
|
+
!isLoading && !isError && !readOnly && showAddRoot && /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(
|
|
3417
|
+
import_ui24.IconTextButton,
|
|
3375
3418
|
{
|
|
3376
|
-
icon:
|
|
3419
|
+
icon: import_lucide_react18.Plus,
|
|
3377
3420
|
text: "Add root",
|
|
3378
3421
|
onClick: () => handleGenreCreationAction(null)
|
|
3379
3422
|
}
|
|
3380
3423
|
)
|
|
3381
3424
|
] })
|
|
3382
3425
|
] });
|
|
3383
|
-
return /* @__PURE__ */ (0,
|
|
3426
|
+
return /* @__PURE__ */ (0, import_jsx_runtime51.jsxs)(
|
|
3384
3427
|
"div",
|
|
3385
3428
|
{
|
|
3386
3429
|
"data-left-panel": isPanelShown && !isCollapsed ? void 0 : "hidden",
|
|
3387
3430
|
className: ["genre-tree-view relative flex flex-col h-full", placement === "regions" && REGIONS_CLASS, className2].filter(Boolean).join(" "),
|
|
3388
3431
|
children: [
|
|
3389
|
-
/* @__PURE__ */ (0,
|
|
3432
|
+
/* @__PURE__ */ (0, import_jsx_runtime51.jsx)(
|
|
3390
3433
|
"div",
|
|
3391
3434
|
{
|
|
3392
3435
|
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"}`,
|
|
3393
3436
|
children: actions
|
|
3394
3437
|
}
|
|
3395
3438
|
),
|
|
3396
|
-
!isLoading && !isError && filterArtist && /* @__PURE__ */ (0,
|
|
3439
|
+
!isLoading && !isError && filterArtist && /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(
|
|
3397
3440
|
"div",
|
|
3398
3441
|
{
|
|
3399
3442
|
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"}`,
|
|
3400
3443
|
children: renderArtistFilter()
|
|
3401
3444
|
}
|
|
3402
3445
|
),
|
|
3403
|
-
/* @__PURE__ */ (0,
|
|
3404
|
-
!isLoading && !isError && viewMode === "outline" && floatingControlsLeading && /* @__PURE__ */ (0,
|
|
3405
|
-
isLoading ? /* @__PURE__ */ (0,
|
|
3446
|
+
/* @__PURE__ */ (0, import_jsx_runtime51.jsx)("div", { className: "content-container flex-1 min-h-0 flex flex-row gap-4", children: /* @__PURE__ */ (0, import_jsx_runtime51.jsxs)("div", { className: "tree-view-container relative flex-1 min-w-0 flex flex-col h-full", children: [
|
|
3447
|
+
!isLoading && !isError && viewMode === "outline" && floatingControlsLeading && /* @__PURE__ */ (0, import_jsx_runtime51.jsx)("div", { className: "absolute bottom-3 right-3 z-10", children: floatingControlsLeading }),
|
|
3448
|
+
isLoading ? /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(import_genre_tree_view5.GenreTreeViewSkeleton, { viewMode }) : isError ? /* @__PURE__ */ (0, import_jsx_runtime51.jsxs)("p", { role: "alert", className: "m-auto text-center", children: [
|
|
3406
3449
|
"Couldn't load the genre tree.",
|
|
3407
3450
|
" ",
|
|
3408
|
-
/* @__PURE__ */ (0,
|
|
3451
|
+
/* @__PURE__ */ (0, import_jsx_runtime51.jsx)("button", { type: "button", className: "underline", onClick: refetch, children: "Retry" })
|
|
3409
3452
|
] }) : viewMode === "wheel" ? (
|
|
3410
3453
|
// The info panel's top edge aligns with the tree's; the search bar floats `--layout-panel-inset` below it,
|
|
3411
3454
|
// and the header inset (the bar's height plus that inset) extends the header's fill behind the bar,
|
|
3412
3455
|
// Google Maps style; the 8px bottom padding mirrors the inset above the bar, and the hidden title's height is zeroed.
|
|
3413
3456
|
// The panel's own Zoom in button is hidden: the search bar carries it.
|
|
3414
|
-
/* @__PURE__ */ (0,
|
|
3457
|
+
/* @__PURE__ */ (0, import_jsx_runtime51.jsx)("div", { className: "tree-container search-overlay relative flex-1 w-full min-h-0 ", children: /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(GenreTreeWheelHandoff, { skeleton: /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(import_genre_tree_view5.GenreTreeWheelSkeleton, {}), onRevealedChange: setIsWheelRevealed, children: /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(
|
|
3415
3458
|
GenrePlaylistTreeWheel,
|
|
3416
3459
|
{
|
|
3417
3460
|
scope,
|
|
3418
3461
|
genrePlaylists: visibleGenrePlaylists,
|
|
3462
|
+
focusUuids,
|
|
3419
3463
|
handleGenreCreationAction,
|
|
3420
3464
|
handleGenreRenameAction,
|
|
3421
3465
|
additionalActions,
|
|
@@ -3428,9 +3472,9 @@ function GenreTreeView({
|
|
|
3428
3472
|
allowWheelRotation,
|
|
3429
3473
|
sizeMetric: isArtistFiltered || !canSizeByViews ? "songs" : deferredSizeMetric,
|
|
3430
3474
|
busy,
|
|
3431
|
-
floatingControlsLeading: floatingControlsLeading || canSizeByViews ? /* @__PURE__ */ (0,
|
|
3475
|
+
floatingControlsLeading: floatingControlsLeading || canSizeByViews ? /* @__PURE__ */ (0, import_jsx_runtime51.jsxs)("div", { className: "flex items-center gap-2", children: [
|
|
3432
3476
|
floatingControlsLeading,
|
|
3433
|
-
canSizeByViews && /* @__PURE__ */ (0,
|
|
3477
|
+
canSizeByViews && /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(SizeMetricToggle, { value: sizeMetric, onChange: changeSizeMetric })
|
|
3434
3478
|
] }) : void 0,
|
|
3435
3479
|
defaultViewport,
|
|
3436
3480
|
viewportRestore,
|
|
@@ -3439,11 +3483,12 @@ function GenreTreeView({
|
|
|
3439
3483
|
) }) })
|
|
3440
3484
|
) : viewMode === "pop-core" ? (
|
|
3441
3485
|
// Same as the wheel: the header inset extends its fill behind the floating search bar, Google Maps style.
|
|
3442
|
-
/* @__PURE__ */ (0,
|
|
3486
|
+
/* @__PURE__ */ (0, import_jsx_runtime51.jsx)("div", { className: "tree-container search-overlay relative flex-1 w-full min-h-0 ", children: /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(GenreTreeWheelHandoff, { skeleton: /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(import_genre_tree_view5.GenreTreeWheelSkeleton, {}), onRevealedChange: setIsWheelRevealed, children: /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(
|
|
3443
3487
|
GenrePlaylistTreeWheelRadialPopCore,
|
|
3444
3488
|
{
|
|
3445
3489
|
scope,
|
|
3446
3490
|
genrePlaylists: visibleGenrePlaylists,
|
|
3491
|
+
focusUuids,
|
|
3447
3492
|
handleGenreCreationAction,
|
|
3448
3493
|
handleGenreRenameAction,
|
|
3449
3494
|
additionalActions,
|
|
@@ -3456,9 +3501,9 @@ function GenreTreeView({
|
|
|
3456
3501
|
allowWheelRotation,
|
|
3457
3502
|
sizeMetric: isArtistFiltered || !canSizeByViews ? "songs" : deferredSizeMetric,
|
|
3458
3503
|
busy,
|
|
3459
|
-
floatingControlsLeading: floatingControlsLeading || canSizeByViews ? /* @__PURE__ */ (0,
|
|
3504
|
+
floatingControlsLeading: floatingControlsLeading || canSizeByViews ? /* @__PURE__ */ (0, import_jsx_runtime51.jsxs)("div", { className: "flex items-center gap-2", children: [
|
|
3460
3505
|
floatingControlsLeading,
|
|
3461
|
-
canSizeByViews && /* @__PURE__ */ (0,
|
|
3506
|
+
canSizeByViews && /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(SizeMetricToggle, { value: sizeMetric, onChange: changeSizeMetric })
|
|
3462
3507
|
] }) : void 0,
|
|
3463
3508
|
defaultViewport,
|
|
3464
3509
|
viewportRestore,
|
|
@@ -3466,12 +3511,13 @@ function GenreTreeView({
|
|
|
3466
3511
|
...focus
|
|
3467
3512
|
}
|
|
3468
3513
|
) }) })
|
|
3469
|
-
) : viewMode === "outline" ? /* @__PURE__ */ (0,
|
|
3514
|
+
) : viewMode === "outline" ? /* @__PURE__ */ (0, import_jsx_runtime51.jsx)("div", { className: "tree-container flex-1 min-h-0 w-full overflow-y-auto relative", children: /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(
|
|
3470
3515
|
GenrePlaylistTreeWheelRadialPopCore,
|
|
3471
3516
|
{
|
|
3472
3517
|
outline: true,
|
|
3473
3518
|
scope,
|
|
3474
3519
|
genrePlaylists: visibleGenrePlaylists,
|
|
3520
|
+
focusUuids,
|
|
3475
3521
|
handleGenreCreationAction,
|
|
3476
3522
|
handleGenreRenameAction,
|
|
3477
3523
|
additionalActions,
|
|
@@ -3482,13 +3528,13 @@ function GenreTreeView({
|
|
|
3482
3528
|
selectedNodeId,
|
|
3483
3529
|
readOnly
|
|
3484
3530
|
}
|
|
3485
|
-
) }) : /* @__PURE__ */ (0,
|
|
3531
|
+
) }) : /* @__PURE__ */ (0, import_jsx_runtime51.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(
|
|
3486
3532
|
([uuid, genrePlaylistTreePerRoot]) => {
|
|
3487
|
-
return /* @__PURE__ */ (0,
|
|
3533
|
+
return /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(
|
|
3488
3534
|
"div",
|
|
3489
3535
|
{
|
|
3490
3536
|
className: "tree-per-root-container relative shrink-0 h-[28rem] mt-2 mr-16 p-2 bg-[var(--color-neutral-100)] rounded-lg",
|
|
3491
|
-
children: /* @__PURE__ */ (0,
|
|
3537
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime51.jsx)("div", { className: "graph-container relative z-10 h-full", children: /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(
|
|
3492
3538
|
GenrePlaylistTreePerRoot,
|
|
3493
3539
|
{
|
|
3494
3540
|
scope,
|
|
@@ -3501,6 +3547,7 @@ function GenreTreeView({
|
|
|
3501
3547
|
onNodeHover: handleNodeHover,
|
|
3502
3548
|
...hostPanel,
|
|
3503
3549
|
playback,
|
|
3550
|
+
focusUuids,
|
|
3504
3551
|
selectedNodeId: uuid === selectedGenrePlaylist?.root.uuid ? selectedNodeId : null,
|
|
3505
3552
|
readOnly,
|
|
3506
3553
|
wheelZoom: "modifier",
|
|
@@ -3514,13 +3561,13 @@ function GenreTreeView({
|
|
|
3514
3561
|
);
|
|
3515
3562
|
}
|
|
3516
3563
|
) }),
|
|
3517
|
-
/* @__PURE__ */ (0,
|
|
3518
|
-
|
|
3564
|
+
/* @__PURE__ */ (0, import_jsx_runtime51.jsx)(
|
|
3565
|
+
import_ui24.DetailPanel,
|
|
3519
3566
|
{
|
|
3520
3567
|
ref: panelRef,
|
|
3521
3568
|
side: "left",
|
|
3522
3569
|
title: activePanel?.title ?? "",
|
|
3523
|
-
titleInSearch:
|
|
3570
|
+
titleInSearch: !isLoading && !isError,
|
|
3524
3571
|
headerAccent: activePanel?.headerAccent,
|
|
3525
3572
|
headerActions: expandButton,
|
|
3526
3573
|
onClose: activePanel?.onClose ?? noop,
|
|
@@ -3529,8 +3576,7 @@ function GenreTreeView({
|
|
|
3529
3576
|
onExpandedChange: activePanel?.onExpandedChange,
|
|
3530
3577
|
aside: activePanel?.aside,
|
|
3531
3578
|
edgeTab: detailTab,
|
|
3532
|
-
|
|
3533
|
-
children: activePanel?.aside && !activePanel.expanded ? /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)(import_jsx_runtime46.Fragment, { children: [
|
|
3579
|
+
children: activePanel?.aside && !activePanel.expanded ? /* @__PURE__ */ (0, import_jsx_runtime51.jsxs)(import_jsx_runtime51.Fragment, { children: [
|
|
3534
3580
|
activePanel.content,
|
|
3535
3581
|
activePanel.aside
|
|
3536
3582
|
] }) : activePanel?.content
|
|
@@ -3546,13 +3592,13 @@ function GenreTreeView({
|
|
|
3546
3592
|
var import_genre_tree_view6 = require("@behindthemusictree/genre-tree-view");
|
|
3547
3593
|
|
|
3548
3594
|
// src/genre-tree/track-list-sidebar/TrackListSidebar.tsx
|
|
3549
|
-
var
|
|
3550
|
-
var
|
|
3551
|
-
var
|
|
3552
|
-
var
|
|
3553
|
-
var
|
|
3554
|
-
var
|
|
3555
|
-
var useBrowserLayoutEffect = typeof window === "undefined" ?
|
|
3595
|
+
var import_react20 = require("react");
|
|
3596
|
+
var import_lucide_react20 = require("lucide-react");
|
|
3597
|
+
var import_genre_tree31 = require("@behindthemusictree/app-kit/genre-tree");
|
|
3598
|
+
var import_genre_tree32 = require("@behindthemusictree/app-kit/genre-tree");
|
|
3599
|
+
var import_track_noun4 = require("@behindthemusictree/app-kit/track-noun");
|
|
3600
|
+
var import_jsx_runtime52 = require("react/jsx-runtime");
|
|
3601
|
+
var useBrowserLayoutEffect = typeof window === "undefined" ? import_react20.useEffect : import_react20.useLayoutEffect;
|
|
3556
3602
|
function TrackListSidebar({
|
|
3557
3603
|
className: className2 = "",
|
|
3558
3604
|
renderDuration,
|
|
@@ -3564,18 +3610,18 @@ function TrackListSidebar({
|
|
|
3564
3610
|
renderArtistLink,
|
|
3565
3611
|
renderSongLink
|
|
3566
3612
|
}) {
|
|
3567
|
-
const { trackList, loadMore, autoAdvanceScrollRequest } = (0,
|
|
3568
|
-
const trackNoun = (0,
|
|
3569
|
-
const trackListRef = (0,
|
|
3570
|
-
const previousOriginRef = (0,
|
|
3571
|
-
const handledAutoAdvanceRequestIdRef = (0,
|
|
3572
|
-
const shouldFollowPlaybackRef = (0,
|
|
3573
|
-
const programmaticScrollTopRef = (0,
|
|
3574
|
-
const userScrollIntentRef = (0,
|
|
3575
|
-
const userScrollIntentTimerRef = (0,
|
|
3576
|
-
const loadMoreSentinelRef = (0,
|
|
3613
|
+
const { trackList, loadMore, autoAdvanceScrollRequest } = (0, import_genre_tree31.useTrackList)();
|
|
3614
|
+
const trackNoun = (0, import_track_noun4.useTrackNoun)();
|
|
3615
|
+
const trackListRef = (0, import_react20.useRef)(null);
|
|
3616
|
+
const previousOriginRef = (0, import_react20.useRef)(trackList?.origin ?? null);
|
|
3617
|
+
const handledAutoAdvanceRequestIdRef = (0, import_react20.useRef)(null);
|
|
3618
|
+
const shouldFollowPlaybackRef = (0, import_react20.useRef)(true);
|
|
3619
|
+
const programmaticScrollTopRef = (0, import_react20.useRef)(null);
|
|
3620
|
+
const userScrollIntentRef = (0, import_react20.useRef)(false);
|
|
3621
|
+
const userScrollIntentTimerRef = (0, import_react20.useRef)(null);
|
|
3622
|
+
const loadMoreSentinelRef = (0, import_react20.useRef)(null);
|
|
3577
3623
|
const hasMore = !!trackList && trackList.nextPage !== null;
|
|
3578
|
-
(0,
|
|
3624
|
+
(0, import_react20.useEffect)(() => {
|
|
3579
3625
|
const sentinel = loadMoreSentinelRef.current;
|
|
3580
3626
|
if (!hasMore || !sentinel) return;
|
|
3581
3627
|
const observer = new IntersectionObserver((entries) => {
|
|
@@ -3595,11 +3641,11 @@ function TrackListSidebar({
|
|
|
3595
3641
|
programmaticScrollTopRef.current = null;
|
|
3596
3642
|
if (trackListRef.current) trackListRef.current.scrollTop = 0;
|
|
3597
3643
|
}, [trackList?.origin]);
|
|
3598
|
-
(0,
|
|
3644
|
+
(0, import_react20.useEffect)(() => {
|
|
3599
3645
|
const list = trackListRef.current;
|
|
3600
3646
|
if (!isCollapsed && list?.scrollTop === 0) shouldFollowPlaybackRef.current = true;
|
|
3601
3647
|
}, [isCollapsed]);
|
|
3602
|
-
(0,
|
|
3648
|
+
(0, import_react20.useEffect)(
|
|
3603
3649
|
() => () => {
|
|
3604
3650
|
if (userScrollIntentTimerRef.current !== null) clearTimeout(userScrollIntentTimerRef.current);
|
|
3605
3651
|
},
|
|
@@ -3653,25 +3699,25 @@ function TrackListSidebar({
|
|
|
3653
3699
|
}
|
|
3654
3700
|
};
|
|
3655
3701
|
const positionClasses = layout === "inline" ? "relative w-full flex h-full flex-col" : "fixed right-0 w-[50rem] flex flex-col";
|
|
3656
|
-
return trackList ? /* @__PURE__ */ (0,
|
|
3702
|
+
return trackList ? /* @__PURE__ */ (0, import_jsx_runtime52.jsxs)(
|
|
3657
3703
|
"div",
|
|
3658
3704
|
{
|
|
3659
3705
|
"data-theme": "dark",
|
|
3660
3706
|
className: `track-list-sidebar ${positionClasses} rounded-2xl bg-[var(--color-surface)] pb-1 ${className2}`,
|
|
3661
3707
|
style: layout === "fixed" ? { top: "63.5px", maxHeight: "calc(100vh - 63.5px - 79px)" } : void 0,
|
|
3662
3708
|
children: [
|
|
3663
|
-
/* @__PURE__ */ (0,
|
|
3664
|
-
/* @__PURE__ */ (0,
|
|
3665
|
-
/* @__PURE__ */ (0,
|
|
3666
|
-
/* @__PURE__ */ (0,
|
|
3667
|
-
/* @__PURE__ */ (0,
|
|
3709
|
+
/* @__PURE__ */ (0, import_jsx_runtime52.jsxs)("div", { className: "header flex h-16 items-center px-4 py-2 text-[var(--color-text)]", children: [
|
|
3710
|
+
/* @__PURE__ */ (0, import_jsx_runtime52.jsxs)("div", { className: "min-w-0 flex flex-1 flex-col justify-center", children: [
|
|
3711
|
+
/* @__PURE__ */ (0, import_jsx_runtime52.jsxs)("div", { className: "origin flex text-xl", children: [
|
|
3712
|
+
/* @__PURE__ */ (0, import_jsx_runtime52.jsx)("div", { className: "from h-auto flex flex-col justify-center items-center mr-2", children: "From" }),
|
|
3713
|
+
/* @__PURE__ */ (0, import_jsx_runtime52.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_runtime52.jsx)("div", { className: "name max-w-full truncate", children: trackList.origin.label }) })
|
|
3668
3714
|
] }),
|
|
3669
|
-
/* @__PURE__ */ (0,
|
|
3670
|
-
trackList.origin.type ===
|
|
3715
|
+
/* @__PURE__ */ (0, import_jsx_runtime52.jsxs)("div", { className: "info flex items-center text-body text-[var(--color-text-muted)]", children: [
|
|
3716
|
+
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 `,
|
|
3671
3717
|
`${trackList.total} ${trackList.total > 1 ? trackNoun.plural : trackNoun.singular}`
|
|
3672
3718
|
] })
|
|
3673
3719
|
] }),
|
|
3674
|
-
(isCollapsed && onExpand || !isCollapsed && onMinimize) && /* @__PURE__ */ (0,
|
|
3720
|
+
(isCollapsed && onExpand || !isCollapsed && onMinimize) && /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
|
|
3675
3721
|
"button",
|
|
3676
3722
|
{
|
|
3677
3723
|
type: "button",
|
|
@@ -3680,11 +3726,11 @@ function TrackListSidebar({
|
|
|
3680
3726
|
"aria-expanded": !isCollapsed,
|
|
3681
3727
|
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"}`,
|
|
3682
3728
|
onClick: isCollapsed ? onExpand : onMinimize,
|
|
3683
|
-
children: /* @__PURE__ */ (0,
|
|
3729
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(import_lucide_react20.ListMusic, { "aria-hidden": "true", className: "h-5 w-5" })
|
|
3684
3730
|
}
|
|
3685
3731
|
)
|
|
3686
3732
|
] }),
|
|
3687
|
-
!isCollapsed && /* @__PURE__ */ (0,
|
|
3733
|
+
!isCollapsed && /* @__PURE__ */ (0, import_jsx_runtime52.jsxs)(
|
|
3688
3734
|
"ul",
|
|
3689
3735
|
{
|
|
3690
3736
|
ref: trackListRef,
|
|
@@ -3694,7 +3740,7 @@ function TrackListSidebar({
|
|
|
3694
3740
|
onPointerDown: markUserScrollIntent,
|
|
3695
3741
|
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",
|
|
3696
3742
|
children: [
|
|
3697
|
-
trackList.tracks.map((track, index) => /* @__PURE__ */ (0,
|
|
3743
|
+
trackList.tracks.map((track, index) => /* @__PURE__ */ (0, import_jsx_runtime52.jsx)("li", { "data-track-uuid": track.uuid, children: /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
|
|
3698
3744
|
TrackItem,
|
|
3699
3745
|
{
|
|
3700
3746
|
track,
|
|
@@ -3705,7 +3751,7 @@ function TrackListSidebar({
|
|
|
3705
3751
|
renderSongLink
|
|
3706
3752
|
}
|
|
3707
3753
|
) }, track.uuid)),
|
|
3708
|
-
hasMore && /* @__PURE__ */ (0,
|
|
3754
|
+
hasMore && /* @__PURE__ */ (0, import_jsx_runtime52.jsx)("li", { ref: loadMoreSentinelRef, "aria-hidden": "true", className: "h-px" })
|
|
3709
3755
|
]
|
|
3710
3756
|
}
|
|
3711
3757
|
)
|
|
@@ -3715,17 +3761,17 @@ function TrackListSidebar({
|
|
|
3715
3761
|
}
|
|
3716
3762
|
|
|
3717
3763
|
// src/genre-tree/PlayerPanel.tsx
|
|
3718
|
-
var
|
|
3764
|
+
var import_react21 = require("react");
|
|
3719
3765
|
var import_tailwind_merge = require("tailwind-merge");
|
|
3720
|
-
var
|
|
3721
|
-
var
|
|
3722
|
-
var
|
|
3766
|
+
var import_player14 = require("@behindthemusictree/app-kit/player");
|
|
3767
|
+
var import_genre_tree34 = require("@behindthemusictree/app-kit/genre-tree");
|
|
3768
|
+
var import_ui25 = require("@behindthemusictree/ui");
|
|
3723
3769
|
|
|
3724
3770
|
// src/genre-tree/PlayerControls.tsx
|
|
3725
|
-
var
|
|
3726
|
-
var
|
|
3727
|
-
var
|
|
3728
|
-
var
|
|
3771
|
+
var import_lucide_react21 = require("lucide-react");
|
|
3772
|
+
var import_genre_tree33 = require("@behindthemusictree/app-kit/genre-tree");
|
|
3773
|
+
var import_player13 = require("@behindthemusictree/app-kit/player");
|
|
3774
|
+
var import_jsx_runtime53 = require("react/jsx-runtime");
|
|
3729
3775
|
function PlayerControls() {
|
|
3730
3776
|
const {
|
|
3731
3777
|
duration,
|
|
@@ -3736,23 +3782,23 @@ function PlayerControls() {
|
|
|
3736
3782
|
seekTo,
|
|
3737
3783
|
setVolume,
|
|
3738
3784
|
volume
|
|
3739
|
-
} = (0,
|
|
3740
|
-
const { hasNextTrack, hasPreviousTrack, playNextTrack, playPreviousTrack } = (0,
|
|
3741
|
-
const currentTime = (0,
|
|
3742
|
-
const isBusy = isLoading || playState ===
|
|
3785
|
+
} = (0, import_player13.usePlayer)();
|
|
3786
|
+
const { hasNextTrack, hasPreviousTrack, playNextTrack, playPreviousTrack } = (0, import_genre_tree33.useTrackList)();
|
|
3787
|
+
const currentTime = (0, import_player13.useCurrentTime)();
|
|
3788
|
+
const isBusy = isLoading || playState === import_player13.PlayStates.LOADING;
|
|
3743
3789
|
const isReady = !!playerTrackObject?.isReady && !isBusy && !playerTrackObject.loadError;
|
|
3744
3790
|
const safeDuration = Number.isFinite(duration) && duration > 0 ? duration : 0;
|
|
3745
3791
|
const safeCurrentTime = Number.isFinite(currentTime) ? Math.max(0, Math.min(currentTime, safeDuration)) : 0;
|
|
3746
|
-
const isPlaying = playState ===
|
|
3747
|
-
return /* @__PURE__ */ (0,
|
|
3792
|
+
const isPlaying = playState === import_player13.PlayStates.PLAYING;
|
|
3793
|
+
return /* @__PURE__ */ (0, import_jsx_runtime53.jsxs)(
|
|
3748
3794
|
"section",
|
|
3749
3795
|
{
|
|
3750
3796
|
"aria-label": "Player controls",
|
|
3751
3797
|
className: "player-controls flex shrink-0 flex-col gap-2 border-b border-zinc-800 px-3 py-2 text-zinc-200",
|
|
3752
3798
|
children: [
|
|
3753
|
-
/* @__PURE__ */ (0,
|
|
3754
|
-
/* @__PURE__ */ (0,
|
|
3755
|
-
/* @__PURE__ */ (0,
|
|
3799
|
+
/* @__PURE__ */ (0, import_jsx_runtime53.jsxs)("div", { className: "flex min-w-0 items-center gap-2 text-xs tabular-nums text-zinc-400", children: [
|
|
3800
|
+
/* @__PURE__ */ (0, import_jsx_runtime53.jsx)("span", { "aria-label": "Elapsed time", children: (0, import_genre_tree33.formatTime)(safeCurrentTime) }),
|
|
3801
|
+
/* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
|
|
3756
3802
|
"input",
|
|
3757
3803
|
{
|
|
3758
3804
|
"aria-label": "Seek",
|
|
@@ -3766,11 +3812,11 @@ function PlayerControls() {
|
|
|
3766
3812
|
onChange: (event) => seekTo(Number(event.currentTarget.value))
|
|
3767
3813
|
}
|
|
3768
3814
|
),
|
|
3769
|
-
/* @__PURE__ */ (0,
|
|
3815
|
+
/* @__PURE__ */ (0, import_jsx_runtime53.jsx)("span", { "aria-label": "Duration", children: (0, import_genre_tree33.formatTime)(safeDuration) })
|
|
3770
3816
|
] }),
|
|
3771
|
-
/* @__PURE__ */ (0,
|
|
3772
|
-
/* @__PURE__ */ (0,
|
|
3773
|
-
/* @__PURE__ */ (0,
|
|
3817
|
+
/* @__PURE__ */ (0, import_jsx_runtime53.jsxs)("div", { className: "grid min-h-9 grid-cols-[1fr_auto_1fr] items-center gap-3", children: [
|
|
3818
|
+
/* @__PURE__ */ (0, import_jsx_runtime53.jsxs)("div", { className: "col-start-2 flex items-center justify-center gap-2", children: [
|
|
3819
|
+
/* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
|
|
3774
3820
|
"button",
|
|
3775
3821
|
{
|
|
3776
3822
|
type: "button",
|
|
@@ -3779,10 +3825,10 @@ function PlayerControls() {
|
|
|
3779
3825
|
disabled: !isReady || !hasPreviousTrack,
|
|
3780
3826
|
onClick: playPreviousTrack,
|
|
3781
3827
|
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",
|
|
3782
|
-
children: /* @__PURE__ */ (0,
|
|
3828
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(import_lucide_react21.SkipBack, { "aria-hidden": "true", className: "h-4 w-4" })
|
|
3783
3829
|
}
|
|
3784
3830
|
),
|
|
3785
|
-
/* @__PURE__ */ (0,
|
|
3831
|
+
/* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
|
|
3786
3832
|
"button",
|
|
3787
3833
|
{
|
|
3788
3834
|
type: "button",
|
|
@@ -3791,10 +3837,10 @@ function PlayerControls() {
|
|
|
3791
3837
|
disabled: !isReady,
|
|
3792
3838
|
onClick: handlePlayPauseAction,
|
|
3793
3839
|
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",
|
|
3794
|
-
children: isPlaying ? /* @__PURE__ */ (0,
|
|
3840
|
+
children: isPlaying ? /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(import_lucide_react21.Pause, { "aria-hidden": "true", className: "h-4 w-4", fill: "currentColor" }) : /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(import_lucide_react21.Play, { "aria-hidden": "true", className: "h-4 w-4", fill: "currentColor" })
|
|
3795
3841
|
}
|
|
3796
3842
|
),
|
|
3797
|
-
/* @__PURE__ */ (0,
|
|
3843
|
+
/* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
|
|
3798
3844
|
"button",
|
|
3799
3845
|
{
|
|
3800
3846
|
type: "button",
|
|
@@ -3803,14 +3849,14 @@ function PlayerControls() {
|
|
|
3803
3849
|
disabled: !isReady || !hasNextTrack,
|
|
3804
3850
|
onClick: playNextTrack,
|
|
3805
3851
|
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",
|
|
3806
|
-
children: /* @__PURE__ */ (0,
|
|
3852
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(import_lucide_react21.SkipForward, { "aria-hidden": "true", className: "h-4 w-4" })
|
|
3807
3853
|
}
|
|
3808
3854
|
)
|
|
3809
3855
|
] }),
|
|
3810
|
-
/* @__PURE__ */ (0,
|
|
3811
|
-
volume === 0 ? /* @__PURE__ */ (0,
|
|
3812
|
-
/* @__PURE__ */ (0,
|
|
3813
|
-
/* @__PURE__ */ (0,
|
|
3856
|
+
/* @__PURE__ */ (0, import_jsx_runtime53.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: [
|
|
3857
|
+
volume === 0 ? /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(import_lucide_react21.VolumeX, { "aria-hidden": "true", className: "h-[0.7rem] w-[0.7rem] shrink-0" }) : /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(import_lucide_react21.Volume2, { "aria-hidden": "true", className: "h-[0.7rem] w-[0.7rem] shrink-0" }),
|
|
3858
|
+
/* @__PURE__ */ (0, import_jsx_runtime53.jsx)("span", { className: "sr-only", children: "Volume" }),
|
|
3859
|
+
/* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
|
|
3814
3860
|
"input",
|
|
3815
3861
|
{
|
|
3816
3862
|
"aria-label": "Volume",
|
|
@@ -3832,7 +3878,7 @@ function PlayerControls() {
|
|
|
3832
3878
|
}
|
|
3833
3879
|
|
|
3834
3880
|
// src/genre-tree/PlayerPanel.tsx
|
|
3835
|
-
var
|
|
3881
|
+
var import_jsx_runtime54 = require("react/jsx-runtime");
|
|
3836
3882
|
var PANEL_ID = "player-panel";
|
|
3837
3883
|
var DEFAULT_EXTENDED_WIDTH = "calc(100vw - var(--layout-center-left) - var(--layout-gutter))";
|
|
3838
3884
|
function PlayerPanel({
|
|
@@ -3844,14 +3890,14 @@ function PlayerPanel({
|
|
|
3844
3890
|
renderArtistLink,
|
|
3845
3891
|
renderSongLink
|
|
3846
3892
|
}) {
|
|
3847
|
-
const { playerTrackObject, retryPlayback } = (0,
|
|
3848
|
-
const { toggleTrackListSidebar, isTrackListSidebarVisible } = (0,
|
|
3849
|
-
const [lastLoadedTrackTitle, setLastLoadedTrackTitle] = (0,
|
|
3893
|
+
const { playerTrackObject, retryPlayback } = (0, import_player14.usePlayer)();
|
|
3894
|
+
const { toggleTrackListSidebar, isTrackListSidebarVisible } = (0, import_genre_tree34.useTrackListSidebarVisibility)();
|
|
3895
|
+
const [lastLoadedTrackTitle, setLastLoadedTrackTitle] = (0, import_react21.useState)("");
|
|
3850
3896
|
const loadedTrackTitle = playerTrackObject?.track.title;
|
|
3851
|
-
(0,
|
|
3897
|
+
(0, import_react21.useEffect)(() => {
|
|
3852
3898
|
if (loadedTrackTitle) setLastLoadedTrackTitle(loadedTrackTitle);
|
|
3853
3899
|
}, [loadedTrackTitle]);
|
|
3854
|
-
const [uncontrolledExtended, setUncontrolledExtended] = (0,
|
|
3900
|
+
const [uncontrolledExtended, setUncontrolledExtended] = (0, import_react21.useState)(false);
|
|
3855
3901
|
const isExtendRequested = expanded ?? uncontrolledExtended;
|
|
3856
3902
|
const setIsExtendRequested = (next) => {
|
|
3857
3903
|
setUncontrolledExtended(next);
|
|
@@ -3872,7 +3918,7 @@ function PlayerPanel({
|
|
|
3872
3918
|
onClick: () => setIsExtendRequested(true),
|
|
3873
3919
|
expanded: false
|
|
3874
3920
|
} : null;
|
|
3875
|
-
return /* @__PURE__ */ (0,
|
|
3921
|
+
return /* @__PURE__ */ (0, import_jsx_runtime54.jsxs)(
|
|
3876
3922
|
"div",
|
|
3877
3923
|
{
|
|
3878
3924
|
id: PANEL_ID,
|
|
@@ -3885,8 +3931,8 @@ function PlayerPanel({
|
|
|
3885
3931
|
),
|
|
3886
3932
|
style: isExtended ? { width: extendedWidth } : void 0,
|
|
3887
3933
|
children: [
|
|
3888
|
-
/* @__PURE__ */ (0,
|
|
3889
|
-
|
|
3934
|
+
/* @__PURE__ */ (0, import_jsx_runtime54.jsx)(
|
|
3935
|
+
import_ui25.PanelEdgeTab,
|
|
3890
3936
|
{
|
|
3891
3937
|
side: "right",
|
|
3892
3938
|
edge: tabEdge,
|
|
@@ -3895,7 +3941,7 @@ function PlayerPanel({
|
|
|
3895
3941
|
className: "absolute right-full top-1/2 -translate-y-1/2"
|
|
3896
3942
|
}
|
|
3897
3943
|
),
|
|
3898
|
-
/* @__PURE__ */ (0,
|
|
3944
|
+
/* @__PURE__ */ (0, import_jsx_runtime54.jsxs)(
|
|
3899
3945
|
"div",
|
|
3900
3946
|
{
|
|
3901
3947
|
className: (0, import_tailwind_merge.twMerge)(
|
|
@@ -3903,20 +3949,20 @@ function PlayerPanel({
|
|
|
3903
3949
|
isExtended ? "flex-row" : "flex-col"
|
|
3904
3950
|
),
|
|
3905
3951
|
children: [
|
|
3906
|
-
/* @__PURE__ */ (0,
|
|
3907
|
-
/* @__PURE__ */ (0,
|
|
3908
|
-
/* @__PURE__ */ (0,
|
|
3909
|
-
/* @__PURE__ */ (0,
|
|
3910
|
-
playerTrackObject?.loadError && /* @__PURE__ */ (0,
|
|
3952
|
+
/* @__PURE__ */ (0, import_jsx_runtime54.jsxs)("div", { className: "flex w-[var(--layout-right-w)] shrink-0 flex-col", children: [
|
|
3953
|
+
/* @__PURE__ */ (0, import_jsx_runtime54.jsx)("div", { className: "flex shrink-0 items-center justify-between gap-2 border-b border-zinc-800 p-2", children: /* @__PURE__ */ (0, import_jsx_runtime54.jsx)("span", { className: "min-w-0 truncate text-sm font-semibold", children: loadedTrackTitle || lastLoadedTrackTitle }) }),
|
|
3954
|
+
/* @__PURE__ */ (0, import_jsx_runtime54.jsxs)("div", { className: "relative w-full shrink-0", children: [
|
|
3955
|
+
/* @__PURE__ */ (0, import_jsx_runtime54.jsx)(import_player14.PlayerVideoSurface, { className: "aspect-video w-full bg-black" }),
|
|
3956
|
+
playerTrackObject?.loadError && /* @__PURE__ */ (0, import_jsx_runtime54.jsxs)("span", { className: "absolute bottom-2 left-2 right-2 text-xs text-red-400", children: [
|
|
3911
3957
|
playerTrackObject.loadError,
|
|
3912
|
-
/* @__PURE__ */ (0,
|
|
3958
|
+
/* @__PURE__ */ (0, import_jsx_runtime54.jsx)("button", { type: "button", className: "ml-2 underline", onClick: () => {
|
|
3913
3959
|
void retryPlayback();
|
|
3914
3960
|
}, children: "Retry" })
|
|
3915
3961
|
] })
|
|
3916
3962
|
] }),
|
|
3917
|
-
/* @__PURE__ */ (0,
|
|
3963
|
+
/* @__PURE__ */ (0, import_jsx_runtime54.jsx)(PlayerControls, {})
|
|
3918
3964
|
] }),
|
|
3919
|
-
/* @__PURE__ */ (0,
|
|
3965
|
+
/* @__PURE__ */ (0, import_jsx_runtime54.jsx)(
|
|
3920
3966
|
TrackListSidebar,
|
|
3921
3967
|
{
|
|
3922
3968
|
layout: "inline",
|
|
@@ -3942,33 +3988,33 @@ function PlayerPanel({
|
|
|
3942
3988
|
// src/genre-tree/Rating.tsx
|
|
3943
3989
|
var import_uuid = require("uuid");
|
|
3944
3990
|
var import_ai = require("react-icons/ai");
|
|
3945
|
-
var
|
|
3946
|
-
var
|
|
3991
|
+
var import_genre_tree35 = require("@behindthemusictree/app-kit/genre-tree");
|
|
3992
|
+
var import_jsx_runtime55 = require("react/jsx-runtime");
|
|
3947
3993
|
function Rating({ rating, handleChange }) {
|
|
3948
3994
|
const instanceId = (0, import_uuid.v4)();
|
|
3949
|
-
return /* @__PURE__ */ (0,
|
|
3950
|
-
/* @__PURE__ */ (0,
|
|
3995
|
+
return /* @__PURE__ */ (0, import_jsx_runtime55.jsx)("div", { className: "flex items-center", children: [...Array(6)].map((_, i) => /* @__PURE__ */ (0, import_jsx_runtime55.jsxs)("div", { className: `relative ${i === 0 ? "mr-4" : "mr-1"}`, children: [
|
|
3996
|
+
/* @__PURE__ */ (0, import_jsx_runtime55.jsx)(
|
|
3951
3997
|
"input",
|
|
3952
3998
|
{
|
|
3953
3999
|
id: `star-${instanceId}-${i}`,
|
|
3954
4000
|
className: "w-6 h-6 opacity-0",
|
|
3955
4001
|
type: "radio",
|
|
3956
4002
|
name: "rating",
|
|
3957
|
-
value: i === 0 ?
|
|
4003
|
+
value: i === 0 ? import_genre_tree35.FORM_RATING_NULL_VALUE : i,
|
|
3958
4004
|
checked: rating === (i === 0 ? null : i),
|
|
3959
4005
|
onChange: handleChange
|
|
3960
4006
|
}
|
|
3961
4007
|
),
|
|
3962
|
-
/* @__PURE__ */ (0,
|
|
3963
|
-
/* @__PURE__ */ (0,
|
|
4008
|
+
/* @__PURE__ */ (0, import_jsx_runtime55.jsx)("label", { htmlFor: `star-${instanceId}-${i}`, className: "cursor-pointer", children: i === 0 ? /* @__PURE__ */ (0, import_jsx_runtime55.jsxs)("div", { className: "flex", children: [
|
|
4009
|
+
/* @__PURE__ */ (0, import_jsx_runtime55.jsx)(
|
|
3964
4010
|
import_ai.AiOutlineStar,
|
|
3965
4011
|
{
|
|
3966
|
-
className: `w-7 h-7 absolute top-0 left-0 ${rating ===
|
|
4012
|
+
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)]"}`
|
|
3967
4013
|
}
|
|
3968
4014
|
),
|
|
3969
|
-
/* @__PURE__ */ (0,
|
|
4015
|
+
/* @__PURE__ */ (0, import_jsx_runtime55.jsx)("span", { className: "flex-grow w-8" }),
|
|
3970
4016
|
" "
|
|
3971
|
-
] }) : /* @__PURE__ */ (0,
|
|
4017
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(
|
|
3972
4018
|
import_ai.AiFillStar,
|
|
3973
4019
|
{
|
|
3974
4020
|
className: `w-7 h-7 absolute top-0 left-0 ${(rating ?? -1) >= i ? "text-[var(--color-accent-rating)]" : "text-[var(--color-text-muted)]"}`
|
|
@@ -3978,9 +4024,9 @@ function Rating({ rating, handleChange }) {
|
|
|
3978
4024
|
}
|
|
3979
4025
|
|
|
3980
4026
|
// src/genre-tree/EntityDetailPanel.tsx
|
|
3981
|
-
var
|
|
3982
|
-
var
|
|
3983
|
-
var
|
|
4027
|
+
var import_react22 = require("react");
|
|
4028
|
+
var import_ui26 = require("@behindthemusictree/ui");
|
|
4029
|
+
var import_jsx_runtime56 = require("react/jsx-runtime");
|
|
3984
4030
|
function EntityDetailPanel({
|
|
3985
4031
|
scope,
|
|
3986
4032
|
getBackendBaseUrl,
|
|
@@ -3996,15 +4042,15 @@ function EntityDetailPanel({
|
|
|
3996
4042
|
edgeTab,
|
|
3997
4043
|
...navigation
|
|
3998
4044
|
}) {
|
|
3999
|
-
const [expandedSongUuid, setExpandedSongUuid] = (0,
|
|
4000
|
-
const [expandedArtistUuid, setExpandedArtistUuid] = (0,
|
|
4045
|
+
const [expandedSongUuid, setExpandedSongUuid] = (0, import_react22.useState)(null);
|
|
4046
|
+
const [expandedArtistUuid, setExpandedArtistUuid] = (0, import_react22.useState)(null);
|
|
4001
4047
|
const panel = useEntityPanel({
|
|
4002
4048
|
scope,
|
|
4003
4049
|
getBackendBaseUrl,
|
|
4004
4050
|
getArtistBackendBaseUrl,
|
|
4005
4051
|
getShareUrl,
|
|
4006
|
-
renderArtistLink: renderArtistLink ?? ((artist) => artist.isSpecialPurpose ? artist.name : /* @__PURE__ */ (0,
|
|
4007
|
-
renderSongLink: renderSongLink ?? ((song) => /* @__PURE__ */ (0,
|
|
4052
|
+
renderArtistLink: renderArtistLink ?? ((artist) => artist.isSpecialPurpose ? artist.name : /* @__PURE__ */ (0, import_jsx_runtime56.jsx)("button", { type: "button", onClick: () => onArtistUuidChange(artist.uuid), className: "hover:underline", children: artist.name })),
|
|
4053
|
+
renderSongLink: renderSongLink ?? ((song) => /* @__PURE__ */ (0, import_jsx_runtime56.jsx)("button", { type: "button", onClick: () => onSongUuidChange(song.uuid), className: "hover:underline", children: song.title })),
|
|
4008
4054
|
song: {
|
|
4009
4055
|
uuid: songUuid,
|
|
4010
4056
|
expanded: songUuid !== null && expandedSongUuid === songUuid,
|
|
@@ -4020,8 +4066,8 @@ function EntityDetailPanel({
|
|
|
4020
4066
|
...navigation
|
|
4021
4067
|
});
|
|
4022
4068
|
if (!panel) return null;
|
|
4023
|
-
return /* @__PURE__ */ (0,
|
|
4024
|
-
|
|
4069
|
+
return /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(
|
|
4070
|
+
import_ui26.DetailPanel,
|
|
4025
4071
|
{
|
|
4026
4072
|
side: "left",
|
|
4027
4073
|
title: panel.title,
|
|
@@ -4032,7 +4078,7 @@ function EntityDetailPanel({
|
|
|
4032
4078
|
onExpandedChange: panel.onExpandedChange,
|
|
4033
4079
|
aside: panel.extraContent,
|
|
4034
4080
|
edgeTab,
|
|
4035
|
-
children: panel.extraContent && !panel.expanded ? /* @__PURE__ */ (0,
|
|
4081
|
+
children: panel.extraContent && !panel.expanded ? /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)(import_jsx_runtime56.Fragment, { children: [
|
|
4036
4082
|
panel.content,
|
|
4037
4083
|
panel.extraContent
|
|
4038
4084
|
] }) : panel.content
|