@behindthemusictree/app-kit-ui 30.0.0 → 32.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-QGGVPIXY.js} +546 -618
- package/dist/chunk-QGGVPIXY.js.map +1 -0
- package/dist/genre-tree/index.cjs +547 -625
- package/dist/genre-tree/index.cjs.map +1 -1
- package/dist/genre-tree/index.d.ts +37 -40
- package/dist/genre-tree/index.js +3 -7
- package/dist/index.cjs +547 -625
- 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
|
@@ -5,13 +5,17 @@ import {
|
|
|
5
5
|
} from "./chunk-DKQQLLMY.js";
|
|
6
6
|
|
|
7
7
|
// src/genre-tree/GenreTreeView.tsx
|
|
8
|
-
import { useCallback as useCallback6, useDeferredValue, useEffect as
|
|
8
|
+
import { useCallback as useCallback6, useDeferredValue, useEffect as useEffect5, useMemo as useMemo7, useRef as useRef3, useState as useState8 } from "react";
|
|
9
9
|
import { useIsMutating } from "@tanstack/react-query";
|
|
10
10
|
import { Plus as Plus2 } from "lucide-react";
|
|
11
|
-
import {
|
|
11
|
+
import { Maximize2, Minimize2 } from "lucide-react";
|
|
12
|
+
import { IconTextButton, IconButton, Button, SegmentedControl as SegmentedControl2, DetailPanel, useObscuredInset } from "@behindthemusictree/ui";
|
|
12
13
|
import {
|
|
14
|
+
GenreNodeAncestors,
|
|
15
|
+
GenreNodeFamily,
|
|
13
16
|
GenreTreeWheelSkeleton,
|
|
14
|
-
GenreTreeViewSkeleton
|
|
17
|
+
GenreTreeViewSkeleton,
|
|
18
|
+
useGenreNodeRelations
|
|
15
19
|
} from "@behindthemusictree/genre-tree-view";
|
|
16
20
|
import {
|
|
17
21
|
useArtistSearch,
|
|
@@ -21,6 +25,32 @@ import {
|
|
|
21
25
|
import { useGenreTreeViewState, useArtist as useArtist2, useUpdateGenre as useUpdateGenre2, genreUpdateMutationKey } from "@behindthemusictree/app-kit/genre-tree";
|
|
22
26
|
import { usePopup as usePopup5 } from "@behindthemusictree/app-kit/popup";
|
|
23
27
|
|
|
28
|
+
// src/genre-tree/playlist-tree/size-metric.ts
|
|
29
|
+
var hasViewsCount = (genrePlaylists) => genrePlaylists.every((genrePlaylist) => genrePlaylist.viewsCount !== void 0);
|
|
30
|
+
var genrePlaylistSize = (genrePlaylist, metric) => {
|
|
31
|
+
if (metric === "songs") return genrePlaylist.tracksCount;
|
|
32
|
+
if (genrePlaylist.viewsCount === void 0) {
|
|
33
|
+
throw new Error(`Genre playlist ${genrePlaylist.uuid} has no viewsCount to size by views`);
|
|
34
|
+
}
|
|
35
|
+
return genrePlaylist.viewsCount;
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
// src/genre-tree/playlist-tree/toTreeNodes.ts
|
|
39
|
+
function toTreeNodes(genrePlaylists, sizeMetric) {
|
|
40
|
+
return genrePlaylists.map((genrePlaylist) => ({
|
|
41
|
+
id: genrePlaylist.uuid,
|
|
42
|
+
parentId: genrePlaylist.parent?.uuid ?? null,
|
|
43
|
+
name: genrePlaylist.name,
|
|
44
|
+
itemCount: genrePlaylistSize(genrePlaylist, sizeMetric),
|
|
45
|
+
actionable: Boolean(genrePlaylist.criteria),
|
|
46
|
+
detached: !genrePlaylist.criteria,
|
|
47
|
+
side: genrePlaylist.criteria?.side ?? void 0,
|
|
48
|
+
wikidataId: genrePlaylist.criteria?.wikidataId ?? null,
|
|
49
|
+
umbrella: genrePlaylist.isUmbrella,
|
|
50
|
+
scene: genrePlaylist.scene ?? void 0
|
|
51
|
+
}));
|
|
52
|
+
}
|
|
53
|
+
|
|
24
54
|
// src/genre-tree/playlist-tree/TreePerRoot.tsx
|
|
25
55
|
import { useCallback as useCallback2, useMemo as useMemo2 } from "react";
|
|
26
56
|
import {
|
|
@@ -63,7 +93,6 @@ function useGenrePlaylistPlayback({
|
|
|
63
93
|
}
|
|
64
94
|
|
|
65
95
|
// src/genre-tree/playlist-tree/TreePerRoot.tsx
|
|
66
|
-
import { capitalize, useTrackNoun } from "@behindthemusictree/app-kit/track-noun";
|
|
67
96
|
import { jsx } from "react/jsx-runtime";
|
|
68
97
|
function GenrePlaylistTreePerRoot({
|
|
69
98
|
scope,
|
|
@@ -75,24 +104,19 @@ function GenrePlaylistTreePerRoot({
|
|
|
75
104
|
additionalActions,
|
|
76
105
|
onNodeClick,
|
|
77
106
|
onNodeHover,
|
|
78
|
-
renderInfoPanelBody,
|
|
79
107
|
selectedNodeId,
|
|
80
108
|
onSelectedNodeChange,
|
|
81
|
-
hideInfoPanelClose,
|
|
82
|
-
hideInfoPanelTitle,
|
|
83
109
|
readOnly = false,
|
|
84
|
-
showToolbar,
|
|
85
110
|
wheelZoom,
|
|
86
111
|
defaultViewport,
|
|
87
112
|
viewportRestore,
|
|
88
113
|
onViewportChange,
|
|
89
114
|
playback,
|
|
90
|
-
...
|
|
115
|
+
...hostPanel
|
|
91
116
|
}) {
|
|
92
117
|
const { isPlaying, setIsPlaying } = usePlayer();
|
|
93
118
|
const defaultPlayback = useGenrePlaylistPlayback({ scope, genrePlaylists: genrePlaylistTreePerRoot });
|
|
94
119
|
const { playingNodeId, play } = playback ?? defaultPlayback;
|
|
95
|
-
const trackNoun = useTrackNoun();
|
|
96
120
|
const { showPopup } = usePopup();
|
|
97
121
|
const nodes = useMemo2(
|
|
98
122
|
() => genrePlaylistTreePerRoot.map((genrePlaylist) => ({
|
|
@@ -157,7 +181,6 @@ function GenrePlaylistTreePerRoot({
|
|
|
157
181
|
{
|
|
158
182
|
className: className2,
|
|
159
183
|
nodes,
|
|
160
|
-
itemCountLabel: `${capitalize(trackNoun.singular)} count`,
|
|
161
184
|
rootColor: getGenreTreeColor(rootUuid),
|
|
162
185
|
playingNodeId,
|
|
163
186
|
playState: isPlaying ? "playing" : "paused",
|
|
@@ -168,18 +191,13 @@ function GenrePlaylistTreePerRoot({
|
|
|
168
191
|
additionalActions,
|
|
169
192
|
onNodeClick,
|
|
170
193
|
onNodeHover,
|
|
171
|
-
renderInfoPanelBody,
|
|
172
194
|
selectedNodeId,
|
|
173
195
|
onSelectedNodeChange,
|
|
174
|
-
hideInfoPanelClose,
|
|
175
|
-
hideInfoPanelTitle,
|
|
176
|
-
showToolbar,
|
|
177
196
|
wheelZoom,
|
|
178
197
|
defaultViewport,
|
|
179
198
|
viewportRestore,
|
|
180
199
|
onViewportChange,
|
|
181
|
-
...
|
|
182
|
-
readOnly
|
|
200
|
+
...hostPanel
|
|
183
201
|
}
|
|
184
202
|
);
|
|
185
203
|
}
|
|
@@ -192,19 +210,6 @@ import {
|
|
|
192
210
|
import { usePlayer as usePlayer2 } from "@behindthemusictree/app-kit/player";
|
|
193
211
|
import { usePopup as usePopup2 } from "@behindthemusictree/app-kit/popup";
|
|
194
212
|
import { ErrorCode as ErrorCode2 } from "@behindthemusictree/app-kit/transport";
|
|
195
|
-
|
|
196
|
-
// src/genre-tree/playlist-tree/size-metric.ts
|
|
197
|
-
var hasViewsCount = (genrePlaylists) => genrePlaylists.every((genrePlaylist) => genrePlaylist.viewsCount !== void 0);
|
|
198
|
-
var genrePlaylistSize = (genrePlaylist, metric) => {
|
|
199
|
-
if (metric === "songs") return genrePlaylist.tracksCount;
|
|
200
|
-
if (genrePlaylist.viewsCount === void 0) {
|
|
201
|
-
throw new Error(`Genre playlist ${genrePlaylist.uuid} has no viewsCount to size by views`);
|
|
202
|
-
}
|
|
203
|
-
return genrePlaylist.viewsCount;
|
|
204
|
-
};
|
|
205
|
-
|
|
206
|
-
// src/genre-tree/playlist-tree/TreeWheel.tsx
|
|
207
|
-
import { capitalize as capitalize2, useTrackNoun as useTrackNoun2 } from "@behindthemusictree/app-kit/track-noun";
|
|
208
213
|
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
209
214
|
function GenrePlaylistTreeWheel({
|
|
210
215
|
scope,
|
|
@@ -215,14 +220,10 @@ function GenrePlaylistTreeWheel({
|
|
|
215
220
|
additionalActions,
|
|
216
221
|
onNodeClick,
|
|
217
222
|
onNodeHover,
|
|
218
|
-
renderInfoPanelBody,
|
|
219
223
|
selectedNodeId,
|
|
220
224
|
onSelectedNodeChange,
|
|
221
|
-
hideInfoPanelClose,
|
|
222
|
-
hideInfoPanelTitle,
|
|
223
225
|
readOnly = false,
|
|
224
226
|
allowWheelRotation,
|
|
225
|
-
showToolbar,
|
|
226
227
|
sizeMetric = "songs",
|
|
227
228
|
floatingControlsLeading,
|
|
228
229
|
busy,
|
|
@@ -230,12 +231,11 @@ function GenrePlaylistTreeWheel({
|
|
|
230
231
|
viewportRestore,
|
|
231
232
|
onViewportChange,
|
|
232
233
|
playback,
|
|
233
|
-
...
|
|
234
|
+
...hostPanel
|
|
234
235
|
}) {
|
|
235
236
|
const { isPlaying, setIsPlaying } = usePlayer2();
|
|
236
237
|
const defaultPlayback = useGenrePlaylistPlayback({ scope, genrePlaylists });
|
|
237
238
|
const { playingNodeId, play } = playback ?? defaultPlayback;
|
|
238
|
-
const trackNoun = useTrackNoun2();
|
|
239
239
|
const { showPopup } = usePopup2();
|
|
240
240
|
const nodes = useMemo3(
|
|
241
241
|
() => genrePlaylists.map((genrePlaylist) => ({
|
|
@@ -299,7 +299,6 @@ function GenrePlaylistTreeWheel({
|
|
|
299
299
|
{
|
|
300
300
|
className: className2,
|
|
301
301
|
nodes,
|
|
302
|
-
itemCountLabel: sizeMetric === "views" ? "Views" : `${capitalize2(trackNoun.singular)} count`,
|
|
303
302
|
playingNodeId,
|
|
304
303
|
playState: isPlaying ? "playing" : "paused",
|
|
305
304
|
onPlayPause: handlePlayPause,
|
|
@@ -309,20 +308,15 @@ function GenrePlaylistTreeWheel({
|
|
|
309
308
|
additionalActions,
|
|
310
309
|
onNodeClick,
|
|
311
310
|
onNodeHover,
|
|
312
|
-
renderInfoPanelBody,
|
|
313
311
|
selectedNodeId,
|
|
314
312
|
onSelectedNodeChange,
|
|
315
|
-
hideInfoPanelClose,
|
|
316
|
-
hideInfoPanelTitle,
|
|
317
313
|
allowWheelRotation,
|
|
318
|
-
showToolbar,
|
|
319
314
|
floatingControlsLeading,
|
|
320
315
|
busy,
|
|
321
316
|
defaultViewport,
|
|
322
317
|
viewportRestore,
|
|
323
318
|
onViewportChange,
|
|
324
|
-
...
|
|
325
|
-
readOnly
|
|
319
|
+
...hostPanel
|
|
326
320
|
}
|
|
327
321
|
);
|
|
328
322
|
}
|
|
@@ -334,7 +328,6 @@ import {
|
|
|
334
328
|
GenreTreeWheelRadialPopCore
|
|
335
329
|
} from "@behindthemusictree/genre-tree-view";
|
|
336
330
|
import { usePlayer as usePlayer3 } from "@behindthemusictree/app-kit/player";
|
|
337
|
-
import { capitalize as capitalize3, useTrackNoun as useTrackNoun3 } from "@behindthemusictree/app-kit/track-noun";
|
|
338
331
|
import { jsx as jsx3 } from "react/jsx-runtime";
|
|
339
332
|
function GenrePlaylistTreeWheelRadialPopCore(props) {
|
|
340
333
|
const {
|
|
@@ -346,14 +339,10 @@ function GenrePlaylistTreeWheelRadialPopCore(props) {
|
|
|
346
339
|
additionalActions,
|
|
347
340
|
onNodeClick,
|
|
348
341
|
onNodeHover,
|
|
349
|
-
renderInfoPanelBody,
|
|
350
342
|
selectedNodeId,
|
|
351
343
|
onSelectedNodeChange,
|
|
352
|
-
hideInfoPanelClose,
|
|
353
|
-
hideInfoPanelTitle,
|
|
354
344
|
readOnly = false,
|
|
355
345
|
allowWheelRotation,
|
|
356
|
-
showToolbar,
|
|
357
346
|
sizeMetric = "songs",
|
|
358
347
|
floatingControlsLeading,
|
|
359
348
|
busy,
|
|
@@ -364,33 +353,14 @@ function GenrePlaylistTreeWheelRadialPopCore(props) {
|
|
|
364
353
|
playback
|
|
365
354
|
} = props;
|
|
366
355
|
const focus = props;
|
|
367
|
-
const
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
onExpandedChange: props.onExpandedChange,
|
|
371
|
-
collapsed: props.collapsed,
|
|
372
|
-
hideExpandButton: props.hideExpandButton,
|
|
373
|
-
overlayPanel: props.overlayPanel
|
|
356
|
+
const hostPanel = {
|
|
357
|
+
obscuredInset: props.obscuredInset,
|
|
358
|
+
onNodeStyleResolverChange: props.onNodeStyleResolverChange
|
|
374
359
|
};
|
|
375
360
|
const { isPlaying, setIsPlaying } = usePlayer3();
|
|
376
361
|
const defaultPlayback = useGenrePlaylistPlayback({ scope, genrePlaylists });
|
|
377
362
|
const { playingNodeId, play } = playback ?? defaultPlayback;
|
|
378
|
-
const
|
|
379
|
-
const nodes = useMemo4(
|
|
380
|
-
() => genrePlaylists.map((genrePlaylist) => ({
|
|
381
|
-
id: genrePlaylist.uuid,
|
|
382
|
-
parentId: genrePlaylist.parent?.uuid ?? null,
|
|
383
|
-
name: genrePlaylist.name,
|
|
384
|
-
itemCount: genrePlaylistSize(genrePlaylist, sizeMetric),
|
|
385
|
-
actionable: Boolean(genrePlaylist.criteria),
|
|
386
|
-
detached: !genrePlaylist.criteria,
|
|
387
|
-
side: genrePlaylist.criteria?.side ?? void 0,
|
|
388
|
-
wikidataId: genrePlaylist.criteria?.wikidataId ?? null,
|
|
389
|
-
umbrella: genrePlaylist.isUmbrella,
|
|
390
|
-
scene: genrePlaylist.scene ?? void 0
|
|
391
|
-
})),
|
|
392
|
-
[genrePlaylists, sizeMetric]
|
|
393
|
-
);
|
|
363
|
+
const nodes = useMemo4(() => toTreeNodes(genrePlaylists, sizeMetric), [genrePlaylists, sizeMetric]);
|
|
394
364
|
const handlePlayPause = useCallback4(
|
|
395
365
|
(nodeId) => {
|
|
396
366
|
const genrePlaylist = genrePlaylists.find((g) => g.uuid === nodeId);
|
|
@@ -431,7 +401,6 @@ function GenrePlaylistTreeWheelRadialPopCore(props) {
|
|
|
431
401
|
const treeProps = {
|
|
432
402
|
className: className2,
|
|
433
403
|
nodes,
|
|
434
|
-
itemCountLabel: sizeMetric === "views" ? "Views" : `${capitalize3(trackNoun.singular)} count`,
|
|
435
404
|
playingNodeId,
|
|
436
405
|
playState: isPlaying ? "playing" : "paused",
|
|
437
406
|
onPlayPause: handlePlayPause,
|
|
@@ -441,14 +410,9 @@ function GenrePlaylistTreeWheelRadialPopCore(props) {
|
|
|
441
410
|
additionalActions,
|
|
442
411
|
onNodeClick,
|
|
443
412
|
onNodeHover,
|
|
444
|
-
renderInfoPanelBody,
|
|
445
413
|
selectedNodeId,
|
|
446
414
|
onSelectedNodeChange,
|
|
447
|
-
|
|
448
|
-
hideInfoPanelTitle,
|
|
449
|
-
showToolbar,
|
|
450
|
-
...infoPanelCuration,
|
|
451
|
-
readOnly
|
|
415
|
+
...hostPanel
|
|
452
416
|
};
|
|
453
417
|
return outline ? /* @__PURE__ */ jsx3(GenreTreeOutline, { ...treeProps }) : /* @__PURE__ */ jsx3(
|
|
454
418
|
GenreTreeWheelRadialPopCore,
|
|
@@ -568,7 +532,7 @@ function GenreSearch({
|
|
|
568
532
|
type: "button",
|
|
569
533
|
"aria-label": "Previous",
|
|
570
534
|
title: "Previous",
|
|
571
|
-
className: "genre-search-previous absolute left-2 top-1/2 z-10
|
|
535
|
+
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)]",
|
|
572
536
|
onClick: onPrevious,
|
|
573
537
|
children: /* @__PURE__ */ jsx5(ArrowLeft, { "aria-hidden": "true", className: "w-4 h-4" })
|
|
574
538
|
}
|
|
@@ -590,7 +554,7 @@ function GenreSearch({
|
|
|
590
554
|
onPick: handlePick,
|
|
591
555
|
status,
|
|
592
556
|
loading: loading ? "Searching\u2026" : void 0,
|
|
593
|
-
inputClassName:
|
|
557
|
+
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`,
|
|
594
558
|
className: "genre-search-results z-40 rounded-xl shadow-md",
|
|
595
559
|
listClassName: "max-h-[min(20rem,50dvh)]",
|
|
596
560
|
optionClassName: "[@media(pointer:coarse)]:min-h-[var(--layout-touch-target)]"
|
|
@@ -952,7 +916,7 @@ function GenreActionBand({
|
|
|
952
916
|
}
|
|
953
917
|
|
|
954
918
|
// src/genre-tree/GenreDetailExtras.tsx
|
|
955
|
-
import { Skeleton as Skeleton2 } from "@behindthemusictree/ui";
|
|
919
|
+
import { PanelSection as PanelSection2, Skeleton as Skeleton2 } from "@behindthemusictree/ui";
|
|
956
920
|
import { useFetchGenreOverview } from "@behindthemusictree/app-kit/genre-tree";
|
|
957
921
|
|
|
958
922
|
// src/genre-tree/ClampedText.tsx
|
|
@@ -983,11 +947,11 @@ function ClampedText({ children, className: className2 = "" }) {
|
|
|
983
947
|
}
|
|
984
948
|
|
|
985
949
|
// src/genre-tree/GenrePlaylistTracks.tsx
|
|
986
|
-
import { useEffect as useEffect3,
|
|
950
|
+
import { useEffect as useEffect3, useState as useState5 } from "react";
|
|
987
951
|
import { useInfiniteQuery } from "@tanstack/react-query";
|
|
988
952
|
import { z } from "zod";
|
|
989
953
|
import { FaPlay, FaPause } from "react-icons/fa";
|
|
990
|
-
import { RingLoader, Skeleton } from "@behindthemusictree/ui";
|
|
954
|
+
import { PanelSection, RingLoader, Skeleton } from "@behindthemusictree/ui";
|
|
991
955
|
import { useSession } from "@behindthemusictree/app-kit/auth";
|
|
992
956
|
import { useFetchWrapper } from "@behindthemusictree/app-kit/transport";
|
|
993
957
|
import { PaginatedResponseSchema } from "@behindthemusictree/app-kit/transport";
|
|
@@ -1027,7 +991,7 @@ function MusicBrainzRecordingLink({
|
|
|
1027
991
|
|
|
1028
992
|
// src/genre-tree/GenrePlaylistTracks.tsx
|
|
1029
993
|
import { ArtistNames } from "@behindthemusictree/app-kit/genre-tree";
|
|
1030
|
-
import { capitalize
|
|
994
|
+
import { capitalize, useTrackNoun } from "@behindthemusictree/app-kit/track-noun";
|
|
1031
995
|
import { jsx as jsx13, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
1032
996
|
var CATALOGUE_PAGE_SIZE = 100;
|
|
1033
997
|
var SongPageSchema = PaginatedResponseSchema(SongDetailedSchema).extend({
|
|
@@ -1061,7 +1025,7 @@ function GenrePlaylistTracks({
|
|
|
1061
1025
|
const { session, sessionRestored } = useSession();
|
|
1062
1026
|
const { playerTrackObject, playState, handlePlayPauseAction } = usePlayer4();
|
|
1063
1027
|
const { showPopup } = usePopup4();
|
|
1064
|
-
const trackNoun =
|
|
1028
|
+
const trackNoun = useTrackNoun();
|
|
1065
1029
|
const { uuid } = genrePlaylist;
|
|
1066
1030
|
const { fetch } = useFetchWrapper(getBackendBaseUrl);
|
|
1067
1031
|
const { data, isPending, isError, refetch, hasNextPage, isFetchingNextPage, fetchNextPage } = useInfiniteQuery({
|
|
@@ -1082,9 +1046,8 @@ function GenrePlaylistTracks({
|
|
|
1082
1046
|
getNextPageParam: (lastPage) => lastPage.nextPage ?? void 0,
|
|
1083
1047
|
enabled: scope !== "me" || sessionRestored && !!session?.accessToken
|
|
1084
1048
|
});
|
|
1085
|
-
const
|
|
1049
|
+
const [sentinel, setSentinel] = useState5(null);
|
|
1086
1050
|
useEffect3(() => {
|
|
1087
|
-
const sentinel = sentinelRef.current;
|
|
1088
1051
|
if (!hasNextPage || isFetchingNextPage || !sentinel) return;
|
|
1089
1052
|
const observer = new IntersectionObserver((entries) => {
|
|
1090
1053
|
if (entries.some((entry) => entry.isIntersecting)) {
|
|
@@ -1093,7 +1056,7 @@ function GenrePlaylistTracks({
|
|
|
1093
1056
|
});
|
|
1094
1057
|
observer.observe(sentinel);
|
|
1095
1058
|
return () => observer.disconnect();
|
|
1096
|
-
}, [hasNextPage, isFetchingNextPage, fetchNextPage]);
|
|
1059
|
+
}, [hasNextPage, isFetchingNextPage, fetchNextPage, sentinel]);
|
|
1097
1060
|
const pages = data?.pages ?? [];
|
|
1098
1061
|
const tracks = pages.flatMap((page) => page.tracks);
|
|
1099
1062
|
const total = pages[0]?.total ?? void 0;
|
|
@@ -1104,11 +1067,7 @@ function GenrePlaylistTracks({
|
|
|
1104
1067
|
showPopup(/* @__PURE__ */ jsx13(InternalErrorPopup, { errorCode: ErrorCode3.CLIENT_UNKNOWN }));
|
|
1105
1068
|
});
|
|
1106
1069
|
};
|
|
1107
|
-
return /* @__PURE__ */
|
|
1108
|
-
/* @__PURE__ */ jsxs9("span", { className: "gtv-info-panel-children-title", children: [
|
|
1109
|
-
capitalize4(trackNoun.plural),
|
|
1110
|
-
total !== void 0 && ` (${total})`
|
|
1111
|
-
] }),
|
|
1070
|
+
return /* @__PURE__ */ jsx13(PanelSection, { title: `${capitalize(trackNoun.plural)}${total !== void 0 ? ` (${total})` : ""}`, children: /* @__PURE__ */ jsxs9("div", { children: [
|
|
1112
1071
|
renderTracksToolbar?.(),
|
|
1113
1072
|
isPending ? /* @__PURE__ */ jsx13(Skeleton, { className: "h-4 w-3/4", "aria-busy": "true" }) : isError && tracks.length === 0 ? /* @__PURE__ */ jsxs9("p", { role: "alert", children: [
|
|
1114
1073
|
"Couldn't load ",
|
|
@@ -1171,13 +1130,13 @@ function GenrePlaylistTracks({
|
|
|
1171
1130
|
track.uuid
|
|
1172
1131
|
);
|
|
1173
1132
|
}),
|
|
1174
|
-
hasNextPage && /* @__PURE__ */ jsx13("li", { ref:
|
|
1133
|
+
hasNextPage && /* @__PURE__ */ jsx13("li", { ref: setSentinel, "aria-hidden": "true", className: "h-4" })
|
|
1175
1134
|
] })
|
|
1176
|
-
] });
|
|
1135
|
+
] }) });
|
|
1177
1136
|
}
|
|
1178
1137
|
|
|
1179
1138
|
// src/genre-tree/GenreDetailExtras.tsx
|
|
1180
|
-
import { useTrackNoun as
|
|
1139
|
+
import { useTrackNoun as useTrackNoun2 } from "@behindthemusictree/app-kit/track-noun";
|
|
1181
1140
|
import { SiWikidata, SiWikipedia } from "react-icons/si";
|
|
1182
1141
|
import { Fragment as Fragment6, jsx as jsx14, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
1183
1142
|
function GenreDetailExtras({
|
|
@@ -1195,7 +1154,7 @@ function GenreDetailExtras({
|
|
|
1195
1154
|
family,
|
|
1196
1155
|
...trackSlots
|
|
1197
1156
|
}) {
|
|
1198
|
-
const trackNoun =
|
|
1157
|
+
const trackNoun = useTrackNoun2();
|
|
1199
1158
|
const { data: overview, isPending } = useFetchGenreOverview(
|
|
1200
1159
|
genreUuid,
|
|
1201
1160
|
scope,
|
|
@@ -1204,10 +1163,7 @@ function GenreDetailExtras({
|
|
|
1204
1163
|
);
|
|
1205
1164
|
if (isPending) {
|
|
1206
1165
|
return /* @__PURE__ */ jsxs10(Fragment6, { children: [
|
|
1207
|
-
/* @__PURE__ */
|
|
1208
|
-
/* @__PURE__ */ jsx14("span", { className: "gtv-info-panel-children-title", children: "Summary" }),
|
|
1209
|
-
/* @__PURE__ */ jsx14(Skeleton2, { className: "h-4 w-3/4" })
|
|
1210
|
-
] }),
|
|
1166
|
+
/* @__PURE__ */ jsx14(PanelSection2, { title: "Summary", children: /* @__PURE__ */ jsx14("div", { "aria-busy": "true", "data-testid": "genre-detail-extras-skeleton", children: /* @__PURE__ */ jsx14(Skeleton2, { className: "h-4 w-3/4" }) }) }),
|
|
1211
1167
|
family
|
|
1212
1168
|
] });
|
|
1213
1169
|
}
|
|
@@ -1215,50 +1171,38 @@ function GenreDetailExtras({
|
|
|
1215
1171
|
const { summary, summarySourceUrl, essentialSongs } = overview;
|
|
1216
1172
|
const wikidataUrl = wikidataId ? `https://www.wikidata.org/wiki/${encodeURIComponent(wikidataId)}` : null;
|
|
1217
1173
|
return /* @__PURE__ */ jsxs10(Fragment6, { children: [
|
|
1218
|
-
(summarySourceUrl || wikidataUrl) && /* @__PURE__ */ jsxs10("div", { className: "
|
|
1219
|
-
/* @__PURE__ */
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
] })
|
|
1248
|
-
] }),
|
|
1249
|
-
renderSummary ? renderSummary(overview) : /* @__PURE__ */ jsxs10("div", { className: "gtv-info-panel-children text-[0.8125rem] leading-[1.45] text-[var(--color-text)]", children: [
|
|
1250
|
-
/* @__PURE__ */ jsx14("span", { className: "gtv-info-panel-children-title", children: "Summary" }),
|
|
1251
|
-
/* @__PURE__ */ jsx14(ClampedText, { className: "mt-1", children: summary ?? "\u2014" }, genreUuid)
|
|
1252
|
-
] }),
|
|
1174
|
+
(summarySourceUrl || wikidataUrl) && /* @__PURE__ */ jsx14(PanelSection2, { title: "Links", children: /* @__PURE__ */ jsxs10("div", { className: "flex flex-wrap gap-x-3 gap-y-1 text-xs text-[var(--color-text)]", children: [
|
|
1175
|
+
summarySourceUrl && /* @__PURE__ */ jsxs10(
|
|
1176
|
+
"a",
|
|
1177
|
+
{
|
|
1178
|
+
href: summarySourceUrl,
|
|
1179
|
+
target: "_blank",
|
|
1180
|
+
rel: "noopener noreferrer",
|
|
1181
|
+
className: "inline-flex items-center gap-1.5 text-[var(--color-text-muted)] hover:text-[var(--color-text)]",
|
|
1182
|
+
children: [
|
|
1183
|
+
/* @__PURE__ */ jsx14(SiWikipedia, { "aria-hidden": "true", className: "h-3.5 w-3.5" }),
|
|
1184
|
+
"Wikipedia"
|
|
1185
|
+
]
|
|
1186
|
+
}
|
|
1187
|
+
),
|
|
1188
|
+
wikidataUrl && /* @__PURE__ */ jsxs10(
|
|
1189
|
+
"a",
|
|
1190
|
+
{
|
|
1191
|
+
href: wikidataUrl,
|
|
1192
|
+
target: "_blank",
|
|
1193
|
+
rel: "noopener noreferrer",
|
|
1194
|
+
className: "inline-flex items-center gap-1.5 text-[var(--color-text-muted)] hover:text-[var(--color-text)]",
|
|
1195
|
+
children: [
|
|
1196
|
+
/* @__PURE__ */ jsx14(SiWikidata, { "aria-hidden": "true", className: "h-3.5 w-3.5" }),
|
|
1197
|
+
"Wikidata"
|
|
1198
|
+
]
|
|
1199
|
+
}
|
|
1200
|
+
)
|
|
1201
|
+
] }) }),
|
|
1202
|
+
/* @__PURE__ */ jsx14(PanelSection2, { title: "Summary", children: renderSummary ? renderSummary(overview) : /* @__PURE__ */ jsx14(ClampedText, { className: "text-[0.8125rem] leading-[1.45] text-[var(--color-text)]", children: summary ?? "\u2014" }, genreUuid) }),
|
|
1253
1203
|
family,
|
|
1254
1204
|
renderGenreDetailExtras?.(overview),
|
|
1255
|
-
renderEssentialTracks ? renderEssentialTracks(overview) : essentialSongs && /* @__PURE__ */
|
|
1256
|
-
/* @__PURE__ */ jsxs10("span", { className: "gtv-info-panel-children-title", children: [
|
|
1257
|
-
"Essential ",
|
|
1258
|
-
trackNoun.plural
|
|
1259
|
-
] }),
|
|
1260
|
-
essentialSongs.length > 0 ? /* @__PURE__ */ jsx14("ul", { className: "mt-1 divide-y divide-[var(--color-border)]", children: essentialSongs.map((track) => /* @__PURE__ */ jsx14("li", { className: "py-1", children: track.title }, track.uuid)) }) : /* @__PURE__ */ jsx14("p", { className: "mt-1", children: "\u2014" })
|
|
1261
|
-
] }),
|
|
1205
|
+
(renderEssentialTracks || essentialSongs) && /* @__PURE__ */ jsx14(PanelSection2, { title: `Essential ${trackNoun.plural}`, children: renderEssentialTracks ? renderEssentialTracks(overview) : essentialSongs && essentialSongs.length > 0 ? /* @__PURE__ */ jsx14("ul", { className: "text-[0.8125rem] leading-[1.45] text-[var(--color-text)]", children: essentialSongs.map((track) => /* @__PURE__ */ jsx14("li", { className: "py-1", children: track.title }, track.uuid)) }) : /* @__PURE__ */ jsx14("p", { className: "text-[0.8125rem] leading-[1.45] text-[var(--color-text)]", children: "\u2014" }) }),
|
|
1262
1206
|
/* @__PURE__ */ jsx14(
|
|
1263
1207
|
GenrePlaylistTracks,
|
|
1264
1208
|
{
|
|
@@ -1329,69 +1273,13 @@ function GenreInfoPanelBody({
|
|
|
1329
1273
|
] });
|
|
1330
1274
|
}
|
|
1331
1275
|
|
|
1332
|
-
// src/genre-tree/PanelEdgeTab.tsx
|
|
1333
|
-
import { ChevronLeft, ChevronRight } from "lucide-react";
|
|
1334
|
-
import { twMerge } from "tailwind-merge";
|
|
1335
|
-
import { jsx as jsx16, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
1336
|
-
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)]";
|
|
1337
|
-
function PanelEdgeTab({ side, edge, center, controls, className: className2 }) {
|
|
1338
|
-
if (!edge && !center) return null;
|
|
1339
|
-
const isLeft = side === "left";
|
|
1340
|
-
const EdgeIcon = isLeft ? ChevronLeft : ChevronRight;
|
|
1341
|
-
const CenterIcon = isLeft ? ChevronRight : ChevronLeft;
|
|
1342
|
-
const renderButton = (action, icon) => /* @__PURE__ */ jsx16(
|
|
1343
|
-
"button",
|
|
1344
|
-
{
|
|
1345
|
-
type: "button",
|
|
1346
|
-
"aria-label": action.label,
|
|
1347
|
-
title: action.label,
|
|
1348
|
-
"aria-controls": controls,
|
|
1349
|
-
"aria-expanded": action.expanded,
|
|
1350
|
-
className: buttonClassName,
|
|
1351
|
-
onClick: action.onClick,
|
|
1352
|
-
children: icon
|
|
1353
|
-
}
|
|
1354
|
-
);
|
|
1355
|
-
const edgeButton = edge && renderButton(edge, /* @__PURE__ */ jsx16(EdgeIcon, { "aria-hidden": "true", className: "h-5 w-5" }));
|
|
1356
|
-
const centerButton = center && renderButton(center, /* @__PURE__ */ jsx16(CenterIcon, { "aria-hidden": "true", className: "h-5 w-5" }));
|
|
1357
|
-
const buttons = isLeft ? [edgeButton, centerButton] : [centerButton, edgeButton];
|
|
1358
|
-
return /* @__PURE__ */ jsxs12(
|
|
1359
|
-
"div",
|
|
1360
|
-
{
|
|
1361
|
-
className: twMerge(
|
|
1362
|
-
"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)]",
|
|
1363
|
-
isLeft ? "rounded-r-lg" : "rounded-l-lg [clip-path:inset(-0.5rem_0_-0.5rem_-0.5rem)]",
|
|
1364
|
-
className2
|
|
1365
|
-
),
|
|
1366
|
-
children: [
|
|
1367
|
-
buttons[0],
|
|
1368
|
-
buttons[0] && buttons[1] && /* @__PURE__ */ jsx16("div", { role: "presentation", className: "h-px shrink-0 bg-[var(--color-border)]" }),
|
|
1369
|
-
buttons[1]
|
|
1370
|
-
]
|
|
1371
|
-
}
|
|
1372
|
-
);
|
|
1373
|
-
}
|
|
1374
|
-
|
|
1375
|
-
// src/genre-tree/useLeftDetailPanelLayout.ts
|
|
1376
|
-
import { useEffect as useEffect4 } from "react";
|
|
1377
|
-
function useLeftDetailPanelLayout(isPanelShown, enabled = true) {
|
|
1378
|
-
useEffect4(() => {
|
|
1379
|
-
if (!enabled || isPanelShown) return void 0;
|
|
1380
|
-
const root = document.documentElement;
|
|
1381
|
-
root.style.setProperty("--layout-left-w", "0px");
|
|
1382
|
-
return () => {
|
|
1383
|
-
root.style.removeProperty("--layout-left-w");
|
|
1384
|
-
};
|
|
1385
|
-
}, [enabled, isPanelShown]);
|
|
1386
|
-
}
|
|
1387
|
-
|
|
1388
1276
|
// src/genre-tree/ChangeParentPopup.tsx
|
|
1389
|
-
import { useEffect as
|
|
1277
|
+
import { useEffect as useEffect4, useMemo as useMemo6 } from "react";
|
|
1390
1278
|
import {
|
|
1391
1279
|
getReparentCandidates,
|
|
1392
1280
|
useUpdateGenre
|
|
1393
1281
|
} from "@behindthemusictree/app-kit/genre-tree";
|
|
1394
|
-
import { jsx as
|
|
1282
|
+
import { jsx as jsx16, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
1395
1283
|
function ChangeParentPopup({
|
|
1396
1284
|
genrePlaylist,
|
|
1397
1285
|
genrePlaylists,
|
|
@@ -1419,19 +1307,19 @@ function ChangeParentPopup({
|
|
|
1419
1307
|
}
|
|
1420
1308
|
);
|
|
1421
1309
|
};
|
|
1422
|
-
|
|
1310
|
+
useEffect4(() => {
|
|
1423
1311
|
const handleKeyDown = (event) => {
|
|
1424
1312
|
if (event.key === "Escape") onClose();
|
|
1425
1313
|
};
|
|
1426
1314
|
window.addEventListener("keydown", handleKeyDown);
|
|
1427
1315
|
return () => window.removeEventListener("keydown", handleKeyDown);
|
|
1428
1316
|
}, [onClose]);
|
|
1429
|
-
return /* @__PURE__ */
|
|
1430
|
-
/* @__PURE__ */
|
|
1317
|
+
return /* @__PURE__ */ jsxs12(BasePopup_default, { title: `Change parent of ${genrePlaylist.name}`, onClose, showCancelButton: true, fitContent: true, children: [
|
|
1318
|
+
/* @__PURE__ */ jsxs12("p", { className: "mb-3 text-sm text-[var(--color-text-muted)]", children: [
|
|
1431
1319
|
"Current parent: ",
|
|
1432
1320
|
genrePlaylist.parent?.name ?? "none"
|
|
1433
1321
|
] }),
|
|
1434
|
-
/* @__PURE__ */
|
|
1322
|
+
/* @__PURE__ */ jsx16("div", { "aria-busy": isPending, className: isPending ? "pointer-events-none opacity-60" : void 0, children: /* @__PURE__ */ jsx16(
|
|
1435
1323
|
GenreSearch,
|
|
1436
1324
|
{
|
|
1437
1325
|
genrePlaylists: candidates,
|
|
@@ -1439,7 +1327,7 @@ function ChangeParentPopup({
|
|
|
1439
1327
|
placeholder: "Search a new parent\u2026"
|
|
1440
1328
|
}
|
|
1441
1329
|
) }),
|
|
1442
|
-
formErrors.length > 0 && /* @__PURE__ */
|
|
1330
|
+
formErrors.length > 0 && /* @__PURE__ */ jsx16("p", { role: "alert", className: "mt-3 text-sm text-[var(--color-red-500)]", children: formErrors.map(({ message }) => message).join(" ") })
|
|
1443
1331
|
] });
|
|
1444
1332
|
}
|
|
1445
1333
|
|
|
@@ -1463,7 +1351,7 @@ import {
|
|
|
1463
1351
|
SiYoutube
|
|
1464
1352
|
} from "react-icons/si";
|
|
1465
1353
|
import { Chip } from "@behindthemusictree/ui";
|
|
1466
|
-
import { jsx as
|
|
1354
|
+
import { jsx as jsx17 } from "react/jsx-runtime";
|
|
1467
1355
|
var LINK_KINDS = {
|
|
1468
1356
|
official: { label: "Official website", Icon: Globe },
|
|
1469
1357
|
wikipedia: { label: "Wikipedia", Icon: SiWikipedia2 },
|
|
@@ -1500,7 +1388,7 @@ function artistLinks(artist) {
|
|
|
1500
1388
|
return links;
|
|
1501
1389
|
}
|
|
1502
1390
|
function ArtistLinks({ links }) {
|
|
1503
|
-
return /* @__PURE__ */
|
|
1391
|
+
return /* @__PURE__ */ jsx17("ul", { className: "flex flex-wrap gap-1.5", children: links.map(({ key, url, Icon, label }) => /* @__PURE__ */ jsx17("li", { children: /* @__PURE__ */ jsx17(Chip, { href: url, icon: /* @__PURE__ */ jsx17(Icon, { className: "h-3.5 w-3.5 shrink-0", "aria-hidden": "true" }), children: label }) }, key)) });
|
|
1504
1392
|
}
|
|
1505
1393
|
|
|
1506
1394
|
// src/genre-tree/artist/formatYears.ts
|
|
@@ -1511,7 +1399,7 @@ function formatYears(beginYear, endYear, ended) {
|
|
|
1511
1399
|
}
|
|
1512
1400
|
|
|
1513
1401
|
// src/genre-tree/artist/ArtistHeader.tsx
|
|
1514
|
-
import { jsx as
|
|
1402
|
+
import { jsx as jsx18 } from "react/jsx-runtime";
|
|
1515
1403
|
var countryNames = new Intl.DisplayNames(["en"], { type: "region" });
|
|
1516
1404
|
function ArtistHeader({ artist }) {
|
|
1517
1405
|
const fields = [];
|
|
@@ -1521,35 +1409,35 @@ function ArtistHeader({ artist }) {
|
|
|
1521
1409
|
const years = formatYears(artist.beginYear, artist.endYear, artist.ended);
|
|
1522
1410
|
if (years) fields.push({ label: "Active", value: years });
|
|
1523
1411
|
const links = artistLinks(artist);
|
|
1524
|
-
if (links.length > 0) fields.push({ label: "Links", value: /* @__PURE__ */
|
|
1412
|
+
if (links.length > 0) fields.push({ label: "Links", value: /* @__PURE__ */ jsx18(ArtistLinks, { links }) });
|
|
1525
1413
|
if (fields.length === 0) return null;
|
|
1526
|
-
return /* @__PURE__ */
|
|
1414
|
+
return /* @__PURE__ */ jsx18(FieldList, { items: fields });
|
|
1527
1415
|
}
|
|
1528
1416
|
|
|
1529
1417
|
// src/genre-tree/artist/ArtistPhoto.tsx
|
|
1530
|
-
import { jsx as
|
|
1418
|
+
import { jsx as jsx19, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
1531
1419
|
function ExternalLink({ href, children }) {
|
|
1532
|
-
return /* @__PURE__ */
|
|
1420
|
+
return /* @__PURE__ */ jsx19("a", { href, target: "_blank", rel: "noopener noreferrer", className: "underline-offset-2 hover:underline", children });
|
|
1533
1421
|
}
|
|
1534
1422
|
function ArtistPhoto({ image, name }) {
|
|
1535
|
-
return /* @__PURE__ */
|
|
1536
|
-
/* @__PURE__ */
|
|
1537
|
-
/* @__PURE__ */
|
|
1423
|
+
return /* @__PURE__ */ jsxs13("figure", { className: "flex flex-col gap-1.5 px-6 py-2.5", children: [
|
|
1424
|
+
/* @__PURE__ */ jsx19("img", { src: image.url, alt: name, className: "h-64 w-full object-contain bg-[var(--color-surface-muted)] rounded" }),
|
|
1425
|
+
/* @__PURE__ */ jsxs13("figcaption", { className: "text-xs text-[var(--color-text-muted)]", children: [
|
|
1538
1426
|
"Photo: ",
|
|
1539
|
-
/* @__PURE__ */
|
|
1427
|
+
/* @__PURE__ */ jsx19(ExternalLink, { href: image.pageUrl, children: image.author ?? "Wikimedia Commons" }),
|
|
1540
1428
|
",",
|
|
1541
1429
|
" ",
|
|
1542
|
-
image.licenseUrl ? /* @__PURE__ */
|
|
1430
|
+
image.licenseUrl ? /* @__PURE__ */ jsx19(ExternalLink, { href: image.licenseUrl, children: image.license }) : image.license
|
|
1543
1431
|
] })
|
|
1544
1432
|
] });
|
|
1545
1433
|
}
|
|
1546
1434
|
|
|
1547
1435
|
// src/genre-tree/artist/ArtistMembers.tsx
|
|
1548
|
-
import { PanelGroup, PanelSection } from "@behindthemusictree/ui";
|
|
1549
|
-
import { jsx as
|
|
1436
|
+
import { PanelGroup, PanelSection as PanelSection3 } from "@behindthemusictree/ui";
|
|
1437
|
+
import { jsx as jsx20, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
1550
1438
|
function MembershipList({ title, memberships, renderArtistLink }) {
|
|
1551
1439
|
if (memberships.length === 0) return null;
|
|
1552
|
-
return /* @__PURE__ */
|
|
1440
|
+
return /* @__PURE__ */ jsx20(PanelGroup, { title, children: /* @__PURE__ */ jsx20("ul", { children: memberships.map((membership, index) => {
|
|
1553
1441
|
const details = [
|
|
1554
1442
|
formatYears(membership.beginYear, membership.endYear, membership.ended),
|
|
1555
1443
|
...membership.roles
|
|
@@ -1557,9 +1445,9 @@ function MembershipList({ title, memberships, renderArtistLink }) {
|
|
|
1557
1445
|
const detailsText = details.filter(Boolean).join(" \xB7 ");
|
|
1558
1446
|
return (
|
|
1559
1447
|
// A member can have several periods in the same group.
|
|
1560
|
-
/* @__PURE__ */
|
|
1561
|
-
/* @__PURE__ */
|
|
1562
|
-
detailsText && /* @__PURE__ */
|
|
1448
|
+
/* @__PURE__ */ jsxs14("li", { className: "truncate py-0.5", title: detailsText || void 0, children: [
|
|
1449
|
+
/* @__PURE__ */ jsx20("span", { className: "font-medium text-[var(--color-text)]", children: renderArtistLink(membership.artist) }),
|
|
1450
|
+
detailsText && /* @__PURE__ */ jsxs14("span", { className: "text-[var(--color-text-muted)]", children: [
|
|
1563
1451
|
" \u2014 ",
|
|
1564
1452
|
detailsText
|
|
1565
1453
|
] })
|
|
@@ -1570,9 +1458,9 @@ function MembershipList({ title, memberships, renderArtistLink }) {
|
|
|
1570
1458
|
function ArtistMembers({ title, memberships, renderArtistLink }) {
|
|
1571
1459
|
if (memberships.length === 0) return null;
|
|
1572
1460
|
const isCurrent = (membership) => !membership.ended && membership.endYear === null;
|
|
1573
|
-
return /* @__PURE__ */
|
|
1574
|
-
/* @__PURE__ */
|
|
1575
|
-
/* @__PURE__ */
|
|
1461
|
+
return /* @__PURE__ */ jsxs14(PanelSection3, { title, children: [
|
|
1462
|
+
/* @__PURE__ */ jsx20(MembershipList, { title: "Current", memberships: memberships.filter(isCurrent), renderArtistLink }),
|
|
1463
|
+
/* @__PURE__ */ jsx20(
|
|
1576
1464
|
MembershipList,
|
|
1577
1465
|
{
|
|
1578
1466
|
title: "Past",
|
|
@@ -1584,8 +1472,8 @@ function ArtistMembers({ title, memberships, renderArtistLink }) {
|
|
|
1584
1472
|
}
|
|
1585
1473
|
|
|
1586
1474
|
// src/genre-tree/artist/ArtistDiscography.tsx
|
|
1587
|
-
import { PanelGroup as PanelGroup2, PanelSection as
|
|
1588
|
-
import { jsx as
|
|
1475
|
+
import { PanelGroup as PanelGroup2, PanelSection as PanelSection4 } from "@behindthemusictree/ui";
|
|
1476
|
+
import { jsx as jsx21, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
1589
1477
|
var GROUPS = ["Albums", "EPs", "Singles", "Live", "Compilations", "Other"];
|
|
1590
1478
|
var PRIMARY_GROUPS = { album: "Albums", ep: "EPs", single: "Singles" };
|
|
1591
1479
|
function discographyGroup({ primaryType, secondaryTypes }) {
|
|
@@ -1605,21 +1493,21 @@ function byYear(a, b) {
|
|
|
1605
1493
|
function ArtistDiscography({ albums }) {
|
|
1606
1494
|
if (albums.length === 0) return null;
|
|
1607
1495
|
const sorted = [...albums].sort(byYear);
|
|
1608
|
-
return /* @__PURE__ */
|
|
1496
|
+
return /* @__PURE__ */ jsx21(PanelSection4, { title: "Discography", children: GROUPS.map((group) => {
|
|
1609
1497
|
const groupAlbums = sorted.filter((album) => discographyGroup(album) === group);
|
|
1610
1498
|
if (groupAlbums.length === 0) return null;
|
|
1611
|
-
return /* @__PURE__ */
|
|
1612
|
-
/* @__PURE__ */
|
|
1613
|
-
/* @__PURE__ */
|
|
1499
|
+
return /* @__PURE__ */ jsx21(PanelGroup2, { title: group, children: /* @__PURE__ */ jsx21("ul", { children: groupAlbums.map((album) => /* @__PURE__ */ jsxs15("li", { className: "grid grid-cols-[2.5rem_minmax(0,1fr)] gap-2 py-0.5", children: [
|
|
1500
|
+
/* @__PURE__ */ jsx21("span", { className: "tabular-nums text-[var(--color-text-muted)]", children: album.year ?? "\u2014" }),
|
|
1501
|
+
/* @__PURE__ */ jsx21("span", { className: "truncate text-[var(--color-text)]", title: album.name, children: album.name })
|
|
1614
1502
|
] }, album.uuid)) }) }, group);
|
|
1615
1503
|
}) });
|
|
1616
1504
|
}
|
|
1617
1505
|
|
|
1618
1506
|
// src/genre-tree/artist/ArtistSongs.tsx
|
|
1619
|
-
import { useState as
|
|
1507
|
+
import { useState as useState6 } from "react";
|
|
1620
1508
|
import { keepPreviousData } from "@tanstack/react-query";
|
|
1621
1509
|
import { Play as Play2 } from "lucide-react";
|
|
1622
|
-
import { Pagination, PanelSection as
|
|
1510
|
+
import { Pagination, PanelSection as PanelSection5, Skeleton as Skeleton3 } from "@behindthemusictree/ui";
|
|
1623
1511
|
import { usePlayer as usePlayer8 } from "@behindthemusictree/app-kit/player";
|
|
1624
1512
|
import {
|
|
1625
1513
|
SongDetailedSchema as SongDetailedSchema2,
|
|
@@ -1637,7 +1525,7 @@ import { useTrackList as useTrackList3 } from "@behindthemusictree/app-kit/genre
|
|
|
1637
1525
|
import { FaPlay as FaPlay2, FaPause as FaPause2 } from "react-icons/fa";
|
|
1638
1526
|
import { usePlayer as usePlayer6 } from "@behindthemusictree/app-kit/player";
|
|
1639
1527
|
import { PlayStates as PlayStates2 } from "@behindthemusictree/app-kit/player";
|
|
1640
|
-
import { jsx as
|
|
1528
|
+
import { jsx as jsx22, jsxs as jsxs16 } from "react/jsx-runtime";
|
|
1641
1529
|
function TrackPositionPlayPause({
|
|
1642
1530
|
position,
|
|
1643
1531
|
uuid,
|
|
@@ -1651,14 +1539,14 @@ function TrackPositionPlayPause({
|
|
|
1651
1539
|
const isPlaying = isThisTrack && isConfirmedPlayable && playState === PlayStates2.PLAYING;
|
|
1652
1540
|
const isPaused = isThisTrack && isConfirmedPlayable && playState === PlayStates2.PAUSED;
|
|
1653
1541
|
const isCurrentTrackActive = isPlaying || isPaused;
|
|
1654
|
-
return /* @__PURE__ */
|
|
1542
|
+
return /* @__PURE__ */ jsxs16(
|
|
1655
1543
|
"div",
|
|
1656
1544
|
{
|
|
1657
1545
|
className: "track-position-play-pause relative flex items-center justify-center gap-2 text-lg w-16 cursor-pointer",
|
|
1658
1546
|
style: { minWidth: "4rem", maxWidth: "4rem" },
|
|
1659
1547
|
onClick: handlePlayPauseClick,
|
|
1660
1548
|
children: [
|
|
1661
|
-
/* @__PURE__ */
|
|
1549
|
+
/* @__PURE__ */ jsx22("div", { className: "track-position-play-pause__status group-hover:hidden flex items-center justify-center", children: isAwaitingPlayback ? /* @__PURE__ */ jsx22("span", { className: "track-position-play-pause__spinner", role: "status", "aria-label": "Loading track" }) : isCurrentTrackActive ? /* @__PURE__ */ jsxs16(
|
|
1662
1550
|
"span",
|
|
1663
1551
|
{
|
|
1664
1552
|
className: "track-position-play-pause__bars",
|
|
@@ -1666,18 +1554,18 @@ function TrackPositionPlayPause({
|
|
|
1666
1554
|
role: "img",
|
|
1667
1555
|
"aria-label": isPlaying ? "Playing" : "Paused",
|
|
1668
1556
|
children: [
|
|
1669
|
-
/* @__PURE__ */
|
|
1670
|
-
/* @__PURE__ */
|
|
1671
|
-
/* @__PURE__ */
|
|
1557
|
+
/* @__PURE__ */ jsx22("span", { className: "track-position-play-pause__bar" }),
|
|
1558
|
+
/* @__PURE__ */ jsx22("span", { className: "track-position-play-pause__bar" }),
|
|
1559
|
+
/* @__PURE__ */ jsx22("span", { className: "track-position-play-pause__bar" })
|
|
1672
1560
|
]
|
|
1673
1561
|
}
|
|
1674
1562
|
) : position }),
|
|
1675
|
-
/* @__PURE__ */
|
|
1563
|
+
/* @__PURE__ */ jsx22(
|
|
1676
1564
|
"div",
|
|
1677
1565
|
{
|
|
1678
1566
|
className: `hidden group-hover:flex items-center justify-center ${isCurrentTrackActive ? "" : "absolute inset-0"}`,
|
|
1679
1567
|
"aria-hidden": "true",
|
|
1680
|
-
children: isAwaitingPlayback ? /* @__PURE__ */
|
|
1568
|
+
children: isAwaitingPlayback ? /* @__PURE__ */ jsx22("span", { className: "track-position-play-pause__spinner" }) : isPlaying ? /* @__PURE__ */ jsx22(FaPause2, {}) : /* @__PURE__ */ jsx22(FaPlay2, {})
|
|
1681
1569
|
}
|
|
1682
1570
|
)
|
|
1683
1571
|
]
|
|
@@ -1688,7 +1576,7 @@ function TrackPositionPlayPause({
|
|
|
1688
1576
|
// src/genre-tree/track-list-sidebar/TrackItem.tsx
|
|
1689
1577
|
import { isSong as isSong2, songUnplayableReason as songUnplayableReason2 } from "@behindthemusictree/app-kit/genre-tree";
|
|
1690
1578
|
import { ArtistNames as ArtistNames2 } from "@behindthemusictree/app-kit/genre-tree";
|
|
1691
|
-
import { jsx as
|
|
1579
|
+
import { jsx as jsx23, jsxs as jsxs17 } from "react/jsx-runtime";
|
|
1692
1580
|
function TrackItem({
|
|
1693
1581
|
track,
|
|
1694
1582
|
position,
|
|
@@ -1712,12 +1600,12 @@ function TrackItem({
|
|
|
1712
1600
|
loadTrackForPlayer(track.uuid);
|
|
1713
1601
|
}
|
|
1714
1602
|
};
|
|
1715
|
-
return /* @__PURE__ */
|
|
1603
|
+
return /* @__PURE__ */ jsxs17(
|
|
1716
1604
|
"div",
|
|
1717
1605
|
{
|
|
1718
1606
|
className: `track-item flex h-14 text-[var(--color-text)] ${isUnplayable ? "opacity-50" : "hover:bg-[var(--color-surface-muted)] group"}`,
|
|
1719
1607
|
children: [
|
|
1720
|
-
isUnplayable ? /* @__PURE__ */
|
|
1608
|
+
isUnplayable ? /* @__PURE__ */ jsx23(
|
|
1721
1609
|
"div",
|
|
1722
1610
|
{
|
|
1723
1611
|
className: "flex items-center justify-center text-lg w-16",
|
|
@@ -1725,7 +1613,7 @@ function TrackItem({
|
|
|
1725
1613
|
"aria-disabled": "true",
|
|
1726
1614
|
children: position
|
|
1727
1615
|
}
|
|
1728
|
-
) : /* @__PURE__ */
|
|
1616
|
+
) : /* @__PURE__ */ jsx23(
|
|
1729
1617
|
TrackPositionPlayPause,
|
|
1730
1618
|
{
|
|
1731
1619
|
position,
|
|
@@ -1734,12 +1622,12 @@ function TrackItem({
|
|
|
1734
1622
|
isSelected: selectedTrack?.uuid === track.uuid
|
|
1735
1623
|
}
|
|
1736
1624
|
),
|
|
1737
|
-
/* @__PURE__ */
|
|
1738
|
-
/* @__PURE__ */
|
|
1739
|
-
track.artists && track.artists.length > 0 ? /* @__PURE__ */
|
|
1625
|
+
/* @__PURE__ */ jsxs17("div", { className: "title-artist-container flex flex-col items-start justify-center min-w-0 flex-1", children: [
|
|
1626
|
+
/* @__PURE__ */ jsx23("div", { className: "flex max-w-full items-center gap-2", children: /* @__PURE__ */ jsx23("div", { className: "title text-lg font-bold text-[var(--color-text)] max-w-full truncate", children: renderSongLink ? renderSongLink(track) : isSong2(track) ? /* @__PURE__ */ jsx23(MusicBrainzRecordingLink, { song: track, className: "hover:underline focus-visible:underline", children: track.title }) : track.title }) }),
|
|
1627
|
+
track.artists && track.artists.length > 0 ? /* @__PURE__ */ jsx23("div", { className: "artist text-base max-w-full truncate text-[var(--color-text-muted)]", children: /* @__PURE__ */ jsx23(ArtistNames2, { artists: track.artists, renderArtistLink }) }) : ""
|
|
1740
1628
|
] }),
|
|
1741
|
-
/* @__PURE__ */
|
|
1742
|
-
renderDuration && /* @__PURE__ */
|
|
1629
|
+
/* @__PURE__ */ jsx23("div", { className: "genre-name-container flex items-center justify-start w-[21.6%] min-w-0 shrink-0", children: track.genre ? /* @__PURE__ */ jsx23("div", { className: "genre-name max-w-full whitespace-normal break-words p-1 text-xs font-bold", children: track.genre.name }) : "" }),
|
|
1630
|
+
renderDuration && /* @__PURE__ */ jsx23(
|
|
1743
1631
|
"div",
|
|
1744
1632
|
{
|
|
1745
1633
|
className: "duration flex text-base w-16 items-center justify-center",
|
|
@@ -1747,22 +1635,22 @@ function TrackItem({
|
|
|
1747
1635
|
children: renderDuration(track)
|
|
1748
1636
|
}
|
|
1749
1637
|
),
|
|
1750
|
-
renderActions && /* @__PURE__ */
|
|
1638
|
+
renderActions && /* @__PURE__ */ jsx23("div", { className: "edit flex text-base w-6 items-center justify-center mr-2 cursor-pointer", children: renderActions(track) })
|
|
1751
1639
|
]
|
|
1752
1640
|
}
|
|
1753
1641
|
);
|
|
1754
1642
|
}
|
|
1755
1643
|
|
|
1756
1644
|
// src/genre-tree/artist/ArtistSongs.tsx
|
|
1757
|
-
import { Fragment as Fragment8, jsx as
|
|
1645
|
+
import { Fragment as Fragment8, jsx as jsx24, jsxs as jsxs18 } from "react/jsx-runtime";
|
|
1758
1646
|
var SongPageSchema2 = PaginatedResponseSchema2(SongDetailedSchema2);
|
|
1759
1647
|
var SORTS = [
|
|
1760
1648
|
{ ordering: "title", label: "Title" },
|
|
1761
1649
|
{ ordering: "-albumYear", label: "Year" }
|
|
1762
1650
|
];
|
|
1763
1651
|
function ArtistSongs({ artist, getBackendBaseUrl, renderArtistLink, renderSongLink }) {
|
|
1764
|
-
const [page, setPage] =
|
|
1765
|
-
const [ordering, setOrdering] =
|
|
1652
|
+
const [page, setPage] = useState6(1);
|
|
1653
|
+
const [ordering, setOrdering] = useState6("title");
|
|
1766
1654
|
const { fetch } = useFetchWrapper2(getBackendBaseUrl);
|
|
1767
1655
|
const { playNewTrackListFromArtist } = useTrackList4();
|
|
1768
1656
|
const { playerTrackObject } = usePlayer8();
|
|
@@ -1787,21 +1675,21 @@ function ArtistSongs({ artist, getBackendBaseUrl, renderArtistLink, renderSongLi
|
|
|
1787
1675
|
event.stopPropagation();
|
|
1788
1676
|
void play(song.uuid);
|
|
1789
1677
|
};
|
|
1790
|
-
return /* @__PURE__ */
|
|
1791
|
-
/* @__PURE__ */
|
|
1792
|
-
/* @__PURE__ */
|
|
1678
|
+
return /* @__PURE__ */ jsx24(PanelSection5, { title: "Songs", children: isPending ? /* @__PURE__ */ jsx24(Skeleton3, { className: "h-14", "aria-busy": "true" }) : isError ? /* @__PURE__ */ jsx24("p", { className: "text-red-600", children: "Could not load songs." }) : data.results.length === 0 ? /* @__PURE__ */ jsx24("p", { className: "text-[var(--color-text-muted)]", children: "No songs yet." }) : /* @__PURE__ */ jsxs18(Fragment8, { children: [
|
|
1679
|
+
/* @__PURE__ */ jsxs18("div", { className: "flex flex-wrap items-center justify-between gap-2 mb-2", children: [
|
|
1680
|
+
/* @__PURE__ */ jsxs18(
|
|
1793
1681
|
"button",
|
|
1794
1682
|
{
|
|
1795
1683
|
type: "button",
|
|
1796
1684
|
onClick: () => void play(),
|
|
1797
1685
|
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",
|
|
1798
1686
|
children: [
|
|
1799
|
-
/* @__PURE__ */
|
|
1687
|
+
/* @__PURE__ */ jsx24(Play2, { className: "h-3.5 w-3.5", "aria-hidden": "true" }),
|
|
1800
1688
|
"Play all"
|
|
1801
1689
|
]
|
|
1802
1690
|
}
|
|
1803
1691
|
),
|
|
1804
|
-
/* @__PURE__ */
|
|
1692
|
+
/* @__PURE__ */ jsx24("div", { role: "group", "aria-label": "Sort songs by", className: "flex gap-1 text-xs", children: SORTS.map((sort) => /* @__PURE__ */ jsx24(
|
|
1805
1693
|
"button",
|
|
1806
1694
|
{
|
|
1807
1695
|
type: "button",
|
|
@@ -1816,7 +1704,7 @@ function ArtistSongs({ artist, getBackendBaseUrl, renderArtistLink, renderSongLi
|
|
|
1816
1704
|
sort.ordering
|
|
1817
1705
|
)) })
|
|
1818
1706
|
] }),
|
|
1819
|
-
/* @__PURE__ */
|
|
1707
|
+
/* @__PURE__ */ jsx24("ul", { className: "overflow-hidden mb-2 bg-zinc-950 rounded-lg", children: data.results.map((song, index) => /* @__PURE__ */ jsx24("li", { onClickCapture: (event) => handleRowClickCapture(event, song), children: /* @__PURE__ */ jsx24(
|
|
1820
1708
|
TrackItem,
|
|
1821
1709
|
{
|
|
1822
1710
|
track: song,
|
|
@@ -1825,12 +1713,12 @@ function ArtistSongs({ artist, getBackendBaseUrl, renderArtistLink, renderSongLi
|
|
|
1825
1713
|
renderSongLink
|
|
1826
1714
|
}
|
|
1827
1715
|
) }, song.uuid)) }),
|
|
1828
|
-
/* @__PURE__ */
|
|
1716
|
+
/* @__PURE__ */ jsx24(Pagination, { currentPage: page, totalPages: data.totalPages, onPageChange: setPage })
|
|
1829
1717
|
] }) });
|
|
1830
1718
|
}
|
|
1831
1719
|
|
|
1832
1720
|
// src/genre-tree/artist/useArtistPanel.tsx
|
|
1833
|
-
import { Fragment as Fragment9, jsx as
|
|
1721
|
+
import { Fragment as Fragment9, jsx as jsx25, jsxs as jsxs19 } from "react/jsx-runtime";
|
|
1834
1722
|
function useArtistPanel({
|
|
1835
1723
|
uuid,
|
|
1836
1724
|
scope,
|
|
@@ -1851,26 +1739,26 @@ function useArtistPanel({
|
|
|
1851
1739
|
return {
|
|
1852
1740
|
...panel,
|
|
1853
1741
|
title: "Artist",
|
|
1854
|
-
content: /* @__PURE__ */
|
|
1855
|
-
/* @__PURE__ */
|
|
1856
|
-
/* @__PURE__ */
|
|
1857
|
-
/* @__PURE__ */
|
|
1858
|
-
/* @__PURE__ */
|
|
1859
|
-
/* @__PURE__ */
|
|
1860
|
-
/* @__PURE__ */
|
|
1742
|
+
content: /* @__PURE__ */ jsxs19("div", { "aria-busy": "true", className: "flex flex-col gap-2.5 px-6 py-2.5", children: [
|
|
1743
|
+
/* @__PURE__ */ jsx25(Skeleton4, { className: "h-3 w-16" }),
|
|
1744
|
+
/* @__PURE__ */ jsx25(Skeleton4, { className: "h-4 w-32" }),
|
|
1745
|
+
/* @__PURE__ */ jsx25(Skeleton4, { className: "h-3 w-16" }),
|
|
1746
|
+
/* @__PURE__ */ jsx25(Skeleton4, { className: "h-4 w-24" }),
|
|
1747
|
+
/* @__PURE__ */ jsx25(Skeleton4, { className: "h-16 mt-2.5" }),
|
|
1748
|
+
/* @__PURE__ */ jsx25(Skeleton4, { className: "h-16" })
|
|
1861
1749
|
] })
|
|
1862
1750
|
};
|
|
1863
1751
|
case "not-found":
|
|
1864
1752
|
return {
|
|
1865
1753
|
...panel,
|
|
1866
1754
|
title: "Artist not found",
|
|
1867
|
-
content: /* @__PURE__ */
|
|
1755
|
+
content: /* @__PURE__ */ jsx25("p", { className: "px-6 py-2.5 text-[var(--color-text-muted)]", children: "This artist does not exist." })
|
|
1868
1756
|
};
|
|
1869
1757
|
case "error":
|
|
1870
1758
|
return {
|
|
1871
1759
|
...panel,
|
|
1872
1760
|
title: "Artist",
|
|
1873
|
-
content: /* @__PURE__ */
|
|
1761
|
+
content: /* @__PURE__ */ jsx25("p", { className: "px-6 py-2.5 text-red-600", children: "Could not load this artist." })
|
|
1874
1762
|
};
|
|
1875
1763
|
case "success": {
|
|
1876
1764
|
const { artist } = result;
|
|
@@ -1879,13 +1767,13 @@ function useArtistPanel({
|
|
|
1879
1767
|
return {
|
|
1880
1768
|
...panel,
|
|
1881
1769
|
title: artist.name,
|
|
1882
|
-
content: /* @__PURE__ */
|
|
1883
|
-
shareUrl && /* @__PURE__ */
|
|
1884
|
-
artist.image && /* @__PURE__ */
|
|
1885
|
-
/* @__PURE__ */
|
|
1886
|
-
/* @__PURE__ */
|
|
1887
|
-
/* @__PURE__ */
|
|
1888
|
-
artist.tracksCount > 0 && /* @__PURE__ */
|
|
1770
|
+
content: /* @__PURE__ */ jsxs19(Fragment9, { children: [
|
|
1771
|
+
shareUrl && /* @__PURE__ */ jsx25("div", { className: "genre-action-band border-b border-[var(--color-border)]", children: /* @__PURE__ */ jsx25("div", { className: "flex flex-wrap gap-1 px-3.5 py-3", children: shareTarget && /* @__PURE__ */ jsx25(ShareActionButton, { target: shareTarget, url: shareUrl }) }) }),
|
|
1772
|
+
artist.image && /* @__PURE__ */ jsx25(ArtistPhoto, { image: artist.image, name: artist.name }),
|
|
1773
|
+
/* @__PURE__ */ jsx25(ArtistHeader, { artist }),
|
|
1774
|
+
/* @__PURE__ */ jsx25(ArtistMembers, { title: "Members", memberships: artist.members, renderArtistLink }),
|
|
1775
|
+
/* @__PURE__ */ jsx25(ArtistMembers, { title: "Member of", memberships: artist.memberOf, renderArtistLink }),
|
|
1776
|
+
artist.tracksCount > 0 && /* @__PURE__ */ jsx25(
|
|
1889
1777
|
ArtistSongs,
|
|
1890
1778
|
{
|
|
1891
1779
|
artist: { uuid: artist.uuid, name: artist.name },
|
|
@@ -1895,7 +1783,7 @@ function useArtistPanel({
|
|
|
1895
1783
|
}
|
|
1896
1784
|
)
|
|
1897
1785
|
] }),
|
|
1898
|
-
extraContent: artist.albums.length > 0 ? /* @__PURE__ */
|
|
1786
|
+
extraContent: artist.albums.length > 0 ? /* @__PURE__ */ jsx25(ArtistDiscography, { albums: artist.albums }) : void 0
|
|
1899
1787
|
};
|
|
1900
1788
|
}
|
|
1901
1789
|
}
|
|
@@ -1908,9 +1796,9 @@ import {
|
|
|
1908
1796
|
} from "@behindthemusictree/app-kit/genre-tree";
|
|
1909
1797
|
|
|
1910
1798
|
// src/genre-tree/song/SongPanelContent.tsx
|
|
1911
|
-
import { useState as
|
|
1799
|
+
import { useState as useState7 } from "react";
|
|
1912
1800
|
import { Pause as Pause2, Play as Play3 } from "lucide-react";
|
|
1913
|
-
import { FieldList as FieldList2, PanelSection as
|
|
1801
|
+
import { FieldList as FieldList2, PanelSection as PanelSection6, Skeleton as Skeleton5 } from "@behindthemusictree/ui";
|
|
1914
1802
|
import { PlayStates as PlayStates3, usePlayer as usePlayer9 } from "@behindthemusictree/app-kit/player";
|
|
1915
1803
|
import {
|
|
1916
1804
|
ArtistNames as ArtistNames3,
|
|
@@ -1919,40 +1807,40 @@ import {
|
|
|
1919
1807
|
useSongHistory,
|
|
1920
1808
|
useTrackList as useTrackList5
|
|
1921
1809
|
} from "@behindthemusictree/app-kit/genre-tree";
|
|
1922
|
-
import { Fragment as Fragment10, jsx as
|
|
1810
|
+
import { Fragment as Fragment10, jsx as jsx26, jsxs as jsxs20 } from "react/jsx-runtime";
|
|
1923
1811
|
var numberFormat = new Intl.NumberFormat("en");
|
|
1924
1812
|
var dateFormat = new Intl.DateTimeFormat("en", { dateStyle: "medium" });
|
|
1925
1813
|
var externalLink = "text-[var(--color-primary)] hover:underline focus-visible:underline";
|
|
1926
1814
|
function SongHistory({ uuid, getBackendBaseUrl }) {
|
|
1927
|
-
const [open, setOpen] =
|
|
1815
|
+
const [open, setOpen] = useState7(false);
|
|
1928
1816
|
const history = useSongHistory(uuid, getBackendBaseUrl, open);
|
|
1929
1817
|
let body = null;
|
|
1930
|
-
if (history.status === "loading") body = /* @__PURE__ */
|
|
1931
|
-
else if (history.status === "error") body = /* @__PURE__ */
|
|
1818
|
+
if (history.status === "loading") body = /* @__PURE__ */ jsx26(Skeleton5, { className: "h-10", "aria-busy": "true" });
|
|
1819
|
+
else if (history.status === "error") body = /* @__PURE__ */ jsx26("p", { className: "text-red-600", children: "Could not load the history." });
|
|
1932
1820
|
else if (history.status === "success")
|
|
1933
|
-
body = history.entries.length === 0 ? /* @__PURE__ */
|
|
1934
|
-
/* @__PURE__ */
|
|
1935
|
-
entry.oldValue !== null || entry.newValue !== null ? /* @__PURE__ */
|
|
1821
|
+
body = history.entries.length === 0 ? /* @__PURE__ */ jsx26("p", { className: "text-[var(--color-text-muted)]", children: "No changes yet." }) : /* @__PURE__ */ jsx26("ul", { className: "divide-y divide-[var(--color-border)]", children: history.entries.map((entry) => /* @__PURE__ */ jsxs20("li", { className: "py-1.5 text-sm", children: [
|
|
1822
|
+
/* @__PURE__ */ jsx26("span", { className: "font-medium", children: entry.action }),
|
|
1823
|
+
entry.oldValue !== null || entry.newValue !== null ? /* @__PURE__ */ jsxs20("span", { className: "text-[var(--color-text-muted)]", children: [
|
|
1936
1824
|
" ",
|
|
1937
1825
|
"\u2014 ",
|
|
1938
1826
|
entry.oldValue ?? "none",
|
|
1939
1827
|
" \u2192 ",
|
|
1940
1828
|
entry.newValue ?? "none"
|
|
1941
1829
|
] }) : null,
|
|
1942
|
-
/* @__PURE__ */
|
|
1830
|
+
/* @__PURE__ */ jsxs20("span", { className: "block text-xs text-[var(--color-text-muted)]", children: [
|
|
1943
1831
|
entry.actorPseudo ?? "Anonymous",
|
|
1944
1832
|
" \xB7 ",
|
|
1945
1833
|
dateFormat.format(new Date(entry.createdOn))
|
|
1946
1834
|
] })
|
|
1947
1835
|
] }, entry.uuid)) });
|
|
1948
|
-
return /* @__PURE__ */
|
|
1836
|
+
return /* @__PURE__ */ jsxs20(
|
|
1949
1837
|
"details",
|
|
1950
1838
|
{
|
|
1951
1839
|
onToggle: (event) => setOpen(event.currentTarget.open),
|
|
1952
1840
|
className: "px-6 pb-2.5 mt-2.5 border-t border-[var(--color-border)]",
|
|
1953
1841
|
children: [
|
|
1954
|
-
/* @__PURE__ */
|
|
1955
|
-
/* @__PURE__ */
|
|
1842
|
+
/* @__PURE__ */ jsx26("summary", { className: "mt-2.5 cursor-pointer text-[0.6875rem] font-semibold uppercase text-[var(--color-text-muted)]", children: "History" }),
|
|
1843
|
+
/* @__PURE__ */ jsx26("div", { className: "mt-1.5", children: body })
|
|
1956
1844
|
]
|
|
1957
1845
|
}
|
|
1958
1846
|
);
|
|
@@ -1978,13 +1866,13 @@ function SongPanelContent({
|
|
|
1978
1866
|
const path = genrePath.length > 0 ? genrePath : null;
|
|
1979
1867
|
fields.push({
|
|
1980
1868
|
label: "Genre",
|
|
1981
|
-
value: path ? /* @__PURE__ */
|
|
1982
|
-
index > 0 && /* @__PURE__ */
|
|
1983
|
-
/* @__PURE__ */
|
|
1869
|
+
value: path ? /* @__PURE__ */ jsx26("span", { className: "flex flex-wrap items-center gap-x-1", children: path.map((genrePlaylist, index) => /* @__PURE__ */ jsxs20("span", { children: [
|
|
1870
|
+
index > 0 && /* @__PURE__ */ jsx26("span", { "aria-hidden": "true", children: "\u203A " }),
|
|
1871
|
+
/* @__PURE__ */ jsx26("button", { type: "button", onClick: () => onSelectGenre(genrePlaylist), className: "hover:underline", children: genrePlaylist.name })
|
|
1984
1872
|
] }, genrePlaylist.uuid)) }) : song.genre.name
|
|
1985
1873
|
});
|
|
1986
1874
|
} else {
|
|
1987
|
-
fields.push({ label: "Genre", value: /* @__PURE__ */
|
|
1875
|
+
fields.push({ label: "Genre", value: /* @__PURE__ */ jsx26("span", { className: "text-[var(--color-text-muted)]", children: "No genre" }) });
|
|
1988
1876
|
}
|
|
1989
1877
|
if (song.firstReleaseYear) fields.push({ label: "First released", value: song.firstReleaseYear });
|
|
1990
1878
|
const viewCount = song.youtubeVideo?.viewCount;
|
|
@@ -1994,11 +1882,11 @@ function SongPanelContent({
|
|
|
1994
1882
|
const links = [];
|
|
1995
1883
|
if (musicBrainzUrl)
|
|
1996
1884
|
links.push(
|
|
1997
|
-
/* @__PURE__ */
|
|
1885
|
+
/* @__PURE__ */ jsx26("a", { href: musicBrainzUrl, target: "_blank", rel: "noopener noreferrer", className: externalLink, children: "MusicBrainz" }, "mb")
|
|
1998
1886
|
);
|
|
1999
1887
|
if (song.youtubeVideo)
|
|
2000
1888
|
links.push(
|
|
2001
|
-
/* @__PURE__ */
|
|
1889
|
+
/* @__PURE__ */ jsx26(
|
|
2002
1890
|
"a",
|
|
2003
1891
|
{
|
|
2004
1892
|
href: `https://www.youtube.com/watch?v=${encodeURIComponent(song.youtubeVideo.id)}`,
|
|
@@ -2013,33 +1901,33 @@ function SongPanelContent({
|
|
|
2013
1901
|
if (links.length > 0)
|
|
2014
1902
|
fields.push({
|
|
2015
1903
|
label: "Links",
|
|
2016
|
-
value: /* @__PURE__ */
|
|
1904
|
+
value: /* @__PURE__ */ jsx26("span", { className: "flex gap-3", children: links })
|
|
2017
1905
|
});
|
|
2018
|
-
return /* @__PURE__ */
|
|
2019
|
-
/* @__PURE__ */
|
|
2020
|
-
unplayableReason ? /* @__PURE__ */
|
|
1906
|
+
return /* @__PURE__ */ jsxs20(Fragment10, { children: [
|
|
1907
|
+
/* @__PURE__ */ jsx26("div", { className: "genre-action-band border-b border-[var(--color-border)]", children: /* @__PURE__ */ jsxs20("div", { className: "flex flex-wrap gap-1 px-3.5 py-3", children: [
|
|
1908
|
+
unplayableReason ? /* @__PURE__ */ jsx26("p", { className: "flex items-center px-2.5 text-sm text-[var(--color-text-muted)]", children: unplayableReason }) : /* @__PURE__ */ jsxs20(
|
|
2021
1909
|
"button",
|
|
2022
1910
|
{
|
|
2023
1911
|
type: "button",
|
|
2024
1912
|
onClick: () => isCurrent ? handlePlayPauseAction() : playNewTrackListFromTrackUuid(song, scope),
|
|
2025
1913
|
className: "group flex flex-col items-center gap-1 w-16 text-xs text-center text-[var(--color-text)] focus-visible:outline-none",
|
|
2026
1914
|
children: [
|
|
2027
|
-
/* @__PURE__ */
|
|
1915
|
+
/* @__PURE__ */ jsx26("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__ */ jsx26(Pause2, { "aria-hidden": "true", className: "w-5 h-5" }) : /* @__PURE__ */ jsx26(Play3, { "aria-hidden": "true", className: "w-5 h-5" }) }),
|
|
2028
1916
|
isPlaying ? "Pause" : "Play"
|
|
2029
1917
|
]
|
|
2030
1918
|
}
|
|
2031
1919
|
),
|
|
2032
|
-
shareUrl && /* @__PURE__ */
|
|
1920
|
+
shareUrl && /* @__PURE__ */ jsx26(ShareActionButton, { target: shareTarget, url: shareUrl })
|
|
2033
1921
|
] }) }),
|
|
2034
|
-
song.artists && song.artists.length > 0 && /* @__PURE__ */
|
|
2035
|
-
/* @__PURE__ */
|
|
2036
|
-
song.essentialGenres && song.essentialGenres.length > 0 && /* @__PURE__ */
|
|
2037
|
-
/* @__PURE__ */
|
|
1922
|
+
song.artists && song.artists.length > 0 && /* @__PURE__ */ jsx26("p", { className: "px-6 pt-2.5 text-[var(--color-text-muted)]", children: /* @__PURE__ */ jsx26(ArtistNames3, { artists: song.artists, renderArtistLink }) }),
|
|
1923
|
+
/* @__PURE__ */ jsx26(FieldList2, { items: fields }),
|
|
1924
|
+
song.essentialGenres && song.essentialGenres.length > 0 && /* @__PURE__ */ jsx26(PanelSection6, { title: "Essential in", children: /* @__PURE__ */ jsx26("ul", { children: song.essentialGenres.map((genre) => /* @__PURE__ */ jsx26("li", { className: "py-0.5", children: genre.name }, genre.uuid)) }) }),
|
|
1925
|
+
/* @__PURE__ */ jsx26(SongHistory, { uuid: song.uuid, getBackendBaseUrl })
|
|
2038
1926
|
] });
|
|
2039
1927
|
}
|
|
2040
1928
|
|
|
2041
1929
|
// src/genre-tree/song/useSongPanel.tsx
|
|
2042
|
-
import { jsx as
|
|
1930
|
+
import { jsx as jsx27, jsxs as jsxs21 } from "react/jsx-runtime";
|
|
2043
1931
|
function useSongPanel({
|
|
2044
1932
|
uuid,
|
|
2045
1933
|
scope,
|
|
@@ -2061,24 +1949,24 @@ function useSongPanel({
|
|
|
2061
1949
|
return {
|
|
2062
1950
|
...panel,
|
|
2063
1951
|
title: "Song",
|
|
2064
|
-
content: /* @__PURE__ */
|
|
2065
|
-
/* @__PURE__ */
|
|
2066
|
-
/* @__PURE__ */
|
|
2067
|
-
/* @__PURE__ */
|
|
2068
|
-
/* @__PURE__ */
|
|
1952
|
+
content: /* @__PURE__ */ jsxs21("div", { "aria-busy": "true", className: "flex flex-col gap-2.5 px-6 py-2.5", children: [
|
|
1953
|
+
/* @__PURE__ */ jsx27(Skeleton6, { className: "h-3 w-16" }),
|
|
1954
|
+
/* @__PURE__ */ jsx27(Skeleton6, { className: "h-4 w-32" }),
|
|
1955
|
+
/* @__PURE__ */ jsx27(Skeleton6, { className: "h-3 w-16" }),
|
|
1956
|
+
/* @__PURE__ */ jsx27(Skeleton6, { className: "h-4 w-24" })
|
|
2069
1957
|
] })
|
|
2070
1958
|
};
|
|
2071
1959
|
case "not-found":
|
|
2072
1960
|
return {
|
|
2073
1961
|
...panel,
|
|
2074
1962
|
title: "Song not found",
|
|
2075
|
-
content: /* @__PURE__ */
|
|
1963
|
+
content: /* @__PURE__ */ jsx27("p", { className: "px-6 py-2.5 text-[var(--color-text-muted)]", children: "This song does not exist." })
|
|
2076
1964
|
};
|
|
2077
1965
|
case "error":
|
|
2078
1966
|
return {
|
|
2079
1967
|
...panel,
|
|
2080
1968
|
title: "Song",
|
|
2081
|
-
content: /* @__PURE__ */
|
|
1969
|
+
content: /* @__PURE__ */ jsx27("p", { className: "px-6 py-2.5 text-red-600", children: "Could not load this song." })
|
|
2082
1970
|
};
|
|
2083
1971
|
case "success": {
|
|
2084
1972
|
const { song } = result;
|
|
@@ -2086,7 +1974,7 @@ function useSongPanel({
|
|
|
2086
1974
|
return {
|
|
2087
1975
|
...panel,
|
|
2088
1976
|
title: song.title,
|
|
2089
|
-
content: /* @__PURE__ */
|
|
1977
|
+
content: /* @__PURE__ */ jsx27(
|
|
2090
1978
|
SongPanelContent,
|
|
2091
1979
|
{
|
|
2092
1980
|
song,
|
|
@@ -2106,12 +1994,12 @@ function useSongPanel({
|
|
|
2106
1994
|
// src/genre-tree/SizeMetricToggle.tsx
|
|
2107
1995
|
import { MdMusicNote, MdVisibility } from "react-icons/md";
|
|
2108
1996
|
import { SegmentedControl } from "@behindthemusictree/ui";
|
|
2109
|
-
import { jsx as
|
|
1997
|
+
import { jsx as jsx28 } from "react/jsx-runtime";
|
|
2110
1998
|
function SizeMetricToggle({
|
|
2111
1999
|
value,
|
|
2112
2000
|
onChange
|
|
2113
2001
|
}) {
|
|
2114
|
-
return /* @__PURE__ */
|
|
2002
|
+
return /* @__PURE__ */ jsx28(
|
|
2115
2003
|
SegmentedControl,
|
|
2116
2004
|
{
|
|
2117
2005
|
variant: "floating",
|
|
@@ -2119,26 +2007,19 @@ function SizeMetricToggle({
|
|
|
2119
2007
|
value,
|
|
2120
2008
|
onChange,
|
|
2121
2009
|
options: [
|
|
2122
|
-
{ value: "songs", label: /* @__PURE__ */
|
|
2123
|
-
{ value: "views", label: /* @__PURE__ */
|
|
2010
|
+
{ value: "songs", label: /* @__PURE__ */ jsx28(MdMusicNote, { size: 18, "aria-hidden": true }), "aria-label": "Size by songs", title: "Node size by song count" },
|
|
2011
|
+
{ value: "views", label: /* @__PURE__ */ jsx28(MdVisibility, { size: 18, "aria-hidden": true }), "aria-label": "Size by views", title: "Node size by song views" }
|
|
2124
2012
|
]
|
|
2125
2013
|
}
|
|
2126
2014
|
);
|
|
2127
2015
|
}
|
|
2128
2016
|
|
|
2129
2017
|
// src/genre-tree/GenreTreeView.tsx
|
|
2130
|
-
import { Fragment as Fragment11, jsx as
|
|
2131
|
-
var PREVIOUS_BUTTON_CSS = `
|
|
2132
|
-
.genre-tree-view .search-overlay .gtv-info-panel-previous { display: none; }
|
|
2133
|
-
.genre-tree-view:has(.search-overlay .gtv-info-panel-previous) .genre-search input { padding-left: 2.75rem; }
|
|
2134
|
-
.genre-tree-view:has(.search-overlay .gtv-info-panel-previous) .genre-search-previous { display: flex; }
|
|
2135
|
-
@keyframes genre-tree-view-previous-in { from { opacity: 0; transform: translate(-0.5rem, -50%); } to { opacity: 1; transform: translate(0, -50%); } }
|
|
2136
|
-
@media (prefers-reduced-motion: no-preference) {
|
|
2137
|
-
.genre-search-previous { animation: genre-tree-view-previous-in 200ms ease-out; }
|
|
2138
|
-
}
|
|
2139
|
-
`;
|
|
2018
|
+
import { Fragment as Fragment11, jsx as jsx29, jsxs as jsxs22 } from "react/jsx-runtime";
|
|
2140
2019
|
var NO_POP_ROOT_TITLE = "This genre tree has no 'Mainstream Pop' root yet";
|
|
2141
|
-
var REGIONS_CLASS = "[--gtv-center-left:var(--layout-center-left)] [--gtv-center-right:var(--layout-center-right)] [--gtv-center-top:var(--layout-band-top)]
|
|
2020
|
+
var REGIONS_CLASS = "[--gtv-center-left:var(--layout-center-left)] [--gtv-center-right:var(--layout-center-right)] [--gtv-center-top:var(--layout-band-top)]";
|
|
2021
|
+
var noop = () => {
|
|
2022
|
+
};
|
|
2142
2023
|
function GenreTreeView({
|
|
2143
2024
|
scope,
|
|
2144
2025
|
handleGenreCreationAction,
|
|
@@ -2192,19 +2073,19 @@ function GenreTreeView({
|
|
|
2192
2073
|
placement = "default",
|
|
2193
2074
|
...focus
|
|
2194
2075
|
}) {
|
|
2195
|
-
const getShareUrlRef =
|
|
2076
|
+
const getShareUrlRef = useRef3(getShareUrl);
|
|
2196
2077
|
getShareUrlRef.current = getShareUrl;
|
|
2197
|
-
const [internalArtistUuid, setInternalArtistUuid] =
|
|
2078
|
+
const [internalArtistUuid, setInternalArtistUuid] = useState8(null);
|
|
2198
2079
|
const isArtistControlled = controlledArtistUuid !== void 0;
|
|
2199
2080
|
const artistUuid = isArtistControlled ? controlledArtistUuid : internalArtistUuid;
|
|
2200
|
-
const [internalSongUuid, setInternalSongUuid] =
|
|
2081
|
+
const [internalSongUuid, setInternalSongUuid] = useState8(null);
|
|
2201
2082
|
const isSongControlled = controlledSongUuid !== void 0;
|
|
2202
2083
|
const songUuid = isSongControlled ? controlledSongUuid : internalSongUuid;
|
|
2203
2084
|
const changeSong = (uuid) => {
|
|
2204
2085
|
if (!isSongControlled) setInternalSongUuid(uuid);
|
|
2205
2086
|
onSongUuidChange?.(uuid);
|
|
2206
2087
|
};
|
|
2207
|
-
const [internalSizeMetric, setInternalSizeMetric] =
|
|
2088
|
+
const [internalSizeMetric, setInternalSizeMetric] = useState8("songs");
|
|
2208
2089
|
const sizeMetric = controlledSizeMetric ?? internalSizeMetric;
|
|
2209
2090
|
const deferredSizeMetric = useDeferredValue(sizeMetric);
|
|
2210
2091
|
const changeSizeMetric = (metric) => {
|
|
@@ -2243,7 +2124,7 @@ function GenreTreeView({
|
|
|
2243
2124
|
artistUuid
|
|
2244
2125
|
});
|
|
2245
2126
|
const restoreRevision = viewportRestore?.revision;
|
|
2246
|
-
const [stackedRestoreOwner, setStackedRestoreOwner] =
|
|
2127
|
+
const [stackedRestoreOwner, setStackedRestoreOwner] = useState8({ revision: restoreRevision, rootUuid: selectedGenrePlaylist?.root.uuid });
|
|
2247
2128
|
let restoreRootUuid = stackedRestoreOwner.rootUuid;
|
|
2248
2129
|
if (stackedRestoreOwner.revision !== restoreRevision) {
|
|
2249
2130
|
restoreRootUuid = selectedGenrePlaylist?.root.uuid;
|
|
@@ -2274,14 +2155,14 @@ function GenreTreeView({
|
|
|
2274
2155
|
if (selectedNodeId !== null) clearSelection();
|
|
2275
2156
|
changeSong(uuid);
|
|
2276
2157
|
};
|
|
2277
|
-
const openSongRef =
|
|
2158
|
+
const openSongRef = useRef3(openSong);
|
|
2278
2159
|
openSongRef.current = openSong;
|
|
2279
2160
|
const resolvedRenderSongLink = useCallback6(
|
|
2280
|
-
(song) => renderSongLink ? renderSongLink(song) : /* @__PURE__ */
|
|
2161
|
+
(song) => renderSongLink ? renderSongLink(song) : /* @__PURE__ */ jsx29("button", { type: "button", onClick: () => openSongRef.current(song.uuid), className: "hover:underline", children: song.title }),
|
|
2281
2162
|
[renderSongLink]
|
|
2282
2163
|
);
|
|
2283
|
-
const [expandedSongUuid, setExpandedSongUuid] =
|
|
2284
|
-
const [expandedArtistUuid, setExpandedArtistUuid] =
|
|
2164
|
+
const [expandedSongUuid, setExpandedSongUuid] = useState8(null);
|
|
2165
|
+
const [expandedArtistUuid, setExpandedArtistUuid] = useState8(null);
|
|
2285
2166
|
const artistBaseUrl = artistSearchBaseUrl ?? getBackendBaseUrl;
|
|
2286
2167
|
const songBaseUrl = getBackendBaseUrl;
|
|
2287
2168
|
const artistPanel = useArtistPanel({
|
|
@@ -2289,7 +2170,7 @@ function GenreTreeView({
|
|
|
2289
2170
|
scope,
|
|
2290
2171
|
getBackendBaseUrl: artistBaseUrl,
|
|
2291
2172
|
getShareUrl: getShareUrlRef.current,
|
|
2292
|
-
renderArtistLink: renderArtistLink ?? ((artist) => artist.isSpecialPurpose ? artist.name : /* @__PURE__ */
|
|
2173
|
+
renderArtistLink: renderArtistLink ?? ((artist) => artist.isSpecialPurpose ? artist.name : /* @__PURE__ */ jsx29("button", { type: "button", onClick: () => openArtist(artist.uuid), className: "hover:underline", children: artist.name })),
|
|
2293
2174
|
expanded: controlledArtistExpanded ?? (artistUuid !== null && expandedArtistUuid === artistUuid),
|
|
2294
2175
|
onExpandedChange: (on) => {
|
|
2295
2176
|
if (controlledArtistExpanded === void 0) setExpandedArtistUuid(on ? artistUuid : null);
|
|
@@ -2298,7 +2179,7 @@ function GenreTreeView({
|
|
|
2298
2179
|
renderSongLink: resolvedRenderSongLink,
|
|
2299
2180
|
onClose: () => changeArtist(null)
|
|
2300
2181
|
});
|
|
2301
|
-
const resolvedRenderArtistLink = renderArtistLink ?? ((artist) => artist.isSpecialPurpose ? artist.name : /* @__PURE__ */
|
|
2182
|
+
const resolvedRenderArtistLink = renderArtistLink ?? ((artist) => artist.isSpecialPurpose ? artist.name : /* @__PURE__ */ jsx29("button", { type: "button", onClick: () => openArtist(artist.uuid), className: "hover:underline", children: artist.name }));
|
|
2302
2183
|
const getGenrePath = (genre) => {
|
|
2303
2184
|
const path = [];
|
|
2304
2185
|
let current = visibleGenrePlaylists.find((playlist) => playlist.criteria?.uuid === genre.uuid);
|
|
@@ -2330,9 +2211,8 @@ function GenreTreeView({
|
|
|
2330
2211
|
const builtInSongPanel = overlayPanel || hasSelectedGenreNode ? void 0 : songPanel;
|
|
2331
2212
|
const builtInArtistPanel = overlayPanel || hasSelectedGenreNode || builtInSongPanel ? void 0 : artistPanel;
|
|
2332
2213
|
const builtInPanel = builtInSongPanel ?? builtInArtistPanel;
|
|
2333
|
-
const
|
|
2334
|
-
const [
|
|
2335
|
-
const [uncontrolledExpanded, setUncontrolledExpanded] = useState7(false);
|
|
2214
|
+
const [uncontrolledCollapsed, setUncontrolledCollapsed] = useState8(false);
|
|
2215
|
+
const [uncontrolledExpanded, setUncontrolledExpanded] = useState8(false);
|
|
2336
2216
|
const isCollapsed = collapsed ?? uncontrolledCollapsed;
|
|
2337
2217
|
const isExpanded = expanded ?? uncontrolledExpanded;
|
|
2338
2218
|
const changeCollapsed = (next) => {
|
|
@@ -2343,55 +2223,56 @@ function GenreTreeView({
|
|
|
2343
2223
|
setUncontrolledExpanded(next);
|
|
2344
2224
|
onExpandedChange?.(next);
|
|
2345
2225
|
};
|
|
2346
|
-
|
|
2226
|
+
useEffect5(() => {
|
|
2347
2227
|
setUncontrolledCollapsed(false);
|
|
2348
2228
|
}, [selectedNodeId, artistUuid, songUuid]);
|
|
2349
|
-
const
|
|
2350
|
-
useLeftDetailPanelLayout(!isDetailHidden, placement === "regions");
|
|
2351
|
-
const detailOverlay = placement === "regions" && activeOverlayPanel?.onExpandedChange ? activeOverlayPanel : void 0;
|
|
2352
|
-
const detailExpanded = detailOverlay ? !!detailOverlay.expanded : isExpanded;
|
|
2353
|
-
const onDetailExpandedChange = detailOverlay ? detailOverlay.onExpandedChange : changeExpanded;
|
|
2354
|
-
const infoPanelCuration = {
|
|
2355
|
-
renderDangerZone,
|
|
2356
|
-
expanded: placement === "regions" ? isExpanded : expanded,
|
|
2357
|
-
onExpandedChange: placement === "regions" ? changeExpanded : onExpandedChange,
|
|
2358
|
-
collapsed: placement === "regions" ? isCollapsed : void 0,
|
|
2359
|
-
hideExpandButton: placement === "regions" ? true : void 0,
|
|
2360
|
-
overlayPanel: detailOverlay ? { ...detailOverlay, collapsed: isCollapsed, hideExpandButton: true } : activeOverlayPanel
|
|
2361
|
-
};
|
|
2362
|
-
const [isWheelRevealed, setIsWheelRevealed] = useState7(false);
|
|
2229
|
+
const [isWheelRevealed, setIsWheelRevealed] = useState8(false);
|
|
2363
2230
|
const usesHandoff = viewMode === "wheel" || viewMode === "pop-core";
|
|
2364
2231
|
const isTreeReady = !isLoading && (!usesHandoff || isWheelRevealed);
|
|
2365
|
-
const
|
|
2366
|
-
const
|
|
2367
|
-
|
|
2368
|
-
|
|
2369
|
-
|
|
2370
|
-
|
|
2371
|
-
|
|
2372
|
-
|
|
2373
|
-
|
|
2374
|
-
|
|
2375
|
-
|
|
2376
|
-
|
|
2377
|
-
|
|
2232
|
+
const [resolveStyle, setResolveStyle] = useState8(null);
|
|
2233
|
+
const handleNodeStyleResolverChange = useCallback6(
|
|
2234
|
+
(resolver) => setResolveStyle(() => resolver),
|
|
2235
|
+
[]
|
|
2236
|
+
);
|
|
2237
|
+
const panelRef = useRef3(null);
|
|
2238
|
+
const obscuredInset = useObscuredInset(panelRef);
|
|
2239
|
+
const hostPanel = { obscuredInset, onNodeStyleResolverChange: handleNodeStyleResolverChange };
|
|
2240
|
+
const nodeMetric = isArtistFiltered || !canSizeByViews ? "songs" : deferredSizeMetric;
|
|
2241
|
+
const treeNodes = useMemo7(() => toTreeNodes(visibleGenrePlaylists, nodeMetric), [visibleGenrePlaylists, nodeMetric]);
|
|
2242
|
+
const relations = useGenreNodeRelations(
|
|
2243
|
+
treeNodes,
|
|
2244
|
+
!overlayPanel && hasSelectedGenreNode ? selectedNodeId : null,
|
|
2245
|
+
resolveStyle
|
|
2246
|
+
);
|
|
2247
|
+
const [selectionHistory, setSelectionHistory] = useState8({
|
|
2248
|
+
current: selectedNodeId,
|
|
2249
|
+
previous: null
|
|
2250
|
+
});
|
|
2251
|
+
if (selectionHistory.current !== selectedNodeId) {
|
|
2252
|
+
setSelectionHistory({
|
|
2253
|
+
current: selectedNodeId,
|
|
2254
|
+
previous: selectionHistory.current ?? selectionHistory.previous
|
|
2255
|
+
});
|
|
2256
|
+
}
|
|
2257
|
+
const previousPlaylist = selectionHistory.previous !== null && selectionHistory.previous !== selectedNodeId ? genrePlaylistByNodeId.get(selectionHistory.previous) : void 0;
|
|
2258
|
+
const handlePrevious = previousPlaylist && visibleGenrePlaylists.includes(previousPlaylist) ? () => handleGenreSearchSelect(previousPlaylist) : void 0;
|
|
2378
2259
|
const { showPopup, hidePopup } = usePopup5();
|
|
2379
|
-
const [searchText, setSearchText] =
|
|
2260
|
+
const [searchText, setSearchText] = useState8("");
|
|
2380
2261
|
const artistSearchResult = useArtistSearch(artistBaseUrl, artistSearch ? searchText : "");
|
|
2381
2262
|
const artistGroup = artistSearch ? {
|
|
2382
2263
|
key: "artists",
|
|
2383
2264
|
label: "Artists",
|
|
2384
2265
|
items: artistSearchResult.artists.map((artist) => ({
|
|
2385
2266
|
key: artist.uuid,
|
|
2386
|
-
content: /* @__PURE__ */
|
|
2387
|
-
/* @__PURE__ */
|
|
2267
|
+
content: /* @__PURE__ */ jsxs22(Fragment11, { children: [
|
|
2268
|
+
/* @__PURE__ */ jsxs22("span", { className: "block truncate font-medium", children: [
|
|
2388
2269
|
artist.name,
|
|
2389
|
-
artist.disambiguation && /* @__PURE__ */
|
|
2270
|
+
artist.disambiguation && /* @__PURE__ */ jsxs22("span", { className: "font-normal text-[var(--color-neutral-500)]", children: [
|
|
2390
2271
|
" \xB7 ",
|
|
2391
2272
|
artist.disambiguation
|
|
2392
2273
|
] })
|
|
2393
2274
|
] }),
|
|
2394
|
-
artist.matchedAlias && /* @__PURE__ */
|
|
2275
|
+
artist.matchedAlias && /* @__PURE__ */ jsxs22("span", { className: "block truncate text-xs text-[var(--color-neutral-500)]", children: [
|
|
2395
2276
|
"also known as ",
|
|
2396
2277
|
artist.matchedAlias
|
|
2397
2278
|
] })
|
|
@@ -2410,9 +2291,9 @@ function GenreTreeView({
|
|
|
2410
2291
|
label: "Songs",
|
|
2411
2292
|
items: songSearchResult.songs.map((song) => ({
|
|
2412
2293
|
key: song.uuid,
|
|
2413
|
-
content: /* @__PURE__ */
|
|
2414
|
-
/* @__PURE__ */
|
|
2415
|
-
/* @__PURE__ */
|
|
2294
|
+
content: /* @__PURE__ */ jsxs22("span", { className: isSongSearchResultPlayable(song) ? void 0 : "opacity-60", children: [
|
|
2295
|
+
/* @__PURE__ */ jsx29("span", { className: "block truncate font-medium", children: song.title }),
|
|
2296
|
+
/* @__PURE__ */ jsx29("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 ") })
|
|
2416
2297
|
] }),
|
|
2417
2298
|
onSelect: () => {
|
|
2418
2299
|
openSong(song.uuid);
|
|
@@ -2438,36 +2319,49 @@ function GenreTreeView({
|
|
|
2438
2319
|
const handleGenreSearchZoomIn = () => {
|
|
2439
2320
|
if (selectedUuid) focus.onFocusGenreChange?.(selectedUuid, "zoom-in");
|
|
2440
2321
|
};
|
|
2441
|
-
const zoomInRef =
|
|
2322
|
+
const zoomInRef = useRef3(void 0);
|
|
2442
2323
|
zoomInRef.current = canZoomIn ? handleGenreSearchZoomIn : void 0;
|
|
2443
|
-
const
|
|
2444
|
-
|
|
2445
|
-
|
|
2446
|
-
|
|
2447
|
-
|
|
2448
|
-
|
|
2449
|
-
|
|
2450
|
-
|
|
2451
|
-
|
|
2452
|
-
|
|
2453
|
-
|
|
2454
|
-
|
|
2455
|
-
|
|
2456
|
-
|
|
2457
|
-
|
|
2458
|
-
|
|
2459
|
-
|
|
2460
|
-
|
|
2461
|
-
|
|
2462
|
-
|
|
2463
|
-
|
|
2464
|
-
|
|
2465
|
-
|
|
2466
|
-
|
|
2467
|
-
|
|
2324
|
+
const selectGenreFromPanel = (nodeId) => {
|
|
2325
|
+
const genrePlaylist = genrePlaylistByNodeId.get(nodeId);
|
|
2326
|
+
if (genrePlaylist) handleGenreSearchSelect(genrePlaylist);
|
|
2327
|
+
};
|
|
2328
|
+
const renderGenreBody = (relation) => {
|
|
2329
|
+
const { node } = relation;
|
|
2330
|
+
const family = /* @__PURE__ */ jsx29(
|
|
2331
|
+
GenreNodeFamily,
|
|
2332
|
+
{
|
|
2333
|
+
node,
|
|
2334
|
+
fill: relation.fill,
|
|
2335
|
+
textColor: relation.textColor,
|
|
2336
|
+
parentNode: relation.parentNode,
|
|
2337
|
+
childNodes: relation.childNodes,
|
|
2338
|
+
onSelectNode: selectGenreFromPanel
|
|
2339
|
+
}
|
|
2340
|
+
);
|
|
2341
|
+
const ancestors = /* @__PURE__ */ jsx29(GenreNodeAncestors, { ancestorNodes: relation.ancestorNodes, onSelectNode: selectGenreFromPanel });
|
|
2342
|
+
const genrePlaylist = genrePlaylistByNodeId.get(node.id);
|
|
2343
|
+
const criteria = genrePlaylist?.criteria;
|
|
2344
|
+
if (!genrePlaylist || !criteria) return { primary: family, aside: ancestors };
|
|
2345
|
+
const genreUuid = criteria.uuid;
|
|
2346
|
+
const parentPlaylist = visibleGenrePlaylists.find(({ uuid }) => uuid === genrePlaylist.parent?.uuid);
|
|
2347
|
+
const canToggleSide = !readOnly && parentPlaylist !== void 0 && parentPlaylist.parent === null;
|
|
2348
|
+
const side = criteria.side ?? "core";
|
|
2349
|
+
const shareTarget = {
|
|
2350
|
+
kind: "genre",
|
|
2351
|
+
genrePlaylistUuid: genrePlaylist.uuid,
|
|
2352
|
+
name: criteria.name,
|
|
2353
|
+
scope,
|
|
2354
|
+
artistUuid
|
|
2355
|
+
};
|
|
2356
|
+
const shareUrl = getShareUrlRef.current?.(shareTarget) ?? void 0;
|
|
2357
|
+
const popSibling = canToggleSide && side === "core" ? visibleGenrePlaylists.find(
|
|
2358
|
+
(sibling) => sibling.parent?.uuid === parentPlaylist.uuid && sibling.uuid !== genrePlaylist.uuid && sibling.criteria?.side === "pop"
|
|
2359
|
+
) : void 0;
|
|
2360
|
+
return {
|
|
2361
|
+
primary: /* @__PURE__ */ jsxs22(Fragment11, { children: [
|
|
2362
|
+
/* @__PURE__ */ jsx29(
|
|
2468
2363
|
GenreInfoPanelBody,
|
|
2469
2364
|
{
|
|
2470
|
-
toolbar,
|
|
2471
2365
|
family,
|
|
2472
2366
|
genreUuid,
|
|
2473
2367
|
genrePlaylist,
|
|
@@ -2483,7 +2377,7 @@ function GenreTreeView({
|
|
|
2483
2377
|
onAddChild: readOnly ? void 0 : () => handleGenreCreationAction(criteria),
|
|
2484
2378
|
onRename: readOnly ? void 0 : () => handleGenreRenameAction(criteria),
|
|
2485
2379
|
onChangeParent: readOnly ? void 0 : () => showPopup(
|
|
2486
|
-
/* @__PURE__ */
|
|
2380
|
+
/* @__PURE__ */ jsx29(
|
|
2487
2381
|
ChangeParentPopup,
|
|
2488
2382
|
{
|
|
2489
2383
|
genrePlaylist: { ...genrePlaylist, criteria },
|
|
@@ -2514,49 +2408,65 @@ function GenreTreeView({
|
|
|
2514
2408
|
}
|
|
2515
2409
|
}
|
|
2516
2410
|
),
|
|
2517
|
-
|
|
2518
|
-
}
|
|
2519
|
-
|
|
2520
|
-
|
|
2521
|
-
|
|
2522
|
-
additionalActions,
|
|
2523
|
-
readOnly,
|
|
2524
|
-
handleGenreCreationAction,
|
|
2525
|
-
handleGenreRenameAction,
|
|
2526
|
-
showPopup,
|
|
2527
|
-
hidePopup,
|
|
2528
|
-
onParentChanged,
|
|
2529
|
-
visibleGenrePlaylists,
|
|
2530
|
-
updateGenre,
|
|
2531
|
-
playback,
|
|
2532
|
-
filterArtist,
|
|
2533
|
-
scope,
|
|
2534
|
-
getBackendBaseUrl,
|
|
2535
|
-
criteriaOverviewSchema,
|
|
2536
|
-
renderGenreDetailExtras,
|
|
2537
|
-
renderArtistLink,
|
|
2538
|
-
resolvedRenderSongLink,
|
|
2539
|
-
renderSummary,
|
|
2540
|
-
renderEssentialTracks,
|
|
2541
|
-
renderSongLeading,
|
|
2542
|
-
renderSongActions,
|
|
2543
|
-
renderTracksToolbar
|
|
2544
|
-
]
|
|
2545
|
-
);
|
|
2411
|
+
renderDangerZone?.(node)
|
|
2412
|
+
] }),
|
|
2413
|
+
aside: ancestors
|
|
2414
|
+
};
|
|
2415
|
+
};
|
|
2546
2416
|
const isRotationControlled = controlledAllowWheelRotation !== void 0;
|
|
2547
2417
|
const allowWheelRotation = controlledAllowWheelRotation ?? internalAllowWheelRotation;
|
|
2548
|
-
|
|
2549
|
-
|
|
2418
|
+
let activePanel = null;
|
|
2419
|
+
if (overlayPanel) {
|
|
2420
|
+
activePanel = {
|
|
2421
|
+
title: overlayPanel.title,
|
|
2422
|
+
content: overlayPanel.content,
|
|
2423
|
+
aside: overlayPanel.extraContent,
|
|
2424
|
+
expanded: overlayPanel.expanded ?? false,
|
|
2425
|
+
onExpandedChange: overlayPanel.onExpandedChange,
|
|
2426
|
+
onClose: overlayPanel.onClose,
|
|
2427
|
+
compact: false
|
|
2428
|
+
};
|
|
2429
|
+
} else if (relations) {
|
|
2430
|
+
const { primary, aside } = renderGenreBody(relations);
|
|
2431
|
+
activePanel = {
|
|
2432
|
+
title: relations.node.name,
|
|
2433
|
+
content: primary,
|
|
2434
|
+
aside,
|
|
2435
|
+
expanded: isExpanded,
|
|
2436
|
+
onExpandedChange: changeExpanded,
|
|
2437
|
+
onClose: clearSelection,
|
|
2438
|
+
compact: true,
|
|
2439
|
+
headerAccent: { background: relations.fill, color: relations.textColor }
|
|
2440
|
+
};
|
|
2441
|
+
} else if (builtInPanel) {
|
|
2442
|
+
activePanel = {
|
|
2443
|
+
title: builtInPanel.title,
|
|
2444
|
+
content: builtInPanel.content,
|
|
2445
|
+
aside: builtInPanel.extraContent,
|
|
2446
|
+
expanded: builtInPanel.expanded,
|
|
2447
|
+
onExpandedChange: builtInPanel.onExpandedChange,
|
|
2448
|
+
onClose: builtInPanel.onClose,
|
|
2449
|
+
compact: true
|
|
2450
|
+
};
|
|
2451
|
+
}
|
|
2452
|
+
const isPanelShown = isTreeReady && activePanel !== null;
|
|
2453
|
+
const detailTab = placement === "regions" && activePanel?.onExpandedChange ? {
|
|
2454
|
+
edge: activePanel.expanded ? { label: "Shrink panel", onClick: () => activePanel.onExpandedChange?.(false) } : isCollapsed ? null : { label: "Hide panel", onClick: () => changeCollapsed(true) },
|
|
2455
|
+
center: activePanel.expanded ? null : isCollapsed ? { label: "Show panel", onClick: () => changeCollapsed(false) } : activePanel.onExpandedChange ? { label: "Extend panel", onClick: () => activePanel.onExpandedChange?.(true) } : null
|
|
2456
|
+
} : void 0;
|
|
2457
|
+
const expandButton = placement === "default" && activePanel?.onExpandedChange ? /* @__PURE__ */ jsx29(
|
|
2458
|
+
IconButton,
|
|
2550
2459
|
{
|
|
2551
|
-
|
|
2552
|
-
|
|
2553
|
-
|
|
2460
|
+
"aria-label": activePanel.expanded ? "Shrink panel" : "Extend panel",
|
|
2461
|
+
style: activePanel.headerAccent && { color: "inherit" },
|
|
2462
|
+
onClick: () => activePanel.onExpandedChange?.(!activePanel.expanded),
|
|
2463
|
+
children: activePanel.expanded ? /* @__PURE__ */ jsx29(Minimize2, { "aria-hidden": "true", className: "h-4 w-4" }) : /* @__PURE__ */ jsx29(Maximize2, { "aria-hidden": "true", className: "h-4 w-4" })
|
|
2554
2464
|
}
|
|
2555
2465
|
) : null;
|
|
2556
2466
|
const renderArtistFilter = () => {
|
|
2557
2467
|
if (isLoading || !filterArtist) return null;
|
|
2558
|
-
return /* @__PURE__ */
|
|
2559
|
-
/* @__PURE__ */
|
|
2468
|
+
return /* @__PURE__ */ jsxs22("span", { className: "inline-flex items-center overflow-hidden rounded-full bg-[var(--color-neutral-100)] text-sm", children: [
|
|
2469
|
+
/* @__PURE__ */ jsx29(
|
|
2560
2470
|
"button",
|
|
2561
2471
|
{
|
|
2562
2472
|
type: "button",
|
|
@@ -2568,7 +2478,7 @@ function GenreTreeView({
|
|
|
2568
2478
|
children: filterArtist.name
|
|
2569
2479
|
}
|
|
2570
2480
|
),
|
|
2571
|
-
/* @__PURE__ */
|
|
2481
|
+
/* @__PURE__ */ jsx29(
|
|
2572
2482
|
"button",
|
|
2573
2483
|
{
|
|
2574
2484
|
type: "button",
|
|
@@ -2580,22 +2490,22 @@ function GenreTreeView({
|
|
|
2580
2490
|
)
|
|
2581
2491
|
] });
|
|
2582
2492
|
};
|
|
2583
|
-
const actions = /* @__PURE__ */
|
|
2584
|
-
!isLoading && /* @__PURE__ */
|
|
2493
|
+
const actions = /* @__PURE__ */ jsxs22(Fragment11, { children: [
|
|
2494
|
+
!isLoading && /* @__PURE__ */ jsx29(
|
|
2585
2495
|
GenreSearch,
|
|
2586
2496
|
{
|
|
2587
2497
|
genrePlaylists: visibleGenrePlaylists,
|
|
2588
2498
|
onSelect: handleGenreSearchSelect,
|
|
2589
|
-
selectedName: selectedGenrePlaylist?.name ?? builtInPanel?.title
|
|
2499
|
+
selectedName: selectedGenrePlaylist?.name ?? (typeof builtInPanel?.title === "string" ? builtInPanel.title : null),
|
|
2590
2500
|
onClear: builtInSongPanel ? () => changeSong(null) : builtInArtistPanel ? () => changeArtist(null) : handleGenreSearchClear,
|
|
2591
2501
|
onPrevious: handlePrevious,
|
|
2592
2502
|
onQueryChange: artistSearch || songSearch ? setSearchText : void 0,
|
|
2593
2503
|
extraGroups
|
|
2594
2504
|
}
|
|
2595
2505
|
),
|
|
2596
|
-
!isLoading && filterArtist && /* @__PURE__ */
|
|
2597
|
-
/* @__PURE__ */
|
|
2598
|
-
!isLoading && !isControlled && /* @__PURE__ */
|
|
2506
|
+
!isLoading && filterArtist && /* @__PURE__ */ jsx29("div", { className: "hidden w-full justify-center max-md:flex", children: renderArtistFilter() }),
|
|
2507
|
+
/* @__PURE__ */ jsxs22("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: [
|
|
2508
|
+
!isLoading && !isControlled && /* @__PURE__ */ jsx29(
|
|
2599
2509
|
SegmentedControl2,
|
|
2600
2510
|
{
|
|
2601
2511
|
"aria-label": "Tree view mode",
|
|
@@ -2609,13 +2519,13 @@ function GenreTreeView({
|
|
|
2609
2519
|
]
|
|
2610
2520
|
}
|
|
2611
2521
|
),
|
|
2612
|
-
!isLoading && showDisplayOptions && /* @__PURE__ */
|
|
2522
|
+
!isLoading && showDisplayOptions && /* @__PURE__ */ jsx29(
|
|
2613
2523
|
"div",
|
|
2614
2524
|
{
|
|
2615
2525
|
className: "flex items-center gap-1",
|
|
2616
2526
|
role: "group",
|
|
2617
2527
|
"aria-label": "Tree display options",
|
|
2618
|
-
children: !isRotationControlled && viewMode !== "stacked" && viewMode !== "outline" && /* @__PURE__ */
|
|
2528
|
+
children: !isRotationControlled && viewMode !== "stacked" && viewMode !== "outline" && /* @__PURE__ */ jsx29(
|
|
2619
2529
|
Button,
|
|
2620
2530
|
{
|
|
2621
2531
|
variant: allowWheelRotation ? "default" : "outline",
|
|
@@ -2626,7 +2536,7 @@ function GenreTreeView({
|
|
|
2626
2536
|
)
|
|
2627
2537
|
}
|
|
2628
2538
|
),
|
|
2629
|
-
!isLoading && !readOnly && showAddRoot && /* @__PURE__ */
|
|
2539
|
+
!isLoading && !readOnly && showAddRoot && /* @__PURE__ */ jsx29(
|
|
2630
2540
|
IconTextButton,
|
|
2631
2541
|
{
|
|
2632
2542
|
icon: Plus2,
|
|
@@ -2636,42 +2546,34 @@ function GenreTreeView({
|
|
|
2636
2546
|
)
|
|
2637
2547
|
] })
|
|
2638
2548
|
] });
|
|
2639
|
-
return /* @__PURE__ */
|
|
2549
|
+
return /* @__PURE__ */ jsxs22(
|
|
2640
2550
|
"div",
|
|
2641
2551
|
{
|
|
2642
|
-
|
|
2552
|
+
"data-left-panel": isPanelShown && !isCollapsed ? void 0 : "hidden",
|
|
2643
2553
|
className: ["genre-tree-view relative flex flex-col h-full", placement === "regions" && REGIONS_CLASS, className2].filter(Boolean).join(" "),
|
|
2644
2554
|
children: [
|
|
2645
|
-
/* @__PURE__ */
|
|
2646
|
-
/* @__PURE__ */ jsx30(
|
|
2555
|
+
/* @__PURE__ */ jsx29(
|
|
2647
2556
|
"div",
|
|
2648
2557
|
{
|
|
2649
2558
|
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"}`,
|
|
2650
2559
|
children: actions
|
|
2651
2560
|
}
|
|
2652
2561
|
),
|
|
2653
|
-
!isLoading && filterArtist && /* @__PURE__ */
|
|
2562
|
+
!isLoading && filterArtist && /* @__PURE__ */ jsx29(
|
|
2654
2563
|
"div",
|
|
2655
2564
|
{
|
|
2656
2565
|
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"}`,
|
|
2657
2566
|
children: renderArtistFilter()
|
|
2658
2567
|
}
|
|
2659
2568
|
),
|
|
2660
|
-
|
|
2661
|
-
"div",
|
|
2662
|
-
{
|
|
2663
|
-
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))]"}`,
|
|
2664
|
-
children: detailTab
|
|
2665
|
-
}
|
|
2666
|
-
),
|
|
2667
|
-
/* @__PURE__ */ jsx30("div", { className: "content-container flex-1 min-h-0 flex flex-row gap-4", children: /* @__PURE__ */ jsxs23("div", { className: "tree-view-container relative flex-1 min-w-0 flex flex-col h-full", children: [
|
|
2668
|
-
!isLoading && viewMode === "outline" && floatingControlsLeading && /* @__PURE__ */ jsx30("div", { className: "absolute bottom-3 right-3 z-10", children: floatingControlsLeading }),
|
|
2669
|
-
isLoading ? /* @__PURE__ */ jsx30(GenreTreeViewSkeleton, { viewMode }) : viewMode === "wheel" ? (
|
|
2569
|
+
/* @__PURE__ */ jsx29("div", { className: "content-container flex-1 min-h-0 flex flex-row gap-4", children: /* @__PURE__ */ jsxs22("div", { className: "tree-view-container relative flex-1 min-w-0 flex flex-col h-full", children: [
|
|
2570
|
+
!isLoading && viewMode === "outline" && floatingControlsLeading && /* @__PURE__ */ jsx29("div", { className: "absolute bottom-3 right-3 z-10", children: floatingControlsLeading }),
|
|
2571
|
+
isLoading ? /* @__PURE__ */ jsx29(GenreTreeViewSkeleton, { viewMode }) : viewMode === "wheel" ? (
|
|
2670
2572
|
// The info panel's top edge aligns with the tree's; the search bar floats `--layout-panel-inset` below it,
|
|
2671
2573
|
// and the header inset (the bar's height plus that inset) extends the header's fill behind the bar,
|
|
2672
2574
|
// Google Maps style; the 8px bottom padding mirrors the inset above the bar, and the hidden title's height is zeroed.
|
|
2673
2575
|
// The panel's own Zoom in button is hidden: the search bar carries it.
|
|
2674
|
-
/* @__PURE__ */
|
|
2576
|
+
/* @__PURE__ */ jsx29("div", { className: "tree-container search-overlay relative flex-1 w-full min-h-0 ", children: /* @__PURE__ */ jsx29(GenreTreeWheelHandoff, { skeleton: /* @__PURE__ */ jsx29(GenreTreeWheelSkeleton, {}), onRevealedChange: setIsWheelRevealed, children: /* @__PURE__ */ jsx29(
|
|
2675
2577
|
GenrePlaylistTreeWheel,
|
|
2676
2578
|
{
|
|
2677
2579
|
scope,
|
|
@@ -2680,29 +2582,26 @@ function GenreTreeView({
|
|
|
2680
2582
|
handleGenreRenameAction,
|
|
2681
2583
|
additionalActions,
|
|
2682
2584
|
onSelectedNodeChange: handleSelectedNodeChange,
|
|
2683
|
-
hideInfoPanelClose: true,
|
|
2684
|
-
hideInfoPanelTitle: true,
|
|
2685
2585
|
onNodeHover: handleNodeHover,
|
|
2686
|
-
|
|
2586
|
+
...hostPanel,
|
|
2687
2587
|
playback,
|
|
2688
2588
|
selectedNodeId,
|
|
2689
2589
|
readOnly,
|
|
2690
2590
|
allowWheelRotation,
|
|
2691
2591
|
sizeMetric: isArtistFiltered || !canSizeByViews ? "songs" : deferredSizeMetric,
|
|
2692
2592
|
busy,
|
|
2693
|
-
floatingControlsLeading: floatingControlsLeading || canSizeByViews ? /* @__PURE__ */
|
|
2593
|
+
floatingControlsLeading: floatingControlsLeading || canSizeByViews ? /* @__PURE__ */ jsxs22("div", { className: "flex items-center gap-2", children: [
|
|
2694
2594
|
floatingControlsLeading,
|
|
2695
|
-
canSizeByViews && /* @__PURE__ */
|
|
2595
|
+
canSizeByViews && /* @__PURE__ */ jsx29(SizeMetricToggle, { value: sizeMetric, onChange: changeSizeMetric })
|
|
2696
2596
|
] }) : void 0,
|
|
2697
2597
|
defaultViewport,
|
|
2698
2598
|
viewportRestore,
|
|
2699
|
-
onViewportChange
|
|
2700
|
-
...infoPanelCuration
|
|
2599
|
+
onViewportChange
|
|
2701
2600
|
}
|
|
2702
2601
|
) }) })
|
|
2703
2602
|
) : viewMode === "pop-core" ? (
|
|
2704
2603
|
// Same as the wheel: the header inset extends its fill behind the floating search bar, Google Maps style.
|
|
2705
|
-
/* @__PURE__ */
|
|
2604
|
+
/* @__PURE__ */ jsx29("div", { className: "tree-container search-overlay relative flex-1 w-full min-h-0 ", children: /* @__PURE__ */ jsx29(GenreTreeWheelHandoff, { skeleton: /* @__PURE__ */ jsx29(GenreTreeWheelSkeleton, {}), onRevealedChange: setIsWheelRevealed, children: /* @__PURE__ */ jsx29(
|
|
2706
2605
|
GenrePlaylistTreeWheelRadialPopCore,
|
|
2707
2606
|
{
|
|
2708
2607
|
scope,
|
|
@@ -2711,28 +2610,25 @@ function GenreTreeView({
|
|
|
2711
2610
|
handleGenreRenameAction,
|
|
2712
2611
|
additionalActions,
|
|
2713
2612
|
onSelectedNodeChange: handleSelectedNodeChange,
|
|
2714
|
-
hideInfoPanelClose: true,
|
|
2715
|
-
hideInfoPanelTitle: true,
|
|
2716
2613
|
onNodeHover: handleNodeHover,
|
|
2717
|
-
|
|
2614
|
+
...hostPanel,
|
|
2718
2615
|
playback,
|
|
2719
2616
|
selectedNodeId,
|
|
2720
2617
|
readOnly,
|
|
2721
2618
|
allowWheelRotation,
|
|
2722
2619
|
sizeMetric: isArtistFiltered || !canSizeByViews ? "songs" : deferredSizeMetric,
|
|
2723
2620
|
busy,
|
|
2724
|
-
floatingControlsLeading: floatingControlsLeading || canSizeByViews ? /* @__PURE__ */
|
|
2621
|
+
floatingControlsLeading: floatingControlsLeading || canSizeByViews ? /* @__PURE__ */ jsxs22("div", { className: "flex items-center gap-2", children: [
|
|
2725
2622
|
floatingControlsLeading,
|
|
2726
|
-
canSizeByViews && /* @__PURE__ */
|
|
2623
|
+
canSizeByViews && /* @__PURE__ */ jsx29(SizeMetricToggle, { value: sizeMetric, onChange: changeSizeMetric })
|
|
2727
2624
|
] }) : void 0,
|
|
2728
2625
|
defaultViewport,
|
|
2729
2626
|
viewportRestore,
|
|
2730
2627
|
onViewportChange,
|
|
2731
|
-
...infoPanelCuration,
|
|
2732
2628
|
...focus
|
|
2733
2629
|
}
|
|
2734
2630
|
) }) })
|
|
2735
|
-
) : viewMode === "outline" ? /* @__PURE__ */
|
|
2631
|
+
) : viewMode === "outline" ? /* @__PURE__ */ jsx29("div", { className: "tree-container flex-1 min-h-0 w-full overflow-y-auto relative", children: /* @__PURE__ */ jsx29(
|
|
2736
2632
|
GenrePlaylistTreeWheelRadialPopCore,
|
|
2737
2633
|
{
|
|
2738
2634
|
outline: true,
|
|
@@ -2742,22 +2638,19 @@ function GenreTreeView({
|
|
|
2742
2638
|
handleGenreRenameAction,
|
|
2743
2639
|
additionalActions,
|
|
2744
2640
|
onSelectedNodeChange: handleSelectedNodeChange,
|
|
2745
|
-
hideInfoPanelClose: true,
|
|
2746
|
-
hideInfoPanelTitle: true,
|
|
2747
2641
|
onNodeHover: handleNodeHover,
|
|
2748
|
-
|
|
2642
|
+
...hostPanel,
|
|
2749
2643
|
playback,
|
|
2750
2644
|
selectedNodeId,
|
|
2751
|
-
readOnly
|
|
2752
|
-
...infoPanelCuration
|
|
2645
|
+
readOnly
|
|
2753
2646
|
}
|
|
2754
|
-
) }) : /* @__PURE__ */
|
|
2755
|
-
([uuid, genrePlaylistTreePerRoot]
|
|
2756
|
-
return /* @__PURE__ */
|
|
2647
|
+
) }) : /* @__PURE__ */ jsx29("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(
|
|
2648
|
+
([uuid, genrePlaylistTreePerRoot]) => {
|
|
2649
|
+
return /* @__PURE__ */ jsx29(
|
|
2757
2650
|
"div",
|
|
2758
2651
|
{
|
|
2759
2652
|
className: "tree-per-root-container relative shrink-0 h-[28rem] mt-2 mr-16 p-2 bg-[var(--color-neutral-100)] rounded-lg",
|
|
2760
|
-
children: /* @__PURE__ */
|
|
2653
|
+
children: /* @__PURE__ */ jsx29("div", { className: "graph-container relative z-10 h-full", children: /* @__PURE__ */ jsx29(
|
|
2761
2654
|
GenrePlaylistTreePerRoot,
|
|
2762
2655
|
{
|
|
2763
2656
|
scope,
|
|
@@ -2767,26 +2660,45 @@ function GenreTreeView({
|
|
|
2767
2660
|
handleGenreRenameAction,
|
|
2768
2661
|
additionalActions,
|
|
2769
2662
|
onSelectedNodeChange: handleSelectedNodeChange,
|
|
2770
|
-
hideInfoPanelClose: true,
|
|
2771
|
-
hideInfoPanelTitle: true,
|
|
2772
2663
|
onNodeHover: handleNodeHover,
|
|
2773
|
-
|
|
2664
|
+
...hostPanel,
|
|
2774
2665
|
playback,
|
|
2775
2666
|
selectedNodeId: uuid === selectedGenrePlaylist?.root.uuid ? selectedNodeId : null,
|
|
2776
2667
|
readOnly,
|
|
2777
2668
|
wheelZoom: "modifier",
|
|
2778
2669
|
defaultViewport: uuid === selectedGenrePlaylist?.root.uuid ? defaultViewport : void 0,
|
|
2779
2670
|
viewportRestore: uuid === selectedGenrePlaylist?.root.uuid && uuid === restoreRootUuid ? viewportRestore : void 0,
|
|
2780
|
-
onViewportChange: uuid === selectedGenrePlaylist?.root.uuid ? onViewportChange : void 0
|
|
2781
|
-
...infoPanelCuration,
|
|
2782
|
-
overlayPanel: rootIndex === 0 ? activeOverlayPanel : void 0
|
|
2671
|
+
onViewportChange: uuid === selectedGenrePlaylist?.root.uuid ? onViewportChange : void 0
|
|
2783
2672
|
}
|
|
2784
2673
|
) })
|
|
2785
2674
|
},
|
|
2786
2675
|
uuid
|
|
2787
2676
|
);
|
|
2788
2677
|
}
|
|
2789
|
-
) })
|
|
2678
|
+
) }),
|
|
2679
|
+
/* @__PURE__ */ jsx29(
|
|
2680
|
+
DetailPanel,
|
|
2681
|
+
{
|
|
2682
|
+
ref: panelRef,
|
|
2683
|
+
side: "left",
|
|
2684
|
+
title: activePanel?.title ?? "",
|
|
2685
|
+
hideTitle: activePanel?.compact,
|
|
2686
|
+
hideClose: activePanel?.compact,
|
|
2687
|
+
headerAccent: activePanel?.headerAccent,
|
|
2688
|
+
headerActions: expandButton,
|
|
2689
|
+
onClose: activePanel?.onClose ?? noop,
|
|
2690
|
+
collapsed: isCollapsed || !isTreeReady || !activePanel,
|
|
2691
|
+
expanded: activePanel?.expanded,
|
|
2692
|
+
onExpandedChange: activePanel?.onExpandedChange,
|
|
2693
|
+
aside: activePanel?.aside,
|
|
2694
|
+
edgeTab: detailTab,
|
|
2695
|
+
headerClassName: activePanel?.compact ? "pt-[calc(var(--layout-search-h)+var(--layout-panel-inset)+0.5rem)]" : void 0,
|
|
2696
|
+
children: activePanel?.aside && !activePanel.expanded ? /* @__PURE__ */ jsxs22(Fragment11, { children: [
|
|
2697
|
+
activePanel.content,
|
|
2698
|
+
activePanel.aside
|
|
2699
|
+
] }) : activePanel?.content
|
|
2700
|
+
}
|
|
2701
|
+
)
|
|
2790
2702
|
] }) })
|
|
2791
2703
|
]
|
|
2792
2704
|
}
|
|
@@ -2797,17 +2709,18 @@ function GenreTreeView({
|
|
|
2797
2709
|
import { useMemo as useMemo8 } from "react";
|
|
2798
2710
|
import {
|
|
2799
2711
|
ACCENT_TEXT_COLOR,
|
|
2712
|
+
GenreNodeAncestors as GenreNodeAncestors2,
|
|
2713
|
+
GenreNodeFamily as GenreNodeFamily2,
|
|
2800
2714
|
getGenreTreeColor as getGenreTreeColor2,
|
|
2801
|
-
InfoPanel,
|
|
2802
2715
|
TEXT_COLOR,
|
|
2803
2716
|
tintSurface
|
|
2804
2717
|
} from "@behindthemusictree/genre-tree-view";
|
|
2805
|
-
import { Skeleton as Skeleton7 } from "@behindthemusictree/ui";
|
|
2718
|
+
import { DetailPanel as DetailPanel2, IconButton as IconButton2, Skeleton as Skeleton7 } from "@behindthemusictree/ui";
|
|
2719
|
+
import { Maximize2 as Maximize22, Minimize2 as Minimize22 } from "lucide-react";
|
|
2806
2720
|
import {
|
|
2807
2721
|
useFetchGenreDetail
|
|
2808
2722
|
} from "@behindthemusictree/app-kit/genre-tree";
|
|
2809
|
-
import { jsx as
|
|
2810
|
-
var ITEM_COUNT_LABEL = "Songs";
|
|
2723
|
+
import { jsx as jsx30, jsxs as jsxs23 } from "react/jsx-runtime";
|
|
2811
2724
|
var RELATIVE_ITEM_COUNT = 1;
|
|
2812
2725
|
function toNode(genre, parentId) {
|
|
2813
2726
|
return {
|
|
@@ -2831,6 +2744,7 @@ function GenreDetailPanel({
|
|
|
2831
2744
|
collapsed,
|
|
2832
2745
|
expanded,
|
|
2833
2746
|
onExpandedChange,
|
|
2747
|
+
edgeTab,
|
|
2834
2748
|
extras
|
|
2835
2749
|
}) {
|
|
2836
2750
|
const { data: detail, isPending, isError } = useFetchGenreDetail(genreUuid, scope, getBackendBaseUrl);
|
|
@@ -2843,7 +2757,7 @@ function GenreDetailPanel({
|
|
|
2843
2757
|
fill: tintSurface(rootColor),
|
|
2844
2758
|
textColor: TEXT_COLOR
|
|
2845
2759
|
});
|
|
2846
|
-
const
|
|
2760
|
+
const ancestors2 = [...detail.ascendants].sort((a, b) => b.degree - a.degree);
|
|
2847
2761
|
return {
|
|
2848
2762
|
node: {
|
|
2849
2763
|
id: detail.uuid,
|
|
@@ -2855,57 +2769,72 @@ function GenreDetailPanel({
|
|
|
2855
2769
|
fill: rootColor,
|
|
2856
2770
|
parentNode: detail.parent ? relative(detail.parent, null) : null,
|
|
2857
2771
|
childNodes: detail.children.map((child) => relative(child, detail.uuid)),
|
|
2858
|
-
ancestorNodes:
|
|
2859
|
-
({ ascendant }, index) => relative(ascendant, index === 0 ? null :
|
|
2772
|
+
ancestorNodes: ancestors2.map(
|
|
2773
|
+
({ ascendant }, index) => relative(ascendant, index === 0 ? null : ancestors2[index - 1].ascendant.uuid)
|
|
2860
2774
|
)
|
|
2861
2775
|
};
|
|
2862
2776
|
}, [detail]);
|
|
2863
2777
|
if (isError) {
|
|
2864
|
-
return /* @__PURE__ */
|
|
2778
|
+
return /* @__PURE__ */ jsx30("div", { role: "alert", className: "p-4 text-sm text-[var(--color-text)]", children: "This genre could not be loaded." });
|
|
2865
2779
|
}
|
|
2866
2780
|
if (isPending || !detail || !view) {
|
|
2867
|
-
return /* @__PURE__ */
|
|
2868
|
-
/* @__PURE__ */
|
|
2869
|
-
/* @__PURE__ */
|
|
2870
|
-
/* @__PURE__ */
|
|
2781
|
+
return /* @__PURE__ */ jsxs23("div", { className: "flex flex-col gap-3 p-4", "aria-busy": "true", "data-testid": "genre-detail-panel-skeleton", children: [
|
|
2782
|
+
/* @__PURE__ */ jsx30(Skeleton7, { className: "h-6 w-2/3" }),
|
|
2783
|
+
/* @__PURE__ */ jsx30(Skeleton7, { className: "h-4 w-full" }),
|
|
2784
|
+
/* @__PURE__ */ jsx30(Skeleton7, { className: "h-4 w-3/4" })
|
|
2871
2785
|
] });
|
|
2872
2786
|
}
|
|
2873
|
-
const
|
|
2874
|
-
|
|
2875
|
-
|
|
2876
|
-
{
|
|
2877
|
-
toolbar: sections.toolbar,
|
|
2878
|
-
family: sections.family,
|
|
2879
|
-
genreUuid: detail.uuid,
|
|
2880
|
-
genrePlaylist: { ...detail.criteriaPlaylist, tracksCount: detail.tracksCount },
|
|
2881
|
-
wikidataId: detail.wikidataId,
|
|
2882
|
-
scope,
|
|
2883
|
-
getBackendBaseUrl,
|
|
2884
|
-
playback,
|
|
2885
|
-
band: { node, onZoomIn, shareUrl, shareTarget: shareUrl ? shareTarget : void 0 },
|
|
2886
|
-
extras
|
|
2887
|
-
}
|
|
2888
|
-
),
|
|
2889
|
-
aside: null
|
|
2890
|
-
});
|
|
2891
|
-
return /* @__PURE__ */ jsx31(
|
|
2892
|
-
InfoPanel,
|
|
2787
|
+
const selectGenre = (nodeId) => onSelectGenre(nodeId);
|
|
2788
|
+
const family = /* @__PURE__ */ jsx30(
|
|
2789
|
+
GenreNodeFamily2,
|
|
2893
2790
|
{
|
|
2894
2791
|
node: view.node,
|
|
2895
2792
|
fill: view.fill,
|
|
2896
2793
|
textColor: ACCENT_TEXT_COLOR,
|
|
2897
2794
|
parentNode: view.parentNode,
|
|
2898
2795
|
childNodes: view.childNodes,
|
|
2899
|
-
|
|
2796
|
+
onSelectNode: selectGenre
|
|
2797
|
+
}
|
|
2798
|
+
);
|
|
2799
|
+
const ancestors = /* @__PURE__ */ jsx30(GenreNodeAncestors2, { ancestorNodes: view.ancestorNodes, onSelectNode: selectGenre });
|
|
2800
|
+
return /* @__PURE__ */ jsxs23(
|
|
2801
|
+
DetailPanel2,
|
|
2802
|
+
{
|
|
2900
2803
|
side: "left",
|
|
2804
|
+
title: view.node.name,
|
|
2805
|
+
headerAccent: { background: view.fill, color: ACCENT_TEXT_COLOR },
|
|
2806
|
+
headerActions: onExpandedChange ? /* @__PURE__ */ jsx30(
|
|
2807
|
+
IconButton2,
|
|
2808
|
+
{
|
|
2809
|
+
"aria-label": expanded ? "Shrink panel" : "Extend panel",
|
|
2810
|
+
style: { color: "inherit" },
|
|
2811
|
+
onClick: () => onExpandedChange(!expanded),
|
|
2812
|
+
children: expanded ? /* @__PURE__ */ jsx30(Minimize22, { "aria-hidden": "true", className: "h-4 w-4" }) : /* @__PURE__ */ jsx30(Maximize22, { "aria-hidden": "true", className: "h-4 w-4" })
|
|
2813
|
+
}
|
|
2814
|
+
) : void 0,
|
|
2901
2815
|
onClose,
|
|
2902
|
-
|
|
2903
|
-
itemCountLabel: ITEM_COUNT_LABEL,
|
|
2904
|
-
renderInfoPanelBody: renderBody,
|
|
2816
|
+
collapsed,
|
|
2905
2817
|
expanded,
|
|
2906
2818
|
onExpandedChange,
|
|
2907
|
-
|
|
2908
|
-
|
|
2819
|
+
edgeTab,
|
|
2820
|
+
aside: ancestors,
|
|
2821
|
+
children: [
|
|
2822
|
+
/* @__PURE__ */ jsx30(
|
|
2823
|
+
GenreInfoPanelBody,
|
|
2824
|
+
{
|
|
2825
|
+
family,
|
|
2826
|
+
genreUuid: detail.uuid,
|
|
2827
|
+
genrePlaylist: { ...detail.criteriaPlaylist, tracksCount: detail.tracksCount },
|
|
2828
|
+
wikidataId: detail.wikidataId,
|
|
2829
|
+
scope,
|
|
2830
|
+
getBackendBaseUrl,
|
|
2831
|
+
playback,
|
|
2832
|
+
band: { node: view.node, onZoomIn, shareUrl, shareTarget: shareUrl ? shareTarget : void 0 },
|
|
2833
|
+
extras
|
|
2834
|
+
}
|
|
2835
|
+
),
|
|
2836
|
+
!expanded && ancestors
|
|
2837
|
+
]
|
|
2909
2838
|
}
|
|
2910
2839
|
);
|
|
2911
2840
|
}
|
|
@@ -2919,13 +2848,13 @@ import {
|
|
|
2919
2848
|
} from "@behindthemusictree/genre-tree-view";
|
|
2920
2849
|
|
|
2921
2850
|
// src/genre-tree/track-list-sidebar/TrackListSidebar.tsx
|
|
2922
|
-
import { useEffect as
|
|
2851
|
+
import { useEffect as useEffect6, useLayoutEffect as useLayoutEffect2, useRef as useRef4 } from "react";
|
|
2923
2852
|
import { ListMusic } from "lucide-react";
|
|
2924
2853
|
import { useTrackList as useTrackList6 } from "@behindthemusictree/app-kit/genre-tree";
|
|
2925
2854
|
import { TrackListOriginType as TrackListOriginType2 } from "@behindthemusictree/app-kit/genre-tree";
|
|
2926
|
-
import { useTrackNoun as
|
|
2927
|
-
import { jsx as
|
|
2928
|
-
var useBrowserLayoutEffect = typeof window === "undefined" ?
|
|
2855
|
+
import { useTrackNoun as useTrackNoun3 } from "@behindthemusictree/app-kit/track-noun";
|
|
2856
|
+
import { jsx as jsx31, jsxs as jsxs24 } from "react/jsx-runtime";
|
|
2857
|
+
var useBrowserLayoutEffect = typeof window === "undefined" ? useEffect6 : useLayoutEffect2;
|
|
2929
2858
|
function TrackListSidebar({
|
|
2930
2859
|
className: className2 = "",
|
|
2931
2860
|
renderDuration,
|
|
@@ -2938,17 +2867,17 @@ function TrackListSidebar({
|
|
|
2938
2867
|
renderSongLink
|
|
2939
2868
|
}) {
|
|
2940
2869
|
const { trackList, loadMore, autoAdvanceScrollRequest } = useTrackList6();
|
|
2941
|
-
const trackNoun =
|
|
2942
|
-
const trackListRef =
|
|
2943
|
-
const previousOriginRef =
|
|
2944
|
-
const handledAutoAdvanceRequestIdRef =
|
|
2945
|
-
const shouldFollowPlaybackRef =
|
|
2946
|
-
const programmaticScrollTopRef =
|
|
2947
|
-
const userScrollIntentRef =
|
|
2948
|
-
const userScrollIntentTimerRef =
|
|
2949
|
-
const loadMoreSentinelRef =
|
|
2870
|
+
const trackNoun = useTrackNoun3();
|
|
2871
|
+
const trackListRef = useRef4(null);
|
|
2872
|
+
const previousOriginRef = useRef4(trackList?.origin ?? null);
|
|
2873
|
+
const handledAutoAdvanceRequestIdRef = useRef4(null);
|
|
2874
|
+
const shouldFollowPlaybackRef = useRef4(true);
|
|
2875
|
+
const programmaticScrollTopRef = useRef4(null);
|
|
2876
|
+
const userScrollIntentRef = useRef4(false);
|
|
2877
|
+
const userScrollIntentTimerRef = useRef4(null);
|
|
2878
|
+
const loadMoreSentinelRef = useRef4(null);
|
|
2950
2879
|
const hasMore = !!trackList && trackList.nextPage !== null;
|
|
2951
|
-
|
|
2880
|
+
useEffect6(() => {
|
|
2952
2881
|
const sentinel = loadMoreSentinelRef.current;
|
|
2953
2882
|
if (!hasMore || !sentinel) return;
|
|
2954
2883
|
const observer = new IntersectionObserver((entries) => {
|
|
@@ -2968,11 +2897,11 @@ function TrackListSidebar({
|
|
|
2968
2897
|
programmaticScrollTopRef.current = null;
|
|
2969
2898
|
if (trackListRef.current) trackListRef.current.scrollTop = 0;
|
|
2970
2899
|
}, [trackList?.origin]);
|
|
2971
|
-
|
|
2900
|
+
useEffect6(() => {
|
|
2972
2901
|
const list = trackListRef.current;
|
|
2973
2902
|
if (!isCollapsed && list?.scrollTop === 0) shouldFollowPlaybackRef.current = true;
|
|
2974
2903
|
}, [isCollapsed]);
|
|
2975
|
-
|
|
2904
|
+
useEffect6(
|
|
2976
2905
|
() => () => {
|
|
2977
2906
|
if (userScrollIntentTimerRef.current !== null) clearTimeout(userScrollIntentTimerRef.current);
|
|
2978
2907
|
},
|
|
@@ -3026,25 +2955,25 @@ function TrackListSidebar({
|
|
|
3026
2955
|
}
|
|
3027
2956
|
};
|
|
3028
2957
|
const positionClasses = layout === "inline" ? "relative w-full flex h-full flex-col" : "fixed right-0 w-[50rem] flex flex-col";
|
|
3029
|
-
return trackList ? /* @__PURE__ */
|
|
2958
|
+
return trackList ? /* @__PURE__ */ jsxs24(
|
|
3030
2959
|
"div",
|
|
3031
2960
|
{
|
|
3032
2961
|
"data-theme": "dark",
|
|
3033
2962
|
className: `track-list-sidebar ${positionClasses} rounded-2xl bg-[var(--color-surface)] pb-1 ${className2}`,
|
|
3034
2963
|
style: layout === "fixed" ? { top: "63.5px", maxHeight: "calc(100vh - 63.5px - 79px)" } : void 0,
|
|
3035
2964
|
children: [
|
|
3036
|
-
/* @__PURE__ */
|
|
3037
|
-
/* @__PURE__ */
|
|
3038
|
-
/* @__PURE__ */
|
|
3039
|
-
/* @__PURE__ */
|
|
3040
|
-
/* @__PURE__ */
|
|
2965
|
+
/* @__PURE__ */ jsxs24("div", { className: "header flex h-16 items-center px-4 py-2 text-[var(--color-text)]", children: [
|
|
2966
|
+
/* @__PURE__ */ jsxs24("div", { className: "min-w-0 flex flex-1 flex-col justify-center", children: [
|
|
2967
|
+
/* @__PURE__ */ jsxs24("div", { className: "origin flex text-xl", children: [
|
|
2968
|
+
/* @__PURE__ */ jsx31("div", { className: "from h-auto flex flex-col justify-center items-center mr-2", children: "From" }),
|
|
2969
|
+
/* @__PURE__ */ jsx31("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__ */ jsx31("div", { className: "name max-w-full truncate", children: trackList.origin.label }) })
|
|
3041
2970
|
] }),
|
|
3042
|
-
/* @__PURE__ */
|
|
2971
|
+
/* @__PURE__ */ jsxs24("div", { className: "info flex items-center text-sm text-[var(--color-text-muted)]", children: [
|
|
3043
2972
|
trackList.origin.type === TrackListOriginType2.GENRE_PLAYLIST ? "Genre \u2022 " : trackList.origin.type === TrackListOriginType2.ARTIST ? "Artist \u2022 " : `${trackNoun.singular} playlist \u2022 `,
|
|
3044
2973
|
`${trackList.total} ${trackList.total > 1 ? trackNoun.plural : trackNoun.singular}`
|
|
3045
2974
|
] })
|
|
3046
2975
|
] }),
|
|
3047
|
-
(isCollapsed && onExpand || !isCollapsed && onMinimize) && /* @__PURE__ */
|
|
2976
|
+
(isCollapsed && onExpand || !isCollapsed && onMinimize) && /* @__PURE__ */ jsx31(
|
|
3048
2977
|
"button",
|
|
3049
2978
|
{
|
|
3050
2979
|
type: "button",
|
|
@@ -3053,11 +2982,11 @@ function TrackListSidebar({
|
|
|
3053
2982
|
"aria-expanded": !isCollapsed,
|
|
3054
2983
|
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"}`,
|
|
3055
2984
|
onClick: isCollapsed ? onExpand : onMinimize,
|
|
3056
|
-
children: /* @__PURE__ */
|
|
2985
|
+
children: /* @__PURE__ */ jsx31(ListMusic, { "aria-hidden": "true", className: "h-5 w-5" })
|
|
3057
2986
|
}
|
|
3058
2987
|
)
|
|
3059
2988
|
] }),
|
|
3060
|
-
!isCollapsed && /* @__PURE__ */
|
|
2989
|
+
!isCollapsed && /* @__PURE__ */ jsxs24(
|
|
3061
2990
|
"ul",
|
|
3062
2991
|
{
|
|
3063
2992
|
ref: trackListRef,
|
|
@@ -3067,7 +2996,7 @@ function TrackListSidebar({
|
|
|
3067
2996
|
onPointerDown: markUserScrollIntent,
|
|
3068
2997
|
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",
|
|
3069
2998
|
children: [
|
|
3070
|
-
trackList.tracks.map((track, index) => /* @__PURE__ */
|
|
2999
|
+
trackList.tracks.map((track, index) => /* @__PURE__ */ jsx31("li", { "data-track-uuid": track.uuid, children: /* @__PURE__ */ jsx31(
|
|
3071
3000
|
TrackItem,
|
|
3072
3001
|
{
|
|
3073
3002
|
track,
|
|
@@ -3078,7 +3007,7 @@ function TrackListSidebar({
|
|
|
3078
3007
|
renderSongLink
|
|
3079
3008
|
}
|
|
3080
3009
|
) }, track.uuid)),
|
|
3081
|
-
hasMore && /* @__PURE__ */
|
|
3010
|
+
hasMore && /* @__PURE__ */ jsx31("li", { ref: loadMoreSentinelRef, "aria-hidden": "true", className: "h-px" })
|
|
3082
3011
|
]
|
|
3083
3012
|
}
|
|
3084
3013
|
)
|
|
@@ -3088,8 +3017,8 @@ function TrackListSidebar({
|
|
|
3088
3017
|
}
|
|
3089
3018
|
|
|
3090
3019
|
// src/genre-tree/PlayerPanel.tsx
|
|
3091
|
-
import { useEffect as
|
|
3092
|
-
import { twMerge
|
|
3020
|
+
import { useEffect as useEffect7, useState as useState9 } from "react";
|
|
3021
|
+
import { twMerge } from "tailwind-merge";
|
|
3093
3022
|
import {
|
|
3094
3023
|
usePlayer as usePlayer11,
|
|
3095
3024
|
PlayerVideoSurface
|
|
@@ -3097,12 +3026,13 @@ import {
|
|
|
3097
3026
|
import {
|
|
3098
3027
|
useTrackListSidebarVisibility
|
|
3099
3028
|
} from "@behindthemusictree/app-kit/genre-tree";
|
|
3029
|
+
import { PanelEdgeTab } from "@behindthemusictree/ui";
|
|
3100
3030
|
|
|
3101
3031
|
// src/genre-tree/PlayerControls.tsx
|
|
3102
3032
|
import { Pause as Pause3, Play as Play4, SkipBack, SkipForward, Volume2, VolumeX } from "lucide-react";
|
|
3103
3033
|
import { formatTime, useTrackList as useTrackList7 } from "@behindthemusictree/app-kit/genre-tree";
|
|
3104
3034
|
import { PlayStates as PlayStates4, useCurrentTime, usePlayer as usePlayer10 } from "@behindthemusictree/app-kit/player";
|
|
3105
|
-
import { jsx as
|
|
3035
|
+
import { jsx as jsx32, jsxs as jsxs25 } from "react/jsx-runtime";
|
|
3106
3036
|
function PlayerControls() {
|
|
3107
3037
|
const {
|
|
3108
3038
|
duration,
|
|
@@ -3121,15 +3051,15 @@ function PlayerControls() {
|
|
|
3121
3051
|
const safeDuration = Number.isFinite(duration) && duration > 0 ? duration : 0;
|
|
3122
3052
|
const safeCurrentTime = Number.isFinite(currentTime) ? Math.max(0, Math.min(currentTime, safeDuration)) : 0;
|
|
3123
3053
|
const isPlaying = playState === PlayStates4.PLAYING;
|
|
3124
|
-
return /* @__PURE__ */
|
|
3054
|
+
return /* @__PURE__ */ jsxs25(
|
|
3125
3055
|
"section",
|
|
3126
3056
|
{
|
|
3127
3057
|
"aria-label": "Player controls",
|
|
3128
3058
|
className: "player-controls flex shrink-0 flex-col gap-2 border-b border-zinc-800 px-3 py-2 text-zinc-200",
|
|
3129
3059
|
children: [
|
|
3130
|
-
/* @__PURE__ */
|
|
3131
|
-
/* @__PURE__ */
|
|
3132
|
-
/* @__PURE__ */
|
|
3060
|
+
/* @__PURE__ */ jsxs25("div", { className: "flex min-w-0 items-center gap-2 text-xs tabular-nums text-zinc-400", children: [
|
|
3061
|
+
/* @__PURE__ */ jsx32("span", { "aria-label": "Elapsed time", children: formatTime(safeCurrentTime) }),
|
|
3062
|
+
/* @__PURE__ */ jsx32(
|
|
3133
3063
|
"input",
|
|
3134
3064
|
{
|
|
3135
3065
|
"aria-label": "Seek",
|
|
@@ -3143,11 +3073,11 @@ function PlayerControls() {
|
|
|
3143
3073
|
onChange: (event) => seekTo(Number(event.currentTarget.value))
|
|
3144
3074
|
}
|
|
3145
3075
|
),
|
|
3146
|
-
/* @__PURE__ */
|
|
3076
|
+
/* @__PURE__ */ jsx32("span", { "aria-label": "Duration", children: formatTime(safeDuration) })
|
|
3147
3077
|
] }),
|
|
3148
|
-
/* @__PURE__ */
|
|
3149
|
-
/* @__PURE__ */
|
|
3150
|
-
/* @__PURE__ */
|
|
3078
|
+
/* @__PURE__ */ jsxs25("div", { className: "grid min-h-9 grid-cols-[1fr_auto_1fr] items-center gap-3", children: [
|
|
3079
|
+
/* @__PURE__ */ jsxs25("div", { className: "col-start-2 flex items-center justify-center gap-2", children: [
|
|
3080
|
+
/* @__PURE__ */ jsx32(
|
|
3151
3081
|
"button",
|
|
3152
3082
|
{
|
|
3153
3083
|
type: "button",
|
|
@@ -3156,10 +3086,10 @@ function PlayerControls() {
|
|
|
3156
3086
|
disabled: !isReady || !hasPreviousTrack,
|
|
3157
3087
|
onClick: playPreviousTrack,
|
|
3158
3088
|
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",
|
|
3159
|
-
children: /* @__PURE__ */
|
|
3089
|
+
children: /* @__PURE__ */ jsx32(SkipBack, { "aria-hidden": "true", className: "h-4 w-4" })
|
|
3160
3090
|
}
|
|
3161
3091
|
),
|
|
3162
|
-
/* @__PURE__ */
|
|
3092
|
+
/* @__PURE__ */ jsx32(
|
|
3163
3093
|
"button",
|
|
3164
3094
|
{
|
|
3165
3095
|
type: "button",
|
|
@@ -3168,10 +3098,10 @@ function PlayerControls() {
|
|
|
3168
3098
|
disabled: !isReady,
|
|
3169
3099
|
onClick: handlePlayPauseAction,
|
|
3170
3100
|
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",
|
|
3171
|
-
children: isPlaying ? /* @__PURE__ */
|
|
3101
|
+
children: isPlaying ? /* @__PURE__ */ jsx32(Pause3, { "aria-hidden": "true", className: "h-4 w-4", fill: "currentColor" }) : /* @__PURE__ */ jsx32(Play4, { "aria-hidden": "true", className: "h-4 w-4", fill: "currentColor" })
|
|
3172
3102
|
}
|
|
3173
3103
|
),
|
|
3174
|
-
/* @__PURE__ */
|
|
3104
|
+
/* @__PURE__ */ jsx32(
|
|
3175
3105
|
"button",
|
|
3176
3106
|
{
|
|
3177
3107
|
type: "button",
|
|
@@ -3180,14 +3110,14 @@ function PlayerControls() {
|
|
|
3180
3110
|
disabled: !isReady || !hasNextTrack,
|
|
3181
3111
|
onClick: playNextTrack,
|
|
3182
3112
|
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",
|
|
3183
|
-
children: /* @__PURE__ */
|
|
3113
|
+
children: /* @__PURE__ */ jsx32(SkipForward, { "aria-hidden": "true", className: "h-4 w-4" })
|
|
3184
3114
|
}
|
|
3185
3115
|
)
|
|
3186
3116
|
] }),
|
|
3187
|
-
/* @__PURE__ */
|
|
3188
|
-
volume === 0 ? /* @__PURE__ */
|
|
3189
|
-
/* @__PURE__ */
|
|
3190
|
-
/* @__PURE__ */
|
|
3117
|
+
/* @__PURE__ */ jsxs25("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: [
|
|
3118
|
+
volume === 0 ? /* @__PURE__ */ jsx32(VolumeX, { "aria-hidden": "true", className: "h-[0.7rem] w-[0.7rem] shrink-0" }) : /* @__PURE__ */ jsx32(Volume2, { "aria-hidden": "true", className: "h-[0.7rem] w-[0.7rem] shrink-0" }),
|
|
3119
|
+
/* @__PURE__ */ jsx32("span", { className: "sr-only", children: "Volume" }),
|
|
3120
|
+
/* @__PURE__ */ jsx32(
|
|
3191
3121
|
"input",
|
|
3192
3122
|
{
|
|
3193
3123
|
"aria-label": "Volume",
|
|
@@ -3209,7 +3139,7 @@ function PlayerControls() {
|
|
|
3209
3139
|
}
|
|
3210
3140
|
|
|
3211
3141
|
// src/genre-tree/PlayerPanel.tsx
|
|
3212
|
-
import { jsx as
|
|
3142
|
+
import { jsx as jsx33, jsxs as jsxs26 } from "react/jsx-runtime";
|
|
3213
3143
|
var PANEL_ID = "player-panel";
|
|
3214
3144
|
var DEFAULT_EXTENDED_WIDTH = "calc(100vw - var(--layout-center-left) - var(--layout-gutter))";
|
|
3215
3145
|
function PlayerPanel({
|
|
@@ -3223,12 +3153,12 @@ function PlayerPanel({
|
|
|
3223
3153
|
}) {
|
|
3224
3154
|
const { playerTrackObject } = usePlayer11();
|
|
3225
3155
|
const { toggleTrackListSidebar, isTrackListSidebarVisible } = useTrackListSidebarVisibility();
|
|
3226
|
-
const [lastLoadedTrackTitle, setLastLoadedTrackTitle] =
|
|
3156
|
+
const [lastLoadedTrackTitle, setLastLoadedTrackTitle] = useState9("");
|
|
3227
3157
|
const loadedTrackTitle = playerTrackObject?.track.title;
|
|
3228
|
-
|
|
3158
|
+
useEffect7(() => {
|
|
3229
3159
|
if (loadedTrackTitle) setLastLoadedTrackTitle(loadedTrackTitle);
|
|
3230
3160
|
}, [loadedTrackTitle]);
|
|
3231
|
-
const [uncontrolledExtended, setUncontrolledExtended] =
|
|
3161
|
+
const [uncontrolledExtended, setUncontrolledExtended] = useState9(false);
|
|
3232
3162
|
const isExtendRequested = expanded ?? uncontrolledExtended;
|
|
3233
3163
|
const setIsExtendRequested = (next) => {
|
|
3234
3164
|
setUncontrolledExtended(next);
|
|
@@ -3249,11 +3179,11 @@ function PlayerPanel({
|
|
|
3249
3179
|
onClick: () => setIsExtendRequested(true),
|
|
3250
3180
|
expanded: false
|
|
3251
3181
|
} : null;
|
|
3252
|
-
return /* @__PURE__ */
|
|
3182
|
+
return /* @__PURE__ */ jsxs26(
|
|
3253
3183
|
"div",
|
|
3254
3184
|
{
|
|
3255
3185
|
id: PANEL_ID,
|
|
3256
|
-
className:
|
|
3186
|
+
className: twMerge(
|
|
3257
3187
|
"fixed right-[var(--layout-gutter)] top-[var(--layout-band-top)] z-40 max-h-[calc(100vh-var(--layout-band-top)-3.5rem)]",
|
|
3258
3188
|
!isExtended && "w-[var(--layout-right-w)]",
|
|
3259
3189
|
isTrackListSidebarVisible && "h-[calc(100vh-var(--layout-band-top)-3.5rem)]",
|
|
@@ -3262,7 +3192,7 @@ function PlayerPanel({
|
|
|
3262
3192
|
),
|
|
3263
3193
|
style: isExtended ? { width: extendedWidth } : void 0,
|
|
3264
3194
|
children: [
|
|
3265
|
-
/* @__PURE__ */
|
|
3195
|
+
/* @__PURE__ */ jsx33(
|
|
3266
3196
|
PanelEdgeTab,
|
|
3267
3197
|
{
|
|
3268
3198
|
side: "right",
|
|
@@ -3272,30 +3202,30 @@ function PlayerPanel({
|
|
|
3272
3202
|
className: "absolute right-full top-1/2 -translate-y-1/2"
|
|
3273
3203
|
}
|
|
3274
3204
|
),
|
|
3275
|
-
/* @__PURE__ */
|
|
3205
|
+
/* @__PURE__ */ jsxs26(
|
|
3276
3206
|
"div",
|
|
3277
3207
|
{
|
|
3278
|
-
className:
|
|
3208
|
+
className: twMerge(
|
|
3279
3209
|
"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)]",
|
|
3280
3210
|
isExtended ? "flex-row" : "flex-col"
|
|
3281
3211
|
),
|
|
3282
3212
|
children: [
|
|
3283
|
-
/* @__PURE__ */
|
|
3284
|
-
/* @__PURE__ */
|
|
3285
|
-
/* @__PURE__ */
|
|
3286
|
-
/* @__PURE__ */
|
|
3287
|
-
playerTrackObject?.loadError && /* @__PURE__ */
|
|
3213
|
+
/* @__PURE__ */ jsxs26("div", { className: "flex w-[var(--layout-right-w)] shrink-0 flex-col", children: [
|
|
3214
|
+
/* @__PURE__ */ jsx33("div", { className: "flex shrink-0 items-center justify-between gap-2 border-b border-zinc-800 p-2", children: /* @__PURE__ */ jsx33("span", { className: "min-w-0 truncate text-sm font-semibold", children: loadedTrackTitle || lastLoadedTrackTitle }) }),
|
|
3215
|
+
/* @__PURE__ */ jsxs26("div", { className: "relative w-full shrink-0", children: [
|
|
3216
|
+
/* @__PURE__ */ jsx33(PlayerVideoSurface, { className: "aspect-video w-full bg-black" }),
|
|
3217
|
+
playerTrackObject?.loadError && /* @__PURE__ */ jsx33("span", { className: "absolute bottom-2 left-2 right-2 text-xs text-red-400", children: playerTrackObject.loadError })
|
|
3288
3218
|
] }),
|
|
3289
|
-
/* @__PURE__ */
|
|
3219
|
+
/* @__PURE__ */ jsx33(PlayerControls, {})
|
|
3290
3220
|
] }),
|
|
3291
|
-
/* @__PURE__ */
|
|
3221
|
+
/* @__PURE__ */ jsx33(
|
|
3292
3222
|
TrackListSidebar,
|
|
3293
3223
|
{
|
|
3294
3224
|
layout: "inline",
|
|
3295
3225
|
isCollapsed: !isTrackListSidebarVisible,
|
|
3296
3226
|
onExpand: toggleTrackListSidebar,
|
|
3297
3227
|
onMinimize: hideSongList,
|
|
3298
|
-
className:
|
|
3228
|
+
className: twMerge(
|
|
3299
3229
|
"min-h-0 min-w-0 flex-1",
|
|
3300
3230
|
isExtended && "border-l border-zinc-800"
|
|
3301
3231
|
),
|
|
@@ -3315,11 +3245,11 @@ function PlayerPanel({
|
|
|
3315
3245
|
import { v4 as uuidv4 } from "uuid";
|
|
3316
3246
|
import { AiFillStar, AiOutlineStar } from "react-icons/ai";
|
|
3317
3247
|
import { FORM_RATING_NULL_VALUE } from "@behindthemusictree/app-kit/genre-tree";
|
|
3318
|
-
import { jsx as
|
|
3248
|
+
import { jsx as jsx34, jsxs as jsxs27 } from "react/jsx-runtime";
|
|
3319
3249
|
function Rating({ rating, handleChange }) {
|
|
3320
3250
|
const instanceId = uuidv4();
|
|
3321
|
-
return /* @__PURE__ */
|
|
3322
|
-
/* @__PURE__ */
|
|
3251
|
+
return /* @__PURE__ */ jsx34("div", { className: "flex items-center", children: [...Array(6)].map((_, i) => /* @__PURE__ */ jsxs27("div", { className: `relative ${i === 0 ? "mr-4" : "mr-1"}`, children: [
|
|
3252
|
+
/* @__PURE__ */ jsx34(
|
|
3323
3253
|
"input",
|
|
3324
3254
|
{
|
|
3325
3255
|
id: `star-${instanceId}-${i}`,
|
|
@@ -3331,16 +3261,16 @@ function Rating({ rating, handleChange }) {
|
|
|
3331
3261
|
onChange: handleChange
|
|
3332
3262
|
}
|
|
3333
3263
|
),
|
|
3334
|
-
/* @__PURE__ */
|
|
3335
|
-
/* @__PURE__ */
|
|
3264
|
+
/* @__PURE__ */ jsx34("label", { htmlFor: `star-${instanceId}-${i}`, className: "cursor-pointer", children: i === 0 ? /* @__PURE__ */ jsxs27("div", { className: "flex", children: [
|
|
3265
|
+
/* @__PURE__ */ jsx34(
|
|
3336
3266
|
AiOutlineStar,
|
|
3337
3267
|
{
|
|
3338
3268
|
className: `w-7 h-7 absolute top-0 left-0 ${rating === FORM_RATING_NULL_VALUE ? "text-[var(--color-accent-rating)]" : "text-[var(--color-text-muted)]"}`
|
|
3339
3269
|
}
|
|
3340
3270
|
),
|
|
3341
|
-
/* @__PURE__ */
|
|
3271
|
+
/* @__PURE__ */ jsx34("span", { className: "flex-grow w-8" }),
|
|
3342
3272
|
" "
|
|
3343
|
-
] }) : /* @__PURE__ */
|
|
3273
|
+
] }) : /* @__PURE__ */ jsx34(
|
|
3344
3274
|
AiFillStar,
|
|
3345
3275
|
{
|
|
3346
3276
|
className: `w-7 h-7 absolute top-0 left-0 ${(rating ?? -1) >= i ? "text-[var(--color-accent-rating)]" : "text-[var(--color-text-muted)]"}`
|
|
@@ -3355,8 +3285,6 @@ export {
|
|
|
3355
3285
|
GenreSearch,
|
|
3356
3286
|
GenreNodeActionBand,
|
|
3357
3287
|
GenreInfoPanelBody,
|
|
3358
|
-
PanelEdgeTab,
|
|
3359
|
-
useLeftDetailPanelLayout,
|
|
3360
3288
|
TrackPositionPlayPause,
|
|
3361
3289
|
TrackItem,
|
|
3362
3290
|
GenreTreeView,
|
|
@@ -3369,4 +3297,4 @@ export {
|
|
|
3369
3297
|
GenreTreeViewSkeleton2 as GenreTreeViewSkeleton,
|
|
3370
3298
|
GenreTreeOutlineSkeleton
|
|
3371
3299
|
};
|
|
3372
|
-
//# sourceMappingURL=chunk-
|
|
3300
|
+
//# sourceMappingURL=chunk-QGGVPIXY.js.map
|