@behindthemusictree/app-kit-ui 30.0.0 → 31.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-2HE2HDFA.js → chunk-AQASG5KT.js} +476 -528
- package/dist/chunk-AQASG5KT.js.map +1 -0
- package/dist/genre-tree/index.cjs +512 -570
- package/dist/genre-tree/index.cjs.map +1 -1
- package/dist/genre-tree/index.d.ts +35 -38
- package/dist/genre-tree/index.js +3 -7
- package/dist/index.cjs +512 -570
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +3 -7
- package/package.json +6 -6
- package/dist/chunk-2HE2HDFA.js.map +0 -1
package/dist/index.cjs
CHANGED
|
@@ -36,7 +36,6 @@ __export(src_exports, {
|
|
|
36
36
|
GenreTreeWheelSkeleton: () => import_genre_tree_view6.GenreTreeWheelSkeleton,
|
|
37
37
|
InternalErrorPopup: () => InternalErrorPopup,
|
|
38
38
|
NetworkErrorPopup: () => NetworkErrorPopup,
|
|
39
|
-
PanelEdgeTab: () => PanelEdgeTab,
|
|
40
39
|
PlayerPanel: () => PlayerPanel,
|
|
41
40
|
PopupButtons: () => PopupButtons,
|
|
42
41
|
PopupTitle: () => PopupTitle,
|
|
@@ -47,8 +46,7 @@ __export(src_exports, {
|
|
|
47
46
|
TrackListSidebar: () => TrackListSidebar,
|
|
48
47
|
TrackPositionPlayPause: () => TrackPositionPlayPause,
|
|
49
48
|
TrackUploadPopup: () => TrackUploadPopup,
|
|
50
|
-
useGenrePlaylistPlayback: () => useGenrePlaylistPlayback
|
|
51
|
-
useLeftDetailPanelLayout: () => useLeftDetailPanelLayout
|
|
49
|
+
useGenrePlaylistPlayback: () => useGenrePlaylistPlayback
|
|
52
50
|
});
|
|
53
51
|
module.exports = __toCommonJS(src_exports);
|
|
54
52
|
|
|
@@ -580,8 +578,9 @@ function AuthCallbackHandler({ renderStatus, ...options }) {
|
|
|
580
578
|
}
|
|
581
579
|
|
|
582
580
|
// src/genre-tree/GenreTreeView.tsx
|
|
583
|
-
var
|
|
581
|
+
var import_react16 = require("react");
|
|
584
582
|
var import_react_query3 = require("@tanstack/react-query");
|
|
583
|
+
var import_lucide_react15 = require("lucide-react");
|
|
585
584
|
var import_lucide_react16 = require("lucide-react");
|
|
586
585
|
var import_ui18 = require("@behindthemusictree/ui");
|
|
587
586
|
var import_genre_tree_view4 = require("@behindthemusictree/genre-tree-view");
|
|
@@ -589,6 +588,32 @@ var import_genre_tree18 = require("@behindthemusictree/app-kit/genre-tree");
|
|
|
589
588
|
var import_genre_tree19 = require("@behindthemusictree/app-kit/genre-tree");
|
|
590
589
|
var import_popup6 = require("@behindthemusictree/app-kit/popup");
|
|
591
590
|
|
|
591
|
+
// src/genre-tree/playlist-tree/size-metric.ts
|
|
592
|
+
var hasViewsCount = (genrePlaylists) => genrePlaylists.every((genrePlaylist) => genrePlaylist.viewsCount !== void 0);
|
|
593
|
+
var genrePlaylistSize = (genrePlaylist, metric) => {
|
|
594
|
+
if (metric === "songs") return genrePlaylist.tracksCount;
|
|
595
|
+
if (genrePlaylist.viewsCount === void 0) {
|
|
596
|
+
throw new Error(`Genre playlist ${genrePlaylist.uuid} has no viewsCount to size by views`);
|
|
597
|
+
}
|
|
598
|
+
return genrePlaylist.viewsCount;
|
|
599
|
+
};
|
|
600
|
+
|
|
601
|
+
// src/genre-tree/playlist-tree/toTreeNodes.ts
|
|
602
|
+
function toTreeNodes(genrePlaylists, sizeMetric) {
|
|
603
|
+
return genrePlaylists.map((genrePlaylist) => ({
|
|
604
|
+
id: genrePlaylist.uuid,
|
|
605
|
+
parentId: genrePlaylist.parent?.uuid ?? null,
|
|
606
|
+
name: genrePlaylist.name,
|
|
607
|
+
itemCount: genrePlaylistSize(genrePlaylist, sizeMetric),
|
|
608
|
+
actionable: Boolean(genrePlaylist.criteria),
|
|
609
|
+
detached: !genrePlaylist.criteria,
|
|
610
|
+
side: genrePlaylist.criteria?.side ?? void 0,
|
|
611
|
+
wikidataId: genrePlaylist.criteria?.wikidataId ?? null,
|
|
612
|
+
umbrella: genrePlaylist.isUmbrella,
|
|
613
|
+
scene: genrePlaylist.scene ?? void 0
|
|
614
|
+
}));
|
|
615
|
+
}
|
|
616
|
+
|
|
592
617
|
// src/genre-tree/playlist-tree/TreePerRoot.tsx
|
|
593
618
|
var import_react4 = require("react");
|
|
594
619
|
var import_genre_tree_view = require("@behindthemusictree/genre-tree-view");
|
|
@@ -625,7 +650,6 @@ function useGenrePlaylistPlayback({
|
|
|
625
650
|
}
|
|
626
651
|
|
|
627
652
|
// src/genre-tree/playlist-tree/TreePerRoot.tsx
|
|
628
|
-
var import_track_noun2 = require("@behindthemusictree/app-kit/track-noun");
|
|
629
653
|
var import_jsx_runtime12 = require("react/jsx-runtime");
|
|
630
654
|
function GenrePlaylistTreePerRoot({
|
|
631
655
|
scope,
|
|
@@ -637,24 +661,19 @@ function GenrePlaylistTreePerRoot({
|
|
|
637
661
|
additionalActions,
|
|
638
662
|
onNodeClick,
|
|
639
663
|
onNodeHover,
|
|
640
|
-
renderInfoPanelBody,
|
|
641
664
|
selectedNodeId,
|
|
642
665
|
onSelectedNodeChange,
|
|
643
|
-
hideInfoPanelClose,
|
|
644
|
-
hideInfoPanelTitle,
|
|
645
666
|
readOnly = false,
|
|
646
|
-
showToolbar,
|
|
647
667
|
wheelZoom,
|
|
648
668
|
defaultViewport,
|
|
649
669
|
viewportRestore,
|
|
650
670
|
onViewportChange,
|
|
651
671
|
playback,
|
|
652
|
-
...
|
|
672
|
+
...hostPanel
|
|
653
673
|
}) {
|
|
654
674
|
const { isPlaying, setIsPlaying } = (0, import_player.usePlayer)();
|
|
655
675
|
const defaultPlayback = useGenrePlaylistPlayback({ scope, genrePlaylists: genrePlaylistTreePerRoot });
|
|
656
676
|
const { playingNodeId, play } = playback ?? defaultPlayback;
|
|
657
|
-
const trackNoun = (0, import_track_noun2.useTrackNoun)();
|
|
658
677
|
const { showPopup } = (0, import_popup2.usePopup)();
|
|
659
678
|
const nodes = (0, import_react4.useMemo)(
|
|
660
679
|
() => genrePlaylistTreePerRoot.map((genrePlaylist) => ({
|
|
@@ -719,7 +738,6 @@ function GenrePlaylistTreePerRoot({
|
|
|
719
738
|
{
|
|
720
739
|
className: className2,
|
|
721
740
|
nodes,
|
|
722
|
-
itemCountLabel: `${(0, import_track_noun2.capitalize)(trackNoun.singular)} count`,
|
|
723
741
|
rootColor: (0, import_genre_tree_view.getGenreTreeColor)(rootUuid),
|
|
724
742
|
playingNodeId,
|
|
725
743
|
playState: isPlaying ? "playing" : "paused",
|
|
@@ -730,18 +748,13 @@ function GenrePlaylistTreePerRoot({
|
|
|
730
748
|
additionalActions,
|
|
731
749
|
onNodeClick,
|
|
732
750
|
onNodeHover,
|
|
733
|
-
renderInfoPanelBody,
|
|
734
751
|
selectedNodeId,
|
|
735
752
|
onSelectedNodeChange,
|
|
736
|
-
hideInfoPanelClose,
|
|
737
|
-
hideInfoPanelTitle,
|
|
738
|
-
showToolbar,
|
|
739
753
|
wheelZoom,
|
|
740
754
|
defaultViewport,
|
|
741
755
|
viewportRestore,
|
|
742
756
|
onViewportChange,
|
|
743
|
-
...
|
|
744
|
-
readOnly
|
|
757
|
+
...hostPanel
|
|
745
758
|
}
|
|
746
759
|
);
|
|
747
760
|
}
|
|
@@ -752,19 +765,6 @@ var import_genre_tree_view2 = require("@behindthemusictree/genre-tree-view");
|
|
|
752
765
|
var import_player2 = require("@behindthemusictree/app-kit/player");
|
|
753
766
|
var import_popup3 = require("@behindthemusictree/app-kit/popup");
|
|
754
767
|
var import_transport3 = require("@behindthemusictree/app-kit/transport");
|
|
755
|
-
|
|
756
|
-
// src/genre-tree/playlist-tree/size-metric.ts
|
|
757
|
-
var hasViewsCount = (genrePlaylists) => genrePlaylists.every((genrePlaylist) => genrePlaylist.viewsCount !== void 0);
|
|
758
|
-
var genrePlaylistSize = (genrePlaylist, metric) => {
|
|
759
|
-
if (metric === "songs") return genrePlaylist.tracksCount;
|
|
760
|
-
if (genrePlaylist.viewsCount === void 0) {
|
|
761
|
-
throw new Error(`Genre playlist ${genrePlaylist.uuid} has no viewsCount to size by views`);
|
|
762
|
-
}
|
|
763
|
-
return genrePlaylist.viewsCount;
|
|
764
|
-
};
|
|
765
|
-
|
|
766
|
-
// src/genre-tree/playlist-tree/TreeWheel.tsx
|
|
767
|
-
var import_track_noun3 = require("@behindthemusictree/app-kit/track-noun");
|
|
768
768
|
var import_jsx_runtime13 = require("react/jsx-runtime");
|
|
769
769
|
function GenrePlaylistTreeWheel({
|
|
770
770
|
scope,
|
|
@@ -775,14 +775,10 @@ function GenrePlaylistTreeWheel({
|
|
|
775
775
|
additionalActions,
|
|
776
776
|
onNodeClick,
|
|
777
777
|
onNodeHover,
|
|
778
|
-
renderInfoPanelBody,
|
|
779
778
|
selectedNodeId,
|
|
780
779
|
onSelectedNodeChange,
|
|
781
|
-
hideInfoPanelClose,
|
|
782
|
-
hideInfoPanelTitle,
|
|
783
780
|
readOnly = false,
|
|
784
781
|
allowWheelRotation,
|
|
785
|
-
showToolbar,
|
|
786
782
|
sizeMetric = "songs",
|
|
787
783
|
floatingControlsLeading,
|
|
788
784
|
busy,
|
|
@@ -790,12 +786,11 @@ function GenrePlaylistTreeWheel({
|
|
|
790
786
|
viewportRestore,
|
|
791
787
|
onViewportChange,
|
|
792
788
|
playback,
|
|
793
|
-
...
|
|
789
|
+
...hostPanel
|
|
794
790
|
}) {
|
|
795
791
|
const { isPlaying, setIsPlaying } = (0, import_player2.usePlayer)();
|
|
796
792
|
const defaultPlayback = useGenrePlaylistPlayback({ scope, genrePlaylists });
|
|
797
793
|
const { playingNodeId, play } = playback ?? defaultPlayback;
|
|
798
|
-
const trackNoun = (0, import_track_noun3.useTrackNoun)();
|
|
799
794
|
const { showPopup } = (0, import_popup3.usePopup)();
|
|
800
795
|
const nodes = (0, import_react5.useMemo)(
|
|
801
796
|
() => genrePlaylists.map((genrePlaylist) => ({
|
|
@@ -859,7 +854,6 @@ function GenrePlaylistTreeWheel({
|
|
|
859
854
|
{
|
|
860
855
|
className: className2,
|
|
861
856
|
nodes,
|
|
862
|
-
itemCountLabel: sizeMetric === "views" ? "Views" : `${(0, import_track_noun3.capitalize)(trackNoun.singular)} count`,
|
|
863
857
|
playingNodeId,
|
|
864
858
|
playState: isPlaying ? "playing" : "paused",
|
|
865
859
|
onPlayPause: handlePlayPause,
|
|
@@ -869,20 +863,15 @@ function GenrePlaylistTreeWheel({
|
|
|
869
863
|
additionalActions,
|
|
870
864
|
onNodeClick,
|
|
871
865
|
onNodeHover,
|
|
872
|
-
renderInfoPanelBody,
|
|
873
866
|
selectedNodeId,
|
|
874
867
|
onSelectedNodeChange,
|
|
875
|
-
hideInfoPanelClose,
|
|
876
|
-
hideInfoPanelTitle,
|
|
877
868
|
allowWheelRotation,
|
|
878
|
-
showToolbar,
|
|
879
869
|
floatingControlsLeading,
|
|
880
870
|
busy,
|
|
881
871
|
defaultViewport,
|
|
882
872
|
viewportRestore,
|
|
883
873
|
onViewportChange,
|
|
884
|
-
...
|
|
885
|
-
readOnly
|
|
874
|
+
...hostPanel
|
|
886
875
|
}
|
|
887
876
|
);
|
|
888
877
|
}
|
|
@@ -891,7 +880,6 @@ function GenrePlaylistTreeWheel({
|
|
|
891
880
|
var import_react6 = require("react");
|
|
892
881
|
var import_genre_tree_view3 = require("@behindthemusictree/genre-tree-view");
|
|
893
882
|
var import_player3 = require("@behindthemusictree/app-kit/player");
|
|
894
|
-
var import_track_noun4 = require("@behindthemusictree/app-kit/track-noun");
|
|
895
883
|
var import_jsx_runtime14 = require("react/jsx-runtime");
|
|
896
884
|
function GenrePlaylistTreeWheelRadialPopCore(props) {
|
|
897
885
|
const {
|
|
@@ -903,14 +891,10 @@ function GenrePlaylistTreeWheelRadialPopCore(props) {
|
|
|
903
891
|
additionalActions,
|
|
904
892
|
onNodeClick,
|
|
905
893
|
onNodeHover,
|
|
906
|
-
renderInfoPanelBody,
|
|
907
894
|
selectedNodeId,
|
|
908
895
|
onSelectedNodeChange,
|
|
909
|
-
hideInfoPanelClose,
|
|
910
|
-
hideInfoPanelTitle,
|
|
911
896
|
readOnly = false,
|
|
912
897
|
allowWheelRotation,
|
|
913
|
-
showToolbar,
|
|
914
898
|
sizeMetric = "songs",
|
|
915
899
|
floatingControlsLeading,
|
|
916
900
|
busy,
|
|
@@ -921,33 +905,14 @@ function GenrePlaylistTreeWheelRadialPopCore(props) {
|
|
|
921
905
|
playback
|
|
922
906
|
} = props;
|
|
923
907
|
const focus = props;
|
|
924
|
-
const
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
onExpandedChange: props.onExpandedChange,
|
|
928
|
-
collapsed: props.collapsed,
|
|
929
|
-
hideExpandButton: props.hideExpandButton,
|
|
930
|
-
overlayPanel: props.overlayPanel
|
|
908
|
+
const hostPanel = {
|
|
909
|
+
obscuredInset: props.obscuredInset,
|
|
910
|
+
onNodeStyleResolverChange: props.onNodeStyleResolverChange
|
|
931
911
|
};
|
|
932
912
|
const { isPlaying, setIsPlaying } = (0, import_player3.usePlayer)();
|
|
933
913
|
const defaultPlayback = useGenrePlaylistPlayback({ scope, genrePlaylists });
|
|
934
914
|
const { playingNodeId, play } = playback ?? defaultPlayback;
|
|
935
|
-
const
|
|
936
|
-
const nodes = (0, import_react6.useMemo)(
|
|
937
|
-
() => genrePlaylists.map((genrePlaylist) => ({
|
|
938
|
-
id: genrePlaylist.uuid,
|
|
939
|
-
parentId: genrePlaylist.parent?.uuid ?? null,
|
|
940
|
-
name: genrePlaylist.name,
|
|
941
|
-
itemCount: genrePlaylistSize(genrePlaylist, sizeMetric),
|
|
942
|
-
actionable: Boolean(genrePlaylist.criteria),
|
|
943
|
-
detached: !genrePlaylist.criteria,
|
|
944
|
-
side: genrePlaylist.criteria?.side ?? void 0,
|
|
945
|
-
wikidataId: genrePlaylist.criteria?.wikidataId ?? null,
|
|
946
|
-
umbrella: genrePlaylist.isUmbrella,
|
|
947
|
-
scene: genrePlaylist.scene ?? void 0
|
|
948
|
-
})),
|
|
949
|
-
[genrePlaylists, sizeMetric]
|
|
950
|
-
);
|
|
915
|
+
const nodes = (0, import_react6.useMemo)(() => toTreeNodes(genrePlaylists, sizeMetric), [genrePlaylists, sizeMetric]);
|
|
951
916
|
const handlePlayPause = (0, import_react6.useCallback)(
|
|
952
917
|
(nodeId) => {
|
|
953
918
|
const genrePlaylist = genrePlaylists.find((g) => g.uuid === nodeId);
|
|
@@ -988,7 +953,6 @@ function GenrePlaylistTreeWheelRadialPopCore(props) {
|
|
|
988
953
|
const treeProps = {
|
|
989
954
|
className: className2,
|
|
990
955
|
nodes,
|
|
991
|
-
itemCountLabel: sizeMetric === "views" ? "Views" : `${(0, import_track_noun4.capitalize)(trackNoun.singular)} count`,
|
|
992
956
|
playingNodeId,
|
|
993
957
|
playState: isPlaying ? "playing" : "paused",
|
|
994
958
|
onPlayPause: handlePlayPause,
|
|
@@ -998,14 +962,9 @@ function GenrePlaylistTreeWheelRadialPopCore(props) {
|
|
|
998
962
|
additionalActions,
|
|
999
963
|
onNodeClick,
|
|
1000
964
|
onNodeHover,
|
|
1001
|
-
renderInfoPanelBody,
|
|
1002
965
|
selectedNodeId,
|
|
1003
966
|
onSelectedNodeChange,
|
|
1004
|
-
|
|
1005
|
-
hideInfoPanelTitle,
|
|
1006
|
-
showToolbar,
|
|
1007
|
-
...infoPanelCuration,
|
|
1008
|
-
readOnly
|
|
967
|
+
...hostPanel
|
|
1009
968
|
};
|
|
1010
969
|
return outline ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_genre_tree_view3.GenreTreeOutline, { ...treeProps }) : /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
1011
970
|
import_genre_tree_view3.GenreTreeWheelRadialPopCore,
|
|
@@ -1125,7 +1084,7 @@ function GenreSearch({
|
|
|
1125
1084
|
type: "button",
|
|
1126
1085
|
"aria-label": "Previous",
|
|
1127
1086
|
title: "Previous",
|
|
1128
|
-
className: "genre-search-previous absolute left-2 top-1/2 z-10
|
|
1087
|
+
className: "genre-search-previous absolute left-2 top-1/2 z-10 flex items-center justify-center p-1.5 [@media(pointer:coarse)]:min-h-[var(--layout-touch-target)] [@media(pointer:coarse)]:min-w-[var(--layout-touch-target)] text-[var(--color-text-muted)] rounded-full -translate-y-1/2 hover:bg-[var(--color-surface-muted)] hover:text-[var(--color-text)]",
|
|
1129
1088
|
onClick: onPrevious,
|
|
1130
1089
|
children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_lucide_react7.ArrowLeft, { "aria-hidden": "true", className: "w-4 h-4" })
|
|
1131
1090
|
}
|
|
@@ -1147,7 +1106,7 @@ function GenreSearch({
|
|
|
1147
1106
|
onPick: handlePick,
|
|
1148
1107
|
status,
|
|
1149
1108
|
loading: loading ? "Searching\u2026" : void 0,
|
|
1150
|
-
inputClassName:
|
|
1109
|
+
inputClassName: `h-[var(--layout-search-h,3rem)] ${onPrevious ? "pl-11" : "pl-6"} pr-20 text-base transition-[padding] duration-200 ease-out motion-reduce:transition-none bg-[var(--color-surface)] border-[var(--color-border)] rounded-full shadow-md`,
|
|
1151
1110
|
className: "genre-search-results z-40 rounded-xl shadow-md",
|
|
1152
1111
|
listClassName: "max-h-[min(20rem,50dvh)]",
|
|
1153
1112
|
optionClassName: "[@media(pointer:coarse)]:min-h-[var(--layout-touch-target)]"
|
|
@@ -1584,7 +1543,7 @@ function MusicBrainzRecordingLink({
|
|
|
1584
1543
|
|
|
1585
1544
|
// src/genre-tree/GenrePlaylistTracks.tsx
|
|
1586
1545
|
var import_genre_tree8 = require("@behindthemusictree/app-kit/genre-tree");
|
|
1587
|
-
var
|
|
1546
|
+
var import_track_noun2 = require("@behindthemusictree/app-kit/track-noun");
|
|
1588
1547
|
var import_jsx_runtime24 = require("react/jsx-runtime");
|
|
1589
1548
|
var CATALOGUE_PAGE_SIZE = 100;
|
|
1590
1549
|
var SongPageSchema = (0, import_transport5.PaginatedResponseSchema)(import_genre_tree6.SongDetailedSchema).extend({
|
|
@@ -1618,7 +1577,7 @@ function GenrePlaylistTracks({
|
|
|
1618
1577
|
const { session, sessionRestored } = (0, import_auth2.useSession)();
|
|
1619
1578
|
const { playerTrackObject, playState, handlePlayPauseAction } = (0, import_player4.usePlayer)();
|
|
1620
1579
|
const { showPopup } = (0, import_popup5.usePopup)();
|
|
1621
|
-
const trackNoun = (0,
|
|
1580
|
+
const trackNoun = (0, import_track_noun2.useTrackNoun)();
|
|
1622
1581
|
const { uuid } = genrePlaylist;
|
|
1623
1582
|
const { fetch } = (0, import_transport4.useFetchWrapper)(getBackendBaseUrl);
|
|
1624
1583
|
const { data, isPending, isError, refetch, hasNextPage, isFetchingNextPage, fetchNextPage } = (0, import_react_query.useInfiniteQuery)({
|
|
@@ -1663,7 +1622,7 @@ function GenrePlaylistTracks({
|
|
|
1663
1622
|
};
|
|
1664
1623
|
return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { className: "gtv-info-panel-children", children: [
|
|
1665
1624
|
/* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("span", { className: "gtv-info-panel-children-title", children: [
|
|
1666
|
-
(0,
|
|
1625
|
+
(0, import_track_noun2.capitalize)(trackNoun.plural),
|
|
1667
1626
|
total !== void 0 && ` (${total})`
|
|
1668
1627
|
] }),
|
|
1669
1628
|
renderTracksToolbar?.(),
|
|
@@ -1734,7 +1693,7 @@ function GenrePlaylistTracks({
|
|
|
1734
1693
|
}
|
|
1735
1694
|
|
|
1736
1695
|
// src/genre-tree/GenreDetailExtras.tsx
|
|
1737
|
-
var
|
|
1696
|
+
var import_track_noun3 = require("@behindthemusictree/app-kit/track-noun");
|
|
1738
1697
|
var import_si2 = require("react-icons/si");
|
|
1739
1698
|
var import_jsx_runtime25 = require("react/jsx-runtime");
|
|
1740
1699
|
function GenreDetailExtras({
|
|
@@ -1752,7 +1711,7 @@ function GenreDetailExtras({
|
|
|
1752
1711
|
family,
|
|
1753
1712
|
...trackSlots
|
|
1754
1713
|
}) {
|
|
1755
|
-
const trackNoun = (0,
|
|
1714
|
+
const trackNoun = (0, import_track_noun3.useTrackNoun)();
|
|
1756
1715
|
const { data: overview, isPending } = (0, import_genre_tree9.useFetchGenreOverview)(
|
|
1757
1716
|
genreUuid,
|
|
1758
1717
|
scope,
|
|
@@ -1886,66 +1845,10 @@ function GenreInfoPanelBody({
|
|
|
1886
1845
|
] });
|
|
1887
1846
|
}
|
|
1888
1847
|
|
|
1889
|
-
// src/genre-tree/PanelEdgeTab.tsx
|
|
1890
|
-
var import_lucide_react12 = require("lucide-react");
|
|
1891
|
-
var import_tailwind_merge = require("tailwind-merge");
|
|
1892
|
-
var import_jsx_runtime27 = require("react/jsx-runtime");
|
|
1893
|
-
var buttonClassName = "flex h-12 w-full items-center justify-center p-0 text-[var(--color-text-muted)] hover:bg-[var(--color-surface-muted)] hover:text-[var(--color-text)] focus-visible:outline focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-[var(--color-primary)]";
|
|
1894
|
-
function PanelEdgeTab({ side, edge, center, controls, className: className2 }) {
|
|
1895
|
-
if (!edge && !center) return null;
|
|
1896
|
-
const isLeft = side === "left";
|
|
1897
|
-
const EdgeIcon = isLeft ? import_lucide_react12.ChevronLeft : import_lucide_react12.ChevronRight;
|
|
1898
|
-
const CenterIcon = isLeft ? import_lucide_react12.ChevronRight : import_lucide_react12.ChevronLeft;
|
|
1899
|
-
const renderButton = (action, icon) => /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
|
|
1900
|
-
"button",
|
|
1901
|
-
{
|
|
1902
|
-
type: "button",
|
|
1903
|
-
"aria-label": action.label,
|
|
1904
|
-
title: action.label,
|
|
1905
|
-
"aria-controls": controls,
|
|
1906
|
-
"aria-expanded": action.expanded,
|
|
1907
|
-
className: buttonClassName,
|
|
1908
|
-
onClick: action.onClick,
|
|
1909
|
-
children: icon
|
|
1910
|
-
}
|
|
1911
|
-
);
|
|
1912
|
-
const edgeButton = edge && renderButton(edge, /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(EdgeIcon, { "aria-hidden": "true", className: "h-5 w-5" }));
|
|
1913
|
-
const centerButton = center && renderButton(center, /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(CenterIcon, { "aria-hidden": "true", className: "h-5 w-5" }));
|
|
1914
|
-
const buttons = isLeft ? [edgeButton, centerButton] : [centerButton, edgeButton];
|
|
1915
|
-
return /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(
|
|
1916
|
-
"div",
|
|
1917
|
-
{
|
|
1918
|
-
className: (0, import_tailwind_merge.twMerge)(
|
|
1919
|
-
"panel-edge-tab flex w-[var(--layout-edge-tab-w)] flex-col overflow-hidden bg-[var(--color-surface)] shadow-[0_1px_2px_rgba(60,64,67,0.3),0_2px_6px_2px_rgba(60,64,67,0.15)] [clip-path:inset(-0.5rem_-0.5rem_-0.5rem_0)]",
|
|
1920
|
-
isLeft ? "rounded-r-lg" : "rounded-l-lg [clip-path:inset(-0.5rem_0_-0.5rem_-0.5rem)]",
|
|
1921
|
-
className2
|
|
1922
|
-
),
|
|
1923
|
-
children: [
|
|
1924
|
-
buttons[0],
|
|
1925
|
-
buttons[0] && buttons[1] && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { role: "presentation", className: "h-px shrink-0 bg-[var(--color-border)]" }),
|
|
1926
|
-
buttons[1]
|
|
1927
|
-
]
|
|
1928
|
-
}
|
|
1929
|
-
);
|
|
1930
|
-
}
|
|
1931
|
-
|
|
1932
|
-
// src/genre-tree/useLeftDetailPanelLayout.ts
|
|
1933
|
-
var import_react13 = require("react");
|
|
1934
|
-
function useLeftDetailPanelLayout(isPanelShown, enabled = true) {
|
|
1935
|
-
(0, import_react13.useEffect)(() => {
|
|
1936
|
-
if (!enabled || isPanelShown) return void 0;
|
|
1937
|
-
const root = document.documentElement;
|
|
1938
|
-
root.style.setProperty("--layout-left-w", "0px");
|
|
1939
|
-
return () => {
|
|
1940
|
-
root.style.removeProperty("--layout-left-w");
|
|
1941
|
-
};
|
|
1942
|
-
}, [enabled, isPanelShown]);
|
|
1943
|
-
}
|
|
1944
|
-
|
|
1945
1848
|
// src/genre-tree/ChangeParentPopup.tsx
|
|
1946
|
-
var
|
|
1849
|
+
var import_react13 = require("react");
|
|
1947
1850
|
var import_genre_tree10 = require("@behindthemusictree/app-kit/genre-tree");
|
|
1948
|
-
var
|
|
1851
|
+
var import_jsx_runtime27 = require("react/jsx-runtime");
|
|
1949
1852
|
function ChangeParentPopup({
|
|
1950
1853
|
genrePlaylist,
|
|
1951
1854
|
genrePlaylists,
|
|
@@ -1955,7 +1858,7 @@ function ChangeParentPopup({
|
|
|
1955
1858
|
onParentChanged
|
|
1956
1859
|
}) {
|
|
1957
1860
|
const { mutate, isPending, formErrors } = (0, import_genre_tree10.useUpdateGenre)(scope, getBackendBaseUrl);
|
|
1958
|
-
const candidates = (0,
|
|
1861
|
+
const candidates = (0, import_react13.useMemo)(
|
|
1959
1862
|
() => (0, import_genre_tree10.getReparentCandidates)(genrePlaylists, genrePlaylist.uuid),
|
|
1960
1863
|
[genrePlaylists, genrePlaylist.uuid]
|
|
1961
1864
|
);
|
|
@@ -1973,19 +1876,19 @@ function ChangeParentPopup({
|
|
|
1973
1876
|
}
|
|
1974
1877
|
);
|
|
1975
1878
|
};
|
|
1976
|
-
(0,
|
|
1879
|
+
(0, import_react13.useEffect)(() => {
|
|
1977
1880
|
const handleKeyDown = (event) => {
|
|
1978
1881
|
if (event.key === "Escape") onClose();
|
|
1979
1882
|
};
|
|
1980
1883
|
window.addEventListener("keydown", handleKeyDown);
|
|
1981
1884
|
return () => window.removeEventListener("keydown", handleKeyDown);
|
|
1982
1885
|
}, [onClose]);
|
|
1983
|
-
return /* @__PURE__ */ (0,
|
|
1984
|
-
/* @__PURE__ */ (0,
|
|
1886
|
+
return /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(BasePopup_default, { title: `Change parent of ${genrePlaylist.name}`, onClose, showCancelButton: true, fitContent: true, children: [
|
|
1887
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("p", { className: "mb-3 text-sm text-[var(--color-text-muted)]", children: [
|
|
1985
1888
|
"Current parent: ",
|
|
1986
1889
|
genrePlaylist.parent?.name ?? "none"
|
|
1987
1890
|
] }),
|
|
1988
|
-
/* @__PURE__ */ (0,
|
|
1891
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { "aria-busy": isPending, className: isPending ? "pointer-events-none opacity-60" : void 0, children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
|
|
1989
1892
|
GenreSearch,
|
|
1990
1893
|
{
|
|
1991
1894
|
genrePlaylists: candidates,
|
|
@@ -1993,7 +1896,7 @@ function ChangeParentPopup({
|
|
|
1993
1896
|
placeholder: "Search a new parent\u2026"
|
|
1994
1897
|
}
|
|
1995
1898
|
) }),
|
|
1996
|
-
formErrors.length > 0 && /* @__PURE__ */ (0,
|
|
1899
|
+
formErrors.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("p", { role: "alert", className: "mt-3 text-sm text-[var(--color-red-500)]", children: formErrors.map(({ message }) => message).join(" ") })
|
|
1997
1900
|
] });
|
|
1998
1901
|
}
|
|
1999
1902
|
|
|
@@ -2005,12 +1908,12 @@ var import_genre_tree15 = require("@behindthemusictree/app-kit/genre-tree");
|
|
|
2005
1908
|
var import_ui10 = require("@behindthemusictree/ui");
|
|
2006
1909
|
|
|
2007
1910
|
// src/genre-tree/artist/ArtistLinks.tsx
|
|
2008
|
-
var
|
|
1911
|
+
var import_lucide_react12 = require("lucide-react");
|
|
2009
1912
|
var import_si3 = require("react-icons/si");
|
|
2010
1913
|
var import_ui9 = require("@behindthemusictree/ui");
|
|
2011
|
-
var
|
|
1914
|
+
var import_jsx_runtime28 = require("react/jsx-runtime");
|
|
2012
1915
|
var LINK_KINDS = {
|
|
2013
|
-
official: { label: "Official website", Icon:
|
|
1916
|
+
official: { label: "Official website", Icon: import_lucide_react12.Globe },
|
|
2014
1917
|
wikipedia: { label: "Wikipedia", Icon: import_si3.SiWikipedia },
|
|
2015
1918
|
wikidata: { label: "Wikidata", Icon: import_si3.SiWikidata },
|
|
2016
1919
|
spotify: { label: "Spotify", Icon: import_si3.SiSpotify },
|
|
@@ -2018,7 +1921,7 @@ var LINK_KINDS = {
|
|
|
2018
1921
|
bandcamp: { label: "Bandcamp", Icon: import_si3.SiBandcamp },
|
|
2019
1922
|
soundcloud: { label: "SoundCloud", Icon: import_si3.SiSoundcloud },
|
|
2020
1923
|
discogs: { label: "Discogs", Icon: import_si3.SiDiscogs },
|
|
2021
|
-
social: { label: "Social", Icon:
|
|
1924
|
+
social: { label: "Social", Icon: import_lucide_react12.Share2 }
|
|
2022
1925
|
};
|
|
2023
1926
|
function socialLabel(url) {
|
|
2024
1927
|
try {
|
|
@@ -2045,7 +1948,7 @@ function artistLinks(artist) {
|
|
|
2045
1948
|
return links;
|
|
2046
1949
|
}
|
|
2047
1950
|
function ArtistLinks({ links }) {
|
|
2048
|
-
return /* @__PURE__ */ (0,
|
|
1951
|
+
return /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("ul", { className: "flex flex-wrap gap-1.5", children: links.map(({ key, url, Icon, label }) => /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_ui9.Chip, { href: url, icon: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(Icon, { className: "h-3.5 w-3.5 shrink-0", "aria-hidden": "true" }), children: label }) }, key)) });
|
|
2049
1952
|
}
|
|
2050
1953
|
|
|
2051
1954
|
// src/genre-tree/artist/formatYears.ts
|
|
@@ -2056,7 +1959,7 @@ function formatYears(beginYear, endYear, ended) {
|
|
|
2056
1959
|
}
|
|
2057
1960
|
|
|
2058
1961
|
// src/genre-tree/artist/ArtistHeader.tsx
|
|
2059
|
-
var
|
|
1962
|
+
var import_jsx_runtime29 = require("react/jsx-runtime");
|
|
2060
1963
|
var countryNames = new Intl.DisplayNames(["en"], { type: "region" });
|
|
2061
1964
|
function ArtistHeader({ artist }) {
|
|
2062
1965
|
const fields = [];
|
|
@@ -2066,35 +1969,35 @@ function ArtistHeader({ artist }) {
|
|
|
2066
1969
|
const years = formatYears(artist.beginYear, artist.endYear, artist.ended);
|
|
2067
1970
|
if (years) fields.push({ label: "Active", value: years });
|
|
2068
1971
|
const links = artistLinks(artist);
|
|
2069
|
-
if (links.length > 0) fields.push({ label: "Links", value: /* @__PURE__ */ (0,
|
|
1972
|
+
if (links.length > 0) fields.push({ label: "Links", value: /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(ArtistLinks, { links }) });
|
|
2070
1973
|
if (fields.length === 0) return null;
|
|
2071
|
-
return /* @__PURE__ */ (0,
|
|
1974
|
+
return /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(import_ui10.FieldList, { items: fields });
|
|
2072
1975
|
}
|
|
2073
1976
|
|
|
2074
1977
|
// src/genre-tree/artist/ArtistPhoto.tsx
|
|
2075
|
-
var
|
|
1978
|
+
var import_jsx_runtime30 = require("react/jsx-runtime");
|
|
2076
1979
|
function ExternalLink({ href, children }) {
|
|
2077
|
-
return /* @__PURE__ */ (0,
|
|
1980
|
+
return /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("a", { href, target: "_blank", rel: "noopener noreferrer", className: "underline-offset-2 hover:underline", children });
|
|
2078
1981
|
}
|
|
2079
1982
|
function ArtistPhoto({ image, name }) {
|
|
2080
|
-
return /* @__PURE__ */ (0,
|
|
2081
|
-
/* @__PURE__ */ (0,
|
|
2082
|
-
/* @__PURE__ */ (0,
|
|
1983
|
+
return /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("figure", { className: "flex flex-col gap-1.5 px-6 py-2.5", children: [
|
|
1984
|
+
/* @__PURE__ */ (0, import_jsx_runtime30.jsx)("img", { src: image.url, alt: name, className: "h-64 w-full object-contain bg-[var(--color-surface-muted)] rounded" }),
|
|
1985
|
+
/* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("figcaption", { className: "text-xs text-[var(--color-text-muted)]", children: [
|
|
2083
1986
|
"Photo: ",
|
|
2084
|
-
/* @__PURE__ */ (0,
|
|
1987
|
+
/* @__PURE__ */ (0, import_jsx_runtime30.jsx)(ExternalLink, { href: image.pageUrl, children: image.author ?? "Wikimedia Commons" }),
|
|
2085
1988
|
",",
|
|
2086
1989
|
" ",
|
|
2087
|
-
image.licenseUrl ? /* @__PURE__ */ (0,
|
|
1990
|
+
image.licenseUrl ? /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(ExternalLink, { href: image.licenseUrl, children: image.license }) : image.license
|
|
2088
1991
|
] })
|
|
2089
1992
|
] });
|
|
2090
1993
|
}
|
|
2091
1994
|
|
|
2092
1995
|
// src/genre-tree/artist/ArtistMembers.tsx
|
|
2093
1996
|
var import_ui11 = require("@behindthemusictree/ui");
|
|
2094
|
-
var
|
|
1997
|
+
var import_jsx_runtime31 = require("react/jsx-runtime");
|
|
2095
1998
|
function MembershipList({ title, memberships, renderArtistLink }) {
|
|
2096
1999
|
if (memberships.length === 0) return null;
|
|
2097
|
-
return /* @__PURE__ */ (0,
|
|
2000
|
+
return /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(import_ui11.PanelGroup, { title, children: /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("ul", { children: memberships.map((membership, index) => {
|
|
2098
2001
|
const details = [
|
|
2099
2002
|
formatYears(membership.beginYear, membership.endYear, membership.ended),
|
|
2100
2003
|
...membership.roles
|
|
@@ -2102,9 +2005,9 @@ function MembershipList({ title, memberships, renderArtistLink }) {
|
|
|
2102
2005
|
const detailsText = details.filter(Boolean).join(" \xB7 ");
|
|
2103
2006
|
return (
|
|
2104
2007
|
// A member can have several periods in the same group.
|
|
2105
|
-
/* @__PURE__ */ (0,
|
|
2106
|
-
/* @__PURE__ */ (0,
|
|
2107
|
-
detailsText && /* @__PURE__ */ (0,
|
|
2008
|
+
/* @__PURE__ */ (0, import_jsx_runtime31.jsxs)("li", { className: "truncate py-0.5", title: detailsText || void 0, children: [
|
|
2009
|
+
/* @__PURE__ */ (0, import_jsx_runtime31.jsx)("span", { className: "font-medium text-[var(--color-text)]", children: renderArtistLink(membership.artist) }),
|
|
2010
|
+
detailsText && /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)("span", { className: "text-[var(--color-text-muted)]", children: [
|
|
2108
2011
|
" \u2014 ",
|
|
2109
2012
|
detailsText
|
|
2110
2013
|
] })
|
|
@@ -2115,9 +2018,9 @@ function MembershipList({ title, memberships, renderArtistLink }) {
|
|
|
2115
2018
|
function ArtistMembers({ title, memberships, renderArtistLink }) {
|
|
2116
2019
|
if (memberships.length === 0) return null;
|
|
2117
2020
|
const isCurrent = (membership) => !membership.ended && membership.endYear === null;
|
|
2118
|
-
return /* @__PURE__ */ (0,
|
|
2119
|
-
/* @__PURE__ */ (0,
|
|
2120
|
-
/* @__PURE__ */ (0,
|
|
2021
|
+
return /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)(import_ui11.PanelSection, { title, children: [
|
|
2022
|
+
/* @__PURE__ */ (0, import_jsx_runtime31.jsx)(MembershipList, { title: "Current", memberships: memberships.filter(isCurrent), renderArtistLink }),
|
|
2023
|
+
/* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
|
|
2121
2024
|
MembershipList,
|
|
2122
2025
|
{
|
|
2123
2026
|
title: "Past",
|
|
@@ -2130,7 +2033,7 @@ function ArtistMembers({ title, memberships, renderArtistLink }) {
|
|
|
2130
2033
|
|
|
2131
2034
|
// src/genre-tree/artist/ArtistDiscography.tsx
|
|
2132
2035
|
var import_ui12 = require("@behindthemusictree/ui");
|
|
2133
|
-
var
|
|
2036
|
+
var import_jsx_runtime32 = require("react/jsx-runtime");
|
|
2134
2037
|
var GROUPS = ["Albums", "EPs", "Singles", "Live", "Compilations", "Other"];
|
|
2135
2038
|
var PRIMARY_GROUPS = { album: "Albums", ep: "EPs", single: "Singles" };
|
|
2136
2039
|
function discographyGroup({ primaryType, secondaryTypes }) {
|
|
@@ -2150,20 +2053,20 @@ function byYear(a, b) {
|
|
|
2150
2053
|
function ArtistDiscography({ albums }) {
|
|
2151
2054
|
if (albums.length === 0) return null;
|
|
2152
2055
|
const sorted = [...albums].sort(byYear);
|
|
2153
|
-
return /* @__PURE__ */ (0,
|
|
2056
|
+
return /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(import_ui12.PanelSection, { title: "Discography", children: GROUPS.map((group) => {
|
|
2154
2057
|
const groupAlbums = sorted.filter((album) => discographyGroup(album) === group);
|
|
2155
2058
|
if (groupAlbums.length === 0) return null;
|
|
2156
|
-
return /* @__PURE__ */ (0,
|
|
2157
|
-
/* @__PURE__ */ (0,
|
|
2158
|
-
/* @__PURE__ */ (0,
|
|
2059
|
+
return /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(import_ui12.PanelGroup, { title: group, children: /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("ul", { children: groupAlbums.map((album) => /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("li", { className: "grid grid-cols-[2.5rem_minmax(0,1fr)] gap-2 py-0.5", children: [
|
|
2060
|
+
/* @__PURE__ */ (0, import_jsx_runtime32.jsx)("span", { className: "tabular-nums text-[var(--color-text-muted)]", children: album.year ?? "\u2014" }),
|
|
2061
|
+
/* @__PURE__ */ (0, import_jsx_runtime32.jsx)("span", { className: "truncate text-[var(--color-text)]", title: album.name, children: album.name })
|
|
2159
2062
|
] }, album.uuid)) }) }, group);
|
|
2160
2063
|
}) });
|
|
2161
2064
|
}
|
|
2162
2065
|
|
|
2163
2066
|
// src/genre-tree/artist/ArtistSongs.tsx
|
|
2164
|
-
var
|
|
2067
|
+
var import_react14 = require("react");
|
|
2165
2068
|
var import_react_query2 = require("@tanstack/react-query");
|
|
2166
|
-
var
|
|
2069
|
+
var import_lucide_react13 = require("lucide-react");
|
|
2167
2070
|
var import_ui13 = require("@behindthemusictree/ui");
|
|
2168
2071
|
var import_player10 = require("@behindthemusictree/app-kit/player");
|
|
2169
2072
|
var import_genre_tree14 = require("@behindthemusictree/app-kit/genre-tree");
|
|
@@ -2177,7 +2080,7 @@ var import_genre_tree11 = require("@behindthemusictree/app-kit/genre-tree");
|
|
|
2177
2080
|
var import_fa5 = require("react-icons/fa");
|
|
2178
2081
|
var import_player7 = require("@behindthemusictree/app-kit/player");
|
|
2179
2082
|
var import_player8 = require("@behindthemusictree/app-kit/player");
|
|
2180
|
-
var
|
|
2083
|
+
var import_jsx_runtime33 = require("react/jsx-runtime");
|
|
2181
2084
|
function TrackPositionPlayPause({
|
|
2182
2085
|
position,
|
|
2183
2086
|
uuid,
|
|
@@ -2191,14 +2094,14 @@ function TrackPositionPlayPause({
|
|
|
2191
2094
|
const isPlaying = isThisTrack && isConfirmedPlayable && playState === import_player8.PlayStates.PLAYING;
|
|
2192
2095
|
const isPaused = isThisTrack && isConfirmedPlayable && playState === import_player8.PlayStates.PAUSED;
|
|
2193
2096
|
const isCurrentTrackActive = isPlaying || isPaused;
|
|
2194
|
-
return /* @__PURE__ */ (0,
|
|
2097
|
+
return /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(
|
|
2195
2098
|
"div",
|
|
2196
2099
|
{
|
|
2197
2100
|
className: "track-position-play-pause relative flex items-center justify-center gap-2 text-lg w-16 cursor-pointer",
|
|
2198
2101
|
style: { minWidth: "4rem", maxWidth: "4rem" },
|
|
2199
2102
|
onClick: handlePlayPauseClick,
|
|
2200
2103
|
children: [
|
|
2201
|
-
/* @__PURE__ */ (0,
|
|
2104
|
+
/* @__PURE__ */ (0, import_jsx_runtime33.jsx)("div", { className: "track-position-play-pause__status group-hover:hidden flex items-center justify-center", children: isAwaitingPlayback ? /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("span", { className: "track-position-play-pause__spinner", role: "status", "aria-label": "Loading track" }) : isCurrentTrackActive ? /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(
|
|
2202
2105
|
"span",
|
|
2203
2106
|
{
|
|
2204
2107
|
className: "track-position-play-pause__bars",
|
|
@@ -2206,18 +2109,18 @@ function TrackPositionPlayPause({
|
|
|
2206
2109
|
role: "img",
|
|
2207
2110
|
"aria-label": isPlaying ? "Playing" : "Paused",
|
|
2208
2111
|
children: [
|
|
2209
|
-
/* @__PURE__ */ (0,
|
|
2210
|
-
/* @__PURE__ */ (0,
|
|
2211
|
-
/* @__PURE__ */ (0,
|
|
2112
|
+
/* @__PURE__ */ (0, import_jsx_runtime33.jsx)("span", { className: "track-position-play-pause__bar" }),
|
|
2113
|
+
/* @__PURE__ */ (0, import_jsx_runtime33.jsx)("span", { className: "track-position-play-pause__bar" }),
|
|
2114
|
+
/* @__PURE__ */ (0, import_jsx_runtime33.jsx)("span", { className: "track-position-play-pause__bar" })
|
|
2212
2115
|
]
|
|
2213
2116
|
}
|
|
2214
2117
|
) : position }),
|
|
2215
|
-
/* @__PURE__ */ (0,
|
|
2118
|
+
/* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
|
|
2216
2119
|
"div",
|
|
2217
2120
|
{
|
|
2218
2121
|
className: `hidden group-hover:flex items-center justify-center ${isCurrentTrackActive ? "" : "absolute inset-0"}`,
|
|
2219
2122
|
"aria-hidden": "true",
|
|
2220
|
-
children: isAwaitingPlayback ? /* @__PURE__ */ (0,
|
|
2123
|
+
children: isAwaitingPlayback ? /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("span", { className: "track-position-play-pause__spinner" }) : isPlaying ? /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(import_fa5.FaPause, {}) : /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(import_fa5.FaPlay, {})
|
|
2221
2124
|
}
|
|
2222
2125
|
)
|
|
2223
2126
|
]
|
|
@@ -2228,7 +2131,7 @@ function TrackPositionPlayPause({
|
|
|
2228
2131
|
// src/genre-tree/track-list-sidebar/TrackItem.tsx
|
|
2229
2132
|
var import_genre_tree12 = require("@behindthemusictree/app-kit/genre-tree");
|
|
2230
2133
|
var import_genre_tree13 = require("@behindthemusictree/app-kit/genre-tree");
|
|
2231
|
-
var
|
|
2134
|
+
var import_jsx_runtime34 = require("react/jsx-runtime");
|
|
2232
2135
|
function TrackItem({
|
|
2233
2136
|
track,
|
|
2234
2137
|
position,
|
|
@@ -2252,12 +2155,12 @@ function TrackItem({
|
|
|
2252
2155
|
loadTrackForPlayer(track.uuid);
|
|
2253
2156
|
}
|
|
2254
2157
|
};
|
|
2255
|
-
return /* @__PURE__ */ (0,
|
|
2158
|
+
return /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)(
|
|
2256
2159
|
"div",
|
|
2257
2160
|
{
|
|
2258
2161
|
className: `track-item flex h-14 text-[var(--color-text)] ${isUnplayable ? "opacity-50" : "hover:bg-[var(--color-surface-muted)] group"}`,
|
|
2259
2162
|
children: [
|
|
2260
|
-
isUnplayable ? /* @__PURE__ */ (0,
|
|
2163
|
+
isUnplayable ? /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
|
|
2261
2164
|
"div",
|
|
2262
2165
|
{
|
|
2263
2166
|
className: "flex items-center justify-center text-lg w-16",
|
|
@@ -2265,7 +2168,7 @@ function TrackItem({
|
|
|
2265
2168
|
"aria-disabled": "true",
|
|
2266
2169
|
children: position
|
|
2267
2170
|
}
|
|
2268
|
-
) : /* @__PURE__ */ (0,
|
|
2171
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
|
|
2269
2172
|
TrackPositionPlayPause,
|
|
2270
2173
|
{
|
|
2271
2174
|
position,
|
|
@@ -2274,12 +2177,12 @@ function TrackItem({
|
|
|
2274
2177
|
isSelected: selectedTrack?.uuid === track.uuid
|
|
2275
2178
|
}
|
|
2276
2179
|
),
|
|
2277
|
-
/* @__PURE__ */ (0,
|
|
2278
|
-
/* @__PURE__ */ (0,
|
|
2279
|
-
track.artists && track.artists.length > 0 ? /* @__PURE__ */ (0,
|
|
2180
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("div", { className: "title-artist-container flex flex-col items-start justify-center min-w-0 flex-1", children: [
|
|
2181
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsx)("div", { className: "flex max-w-full items-center gap-2", children: /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("div", { className: "title text-lg font-bold text-[var(--color-text)] max-w-full truncate", children: renderSongLink ? renderSongLink(track) : (0, import_genre_tree12.isSong)(track) ? /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(MusicBrainzRecordingLink, { song: track, className: "hover:underline focus-visible:underline", children: track.title }) : track.title }) }),
|
|
2182
|
+
track.artists && track.artists.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("div", { className: "artist text-base max-w-full truncate text-[var(--color-text-muted)]", children: /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(import_genre_tree13.ArtistNames, { artists: track.artists, renderArtistLink }) }) : ""
|
|
2280
2183
|
] }),
|
|
2281
|
-
/* @__PURE__ */ (0,
|
|
2282
|
-
renderDuration && /* @__PURE__ */ (0,
|
|
2184
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.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_runtime34.jsx)("div", { className: "genre-name max-w-full whitespace-normal break-words p-1 text-xs font-bold", children: track.genre.name }) : "" }),
|
|
2185
|
+
renderDuration && /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
|
|
2283
2186
|
"div",
|
|
2284
2187
|
{
|
|
2285
2188
|
className: "duration flex text-base w-16 items-center justify-center",
|
|
@@ -2287,22 +2190,22 @@ function TrackItem({
|
|
|
2287
2190
|
children: renderDuration(track)
|
|
2288
2191
|
}
|
|
2289
2192
|
),
|
|
2290
|
-
renderActions && /* @__PURE__ */ (0,
|
|
2193
|
+
renderActions && /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("div", { className: "edit flex text-base w-6 items-center justify-center mr-2 cursor-pointer", children: renderActions(track) })
|
|
2291
2194
|
]
|
|
2292
2195
|
}
|
|
2293
2196
|
);
|
|
2294
2197
|
}
|
|
2295
2198
|
|
|
2296
2199
|
// src/genre-tree/artist/ArtistSongs.tsx
|
|
2297
|
-
var
|
|
2200
|
+
var import_jsx_runtime35 = require("react/jsx-runtime");
|
|
2298
2201
|
var SongPageSchema2 = (0, import_transport8.PaginatedResponseSchema)(import_genre_tree14.SongDetailedSchema);
|
|
2299
2202
|
var SORTS = [
|
|
2300
2203
|
{ ordering: "title", label: "Title" },
|
|
2301
2204
|
{ ordering: "-albumYear", label: "Year" }
|
|
2302
2205
|
];
|
|
2303
2206
|
function ArtistSongs({ artist, getBackendBaseUrl, renderArtistLink, renderSongLink }) {
|
|
2304
|
-
const [page, setPage] = (0,
|
|
2305
|
-
const [ordering, setOrdering] = (0,
|
|
2207
|
+
const [page, setPage] = (0, import_react14.useState)(1);
|
|
2208
|
+
const [ordering, setOrdering] = (0, import_react14.useState)("title");
|
|
2306
2209
|
const { fetch } = (0, import_transport8.useFetchWrapper)(getBackendBaseUrl);
|
|
2307
2210
|
const { playNewTrackListFromArtist } = (0, import_genre_tree14.useTrackList)();
|
|
2308
2211
|
const { playerTrackObject } = (0, import_player10.usePlayer)();
|
|
@@ -2327,21 +2230,21 @@ function ArtistSongs({ artist, getBackendBaseUrl, renderArtistLink, renderSongLi
|
|
|
2327
2230
|
event.stopPropagation();
|
|
2328
2231
|
void play(song.uuid);
|
|
2329
2232
|
};
|
|
2330
|
-
return /* @__PURE__ */ (0,
|
|
2331
|
-
/* @__PURE__ */ (0,
|
|
2332
|
-
/* @__PURE__ */ (0,
|
|
2233
|
+
return /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(import_ui13.PanelSection, { title: "Songs", children: isPending ? /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(import_ui13.Skeleton, { className: "h-14", "aria-busy": "true" }) : isError ? /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("p", { className: "text-red-600", children: "Could not load songs." }) : data.results.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("p", { className: "text-[var(--color-text-muted)]", children: "No songs yet." }) : /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)(import_jsx_runtime35.Fragment, { children: [
|
|
2234
|
+
/* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("div", { className: "flex flex-wrap items-center justify-between gap-2 mb-2", children: [
|
|
2235
|
+
/* @__PURE__ */ (0, import_jsx_runtime35.jsxs)(
|
|
2333
2236
|
"button",
|
|
2334
2237
|
{
|
|
2335
2238
|
type: "button",
|
|
2336
2239
|
onClick: () => void play(),
|
|
2337
2240
|
className: "flex w-fit items-center gap-1.5 px-3 py-1 text-xs font-medium bg-gray-900 text-white rounded-full hover:bg-gray-700",
|
|
2338
2241
|
children: [
|
|
2339
|
-
/* @__PURE__ */ (0,
|
|
2242
|
+
/* @__PURE__ */ (0, import_jsx_runtime35.jsx)(import_lucide_react13.Play, { className: "h-3.5 w-3.5", "aria-hidden": "true" }),
|
|
2340
2243
|
"Play all"
|
|
2341
2244
|
]
|
|
2342
2245
|
}
|
|
2343
2246
|
),
|
|
2344
|
-
/* @__PURE__ */ (0,
|
|
2247
|
+
/* @__PURE__ */ (0, import_jsx_runtime35.jsx)("div", { role: "group", "aria-label": "Sort songs by", className: "flex gap-1 text-xs", children: SORTS.map((sort) => /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
|
|
2345
2248
|
"button",
|
|
2346
2249
|
{
|
|
2347
2250
|
type: "button",
|
|
@@ -2356,7 +2259,7 @@ function ArtistSongs({ artist, getBackendBaseUrl, renderArtistLink, renderSongLi
|
|
|
2356
2259
|
sort.ordering
|
|
2357
2260
|
)) })
|
|
2358
2261
|
] }),
|
|
2359
|
-
/* @__PURE__ */ (0,
|
|
2262
|
+
/* @__PURE__ */ (0, import_jsx_runtime35.jsx)("ul", { className: "overflow-hidden mb-2 bg-zinc-950 rounded-lg", children: data.results.map((song, index) => /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("li", { onClickCapture: (event) => handleRowClickCapture(event, song), children: /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
|
|
2360
2263
|
TrackItem,
|
|
2361
2264
|
{
|
|
2362
2265
|
track: song,
|
|
@@ -2365,12 +2268,12 @@ function ArtistSongs({ artist, getBackendBaseUrl, renderArtistLink, renderSongLi
|
|
|
2365
2268
|
renderSongLink
|
|
2366
2269
|
}
|
|
2367
2270
|
) }, song.uuid)) }),
|
|
2368
|
-
/* @__PURE__ */ (0,
|
|
2271
|
+
/* @__PURE__ */ (0, import_jsx_runtime35.jsx)(import_ui13.Pagination, { currentPage: page, totalPages: data.totalPages, onPageChange: setPage })
|
|
2369
2272
|
] }) });
|
|
2370
2273
|
}
|
|
2371
2274
|
|
|
2372
2275
|
// src/genre-tree/artist/useArtistPanel.tsx
|
|
2373
|
-
var
|
|
2276
|
+
var import_jsx_runtime36 = require("react/jsx-runtime");
|
|
2374
2277
|
function useArtistPanel({
|
|
2375
2278
|
uuid,
|
|
2376
2279
|
scope,
|
|
@@ -2391,26 +2294,26 @@ function useArtistPanel({
|
|
|
2391
2294
|
return {
|
|
2392
2295
|
...panel,
|
|
2393
2296
|
title: "Artist",
|
|
2394
|
-
content: /* @__PURE__ */ (0,
|
|
2395
|
-
/* @__PURE__ */ (0,
|
|
2396
|
-
/* @__PURE__ */ (0,
|
|
2397
|
-
/* @__PURE__ */ (0,
|
|
2398
|
-
/* @__PURE__ */ (0,
|
|
2399
|
-
/* @__PURE__ */ (0,
|
|
2400
|
-
/* @__PURE__ */ (0,
|
|
2297
|
+
content: /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("div", { "aria-busy": "true", className: "flex flex-col gap-2.5 px-6 py-2.5", children: [
|
|
2298
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)(import_ui14.Skeleton, { className: "h-3 w-16" }),
|
|
2299
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)(import_ui14.Skeleton, { className: "h-4 w-32" }),
|
|
2300
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)(import_ui14.Skeleton, { className: "h-3 w-16" }),
|
|
2301
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)(import_ui14.Skeleton, { className: "h-4 w-24" }),
|
|
2302
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)(import_ui14.Skeleton, { className: "h-16 mt-2.5" }),
|
|
2303
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)(import_ui14.Skeleton, { className: "h-16" })
|
|
2401
2304
|
] })
|
|
2402
2305
|
};
|
|
2403
2306
|
case "not-found":
|
|
2404
2307
|
return {
|
|
2405
2308
|
...panel,
|
|
2406
2309
|
title: "Artist not found",
|
|
2407
|
-
content: /* @__PURE__ */ (0,
|
|
2310
|
+
content: /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("p", { className: "px-6 py-2.5 text-[var(--color-text-muted)]", children: "This artist does not exist." })
|
|
2408
2311
|
};
|
|
2409
2312
|
case "error":
|
|
2410
2313
|
return {
|
|
2411
2314
|
...panel,
|
|
2412
2315
|
title: "Artist",
|
|
2413
|
-
content: /* @__PURE__ */ (0,
|
|
2316
|
+
content: /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("p", { className: "px-6 py-2.5 text-red-600", children: "Could not load this artist." })
|
|
2414
2317
|
};
|
|
2415
2318
|
case "success": {
|
|
2416
2319
|
const { artist } = result;
|
|
@@ -2419,13 +2322,13 @@ function useArtistPanel({
|
|
|
2419
2322
|
return {
|
|
2420
2323
|
...panel,
|
|
2421
2324
|
title: artist.name,
|
|
2422
|
-
content: /* @__PURE__ */ (0,
|
|
2423
|
-
shareUrl && /* @__PURE__ */ (0,
|
|
2424
|
-
artist.image && /* @__PURE__ */ (0,
|
|
2425
|
-
/* @__PURE__ */ (0,
|
|
2426
|
-
/* @__PURE__ */ (0,
|
|
2427
|
-
/* @__PURE__ */ (0,
|
|
2428
|
-
artist.tracksCount > 0 && /* @__PURE__ */ (0,
|
|
2325
|
+
content: /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)(import_jsx_runtime36.Fragment, { children: [
|
|
2326
|
+
shareUrl && /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("div", { className: "genre-action-band border-b border-[var(--color-border)]", children: /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("div", { className: "flex flex-wrap gap-1 px-3.5 py-3", children: shareTarget && /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(ShareActionButton, { target: shareTarget, url: shareUrl }) }) }),
|
|
2327
|
+
artist.image && /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(ArtistPhoto, { image: artist.image, name: artist.name }),
|
|
2328
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)(ArtistHeader, { artist }),
|
|
2329
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)(ArtistMembers, { title: "Members", memberships: artist.members, renderArtistLink }),
|
|
2330
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)(ArtistMembers, { title: "Member of", memberships: artist.memberOf, renderArtistLink }),
|
|
2331
|
+
artist.tracksCount > 0 && /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
|
|
2429
2332
|
ArtistSongs,
|
|
2430
2333
|
{
|
|
2431
2334
|
artist: { uuid: artist.uuid, name: artist.name },
|
|
@@ -2435,7 +2338,7 @@ function useArtistPanel({
|
|
|
2435
2338
|
}
|
|
2436
2339
|
)
|
|
2437
2340
|
] }),
|
|
2438
|
-
extraContent: artist.albums.length > 0 ? /* @__PURE__ */ (0,
|
|
2341
|
+
extraContent: artist.albums.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(ArtistDiscography, { albums: artist.albums }) : void 0
|
|
2439
2342
|
};
|
|
2440
2343
|
}
|
|
2441
2344
|
}
|
|
@@ -2446,45 +2349,45 @@ var import_ui16 = require("@behindthemusictree/ui");
|
|
|
2446
2349
|
var import_genre_tree17 = require("@behindthemusictree/app-kit/genre-tree");
|
|
2447
2350
|
|
|
2448
2351
|
// src/genre-tree/song/SongPanelContent.tsx
|
|
2449
|
-
var
|
|
2450
|
-
var
|
|
2352
|
+
var import_react15 = require("react");
|
|
2353
|
+
var import_lucide_react14 = require("lucide-react");
|
|
2451
2354
|
var import_ui15 = require("@behindthemusictree/ui");
|
|
2452
2355
|
var import_player11 = require("@behindthemusictree/app-kit/player");
|
|
2453
2356
|
var import_genre_tree16 = require("@behindthemusictree/app-kit/genre-tree");
|
|
2454
|
-
var
|
|
2357
|
+
var import_jsx_runtime37 = require("react/jsx-runtime");
|
|
2455
2358
|
var numberFormat = new Intl.NumberFormat("en");
|
|
2456
2359
|
var dateFormat = new Intl.DateTimeFormat("en", { dateStyle: "medium" });
|
|
2457
2360
|
var externalLink = "text-[var(--color-primary)] hover:underline focus-visible:underline";
|
|
2458
2361
|
function SongHistory({ uuid, getBackendBaseUrl }) {
|
|
2459
|
-
const [open, setOpen] = (0,
|
|
2362
|
+
const [open, setOpen] = (0, import_react15.useState)(false);
|
|
2460
2363
|
const history = (0, import_genre_tree16.useSongHistory)(uuid, getBackendBaseUrl, open);
|
|
2461
2364
|
let body = null;
|
|
2462
|
-
if (history.status === "loading") body = /* @__PURE__ */ (0,
|
|
2463
|
-
else if (history.status === "error") body = /* @__PURE__ */ (0,
|
|
2365
|
+
if (history.status === "loading") body = /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(import_ui15.Skeleton, { className: "h-10", "aria-busy": "true" });
|
|
2366
|
+
else if (history.status === "error") body = /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("p", { className: "text-red-600", children: "Could not load the history." });
|
|
2464
2367
|
else if (history.status === "success")
|
|
2465
|
-
body = history.entries.length === 0 ? /* @__PURE__ */ (0,
|
|
2466
|
-
/* @__PURE__ */ (0,
|
|
2467
|
-
entry.oldValue !== null || entry.newValue !== null ? /* @__PURE__ */ (0,
|
|
2368
|
+
body = history.entries.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("p", { className: "text-[var(--color-text-muted)]", children: "No changes yet." }) : /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("ul", { className: "divide-y divide-[var(--color-border)]", children: history.entries.map((entry) => /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)("li", { className: "py-1.5 text-sm", children: [
|
|
2369
|
+
/* @__PURE__ */ (0, import_jsx_runtime37.jsx)("span", { className: "font-medium", children: entry.action }),
|
|
2370
|
+
entry.oldValue !== null || entry.newValue !== null ? /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)("span", { className: "text-[var(--color-text-muted)]", children: [
|
|
2468
2371
|
" ",
|
|
2469
2372
|
"\u2014 ",
|
|
2470
2373
|
entry.oldValue ?? "none",
|
|
2471
2374
|
" \u2192 ",
|
|
2472
2375
|
entry.newValue ?? "none"
|
|
2473
2376
|
] }) : null,
|
|
2474
|
-
/* @__PURE__ */ (0,
|
|
2377
|
+
/* @__PURE__ */ (0, import_jsx_runtime37.jsxs)("span", { className: "block text-xs text-[var(--color-text-muted)]", children: [
|
|
2475
2378
|
entry.actorPseudo ?? "Anonymous",
|
|
2476
2379
|
" \xB7 ",
|
|
2477
2380
|
dateFormat.format(new Date(entry.createdOn))
|
|
2478
2381
|
] })
|
|
2479
2382
|
] }, entry.uuid)) });
|
|
2480
|
-
return /* @__PURE__ */ (0,
|
|
2383
|
+
return /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)(
|
|
2481
2384
|
"details",
|
|
2482
2385
|
{
|
|
2483
2386
|
onToggle: (event) => setOpen(event.currentTarget.open),
|
|
2484
2387
|
className: "px-6 pb-2.5 mt-2.5 border-t border-[var(--color-border)]",
|
|
2485
2388
|
children: [
|
|
2486
|
-
/* @__PURE__ */ (0,
|
|
2487
|
-
/* @__PURE__ */ (0,
|
|
2389
|
+
/* @__PURE__ */ (0, import_jsx_runtime37.jsx)("summary", { className: "mt-2.5 cursor-pointer text-[0.6875rem] font-semibold uppercase text-[var(--color-text-muted)]", children: "History" }),
|
|
2390
|
+
/* @__PURE__ */ (0, import_jsx_runtime37.jsx)("div", { className: "mt-1.5", children: body })
|
|
2488
2391
|
]
|
|
2489
2392
|
}
|
|
2490
2393
|
);
|
|
@@ -2510,13 +2413,13 @@ function SongPanelContent({
|
|
|
2510
2413
|
const path = genrePath.length > 0 ? genrePath : null;
|
|
2511
2414
|
fields.push({
|
|
2512
2415
|
label: "Genre",
|
|
2513
|
-
value: path ? /* @__PURE__ */ (0,
|
|
2514
|
-
index > 0 && /* @__PURE__ */ (0,
|
|
2515
|
-
/* @__PURE__ */ (0,
|
|
2416
|
+
value: path ? /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("span", { className: "flex flex-wrap items-center gap-x-1", children: path.map((genrePlaylist, index) => /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)("span", { children: [
|
|
2417
|
+
index > 0 && /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("span", { "aria-hidden": "true", children: "\u203A " }),
|
|
2418
|
+
/* @__PURE__ */ (0, import_jsx_runtime37.jsx)("button", { type: "button", onClick: () => onSelectGenre(genrePlaylist), className: "hover:underline", children: genrePlaylist.name })
|
|
2516
2419
|
] }, genrePlaylist.uuid)) }) : song.genre.name
|
|
2517
2420
|
});
|
|
2518
2421
|
} else {
|
|
2519
|
-
fields.push({ label: "Genre", value: /* @__PURE__ */ (0,
|
|
2422
|
+
fields.push({ label: "Genre", value: /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("span", { className: "text-[var(--color-text-muted)]", children: "No genre" }) });
|
|
2520
2423
|
}
|
|
2521
2424
|
if (song.firstReleaseYear) fields.push({ label: "First released", value: song.firstReleaseYear });
|
|
2522
2425
|
const viewCount = song.youtubeVideo?.viewCount;
|
|
@@ -2526,11 +2429,11 @@ function SongPanelContent({
|
|
|
2526
2429
|
const links = [];
|
|
2527
2430
|
if (musicBrainzUrl)
|
|
2528
2431
|
links.push(
|
|
2529
|
-
/* @__PURE__ */ (0,
|
|
2432
|
+
/* @__PURE__ */ (0, import_jsx_runtime37.jsx)("a", { href: musicBrainzUrl, target: "_blank", rel: "noopener noreferrer", className: externalLink, children: "MusicBrainz" }, "mb")
|
|
2530
2433
|
);
|
|
2531
2434
|
if (song.youtubeVideo)
|
|
2532
2435
|
links.push(
|
|
2533
|
-
/* @__PURE__ */ (0,
|
|
2436
|
+
/* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
|
|
2534
2437
|
"a",
|
|
2535
2438
|
{
|
|
2536
2439
|
href: `https://www.youtube.com/watch?v=${encodeURIComponent(song.youtubeVideo.id)}`,
|
|
@@ -2545,33 +2448,33 @@ function SongPanelContent({
|
|
|
2545
2448
|
if (links.length > 0)
|
|
2546
2449
|
fields.push({
|
|
2547
2450
|
label: "Links",
|
|
2548
|
-
value: /* @__PURE__ */ (0,
|
|
2451
|
+
value: /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("span", { className: "flex gap-3", children: links })
|
|
2549
2452
|
});
|
|
2550
|
-
return /* @__PURE__ */ (0,
|
|
2551
|
-
/* @__PURE__ */ (0,
|
|
2552
|
-
unplayableReason ? /* @__PURE__ */ (0,
|
|
2453
|
+
return /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)(import_jsx_runtime37.Fragment, { children: [
|
|
2454
|
+
/* @__PURE__ */ (0, import_jsx_runtime37.jsx)("div", { className: "genre-action-band border-b border-[var(--color-border)]", children: /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)("div", { className: "flex flex-wrap gap-1 px-3.5 py-3", children: [
|
|
2455
|
+
unplayableReason ? /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("p", { className: "flex items-center px-2.5 text-sm text-[var(--color-text-muted)]", children: unplayableReason }) : /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)(
|
|
2553
2456
|
"button",
|
|
2554
2457
|
{
|
|
2555
2458
|
type: "button",
|
|
2556
2459
|
onClick: () => isCurrent ? handlePlayPauseAction() : playNewTrackListFromTrackUuid(song, scope),
|
|
2557
2460
|
className: "group flex flex-col items-center gap-1 w-16 text-xs text-center text-[var(--color-text)] focus-visible:outline-none",
|
|
2558
2461
|
children: [
|
|
2559
|
-
/* @__PURE__ */ (0,
|
|
2462
|
+
/* @__PURE__ */ (0, import_jsx_runtime37.jsx)("span", { className: "flex items-center justify-center w-10 h-10 rounded-full group-focus-visible:ring-2 group-focus-visible:ring-[var(--color-focus-ring)] bg-[var(--color-surface-muted)] transition-colors group-hover:bg-[var(--color-border)]", children: isPlaying ? /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(import_lucide_react14.Pause, { "aria-hidden": "true", className: "w-5 h-5" }) : /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(import_lucide_react14.Play, { "aria-hidden": "true", className: "w-5 h-5" }) }),
|
|
2560
2463
|
isPlaying ? "Pause" : "Play"
|
|
2561
2464
|
]
|
|
2562
2465
|
}
|
|
2563
2466
|
),
|
|
2564
|
-
shareUrl && /* @__PURE__ */ (0,
|
|
2467
|
+
shareUrl && /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(ShareActionButton, { target: shareTarget, url: shareUrl })
|
|
2565
2468
|
] }) }),
|
|
2566
|
-
song.artists && song.artists.length > 0 && /* @__PURE__ */ (0,
|
|
2567
|
-
/* @__PURE__ */ (0,
|
|
2568
|
-
song.essentialGenres && song.essentialGenres.length > 0 && /* @__PURE__ */ (0,
|
|
2569
|
-
/* @__PURE__ */ (0,
|
|
2469
|
+
song.artists && song.artists.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("p", { className: "px-6 pt-2.5 text-[var(--color-text-muted)]", children: /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(import_genre_tree16.ArtistNames, { artists: song.artists, renderArtistLink }) }),
|
|
2470
|
+
/* @__PURE__ */ (0, import_jsx_runtime37.jsx)(import_ui15.FieldList, { items: fields }),
|
|
2471
|
+
song.essentialGenres && song.essentialGenres.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(import_ui15.PanelSection, { title: "Essential in", children: /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("ul", { children: song.essentialGenres.map((genre) => /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("li", { className: "py-0.5", children: genre.name }, genre.uuid)) }) }),
|
|
2472
|
+
/* @__PURE__ */ (0, import_jsx_runtime37.jsx)(SongHistory, { uuid: song.uuid, getBackendBaseUrl })
|
|
2570
2473
|
] });
|
|
2571
2474
|
}
|
|
2572
2475
|
|
|
2573
2476
|
// src/genre-tree/song/useSongPanel.tsx
|
|
2574
|
-
var
|
|
2477
|
+
var import_jsx_runtime38 = require("react/jsx-runtime");
|
|
2575
2478
|
function useSongPanel({
|
|
2576
2479
|
uuid,
|
|
2577
2480
|
scope,
|
|
@@ -2593,24 +2496,24 @@ function useSongPanel({
|
|
|
2593
2496
|
return {
|
|
2594
2497
|
...panel,
|
|
2595
2498
|
title: "Song",
|
|
2596
|
-
content: /* @__PURE__ */ (0,
|
|
2597
|
-
/* @__PURE__ */ (0,
|
|
2598
|
-
/* @__PURE__ */ (0,
|
|
2599
|
-
/* @__PURE__ */ (0,
|
|
2600
|
-
/* @__PURE__ */ (0,
|
|
2499
|
+
content: /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("div", { "aria-busy": "true", className: "flex flex-col gap-2.5 px-6 py-2.5", children: [
|
|
2500
|
+
/* @__PURE__ */ (0, import_jsx_runtime38.jsx)(import_ui16.Skeleton, { className: "h-3 w-16" }),
|
|
2501
|
+
/* @__PURE__ */ (0, import_jsx_runtime38.jsx)(import_ui16.Skeleton, { className: "h-4 w-32" }),
|
|
2502
|
+
/* @__PURE__ */ (0, import_jsx_runtime38.jsx)(import_ui16.Skeleton, { className: "h-3 w-16" }),
|
|
2503
|
+
/* @__PURE__ */ (0, import_jsx_runtime38.jsx)(import_ui16.Skeleton, { className: "h-4 w-24" })
|
|
2601
2504
|
] })
|
|
2602
2505
|
};
|
|
2603
2506
|
case "not-found":
|
|
2604
2507
|
return {
|
|
2605
2508
|
...panel,
|
|
2606
2509
|
title: "Song not found",
|
|
2607
|
-
content: /* @__PURE__ */ (0,
|
|
2510
|
+
content: /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("p", { className: "px-6 py-2.5 text-[var(--color-text-muted)]", children: "This song does not exist." })
|
|
2608
2511
|
};
|
|
2609
2512
|
case "error":
|
|
2610
2513
|
return {
|
|
2611
2514
|
...panel,
|
|
2612
2515
|
title: "Song",
|
|
2613
|
-
content: /* @__PURE__ */ (0,
|
|
2516
|
+
content: /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("p", { className: "px-6 py-2.5 text-red-600", children: "Could not load this song." })
|
|
2614
2517
|
};
|
|
2615
2518
|
case "success": {
|
|
2616
2519
|
const { song } = result;
|
|
@@ -2618,7 +2521,7 @@ function useSongPanel({
|
|
|
2618
2521
|
return {
|
|
2619
2522
|
...panel,
|
|
2620
2523
|
title: song.title,
|
|
2621
|
-
content: /* @__PURE__ */ (0,
|
|
2524
|
+
content: /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
|
|
2622
2525
|
SongPanelContent,
|
|
2623
2526
|
{
|
|
2624
2527
|
song,
|
|
@@ -2638,12 +2541,12 @@ function useSongPanel({
|
|
|
2638
2541
|
// src/genre-tree/SizeMetricToggle.tsx
|
|
2639
2542
|
var import_md2 = require("react-icons/md");
|
|
2640
2543
|
var import_ui17 = require("@behindthemusictree/ui");
|
|
2641
|
-
var
|
|
2544
|
+
var import_jsx_runtime39 = require("react/jsx-runtime");
|
|
2642
2545
|
function SizeMetricToggle({
|
|
2643
2546
|
value,
|
|
2644
2547
|
onChange
|
|
2645
2548
|
}) {
|
|
2646
|
-
return /* @__PURE__ */ (0,
|
|
2549
|
+
return /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
|
|
2647
2550
|
import_ui17.SegmentedControl,
|
|
2648
2551
|
{
|
|
2649
2552
|
variant: "floating",
|
|
@@ -2651,26 +2554,19 @@ function SizeMetricToggle({
|
|
|
2651
2554
|
value,
|
|
2652
2555
|
onChange,
|
|
2653
2556
|
options: [
|
|
2654
|
-
{ value: "songs", label: /* @__PURE__ */ (0,
|
|
2655
|
-
{ value: "views", label: /* @__PURE__ */ (0,
|
|
2557
|
+
{ value: "songs", label: /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(import_md2.MdMusicNote, { size: 18, "aria-hidden": true }), "aria-label": "Size by songs", title: "Node size by song count" },
|
|
2558
|
+
{ value: "views", label: /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(import_md2.MdVisibility, { size: 18, "aria-hidden": true }), "aria-label": "Size by views", title: "Node size by song views" }
|
|
2656
2559
|
]
|
|
2657
2560
|
}
|
|
2658
2561
|
);
|
|
2659
2562
|
}
|
|
2660
2563
|
|
|
2661
2564
|
// src/genre-tree/GenreTreeView.tsx
|
|
2662
|
-
var
|
|
2663
|
-
var PREVIOUS_BUTTON_CSS = `
|
|
2664
|
-
.genre-tree-view .search-overlay .gtv-info-panel-previous { display: none; }
|
|
2665
|
-
.genre-tree-view:has(.search-overlay .gtv-info-panel-previous) .genre-search input { padding-left: 2.75rem; }
|
|
2666
|
-
.genre-tree-view:has(.search-overlay .gtv-info-panel-previous) .genre-search-previous { display: flex; }
|
|
2667
|
-
@keyframes genre-tree-view-previous-in { from { opacity: 0; transform: translate(-0.5rem, -50%); } to { opacity: 1; transform: translate(0, -50%); } }
|
|
2668
|
-
@media (prefers-reduced-motion: no-preference) {
|
|
2669
|
-
.genre-search-previous { animation: genre-tree-view-previous-in 200ms ease-out; }
|
|
2670
|
-
}
|
|
2671
|
-
`;
|
|
2565
|
+
var import_jsx_runtime40 = require("react/jsx-runtime");
|
|
2672
2566
|
var NO_POP_ROOT_TITLE = "This genre tree has no 'Mainstream Pop' root yet";
|
|
2673
|
-
var REGIONS_CLASS = "[--gtv-center-left:var(--layout-center-left)] [--gtv-center-right:var(--layout-center-right)] [--gtv-center-top:var(--layout-band-top)]
|
|
2567
|
+
var REGIONS_CLASS = "[--gtv-center-left:var(--layout-center-left)] [--gtv-center-right:var(--layout-center-right)] [--gtv-center-top:var(--layout-band-top)]";
|
|
2568
|
+
var noop = () => {
|
|
2569
|
+
};
|
|
2674
2570
|
function GenreTreeView({
|
|
2675
2571
|
scope,
|
|
2676
2572
|
handleGenreCreationAction,
|
|
@@ -2724,21 +2620,21 @@ function GenreTreeView({
|
|
|
2724
2620
|
placement = "default",
|
|
2725
2621
|
...focus
|
|
2726
2622
|
}) {
|
|
2727
|
-
const getShareUrlRef = (0,
|
|
2623
|
+
const getShareUrlRef = (0, import_react16.useRef)(getShareUrl);
|
|
2728
2624
|
getShareUrlRef.current = getShareUrl;
|
|
2729
|
-
const [internalArtistUuid, setInternalArtistUuid] = (0,
|
|
2625
|
+
const [internalArtistUuid, setInternalArtistUuid] = (0, import_react16.useState)(null);
|
|
2730
2626
|
const isArtistControlled = controlledArtistUuid !== void 0;
|
|
2731
2627
|
const artistUuid = isArtistControlled ? controlledArtistUuid : internalArtistUuid;
|
|
2732
|
-
const [internalSongUuid, setInternalSongUuid] = (0,
|
|
2628
|
+
const [internalSongUuid, setInternalSongUuid] = (0, import_react16.useState)(null);
|
|
2733
2629
|
const isSongControlled = controlledSongUuid !== void 0;
|
|
2734
2630
|
const songUuid = isSongControlled ? controlledSongUuid : internalSongUuid;
|
|
2735
2631
|
const changeSong = (uuid) => {
|
|
2736
2632
|
if (!isSongControlled) setInternalSongUuid(uuid);
|
|
2737
2633
|
onSongUuidChange?.(uuid);
|
|
2738
2634
|
};
|
|
2739
|
-
const [internalSizeMetric, setInternalSizeMetric] = (0,
|
|
2635
|
+
const [internalSizeMetric, setInternalSizeMetric] = (0, import_react16.useState)("songs");
|
|
2740
2636
|
const sizeMetric = controlledSizeMetric ?? internalSizeMetric;
|
|
2741
|
-
const deferredSizeMetric = (0,
|
|
2637
|
+
const deferredSizeMetric = (0, import_react16.useDeferredValue)(sizeMetric);
|
|
2742
2638
|
const changeSizeMetric = (metric) => {
|
|
2743
2639
|
if (controlledSizeMetric === void 0) setInternalSizeMetric(metric);
|
|
2744
2640
|
onSizeMetricChange?.(metric);
|
|
@@ -2775,7 +2671,7 @@ function GenreTreeView({
|
|
|
2775
2671
|
artistUuid
|
|
2776
2672
|
});
|
|
2777
2673
|
const restoreRevision = viewportRestore?.revision;
|
|
2778
|
-
const [stackedRestoreOwner, setStackedRestoreOwner] = (0,
|
|
2674
|
+
const [stackedRestoreOwner, setStackedRestoreOwner] = (0, import_react16.useState)({ revision: restoreRevision, rootUuid: selectedGenrePlaylist?.root.uuid });
|
|
2779
2675
|
let restoreRootUuid = stackedRestoreOwner.rootUuid;
|
|
2780
2676
|
if (stackedRestoreOwner.revision !== restoreRevision) {
|
|
2781
2677
|
restoreRootUuid = selectedGenrePlaylist?.root.uuid;
|
|
@@ -2791,7 +2687,7 @@ function GenreTreeView({
|
|
|
2791
2687
|
const canSizeByViews = !isArtistFiltered && hasViewsCount(visibleGenrePlaylists);
|
|
2792
2688
|
const artistResult = (0, import_genre_tree19.useArtist)(artistUuid, artistSearchBaseUrl ?? getBackendBaseUrl);
|
|
2793
2689
|
const filterArtistName = artistResult.status === "success" ? artistResult.artist.name : null;
|
|
2794
|
-
const filterArtist = (0,
|
|
2690
|
+
const filterArtist = (0, import_react16.useMemo)(
|
|
2795
2691
|
() => artistUuid !== null && filterArtistName !== null ? { uuid: artistUuid, name: filterArtistName } : null,
|
|
2796
2692
|
[artistUuid, filterArtistName]
|
|
2797
2693
|
);
|
|
@@ -2806,14 +2702,14 @@ function GenreTreeView({
|
|
|
2806
2702
|
if (selectedNodeId !== null) clearSelection();
|
|
2807
2703
|
changeSong(uuid);
|
|
2808
2704
|
};
|
|
2809
|
-
const openSongRef = (0,
|
|
2705
|
+
const openSongRef = (0, import_react16.useRef)(openSong);
|
|
2810
2706
|
openSongRef.current = openSong;
|
|
2811
|
-
const resolvedRenderSongLink = (0,
|
|
2812
|
-
(song) => renderSongLink ? renderSongLink(song) : /* @__PURE__ */ (0,
|
|
2707
|
+
const resolvedRenderSongLink = (0, import_react16.useCallback)(
|
|
2708
|
+
(song) => renderSongLink ? renderSongLink(song) : /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("button", { type: "button", onClick: () => openSongRef.current(song.uuid), className: "hover:underline", children: song.title }),
|
|
2813
2709
|
[renderSongLink]
|
|
2814
2710
|
);
|
|
2815
|
-
const [expandedSongUuid, setExpandedSongUuid] = (0,
|
|
2816
|
-
const [expandedArtistUuid, setExpandedArtistUuid] = (0,
|
|
2711
|
+
const [expandedSongUuid, setExpandedSongUuid] = (0, import_react16.useState)(null);
|
|
2712
|
+
const [expandedArtistUuid, setExpandedArtistUuid] = (0, import_react16.useState)(null);
|
|
2817
2713
|
const artistBaseUrl = artistSearchBaseUrl ?? getBackendBaseUrl;
|
|
2818
2714
|
const songBaseUrl = getBackendBaseUrl;
|
|
2819
2715
|
const artistPanel = useArtistPanel({
|
|
@@ -2821,7 +2717,7 @@ function GenreTreeView({
|
|
|
2821
2717
|
scope,
|
|
2822
2718
|
getBackendBaseUrl: artistBaseUrl,
|
|
2823
2719
|
getShareUrl: getShareUrlRef.current,
|
|
2824
|
-
renderArtistLink: renderArtistLink ?? ((artist) => artist.isSpecialPurpose ? artist.name : /* @__PURE__ */ (0,
|
|
2720
|
+
renderArtistLink: renderArtistLink ?? ((artist) => artist.isSpecialPurpose ? artist.name : /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("button", { type: "button", onClick: () => openArtist(artist.uuid), className: "hover:underline", children: artist.name })),
|
|
2825
2721
|
expanded: controlledArtistExpanded ?? (artistUuid !== null && expandedArtistUuid === artistUuid),
|
|
2826
2722
|
onExpandedChange: (on) => {
|
|
2827
2723
|
if (controlledArtistExpanded === void 0) setExpandedArtistUuid(on ? artistUuid : null);
|
|
@@ -2830,7 +2726,7 @@ function GenreTreeView({
|
|
|
2830
2726
|
renderSongLink: resolvedRenderSongLink,
|
|
2831
2727
|
onClose: () => changeArtist(null)
|
|
2832
2728
|
});
|
|
2833
|
-
const resolvedRenderArtistLink = renderArtistLink ?? ((artist) => artist.isSpecialPurpose ? artist.name : /* @__PURE__ */ (0,
|
|
2729
|
+
const resolvedRenderArtistLink = renderArtistLink ?? ((artist) => artist.isSpecialPurpose ? artist.name : /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("button", { type: "button", onClick: () => openArtist(artist.uuid), className: "hover:underline", children: artist.name }));
|
|
2834
2730
|
const getGenrePath = (genre) => {
|
|
2835
2731
|
const path = [];
|
|
2836
2732
|
let current = visibleGenrePlaylists.find((playlist) => playlist.criteria?.uuid === genre.uuid);
|
|
@@ -2862,9 +2758,8 @@ function GenreTreeView({
|
|
|
2862
2758
|
const builtInSongPanel = overlayPanel || hasSelectedGenreNode ? void 0 : songPanel;
|
|
2863
2759
|
const builtInArtistPanel = overlayPanel || hasSelectedGenreNode || builtInSongPanel ? void 0 : artistPanel;
|
|
2864
2760
|
const builtInPanel = builtInSongPanel ?? builtInArtistPanel;
|
|
2865
|
-
const
|
|
2866
|
-
const [
|
|
2867
|
-
const [uncontrolledExpanded, setUncontrolledExpanded] = (0, import_react17.useState)(false);
|
|
2761
|
+
const [uncontrolledCollapsed, setUncontrolledCollapsed] = (0, import_react16.useState)(false);
|
|
2762
|
+
const [uncontrolledExpanded, setUncontrolledExpanded] = (0, import_react16.useState)(false);
|
|
2868
2763
|
const isCollapsed = collapsed ?? uncontrolledCollapsed;
|
|
2869
2764
|
const isExpanded = expanded ?? uncontrolledExpanded;
|
|
2870
2765
|
const changeCollapsed = (next) => {
|
|
@@ -2875,55 +2770,56 @@ function GenreTreeView({
|
|
|
2875
2770
|
setUncontrolledExpanded(next);
|
|
2876
2771
|
onExpandedChange?.(next);
|
|
2877
2772
|
};
|
|
2878
|
-
(0,
|
|
2773
|
+
(0, import_react16.useEffect)(() => {
|
|
2879
2774
|
setUncontrolledCollapsed(false);
|
|
2880
2775
|
}, [selectedNodeId, artistUuid, songUuid]);
|
|
2881
|
-
const
|
|
2882
|
-
useLeftDetailPanelLayout(!isDetailHidden, placement === "regions");
|
|
2883
|
-
const detailOverlay = placement === "regions" && activeOverlayPanel?.onExpandedChange ? activeOverlayPanel : void 0;
|
|
2884
|
-
const detailExpanded = detailOverlay ? !!detailOverlay.expanded : isExpanded;
|
|
2885
|
-
const onDetailExpandedChange = detailOverlay ? detailOverlay.onExpandedChange : changeExpanded;
|
|
2886
|
-
const infoPanelCuration = {
|
|
2887
|
-
renderDangerZone,
|
|
2888
|
-
expanded: placement === "regions" ? isExpanded : expanded,
|
|
2889
|
-
onExpandedChange: placement === "regions" ? changeExpanded : onExpandedChange,
|
|
2890
|
-
collapsed: placement === "regions" ? isCollapsed : void 0,
|
|
2891
|
-
hideExpandButton: placement === "regions" ? true : void 0,
|
|
2892
|
-
overlayPanel: detailOverlay ? { ...detailOverlay, collapsed: isCollapsed, hideExpandButton: true } : activeOverlayPanel
|
|
2893
|
-
};
|
|
2894
|
-
const [isWheelRevealed, setIsWheelRevealed] = (0, import_react17.useState)(false);
|
|
2776
|
+
const [isWheelRevealed, setIsWheelRevealed] = (0, import_react16.useState)(false);
|
|
2895
2777
|
const usesHandoff = viewMode === "wheel" || viewMode === "pop-core";
|
|
2896
2778
|
const isTreeReady = !isLoading && (!usesHandoff || isWheelRevealed);
|
|
2897
|
-
const
|
|
2898
|
-
const
|
|
2899
|
-
|
|
2900
|
-
|
|
2901
|
-
|
|
2902
|
-
|
|
2903
|
-
|
|
2904
|
-
|
|
2905
|
-
|
|
2906
|
-
|
|
2907
|
-
|
|
2908
|
-
|
|
2909
|
-
|
|
2779
|
+
const [resolveStyle, setResolveStyle] = (0, import_react16.useState)(null);
|
|
2780
|
+
const handleNodeStyleResolverChange = (0, import_react16.useCallback)(
|
|
2781
|
+
(resolver) => setResolveStyle(() => resolver),
|
|
2782
|
+
[]
|
|
2783
|
+
);
|
|
2784
|
+
const panelRef = (0, import_react16.useRef)(null);
|
|
2785
|
+
const obscuredInset = (0, import_ui18.useObscuredInset)(panelRef);
|
|
2786
|
+
const hostPanel = { obscuredInset, onNodeStyleResolverChange: handleNodeStyleResolverChange };
|
|
2787
|
+
const nodeMetric = isArtistFiltered || !canSizeByViews ? "songs" : deferredSizeMetric;
|
|
2788
|
+
const treeNodes = (0, import_react16.useMemo)(() => toTreeNodes(visibleGenrePlaylists, nodeMetric), [visibleGenrePlaylists, nodeMetric]);
|
|
2789
|
+
const relations = (0, import_genre_tree_view4.useGenreNodeRelations)(
|
|
2790
|
+
treeNodes,
|
|
2791
|
+
!overlayPanel && hasSelectedGenreNode ? selectedNodeId : null,
|
|
2792
|
+
resolveStyle
|
|
2793
|
+
);
|
|
2794
|
+
const [selectionHistory, setSelectionHistory] = (0, import_react16.useState)({
|
|
2795
|
+
current: selectedNodeId,
|
|
2796
|
+
previous: null
|
|
2797
|
+
});
|
|
2798
|
+
if (selectionHistory.current !== selectedNodeId) {
|
|
2799
|
+
setSelectionHistory({
|
|
2800
|
+
current: selectedNodeId,
|
|
2801
|
+
previous: selectionHistory.current ?? selectionHistory.previous
|
|
2802
|
+
});
|
|
2803
|
+
}
|
|
2804
|
+
const previousPlaylist = selectionHistory.previous !== null && selectionHistory.previous !== selectedNodeId ? genrePlaylistByNodeId.get(selectionHistory.previous) : void 0;
|
|
2805
|
+
const handlePrevious = previousPlaylist && visibleGenrePlaylists.includes(previousPlaylist) ? () => handleGenreSearchSelect(previousPlaylist) : void 0;
|
|
2910
2806
|
const { showPopup, hidePopup } = (0, import_popup6.usePopup)();
|
|
2911
|
-
const [searchText, setSearchText] = (0,
|
|
2807
|
+
const [searchText, setSearchText] = (0, import_react16.useState)("");
|
|
2912
2808
|
const artistSearchResult = (0, import_genre_tree18.useArtistSearch)(artistBaseUrl, artistSearch ? searchText : "");
|
|
2913
2809
|
const artistGroup = artistSearch ? {
|
|
2914
2810
|
key: "artists",
|
|
2915
2811
|
label: "Artists",
|
|
2916
2812
|
items: artistSearchResult.artists.map((artist) => ({
|
|
2917
2813
|
key: artist.uuid,
|
|
2918
|
-
content: /* @__PURE__ */ (0,
|
|
2919
|
-
/* @__PURE__ */ (0,
|
|
2814
|
+
content: /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)(import_jsx_runtime40.Fragment, { children: [
|
|
2815
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("span", { className: "block truncate font-medium", children: [
|
|
2920
2816
|
artist.name,
|
|
2921
|
-
artist.disambiguation && /* @__PURE__ */ (0,
|
|
2817
|
+
artist.disambiguation && /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("span", { className: "font-normal text-[var(--color-neutral-500)]", children: [
|
|
2922
2818
|
" \xB7 ",
|
|
2923
2819
|
artist.disambiguation
|
|
2924
2820
|
] })
|
|
2925
2821
|
] }),
|
|
2926
|
-
artist.matchedAlias && /* @__PURE__ */ (0,
|
|
2822
|
+
artist.matchedAlias && /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("span", { className: "block truncate text-xs text-[var(--color-neutral-500)]", children: [
|
|
2927
2823
|
"also known as ",
|
|
2928
2824
|
artist.matchedAlias
|
|
2929
2825
|
] })
|
|
@@ -2942,9 +2838,9 @@ function GenreTreeView({
|
|
|
2942
2838
|
label: "Songs",
|
|
2943
2839
|
items: songSearchResult.songs.map((song) => ({
|
|
2944
2840
|
key: song.uuid,
|
|
2945
|
-
content: /* @__PURE__ */ (0,
|
|
2946
|
-
/* @__PURE__ */ (0,
|
|
2947
|
-
/* @__PURE__ */ (0,
|
|
2841
|
+
content: /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("span", { className: (0, import_genre_tree18.isSongSearchResultPlayable)(song) ? void 0 : "opacity-60", children: [
|
|
2842
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsx)("span", { className: "block truncate font-medium", children: song.title }),
|
|
2843
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsx)("span", { className: "block truncate text-xs text-[var(--color-neutral-500)]", children: [song.artists.map((artist) => artist.name).join(", "), song.genre?.name ?? "No genre"].filter(Boolean).join(" \xB7 ") })
|
|
2948
2844
|
] }),
|
|
2949
2845
|
onSelect: () => {
|
|
2950
2846
|
openSong(song.uuid);
|
|
@@ -2970,36 +2866,49 @@ function GenreTreeView({
|
|
|
2970
2866
|
const handleGenreSearchZoomIn = () => {
|
|
2971
2867
|
if (selectedUuid) focus.onFocusGenreChange?.(selectedUuid, "zoom-in");
|
|
2972
2868
|
};
|
|
2973
|
-
const zoomInRef = (0,
|
|
2869
|
+
const zoomInRef = (0, import_react16.useRef)(void 0);
|
|
2974
2870
|
zoomInRef.current = canZoomIn ? handleGenreSearchZoomIn : void 0;
|
|
2975
|
-
const
|
|
2976
|
-
|
|
2977
|
-
|
|
2978
|
-
|
|
2979
|
-
|
|
2980
|
-
|
|
2981
|
-
|
|
2982
|
-
|
|
2983
|
-
|
|
2984
|
-
|
|
2985
|
-
|
|
2986
|
-
|
|
2987
|
-
|
|
2988
|
-
|
|
2989
|
-
|
|
2990
|
-
|
|
2991
|
-
|
|
2992
|
-
|
|
2993
|
-
|
|
2994
|
-
|
|
2995
|
-
|
|
2996
|
-
|
|
2997
|
-
|
|
2998
|
-
|
|
2999
|
-
|
|
2871
|
+
const selectGenreFromPanel = (nodeId) => {
|
|
2872
|
+
const genrePlaylist = genrePlaylistByNodeId.get(nodeId);
|
|
2873
|
+
if (genrePlaylist) handleGenreSearchSelect(genrePlaylist);
|
|
2874
|
+
};
|
|
2875
|
+
const renderGenreBody = (relation) => {
|
|
2876
|
+
const { node } = relation;
|
|
2877
|
+
const family = /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
|
|
2878
|
+
import_genre_tree_view4.GenreNodeFamily,
|
|
2879
|
+
{
|
|
2880
|
+
node,
|
|
2881
|
+
fill: relation.fill,
|
|
2882
|
+
textColor: relation.textColor,
|
|
2883
|
+
parentNode: relation.parentNode,
|
|
2884
|
+
childNodes: relation.childNodes,
|
|
2885
|
+
onSelectNode: selectGenreFromPanel
|
|
2886
|
+
}
|
|
2887
|
+
);
|
|
2888
|
+
const ancestors = /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(import_genre_tree_view4.GenreNodeAncestors, { ancestorNodes: relation.ancestorNodes, onSelectNode: selectGenreFromPanel });
|
|
2889
|
+
const genrePlaylist = genrePlaylistByNodeId.get(node.id);
|
|
2890
|
+
const criteria = genrePlaylist?.criteria;
|
|
2891
|
+
if (!genrePlaylist || !criteria) return { primary: family, aside: ancestors };
|
|
2892
|
+
const genreUuid = criteria.uuid;
|
|
2893
|
+
const parentPlaylist = visibleGenrePlaylists.find(({ uuid }) => uuid === genrePlaylist.parent?.uuid);
|
|
2894
|
+
const canToggleSide = !readOnly && parentPlaylist !== void 0 && parentPlaylist.parent === null;
|
|
2895
|
+
const side = criteria.side ?? "core";
|
|
2896
|
+
const shareTarget = {
|
|
2897
|
+
kind: "genre",
|
|
2898
|
+
genrePlaylistUuid: genrePlaylist.uuid,
|
|
2899
|
+
name: criteria.name,
|
|
2900
|
+
scope,
|
|
2901
|
+
artistUuid
|
|
2902
|
+
};
|
|
2903
|
+
const shareUrl = getShareUrlRef.current?.(shareTarget) ?? void 0;
|
|
2904
|
+
const popSibling = canToggleSide && side === "core" ? visibleGenrePlaylists.find(
|
|
2905
|
+
(sibling) => sibling.parent?.uuid === parentPlaylist.uuid && sibling.uuid !== genrePlaylist.uuid && sibling.criteria?.side === "pop"
|
|
2906
|
+
) : void 0;
|
|
2907
|
+
return {
|
|
2908
|
+
primary: /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)(import_jsx_runtime40.Fragment, { children: [
|
|
2909
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
|
|
3000
2910
|
GenreInfoPanelBody,
|
|
3001
2911
|
{
|
|
3002
|
-
toolbar,
|
|
3003
2912
|
family,
|
|
3004
2913
|
genreUuid,
|
|
3005
2914
|
genrePlaylist,
|
|
@@ -3015,7 +2924,7 @@ function GenreTreeView({
|
|
|
3015
2924
|
onAddChild: readOnly ? void 0 : () => handleGenreCreationAction(criteria),
|
|
3016
2925
|
onRename: readOnly ? void 0 : () => handleGenreRenameAction(criteria),
|
|
3017
2926
|
onChangeParent: readOnly ? void 0 : () => showPopup(
|
|
3018
|
-
/* @__PURE__ */ (0,
|
|
2927
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
|
|
3019
2928
|
ChangeParentPopup,
|
|
3020
2929
|
{
|
|
3021
2930
|
genrePlaylist: { ...genrePlaylist, criteria },
|
|
@@ -3046,49 +2955,65 @@ function GenreTreeView({
|
|
|
3046
2955
|
}
|
|
3047
2956
|
}
|
|
3048
2957
|
),
|
|
3049
|
-
|
|
3050
|
-
}
|
|
3051
|
-
|
|
3052
|
-
|
|
3053
|
-
|
|
3054
|
-
additionalActions,
|
|
3055
|
-
readOnly,
|
|
3056
|
-
handleGenreCreationAction,
|
|
3057
|
-
handleGenreRenameAction,
|
|
3058
|
-
showPopup,
|
|
3059
|
-
hidePopup,
|
|
3060
|
-
onParentChanged,
|
|
3061
|
-
visibleGenrePlaylists,
|
|
3062
|
-
updateGenre,
|
|
3063
|
-
playback,
|
|
3064
|
-
filterArtist,
|
|
3065
|
-
scope,
|
|
3066
|
-
getBackendBaseUrl,
|
|
3067
|
-
criteriaOverviewSchema,
|
|
3068
|
-
renderGenreDetailExtras,
|
|
3069
|
-
renderArtistLink,
|
|
3070
|
-
resolvedRenderSongLink,
|
|
3071
|
-
renderSummary,
|
|
3072
|
-
renderEssentialTracks,
|
|
3073
|
-
renderSongLeading,
|
|
3074
|
-
renderSongActions,
|
|
3075
|
-
renderTracksToolbar
|
|
3076
|
-
]
|
|
3077
|
-
);
|
|
2958
|
+
renderDangerZone?.(node)
|
|
2959
|
+
] }),
|
|
2960
|
+
aside: ancestors
|
|
2961
|
+
};
|
|
2962
|
+
};
|
|
3078
2963
|
const isRotationControlled = controlledAllowWheelRotation !== void 0;
|
|
3079
2964
|
const allowWheelRotation = controlledAllowWheelRotation ?? internalAllowWheelRotation;
|
|
3080
|
-
|
|
3081
|
-
|
|
2965
|
+
let activePanel = null;
|
|
2966
|
+
if (overlayPanel) {
|
|
2967
|
+
activePanel = {
|
|
2968
|
+
title: overlayPanel.title,
|
|
2969
|
+
content: overlayPanel.content,
|
|
2970
|
+
aside: overlayPanel.extraContent,
|
|
2971
|
+
expanded: overlayPanel.expanded ?? false,
|
|
2972
|
+
onExpandedChange: overlayPanel.onExpandedChange,
|
|
2973
|
+
onClose: overlayPanel.onClose,
|
|
2974
|
+
compact: false
|
|
2975
|
+
};
|
|
2976
|
+
} else if (relations) {
|
|
2977
|
+
const { primary, aside } = renderGenreBody(relations);
|
|
2978
|
+
activePanel = {
|
|
2979
|
+
title: relations.node.name,
|
|
2980
|
+
content: primary,
|
|
2981
|
+
aside,
|
|
2982
|
+
expanded: isExpanded,
|
|
2983
|
+
onExpandedChange: changeExpanded,
|
|
2984
|
+
onClose: clearSelection,
|
|
2985
|
+
compact: true,
|
|
2986
|
+
headerAccent: { background: relations.fill, color: relations.textColor }
|
|
2987
|
+
};
|
|
2988
|
+
} else if (builtInPanel) {
|
|
2989
|
+
activePanel = {
|
|
2990
|
+
title: builtInPanel.title,
|
|
2991
|
+
content: builtInPanel.content,
|
|
2992
|
+
aside: builtInPanel.extraContent,
|
|
2993
|
+
expanded: builtInPanel.expanded,
|
|
2994
|
+
onExpandedChange: builtInPanel.onExpandedChange,
|
|
2995
|
+
onClose: builtInPanel.onClose,
|
|
2996
|
+
compact: true
|
|
2997
|
+
};
|
|
2998
|
+
}
|
|
2999
|
+
const isPanelShown = isTreeReady && activePanel !== null;
|
|
3000
|
+
const detailTab = placement === "regions" && activePanel?.onExpandedChange ? {
|
|
3001
|
+
edge: activePanel.expanded ? { label: "Shrink panel", onClick: () => activePanel.onExpandedChange?.(false) } : isCollapsed ? null : { label: "Hide panel", onClick: () => changeCollapsed(true) },
|
|
3002
|
+
center: activePanel.expanded ? null : isCollapsed ? { label: "Show panel", onClick: () => changeCollapsed(false) } : activePanel.onExpandedChange ? { label: "Extend panel", onClick: () => activePanel.onExpandedChange?.(true) } : null
|
|
3003
|
+
} : void 0;
|
|
3004
|
+
const expandButton = placement === "default" && activePanel?.onExpandedChange ? /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
|
|
3005
|
+
import_ui18.IconButton,
|
|
3082
3006
|
{
|
|
3083
|
-
|
|
3084
|
-
|
|
3085
|
-
|
|
3007
|
+
"aria-label": activePanel.expanded ? "Shrink panel" : "Extend panel",
|
|
3008
|
+
style: activePanel.headerAccent && { color: "inherit" },
|
|
3009
|
+
onClick: () => activePanel.onExpandedChange?.(!activePanel.expanded),
|
|
3010
|
+
children: activePanel.expanded ? /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(import_lucide_react16.Minimize2, { "aria-hidden": "true", className: "h-4 w-4" }) : /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(import_lucide_react16.Maximize2, { "aria-hidden": "true", className: "h-4 w-4" })
|
|
3086
3011
|
}
|
|
3087
3012
|
) : null;
|
|
3088
3013
|
const renderArtistFilter = () => {
|
|
3089
3014
|
if (isLoading || !filterArtist) return null;
|
|
3090
|
-
return /* @__PURE__ */ (0,
|
|
3091
|
-
/* @__PURE__ */ (0,
|
|
3015
|
+
return /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("span", { className: "inline-flex items-center overflow-hidden rounded-full bg-[var(--color-neutral-100)] text-sm", children: [
|
|
3016
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
|
|
3092
3017
|
"button",
|
|
3093
3018
|
{
|
|
3094
3019
|
type: "button",
|
|
@@ -3100,7 +3025,7 @@ function GenreTreeView({
|
|
|
3100
3025
|
children: filterArtist.name
|
|
3101
3026
|
}
|
|
3102
3027
|
),
|
|
3103
|
-
/* @__PURE__ */ (0,
|
|
3028
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
|
|
3104
3029
|
"button",
|
|
3105
3030
|
{
|
|
3106
3031
|
type: "button",
|
|
@@ -3112,22 +3037,22 @@ function GenreTreeView({
|
|
|
3112
3037
|
)
|
|
3113
3038
|
] });
|
|
3114
3039
|
};
|
|
3115
|
-
const actions = /* @__PURE__ */ (0,
|
|
3116
|
-
!isLoading && /* @__PURE__ */ (0,
|
|
3040
|
+
const actions = /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)(import_jsx_runtime40.Fragment, { children: [
|
|
3041
|
+
!isLoading && /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
|
|
3117
3042
|
GenreSearch,
|
|
3118
3043
|
{
|
|
3119
3044
|
genrePlaylists: visibleGenrePlaylists,
|
|
3120
3045
|
onSelect: handleGenreSearchSelect,
|
|
3121
|
-
selectedName: selectedGenrePlaylist?.name ?? builtInPanel?.title
|
|
3046
|
+
selectedName: selectedGenrePlaylist?.name ?? (typeof builtInPanel?.title === "string" ? builtInPanel.title : null),
|
|
3122
3047
|
onClear: builtInSongPanel ? () => changeSong(null) : builtInArtistPanel ? () => changeArtist(null) : handleGenreSearchClear,
|
|
3123
3048
|
onPrevious: handlePrevious,
|
|
3124
3049
|
onQueryChange: artistSearch || songSearch ? setSearchText : void 0,
|
|
3125
3050
|
extraGroups
|
|
3126
3051
|
}
|
|
3127
3052
|
),
|
|
3128
|
-
!isLoading && filterArtist && /* @__PURE__ */ (0,
|
|
3129
|
-
/* @__PURE__ */ (0,
|
|
3130
|
-
!isLoading && !isControlled && /* @__PURE__ */ (0,
|
|
3053
|
+
!isLoading && filterArtist && /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("div", { className: "hidden w-full justify-center max-md:flex", children: renderArtistFilter() }),
|
|
3054
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.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: [
|
|
3055
|
+
!isLoading && !isControlled && /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
|
|
3131
3056
|
import_ui18.SegmentedControl,
|
|
3132
3057
|
{
|
|
3133
3058
|
"aria-label": "Tree view mode",
|
|
@@ -3141,13 +3066,13 @@ function GenreTreeView({
|
|
|
3141
3066
|
]
|
|
3142
3067
|
}
|
|
3143
3068
|
),
|
|
3144
|
-
!isLoading && showDisplayOptions && /* @__PURE__ */ (0,
|
|
3069
|
+
!isLoading && showDisplayOptions && /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
|
|
3145
3070
|
"div",
|
|
3146
3071
|
{
|
|
3147
3072
|
className: "flex items-center gap-1",
|
|
3148
3073
|
role: "group",
|
|
3149
3074
|
"aria-label": "Tree display options",
|
|
3150
|
-
children: !isRotationControlled && viewMode !== "stacked" && viewMode !== "outline" && /* @__PURE__ */ (0,
|
|
3075
|
+
children: !isRotationControlled && viewMode !== "stacked" && viewMode !== "outline" && /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
|
|
3151
3076
|
import_ui18.Button,
|
|
3152
3077
|
{
|
|
3153
3078
|
variant: allowWheelRotation ? "default" : "outline",
|
|
@@ -3158,52 +3083,44 @@ function GenreTreeView({
|
|
|
3158
3083
|
)
|
|
3159
3084
|
}
|
|
3160
3085
|
),
|
|
3161
|
-
!isLoading && !readOnly && showAddRoot && /* @__PURE__ */ (0,
|
|
3086
|
+
!isLoading && !readOnly && showAddRoot && /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
|
|
3162
3087
|
import_ui18.IconTextButton,
|
|
3163
3088
|
{
|
|
3164
|
-
icon:
|
|
3089
|
+
icon: import_lucide_react15.Plus,
|
|
3165
3090
|
text: "Add root",
|
|
3166
3091
|
onClick: () => handleGenreCreationAction(null)
|
|
3167
3092
|
}
|
|
3168
3093
|
)
|
|
3169
3094
|
] })
|
|
3170
3095
|
] });
|
|
3171
|
-
return /* @__PURE__ */ (0,
|
|
3096
|
+
return /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)(
|
|
3172
3097
|
"div",
|
|
3173
3098
|
{
|
|
3174
|
-
|
|
3099
|
+
"data-left-panel": isPanelShown && !isCollapsed ? void 0 : "hidden",
|
|
3175
3100
|
className: ["genre-tree-view relative flex flex-col h-full", placement === "regions" && REGIONS_CLASS, className2].filter(Boolean).join(" "),
|
|
3176
3101
|
children: [
|
|
3177
|
-
/* @__PURE__ */ (0,
|
|
3178
|
-
/* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
|
|
3102
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
|
|
3179
3103
|
"div",
|
|
3180
3104
|
{
|
|
3181
3105
|
className: `actions-container absolute z-30 flex items-center gap-2 ${placement === "regions" ? "left-[calc(var(--layout-gutter)+var(--layout-panel-inset))] top-[calc(var(--layout-gutter)+var(--layout-panel-inset))] max-md:right-[calc(var(--layout-gutter)+var(--layout-panel-inset))] max-md:top-[var(--layout-band-top)] max-md:flex-col max-md:items-stretch" : "left-5 top-5"}`,
|
|
3182
3106
|
children: actions
|
|
3183
3107
|
}
|
|
3184
3108
|
),
|
|
3185
|
-
!isLoading && filterArtist && /* @__PURE__ */ (0,
|
|
3109
|
+
!isLoading && filterArtist && /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
|
|
3186
3110
|
"div",
|
|
3187
3111
|
{
|
|
3188
3112
|
className: `absolute left-1/2 z-30 hidden -translate-x-1/2 md:block ${placement === "regions" ? "top-[calc(var(--layout-gutter)+var(--layout-panel-inset))]" : "top-5"}`,
|
|
3189
3113
|
children: renderArtistFilter()
|
|
3190
3114
|
}
|
|
3191
3115
|
),
|
|
3192
|
-
|
|
3193
|
-
"div",
|
|
3194
|
-
{
|
|
3195
|
-
className: `absolute top-1/2 z-30 -translate-y-1/2 max-md:hidden transition-[opacity,visibility] duration-150 ease-out ${isTreeReady ? "opacity-100" : "pointer-events-none invisible opacity-0"} ${detailExpanded ? "right-[calc(var(--layout-center-right)-var(--layout-edge-tab-w))]" : isCollapsed ? "left-0" : "left-[calc(var(--layout-gutter)+var(--layout-left-w))]"}`,
|
|
3196
|
-
children: detailTab
|
|
3197
|
-
}
|
|
3198
|
-
),
|
|
3199
|
-
/* @__PURE__ */ (0, import_jsx_runtime41.jsx)("div", { className: "content-container flex-1 min-h-0 flex flex-row gap-4", children: /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { className: "tree-view-container relative flex-1 min-w-0 flex flex-col h-full", children: [
|
|
3200
|
-
!isLoading && viewMode === "outline" && floatingControlsLeading && /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("div", { className: "absolute bottom-3 right-3 z-10", children: floatingControlsLeading }),
|
|
3201
|
-
isLoading ? /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(import_genre_tree_view4.GenreTreeViewSkeleton, { viewMode }) : viewMode === "wheel" ? (
|
|
3116
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsx)("div", { className: "content-container flex-1 min-h-0 flex flex-row gap-4", children: /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("div", { className: "tree-view-container relative flex-1 min-w-0 flex flex-col h-full", children: [
|
|
3117
|
+
!isLoading && viewMode === "outline" && floatingControlsLeading && /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("div", { className: "absolute bottom-3 right-3 z-10", children: floatingControlsLeading }),
|
|
3118
|
+
isLoading ? /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(import_genre_tree_view4.GenreTreeViewSkeleton, { viewMode }) : viewMode === "wheel" ? (
|
|
3202
3119
|
// The info panel's top edge aligns with the tree's; the search bar floats `--layout-panel-inset` below it,
|
|
3203
3120
|
// and the header inset (the bar's height plus that inset) extends the header's fill behind the bar,
|
|
3204
3121
|
// Google Maps style; the 8px bottom padding mirrors the inset above the bar, and the hidden title's height is zeroed.
|
|
3205
3122
|
// The panel's own Zoom in button is hidden: the search bar carries it.
|
|
3206
|
-
/* @__PURE__ */ (0,
|
|
3123
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsx)("div", { className: "tree-container search-overlay relative flex-1 w-full min-h-0 ", children: /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(GenreTreeWheelHandoff, { skeleton: /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(import_genre_tree_view4.GenreTreeWheelSkeleton, {}), onRevealedChange: setIsWheelRevealed, children: /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
|
|
3207
3124
|
GenrePlaylistTreeWheel,
|
|
3208
3125
|
{
|
|
3209
3126
|
scope,
|
|
@@ -3212,29 +3129,26 @@ function GenreTreeView({
|
|
|
3212
3129
|
handleGenreRenameAction,
|
|
3213
3130
|
additionalActions,
|
|
3214
3131
|
onSelectedNodeChange: handleSelectedNodeChange,
|
|
3215
|
-
hideInfoPanelClose: true,
|
|
3216
|
-
hideInfoPanelTitle: true,
|
|
3217
3132
|
onNodeHover: handleNodeHover,
|
|
3218
|
-
|
|
3133
|
+
...hostPanel,
|
|
3219
3134
|
playback,
|
|
3220
3135
|
selectedNodeId,
|
|
3221
3136
|
readOnly,
|
|
3222
3137
|
allowWheelRotation,
|
|
3223
3138
|
sizeMetric: isArtistFiltered || !canSizeByViews ? "songs" : deferredSizeMetric,
|
|
3224
3139
|
busy,
|
|
3225
|
-
floatingControlsLeading: floatingControlsLeading || canSizeByViews ? /* @__PURE__ */ (0,
|
|
3140
|
+
floatingControlsLeading: floatingControlsLeading || canSizeByViews ? /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("div", { className: "flex items-center gap-2", children: [
|
|
3226
3141
|
floatingControlsLeading,
|
|
3227
|
-
canSizeByViews && /* @__PURE__ */ (0,
|
|
3142
|
+
canSizeByViews && /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(SizeMetricToggle, { value: sizeMetric, onChange: changeSizeMetric })
|
|
3228
3143
|
] }) : void 0,
|
|
3229
3144
|
defaultViewport,
|
|
3230
3145
|
viewportRestore,
|
|
3231
|
-
onViewportChange
|
|
3232
|
-
...infoPanelCuration
|
|
3146
|
+
onViewportChange
|
|
3233
3147
|
}
|
|
3234
3148
|
) }) })
|
|
3235
3149
|
) : viewMode === "pop-core" ? (
|
|
3236
3150
|
// Same as the wheel: the header inset extends its fill behind the floating search bar, Google Maps style.
|
|
3237
|
-
/* @__PURE__ */ (0,
|
|
3151
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsx)("div", { className: "tree-container search-overlay relative flex-1 w-full min-h-0 ", children: /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(GenreTreeWheelHandoff, { skeleton: /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(import_genre_tree_view4.GenreTreeWheelSkeleton, {}), onRevealedChange: setIsWheelRevealed, children: /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
|
|
3238
3152
|
GenrePlaylistTreeWheelRadialPopCore,
|
|
3239
3153
|
{
|
|
3240
3154
|
scope,
|
|
@@ -3243,28 +3157,25 @@ function GenreTreeView({
|
|
|
3243
3157
|
handleGenreRenameAction,
|
|
3244
3158
|
additionalActions,
|
|
3245
3159
|
onSelectedNodeChange: handleSelectedNodeChange,
|
|
3246
|
-
hideInfoPanelClose: true,
|
|
3247
|
-
hideInfoPanelTitle: true,
|
|
3248
3160
|
onNodeHover: handleNodeHover,
|
|
3249
|
-
|
|
3161
|
+
...hostPanel,
|
|
3250
3162
|
playback,
|
|
3251
3163
|
selectedNodeId,
|
|
3252
3164
|
readOnly,
|
|
3253
3165
|
allowWheelRotation,
|
|
3254
3166
|
sizeMetric: isArtistFiltered || !canSizeByViews ? "songs" : deferredSizeMetric,
|
|
3255
3167
|
busy,
|
|
3256
|
-
floatingControlsLeading: floatingControlsLeading || canSizeByViews ? /* @__PURE__ */ (0,
|
|
3168
|
+
floatingControlsLeading: floatingControlsLeading || canSizeByViews ? /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("div", { className: "flex items-center gap-2", children: [
|
|
3257
3169
|
floatingControlsLeading,
|
|
3258
|
-
canSizeByViews && /* @__PURE__ */ (0,
|
|
3170
|
+
canSizeByViews && /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(SizeMetricToggle, { value: sizeMetric, onChange: changeSizeMetric })
|
|
3259
3171
|
] }) : void 0,
|
|
3260
3172
|
defaultViewport,
|
|
3261
3173
|
viewportRestore,
|
|
3262
3174
|
onViewportChange,
|
|
3263
|
-
...infoPanelCuration,
|
|
3264
3175
|
...focus
|
|
3265
3176
|
}
|
|
3266
3177
|
) }) })
|
|
3267
|
-
) : viewMode === "outline" ? /* @__PURE__ */ (0,
|
|
3178
|
+
) : viewMode === "outline" ? /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("div", { className: "tree-container flex-1 min-h-0 w-full overflow-y-auto relative", children: /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
|
|
3268
3179
|
GenrePlaylistTreeWheelRadialPopCore,
|
|
3269
3180
|
{
|
|
3270
3181
|
outline: true,
|
|
@@ -3274,22 +3185,19 @@ function GenreTreeView({
|
|
|
3274
3185
|
handleGenreRenameAction,
|
|
3275
3186
|
additionalActions,
|
|
3276
3187
|
onSelectedNodeChange: handleSelectedNodeChange,
|
|
3277
|
-
hideInfoPanelClose: true,
|
|
3278
|
-
hideInfoPanelTitle: true,
|
|
3279
3188
|
onNodeHover: handleNodeHover,
|
|
3280
|
-
|
|
3189
|
+
...hostPanel,
|
|
3281
3190
|
playback,
|
|
3282
3191
|
selectedNodeId,
|
|
3283
|
-
readOnly
|
|
3284
|
-
...infoPanelCuration
|
|
3192
|
+
readOnly
|
|
3285
3193
|
}
|
|
3286
|
-
) }) : /* @__PURE__ */ (0,
|
|
3287
|
-
([uuid, genrePlaylistTreePerRoot]
|
|
3288
|
-
return /* @__PURE__ */ (0,
|
|
3194
|
+
) }) : /* @__PURE__ */ (0, import_jsx_runtime40.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(
|
|
3195
|
+
([uuid, genrePlaylistTreePerRoot]) => {
|
|
3196
|
+
return /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
|
|
3289
3197
|
"div",
|
|
3290
3198
|
{
|
|
3291
3199
|
className: "tree-per-root-container relative shrink-0 h-[28rem] mt-2 mr-16 p-2 bg-[var(--color-neutral-100)] rounded-lg",
|
|
3292
|
-
children: /* @__PURE__ */ (0,
|
|
3200
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("div", { className: "graph-container relative z-10 h-full", children: /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
|
|
3293
3201
|
GenrePlaylistTreePerRoot,
|
|
3294
3202
|
{
|
|
3295
3203
|
scope,
|
|
@@ -3299,26 +3207,45 @@ function GenreTreeView({
|
|
|
3299
3207
|
handleGenreRenameAction,
|
|
3300
3208
|
additionalActions,
|
|
3301
3209
|
onSelectedNodeChange: handleSelectedNodeChange,
|
|
3302
|
-
hideInfoPanelClose: true,
|
|
3303
|
-
hideInfoPanelTitle: true,
|
|
3304
3210
|
onNodeHover: handleNodeHover,
|
|
3305
|
-
|
|
3211
|
+
...hostPanel,
|
|
3306
3212
|
playback,
|
|
3307
3213
|
selectedNodeId: uuid === selectedGenrePlaylist?.root.uuid ? selectedNodeId : null,
|
|
3308
3214
|
readOnly,
|
|
3309
3215
|
wheelZoom: "modifier",
|
|
3310
3216
|
defaultViewport: uuid === selectedGenrePlaylist?.root.uuid ? defaultViewport : void 0,
|
|
3311
3217
|
viewportRestore: uuid === selectedGenrePlaylist?.root.uuid && uuid === restoreRootUuid ? viewportRestore : void 0,
|
|
3312
|
-
onViewportChange: uuid === selectedGenrePlaylist?.root.uuid ? onViewportChange : void 0
|
|
3313
|
-
...infoPanelCuration,
|
|
3314
|
-
overlayPanel: rootIndex === 0 ? activeOverlayPanel : void 0
|
|
3218
|
+
onViewportChange: uuid === selectedGenrePlaylist?.root.uuid ? onViewportChange : void 0
|
|
3315
3219
|
}
|
|
3316
3220
|
) })
|
|
3317
3221
|
},
|
|
3318
3222
|
uuid
|
|
3319
3223
|
);
|
|
3320
3224
|
}
|
|
3321
|
-
) })
|
|
3225
|
+
) }),
|
|
3226
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
|
|
3227
|
+
import_ui18.DetailPanel,
|
|
3228
|
+
{
|
|
3229
|
+
ref: panelRef,
|
|
3230
|
+
side: "left",
|
|
3231
|
+
title: activePanel?.title ?? "",
|
|
3232
|
+
hideTitle: activePanel?.compact,
|
|
3233
|
+
hideClose: activePanel?.compact,
|
|
3234
|
+
headerAccent: activePanel?.headerAccent,
|
|
3235
|
+
headerActions: expandButton,
|
|
3236
|
+
onClose: activePanel?.onClose ?? noop,
|
|
3237
|
+
collapsed: isCollapsed || !isTreeReady || !activePanel,
|
|
3238
|
+
expanded: activePanel?.expanded,
|
|
3239
|
+
onExpandedChange: activePanel?.onExpandedChange,
|
|
3240
|
+
aside: activePanel?.aside,
|
|
3241
|
+
edgeTab: detailTab,
|
|
3242
|
+
headerClassName: activePanel?.compact ? "pt-[calc(var(--layout-search-h)+var(--layout-panel-inset)+0.5rem)]" : void 0,
|
|
3243
|
+
children: activePanel?.aside && !activePanel.expanded ? /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)(import_jsx_runtime40.Fragment, { children: [
|
|
3244
|
+
activePanel.content,
|
|
3245
|
+
activePanel.aside
|
|
3246
|
+
] }) : activePanel?.content
|
|
3247
|
+
}
|
|
3248
|
+
)
|
|
3322
3249
|
] }) })
|
|
3323
3250
|
]
|
|
3324
3251
|
}
|
|
@@ -3326,12 +3253,12 @@ function GenreTreeView({
|
|
|
3326
3253
|
}
|
|
3327
3254
|
|
|
3328
3255
|
// src/genre-tree/GenreDetailPanel.tsx
|
|
3329
|
-
var
|
|
3256
|
+
var import_react17 = require("react");
|
|
3330
3257
|
var import_genre_tree_view5 = require("@behindthemusictree/genre-tree-view");
|
|
3331
3258
|
var import_ui19 = require("@behindthemusictree/ui");
|
|
3259
|
+
var import_lucide_react17 = require("lucide-react");
|
|
3332
3260
|
var import_genre_tree20 = require("@behindthemusictree/app-kit/genre-tree");
|
|
3333
|
-
var
|
|
3334
|
-
var ITEM_COUNT_LABEL = "Songs";
|
|
3261
|
+
var import_jsx_runtime41 = require("react/jsx-runtime");
|
|
3335
3262
|
var RELATIVE_ITEM_COUNT = 1;
|
|
3336
3263
|
function toNode(genre, parentId) {
|
|
3337
3264
|
return {
|
|
@@ -3355,11 +3282,12 @@ function GenreDetailPanel({
|
|
|
3355
3282
|
collapsed,
|
|
3356
3283
|
expanded,
|
|
3357
3284
|
onExpandedChange,
|
|
3285
|
+
edgeTab,
|
|
3358
3286
|
extras
|
|
3359
3287
|
}) {
|
|
3360
3288
|
const { data: detail, isPending, isError } = (0, import_genre_tree20.useFetchGenreDetail)(genreUuid, scope, getBackendBaseUrl);
|
|
3361
3289
|
const playback = useGenrePlaylistPlayback({ scope, genrePlaylists: [] });
|
|
3362
|
-
const view = (0,
|
|
3290
|
+
const view = (0, import_react17.useMemo)(() => {
|
|
3363
3291
|
if (!detail) return null;
|
|
3364
3292
|
const rootColor = (0, import_genre_tree_view5.getGenreTreeColor)(detail.root.wikidataId);
|
|
3365
3293
|
const relative = (genre, parentId) => ({
|
|
@@ -3367,7 +3295,7 @@ function GenreDetailPanel({
|
|
|
3367
3295
|
fill: (0, import_genre_tree_view5.tintSurface)(rootColor),
|
|
3368
3296
|
textColor: import_genre_tree_view5.TEXT_COLOR
|
|
3369
3297
|
});
|
|
3370
|
-
const
|
|
3298
|
+
const ancestors2 = [...detail.ascendants].sort((a, b) => b.degree - a.degree);
|
|
3371
3299
|
return {
|
|
3372
3300
|
node: {
|
|
3373
3301
|
id: detail.uuid,
|
|
@@ -3379,57 +3307,72 @@ function GenreDetailPanel({
|
|
|
3379
3307
|
fill: rootColor,
|
|
3380
3308
|
parentNode: detail.parent ? relative(detail.parent, null) : null,
|
|
3381
3309
|
childNodes: detail.children.map((child) => relative(child, detail.uuid)),
|
|
3382
|
-
ancestorNodes:
|
|
3383
|
-
({ ascendant }, index) => relative(ascendant, index === 0 ? null :
|
|
3310
|
+
ancestorNodes: ancestors2.map(
|
|
3311
|
+
({ ascendant }, index) => relative(ascendant, index === 0 ? null : ancestors2[index - 1].ascendant.uuid)
|
|
3384
3312
|
)
|
|
3385
3313
|
};
|
|
3386
3314
|
}, [detail]);
|
|
3387
3315
|
if (isError) {
|
|
3388
|
-
return /* @__PURE__ */ (0,
|
|
3316
|
+
return /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("div", { role: "alert", className: "p-4 text-sm text-[var(--color-text)]", children: "This genre could not be loaded." });
|
|
3389
3317
|
}
|
|
3390
3318
|
if (isPending || !detail || !view) {
|
|
3391
|
-
return /* @__PURE__ */ (0,
|
|
3392
|
-
/* @__PURE__ */ (0,
|
|
3393
|
-
/* @__PURE__ */ (0,
|
|
3394
|
-
/* @__PURE__ */ (0,
|
|
3319
|
+
return /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { className: "flex flex-col gap-3 p-4", "aria-busy": "true", "data-testid": "genre-detail-panel-skeleton", children: [
|
|
3320
|
+
/* @__PURE__ */ (0, import_jsx_runtime41.jsx)(import_ui19.Skeleton, { className: "h-6 w-2/3" }),
|
|
3321
|
+
/* @__PURE__ */ (0, import_jsx_runtime41.jsx)(import_ui19.Skeleton, { className: "h-4 w-full" }),
|
|
3322
|
+
/* @__PURE__ */ (0, import_jsx_runtime41.jsx)(import_ui19.Skeleton, { className: "h-4 w-3/4" })
|
|
3395
3323
|
] });
|
|
3396
3324
|
}
|
|
3397
|
-
const
|
|
3398
|
-
|
|
3399
|
-
|
|
3400
|
-
{
|
|
3401
|
-
toolbar: sections.toolbar,
|
|
3402
|
-
family: sections.family,
|
|
3403
|
-
genreUuid: detail.uuid,
|
|
3404
|
-
genrePlaylist: { ...detail.criteriaPlaylist, tracksCount: detail.tracksCount },
|
|
3405
|
-
wikidataId: detail.wikidataId,
|
|
3406
|
-
scope,
|
|
3407
|
-
getBackendBaseUrl,
|
|
3408
|
-
playback,
|
|
3409
|
-
band: { node, onZoomIn, shareUrl, shareTarget: shareUrl ? shareTarget : void 0 },
|
|
3410
|
-
extras
|
|
3411
|
-
}
|
|
3412
|
-
),
|
|
3413
|
-
aside: null
|
|
3414
|
-
});
|
|
3415
|
-
return /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
|
|
3416
|
-
import_genre_tree_view5.InfoPanel,
|
|
3325
|
+
const selectGenre = (nodeId) => onSelectGenre(nodeId);
|
|
3326
|
+
const family = /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
|
|
3327
|
+
import_genre_tree_view5.GenreNodeFamily,
|
|
3417
3328
|
{
|
|
3418
3329
|
node: view.node,
|
|
3419
3330
|
fill: view.fill,
|
|
3420
3331
|
textColor: import_genre_tree_view5.ACCENT_TEXT_COLOR,
|
|
3421
3332
|
parentNode: view.parentNode,
|
|
3422
3333
|
childNodes: view.childNodes,
|
|
3423
|
-
|
|
3334
|
+
onSelectNode: selectGenre
|
|
3335
|
+
}
|
|
3336
|
+
);
|
|
3337
|
+
const ancestors = /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(import_genre_tree_view5.GenreNodeAncestors, { ancestorNodes: view.ancestorNodes, onSelectNode: selectGenre });
|
|
3338
|
+
return /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)(
|
|
3339
|
+
import_ui19.DetailPanel,
|
|
3340
|
+
{
|
|
3424
3341
|
side: "left",
|
|
3342
|
+
title: view.node.name,
|
|
3343
|
+
headerAccent: { background: view.fill, color: import_genre_tree_view5.ACCENT_TEXT_COLOR },
|
|
3344
|
+
headerActions: onExpandedChange ? /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
|
|
3345
|
+
import_ui19.IconButton,
|
|
3346
|
+
{
|
|
3347
|
+
"aria-label": expanded ? "Shrink panel" : "Extend panel",
|
|
3348
|
+
style: { color: "inherit" },
|
|
3349
|
+
onClick: () => onExpandedChange(!expanded),
|
|
3350
|
+
children: expanded ? /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(import_lucide_react17.Minimize2, { "aria-hidden": "true", className: "h-4 w-4" }) : /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(import_lucide_react17.Maximize2, { "aria-hidden": "true", className: "h-4 w-4" })
|
|
3351
|
+
}
|
|
3352
|
+
) : void 0,
|
|
3425
3353
|
onClose,
|
|
3426
|
-
|
|
3427
|
-
itemCountLabel: ITEM_COUNT_LABEL,
|
|
3428
|
-
renderInfoPanelBody: renderBody,
|
|
3354
|
+
collapsed,
|
|
3429
3355
|
expanded,
|
|
3430
3356
|
onExpandedChange,
|
|
3431
|
-
|
|
3432
|
-
|
|
3357
|
+
edgeTab,
|
|
3358
|
+
aside: ancestors,
|
|
3359
|
+
children: [
|
|
3360
|
+
/* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
|
|
3361
|
+
GenreInfoPanelBody,
|
|
3362
|
+
{
|
|
3363
|
+
family,
|
|
3364
|
+
genreUuid: detail.uuid,
|
|
3365
|
+
genrePlaylist: { ...detail.criteriaPlaylist, tracksCount: detail.tracksCount },
|
|
3366
|
+
wikidataId: detail.wikidataId,
|
|
3367
|
+
scope,
|
|
3368
|
+
getBackendBaseUrl,
|
|
3369
|
+
playback,
|
|
3370
|
+
band: { node: view.node, onZoomIn, shareUrl, shareTarget: shareUrl ? shareTarget : void 0 },
|
|
3371
|
+
extras
|
|
3372
|
+
}
|
|
3373
|
+
),
|
|
3374
|
+
!expanded && ancestors
|
|
3375
|
+
]
|
|
3433
3376
|
}
|
|
3434
3377
|
);
|
|
3435
3378
|
}
|
|
@@ -3438,13 +3381,13 @@ function GenreDetailPanel({
|
|
|
3438
3381
|
var import_genre_tree_view6 = require("@behindthemusictree/genre-tree-view");
|
|
3439
3382
|
|
|
3440
3383
|
// src/genre-tree/track-list-sidebar/TrackListSidebar.tsx
|
|
3441
|
-
var
|
|
3442
|
-
var
|
|
3384
|
+
var import_react18 = require("react");
|
|
3385
|
+
var import_lucide_react18 = require("lucide-react");
|
|
3443
3386
|
var import_genre_tree21 = require("@behindthemusictree/app-kit/genre-tree");
|
|
3444
3387
|
var import_genre_tree22 = require("@behindthemusictree/app-kit/genre-tree");
|
|
3445
|
-
var
|
|
3446
|
-
var
|
|
3447
|
-
var useBrowserLayoutEffect = typeof window === "undefined" ?
|
|
3388
|
+
var import_track_noun4 = require("@behindthemusictree/app-kit/track-noun");
|
|
3389
|
+
var import_jsx_runtime42 = require("react/jsx-runtime");
|
|
3390
|
+
var useBrowserLayoutEffect = typeof window === "undefined" ? import_react18.useEffect : import_react18.useLayoutEffect;
|
|
3448
3391
|
function TrackListSidebar({
|
|
3449
3392
|
className: className2 = "",
|
|
3450
3393
|
renderDuration,
|
|
@@ -3457,17 +3400,17 @@ function TrackListSidebar({
|
|
|
3457
3400
|
renderSongLink
|
|
3458
3401
|
}) {
|
|
3459
3402
|
const { trackList, loadMore, autoAdvanceScrollRequest } = (0, import_genre_tree21.useTrackList)();
|
|
3460
|
-
const trackNoun = (0,
|
|
3461
|
-
const trackListRef = (0,
|
|
3462
|
-
const previousOriginRef = (0,
|
|
3463
|
-
const handledAutoAdvanceRequestIdRef = (0,
|
|
3464
|
-
const shouldFollowPlaybackRef = (0,
|
|
3465
|
-
const programmaticScrollTopRef = (0,
|
|
3466
|
-
const userScrollIntentRef = (0,
|
|
3467
|
-
const userScrollIntentTimerRef = (0,
|
|
3468
|
-
const loadMoreSentinelRef = (0,
|
|
3403
|
+
const trackNoun = (0, import_track_noun4.useTrackNoun)();
|
|
3404
|
+
const trackListRef = (0, import_react18.useRef)(null);
|
|
3405
|
+
const previousOriginRef = (0, import_react18.useRef)(trackList?.origin ?? null);
|
|
3406
|
+
const handledAutoAdvanceRequestIdRef = (0, import_react18.useRef)(null);
|
|
3407
|
+
const shouldFollowPlaybackRef = (0, import_react18.useRef)(true);
|
|
3408
|
+
const programmaticScrollTopRef = (0, import_react18.useRef)(null);
|
|
3409
|
+
const userScrollIntentRef = (0, import_react18.useRef)(false);
|
|
3410
|
+
const userScrollIntentTimerRef = (0, import_react18.useRef)(null);
|
|
3411
|
+
const loadMoreSentinelRef = (0, import_react18.useRef)(null);
|
|
3469
3412
|
const hasMore = !!trackList && trackList.nextPage !== null;
|
|
3470
|
-
(0,
|
|
3413
|
+
(0, import_react18.useEffect)(() => {
|
|
3471
3414
|
const sentinel = loadMoreSentinelRef.current;
|
|
3472
3415
|
if (!hasMore || !sentinel) return;
|
|
3473
3416
|
const observer = new IntersectionObserver((entries) => {
|
|
@@ -3487,11 +3430,11 @@ function TrackListSidebar({
|
|
|
3487
3430
|
programmaticScrollTopRef.current = null;
|
|
3488
3431
|
if (trackListRef.current) trackListRef.current.scrollTop = 0;
|
|
3489
3432
|
}, [trackList?.origin]);
|
|
3490
|
-
(0,
|
|
3433
|
+
(0, import_react18.useEffect)(() => {
|
|
3491
3434
|
const list = trackListRef.current;
|
|
3492
3435
|
if (!isCollapsed && list?.scrollTop === 0) shouldFollowPlaybackRef.current = true;
|
|
3493
3436
|
}, [isCollapsed]);
|
|
3494
|
-
(0,
|
|
3437
|
+
(0, import_react18.useEffect)(
|
|
3495
3438
|
() => () => {
|
|
3496
3439
|
if (userScrollIntentTimerRef.current !== null) clearTimeout(userScrollIntentTimerRef.current);
|
|
3497
3440
|
},
|
|
@@ -3545,25 +3488,25 @@ function TrackListSidebar({
|
|
|
3545
3488
|
}
|
|
3546
3489
|
};
|
|
3547
3490
|
const positionClasses = layout === "inline" ? "relative w-full flex h-full flex-col" : "fixed right-0 w-[50rem] flex flex-col";
|
|
3548
|
-
return trackList ? /* @__PURE__ */ (0,
|
|
3491
|
+
return trackList ? /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)(
|
|
3549
3492
|
"div",
|
|
3550
3493
|
{
|
|
3551
3494
|
"data-theme": "dark",
|
|
3552
3495
|
className: `track-list-sidebar ${positionClasses} rounded-2xl bg-[var(--color-surface)] pb-1 ${className2}`,
|
|
3553
3496
|
style: layout === "fixed" ? { top: "63.5px", maxHeight: "calc(100vh - 63.5px - 79px)" } : void 0,
|
|
3554
3497
|
children: [
|
|
3555
|
-
/* @__PURE__ */ (0,
|
|
3556
|
-
/* @__PURE__ */ (0,
|
|
3557
|
-
/* @__PURE__ */ (0,
|
|
3558
|
-
/* @__PURE__ */ (0,
|
|
3559
|
-
/* @__PURE__ */ (0,
|
|
3498
|
+
/* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { className: "header flex h-16 items-center px-4 py-2 text-[var(--color-text)]", children: [
|
|
3499
|
+
/* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { className: "min-w-0 flex flex-1 flex-col justify-center", children: [
|
|
3500
|
+
/* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { className: "origin flex text-xl", children: [
|
|
3501
|
+
/* @__PURE__ */ (0, import_jsx_runtime42.jsx)("div", { className: "from h-auto flex flex-col justify-center items-center mr-2", children: "From" }),
|
|
3502
|
+
/* @__PURE__ */ (0, import_jsx_runtime42.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_runtime42.jsx)("div", { className: "name max-w-full truncate", children: trackList.origin.label }) })
|
|
3560
3503
|
] }),
|
|
3561
|
-
/* @__PURE__ */ (0,
|
|
3504
|
+
/* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { className: "info flex items-center text-sm text-[var(--color-text-muted)]", children: [
|
|
3562
3505
|
trackList.origin.type === import_genre_tree22.TrackListOriginType.GENRE_PLAYLIST ? "Genre \u2022 " : trackList.origin.type === import_genre_tree22.TrackListOriginType.ARTIST ? "Artist \u2022 " : `${trackNoun.singular} playlist \u2022 `,
|
|
3563
3506
|
`${trackList.total} ${trackList.total > 1 ? trackNoun.plural : trackNoun.singular}`
|
|
3564
3507
|
] })
|
|
3565
3508
|
] }),
|
|
3566
|
-
(isCollapsed && onExpand || !isCollapsed && onMinimize) && /* @__PURE__ */ (0,
|
|
3509
|
+
(isCollapsed && onExpand || !isCollapsed && onMinimize) && /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
|
|
3567
3510
|
"button",
|
|
3568
3511
|
{
|
|
3569
3512
|
type: "button",
|
|
@@ -3572,11 +3515,11 @@ function TrackListSidebar({
|
|
|
3572
3515
|
"aria-expanded": !isCollapsed,
|
|
3573
3516
|
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"}`,
|
|
3574
3517
|
onClick: isCollapsed ? onExpand : onMinimize,
|
|
3575
|
-
children: /* @__PURE__ */ (0,
|
|
3518
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(import_lucide_react18.ListMusic, { "aria-hidden": "true", className: "h-5 w-5" })
|
|
3576
3519
|
}
|
|
3577
3520
|
)
|
|
3578
3521
|
] }),
|
|
3579
|
-
!isCollapsed && /* @__PURE__ */ (0,
|
|
3522
|
+
!isCollapsed && /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)(
|
|
3580
3523
|
"ul",
|
|
3581
3524
|
{
|
|
3582
3525
|
ref: trackListRef,
|
|
@@ -3586,7 +3529,7 @@ function TrackListSidebar({
|
|
|
3586
3529
|
onPointerDown: markUserScrollIntent,
|
|
3587
3530
|
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",
|
|
3588
3531
|
children: [
|
|
3589
|
-
trackList.tracks.map((track, index) => /* @__PURE__ */ (0,
|
|
3532
|
+
trackList.tracks.map((track, index) => /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("li", { "data-track-uuid": track.uuid, children: /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
|
|
3590
3533
|
TrackItem,
|
|
3591
3534
|
{
|
|
3592
3535
|
track,
|
|
@@ -3597,7 +3540,7 @@ function TrackListSidebar({
|
|
|
3597
3540
|
renderSongLink
|
|
3598
3541
|
}
|
|
3599
3542
|
) }, track.uuid)),
|
|
3600
|
-
hasMore && /* @__PURE__ */ (0,
|
|
3543
|
+
hasMore && /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("li", { ref: loadMoreSentinelRef, "aria-hidden": "true", className: "h-px" })
|
|
3601
3544
|
]
|
|
3602
3545
|
}
|
|
3603
3546
|
)
|
|
@@ -3607,16 +3550,17 @@ function TrackListSidebar({
|
|
|
3607
3550
|
}
|
|
3608
3551
|
|
|
3609
3552
|
// src/genre-tree/PlayerPanel.tsx
|
|
3610
|
-
var
|
|
3611
|
-
var
|
|
3553
|
+
var import_react19 = require("react");
|
|
3554
|
+
var import_tailwind_merge = require("tailwind-merge");
|
|
3612
3555
|
var import_player13 = require("@behindthemusictree/app-kit/player");
|
|
3613
3556
|
var import_genre_tree24 = require("@behindthemusictree/app-kit/genre-tree");
|
|
3557
|
+
var import_ui20 = require("@behindthemusictree/ui");
|
|
3614
3558
|
|
|
3615
3559
|
// src/genre-tree/PlayerControls.tsx
|
|
3616
|
-
var
|
|
3560
|
+
var import_lucide_react19 = require("lucide-react");
|
|
3617
3561
|
var import_genre_tree23 = require("@behindthemusictree/app-kit/genre-tree");
|
|
3618
3562
|
var import_player12 = require("@behindthemusictree/app-kit/player");
|
|
3619
|
-
var
|
|
3563
|
+
var import_jsx_runtime43 = require("react/jsx-runtime");
|
|
3620
3564
|
function PlayerControls() {
|
|
3621
3565
|
const {
|
|
3622
3566
|
duration,
|
|
@@ -3635,15 +3579,15 @@ function PlayerControls() {
|
|
|
3635
3579
|
const safeDuration = Number.isFinite(duration) && duration > 0 ? duration : 0;
|
|
3636
3580
|
const safeCurrentTime = Number.isFinite(currentTime) ? Math.max(0, Math.min(currentTime, safeDuration)) : 0;
|
|
3637
3581
|
const isPlaying = playState === import_player12.PlayStates.PLAYING;
|
|
3638
|
-
return /* @__PURE__ */ (0,
|
|
3582
|
+
return /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)(
|
|
3639
3583
|
"section",
|
|
3640
3584
|
{
|
|
3641
3585
|
"aria-label": "Player controls",
|
|
3642
3586
|
className: "player-controls flex shrink-0 flex-col gap-2 border-b border-zinc-800 px-3 py-2 text-zinc-200",
|
|
3643
3587
|
children: [
|
|
3644
|
-
/* @__PURE__ */ (0,
|
|
3645
|
-
/* @__PURE__ */ (0,
|
|
3646
|
-
/* @__PURE__ */ (0,
|
|
3588
|
+
/* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("div", { className: "flex min-w-0 items-center gap-2 text-xs tabular-nums text-zinc-400", children: [
|
|
3589
|
+
/* @__PURE__ */ (0, import_jsx_runtime43.jsx)("span", { "aria-label": "Elapsed time", children: (0, import_genre_tree23.formatTime)(safeCurrentTime) }),
|
|
3590
|
+
/* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
|
|
3647
3591
|
"input",
|
|
3648
3592
|
{
|
|
3649
3593
|
"aria-label": "Seek",
|
|
@@ -3657,11 +3601,11 @@ function PlayerControls() {
|
|
|
3657
3601
|
onChange: (event) => seekTo(Number(event.currentTarget.value))
|
|
3658
3602
|
}
|
|
3659
3603
|
),
|
|
3660
|
-
/* @__PURE__ */ (0,
|
|
3604
|
+
/* @__PURE__ */ (0, import_jsx_runtime43.jsx)("span", { "aria-label": "Duration", children: (0, import_genre_tree23.formatTime)(safeDuration) })
|
|
3661
3605
|
] }),
|
|
3662
|
-
/* @__PURE__ */ (0,
|
|
3663
|
-
/* @__PURE__ */ (0,
|
|
3664
|
-
/* @__PURE__ */ (0,
|
|
3606
|
+
/* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("div", { className: "grid min-h-9 grid-cols-[1fr_auto_1fr] items-center gap-3", children: [
|
|
3607
|
+
/* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("div", { className: "col-start-2 flex items-center justify-center gap-2", children: [
|
|
3608
|
+
/* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
|
|
3665
3609
|
"button",
|
|
3666
3610
|
{
|
|
3667
3611
|
type: "button",
|
|
@@ -3670,10 +3614,10 @@ function PlayerControls() {
|
|
|
3670
3614
|
disabled: !isReady || !hasPreviousTrack,
|
|
3671
3615
|
onClick: playPreviousTrack,
|
|
3672
3616
|
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",
|
|
3673
|
-
children: /* @__PURE__ */ (0,
|
|
3617
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(import_lucide_react19.SkipBack, { "aria-hidden": "true", className: "h-4 w-4" })
|
|
3674
3618
|
}
|
|
3675
3619
|
),
|
|
3676
|
-
/* @__PURE__ */ (0,
|
|
3620
|
+
/* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
|
|
3677
3621
|
"button",
|
|
3678
3622
|
{
|
|
3679
3623
|
type: "button",
|
|
@@ -3682,10 +3626,10 @@ function PlayerControls() {
|
|
|
3682
3626
|
disabled: !isReady,
|
|
3683
3627
|
onClick: handlePlayPauseAction,
|
|
3684
3628
|
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",
|
|
3685
|
-
children: isPlaying ? /* @__PURE__ */ (0,
|
|
3629
|
+
children: isPlaying ? /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(import_lucide_react19.Pause, { "aria-hidden": "true", className: "h-4 w-4", fill: "currentColor" }) : /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(import_lucide_react19.Play, { "aria-hidden": "true", className: "h-4 w-4", fill: "currentColor" })
|
|
3686
3630
|
}
|
|
3687
3631
|
),
|
|
3688
|
-
/* @__PURE__ */ (0,
|
|
3632
|
+
/* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
|
|
3689
3633
|
"button",
|
|
3690
3634
|
{
|
|
3691
3635
|
type: "button",
|
|
@@ -3694,14 +3638,14 @@ function PlayerControls() {
|
|
|
3694
3638
|
disabled: !isReady || !hasNextTrack,
|
|
3695
3639
|
onClick: playNextTrack,
|
|
3696
3640
|
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",
|
|
3697
|
-
children: /* @__PURE__ */ (0,
|
|
3641
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(import_lucide_react19.SkipForward, { "aria-hidden": "true", className: "h-4 w-4" })
|
|
3698
3642
|
}
|
|
3699
3643
|
)
|
|
3700
3644
|
] }),
|
|
3701
|
-
/* @__PURE__ */ (0,
|
|
3702
|
-
volume === 0 ? /* @__PURE__ */ (0,
|
|
3703
|
-
/* @__PURE__ */ (0,
|
|
3704
|
-
/* @__PURE__ */ (0,
|
|
3645
|
+
/* @__PURE__ */ (0, import_jsx_runtime43.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: [
|
|
3646
|
+
volume === 0 ? /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(import_lucide_react19.VolumeX, { "aria-hidden": "true", className: "h-[0.7rem] w-[0.7rem] shrink-0" }) : /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(import_lucide_react19.Volume2, { "aria-hidden": "true", className: "h-[0.7rem] w-[0.7rem] shrink-0" }),
|
|
3647
|
+
/* @__PURE__ */ (0, import_jsx_runtime43.jsx)("span", { className: "sr-only", children: "Volume" }),
|
|
3648
|
+
/* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
|
|
3705
3649
|
"input",
|
|
3706
3650
|
{
|
|
3707
3651
|
"aria-label": "Volume",
|
|
@@ -3723,7 +3667,7 @@ function PlayerControls() {
|
|
|
3723
3667
|
}
|
|
3724
3668
|
|
|
3725
3669
|
// src/genre-tree/PlayerPanel.tsx
|
|
3726
|
-
var
|
|
3670
|
+
var import_jsx_runtime44 = require("react/jsx-runtime");
|
|
3727
3671
|
var PANEL_ID = "player-panel";
|
|
3728
3672
|
var DEFAULT_EXTENDED_WIDTH = "calc(100vw - var(--layout-center-left) - var(--layout-gutter))";
|
|
3729
3673
|
function PlayerPanel({
|
|
@@ -3737,12 +3681,12 @@ function PlayerPanel({
|
|
|
3737
3681
|
}) {
|
|
3738
3682
|
const { playerTrackObject } = (0, import_player13.usePlayer)();
|
|
3739
3683
|
const { toggleTrackListSidebar, isTrackListSidebarVisible } = (0, import_genre_tree24.useTrackListSidebarVisibility)();
|
|
3740
|
-
const [lastLoadedTrackTitle, setLastLoadedTrackTitle] = (0,
|
|
3684
|
+
const [lastLoadedTrackTitle, setLastLoadedTrackTitle] = (0, import_react19.useState)("");
|
|
3741
3685
|
const loadedTrackTitle = playerTrackObject?.track.title;
|
|
3742
|
-
(0,
|
|
3686
|
+
(0, import_react19.useEffect)(() => {
|
|
3743
3687
|
if (loadedTrackTitle) setLastLoadedTrackTitle(loadedTrackTitle);
|
|
3744
3688
|
}, [loadedTrackTitle]);
|
|
3745
|
-
const [uncontrolledExtended, setUncontrolledExtended] = (0,
|
|
3689
|
+
const [uncontrolledExtended, setUncontrolledExtended] = (0, import_react19.useState)(false);
|
|
3746
3690
|
const isExtendRequested = expanded ?? uncontrolledExtended;
|
|
3747
3691
|
const setIsExtendRequested = (next) => {
|
|
3748
3692
|
setUncontrolledExtended(next);
|
|
@@ -3763,11 +3707,11 @@ function PlayerPanel({
|
|
|
3763
3707
|
onClick: () => setIsExtendRequested(true),
|
|
3764
3708
|
expanded: false
|
|
3765
3709
|
} : null;
|
|
3766
|
-
return /* @__PURE__ */ (0,
|
|
3710
|
+
return /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)(
|
|
3767
3711
|
"div",
|
|
3768
3712
|
{
|
|
3769
3713
|
id: PANEL_ID,
|
|
3770
|
-
className: (0,
|
|
3714
|
+
className: (0, import_tailwind_merge.twMerge)(
|
|
3771
3715
|
"fixed right-[var(--layout-gutter)] top-[var(--layout-band-top)] z-40 max-h-[calc(100vh-var(--layout-band-top)-3.5rem)]",
|
|
3772
3716
|
!isExtended && "w-[var(--layout-right-w)]",
|
|
3773
3717
|
isTrackListSidebarVisible && "h-[calc(100vh-var(--layout-band-top)-3.5rem)]",
|
|
@@ -3776,8 +3720,8 @@ function PlayerPanel({
|
|
|
3776
3720
|
),
|
|
3777
3721
|
style: isExtended ? { width: extendedWidth } : void 0,
|
|
3778
3722
|
children: [
|
|
3779
|
-
/* @__PURE__ */ (0,
|
|
3780
|
-
PanelEdgeTab,
|
|
3723
|
+
/* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
|
|
3724
|
+
import_ui20.PanelEdgeTab,
|
|
3781
3725
|
{
|
|
3782
3726
|
side: "right",
|
|
3783
3727
|
edge: tabEdge,
|
|
@@ -3786,30 +3730,30 @@ function PlayerPanel({
|
|
|
3786
3730
|
className: "absolute right-full top-1/2 -translate-y-1/2"
|
|
3787
3731
|
}
|
|
3788
3732
|
),
|
|
3789
|
-
/* @__PURE__ */ (0,
|
|
3733
|
+
/* @__PURE__ */ (0, import_jsx_runtime44.jsxs)(
|
|
3790
3734
|
"div",
|
|
3791
3735
|
{
|
|
3792
|
-
className: (0,
|
|
3736
|
+
className: (0, import_tailwind_merge.twMerge)(
|
|
3793
3737
|
"flex h-full max-h-[inherit] overflow-hidden rounded-[var(--radius-panel,1rem)] bg-zinc-950 text-zinc-100 shadow-[0_1px_2px_rgba(0,0,0,0.5),0_2px_6px_2px_rgba(0,0,0,0.3)]",
|
|
3794
3738
|
isExtended ? "flex-row" : "flex-col"
|
|
3795
3739
|
),
|
|
3796
3740
|
children: [
|
|
3797
|
-
/* @__PURE__ */ (0,
|
|
3798
|
-
/* @__PURE__ */ (0,
|
|
3799
|
-
/* @__PURE__ */ (0,
|
|
3800
|
-
/* @__PURE__ */ (0,
|
|
3801
|
-
playerTrackObject?.loadError && /* @__PURE__ */ (0,
|
|
3741
|
+
/* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("div", { className: "flex w-[var(--layout-right-w)] shrink-0 flex-col", children: [
|
|
3742
|
+
/* @__PURE__ */ (0, import_jsx_runtime44.jsx)("div", { className: "flex shrink-0 items-center justify-between gap-2 border-b border-zinc-800 p-2", children: /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("span", { className: "min-w-0 truncate text-sm font-semibold", children: loadedTrackTitle || lastLoadedTrackTitle }) }),
|
|
3743
|
+
/* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("div", { className: "relative w-full shrink-0", children: [
|
|
3744
|
+
/* @__PURE__ */ (0, import_jsx_runtime44.jsx)(import_player13.PlayerVideoSurface, { className: "aspect-video w-full bg-black" }),
|
|
3745
|
+
playerTrackObject?.loadError && /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("span", { className: "absolute bottom-2 left-2 right-2 text-xs text-red-400", children: playerTrackObject.loadError })
|
|
3802
3746
|
] }),
|
|
3803
|
-
/* @__PURE__ */ (0,
|
|
3747
|
+
/* @__PURE__ */ (0, import_jsx_runtime44.jsx)(PlayerControls, {})
|
|
3804
3748
|
] }),
|
|
3805
|
-
/* @__PURE__ */ (0,
|
|
3749
|
+
/* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
|
|
3806
3750
|
TrackListSidebar,
|
|
3807
3751
|
{
|
|
3808
3752
|
layout: "inline",
|
|
3809
3753
|
isCollapsed: !isTrackListSidebarVisible,
|
|
3810
3754
|
onExpand: toggleTrackListSidebar,
|
|
3811
3755
|
onMinimize: hideSongList,
|
|
3812
|
-
className: (0,
|
|
3756
|
+
className: (0, import_tailwind_merge.twMerge)(
|
|
3813
3757
|
"min-h-0 min-w-0 flex-1",
|
|
3814
3758
|
isExtended && "border-l border-zinc-800"
|
|
3815
3759
|
),
|
|
@@ -3829,11 +3773,11 @@ function PlayerPanel({
|
|
|
3829
3773
|
var import_uuid = require("uuid");
|
|
3830
3774
|
var import_ai = require("react-icons/ai");
|
|
3831
3775
|
var import_genre_tree25 = require("@behindthemusictree/app-kit/genre-tree");
|
|
3832
|
-
var
|
|
3776
|
+
var import_jsx_runtime45 = require("react/jsx-runtime");
|
|
3833
3777
|
function Rating({ rating, handleChange }) {
|
|
3834
3778
|
const instanceId = (0, import_uuid.v4)();
|
|
3835
|
-
return /* @__PURE__ */ (0,
|
|
3836
|
-
/* @__PURE__ */ (0,
|
|
3779
|
+
return /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("div", { className: "flex items-center", children: [...Array(6)].map((_, i) => /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("div", { className: `relative ${i === 0 ? "mr-4" : "mr-1"}`, children: [
|
|
3780
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
|
|
3837
3781
|
"input",
|
|
3838
3782
|
{
|
|
3839
3783
|
id: `star-${instanceId}-${i}`,
|
|
@@ -3845,16 +3789,16 @@ function Rating({ rating, handleChange }) {
|
|
|
3845
3789
|
onChange: handleChange
|
|
3846
3790
|
}
|
|
3847
3791
|
),
|
|
3848
|
-
/* @__PURE__ */ (0,
|
|
3849
|
-
/* @__PURE__ */ (0,
|
|
3792
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)("label", { htmlFor: `star-${instanceId}-${i}`, className: "cursor-pointer", children: i === 0 ? /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("div", { className: "flex", children: [
|
|
3793
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
|
|
3850
3794
|
import_ai.AiOutlineStar,
|
|
3851
3795
|
{
|
|
3852
3796
|
className: `w-7 h-7 absolute top-0 left-0 ${rating === import_genre_tree25.FORM_RATING_NULL_VALUE ? "text-[var(--color-accent-rating)]" : "text-[var(--color-text-muted)]"}`
|
|
3853
3797
|
}
|
|
3854
3798
|
),
|
|
3855
|
-
/* @__PURE__ */ (0,
|
|
3799
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)("span", { className: "flex-grow w-8" }),
|
|
3856
3800
|
" "
|
|
3857
|
-
] }) : /* @__PURE__ */ (0,
|
|
3801
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
|
|
3858
3802
|
import_ai.AiFillStar,
|
|
3859
3803
|
{
|
|
3860
3804
|
className: `w-7 h-7 absolute top-0 left-0 ${(rating ?? -1) >= i ? "text-[var(--color-accent-rating)]" : "text-[var(--color-text-muted)]"}`
|
|
@@ -3880,7 +3824,6 @@ function Rating({ rating, handleChange }) {
|
|
|
3880
3824
|
GenreTreeWheelSkeleton,
|
|
3881
3825
|
InternalErrorPopup,
|
|
3882
3826
|
NetworkErrorPopup,
|
|
3883
|
-
PanelEdgeTab,
|
|
3884
3827
|
PlayerPanel,
|
|
3885
3828
|
PopupButtons,
|
|
3886
3829
|
PopupTitle,
|
|
@@ -3891,7 +3834,6 @@ function Rating({ rating, handleChange }) {
|
|
|
3891
3834
|
TrackListSidebar,
|
|
3892
3835
|
TrackPositionPlayPause,
|
|
3893
3836
|
TrackUploadPopup,
|
|
3894
|
-
useGenrePlaylistPlayback
|
|
3895
|
-
useLeftDetailPanelLayout
|
|
3837
|
+
useGenrePlaylistPlayback
|
|
3896
3838
|
});
|
|
3897
3839
|
//# sourceMappingURL=index.cjs.map
|