@behindthemusictree/app-kit-ui 39.0.0 → 40.1.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-2K2SQOUJ.js → chunk-DPYUE6WD.js} +379 -411
- package/dist/chunk-DPYUE6WD.js.map +1 -0
- package/dist/genre-tree/index.cjs +461 -494
- package/dist/genre-tree/index.cjs.map +1 -1
- package/dist/genre-tree/index.d.ts +12 -5
- package/dist/genre-tree/index.js +1 -1
- package/dist/index.cjs +456 -489
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +1 -1
- package/package.json +6 -6
- package/dist/chunk-2K2SQOUJ.js.map +0 -1
|
@@ -16,7 +16,7 @@ import {
|
|
|
16
16
|
useGenreNodeRelations
|
|
17
17
|
} from "@behindthemusictree/genre-tree-view";
|
|
18
18
|
import { useGenreTreeViewState, useArtist as useArtist2, useUpdateGenre as useUpdateGenre2, genreUpdateMutationKey } from "@behindthemusictree/app-kit/genre-tree";
|
|
19
|
-
import { usePopup as
|
|
19
|
+
import { usePopup as usePopup4 } from "@behindthemusictree/app-kit/popup";
|
|
20
20
|
|
|
21
21
|
// src/genre-tree/playlist-tree/size-metric.ts
|
|
22
22
|
import { genrePlaylistTrackCount } from "@behindthemusictree/app-kit/genre-tree";
|
|
@@ -30,7 +30,7 @@ var genrePlaylistSize = (genrePlaylist, metric) => {
|
|
|
30
30
|
};
|
|
31
31
|
|
|
32
32
|
// src/genre-tree/playlist-tree/toTreeNodes.ts
|
|
33
|
-
function toTreeNodes(genrePlaylists, sizeMetric) {
|
|
33
|
+
function toTreeNodes(genrePlaylists, sizeMetric, focusUuids) {
|
|
34
34
|
return genrePlaylists.map((genrePlaylist) => ({
|
|
35
35
|
id: genrePlaylist.uuid,
|
|
36
36
|
parentId: genrePlaylist.parent?.uuid ?? null,
|
|
@@ -41,10 +41,26 @@ function toTreeNodes(genrePlaylists, sizeMetric) {
|
|
|
41
41
|
side: genrePlaylist.criteria?.side ?? void 0,
|
|
42
42
|
wikidataId: genrePlaylist.criteria?.wikidataId ?? null,
|
|
43
43
|
umbrella: genrePlaylist.isUmbrella,
|
|
44
|
-
scene: genrePlaylist.scene ?? void 0
|
|
44
|
+
scene: genrePlaylist.scene ?? void 0,
|
|
45
|
+
muted: focusUuids ? !focusUuids.has(genrePlaylist.uuid) : void 0
|
|
45
46
|
}));
|
|
46
47
|
}
|
|
47
48
|
|
|
49
|
+
// src/genre-tree/playlist-tree/toGenreNodeStyles.ts
|
|
50
|
+
function toGenreNodeStyles(relations, genrePlaylists) {
|
|
51
|
+
const styles = /* @__PURE__ */ new Map();
|
|
52
|
+
if (!relations) return styles;
|
|
53
|
+
const genreUuidByPlaylistUuid = new Map(
|
|
54
|
+
genrePlaylists.flatMap((genrePlaylist) => genrePlaylist.criteria ? [[genrePlaylist.uuid, genrePlaylist.criteria.uuid]] : [])
|
|
55
|
+
);
|
|
56
|
+
const drawn = [relations, relations.parentNode, ...relations.childNodes, ...relations.ancestorNodes];
|
|
57
|
+
for (const entry of drawn) {
|
|
58
|
+
const genreUuid = entry && genreUuidByPlaylistUuid.get(entry.node.id);
|
|
59
|
+
if (entry && genreUuid) styles.set(genreUuid, { fill: entry.fill, textColor: entry.textColor });
|
|
60
|
+
}
|
|
61
|
+
return styles;
|
|
62
|
+
}
|
|
63
|
+
|
|
48
64
|
// src/genre-tree/playlist-tree/TreePerRoot.tsx
|
|
49
65
|
import { genrePlaylistTrackCount as genrePlaylistTrackCount2 } from "@behindthemusictree/app-kit/genre-tree";
|
|
50
66
|
import { useCallback as useCallback2, useMemo as useMemo2 } from "react";
|
|
@@ -53,24 +69,27 @@ import {
|
|
|
53
69
|
getGenreTreeColor
|
|
54
70
|
} from "@behindthemusictree/genre-tree-view";
|
|
55
71
|
import { usePlayer } from "@behindthemusictree/app-kit/player";
|
|
56
|
-
import { usePopup } from "@behindthemusictree/app-kit/popup";
|
|
57
|
-
import { ErrorCode } from "@behindthemusictree/app-kit/transport";
|
|
58
72
|
|
|
59
|
-
// src/genre-tree/playlist-tree/useGenrePlaylistPlayback.
|
|
73
|
+
// src/genre-tree/playlist-tree/useGenrePlaylistPlayback.tsx
|
|
60
74
|
import { useCallback, useMemo } from "react";
|
|
61
75
|
import {
|
|
62
76
|
TrackListOriginType,
|
|
77
|
+
TracksFailureAlreadyReportedError,
|
|
63
78
|
useTrackList,
|
|
64
79
|
GenreCatalogueCountsSchema,
|
|
65
80
|
defaultGenreMusicSelection,
|
|
66
81
|
genreMusicSelectionKey
|
|
67
82
|
} from "@behindthemusictree/app-kit/genre-tree";
|
|
83
|
+
import { usePopup } from "@behindthemusictree/app-kit/popup";
|
|
84
|
+
import { AppError, ErrorCode } from "@behindthemusictree/app-kit/transport";
|
|
85
|
+
import { jsx } from "react/jsx-runtime";
|
|
68
86
|
function useGenrePlaylistPlayback({
|
|
69
87
|
scope,
|
|
70
88
|
genrePlaylists,
|
|
71
89
|
artist = null
|
|
72
90
|
}) {
|
|
73
91
|
const { trackList, playNewTrackListFromGenrePlaylist } = useTrackList();
|
|
92
|
+
const { showPopup } = usePopup();
|
|
74
93
|
const origin = trackList?.origin;
|
|
75
94
|
const playing = useMemo(() => {
|
|
76
95
|
if (!origin || origin.type !== TrackListOriginType.GENRE_PLAYLIST || origin.scope !== scope) return null;
|
|
@@ -82,14 +101,20 @@ function useGenrePlaylistPlayback({
|
|
|
82
101
|
}, [origin, artist, genrePlaylists, scope]);
|
|
83
102
|
const play = useCallback(async (playlist, requested) => {
|
|
84
103
|
if (artist && !playlist.criteria) return;
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
104
|
+
try {
|
|
105
|
+
const selection = scope === "reference" && playlist.criteria !== null ? requested ?? defaultGenreMusicSelection(GenreCatalogueCountsSchema.parse(playlist)) : void 0;
|
|
106
|
+
await (selection || artist ? playNewTrackListFromGenrePlaylist(playlist, scope, { selection, ...artist && { artistUuid: artist.uuid } }) : playNewTrackListFromGenrePlaylist(playlist, scope));
|
|
107
|
+
} catch (error) {
|
|
108
|
+
console.error("Failed to load genre playlist tracks:", error);
|
|
109
|
+
if (error instanceof TracksFailureAlreadyReportedError) return;
|
|
110
|
+
showPopup(/* @__PURE__ */ jsx(InternalErrorPopup, { errorCode: error instanceof AppError ? error.code : ErrorCode.CLIENT_UNKNOWN }));
|
|
111
|
+
}
|
|
112
|
+
}, [artist, scope, playNewTrackListFromGenrePlaylist, showPopup]);
|
|
88
113
|
return useMemo(() => ({ playing, play }), [playing, play]);
|
|
89
114
|
}
|
|
90
115
|
|
|
91
116
|
// src/genre-tree/playlist-tree/TreePerRoot.tsx
|
|
92
|
-
import { jsx } from "react/jsx-runtime";
|
|
117
|
+
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
93
118
|
function GenrePlaylistTreePerRoot({
|
|
94
119
|
scope,
|
|
95
120
|
className: className2,
|
|
@@ -108,25 +133,16 @@ function GenrePlaylistTreePerRoot({
|
|
|
108
133
|
viewportRestore,
|
|
109
134
|
onViewportChange,
|
|
110
135
|
playback,
|
|
136
|
+
focusUuids,
|
|
111
137
|
...hostPanel
|
|
112
138
|
}) {
|
|
113
139
|
const { isPlaying, setIsPlaying } = usePlayer();
|
|
114
140
|
const defaultPlayback = useGenrePlaylistPlayback({ scope, genrePlaylists: genrePlaylistTreePerRoot });
|
|
115
141
|
const { playing, play } = playback ?? defaultPlayback;
|
|
116
142
|
const playingNodeId = playing?.uuid ?? null;
|
|
117
|
-
const { showPopup } = usePopup();
|
|
118
143
|
const nodes = useMemo2(
|
|
119
|
-
() => genrePlaylistTreePerRoot
|
|
120
|
-
|
|
121
|
-
parentId: genrePlaylist.parent?.uuid ?? null,
|
|
122
|
-
name: genrePlaylist.name,
|
|
123
|
-
itemCount: genrePlaylistTrackCount2(genrePlaylist),
|
|
124
|
-
actionable: Boolean(genrePlaylist.criteria),
|
|
125
|
-
side: genrePlaylist.criteria?.side ?? void 0,
|
|
126
|
-
wikidataId: genrePlaylist.criteria?.wikidataId ?? null,
|
|
127
|
-
umbrella: genrePlaylist.isUmbrella
|
|
128
|
-
})),
|
|
129
|
-
[genrePlaylistTreePerRoot]
|
|
144
|
+
() => toTreeNodes(genrePlaylistTreePerRoot, "songs", focusUuids),
|
|
145
|
+
[genrePlaylistTreePerRoot, focusUuids]
|
|
130
146
|
);
|
|
131
147
|
const handlePlayPause = useCallback2(
|
|
132
148
|
(nodeId) => {
|
|
@@ -139,18 +155,14 @@ function GenrePlaylistTreePerRoot({
|
|
|
139
155
|
if (genrePlaylistTrackCount2(genrePlaylist) === 0) {
|
|
140
156
|
return;
|
|
141
157
|
}
|
|
142
|
-
play(genrePlaylist)
|
|
143
|
-
console.error("Failed to load genre playlist tracks:", error);
|
|
144
|
-
showPopup(/* @__PURE__ */ jsx(InternalErrorPopup, { errorCode: ErrorCode.CLIENT_UNKNOWN }));
|
|
145
|
-
});
|
|
158
|
+
void play(genrePlaylist);
|
|
146
159
|
},
|
|
147
160
|
[
|
|
148
161
|
genrePlaylistTreePerRoot,
|
|
149
162
|
playingNodeId,
|
|
150
163
|
isPlaying,
|
|
151
164
|
setIsPlaying,
|
|
152
|
-
play
|
|
153
|
-
showPopup
|
|
165
|
+
play
|
|
154
166
|
]
|
|
155
167
|
);
|
|
156
168
|
const handleAddChild = useCallback2(
|
|
@@ -173,7 +185,7 @@ function GenrePlaylistTreePerRoot({
|
|
|
173
185
|
if (confirm(`Are you sure you want to delete "${node.name}"?`)) {
|
|
174
186
|
}
|
|
175
187
|
}, []);
|
|
176
|
-
return /* @__PURE__ */
|
|
188
|
+
return /* @__PURE__ */ jsx2(
|
|
177
189
|
GenreTree,
|
|
178
190
|
{
|
|
179
191
|
className: className2,
|
|
@@ -206,9 +218,7 @@ import {
|
|
|
206
218
|
GenreTreeWheel
|
|
207
219
|
} from "@behindthemusictree/genre-tree-view";
|
|
208
220
|
import { usePlayer as usePlayer2 } from "@behindthemusictree/app-kit/player";
|
|
209
|
-
import {
|
|
210
|
-
import { ErrorCode as ErrorCode2 } from "@behindthemusictree/app-kit/transport";
|
|
211
|
-
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
221
|
+
import { jsx as jsx3 } from "react/jsx-runtime";
|
|
212
222
|
function GenrePlaylistTreeWheel({
|
|
213
223
|
scope,
|
|
214
224
|
className: className2,
|
|
@@ -229,24 +239,16 @@ function GenrePlaylistTreeWheel({
|
|
|
229
239
|
viewportRestore,
|
|
230
240
|
onViewportChange,
|
|
231
241
|
playback,
|
|
242
|
+
focusUuids,
|
|
232
243
|
...hostPanel
|
|
233
244
|
}) {
|
|
234
245
|
const { isPlaying, setIsPlaying } = usePlayer2();
|
|
235
246
|
const defaultPlayback = useGenrePlaylistPlayback({ scope, genrePlaylists });
|
|
236
247
|
const { playing, play } = playback ?? defaultPlayback;
|
|
237
248
|
const playingNodeId = playing?.uuid ?? null;
|
|
238
|
-
const { showPopup } = usePopup2();
|
|
239
249
|
const nodes = useMemo3(
|
|
240
|
-
() => genrePlaylists
|
|
241
|
-
|
|
242
|
-
parentId: genrePlaylist.parent?.uuid ?? null,
|
|
243
|
-
name: genrePlaylist.name,
|
|
244
|
-
itemCount: genrePlaylistSize(genrePlaylist, sizeMetric),
|
|
245
|
-
actionable: Boolean(genrePlaylist.criteria),
|
|
246
|
-
side: genrePlaylist.criteria?.side ?? void 0,
|
|
247
|
-
wikidataId: genrePlaylist.criteria?.wikidataId ?? null
|
|
248
|
-
})),
|
|
249
|
-
[genrePlaylists, sizeMetric]
|
|
250
|
+
() => toTreeNodes(genrePlaylists, sizeMetric, focusUuids),
|
|
251
|
+
[genrePlaylists, sizeMetric, focusUuids]
|
|
250
252
|
);
|
|
251
253
|
const handlePlayPause = useCallback3(
|
|
252
254
|
(nodeId) => {
|
|
@@ -259,18 +261,14 @@ function GenrePlaylistTreeWheel({
|
|
|
259
261
|
if (genrePlaylistTrackCount3(genrePlaylist) === 0) {
|
|
260
262
|
return;
|
|
261
263
|
}
|
|
262
|
-
play(genrePlaylist)
|
|
263
|
-
console.error("Failed to load genre playlist tracks:", error);
|
|
264
|
-
showPopup(/* @__PURE__ */ jsx2(InternalErrorPopup, { errorCode: ErrorCode2.CLIENT_UNKNOWN }));
|
|
265
|
-
});
|
|
264
|
+
void play(genrePlaylist);
|
|
266
265
|
},
|
|
267
266
|
[
|
|
268
267
|
genrePlaylists,
|
|
269
268
|
playingNodeId,
|
|
270
269
|
isPlaying,
|
|
271
270
|
setIsPlaying,
|
|
272
|
-
play
|
|
273
|
-
showPopup
|
|
271
|
+
play
|
|
274
272
|
]
|
|
275
273
|
);
|
|
276
274
|
const handleAddChild = useCallback3(
|
|
@@ -293,7 +291,7 @@ function GenrePlaylistTreeWheel({
|
|
|
293
291
|
if (confirm(`Are you sure you want to delete "${node.name}"?`)) {
|
|
294
292
|
}
|
|
295
293
|
}, []);
|
|
296
|
-
return /* @__PURE__ */
|
|
294
|
+
return /* @__PURE__ */ jsx3(
|
|
297
295
|
GenreTreeWheel,
|
|
298
296
|
{
|
|
299
297
|
className: className2,
|
|
@@ -328,7 +326,7 @@ import {
|
|
|
328
326
|
GenreTreeWheelRadialPopCore
|
|
329
327
|
} from "@behindthemusictree/genre-tree-view";
|
|
330
328
|
import { usePlayer as usePlayer3 } from "@behindthemusictree/app-kit/player";
|
|
331
|
-
import { jsx as
|
|
329
|
+
import { jsx as jsx4 } from "react/jsx-runtime";
|
|
332
330
|
function GenrePlaylistTreeWheelRadialPopCore(props) {
|
|
333
331
|
const {
|
|
334
332
|
scope,
|
|
@@ -361,7 +359,7 @@ function GenrePlaylistTreeWheelRadialPopCore(props) {
|
|
|
361
359
|
const defaultPlayback = useGenrePlaylistPlayback({ scope, genrePlaylists });
|
|
362
360
|
const { playing, play } = playback ?? defaultPlayback;
|
|
363
361
|
const playingNodeId = playing?.uuid ?? null;
|
|
364
|
-
const nodes = useMemo4(() => toTreeNodes(genrePlaylists, sizeMetric), [genrePlaylists, sizeMetric]);
|
|
362
|
+
const nodes = useMemo4(() => toTreeNodes(genrePlaylists, sizeMetric, props.focusUuids), [genrePlaylists, sizeMetric, props.focusUuids]);
|
|
365
363
|
const handlePlayPause = useCallback4(
|
|
366
364
|
(nodeId) => {
|
|
367
365
|
const genrePlaylist = genrePlaylists.find((g) => g.uuid === nodeId);
|
|
@@ -373,9 +371,7 @@ function GenrePlaylistTreeWheelRadialPopCore(props) {
|
|
|
373
371
|
if (genrePlaylistTrackCount4(genrePlaylist) === 0) {
|
|
374
372
|
return;
|
|
375
373
|
}
|
|
376
|
-
play(genrePlaylist)
|
|
377
|
-
console.error("Failed to load genre playlist tracks:", error);
|
|
378
|
-
});
|
|
374
|
+
void play(genrePlaylist);
|
|
379
375
|
},
|
|
380
376
|
[genrePlaylists, playingNodeId, isPlaying, setIsPlaying, play]
|
|
381
377
|
);
|
|
@@ -415,7 +411,7 @@ function GenrePlaylistTreeWheelRadialPopCore(props) {
|
|
|
415
411
|
onSelectedNodeChange,
|
|
416
412
|
...hostPanel
|
|
417
413
|
};
|
|
418
|
-
return outline ? /* @__PURE__ */
|
|
414
|
+
return outline ? /* @__PURE__ */ jsx4(GenreTreeOutline, { ...treeProps }) : /* @__PURE__ */ jsx4(
|
|
419
415
|
GenreTreeWheelRadialPopCore,
|
|
420
416
|
{
|
|
421
417
|
...treeProps,
|
|
@@ -432,7 +428,7 @@ function GenrePlaylistTreeWheelRadialPopCore(props) {
|
|
|
432
428
|
|
|
433
429
|
// src/genre-tree/GenreTreeWheelHandoff.tsx
|
|
434
430
|
import { useEffect, useRef, useState } from "react";
|
|
435
|
-
import { jsx as
|
|
431
|
+
import { jsx as jsx5, jsxs } from "react/jsx-runtime";
|
|
436
432
|
function GenreTreeWheelHandoff({ skeleton, children, onRevealedChange }) {
|
|
437
433
|
const [revealed, setRevealed] = useState(false);
|
|
438
434
|
const onRevealedChangeRef = useRef(onRevealedChange);
|
|
@@ -452,7 +448,7 @@ function GenreTreeWheelHandoff({ skeleton, children, onRevealedChange }) {
|
|
|
452
448
|
};
|
|
453
449
|
}, []);
|
|
454
450
|
return /* @__PURE__ */ jsxs("div", { className: "relative w-full h-full", children: [
|
|
455
|
-
/* @__PURE__ */
|
|
451
|
+
/* @__PURE__ */ jsx5(
|
|
456
452
|
"div",
|
|
457
453
|
{
|
|
458
454
|
className: "absolute inset-0 transition-opacity duration-150 ease-out",
|
|
@@ -461,7 +457,7 @@ function GenreTreeWheelHandoff({ skeleton, children, onRevealedChange }) {
|
|
|
461
457
|
children
|
|
462
458
|
}
|
|
463
459
|
),
|
|
464
|
-
!revealed && /* @__PURE__ */
|
|
460
|
+
!revealed && /* @__PURE__ */ jsx5("div", { className: "absolute inset-0", "aria-hidden": "true", children: skeleton })
|
|
465
461
|
] });
|
|
466
462
|
}
|
|
467
463
|
|
|
@@ -476,7 +472,7 @@ import { useGenreSearch } from "@behindthemusictree/app-kit/genre-tree";
|
|
|
476
472
|
// src/genre-tree/search/SearchBox.tsx
|
|
477
473
|
import { useState as useState2 } from "react";
|
|
478
474
|
import { SearchCombobox } from "@behindthemusictree/ui";
|
|
479
|
-
import { jsx as
|
|
475
|
+
import { jsx as jsx6 } from "react/jsx-runtime";
|
|
480
476
|
function SearchBox({
|
|
481
477
|
label,
|
|
482
478
|
placeholder,
|
|
@@ -498,7 +494,7 @@ function SearchBox({
|
|
|
498
494
|
groups.find((group) => group.key === groupKey)?.items.find((item) => item.key === itemKey)?.onSelect();
|
|
499
495
|
onPicked?.(groupKey, itemKey);
|
|
500
496
|
};
|
|
501
|
-
return /* @__PURE__ */
|
|
497
|
+
return /* @__PURE__ */ jsx6("div", { className: className2, onFocusCapture: onFocus, children: /* @__PURE__ */ jsx6(
|
|
502
498
|
SearchCombobox,
|
|
503
499
|
{
|
|
504
500
|
ariaLabel: label,
|
|
@@ -564,7 +560,7 @@ import {
|
|
|
564
560
|
isSongSearchResultPlayable,
|
|
565
561
|
useSongSearch
|
|
566
562
|
} from "@behindthemusictree/app-kit/genre-tree";
|
|
567
|
-
import { jsx as
|
|
563
|
+
import { jsx as jsx7, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
568
564
|
function useSongSearchGroup(getBaseUrl, text, onSelect, enabled = true) {
|
|
569
565
|
const search = useSongSearch(getBaseUrl, enabled ? text : "");
|
|
570
566
|
if (!enabled) return void 0;
|
|
@@ -574,8 +570,8 @@ function useSongSearchGroup(getBaseUrl, text, onSelect, enabled = true) {
|
|
|
574
570
|
items: search.songs.map((song) => ({
|
|
575
571
|
key: song.uuid,
|
|
576
572
|
content: /* @__PURE__ */ jsxs3("span", { className: isSongSearchResultPlayable(song) ? void 0 : "opacity-60", children: [
|
|
577
|
-
/* @__PURE__ */
|
|
578
|
-
/* @__PURE__ */
|
|
573
|
+
/* @__PURE__ */ jsx7("span", { className: "block truncate font-medium", children: song.title }),
|
|
574
|
+
/* @__PURE__ */ jsx7("span", { className: "block truncate text-caption text-[var(--color-neutral-500)]", children: [song.artists.map((artist) => artist.name).join(", "), song.genre?.name ?? "No genre"].filter(Boolean).join(" \xB7 ") })
|
|
579
575
|
] }),
|
|
580
576
|
onSelect: () => onSelect(song)
|
|
581
577
|
})),
|
|
@@ -588,7 +584,7 @@ function useSongSearchGroup(getBaseUrl, text, onSelect, enabled = true) {
|
|
|
588
584
|
import {
|
|
589
585
|
useGenreRemoteSearch
|
|
590
586
|
} from "@behindthemusictree/app-kit/genre-tree";
|
|
591
|
-
import { Fragment as Fragment2, jsx as
|
|
587
|
+
import { Fragment as Fragment2, jsx as jsx8, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
592
588
|
function useGenreRemoteSearchGroup(getBaseUrl, text, onSelect, { key = "genres", label = "Genres", filter, describe, ...options } = {}) {
|
|
593
589
|
const search = useGenreRemoteSearch(getBaseUrl, text, options);
|
|
594
590
|
const genres = filter ? search.genres.filter(filter) : search.genres;
|
|
@@ -600,9 +596,9 @@ function useGenreRemoteSearchGroup(getBaseUrl, text, onSelect, { key = "genres",
|
|
|
600
596
|
content: /* @__PURE__ */ jsxs4(Fragment2, { children: [
|
|
601
597
|
/* @__PURE__ */ jsxs4("span", { className: "block truncate font-medium", children: [
|
|
602
598
|
genre.name,
|
|
603
|
-
genre.isUmbrella && /* @__PURE__ */
|
|
599
|
+
genre.isUmbrella && /* @__PURE__ */ jsx8("span", { className: "ml-2 text-caption font-normal italic text-[var(--color-text-muted)]", children: "umbrella" })
|
|
604
600
|
] }),
|
|
605
|
-
/* @__PURE__ */
|
|
601
|
+
/* @__PURE__ */ jsx8("span", { className: "block truncate text-caption text-[var(--color-neutral-500)]", children: describe?.(genre) ?? `${genre.treeName} \xB7 ${genre.root.name}` })
|
|
606
602
|
] }),
|
|
607
603
|
onSelect: () => onSelect(genre)
|
|
608
604
|
})),
|
|
@@ -612,7 +608,7 @@ function useGenreRemoteSearchGroup(getBaseUrl, text, onSelect, { key = "genres",
|
|
|
612
608
|
}
|
|
613
609
|
|
|
614
610
|
// src/genre-tree/GenreSearch.tsx
|
|
615
|
-
import { Fragment as Fragment3, jsx as
|
|
611
|
+
import { Fragment as Fragment3, jsx as jsx9, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
616
612
|
function GenreSearch({
|
|
617
613
|
genrePlaylists,
|
|
618
614
|
onSelect,
|
|
@@ -643,7 +639,7 @@ function GenreSearch({
|
|
|
643
639
|
key: genrePlaylist.uuid,
|
|
644
640
|
content: /* @__PURE__ */ jsxs5(Fragment3, { children: [
|
|
645
641
|
genrePlaylist.name,
|
|
646
|
-
genrePlaylist.isUmbrella && /* @__PURE__ */
|
|
642
|
+
genrePlaylist.isUmbrella && /* @__PURE__ */ jsx9("span", { className: "ml-2 text-caption italic text-[var(--color-text-muted)]", children: "umbrella" })
|
|
647
643
|
] }),
|
|
648
644
|
onSelect: () => select(genrePlaylist)
|
|
649
645
|
}))
|
|
@@ -652,7 +648,7 @@ function GenreSearch({
|
|
|
652
648
|
(group) => active ? group : { ...group, items: [], status: "", loading: false }
|
|
653
649
|
)
|
|
654
650
|
];
|
|
655
|
-
return /* @__PURE__ */
|
|
651
|
+
return /* @__PURE__ */ jsx9("div", { className: "genre-search w-[calc(var(--layout-detail-panel-w,25.5rem)-2*var(--layout-panel-inset,1rem))] shrink-0 max-md:w-full", children: /* @__PURE__ */ jsx9(
|
|
656
652
|
SearchBox,
|
|
657
653
|
{
|
|
658
654
|
label,
|
|
@@ -672,14 +668,14 @@ function GenreSearch({
|
|
|
672
668
|
clear();
|
|
673
669
|
onQueryChange?.("");
|
|
674
670
|
} : void 0,
|
|
675
|
-
leading: onPrevious && /* @__PURE__ */
|
|
671
|
+
leading: onPrevious && /* @__PURE__ */ jsx9("button", { type: "button", "aria-label": "Previous", title: "Previous", className: SEARCH_LEADING_BUTTON_CLASS, onClick: onPrevious, children: /* @__PURE__ */ jsx9(ArrowLeft, { "aria-hidden": "true", className: "h-4 w-4" }) }),
|
|
676
672
|
onFocus
|
|
677
673
|
}
|
|
678
674
|
) });
|
|
679
675
|
}
|
|
680
676
|
|
|
681
677
|
// src/genre-tree/GenreTreeSearch.tsx
|
|
682
|
-
import { jsx as
|
|
678
|
+
import { jsx as jsx10 } from "react/jsx-runtime";
|
|
683
679
|
function GenreTreeSearch({
|
|
684
680
|
artistBaseUrl,
|
|
685
681
|
songBaseUrl,
|
|
@@ -699,7 +695,7 @@ function GenreTreeSearch({
|
|
|
699
695
|
const deferredQuery = useDeferredValue(query);
|
|
700
696
|
const artistGroup = useArtistSearchGroup(artistBaseUrl, deferredQuery, onArtistSelect, artistSearch);
|
|
701
697
|
const songGroup = useSongSearchGroup(songBaseUrl, deferredQuery, onSongSelect, songSearch);
|
|
702
|
-
const render = (hostGroups) => /* @__PURE__ */
|
|
698
|
+
const render = (hostGroups) => /* @__PURE__ */ jsx10(
|
|
703
699
|
GenreSearch,
|
|
704
700
|
{
|
|
705
701
|
...props,
|
|
@@ -714,7 +710,7 @@ function GenreTreeSearch({
|
|
|
714
710
|
extraGroups: [...extraGroups, ...hostGroups, artistGroup, songGroup].filter((group) => group !== void 0)
|
|
715
711
|
}
|
|
716
712
|
);
|
|
717
|
-
return SearchGroups ? /* @__PURE__ */
|
|
713
|
+
return SearchGroups ? /* @__PURE__ */ jsx10(SearchGroups, { query: deferredQuery, focused, onSelectGenre, children: render }) : render([]);
|
|
718
714
|
}
|
|
719
715
|
|
|
720
716
|
// src/genre-tree/GenreDetailPanel.tsx
|
|
@@ -751,7 +747,7 @@ import { ActionBand, ActionButton as ActionButton2, PanelBleed } from "@behindth
|
|
|
751
747
|
// src/genre-tree/ShareActionButton.tsx
|
|
752
748
|
import { Share2 as Share22 } from "lucide-react";
|
|
753
749
|
import { ActionButton } from "@behindthemusictree/ui";
|
|
754
|
-
import { usePopup as
|
|
750
|
+
import { usePopup as usePopup2 } from "@behindthemusictree/app-kit/popup";
|
|
755
751
|
|
|
756
752
|
// src/genre-tree/SharePopup.tsx
|
|
757
753
|
import { useCallback as useCallback5, useEffect as useEffect2, useMemo as useMemo5, useState as useState4 } from "react";
|
|
@@ -760,12 +756,12 @@ import { FaWhatsapp } from "react-icons/fa";
|
|
|
760
756
|
import { SiGmail } from "react-icons/si";
|
|
761
757
|
|
|
762
758
|
// src/genre-tree/ShareDestinationButton.tsx
|
|
763
|
-
import { Fragment as Fragment4, jsx as
|
|
759
|
+
import { Fragment as Fragment4, jsx as jsx11, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
764
760
|
var className = "group flex min-w-0 flex-1 flex-col items-center justify-center gap-1.5 rounded-xl px-2 py-2 text-caption text-[var(--color-text)] transition-colors hover:bg-[var(--color-surface-muted)] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-focus-ring)] disabled:cursor-not-allowed disabled:opacity-50";
|
|
765
761
|
function Contents({ icon, label }) {
|
|
766
762
|
return /* @__PURE__ */ jsxs6(Fragment4, { children: [
|
|
767
|
-
/* @__PURE__ */
|
|
768
|
-
/* @__PURE__ */
|
|
763
|
+
/* @__PURE__ */ jsx11("span", { className: "flex h-12 w-12 items-center justify-center rounded-full bg-[var(--color-surface-muted)] transition-colors group-hover:bg-[var(--color-border)]", children: icon }),
|
|
764
|
+
/* @__PURE__ */ jsx11("span", { className: "max-w-full truncate", children: label })
|
|
769
765
|
] });
|
|
770
766
|
}
|
|
771
767
|
function ShareDestinationButton({
|
|
@@ -777,29 +773,29 @@ function ShareDestinationButton({
|
|
|
777
773
|
ariaLabel
|
|
778
774
|
}) {
|
|
779
775
|
if (href) {
|
|
780
|
-
return /* @__PURE__ */
|
|
776
|
+
return /* @__PURE__ */ jsx11("a", { href, target: "_blank", rel: "noopener noreferrer", "aria-label": ariaLabel, className, children: /* @__PURE__ */ jsx11(Contents, { icon, label }) });
|
|
781
777
|
}
|
|
782
|
-
return /* @__PURE__ */
|
|
778
|
+
return /* @__PURE__ */ jsx11("button", { type: "button", onClick, disabled, "aria-label": ariaLabel, className, children: /* @__PURE__ */ jsx11(Contents, { icon, label }) });
|
|
783
779
|
}
|
|
784
780
|
|
|
785
781
|
// src/genre-tree/SharePreviewCard.tsx
|
|
786
782
|
import { Music, Music2, UserRound } from "lucide-react";
|
|
787
|
-
import { jsx as
|
|
783
|
+
import { jsx as jsx12, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
788
784
|
function SharePreviewCard({ target, url }) {
|
|
789
785
|
const Icon = { genre: Music2, artist: UserRound, song: Music }[target.kind];
|
|
790
786
|
const typeLabel = { genre: "Genre", artist: "Artist", song: "Song" }[target.kind];
|
|
791
|
-
return /* @__PURE__ */
|
|
792
|
-
/* @__PURE__ */
|
|
787
|
+
return /* @__PURE__ */ jsx12("div", { className: "rounded-3xl bg-[var(--color-surface-muted)] p-4", children: /* @__PURE__ */ jsxs7("div", { className: "flex min-h-32 overflow-hidden rounded-2xl bg-[var(--color-surface)] shadow-lg", children: [
|
|
788
|
+
/* @__PURE__ */ jsx12("div", { className: "flex w-28 shrink-0 items-center justify-center bg-[var(--color-primary)]/15 text-[var(--color-primary)]", children: /* @__PURE__ */ jsx12(Icon, { "aria-hidden": "true", className: "h-10 w-10" }) }),
|
|
793
789
|
/* @__PURE__ */ jsxs7("div", { className: "flex min-w-0 flex-1 flex-col justify-center gap-1 p-4", children: [
|
|
794
|
-
/* @__PURE__ */
|
|
795
|
-
/* @__PURE__ */
|
|
796
|
-
/* @__PURE__ */
|
|
790
|
+
/* @__PURE__ */ jsx12("span", { className: "text-caption font-medium uppercase tracking-wide text-[var(--color-text-muted)]", children: typeLabel }),
|
|
791
|
+
/* @__PURE__ */ jsx12("span", { className: "truncate text-base font-semibold text-[var(--color-text)]", title: target.name, children: target.name }),
|
|
792
|
+
/* @__PURE__ */ jsx12("span", { className: "truncate text-body text-[var(--color-primary)]", title: url, children: url })
|
|
797
793
|
] })
|
|
798
794
|
] }) });
|
|
799
795
|
}
|
|
800
796
|
|
|
801
797
|
// src/genre-tree/SharePopup.tsx
|
|
802
|
-
import { Fragment as Fragment5, jsx as
|
|
798
|
+
import { Fragment as Fragment5, jsx as jsx13, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
803
799
|
function resolveAbsoluteUrl(url) {
|
|
804
800
|
try {
|
|
805
801
|
const parsed = new URL(url, window.location.href);
|
|
@@ -875,7 +871,7 @@ function SharePopup({ target, url, onClose }) {
|
|
|
875
871
|
}
|
|
876
872
|
};
|
|
877
873
|
return /* @__PURE__ */ jsxs8(Fragment5, { children: [
|
|
878
|
-
/* @__PURE__ */
|
|
874
|
+
/* @__PURE__ */ jsx13(
|
|
879
875
|
BasePopup_default,
|
|
880
876
|
{
|
|
881
877
|
title: "Share",
|
|
@@ -891,69 +887,69 @@ function SharePopup({ target, url, onClose }) {
|
|
|
891
887
|
closeButtonClassName: "!h-10 !w-10 !rounded-none !border-0 !bg-transparent !p-0 !text-[var(--color-text)] hover:!bg-transparent hover:!text-[var(--color-text)]",
|
|
892
888
|
contentClassName: "!rounded-none !bg-transparent !px-6 !pb-6 !pt-2",
|
|
893
889
|
children: /* @__PURE__ */ jsxs8("div", { className: "flex flex-col gap-4", children: [
|
|
894
|
-
/* @__PURE__ */
|
|
890
|
+
/* @__PURE__ */ jsx13(SharePreviewCard, { target, url: absoluteUrl || url }),
|
|
895
891
|
/* @__PURE__ */ jsxs8("div", { className: "grid grid-cols-3 gap-1 rounded-3xl bg-[var(--color-surface)] p-3 sm:grid-cols-4", children: [
|
|
896
|
-
/* @__PURE__ */
|
|
892
|
+
/* @__PURE__ */ jsx13(
|
|
897
893
|
ShareDestinationButton,
|
|
898
894
|
{
|
|
899
895
|
label: "Copy Link",
|
|
900
|
-
icon: /* @__PURE__ */
|
|
896
|
+
icon: /* @__PURE__ */ jsx13(Link2, { "aria-hidden": "true", className: "h-6 w-6" }),
|
|
901
897
|
onClick: () => void handleCopy(),
|
|
902
898
|
ariaLabel: "Copy link",
|
|
903
899
|
disabled: !absoluteUrl
|
|
904
900
|
}
|
|
905
901
|
),
|
|
906
|
-
/* @__PURE__ */
|
|
902
|
+
/* @__PURE__ */ jsx13(
|
|
907
903
|
ShareDestinationButton,
|
|
908
904
|
{
|
|
909
905
|
label: "WhatsApp",
|
|
910
|
-
icon: /* @__PURE__ */
|
|
906
|
+
icon: /* @__PURE__ */ jsx13(FaWhatsapp, { "aria-hidden": "true", className: "h-9 w-9 text-[#25D366]" }),
|
|
911
907
|
href: destinationUrls?.whatsapp,
|
|
912
908
|
ariaLabel: `Share ${target.name} via WhatsApp`,
|
|
913
909
|
disabled: !absoluteUrl
|
|
914
910
|
}
|
|
915
911
|
),
|
|
916
|
-
/* @__PURE__ */
|
|
912
|
+
/* @__PURE__ */ jsx13(
|
|
917
913
|
ShareDestinationButton,
|
|
918
914
|
{
|
|
919
915
|
label: "Gmail",
|
|
920
|
-
icon: /* @__PURE__ */
|
|
916
|
+
icon: /* @__PURE__ */ jsx13(SiGmail, { "aria-hidden": "true", className: "h-8 w-8 text-[#EA4335]" }),
|
|
921
917
|
href: destinationUrls?.gmail,
|
|
922
918
|
ariaLabel: `Email ${target.name} with Gmail`,
|
|
923
919
|
disabled: !absoluteUrl
|
|
924
920
|
}
|
|
925
921
|
),
|
|
926
|
-
canUseNativeShare && /* @__PURE__ */
|
|
922
|
+
canUseNativeShare && /* @__PURE__ */ jsx13(
|
|
927
923
|
ShareDestinationButton,
|
|
928
924
|
{
|
|
929
925
|
label: "More",
|
|
930
|
-
icon: /* @__PURE__ */
|
|
926
|
+
icon: /* @__PURE__ */ jsx13(Share2, { "aria-hidden": "true", className: "h-6 w-6" }),
|
|
931
927
|
onClick: () => void handleNativeShare(),
|
|
932
928
|
ariaLabel: "More sharing options",
|
|
933
929
|
disabled: !absoluteUrl
|
|
934
930
|
}
|
|
935
931
|
)
|
|
936
932
|
] }),
|
|
937
|
-
copyStatus === "failed" && /* @__PURE__ */
|
|
938
|
-
shareError && /* @__PURE__ */
|
|
933
|
+
copyStatus === "failed" && /* @__PURE__ */ jsx13("p", { role: "alert", className: "text-center text-body text-[var(--color-red-500)]", children: "Could not copy the link." }),
|
|
934
|
+
shareError && /* @__PURE__ */ jsx13("p", { role: "alert", className: "text-center text-body text-[var(--color-red-500)]", children: shareError })
|
|
939
935
|
] })
|
|
940
936
|
}
|
|
941
937
|
),
|
|
942
|
-
toastId > 0 && /* @__PURE__ */
|
|
938
|
+
toastId > 0 && /* @__PURE__ */ jsx13(Toast, { message: "Link copied", onClose: dismissToast }, toastId)
|
|
943
939
|
] });
|
|
944
940
|
}
|
|
945
941
|
|
|
946
942
|
// src/genre-tree/ShareActionButton.tsx
|
|
947
|
-
import { jsx as
|
|
943
|
+
import { jsx as jsx14 } from "react/jsx-runtime";
|
|
948
944
|
function ShareActionButton({ target, url }) {
|
|
949
|
-
const { showPopup, hidePopup } =
|
|
945
|
+
const { showPopup, hidePopup } = usePopup2();
|
|
950
946
|
const openSharePopup = () => {
|
|
951
|
-
showPopup(/* @__PURE__ */
|
|
947
|
+
showPopup(/* @__PURE__ */ jsx14(SharePopup, { target, url, onClose: hidePopup }));
|
|
952
948
|
};
|
|
953
|
-
return /* @__PURE__ */
|
|
949
|
+
return /* @__PURE__ */ jsx14(
|
|
954
950
|
ActionButton,
|
|
955
951
|
{
|
|
956
|
-
icon: /* @__PURE__ */
|
|
952
|
+
icon: /* @__PURE__ */ jsx14(Share22, { "aria-hidden": "true", className: "w-5 h-5" }),
|
|
957
953
|
label: "Share",
|
|
958
954
|
"aria-label": `Share ${target.name}`,
|
|
959
955
|
title: `Share ${target.name}`,
|
|
@@ -963,7 +959,7 @@ function ShareActionButton({ target, url }) {
|
|
|
963
959
|
}
|
|
964
960
|
|
|
965
961
|
// src/genre-tree/GenreActionBand.tsx
|
|
966
|
-
import { jsx as
|
|
962
|
+
import { jsx as jsx15, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
967
963
|
function GenreActionBand({
|
|
968
964
|
node,
|
|
969
965
|
playActions,
|
|
@@ -984,24 +980,24 @@ function GenreActionBand({
|
|
|
984
980
|
items.push({
|
|
985
981
|
key: "zoom-in",
|
|
986
982
|
label: "Focus",
|
|
987
|
-
icon: /* @__PURE__ */
|
|
983
|
+
icon: /* @__PURE__ */ jsx15(ZoomIn, { "aria-hidden": "true", className: "w-5 h-5" }),
|
|
988
984
|
onClick: onZoomIn
|
|
989
985
|
});
|
|
990
986
|
}
|
|
991
987
|
if (onAddChild) {
|
|
992
|
-
adminItems.push({ key: "add-child", label: "Add", icon: /* @__PURE__ */
|
|
988
|
+
adminItems.push({ key: "add-child", label: "Add", icon: /* @__PURE__ */ jsx15(Plus, { "aria-hidden": "true", className: "w-5 h-5" }), onClick: onAddChild });
|
|
993
989
|
}
|
|
994
990
|
if (onRename) {
|
|
995
|
-
adminItems.push({ key: "rename", label: "Rename", icon: /* @__PURE__ */
|
|
991
|
+
adminItems.push({ key: "rename", label: "Rename", icon: /* @__PURE__ */ jsx15(Pencil, { "aria-hidden": "true", className: "w-5 h-5" }), onClick: onRename });
|
|
996
992
|
}
|
|
997
993
|
if (onChangeParent) {
|
|
998
|
-
adminItems.push({ key: "change-parent", label: "Parent", icon: /* @__PURE__ */
|
|
994
|
+
adminItems.push({ key: "change-parent", label: "Parent", icon: /* @__PURE__ */ jsx15(MoveUpRight, { "aria-hidden": "true", className: "w-5 h-5" }), onClick: onChangeParent });
|
|
999
995
|
}
|
|
1000
996
|
if (onToggleSide) {
|
|
1001
997
|
adminItems.push({
|
|
1002
998
|
key: "toggle-side",
|
|
1003
999
|
label: side === "pop" ? "Make core" : "Make pop",
|
|
1004
|
-
icon: /* @__PURE__ */
|
|
1000
|
+
icon: /* @__PURE__ */ jsx15(ArrowLeftRight, { "aria-hidden": "true", className: "w-5 h-5" }),
|
|
1005
1001
|
onClick: onToggleSide,
|
|
1006
1002
|
disabled: !!toggleSideDisabledReason,
|
|
1007
1003
|
title: toggleSideDisabledReason
|
|
@@ -1016,9 +1012,9 @@ function GenreActionBand({
|
|
|
1016
1012
|
disabled: action.enabled ? !action.enabled(node) : false
|
|
1017
1013
|
});
|
|
1018
1014
|
}
|
|
1019
|
-
const renderItems = (list) => list.map((item) => /* @__PURE__ */
|
|
1015
|
+
const renderItems = (list) => list.map((item) => /* @__PURE__ */ jsx15(ActionButton2, { icon: item.icon, label: item.label, disabled: item.disabled, title: item.title, onClick: item.onClick }, item.key));
|
|
1020
1016
|
if (!playActions && items.length === 0 && adminItems.length === 0 && !(shareTarget && shareUrl)) return null;
|
|
1021
|
-
return /* @__PURE__ */
|
|
1017
|
+
return /* @__PURE__ */ jsx15(PanelBleed, { children: /* @__PURE__ */ jsxs9(
|
|
1022
1018
|
ActionBand,
|
|
1023
1019
|
{
|
|
1024
1020
|
className: "genre-action-band",
|
|
@@ -1026,7 +1022,7 @@ function GenreActionBand({
|
|
|
1026
1022
|
children: [
|
|
1027
1023
|
playActions,
|
|
1028
1024
|
renderItems(items),
|
|
1029
|
-
shareTarget && shareUrl && /* @__PURE__ */
|
|
1025
|
+
shareTarget && shareUrl && /* @__PURE__ */ jsx15(ShareActionButton, { target: shareTarget, url: shareUrl })
|
|
1030
1026
|
]
|
|
1031
1027
|
}
|
|
1032
1028
|
) });
|
|
@@ -1053,7 +1049,7 @@ var REGION_GLOBE_PATHS = {
|
|
|
1053
1049
|
var REGION_GLOBES = ["africa", "americas", "asia"];
|
|
1054
1050
|
|
|
1055
1051
|
// src/genre-tree/RegionGlobeIcon.tsx
|
|
1056
|
-
import { jsx as
|
|
1052
|
+
import { jsx as jsx16 } from "react/jsx-runtime";
|
|
1057
1053
|
var ROTATION_INTERVAL_MS = 3e3;
|
|
1058
1054
|
function RegionGlobeIcon({ className: className2 }) {
|
|
1059
1055
|
const [index, setIndex] = useState5(0);
|
|
@@ -1071,29 +1067,29 @@ function RegionGlobeIcon({ className: className2 }) {
|
|
|
1071
1067
|
clearInterval(timer);
|
|
1072
1068
|
};
|
|
1073
1069
|
}, []);
|
|
1074
|
-
return /* @__PURE__ */
|
|
1070
|
+
return /* @__PURE__ */ jsx16("svg", { viewBox: "0 0 512 512", fill: "currentColor", className: className2, "aria-hidden": true, children: /* @__PURE__ */ jsx16("path", { "data-testid": "region-globe-path", d: REGION_GLOBE_PATHS[REGION_GLOBES[index]] }) });
|
|
1075
1071
|
}
|
|
1076
1072
|
|
|
1077
1073
|
// src/genre-tree/treeMarkPath.ts
|
|
1078
1074
|
var TREE_MARK_PATH = "M3171 5598 c-5 -13 -5 -24 0 -26 5 -2 9 -16 9 -31 0 -25 -3 -28 -25 -23 l-25 4 0 -116 c0 -64 3 -116 8 -116 10 0 32 51 26 61 -3 5 -1 9 4 9 5 0 15 12 21 28 7 15 26 36 43 47 30 20 88 105 71 105 -4 0 -33 -21 -62 -47 l-54 -47 6 63 c4 35 7 72 7 82 0 10 9 19 23 22 16 3 13 5 -11 6 -25 1 -35 -4 -41 -21z M2893 5485 c8 -76 24 -100 71 -100 l36 0 0 53 c0 58 -15 69 -28 20 -8 -29 -10 -30 -16 -13 -15 43 -42 89 -55 93 -11 4 -13 -6 -8 -53z M2484 5438 c8 -70 49 -169 54 -131 2 12 10 27 18 33 17 15 19 84 3 129 -9 27 -16 31 -46 31 l-36 0 7 -62z M2625 5448 c-7 -22 -24 -121 -31 -179 l-6 -57 -27 11 c-15 5 -32 19 -37 31 -9 21 -88 86 -105 86 -39 0 38 -104 118 -158 17 -12 56 -59 86 -105 30 -45 67 -92 81 -104 14 -13 26 -30 26 -38 0 -13 -9 -11 -45 11 -67 39 -58 10 21 -66 67 -65 96 -110 108 -167 4 -17 13 -34 20 -36 20 -8 66 -186 75 -289 13 -161 -8 -272 -72 -365 -12 -18 -30 -33 -39 -33 -23 0 -53 33 -79 89 -25 54 -69 112 -121 162 -35 33 -38 40 -38 92 0 58 36 172 79 252 25 47 29 125 6 125 -19 0 -30 -22 -50 -100 -9 -35 -24 -78 -32 -94 l-16 -30 -19 24 -20 25 7 -58 c8 -62 0 -127 -16 -127 -19 0 -122 107 -166 172 -52 79 -68 150 -60 273 8 108 17 129 67 149 58 23 97 64 105 109 9 47 -5 49 -63 6 l-42 -30 15 35 c17 41 20 102 5 111 -18 11 -45 -4 -64 -36 -11 -19 -20 -60 -23 -110 -4 -54 -10 -79 -18 -79 -20 0 -27 28 -30 108 -2 40 -6 76 -9 79 -3 4 -6 51 -6 105 0 86 -3 101 -21 119 -27 27 -42 20 -53 -24 -7 -28 -5 -51 7 -90 9 -30 17 -76 17 -103 l0 -49 -29 51 c-29 49 -92 114 -111 114 -6 0 -10 -11 -10 -25 0 -14 5 -25 10 -25 6 0 10 -6 10 -13 0 -7 23 -44 51 -82 61 -84 59 -82 52 -57 -3 14 2 24 15 31 12 6 23 23 25 38 2 16 5 2 6 -29 1 -46 -2 -58 -14 -58 -21 0 -19 -13 10 -70 22 -44 25 -61 25 -165 l0 -116 -47 27 c-65 36 -142 118 -176 187 -15 31 -37 62 -49 68 -21 11 -21 10 -15 -41 l6 -52 -29 6 c-37 7 -39 -7 -4 -31 14 -10 53 -40 86 -68 92 -76 130 -104 163 -119 39 -19 101 -84 109 -116 10 -42 50 -88 217 -245 50 -47 94 -102 134 -167 33 -54 65 -98 71 -98 17 0 45 -79 51 -145 4 -47 0 -76 -20 -135 -14 -41 -39 -121 -56 -177 -18 -57 -35 -103 -40 -103 -4 0 -26 13 -49 30 -31 22 -50 49 -82 117 -99 209 -116 241 -185 337 -123 172 -123 173 -128 311 -5 140 -29 245 -57 245 -12 0 -20 -11 -24 -31 -9 -46 -7 -108 3 -127 14 -26 25 -162 14 -162 -20 0 -160 99 -192 135 -19 22 -42 58 -52 80 -10 23 -27 52 -37 66 -10 13 -26 38 -34 54 -9 17 -23 45 -33 64 -15 29 -16 40 -6 80 31 116 34 139 27 205 -7 57 -11 69 -28 74 -14 3 -32 30 -54 79 -21 46 -39 73 -47 70 -13 -5 -14 -15 -3 -65 l8 -33 -49 25 c-61 31 -93 40 -93 27 0 -13 43 -41 122 -79 47 -22 72 -41 83 -61 19 -38 19 -51 0 -51 -12 0 -15 -15 -16 -72 -1 -79 -12 -134 -22 -108 -3 8 -10 48 -16 89 -14 89 -25 111 -54 111 -38 0 -50 -15 -45 -54 4 -40 2 -42 -26 -21 -29 22 -36 19 -36 -20 0 -39 39 -85 125 -145 38 -27 62 -56 99 -120 45 -79 82 -177 70 -189 -2 -3 -42 3 -87 13 -45 10 -99 21 -119 26 -47 9 -103 51 -125 93 -24 44 -83 203 -94 252 -5 25 -4 59 3 91 14 68 3 140 -23 155 -12 6 -23 8 -27 5 -14 -15 -13 -115 2 -159 39 -116 0 -116 -70 1 -22 36 -31 42 -59 42 -20 0 -35 6 -39 15 -6 16 -56 21 -56 6 0 -5 23 -25 51 -44 53 -36 158 -156 188 -216 10 -20 26 -60 36 -88 11 -29 25 -53 32 -53 8 0 13 -12 13 -30 0 -26 -4 -30 -27 -31 l-28 -1 25 -7 c26 -8 177 -87 196 -102 5 -4 50 -18 100 -29 122 -29 277 -78 300 -95 10 -8 26 -15 34 -15 35 0 160 -166 160 -212 0 -22 -32 -24 -50 -4 -11 14 -100 46 -165 61 -16 3 -68 25 -115 48 -102 49 -163 56 -168 19 -9 -62 58 -104 178 -112 63 -5 103 -14 155 -37 39 -16 91 -38 117 -47 26 -9 74 -35 106 -56 52 -33 65 -48 96 -112 20 -40 39 -95 43 -122 6 -47 6 -48 -18 -41 -33 10 -69 33 -69 45 0 6 -10 10 -23 10 -13 0 -27 4 -32 9 -6 5 -27 14 -47 20 -20 7 -53 23 -73 37 -43 29 -45 29 -45 7 0 -26 80 -96 145 -127 119 -56 274 -185 311 -259 55 -107 104 -410 104 -640 0 -162 -22 -325 -45 -333 -25 -10 -72 25 -168 123 -129 131 -140 148 -182 274 -20 60 -50 142 -66 181 -16 39 -45 131 -65 202 -24 93 -55 173 -104 274 -77 158 -78 166 -32 256 31 64 27 129 -12 181 -31 40 -39 42 -65 18 -51 -49 -55 -120 -11 -208 37 -74 37 -85 3 -85 -36 0 -94 65 -137 154 -18 39 -37 80 -40 92 -3 11 -14 29 -24 40 -10 10 -28 35 -42 54 -13 19 -40 55 -61 80 -20 25 -41 63 -47 85 -6 22 -16 62 -23 89 -20 81 -95 147 -113 100 -18 -47 -6 -92 39 -147 25 -31 45 -61 45 -67 0 -15 -42 -3 -116 31 -94 44 -156 124 -184 235 -9 36 -13 41 -38 40 -39 -2 -144 113 -186 205 -31 66 -33 68 -53 54 -11 -8 -24 -11 -27 -7 -4 4 11 -24 33 -62 39 -67 43 -86 18 -86 -8 0 -8 3 1 9 11 6 9 9 -7 14 -11 3 -25 -1 -31 -7 -7 -10 0 -16 29 -24 39 -12 203 -147 215 -178 13 -34 4 -35 -48 -6 -64 37 -126 51 -126 30 0 -26 55 -67 125 -92 46 -16 80 -36 100 -58 l29 -33 -54 -3 c-79 -5 -203 14 -249 38 -47 24 -70 54 -105 140 -43 105 -115 163 -103 83 3 -21 9 -47 13 -57 4 -11 -15 4 -42 32 -62 64 -84 67 -84 14 0 -41 24 -76 61 -87 16 -6 18 -9 8 -15 -23 -15 15 -45 117 -91 52 -24 93 -48 91 -54 -10 -28 -150 -28 -190 0 -21 15 -47 5 -47 -17 0 -5 -10 -19 -22 -29 -23 -20 -23 -20 112 -14 174 8 208 8 430 0 l185 -7 84 -41 c115 -57 180 -118 225 -212 20 -41 36 -77 36 -80 0 -14 89 -126 150 -190 74 -78 120 -144 120 -175 0 -30 10 -33 -201 52 -94 38 -131 71 -218 195 -27 37 -59 77 -71 88 l-23 20 7 -40 c4 -22 12 -44 17 -49 13 -14 11 -26 -4 -26 -7 0 -29 21 -48 48 -33 45 -34 51 -39 159 -4 89 -9 116 -22 130 -17 16 -18 16 -18 0 0 -9 -7 -17 -16 -17 -14 0 -16 -9 -11 -62 3 -35 8 -74 12 -88 l7 -25 -25 27 c-41 44 -127 118 -137 118 -18 0 -10 -57 12 -85 18 -24 20 -32 10 -57 -10 -28 -9 -30 22 -43 18 -8 54 -19 79 -26 36 -9 60 -24 99 -66 80 -83 80 -83 1 -83 -80 0 -176 21 -236 51 -107 54 -234 169 -252 228 -4 14 -12 29 -17 35 -5 6 -18 25 -28 43 -24 40 -90 64 -116 42 -22 -18 -13 -84 17 -116 13 -13 42 -32 64 -42 22 -10 74 -53 115 -96 l75 -77 -75 5 c-135 8 -243 76 -336 207 -31 44 -65 87 -77 95 -37 26 -34 -9 7 -88 20 -39 34 -72 31 -75 -2 -2 -26 11 -52 31 -90 65 -143 83 -143 49 0 -32 71 -88 150 -117 41 -15 113 -47 159 -71 46 -24 99 -46 118 -50 18 -3 33 -12 33 -18 0 -12 -111 -46 -149 -46 -12 0 -29 -8 -39 -17 -10 -10 -27 -19 -37 -19 -11 -1 -45 -9 -75 -17 -58 -16 -110 -62 -110 -97 0 -39 116 -45 167 -9 11 8 34 31 52 51 28 32 50 43 144 74 145 47 222 48 404 5 70 -17 177 -38 237 -47 128 -19 202 -43 250 -79 18 -14 73 -42 122 -61 164 -66 208 -112 243 -251 36 -141 27 -167 -44 -123 -19 12 -63 23 -111 28 -117 13 -134 25 -275 193 -63 74 -193 151 -266 157 -29 2 -66 -1 -81 -7 -24 -10 -37 -9 -80 8 -66 26 -70 9 -11 -44 72 -65 119 -80 239 -78 60 1 109 -2 117 -8 6 -6 26 -35 42 -64 17 -30 46 -64 64 -77 19 -13 49 -40 67 -61 l34 -39 -79 3 c-57 3 -80 0 -83 -9 -3 -10 -7 -10 -18 -1 -8 6 -11 15 -8 20 3 5 0 9 -5 9 -16 0 -13 -16 6 -36 36 -36 78 -44 227 -44 119 0 152 -3 188 -19 56 -24 95 -64 125 -126 13 -27 35 -68 48 -90 14 -22 25 -53 25 -69 l0 -29 -107 5 c-131 6 -193 28 -290 100 -37 28 -82 56 -98 63 -75 32 -176 123 -277 247 -34 42 -122 98 -134 85 -5 -5 103 -138 184 -226 52 -57 46 -61 -49 -31 -87 28 -173 85 -325 214 -144 123 -189 151 -254 159 -25 2 -39 3 -32 0 6 -3 12 -16 12 -29 0 -17 -4 -23 -12 -19 -7 4 -1 -5 15 -19 15 -14 46 -30 70 -36 23 -6 60 -17 82 -25 l40 -13 -52 -1 c-49 -1 -53 -3 -53 -25 0 -28 28 -36 122 -36 54 0 62 -3 91 -32 l32 -33 -52 -3 c-88 -5 -75 -26 39 -62 130 -41 178 -63 206 -93 l22 -24 -20 -18 c-12 -11 -41 -20 -74 -23 -48 -4 -60 0 -116 32 -118 69 -241 96 -279 62 -13 -12 -40 -16 -104 -16 -48 0 -95 4 -105 9 -9 5 -34 16 -55 25 -20 9 -76 53 -122 97 -47 45 -88 79 -91 76 -12 -12 6 -54 41 -100 l36 -47 -74 0 c-88 0 -112 15 -78 49 26 26 21 39 -34 84 -87 73 -132 32 -50 -45 25 -23 45 -46 45 -50 0 -4 -21 2 -46 12 -45 20 -114 27 -114 12 0 -4 16 -22 35 -40 39 -38 78 -47 255 -61 164 -14 178 -17 172 -47 -2 -13 -2 -30 2 -39 5 -13 9 -13 40 2 19 9 33 20 30 25 -4 5 4 4 15 -4 21 -13 20 -15 -44 -74 -36 -33 -65 -66 -65 -72 0 -21 68 15 142 74 38 30 84 62 103 70 73 30 203 11 312 -46 32 -17 82 -33 111 -37 l53 -6 -28 -30 c-15 -16 -44 -40 -63 -52 -63 -42 -100 -82 -100 -111 0 -25 2 -26 37 -21 28 5 47 17 73 49 65 78 175 183 224 216 34 22 61 32 88 32 43 0 122 -36 152 -69 10 -11 39 -32 62 -46 43 -25 53 -46 36 -72 -11 -17 -200 -86 -232 -85 -28 1 -122 -47 -127 -65 -3 -8 14 -13 54 -15 l58 -3 -65 -44 c-36 -25 -68 -49 -71 -53 -11 -17 -115 -10 -188 12 -105 32 -112 11 -14 -39 l56 -28 -40 -6 c-52 -9 -96 0 -154 29 -31 15 -50 19 -60 13 -15 -10 -16 -10 44 -47 20 -13 37 -27 37 -31 0 -15 -144 -71 -205 -81 -33 -5 -85 -10 -116 -10 -32 0 -63 -6 -75 -14 -18 -13 -15 -15 34 -22 l53 -7 -31 -18 c-18 -12 -30 -27 -30 -40 0 -21 4 -21 61 -16 50 4 75 14 145 57 46 28 112 63 146 77 62 24 191 62 215 63 22 0 -47 -103 -107 -161 -42 -41 -60 -66 -65 -92 -10 -49 0 -60 47 -54 65 9 99 53 124 160 20 83 49 133 94 163 22 15 40 30 40 34 0 4 8 10 18 13 9 3 31 15 49 27 31 21 31 21 26 0 -3 -11 -21 -37 -40 -58 -43 -45 -72 -106 -73 -150 0 -39 18 -49 56 -30 38 18 63 64 75 137 13 82 40 142 89 194 22 24 40 49 40 54 0 6 24 21 53 34 49 22 63 23 237 20 193 -2 278 -14 348 -50 21 -11 44 -27 52 -36 7 -9 32 -27 55 -41 49 -28 138 -147 184 -243 16 -35 42 -114 57 -175 35 -147 31 -268 -14 -436 -17 -63 -37 -166 -45 -227 -12 -94 -21 -127 -54 -195 -22 -46 -52 -94 -67 -108 -15 -14 -46 -44 -68 -67 -23 -24 -47 -43 -53 -43 -7 0 -25 -12 -41 -26 -129 -121 -526 -267 -721 -268 -104 0 -109 -15 -19 -57 75 -35 67 -35 221 -10 125 21 235 27 235 13 0 -16 -66 -72 -85 -72 -24 0 -85 -36 -85 -49 0 -14 12 -19 58 -27 35 -5 42 -4 42 10 0 9 5 17 10 17 28 4 74 20 80 29 9 14 226 119 288 139 63 21 215 43 239 34 32 -12 12 -50 -52 -102 -36 -28 -73 -55 -83 -58 -17 -7 -66 -39 -92 -60 -8 -7 -38 -32 -67 -57 l-52 -45 42 -6 c36 -6 54 -1 122 33 44 22 120 56 169 76 112 45 222 107 289 164 46 40 84 62 107 62 18 0 130 -83 130 -96 0 -8 4 -14 10 -14 5 0 39 -26 75 -59 36 -32 96 -76 132 -97 36 -21 68 -46 71 -56 5 -19 21 -22 59 -12 18 5 20 9 10 19 -7 7 -69 71 -139 143 -147 149 -161 179 -80 168 136 -19 195 -39 378 -128 78 -37 147 -68 152 -68 6 0 15 -7 20 -16 8 -14 14 -15 46 -4 l38 12 -104 57 c-125 69 -148 84 -148 93 0 16 94 7 223 -22 74 -17 146 -30 160 -30 14 0 29 -4 32 -10 7 -11 54 6 115 43 l40 24 -38 1 c-22 1 -68 11 -103 21 -35 11 -107 30 -159 41 -131 31 -295 99 -406 171 -235 153 -355 366 -357 634 -1 211 65 343 285 568 117 119 206 167 368 198 153 29 267 59 328 86 80 35 166 44 264 27 148 -26 167 -38 251 -169 71 -110 136 -165 196 -165 26 0 31 4 31 23 -1 32 -28 62 -87 91 -39 20 -66 45 -118 112 -95 123 -95 135 -5 92 25 -12 77 -31 116 -43 56 -17 76 -19 97 -10 27 11 26 11 -25 29 -113 39 -138 49 -138 57 0 14 91 55 153 68 33 7 75 10 95 7 27 -4 31 -3 17 4 -19 8 -19 9 3 9 12 1 22 7 22 15 0 10 7 12 22 8 12 -3 17 -7 10 -10 -6 -2 -12 -10 -12 -18 0 -8 -6 -14 -12 -15 -27 -2 39 -17 80 -18 29 -1 42 3 42 13 0 20 -19 32 -67 45 -49 13 -53 22 -20 44 49 32 128 39 235 21 56 -9 112 -14 126 -10 26 6 96 69 96 86 0 6 -32 10 -77 10 -84 0 -126 -7 -118 -20 9 -14 -17 -24 -67 -24 -34 -1 -48 3 -48 13 0 8 -7 11 -20 8 -17 -4 -18 -2 -9 14 5 11 14 17 20 14 5 -4 9 0 9 8 0 8 16 35 35 60 35 45 35 46 14 57 -18 10 -23 8 -37 -12 -67 -95 -162 -167 -297 -225 -55 -23 -99 -47 -98 -53 2 -5 -6 -10 -18 -10 -27 0 -23 8 31 71 100 117 116 131 161 155 80 40 80 70 1 41 l-47 -18 36 38 c47 49 59 73 59 120 0 67 -24 80 -82 46 -49 -29 -76 -85 -89 -183 -10 -81 -9 -80 -89 -174 -20 -22 -43 -53 -53 -68 -28 -45 -89 -61 -217 -56 -70 2 -114 8 -118 15 -4 6 -28 13 -54 15 l-46 3 53 71 c51 68 100 104 140 104 50 0 125 73 125 122 0 30 0 31 -45 26 -28 -4 -59 -16 -82 -34 -30 -23 -35 -24 -28 -8 22 51 37 105 31 111 -13 13 -47 -34 -105 -146 -72 -138 -171 -248 -261 -292 -62 -30 -164 -44 -242 -34 -48 7 -50 8 -45 34 14 70 51 144 95 190 42 43 56 51 127 69 44 12 98 24 120 27 99 15 155 57 155 117 l0 31 -51 -5 c-40 -4 -58 -12 -87 -40 -56 -52 -66 -58 -131 -78 l-60 -18 10 27 c6 14 36 62 68 106 70 96 91 136 91 170 0 41 -18 29 -50 -35 -30 -59 -31 -60 -74 -60 -56 0 -71 -18 -101 -115 -23 -75 -43 -114 -72 -145 -8 -8 -41 -61 -73 -117 -35 -59 -75 -113 -95 -128 -37 -29 -177 -85 -210 -85 -35 0 -222 -134 -282 -202 -31 -35 -64 -64 -72 -66 -22 -4 -68 116 -88 223 -20 113 -5 256 37 340 37 76 124 182 195 238 140 110 221 137 416 137 136 0 171 6 186 28 9 15 2 17 -76 18 -47 0 -127 4 -178 9 -167 15 -274 -28 -423 -170 -72 -68 -114 -95 -128 -81 -12 12 17 138 44 194 64 132 229 243 439 298 182 46 319 21 425 -80 68 -65 144 -115 202 -135 119 -41 155 -32 72 17 -88 52 -224 144 -224 152 0 14 51 20 210 22 115 2 160 0 175 -10 19 -12 18 -13 -8 -9 -36 6 -45 -9 -11 -17 56 -15 117 -51 183 -110 66 -59 119 -86 169 -86 54 0 31 59 -35 90 -167 77 -176 82 -158 93 25 13 138 -8 201 -37 27 -13 67 -43 89 -66 50 -53 84 -70 134 -70 37 0 71 19 71 40 0 24 -62 57 -129 70 -40 7 -74 17 -77 22 -3 4 24 8 60 8 36 0 68 -4 71 -10 3 -5 26 -10 51 -10 50 0 57 15 23 46 -24 21 -113 25 -226 10 -50 -7 -65 -6 -77 7 -19 18 -100 37 -160 37 -74 0 -136 12 -136 26 0 17 11 23 53 28 32 4 83 29 97 47 8 10 71 40 99 47 28 7 159 8 309 1 50 -2 92 -1 92 4 0 4 14 7 30 7 23 0 30 -4 30 -20 0 -15 -7 -20 -25 -20 -42 0 -28 -17 30 -39 75 -28 103 -27 117 4 8 18 19 25 38 25 34 0 47 35 23 62 -24 27 -70 31 -190 18 -101 -11 -112 -10 -173 10 -36 12 -104 24 -152 27 -49 3 -88 9 -88 13 0 8 35 26 66 35 12 3 37 21 55 40 19 20 67 58 106 86 57 39 86 52 134 60 71 11 170 58 193 91 34 49 10 51 -66 5 -52 -31 -154 -65 -165 -54 -11 12 9 25 67 47 33 12 60 26 60 30 0 5 15 17 34 28 31 18 67 84 53 98 -15 15 -69 -17 -124 -75 -35 -36 -63 -63 -63 -58 0 4 14 31 30 60 43 77 39 180 -7 151 -39 -24 -56 -62 -63 -141 -7 -87 -27 -127 -98 -200 -50 -52 -120 -103 -139 -103 -8 0 -22 -8 -31 -17 -31 -31 -26 11 12 94 33 74 61 171 53 180 -3 2 -17 1 -32 -3 -38 -10 -65 -74 -75 -185 -9 -97 -31 -147 -79 -176 -31 -20 -81 -71 -81 -83 0 -5 -24 -16 -52 -26 -29 -9 -58 -24 -64 -32 -7 -9 -33 -17 -70 -19 l-59 -4 55 48 c120 105 133 126 66 103 -19 -6 -58 -36 -88 -66 -29 -30 -72 -64 -96 -76 -41 -19 -50 -20 -163 -9 -168 16 -237 52 -196 103 21 27 121 88 143 88 60 0 183 34 234 65 30 18 74 36 97 40 85 14 180 99 131 118 -16 5 -19 13 -14 33 7 25 5 25 -26 19 -52 -11 -83 -31 -122 -76 -54 -63 -94 -86 -197 -109 -52 -12 -102 -24 -111 -26 -28 -8 -22 22 10 44 15 11 35 34 45 51 16 27 16 31 2 31 -8 0 -18 -7 -22 -16 -8 -23 -23 2 -23 40 0 23 -3 27 -12 18 -14 -14 -42 -16 -33 -2 3 6 4 10 1 10 -9 0 -37 -61 -62 -133 -29 -84 -85 -162 -137 -189 -24 -12 -67 -21 -110 -24 -40 -2 -100 -6 -134 -9 l-62 -4 36 72 c20 39 48 84 62 98 29 29 86 122 96 157 9 32 -20 29 -42 -5 -17 -27 -128 -174 -222 -297 -45 -58 -101 -96 -141 -96 -48 0 -9 184 59 284 41 59 113 107 234 156 51 20 141 67 198 102 57 36 118 72 134 80 40 21 155 46 240 53 48 5 82 14 113 32 58 34 150 44 258 28 41 -6 57 -4 75 9 17 12 46 16 111 16 88 0 116 12 57 24 -17 3 -48 6 -69 6 -21 0 -43 6 -49 14 -14 17 -8 22 40 31 30 5 36 10 32 26 -4 13 0 19 12 19 23 0 95 44 129 79 34 35 30 67 -6 55 -13 -4 -31 -7 -41 -6 -11 0 -38 -25 -68 -64 -28 -35 -53 -64 -55 -64 -2 0 7 22 21 50 14 27 25 60 25 74 0 14 5 37 11 53 7 19 7 29 0 31 -6 2 -11 17 -11 33 0 16 -4 29 -10 29 -5 0 -10 -19 -10 -42 0 -50 -37 -158 -74 -222 -28 -48 -90 -86 -141 -86 l-29 0 36 38 c20 20 43 52 52 70 16 31 16 32 -5 32 -25 0 -94 -47 -109 -75 -19 -35 -161 -104 -245 -120 -42 -8 -85 -15 -96 -15 -18 0 -18 1 -2 35 9 19 20 35 25 35 4 0 8 6 8 13 0 7 13 34 30 60 30 48 75 77 182 117 58 21 112 66 176 146 26 31 57 57 84 69 124 52 167 75 177 93 17 33 -14 35 -71 6 -29 -14 -69 -32 -89 -39 l-38 -14 20 51 c11 28 24 59 29 68 10 19 -20 60 -45 60 -18 0 -21 46 -4 52 6 2 14 26 16 53 4 43 2 52 -16 63 -20 11 -21 10 -21 -25 -1 -209 -5 -248 -32 -305 -34 -73 -116 -188 -133 -188 -8 0 -20 -6 -27 -13 -7 -7 -29 -18 -48 -24 -19 -6 -52 -18 -72 -27 -34 -15 -38 -15 -38 -1 0 35 32 73 89 109 60 37 77 51 45 39 -14 -5 -14 -3 -3 14 7 13 9 28 4 39 -5 11 -7 24 -6 29 1 6 -19 -11 -44 -37 -25 -26 -45 -44 -45 -40 0 4 18 34 40 67 30 45 40 69 40 100 0 53 -11 67 -46 63 -22 -2 -34 -13 -53 -47 -14 -25 -26 -40 -29 -33 -2 7 -10 12 -17 12 -10 0 -14 -33 -17 -142 l-4 -143 -63 -127 c-39 -81 -74 -137 -94 -154 -51 -43 -167 -87 -167 -63 0 6 26 38 58 72 32 34 66 73 75 87 18 26 23 100 8 100 -5 0 -22 -19 -38 -42 -15 -23 -52 -60 -81 -82 -31 -25 -61 -59 -74 -85 -37 -75 -125 -156 -220 -201 -46 -22 -101 -43 -121 -47 -32 -5 -37 -3 -37 13 0 36 50 229 70 269 10 23 38 95 61 160 39 116 84 211 117 248 12 13 13 20 4 29 -9 9 -21 5 -49 -18 -58 -46 -166 -272 -249 -519 -37 -110 -73 -207 -80 -216 -8 -8 -14 -21 -14 -28 0 -8 -19 -54 -41 -105 -23 -50 -61 -146 -84 -212 -49 -144 -77 -193 -152 -274 -71 -77 -89 -77 -115 2 -11 33 -27 59 -36 62 -19 6 -21 27 -23 201 -2 197 49 394 151 580 33 61 72 135 86 165 118 253 140 288 273 462 87 112 121 167 121 195 0 37 -25 27 -75 -29 -42 -48 -45 -50 -38 -23 13 50 9 145 -8 156 -19 12 -30 7 -50 -22 -23 -33 -15 -116 12 -124 28 -9 35 -49 12 -73 -10 -11 -36 -45 -58 -76 -22 -31 -44 -56 -48 -56 -12 0 -3 78 17 160 8 36 15 84 16 107 0 23 4 44 9 47 4 3 11 37 14 75 3 39 14 86 26 109 26 50 80 97 94 83 16 -16 59 -13 85 5 30 21 52 66 52 109 0 33 -2 35 -32 35 -59 0 -78 -12 -118 -69 -21 -31 -55 -74 -74 -96 l-35 -40 -1 41 c0 23 7 60 15 83 15 43 92 151 124 173 20 14 55 77 48 85 -3 2 -8 -5 -12 -16 -7 -24 -35 -17 -35 9 0 23 -13 32 -35 24 -9 -4 -12 -9 -7 -13 17 -10 2 -62 -16 -59 -11 2 -30 -24 -61 -87 -34 -68 -46 -84 -49 -67 -2 12 -8 22 -13 22 -5 0 -9 -10 -9 -22 -1 -23 -1 -23 -16 -3 -9 11 -24 37 -34 58 -11 24 -20 34 -23 25 -3 -7 -6 25 -6 72 -1 105 -21 98 -26 -10 -3 -43 -9 -76 -16 -81 -10 -6 -10 -11 0 -23 14 -16 3 -22 -15 -8 -5 4 2 -2 15 -13 51 -41 78 -76 96 -128 26 -70 25 -187 -3 -292 -13 -49 -21 -109 -20 -155 0 -104 -54 -310 -81 -310 -6 0 -11 3 -11 8 -1 44 -24 191 -41 259 l-22 85 27 108 c30 123 34 211 10 231 -20 16 -40 5 -72 -42 -21 -30 -23 -42 -18 -97 3 -36 1 -60 -4 -57 -17 11 -34 81 -34 150 -1 64 2 76 39 140 22 39 45 84 52 100 17 43 16 92 -2 98 -17 7 -17 8 -44 -73 -12 -36 -34 -87 -50 -113 -33 -56 -41 -48 -41 39 0 41 -4 54 -15 54 -11 0 -15 -18 -17 -80 -2 -45 -7 -80 -13 -80 -5 0 -10 4 -10 8 0 5 -8 16 -18 26 -58 58 -70 132 -53 314 7 69 6 92 -3 92 -6 0 -13 -6 -16 -12z m321 -503 c3 -20 4 -39 0 -42 -3 -4 -6 6 -6 20 0 17 -5 27 -15 27 -16 0 -20 12 -8 23 14 14 22 6 29 -28z m-1006 -80 c0 -8 -9 -15 -19 -15 -29 0 -35 18 -9 23 13 2 24 5 26 6 1 0 2 -6 2 -14z m327 -27 c-3 -7 -5 -2 -5 12 0 14 2 19 5 13 2 -7 2 -19 0 -25z m-462 -358 c3 -5 1 -10 -4 -10 -6 0 -11 5 -11 10 0 6 2 10 4 10 3 0 8 -4 11 -10z m-835 -40 c-6 -11 -15 -20 -19 -20 -5 0 -7 9 -4 20 3 11 12 20 20 20 11 0 11 -4 3 -20z m864 -25 c3 -9 0 -15 -9 -15 -9 0 -15 -10 -16 -27 0 -27 -1 -27 -13 7 -10 25 -10 37 -2 42 18 12 33 9 40 -7z m-892 -863 c38 2 68 0 68 -4 0 -5 -33 -8 -73 -8 -49 0 -80 -5 -95 -16 -21 -14 -22 -14 -22 5 0 14 -6 21 -20 21 -11 0 -20 2 -20 4 0 2 -3 12 -6 21 -6 13 1 13 47 -5 40 -16 70 -21 121 -18z m3218 -91 c0 -10 -7 -21 -15 -25 -11 -4 -15 1 -15 19 0 16 6 25 15 25 8 0 15 -9 15 -19z m-3479 -32 c-14 -5 -30 -14 -37 -20 -8 -7 -13 -3 -17 11 -5 18 0 20 36 19 38 0 40 -1 18 -10z m3359 -572 c0 -7 -7 -22 -15 -33 -13 -17 -14 -16 -4 14 11 33 19 41 19 19z m-3345 -198 c7 -22 -7 -39 -33 -39 -10 0 -10 4 0 20 11 17 10 22 -2 30 -12 8 -11 10 7 10 13 0 24 -8 28 -21z m445 -37 c0 -23 -35 -8 -38 16 -3 21 -2 22 17 10 12 -7 21 -19 21 -26z m-310 -647 c-28 -30 -60 -33 -60 -7 0 26 9 32 48 32 l35 0 -23 -25z M3684 5414 c-14 -21 -16 -41 -10 -124 4 -62 2 -100 -3 -100 -9 0 -17 26 -25 84 -1 11 -8 22 -14 24 -9 3 -12 -27 -12 -105 0 -69 -6 -130 -16 -164 -24 -86 -24 -85 -33 -70 -6 9 -10 3 -14 -17 -4 -20 -23 -43 -59 -72 -29 -23 -54 -46 -54 -51 -1 -5 -3 -39 -4 -76 -1 -46 -4 -60 -9 -43 -6 21 -9 15 -20 -35 -16 -74 -29 -99 -97 -197 -35 -49 -54 -86 -54 -105 0 -31 59 -200 60 -171 0 9 6 21 14 25 13 7 13 16 0 68 -17 72 -12 78 75 93 106 19 127 33 145 95 20 70 65 111 186 172 83 42 89 47 75 62 -9 8 -14 23 -11 32 5 14 5 14 -6 1 -7 -8 -41 -25 -75 -37 -54 -19 -61 -19 -56 -5 10 26 43 72 91 126 46 53 77 104 68 114 -6 6 -95 -81 -143 -141 l-30 -38 -7 80 c-4 45 -5 89 -1 98 3 10 31 34 63 53 61 37 147 112 164 144 21 38 -53 8 -126 -52 -98 -80 -100 -81 -92 -46 12 47 54 133 81 166 14 16 25 42 25 56 l-1 27 -25 -30 -26 -30 6 53 c3 28 9 74 12 100 5 40 3 50 -10 55 -10 4 -22 -2 -32 -19z m-79 -654 c0 -125 0 -126 -33 -176 -22 -36 -56 -67 -109 -103 -42 -28 -82 -51 -90 -51 -20 0 -16 22 11 59 13 18 30 46 36 62 7 16 16 29 20 29 5 0 13 33 20 73 16 102 29 149 40 142 6 -4 10 -2 10 3 0 5 13 25 30 43 16 19 30 38 30 42 0 5 8 7 18 5 15 -3 17 -17 17 -128z M2287 5348 c-10 -10 -22 -16 -27 -13 -5 3 -8 -3 -8 -12 1 -10 -2 -37 -6 -59 -6 -32 -4 -43 7 -47 23 -9 67 61 67 105 0 44 -9 51 -33 26z M1853 5256 c4 -22 11 -42 17 -46 7 -4 14 -26 17 -49 3 -22 10 -41 15 -41 5 0 7 12 4 28 -3 15 -8 46 -11 69 -4 23 -16 49 -27 60 -21 18 -21 18 -15 -21z M1780 5267 c0 -47 15 -79 42 -93 l30 -16 -7 34 c-4 18 -12 44 -19 58 -12 28 -46 40 -46 17z M1960 5120 c0 -21 30 -70 49 -80 27 -14 31 -13 31 10 0 11 5 20 10 20 6 0 8 -11 4 -25 -6 -23 -4 -25 30 -25 20 0 36 4 36 8 0 18 -68 72 -109 87 -52 18 -51 18 -51 5z M4127 5076 c-4 -10 -7 -45 -7 -79 0 -42 -6 -70 -18 -88 -56 -85 -73 -107 -106 -138 -20 -19 -36 -39 -36 -43 0 -18 34 -6 62 23 29 28 34 30 84 24 41 -6 59 -3 83 11 37 22 44 37 28 59 -16 21 -72 22 -95 2 -21 -19 -32 -22 -32 -7 0 5 38 35 84 66 77 51 106 84 106 119 0 26 -43 16 -77 -17 l-33 -32 0 47 c0 34 -4 47 -14 47 -8 0 -16 5 -18 12 -3 7 -7 5 -11 -6z M1049 5043 c-8 -10 -9 -14 -2 -10 7 5 28 -18 57 -63 48 -74 62 -86 52 -45 -4 15 -2 25 4 25 15 0 -17 72 -41 93 -27 22 -53 22 -70 0z M3400 4964 c-14 -37 -12 -60 6 -75 14 -11 18 -10 30 6 19 26 18 81 -2 89 -23 9 -24 8 -34 -20z M3910 4933 c-29 -20 -40 -33 -40 -50 0 -33 63 6 75 45 8 26 -2 28 -35 5z M3401 4844 c0 -11 3 -14 6 -6 3 7 2 16 -1 19 -3 4 -6 -2 -5 -13z M4532 4829 c-8 -12 -9 -18 -3 -14 7 4 11 -8 12 -32 1 -21 4 -51 8 -68 6 -26 8 -22 13 29 5 39 3 67 -5 83 l-12 23 -13 -21z M1017 4820 c-8 -30 16 -52 65 -60 41 -6 45 -5 40 12 -5 20 -68 68 -88 68 -6 0 -14 -9 -17 -20z M2529 4778 c-11 -21 -7 -134 7 -185 8 -30 24 -19 24 17 0 16 7 35 15 44 18 17 20 70 4 115 -13 36 -33 40 -50 9z M830 4767 c0 -24 30 -116 40 -122 11 -7 1 92 -12 118 -10 20 -28 23 -28 4z M4660 4751 c0 -5 -9 -12 -19 -16 -23 -7 -101 -81 -101 -95 0 -26 50 -6 98 38 51 47 67 82 37 82 -8 0 -15 -4 -15 -9z M764 4719 c-7 -13 82 -106 92 -96 11 11 -9 43 -46 75 -27 23 -41 29 -46 21z M1887 4634 c-18 -18 -6 -91 21 -131 79 -118 125 -171 138 -159 10 9 8 18 -9 46 -12 19 -25 37 -29 38 -4 2 -8 25 -8 50 0 60 -15 115 -38 135 -20 19 -65 31 -75 21z M1030 4579 c0 -35 54 -169 68 -169 6 0 12 -8 12 -17 1 -17 2 -17 15 0 11 16 11 26 -5 71 -25 75 -47 114 -70 126 -17 9 -20 8 -20 -11z M697 4553 c19 -54 69 -92 112 -85 36 5 46 34 20 58 -11 9 -22 14 -25 11 -4 -4 -18 3 -32 13 -32 26 -84 28 -75 3z M1150 4486 c0 -36 52 -76 101 -76 47 0 57 29 12 32 -16 1 6 4 47 8 l75 6 -75 2 c-41 1 -85 8 -96 15 -12 6 -31 18 -43 25 -19 12 -21 11 -21 -12z M3909 4427 c-16 -27 -19 -51 -19 -149 0 -111 1 -118 20 -118 15 0 24 14 40 68 39 124 39 215 -1 225 -15 4 -25 -2 -40 -26z M4723 4375 c-30 -13 -33 -18 -33 -60 l0 -45 24 15 c27 18 49 48 60 83 9 26 -4 28 -51 7z M5002 4348 c-5 -7 -23 -40 -40 -73 -32 -65 -106 -146 -156 -172 -17 -9 -51 -21 -75 -28 -46 -11 -63 -28 -38 -38 7 -3 47 2 87 10 58 12 85 13 128 4 96 -19 162 -13 162 15 0 11 -19 14 -82 15 -46 0 -91 4 -101 8 -17 6 -17 8 2 25 11 10 44 25 73 32 34 8 43 13 27 13 -31 1 -44 24 -23 41 8 7 14 21 14 31 0 11 10 36 23 57 33 52 39 72 23 72 -7 0 -18 -6 -24 -12z M3632 4290 c-52 -37 -68 -69 -74 -145 -3 -33 -3 -54 0 -47 3 10 7 9 16 -4 12 -15 18 -14 79 15 69 33 101 66 95 98 -4 22 -37 30 -49 11 -6 -8 -7 10 -3 45 8 68 -2 72 -64 27z M5016 4271 c-11 -12 -16 -24 -12 -28 9 -9 39 22 34 37 -2 7 -10 4 -22 -9z M470 4264 c0 -9 8 -28 18 -42 10 -15 22 -33 27 -40 8 -15 -67 31 -102 62 -13 11 -23 14 -23 8 0 -7 -7 -12 -15 -12 -19 0 -19 -15 2 -50 20 -35 48 -48 118 -56 37 -5 55 -11 55 -20 0 -8 11 -14 25 -14 14 0 25 4 25 10 0 5 -22 43 -50 84 -49 73 -80 100 -80 70z M2382 4102 c-5 -9 -12 -42 -14 -72 -9 -96 18 -125 39 -43 17 66 17 120 -2 127 -8 3 -19 -2 -23 -12z M4235 3850 c36 -39 118 -80 162 -80 30 0 93 41 93 61 0 5 -14 15 -30 24 -25 13 -44 14 -107 6 -43 -5 -80 -6 -83 -1 -3 5 -19 12 -35 16 l-30 7 30 -33z M133 3667 c-19 -41 -15 -59 18 -86 30 -24 135 -55 151 -45 11 7 10 42 -2 49 -5 3 -10 11 -10 17 0 6 7 5 17 -3 12 -10 15 -10 9 -1 -13 22 -84 52 -125 52 -33 0 -40 4 -43 22 -3 21 -4 21 -15 -5z M5265 3631 c-16 -10 -43 -33 -60 -51 l-30 -32 83 4 c77 3 86 6 107 30 35 41 24 68 -29 68 -23 0 -54 -8 -71 -19z M400 3512 c0 -5 -53 -12 -117 -16 -64 -4 -120 -9 -125 -12 -16 -10 -8 -53 13 -65 51 -27 183 0 213 43 13 17 19 18 68 9 29 -5 66 -13 81 -16 22 -6 26 -4 21 9 -5 12 0 16 17 17 13 1 -3 7 -36 14 -106 22 -135 26 -135 17z M5090 3480 c0 -5 9 -10 20 -10 11 0 47 -13 80 -30 57 -29 121 -39 147 -22 22 14 19 45 -7 59 -30 15 -240 18 -240 3z M926 3272 c-12 -11 -6 -94 9 -122 16 -31 39 -47 86 -60 24 -7 29 -5 39 21 19 44 5 94 -34 124 -35 27 -90 47 -100 37z M500 3049 c0 -23 9 -62 20 -85 17 -33 30 -46 70 -62 34 -14 56 -32 70 -54 16 -28 109 -108 125 -108 3 0 5 7 5 15 0 12 7 14 28 9 15 -3 -8 11 -50 32 -42 20 -80 44 -83 53 -4 9 -9 46 -12 84 -5 61 -9 70 -41 98 -34 30 -59 43 -107 55 -24 6 -25 4 -25 -37z M5203 2779 c-18 -11 -35 -29 -38 -40 -7 -22 -20 -25 -32 -6 -8 13 -20 -26 -22 -74 -1 -30 25 -36 35 -7 4 15 9 17 20 7 8 -6 14 -18 14 -26 0 -11 7 -9 27 7 43 33 63 71 63 118 0 49 -14 53 -67 21z M5307 2622 c-34 -32 -86 -72 -115 -88 -51 -29 -61 -46 -29 -52 25 -5 198 81 229 114 15 16 30 41 33 57 7 25 5 27 -24 27 -25 0 -45 -13 -94 -58z M447 2652 c-10 -10 -15 -21 -12 -24 7 -7 75 24 75 34 0 15 -47 8 -63 -10z M263 2600 c-12 -5 -26 -18 -32 -28 -8 -15 -6 -24 13 -41 33 -31 84 -27 160 13 68 36 68 47 1 51 -16 1 -50 5 -75 8 -25 4 -55 3 -67 -3z M996 2540 c-37 -11 -102 -74 -115 -112 l-10 -28 58 0 c48 0 65 5 98 29 49 35 87 86 79 106 -6 17 -62 19 -110 5z M673 2324 c-43 -18 -42 -43 1 -88 33 -35 35 -36 114 -36 70 0 80 2 78 18 0 10 6 16 16 16 13 -1 9 8 -18 40 -19 22 -45 46 -57 53 -29 16 -94 15 -134 -3z M4790 2120 c-9 -17 -5 -20 43 -29 72 -15 166 -19 169 -9 2 5 11 6 21 3 20 -8 23 -35 5 -35 -7 -1 -2 -7 12 -15 29 -17 113 -20 141 -5 24 13 25 36 2 48 -10 5 -58 12 -108 15 -49 3 -117 12 -150 20 -110 28 -124 28 -135 7z M4881 2021 c6 -17 30 -50 53 -75 33 -36 49 -46 74 -46 25 0 32 4 32 19 0 25 -60 77 -99 86 -17 4 -36 15 -41 26 -17 30 -30 23 -19 -10z";
|
|
1079
1075
|
|
|
1080
1076
|
// src/genre-tree/TreeMarkIcon.tsx
|
|
1081
|
-
import { jsx as
|
|
1077
|
+
import { jsx as jsx17 } from "react/jsx-runtime";
|
|
1082
1078
|
function TreeMarkIcon({ className: className2 }) {
|
|
1083
|
-
return /* @__PURE__ */
|
|
1079
|
+
return /* @__PURE__ */ jsx17("svg", { viewBox: "0 0 551 567", fill: "currentColor", className: className2, "aria-hidden": true, children: /* @__PURE__ */ jsx17("path", { transform: "translate(0 567) scale(0.1 -0.1)", d: TREE_MARK_PATH }) });
|
|
1084
1080
|
}
|
|
1085
1081
|
|
|
1086
1082
|
// src/genre-tree/GenrePlayActions.tsx
|
|
1087
|
-
import { Fragment as Fragment6, jsx as
|
|
1083
|
+
import { Fragment as Fragment6, jsx as jsx18, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
1088
1084
|
function PlayIcon({ kind }) {
|
|
1089
1085
|
return /* @__PURE__ */ jsxs10("span", { "aria-hidden": "true", className: "relative flex items-center justify-center w-5 h-5", children: [
|
|
1090
|
-
kind === "tree" && /* @__PURE__ */
|
|
1091
|
-
kind === "map" && /* @__PURE__ */
|
|
1086
|
+
kind === "tree" && /* @__PURE__ */ jsx18(TreeMarkIcon, { className: "absolute -left-1.5 -top-1.5 w-8 h-8 opacity-35" }),
|
|
1087
|
+
kind === "map" && /* @__PURE__ */ jsx18(RegionGlobeIcon, { className: "absolute -left-1.5 -top-1.5 w-8 h-8 opacity-35" }),
|
|
1092
1088
|
kind === "tree-map" && /* @__PURE__ */ jsxs10(Fragment6, { children: [
|
|
1093
|
-
/* @__PURE__ */
|
|
1094
|
-
/* @__PURE__ */
|
|
1089
|
+
/* @__PURE__ */ jsx18(TreeMarkIcon, { className: "absolute -left-1.5 -top-1.5 w-8 h-8 opacity-35 [clip-path:inset(0_50%_0_0)]" }),
|
|
1090
|
+
/* @__PURE__ */ jsx18(RegionGlobeIcon, { className: "absolute -left-1.5 -top-1.5 w-8 h-8 opacity-35 [clip-path:inset(0_0_0_50%)]" })
|
|
1095
1091
|
] }),
|
|
1096
|
-
/* @__PURE__ */
|
|
1092
|
+
/* @__PURE__ */ jsx18(Play, { className: "relative w-5 h-5 fill-[var(--color-surface)]" })
|
|
1097
1093
|
] });
|
|
1098
1094
|
}
|
|
1099
1095
|
function playOptions(playlist) {
|
|
@@ -1109,13 +1105,13 @@ function playOptions(playlist) {
|
|
|
1109
1105
|
function GenrePlayActions({ genrePlaylist, playback }) {
|
|
1110
1106
|
const { isPlaying, setIsPlaying } = usePlayer4();
|
|
1111
1107
|
const options = playOptions(genrePlaylist);
|
|
1112
|
-
return /* @__PURE__ */
|
|
1108
|
+
return /* @__PURE__ */ jsx18(Fragment6, { children: options.map((option) => {
|
|
1113
1109
|
const isCurrent = playback.playing?.uuid === genrePlaylist.uuid && (option.selection === void 0 || playback.playing.selectionKey === "" || playback.playing.selectionKey === genreMusicSelectionKey2(option.selection).join());
|
|
1114
1110
|
const playing = isCurrent && isPlaying;
|
|
1115
|
-
return /* @__PURE__ */
|
|
1111
|
+
return /* @__PURE__ */ jsx18(
|
|
1116
1112
|
ActionButton3,
|
|
1117
1113
|
{
|
|
1118
|
-
icon: playing ? /* @__PURE__ */
|
|
1114
|
+
icon: playing ? /* @__PURE__ */ jsx18(Pause, { "aria-hidden": "true", className: "w-5 h-5" }) : /* @__PURE__ */ jsx18(PlayIcon, { kind: option.icon }),
|
|
1119
1115
|
label: playing ? "Pause" : option.label,
|
|
1120
1116
|
caption: String(option.count),
|
|
1121
1117
|
disabled: option.count === 0,
|
|
@@ -1125,9 +1121,7 @@ function GenrePlayActions({ genrePlaylist, playback }) {
|
|
|
1125
1121
|
setIsPlaying(!isPlaying);
|
|
1126
1122
|
return;
|
|
1127
1123
|
}
|
|
1128
|
-
playback.play(genrePlaylist, option.selection)
|
|
1129
|
-
console.error("Failed to load genre playlist tracks:", error);
|
|
1130
|
-
});
|
|
1124
|
+
void playback.play(genrePlaylist, option.selection);
|
|
1131
1125
|
}
|
|
1132
1126
|
},
|
|
1133
1127
|
option.key
|
|
@@ -1141,7 +1135,7 @@ import { useFetchGenreOverview } from "@behindthemusictree/app-kit/genre-tree";
|
|
|
1141
1135
|
|
|
1142
1136
|
// src/genre-tree/ClampedText.tsx
|
|
1143
1137
|
import { useLayoutEffect, useRef as useRef2, useState as useState6 } from "react";
|
|
1144
|
-
import { Fragment as Fragment7, jsx as
|
|
1138
|
+
import { Fragment as Fragment7, jsx as jsx19, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
1145
1139
|
function ClampedText({ children, className: className2 = "" }) {
|
|
1146
1140
|
const ref = useRef2(null);
|
|
1147
1141
|
const [expanded, setExpanded] = useState6(false);
|
|
@@ -1152,8 +1146,8 @@ function ClampedText({ children, className: className2 = "" }) {
|
|
|
1152
1146
|
setOverflows(element.scrollHeight > element.clientHeight);
|
|
1153
1147
|
}, [children, expanded]);
|
|
1154
1148
|
return /* @__PURE__ */ jsxs11(Fragment7, { children: [
|
|
1155
|
-
/* @__PURE__ */
|
|
1156
|
-
(overflows || expanded) && /* @__PURE__ */
|
|
1149
|
+
/* @__PURE__ */ jsx19("p", { ref, className: `${className2} ${expanded ? "" : "line-clamp-3"}`, children }),
|
|
1150
|
+
(overflows || expanded) && /* @__PURE__ */ jsx19(
|
|
1157
1151
|
"button",
|
|
1158
1152
|
{
|
|
1159
1153
|
type: "button",
|
|
@@ -1178,25 +1172,25 @@ import { PaginatedResponseSchema } from "@behindthemusictree/app-kit/transport";
|
|
|
1178
1172
|
import { parseWithLog } from "@behindthemusictree/app-kit/transport";
|
|
1179
1173
|
import { usePlayer as usePlayer5 } from "@behindthemusictree/app-kit/player";
|
|
1180
1174
|
import { PlayStates } from "@behindthemusictree/app-kit/player";
|
|
1181
|
-
import { usePopup as
|
|
1182
|
-
import { ErrorCode as
|
|
1175
|
+
import { usePopup as usePopup3 } from "@behindthemusictree/app-kit/popup";
|
|
1176
|
+
import { AppError as AppError2, ErrorCode as ErrorCode2 } from "@behindthemusictree/app-kit/transport";
|
|
1183
1177
|
import { genreMusicQueryParams } from "@behindthemusictree/app-kit/genre-tree";
|
|
1184
1178
|
import { genrePlaylistQueryKeys } from "@behindthemusictree/app-kit/genre-tree";
|
|
1185
1179
|
import { libraryEndpoints, libraryQueryKeys } from "@behindthemusictree/app-kit/genre-tree";
|
|
1186
1180
|
import { isSong, songUnplayableReason, SongDetailedSchema } from "@behindthemusictree/app-kit/genre-tree";
|
|
1187
|
-
import { useTrackList as useTrackList2 } from "@behindthemusictree/app-kit/genre-tree";
|
|
1181
|
+
import { TracksFailureAlreadyReportedError as TracksFailureAlreadyReportedError2, useTrackList as useTrackList2 } from "@behindthemusictree/app-kit/genre-tree";
|
|
1188
1182
|
|
|
1189
1183
|
// src/genre-tree/MusicBrainzRecordingLink.tsx
|
|
1190
1184
|
import { musicBrainzRecordingUrl } from "@behindthemusictree/app-kit/genre-tree";
|
|
1191
|
-
import { Fragment as Fragment8, jsx as
|
|
1185
|
+
import { Fragment as Fragment8, jsx as jsx20 } from "react/jsx-runtime";
|
|
1192
1186
|
function MusicBrainzRecordingLink({
|
|
1193
1187
|
song,
|
|
1194
1188
|
children,
|
|
1195
1189
|
className: className2 = ""
|
|
1196
1190
|
}) {
|
|
1197
1191
|
const url = musicBrainzRecordingUrl(song);
|
|
1198
|
-
if (!url) return /* @__PURE__ */
|
|
1199
|
-
return /* @__PURE__ */
|
|
1192
|
+
if (!url) return /* @__PURE__ */ jsx20(Fragment8, { children });
|
|
1193
|
+
return /* @__PURE__ */ jsx20(
|
|
1200
1194
|
"a",
|
|
1201
1195
|
{
|
|
1202
1196
|
href: url,
|
|
@@ -1213,7 +1207,7 @@ function MusicBrainzRecordingLink({
|
|
|
1213
1207
|
// src/genre-tree/GenrePlaylistTracks.tsx
|
|
1214
1208
|
import { ArtistNames } from "@behindthemusictree/app-kit/genre-tree";
|
|
1215
1209
|
import { capitalize, useTrackNoun } from "@behindthemusictree/app-kit/track-noun";
|
|
1216
|
-
import { jsx as
|
|
1210
|
+
import { jsx as jsx21, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
1217
1211
|
var CATALOGUE_PAGE_SIZE = 100;
|
|
1218
1212
|
var SongPageSchema = PaginatedResponseSchema(SongDetailedSchema).extend({
|
|
1219
1213
|
overallTotal: z.number().nullable(),
|
|
@@ -1247,7 +1241,7 @@ function GenrePlaylistTracks({
|
|
|
1247
1241
|
const { fetchGenrePlaylistTracksPage, playNewTrackListFromGenrePlaylist, playNewTrackListFromArtist, playNewTrackListFromGenreCatalogue } = useTrackList2();
|
|
1248
1242
|
const { session, sessionRestored } = useSession();
|
|
1249
1243
|
const { playerTrackObject, playState, handlePlayPauseAction } = usePlayer5();
|
|
1250
|
-
const { showPopup } =
|
|
1244
|
+
const { showPopup } = usePopup3();
|
|
1251
1245
|
const trackNoun = useTrackNoun();
|
|
1252
1246
|
const uuid = genrePlaylist?.uuid;
|
|
1253
1247
|
const genreName = selectedGenreName ?? genrePlaylist?.name ?? "Genre";
|
|
@@ -1299,27 +1293,28 @@ function GenrePlaylistTracks({
|
|
|
1299
1293
|
}) : scope === "reference" ? playNewTrackListFromGenreCatalogue({ uuid: genreUuid, name: genreName }, scope, { startSongUuid, ...selection && { selection } }) : genrePlaylist ? playNewTrackListFromGenrePlaylist(genrePlaylist, scope, { startSongUuid }) : Promise.reject(new Error("Personal genre has no playlist"));
|
|
1300
1294
|
started.catch((error) => {
|
|
1301
1295
|
console.error("Failed to play genre playlist:", error);
|
|
1302
|
-
|
|
1296
|
+
if (error instanceof TracksFailureAlreadyReportedError2) return;
|
|
1297
|
+
showPopup(/* @__PURE__ */ jsx21(InternalErrorPopup, { errorCode: error instanceof AppError2 ? error.code : ErrorCode2.CLIENT_UNKNOWN }));
|
|
1303
1298
|
});
|
|
1304
1299
|
};
|
|
1305
|
-
return /* @__PURE__ */
|
|
1300
|
+
return /* @__PURE__ */ jsx21(PanelSection, { title: `${capitalize(trackNoun.plural)}${total !== void 0 ? ` (${total})` : ""}`, children: /* @__PURE__ */ jsxs12("div", { children: [
|
|
1306
1301
|
renderTracksToolbar?.(),
|
|
1307
|
-
scope === "me" && !genrePlaylist ? /* @__PURE__ */
|
|
1302
|
+
scope === "me" && !genrePlaylist ? /* @__PURE__ */ jsx21("p", { children: "\u2014" }) : isPending ? /* @__PURE__ */ jsx21(Skeleton, { className: "h-4 w-3/4", "aria-busy": "true" }) : isError && tracks.length === 0 ? /* @__PURE__ */ jsxs12("p", { role: "alert", children: [
|
|
1308
1303
|
"Couldn't load ",
|
|
1309
1304
|
trackNoun.plural,
|
|
1310
1305
|
".",
|
|
1311
1306
|
" ",
|
|
1312
|
-
/* @__PURE__ */
|
|
1313
|
-
] }) : tracks.length === 0 ? /* @__PURE__ */
|
|
1307
|
+
/* @__PURE__ */ jsx21("button", { type: "button", className: "underline", onClick: () => void refetch(), children: "Retry" })
|
|
1308
|
+
] }) : tracks.length === 0 ? /* @__PURE__ */ jsx21("p", { children: "\u2014" }) : /* @__PURE__ */ jsxs12("ul", { className: "mt-1 max-h-64 overflow-y-auto text-body [container-type:inline-size]", "aria-label": `${genreName} ${trackNoun.plural}`, children: [
|
|
1314
1309
|
tracks.map((track, index) => {
|
|
1315
1310
|
const label = track.artists?.length ? `${track.title} \u2014 ${track.artists.map((artist2) => artist2.name).join(", ")}` : track.title;
|
|
1316
1311
|
const isCurrent = playerTrackObject?.track.id === track.uuid;
|
|
1317
1312
|
const isPlaying = isCurrent && playState === PlayStates.PLAYING;
|
|
1318
1313
|
const text = /* @__PURE__ */ jsxs12("span", { className: TEXT_CELL, children: [
|
|
1319
|
-
/* @__PURE__ */
|
|
1320
|
-
track.artists?.length ? /* @__PURE__ */
|
|
1321
|
-
/* @__PURE__ */
|
|
1322
|
-
track.album && /* @__PURE__ */
|
|
1314
|
+
/* @__PURE__ */ jsx21("span", { className: TITLE_CELL, children: renderSongLink ? renderSongLink(track) : isSong(track) ? /* @__PURE__ */ jsx21(MusicBrainzRecordingLink, { song: track, className: "hover:underline focus-visible:underline", children: track.title }) : track.title }),
|
|
1315
|
+
track.artists?.length ? /* @__PURE__ */ jsx21("span", { className: SEPARATOR, children: " \u2014 " }) : null,
|
|
1316
|
+
/* @__PURE__ */ jsx21("span", { className: COLUMN_CELL, children: track.artists?.length ? /* @__PURE__ */ jsx21(ArtistNames, { artists: track.artists, renderArtistLink }) : null }),
|
|
1317
|
+
track.album && /* @__PURE__ */ jsx21("span", { className: ALBUM_CELL, children: track.album.name })
|
|
1323
1318
|
] });
|
|
1324
1319
|
const leading = renderSongLeading?.(track, index);
|
|
1325
1320
|
const actions = renderSongActions?.(track);
|
|
@@ -1327,7 +1322,7 @@ function GenrePlaylistTracks({
|
|
|
1327
1322
|
if (isUnplayable) {
|
|
1328
1323
|
return /* @__PURE__ */ jsxs12("li", { className: "flex min-h-8 items-center gap-1 px-1 opacity-50", children: [
|
|
1329
1324
|
leading,
|
|
1330
|
-
/* @__PURE__ */
|
|
1325
|
+
/* @__PURE__ */ jsx21(
|
|
1331
1326
|
"button",
|
|
1332
1327
|
{
|
|
1333
1328
|
type: "button",
|
|
@@ -1335,7 +1330,7 @@ function GenrePlaylistTracks({
|
|
|
1335
1330
|
"aria-disabled": "true",
|
|
1336
1331
|
"aria-label": label,
|
|
1337
1332
|
className: "flex h-6 w-6 shrink-0 items-center justify-center rounded-full opacity-0 cursor-not-allowed",
|
|
1338
|
-
children: /* @__PURE__ */
|
|
1333
|
+
children: /* @__PURE__ */ jsx21(FaPlay, { size: 10 })
|
|
1339
1334
|
}
|
|
1340
1335
|
),
|
|
1341
1336
|
text,
|
|
@@ -1348,14 +1343,14 @@ function GenrePlaylistTracks({
|
|
|
1348
1343
|
className: `group flex min-h-8 items-center gap-1 rounded px-1 hover:bg-[var(--color-neutral-100)] ${isCurrent ? "font-medium text-[var(--color-primary)]" : ""}`,
|
|
1349
1344
|
children: [
|
|
1350
1345
|
leading,
|
|
1351
|
-
/* @__PURE__ */
|
|
1346
|
+
/* @__PURE__ */ jsx21(
|
|
1352
1347
|
"button",
|
|
1353
1348
|
{
|
|
1354
1349
|
type: "button",
|
|
1355
1350
|
"aria-label": `${isPlaying ? "Pause" : "Play"} ${label}`,
|
|
1356
1351
|
className: `flex h-6 w-6 shrink-0 items-center justify-center rounded-full cursor-pointer group-hover:opacity-100 focus-visible:opacity-100 ${isCurrent && playState !== PlayStates.STOPPED ? "opacity-100" : "opacity-0 [@media(pointer:coarse)]:opacity-100"}`,
|
|
1357
1352
|
onClick: () => isCurrent ? handlePlayPauseAction() : play(track.uuid),
|
|
1358
|
-
children: isCurrent && playState === PlayStates.LOADING ? /* @__PURE__ */
|
|
1353
|
+
children: isCurrent && playState === PlayStates.LOADING ? /* @__PURE__ */ jsx21(RingLoader, { size: 10 }) : isPlaying ? /* @__PURE__ */ jsx21(FaPause, { size: 10 }) : /* @__PURE__ */ jsx21(FaPlay, { size: 10 })
|
|
1359
1354
|
}
|
|
1360
1355
|
),
|
|
1361
1356
|
text,
|
|
@@ -1365,7 +1360,7 @@ function GenrePlaylistTracks({
|
|
|
1365
1360
|
track.uuid
|
|
1366
1361
|
);
|
|
1367
1362
|
}),
|
|
1368
|
-
hasNextPage && /* @__PURE__ */
|
|
1363
|
+
hasNextPage && /* @__PURE__ */ jsx21("li", { ref: setSentinel, "aria-hidden": "true", className: "h-4" })
|
|
1369
1364
|
] })
|
|
1370
1365
|
] }) });
|
|
1371
1366
|
}
|
|
@@ -1373,7 +1368,7 @@ function GenrePlaylistTracks({
|
|
|
1373
1368
|
// src/genre-tree/GenreDetailExtras.tsx
|
|
1374
1369
|
import { useTrackNoun as useTrackNoun2 } from "@behindthemusictree/app-kit/track-noun";
|
|
1375
1370
|
import { SiWikidata, SiWikipedia } from "react-icons/si";
|
|
1376
|
-
import { Fragment as Fragment9, jsx as
|
|
1371
|
+
import { Fragment as Fragment9, jsx as jsx22, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
1377
1372
|
function GenreDetailExtras({
|
|
1378
1373
|
genreUuid,
|
|
1379
1374
|
genrePlaylist,
|
|
@@ -1400,15 +1395,15 @@ function GenreDetailExtras({
|
|
|
1400
1395
|
);
|
|
1401
1396
|
if (isPending) {
|
|
1402
1397
|
return /* @__PURE__ */ jsxs13(Fragment9, { children: [
|
|
1403
|
-
/* @__PURE__ */
|
|
1398
|
+
/* @__PURE__ */ jsx22(PanelSection2, { title: "Summary", children: /* @__PURE__ */ jsx22("div", { "aria-busy": "true", "data-testid": "genre-detail-extras-skeleton", children: /* @__PURE__ */ jsx22(Skeleton2, { className: "h-4 w-3/4" }) }) }),
|
|
1404
1399
|
family
|
|
1405
1400
|
] });
|
|
1406
1401
|
}
|
|
1407
|
-
if (!overview) return /* @__PURE__ */
|
|
1402
|
+
if (!overview) return /* @__PURE__ */ jsx22(Fragment9, { children: family });
|
|
1408
1403
|
const { summary, summarySourceUrl, essentialSongs } = overview;
|
|
1409
1404
|
const wikidataUrl = wikidataId ? `https://www.wikidata.org/wiki/${encodeURIComponent(wikidataId)}` : null;
|
|
1410
1405
|
return /* @__PURE__ */ jsxs13(Fragment9, { children: [
|
|
1411
|
-
(summarySourceUrl || wikidataUrl) && /* @__PURE__ */
|
|
1406
|
+
(summarySourceUrl || wikidataUrl) && /* @__PURE__ */ jsx22(PanelSection2, { title: "Links", children: /* @__PURE__ */ jsxs13("div", { className: "flex flex-wrap gap-x-3 gap-y-1 text-caption text-[var(--color-text)]", children: [
|
|
1412
1407
|
summarySourceUrl && /* @__PURE__ */ jsxs13(
|
|
1413
1408
|
"a",
|
|
1414
1409
|
{
|
|
@@ -1417,7 +1412,7 @@ function GenreDetailExtras({
|
|
|
1417
1412
|
rel: "noopener noreferrer",
|
|
1418
1413
|
className: "inline-flex items-center gap-1.5 text-[var(--color-text-muted)] hover:text-[var(--color-text)]",
|
|
1419
1414
|
children: [
|
|
1420
|
-
/* @__PURE__ */
|
|
1415
|
+
/* @__PURE__ */ jsx22(SiWikipedia, { "aria-hidden": "true", className: "h-3.5 w-3.5" }),
|
|
1421
1416
|
"Wikipedia"
|
|
1422
1417
|
]
|
|
1423
1418
|
}
|
|
@@ -1430,17 +1425,17 @@ function GenreDetailExtras({
|
|
|
1430
1425
|
rel: "noopener noreferrer",
|
|
1431
1426
|
className: "inline-flex items-center gap-1.5 text-[var(--color-text-muted)] hover:text-[var(--color-text)]",
|
|
1432
1427
|
children: [
|
|
1433
|
-
/* @__PURE__ */
|
|
1428
|
+
/* @__PURE__ */ jsx22(SiWikidata, { "aria-hidden": "true", className: "h-3.5 w-3.5" }),
|
|
1434
1429
|
"Wikidata"
|
|
1435
1430
|
]
|
|
1436
1431
|
}
|
|
1437
1432
|
)
|
|
1438
1433
|
] }) }),
|
|
1439
|
-
/* @__PURE__ */
|
|
1434
|
+
/* @__PURE__ */ jsx22(PanelSection2, { title: "Summary", children: renderSummary ? renderSummary(overview) : /* @__PURE__ */ jsx22(ClampedText, { className: "text-body text-[var(--color-text)]", children: summary ?? "\u2014" }, genreUuid) }),
|
|
1440
1435
|
family,
|
|
1441
1436
|
renderGenreDetailExtras?.(overview),
|
|
1442
|
-
(renderEssentialTracks || essentialSongs) && /* @__PURE__ */
|
|
1443
|
-
/* @__PURE__ */
|
|
1437
|
+
(renderEssentialTracks || essentialSongs) && /* @__PURE__ */ jsx22(PanelSection2, { title: `Essential ${trackNoun.plural}`, children: renderEssentialTracks ? renderEssentialTracks(overview) : essentialSongs && essentialSongs.length > 0 ? /* @__PURE__ */ jsx22("ul", { className: "text-body text-[var(--color-text)]", children: essentialSongs.map((track) => /* @__PURE__ */ jsx22("li", { className: "py-1", children: track.title }, track.uuid)) }) : /* @__PURE__ */ jsx22("p", { className: "text-body text-[var(--color-text)]", children: "\u2014" }) }),
|
|
1438
|
+
/* @__PURE__ */ jsx22(
|
|
1444
1439
|
GenrePlaylistTracks,
|
|
1445
1440
|
{
|
|
1446
1441
|
genreUuid,
|
|
@@ -1458,10 +1453,10 @@ function GenreDetailExtras({
|
|
|
1458
1453
|
}
|
|
1459
1454
|
|
|
1460
1455
|
// src/genre-tree/GenreInfoPanelBody.tsx
|
|
1461
|
-
import { Fragment as Fragment10, jsx as
|
|
1456
|
+
import { Fragment as Fragment10, jsx as jsx23, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
1462
1457
|
import { createElement } from "react";
|
|
1463
1458
|
function GenreNodeActionBand({ genrePlaylist, playback, ...bandProps }) {
|
|
1464
|
-
return /* @__PURE__ */
|
|
1459
|
+
return /* @__PURE__ */ jsx23(GenreActionBand, { ...bandProps, playActions: /* @__PURE__ */ jsx23(GenrePlayActions, { genrePlaylist, playback }) });
|
|
1465
1460
|
}
|
|
1466
1461
|
function GenreInfoPanelBody({
|
|
1467
1462
|
toolbar,
|
|
@@ -1480,7 +1475,7 @@ function GenreInfoPanelBody({
|
|
|
1480
1475
|
const selection = summary ? defaultGenreMusicSelection2(summary) : void 0;
|
|
1481
1476
|
return /* @__PURE__ */ jsxs14(Fragment10, { children: [
|
|
1482
1477
|
toolbar,
|
|
1483
|
-
genrePlaylist ? /* @__PURE__ */
|
|
1478
|
+
genrePlaylist ? /* @__PURE__ */ jsx23(GenreNodeActionBand, { ...band, genrePlaylist, playback }) : /* @__PURE__ */ jsx23(GenreActionBand, { ...band }),
|
|
1484
1479
|
/* @__PURE__ */ createElement(
|
|
1485
1480
|
GenreDetailExtras,
|
|
1486
1481
|
{
|
|
@@ -1500,7 +1495,7 @@ function GenreInfoPanelBody({
|
|
|
1500
1495
|
}
|
|
1501
1496
|
|
|
1502
1497
|
// src/genre-tree/GenreDetailPanel.tsx
|
|
1503
|
-
import { Fragment as Fragment11, jsx as
|
|
1498
|
+
import { Fragment as Fragment11, jsx as jsx24, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
1504
1499
|
var RELATIVE_ITEM_COUNT = 1;
|
|
1505
1500
|
function toNode(genre, parentId) {
|
|
1506
1501
|
return {
|
|
@@ -1523,7 +1518,7 @@ function useGenreDetailContent({
|
|
|
1523
1518
|
trailing,
|
|
1524
1519
|
genrePlaylist: hostPlaylist,
|
|
1525
1520
|
expanded,
|
|
1526
|
-
|
|
1521
|
+
treeStyles
|
|
1527
1522
|
}) {
|
|
1528
1523
|
const { data: detail, isPending, isError } = useFetchGenreDetail(genreUuid, scope, getBackendBaseUrl);
|
|
1529
1524
|
const defaultPlayback = useGenrePlaylistPlayback({ scope, genrePlaylists: [], artist: extras?.artist });
|
|
@@ -1531,19 +1526,12 @@ function useGenreDetailContent({
|
|
|
1531
1526
|
const view = useMemo6(() => {
|
|
1532
1527
|
if (!detail) return null;
|
|
1533
1528
|
const rootColor = getGenreTreeColor2(detail.root.wikidataId);
|
|
1534
|
-
const treeStyles = /* @__PURE__ */ new Map();
|
|
1535
|
-
if (treeRelations) {
|
|
1536
|
-
const drawn = [treeRelations, treeRelations.parentNode, ...treeRelations.childNodes, ...treeRelations.ancestorNodes];
|
|
1537
|
-
for (const entry of drawn) {
|
|
1538
|
-
if (entry) treeStyles.set(entry.node.id, { fill: entry.fill, textColor: entry.textColor });
|
|
1539
|
-
}
|
|
1540
|
-
}
|
|
1541
1529
|
const relative = (genre, parentId) => ({
|
|
1542
1530
|
node: toNode(genre, parentId),
|
|
1543
|
-
...treeStyles
|
|
1531
|
+
...treeStyles?.get(genre.uuid) ?? { fill: tintSurface(rootColor), textColor: TEXT_COLOR }
|
|
1544
1532
|
});
|
|
1545
1533
|
const ancestors2 = [...detail.ascendants].sort((a, b) => b.degree - a.degree);
|
|
1546
|
-
const own = treeStyles
|
|
1534
|
+
const own = treeStyles?.get(detail.uuid) ?? { fill: rootColor, textColor: getTextColorOnFill(rootColor) };
|
|
1547
1535
|
return {
|
|
1548
1536
|
node: {
|
|
1549
1537
|
id: detail.uuid,
|
|
@@ -1560,23 +1548,23 @@ function useGenreDetailContent({
|
|
|
1560
1548
|
({ ascendant }, index) => relative(ascendant, index === 0 ? null : ancestors2[index - 1].ascendant.uuid)
|
|
1561
1549
|
)
|
|
1562
1550
|
};
|
|
1563
|
-
}, [detail, scope,
|
|
1551
|
+
}, [detail, scope, treeStyles]);
|
|
1564
1552
|
if (isError) return {
|
|
1565
1553
|
name: null,
|
|
1566
1554
|
title: "Genre unavailable",
|
|
1567
|
-
content: /* @__PURE__ */
|
|
1555
|
+
content: /* @__PURE__ */ jsx24("p", { role: "alert", className: "text-body text-[var(--color-text)]", children: "This genre could not be loaded." })
|
|
1568
1556
|
};
|
|
1569
1557
|
if (isPending || !detail || !view) return {
|
|
1570
1558
|
name: null,
|
|
1571
1559
|
title: "Loading genre\u2026",
|
|
1572
1560
|
content: /* @__PURE__ */ jsxs15("div", { className: "flex flex-col gap-3", "aria-busy": "true", "data-testid": "genre-detail-panel-skeleton", children: [
|
|
1573
|
-
/* @__PURE__ */
|
|
1574
|
-
/* @__PURE__ */
|
|
1575
|
-
/* @__PURE__ */
|
|
1561
|
+
/* @__PURE__ */ jsx24(Skeleton3, { className: "h-6 w-2/3" }),
|
|
1562
|
+
/* @__PURE__ */ jsx24(Skeleton3, { className: "h-4 w-full" }),
|
|
1563
|
+
/* @__PURE__ */ jsx24(Skeleton3, { className: "h-4 w-3/4" })
|
|
1576
1564
|
] })
|
|
1577
1565
|
};
|
|
1578
1566
|
const selectGenre = (nodeId) => onSelectGenre(GenreUuidSchema.parse(nodeId));
|
|
1579
|
-
const family = /* @__PURE__ */
|
|
1567
|
+
const family = /* @__PURE__ */ jsx24(
|
|
1580
1568
|
GenreNodeFamily,
|
|
1581
1569
|
{
|
|
1582
1570
|
node: view.node,
|
|
@@ -1587,14 +1575,14 @@ function useGenreDetailContent({
|
|
|
1587
1575
|
onSelectNode: selectGenre
|
|
1588
1576
|
}
|
|
1589
1577
|
);
|
|
1590
|
-
const ancestors = /* @__PURE__ */
|
|
1578
|
+
const ancestors = /* @__PURE__ */ jsx24(GenreNodeAncestors, { ancestorNodes: view.ancestorNodes, onSelectNode: selectGenre });
|
|
1591
1579
|
return {
|
|
1592
1580
|
name: detail.name,
|
|
1593
1581
|
title: detail.name,
|
|
1594
1582
|
headerAccent: { background: view.fill, color: view.textColor },
|
|
1595
1583
|
aside: expanded ? ancestors : void 0,
|
|
1596
1584
|
content: /* @__PURE__ */ jsxs15(Fragment11, { children: [
|
|
1597
|
-
/* @__PURE__ */
|
|
1585
|
+
/* @__PURE__ */ jsx24(
|
|
1598
1586
|
GenreInfoPanelBody,
|
|
1599
1587
|
{
|
|
1600
1588
|
family: /* @__PURE__ */ jsxs15(Fragment11, { children: [
|
|
@@ -1641,7 +1629,7 @@ function GenreDetailPanel({
|
|
|
1641
1629
|
expanded,
|
|
1642
1630
|
band: { onZoomIn, shareUrl, shareTarget: shareUrl ? shareTarget : void 0 }
|
|
1643
1631
|
});
|
|
1644
|
-
return /* @__PURE__ */
|
|
1632
|
+
return /* @__PURE__ */ jsx24(
|
|
1645
1633
|
DetailPanel,
|
|
1646
1634
|
{
|
|
1647
1635
|
side: "left",
|
|
@@ -1654,7 +1642,7 @@ function GenreDetailPanel({
|
|
|
1654
1642
|
edgeTab,
|
|
1655
1643
|
aside: panel.aside,
|
|
1656
1644
|
titleInSearch,
|
|
1657
|
-
headerActions: onExpandedChange ? /* @__PURE__ */
|
|
1645
|
+
headerActions: onExpandedChange ? /* @__PURE__ */ jsx24(IconButton, { "aria-label": expanded ? "Shrink panel" : "Extend panel", onClick: () => onExpandedChange(!expanded), children: expanded ? /* @__PURE__ */ jsx24(Minimize2, { "aria-hidden": "true", className: "h-4 w-4" }) : /* @__PURE__ */ jsx24(Maximize2, { "aria-hidden": "true", className: "h-4 w-4" }) }) : void 0,
|
|
1658
1646
|
children: panel.content
|
|
1659
1647
|
}
|
|
1660
1648
|
);
|
|
@@ -1666,7 +1654,7 @@ import {
|
|
|
1666
1654
|
getReparentCandidates,
|
|
1667
1655
|
useUpdateGenre
|
|
1668
1656
|
} from "@behindthemusictree/app-kit/genre-tree";
|
|
1669
|
-
import { jsx as
|
|
1657
|
+
import { jsx as jsx25, jsxs as jsxs16 } from "react/jsx-runtime";
|
|
1670
1658
|
function ChangeParentPopup({
|
|
1671
1659
|
genrePlaylist,
|
|
1672
1660
|
genrePlaylists,
|
|
@@ -1706,7 +1694,7 @@ function ChangeParentPopup({
|
|
|
1706
1694
|
"Current parent: ",
|
|
1707
1695
|
genrePlaylist.parent?.name ?? "none"
|
|
1708
1696
|
] }),
|
|
1709
|
-
/* @__PURE__ */
|
|
1697
|
+
/* @__PURE__ */ jsx25("div", { "aria-busy": isPending, className: isPending ? "pointer-events-none opacity-60" : void 0, children: /* @__PURE__ */ jsx25(
|
|
1710
1698
|
GenreSearch,
|
|
1711
1699
|
{
|
|
1712
1700
|
genrePlaylists: candidates,
|
|
@@ -1714,7 +1702,7 @@ function ChangeParentPopup({
|
|
|
1714
1702
|
placeholder: "Search a new parent\u2026"
|
|
1715
1703
|
}
|
|
1716
1704
|
) }),
|
|
1717
|
-
formErrors.length > 0 && /* @__PURE__ */
|
|
1705
|
+
formErrors.length > 0 && /* @__PURE__ */ jsx25("p", { role: "alert", className: "mt-3 text-body text-[var(--color-red-500)]", children: formErrors.map(({ message }) => message).join(" ") })
|
|
1718
1706
|
] });
|
|
1719
1707
|
}
|
|
1720
1708
|
|
|
@@ -1727,7 +1715,7 @@ import { Pause as Pause2, Play as Play2 } from "lucide-react";
|
|
|
1727
1715
|
import { ActionBand as ActionBand2, ActionButton as ActionButton4, PanelBleed as PanelBleed2 } from "@behindthemusictree/ui";
|
|
1728
1716
|
import { TrackListOriginType as TrackListOriginType2, useTrackList as useTrackList3 } from "@behindthemusictree/app-kit/genre-tree";
|
|
1729
1717
|
import { usePlayer as usePlayer6 } from "@behindthemusictree/app-kit/player";
|
|
1730
|
-
import { jsx as
|
|
1718
|
+
import { jsx as jsx26, jsxs as jsxs17 } from "react/jsx-runtime";
|
|
1731
1719
|
function ArtistActionBand({ artist, share }) {
|
|
1732
1720
|
const { trackList, playNewTrackListFromArtist } = useTrackList3();
|
|
1733
1721
|
const { isPlaying, setIsPlaying } = usePlayer6();
|
|
@@ -1743,11 +1731,11 @@ function ArtistActionBand({ artist, share }) {
|
|
|
1743
1731
|
console.error("Failed to load artist tracks:", error);
|
|
1744
1732
|
});
|
|
1745
1733
|
};
|
|
1746
|
-
return /* @__PURE__ */
|
|
1747
|
-
/* @__PURE__ */
|
|
1734
|
+
return /* @__PURE__ */ jsx26(PanelBleed2, { children: /* @__PURE__ */ jsxs17(ActionBand2, { children: [
|
|
1735
|
+
/* @__PURE__ */ jsx26(
|
|
1748
1736
|
ActionButton4,
|
|
1749
1737
|
{
|
|
1750
|
-
icon: playing ? /* @__PURE__ */
|
|
1738
|
+
icon: playing ? /* @__PURE__ */ jsx26(Pause2, { "aria-hidden": "true", className: "w-5 h-5" }) : /* @__PURE__ */ jsx26(Play2, { "aria-hidden": "true", className: "w-5 h-5" }),
|
|
1751
1739
|
label: playing ? "Pause" : "Play",
|
|
1752
1740
|
caption: String(artist.playableTracksCount),
|
|
1753
1741
|
disabled: artist.playableTracksCount === 0,
|
|
@@ -1775,7 +1763,7 @@ import {
|
|
|
1775
1763
|
SiYoutube
|
|
1776
1764
|
} from "react-icons/si";
|
|
1777
1765
|
import { Chip } from "@behindthemusictree/ui";
|
|
1778
|
-
import { jsx as
|
|
1766
|
+
import { jsx as jsx27 } from "react/jsx-runtime";
|
|
1779
1767
|
var LINK_KINDS = {
|
|
1780
1768
|
official: { label: "Official website", Icon: Globe },
|
|
1781
1769
|
wikipedia: { label: "Wikipedia", Icon: SiWikipedia2 },
|
|
@@ -1812,7 +1800,7 @@ function artistLinks(artist) {
|
|
|
1812
1800
|
return links;
|
|
1813
1801
|
}
|
|
1814
1802
|
function ArtistLinks({ links }) {
|
|
1815
|
-
return /* @__PURE__ */
|
|
1803
|
+
return /* @__PURE__ */ jsx27("ul", { className: "flex flex-wrap gap-1.5", children: links.map(({ key, url, Icon, label }) => /* @__PURE__ */ jsx27("li", { children: /* @__PURE__ */ jsx27(Chip, { href: url, icon: /* @__PURE__ */ jsx27(Icon, { className: "h-3.5 w-3.5 shrink-0", "aria-hidden": "true" }), children: label }) }, key)) });
|
|
1816
1804
|
}
|
|
1817
1805
|
|
|
1818
1806
|
// src/genre-tree/artist/formatYears.ts
|
|
@@ -1823,7 +1811,7 @@ function formatYears(beginYear, endYear, ended) {
|
|
|
1823
1811
|
}
|
|
1824
1812
|
|
|
1825
1813
|
// src/genre-tree/artist/ArtistHeader.tsx
|
|
1826
|
-
import { jsx as
|
|
1814
|
+
import { jsx as jsx28 } from "react/jsx-runtime";
|
|
1827
1815
|
var countryNames = new Intl.DisplayNames(["en"], { type: "region" });
|
|
1828
1816
|
function ArtistHeader({ artist }) {
|
|
1829
1817
|
const fields = [];
|
|
@@ -1833,35 +1821,35 @@ function ArtistHeader({ artist }) {
|
|
|
1833
1821
|
const years = formatYears(artist.beginYear, artist.endYear, artist.ended);
|
|
1834
1822
|
if (years) fields.push({ label: "Active", value: years });
|
|
1835
1823
|
const links = artistLinks(artist);
|
|
1836
|
-
if (links.length > 0) fields.push({ label: "Links", value: /* @__PURE__ */
|
|
1824
|
+
if (links.length > 0) fields.push({ label: "Links", value: /* @__PURE__ */ jsx28(ArtistLinks, { links }) });
|
|
1837
1825
|
if (fields.length === 0) return null;
|
|
1838
|
-
return /* @__PURE__ */
|
|
1826
|
+
return /* @__PURE__ */ jsx28(FieldList, { items: fields });
|
|
1839
1827
|
}
|
|
1840
1828
|
|
|
1841
1829
|
// src/genre-tree/artist/ArtistPhoto.tsx
|
|
1842
|
-
import { jsx as
|
|
1830
|
+
import { jsx as jsx29, jsxs as jsxs18 } from "react/jsx-runtime";
|
|
1843
1831
|
function ExternalLink({ href, children }) {
|
|
1844
|
-
return /* @__PURE__ */
|
|
1832
|
+
return /* @__PURE__ */ jsx29("a", { href, target: "_blank", rel: "noopener noreferrer", className: "underline-offset-2 hover:underline", children });
|
|
1845
1833
|
}
|
|
1846
1834
|
function ArtistPhoto({ image, name }) {
|
|
1847
1835
|
return /* @__PURE__ */ jsxs18("figure", { className: "flex flex-col gap-1.5", children: [
|
|
1848
|
-
/* @__PURE__ */
|
|
1836
|
+
/* @__PURE__ */ jsx29("img", { src: image.url, alt: name, className: "h-64 w-full object-contain bg-[var(--color-surface-muted)] rounded" }),
|
|
1849
1837
|
/* @__PURE__ */ jsxs18("figcaption", { className: "text-caption text-[var(--color-text-muted)]", children: [
|
|
1850
1838
|
"Photo: ",
|
|
1851
|
-
/* @__PURE__ */
|
|
1839
|
+
/* @__PURE__ */ jsx29(ExternalLink, { href: image.pageUrl, children: image.author ?? "Wikimedia Commons" }),
|
|
1852
1840
|
",",
|
|
1853
1841
|
" ",
|
|
1854
|
-
image.licenseUrl ? /* @__PURE__ */
|
|
1842
|
+
image.licenseUrl ? /* @__PURE__ */ jsx29(ExternalLink, { href: image.licenseUrl, children: image.license }) : image.license
|
|
1855
1843
|
] })
|
|
1856
1844
|
] });
|
|
1857
1845
|
}
|
|
1858
1846
|
|
|
1859
1847
|
// src/genre-tree/artist/ArtistMembers.tsx
|
|
1860
1848
|
import { PanelGroup, PanelSection as PanelSection3 } from "@behindthemusictree/ui";
|
|
1861
|
-
import { jsx as
|
|
1849
|
+
import { jsx as jsx30, jsxs as jsxs19 } from "react/jsx-runtime";
|
|
1862
1850
|
function MembershipList({ title, memberships, renderArtistLink }) {
|
|
1863
1851
|
if (memberships.length === 0) return null;
|
|
1864
|
-
return /* @__PURE__ */
|
|
1852
|
+
return /* @__PURE__ */ jsx30(PanelGroup, { title, children: /* @__PURE__ */ jsx30("ul", { children: memberships.map((membership, index) => {
|
|
1865
1853
|
const details = [
|
|
1866
1854
|
formatYears(membership.beginYear, membership.endYear, membership.ended),
|
|
1867
1855
|
...membership.roles
|
|
@@ -1870,7 +1858,7 @@ function MembershipList({ title, memberships, renderArtistLink }) {
|
|
|
1870
1858
|
return (
|
|
1871
1859
|
// A member can have several periods in the same group.
|
|
1872
1860
|
/* @__PURE__ */ jsxs19("li", { className: "truncate py-0.5", title: detailsText || void 0, children: [
|
|
1873
|
-
/* @__PURE__ */
|
|
1861
|
+
/* @__PURE__ */ jsx30("span", { className: "font-medium text-[var(--color-text)]", children: renderArtistLink(membership.artist) }),
|
|
1874
1862
|
detailsText && /* @__PURE__ */ jsxs19("span", { className: "text-[var(--color-text-muted)]", children: [
|
|
1875
1863
|
" \u2014 ",
|
|
1876
1864
|
detailsText
|
|
@@ -1883,8 +1871,8 @@ function ArtistMembers({ title, memberships, renderArtistLink }) {
|
|
|
1883
1871
|
if (memberships.length === 0) return null;
|
|
1884
1872
|
const isCurrent = (membership) => !membership.ended && membership.endYear === null;
|
|
1885
1873
|
return /* @__PURE__ */ jsxs19(PanelSection3, { title, children: [
|
|
1886
|
-
/* @__PURE__ */
|
|
1887
|
-
/* @__PURE__ */
|
|
1874
|
+
/* @__PURE__ */ jsx30(MembershipList, { title: "Current", memberships: memberships.filter(isCurrent), renderArtistLink }),
|
|
1875
|
+
/* @__PURE__ */ jsx30(
|
|
1888
1876
|
MembershipList,
|
|
1889
1877
|
{
|
|
1890
1878
|
title: "Past",
|
|
@@ -1897,7 +1885,7 @@ function ArtistMembers({ title, memberships, renderArtistLink }) {
|
|
|
1897
1885
|
|
|
1898
1886
|
// src/genre-tree/artist/ArtistDiscography.tsx
|
|
1899
1887
|
import { PanelGroup as PanelGroup2, PanelSection as PanelSection4 } from "@behindthemusictree/ui";
|
|
1900
|
-
import { jsx as
|
|
1888
|
+
import { jsx as jsx31, jsxs as jsxs20 } from "react/jsx-runtime";
|
|
1901
1889
|
var GROUPS = ["Albums", "EPs", "Singles", "Live", "Compilations", "Other"];
|
|
1902
1890
|
var PRIMARY_GROUPS = { album: "Albums", ep: "EPs", single: "Singles" };
|
|
1903
1891
|
function discographyGroup({ primaryType, secondaryTypes }) {
|
|
@@ -1917,12 +1905,12 @@ function byYear(a, b) {
|
|
|
1917
1905
|
function ArtistDiscography({ albums }) {
|
|
1918
1906
|
if (albums.length === 0) return null;
|
|
1919
1907
|
const sorted = [...albums].sort(byYear);
|
|
1920
|
-
return /* @__PURE__ */
|
|
1908
|
+
return /* @__PURE__ */ jsx31(PanelSection4, { title: "Discography", children: GROUPS.map((group) => {
|
|
1921
1909
|
const groupAlbums = sorted.filter((album) => discographyGroup(album) === group);
|
|
1922
1910
|
if (groupAlbums.length === 0) return null;
|
|
1923
|
-
return /* @__PURE__ */
|
|
1924
|
-
/* @__PURE__ */
|
|
1925
|
-
/* @__PURE__ */
|
|
1911
|
+
return /* @__PURE__ */ jsx31(PanelGroup2, { title: group, children: /* @__PURE__ */ jsx31("ul", { children: groupAlbums.map((album) => /* @__PURE__ */ jsxs20("li", { className: "grid grid-cols-[2.5rem_minmax(0,1fr)] gap-2 py-0.5", children: [
|
|
1912
|
+
/* @__PURE__ */ jsx31("span", { className: "tabular-nums text-[var(--color-text-muted)]", children: album.year ?? "\u2014" }),
|
|
1913
|
+
/* @__PURE__ */ jsx31("span", { className: "truncate text-[var(--color-text)]", title: album.name, children: album.name })
|
|
1926
1914
|
] }, album.uuid)) }) }, group);
|
|
1927
1915
|
}) });
|
|
1928
1916
|
}
|
|
@@ -1930,7 +1918,6 @@ function ArtistDiscography({ albums }) {
|
|
|
1930
1918
|
// src/genre-tree/artist/ArtistSongs.tsx
|
|
1931
1919
|
import { useState as useState8 } from "react";
|
|
1932
1920
|
import { keepPreviousData } from "@tanstack/react-query";
|
|
1933
|
-
import { Play as Play3 } from "lucide-react";
|
|
1934
1921
|
import { Pagination, PanelSection as PanelSection5, Skeleton as Skeleton4 } from "@behindthemusictree/ui";
|
|
1935
1922
|
import { usePlayer as usePlayer9 } from "@behindthemusictree/app-kit/player";
|
|
1936
1923
|
import {
|
|
@@ -1949,7 +1936,7 @@ import { useTrackList as useTrackList4 } from "@behindthemusictree/app-kit/genre
|
|
|
1949
1936
|
import { FaPlay as FaPlay2, FaPause as FaPause2 } from "react-icons/fa";
|
|
1950
1937
|
import { usePlayer as usePlayer7 } from "@behindthemusictree/app-kit/player";
|
|
1951
1938
|
import { PlayStates as PlayStates2 } from "@behindthemusictree/app-kit/player";
|
|
1952
|
-
import { jsx as
|
|
1939
|
+
import { jsx as jsx32, jsxs as jsxs21 } from "react/jsx-runtime";
|
|
1953
1940
|
function TrackPositionPlayPause({
|
|
1954
1941
|
position,
|
|
1955
1942
|
uuid,
|
|
@@ -1970,7 +1957,7 @@ function TrackPositionPlayPause({
|
|
|
1970
1957
|
style: { minWidth: "4rem", maxWidth: "4rem" },
|
|
1971
1958
|
onClick: handlePlayPauseClick,
|
|
1972
1959
|
children: [
|
|
1973
|
-
/* @__PURE__ */
|
|
1960
|
+
/* @__PURE__ */ jsx32("div", { className: "track-position-play-pause__status group-hover:hidden flex items-center justify-center", children: isAwaitingPlayback ? /* @__PURE__ */ jsx32("span", { className: "track-position-play-pause__spinner", role: "status", "aria-label": "Loading track" }) : isCurrentTrackActive ? /* @__PURE__ */ jsxs21(
|
|
1974
1961
|
"span",
|
|
1975
1962
|
{
|
|
1976
1963
|
className: "track-position-play-pause__bars",
|
|
@@ -1978,18 +1965,18 @@ function TrackPositionPlayPause({
|
|
|
1978
1965
|
role: "img",
|
|
1979
1966
|
"aria-label": isPlaying ? "Playing" : "Paused",
|
|
1980
1967
|
children: [
|
|
1981
|
-
/* @__PURE__ */
|
|
1982
|
-
/* @__PURE__ */
|
|
1983
|
-
/* @__PURE__ */
|
|
1968
|
+
/* @__PURE__ */ jsx32("span", { className: "track-position-play-pause__bar" }),
|
|
1969
|
+
/* @__PURE__ */ jsx32("span", { className: "track-position-play-pause__bar" }),
|
|
1970
|
+
/* @__PURE__ */ jsx32("span", { className: "track-position-play-pause__bar" })
|
|
1984
1971
|
]
|
|
1985
1972
|
}
|
|
1986
1973
|
) : position }),
|
|
1987
|
-
/* @__PURE__ */
|
|
1974
|
+
/* @__PURE__ */ jsx32(
|
|
1988
1975
|
"div",
|
|
1989
1976
|
{
|
|
1990
1977
|
className: `hidden group-hover:flex items-center justify-center ${isCurrentTrackActive ? "" : "absolute inset-0"}`,
|
|
1991
1978
|
"aria-hidden": "true",
|
|
1992
|
-
children: isAwaitingPlayback ? /* @__PURE__ */
|
|
1979
|
+
children: isAwaitingPlayback ? /* @__PURE__ */ jsx32("span", { className: "track-position-play-pause__spinner" }) : isPlaying ? /* @__PURE__ */ jsx32(FaPause2, {}) : /* @__PURE__ */ jsx32(FaPlay2, {})
|
|
1993
1980
|
}
|
|
1994
1981
|
)
|
|
1995
1982
|
]
|
|
@@ -2000,7 +1987,7 @@ function TrackPositionPlayPause({
|
|
|
2000
1987
|
// src/genre-tree/track-list-sidebar/TrackItem.tsx
|
|
2001
1988
|
import { isSong as isSong2, songUnplayableReason as songUnplayableReason2 } from "@behindthemusictree/app-kit/genre-tree";
|
|
2002
1989
|
import { ArtistNames as ArtistNames2 } from "@behindthemusictree/app-kit/genre-tree";
|
|
2003
|
-
import { jsx as
|
|
1990
|
+
import { jsx as jsx33, jsxs as jsxs22 } from "react/jsx-runtime";
|
|
2004
1991
|
function TrackItem({
|
|
2005
1992
|
track,
|
|
2006
1993
|
position,
|
|
@@ -2029,7 +2016,7 @@ function TrackItem({
|
|
|
2029
2016
|
{
|
|
2030
2017
|
className: `track-item flex h-14 text-[var(--color-text)] ${isUnplayable ? "opacity-50" : "hover:bg-[var(--color-surface-muted)] group"}`,
|
|
2031
2018
|
children: [
|
|
2032
|
-
isUnplayable ? /* @__PURE__ */
|
|
2019
|
+
isUnplayable ? /* @__PURE__ */ jsx33(
|
|
2033
2020
|
"div",
|
|
2034
2021
|
{
|
|
2035
2022
|
className: "flex items-center justify-center text-lg w-16",
|
|
@@ -2037,7 +2024,7 @@ function TrackItem({
|
|
|
2037
2024
|
"aria-disabled": "true",
|
|
2038
2025
|
children: position
|
|
2039
2026
|
}
|
|
2040
|
-
) : /* @__PURE__ */
|
|
2027
|
+
) : /* @__PURE__ */ jsx33(
|
|
2041
2028
|
TrackPositionPlayPause,
|
|
2042
2029
|
{
|
|
2043
2030
|
position,
|
|
@@ -2047,11 +2034,11 @@ function TrackItem({
|
|
|
2047
2034
|
}
|
|
2048
2035
|
),
|
|
2049
2036
|
/* @__PURE__ */ jsxs22("div", { className: "title-artist-container flex flex-col items-start justify-center min-w-0 flex-1", children: [
|
|
2050
|
-
/* @__PURE__ */
|
|
2051
|
-
track.artists && track.artists.length > 0 ? /* @__PURE__ */
|
|
2037
|
+
/* @__PURE__ */ jsx33("div", { className: "flex max-w-full items-center gap-2", children: /* @__PURE__ */ jsx33("div", { className: "title text-lg font-bold text-[var(--color-text)] max-w-full truncate", children: renderSongLink ? renderSongLink(track) : isSong2(track) ? /* @__PURE__ */ jsx33(MusicBrainzRecordingLink, { song: track, className: "hover:underline focus-visible:underline", children: track.title }) : track.title }) }),
|
|
2038
|
+
track.artists && track.artists.length > 0 ? /* @__PURE__ */ jsx33("div", { className: "artist text-base max-w-full truncate text-[var(--color-text-muted)]", children: /* @__PURE__ */ jsx33(ArtistNames2, { artists: track.artists, renderArtistLink }) }) : ""
|
|
2052
2039
|
] }),
|
|
2053
|
-
/* @__PURE__ */
|
|
2054
|
-
renderDuration && /* @__PURE__ */
|
|
2040
|
+
/* @__PURE__ */ jsx33("div", { className: "genre-name-container flex items-center justify-start w-[21.6%] min-w-0 shrink-0", children: track.genre ? /* @__PURE__ */ jsx33("div", { className: "genre-name max-w-full whitespace-normal break-words p-1 text-caption font-bold", children: track.genre.name }) : "" }),
|
|
2041
|
+
renderDuration && /* @__PURE__ */ jsx33(
|
|
2055
2042
|
"div",
|
|
2056
2043
|
{
|
|
2057
2044
|
className: "duration flex text-base w-16 items-center justify-center",
|
|
@@ -2059,14 +2046,14 @@ function TrackItem({
|
|
|
2059
2046
|
children: renderDuration(track)
|
|
2060
2047
|
}
|
|
2061
2048
|
),
|
|
2062
|
-
renderActions && /* @__PURE__ */
|
|
2049
|
+
renderActions && /* @__PURE__ */ jsx33("div", { className: "edit flex text-base w-6 items-center justify-center mr-2 cursor-pointer", children: renderActions(track) })
|
|
2063
2050
|
]
|
|
2064
2051
|
}
|
|
2065
2052
|
);
|
|
2066
2053
|
}
|
|
2067
2054
|
|
|
2068
2055
|
// src/genre-tree/artist/ArtistSongs.tsx
|
|
2069
|
-
import { Fragment as Fragment12, jsx as
|
|
2056
|
+
import { Fragment as Fragment12, jsx as jsx34, jsxs as jsxs23 } from "react/jsx-runtime";
|
|
2070
2057
|
var SongPageSchema2 = PaginatedResponseSchema2(SongDetailedSchema2);
|
|
2071
2058
|
var SORTS = [
|
|
2072
2059
|
{ ordering: "title", label: "Title" },
|
|
@@ -2099,36 +2086,22 @@ function ArtistSongs({ artist, getBackendBaseUrl, renderArtistLink, renderSongLi
|
|
|
2099
2086
|
event.stopPropagation();
|
|
2100
2087
|
void play(song.uuid);
|
|
2101
2088
|
};
|
|
2102
|
-
return /* @__PURE__ */
|
|
2103
|
-
/* @__PURE__ */
|
|
2104
|
-
|
|
2105
|
-
|
|
2106
|
-
|
|
2107
|
-
|
|
2108
|
-
|
|
2109
|
-
|
|
2110
|
-
|
|
2111
|
-
/* @__PURE__ */ jsx33(Play3, { className: "h-3.5 w-3.5", "aria-hidden": "true" }),
|
|
2112
|
-
"Play all"
|
|
2113
|
-
]
|
|
2114
|
-
}
|
|
2115
|
-
),
|
|
2116
|
-
/* @__PURE__ */ jsx33("div", { role: "group", "aria-label": "Sort songs by", className: "flex gap-1 text-caption", children: SORTS.map((sort) => /* @__PURE__ */ jsx33(
|
|
2117
|
-
"button",
|
|
2118
|
-
{
|
|
2119
|
-
type: "button",
|
|
2120
|
-
"aria-pressed": ordering === sort.ordering,
|
|
2121
|
-
onClick: () => {
|
|
2122
|
-
setOrdering(sort.ordering);
|
|
2123
|
-
setPage(1);
|
|
2124
|
-
},
|
|
2125
|
-
className: "px-2.5 py-0.5 text-[var(--color-text)] rounded-full hover:bg-[var(--color-surface-muted)] aria-pressed:bg-gray-900 aria-pressed:text-white",
|
|
2126
|
-
children: sort.label
|
|
2089
|
+
return /* @__PURE__ */ jsx34(PanelSection5, { title: "Songs", children: isPending ? /* @__PURE__ */ jsx34(Skeleton4, { className: "h-14", "aria-busy": "true" }) : isError ? /* @__PURE__ */ jsx34("p", { className: "text-red-600", children: "Could not load songs." }) : data.results.length === 0 ? /* @__PURE__ */ jsx34("p", { className: "text-[var(--color-text-muted)]", children: "No songs yet." }) : /* @__PURE__ */ jsxs23(Fragment12, { children: [
|
|
2090
|
+
/* @__PURE__ */ jsx34("div", { className: "flex flex-wrap items-center justify-end gap-2 mb-2", children: /* @__PURE__ */ jsx34("div", { role: "group", "aria-label": "Sort songs by", className: "flex gap-1 text-caption", children: SORTS.map((sort) => /* @__PURE__ */ jsx34(
|
|
2091
|
+
"button",
|
|
2092
|
+
{
|
|
2093
|
+
type: "button",
|
|
2094
|
+
"aria-pressed": ordering === sort.ordering,
|
|
2095
|
+
onClick: () => {
|
|
2096
|
+
setOrdering(sort.ordering);
|
|
2097
|
+
setPage(1);
|
|
2127
2098
|
},
|
|
2128
|
-
|
|
2129
|
-
|
|
2130
|
-
|
|
2131
|
-
|
|
2099
|
+
className: "px-2.5 py-0.5 text-[var(--color-text)] rounded-full hover:bg-[var(--color-surface-muted)] aria-pressed:bg-gray-900 aria-pressed:text-white",
|
|
2100
|
+
children: sort.label
|
|
2101
|
+
},
|
|
2102
|
+
sort.ordering
|
|
2103
|
+
)) }) }),
|
|
2104
|
+
/* @__PURE__ */ jsx34("ul", { className: "overflow-hidden mb-2 bg-zinc-950 rounded-lg", children: data.results.map((song, index) => /* @__PURE__ */ jsx34("li", { onClickCapture: (event) => handleRowClickCapture(event, song), children: /* @__PURE__ */ jsx34(
|
|
2132
2105
|
TrackItem,
|
|
2133
2106
|
{
|
|
2134
2107
|
track: song,
|
|
@@ -2137,12 +2110,12 @@ function ArtistSongs({ artist, getBackendBaseUrl, renderArtistLink, renderSongLi
|
|
|
2137
2110
|
renderSongLink
|
|
2138
2111
|
}
|
|
2139
2112
|
) }, song.uuid)) }),
|
|
2140
|
-
/* @__PURE__ */
|
|
2113
|
+
/* @__PURE__ */ jsx34(Pagination, { currentPage: page, totalPages: data.totalPages, onPageChange: setPage })
|
|
2141
2114
|
] }) });
|
|
2142
2115
|
}
|
|
2143
2116
|
|
|
2144
2117
|
// src/genre-tree/artist/useArtistPanel.tsx
|
|
2145
|
-
import { Fragment as Fragment13, jsx as
|
|
2118
|
+
import { Fragment as Fragment13, jsx as jsx35, jsxs as jsxs24 } from "react/jsx-runtime";
|
|
2146
2119
|
function useArtistPanel({
|
|
2147
2120
|
uuid,
|
|
2148
2121
|
scope,
|
|
@@ -2164,25 +2137,25 @@ function useArtistPanel({
|
|
|
2164
2137
|
...panel,
|
|
2165
2138
|
title: "Artist",
|
|
2166
2139
|
content: /* @__PURE__ */ jsxs24("div", { "aria-busy": "true", className: "flex flex-col gap-2.5", children: [
|
|
2167
|
-
/* @__PURE__ */
|
|
2168
|
-
/* @__PURE__ */
|
|
2169
|
-
/* @__PURE__ */
|
|
2170
|
-
/* @__PURE__ */
|
|
2171
|
-
/* @__PURE__ */
|
|
2172
|
-
/* @__PURE__ */
|
|
2140
|
+
/* @__PURE__ */ jsx35(Skeleton5, { className: "h-3 w-16" }),
|
|
2141
|
+
/* @__PURE__ */ jsx35(Skeleton5, { className: "h-4 w-32" }),
|
|
2142
|
+
/* @__PURE__ */ jsx35(Skeleton5, { className: "h-3 w-16" }),
|
|
2143
|
+
/* @__PURE__ */ jsx35(Skeleton5, { className: "h-4 w-24" }),
|
|
2144
|
+
/* @__PURE__ */ jsx35(Skeleton5, { className: "h-16 mt-2.5" }),
|
|
2145
|
+
/* @__PURE__ */ jsx35(Skeleton5, { className: "h-16" })
|
|
2173
2146
|
] })
|
|
2174
2147
|
};
|
|
2175
2148
|
case "not-found":
|
|
2176
2149
|
return {
|
|
2177
2150
|
...panel,
|
|
2178
2151
|
title: "Artist not found",
|
|
2179
|
-
content: /* @__PURE__ */
|
|
2152
|
+
content: /* @__PURE__ */ jsx35("p", { className: "text-[var(--color-text-muted)]", children: "This artist does not exist." })
|
|
2180
2153
|
};
|
|
2181
2154
|
case "error":
|
|
2182
2155
|
return {
|
|
2183
2156
|
...panel,
|
|
2184
2157
|
title: "Artist",
|
|
2185
|
-
content: /* @__PURE__ */
|
|
2158
|
+
content: /* @__PURE__ */ jsx35("p", { className: "text-red-600", children: "Could not load this artist." })
|
|
2186
2159
|
};
|
|
2187
2160
|
case "success": {
|
|
2188
2161
|
const { artist } = result;
|
|
@@ -2192,18 +2165,18 @@ function useArtistPanel({
|
|
|
2192
2165
|
...panel,
|
|
2193
2166
|
title: artist.name,
|
|
2194
2167
|
content: /* @__PURE__ */ jsxs24(Fragment13, { children: [
|
|
2195
|
-
/* @__PURE__ */
|
|
2168
|
+
/* @__PURE__ */ jsx35(
|
|
2196
2169
|
ArtistActionBand,
|
|
2197
2170
|
{
|
|
2198
2171
|
artist,
|
|
2199
|
-
share: shareTarget && shareUrl ? /* @__PURE__ */
|
|
2172
|
+
share: shareTarget && shareUrl ? /* @__PURE__ */ jsx35(ShareActionButton, { target: shareTarget, url: shareUrl }) : void 0
|
|
2200
2173
|
}
|
|
2201
2174
|
),
|
|
2202
|
-
artist.image && /* @__PURE__ */
|
|
2203
|
-
/* @__PURE__ */
|
|
2204
|
-
/* @__PURE__ */
|
|
2205
|
-
/* @__PURE__ */
|
|
2206
|
-
artist.tracksCount > 0 && /* @__PURE__ */
|
|
2175
|
+
artist.image && /* @__PURE__ */ jsx35(ArtistPhoto, { image: artist.image, name: artist.name }),
|
|
2176
|
+
/* @__PURE__ */ jsx35(ArtistHeader, { artist }),
|
|
2177
|
+
/* @__PURE__ */ jsx35(ArtistMembers, { title: "Members", memberships: artist.members, renderArtistLink }),
|
|
2178
|
+
/* @__PURE__ */ jsx35(ArtistMembers, { title: "Member of", memberships: artist.memberOf, renderArtistLink }),
|
|
2179
|
+
artist.tracksCount > 0 && /* @__PURE__ */ jsx35(
|
|
2207
2180
|
ArtistSongs,
|
|
2208
2181
|
{
|
|
2209
2182
|
artist: { uuid: artist.uuid, name: artist.name },
|
|
@@ -2213,7 +2186,7 @@ function useArtistPanel({
|
|
|
2213
2186
|
}
|
|
2214
2187
|
)
|
|
2215
2188
|
] }),
|
|
2216
|
-
extraContent: artist.albums.length > 0 ? /* @__PURE__ */
|
|
2189
|
+
extraContent: artist.albums.length > 0 ? /* @__PURE__ */ jsx35(ArtistDiscography, { albums: artist.albums }) : void 0
|
|
2217
2190
|
};
|
|
2218
2191
|
}
|
|
2219
2192
|
}
|
|
@@ -2227,7 +2200,7 @@ import {
|
|
|
2227
2200
|
|
|
2228
2201
|
// src/genre-tree/song/SongPanelContent.tsx
|
|
2229
2202
|
import { useState as useState9 } from "react";
|
|
2230
|
-
import { Pause as Pause3, Play as
|
|
2203
|
+
import { Pause as Pause3, Play as Play3 } from "lucide-react";
|
|
2231
2204
|
import { ActionBand as ActionBand3, ActionButton as ActionButton5, FieldList as FieldList2, PANEL_LABEL_CLASS, PanelBleed as PanelBleed3, PanelSection as PanelSection6, Skeleton as Skeleton6 } from "@behindthemusictree/ui";
|
|
2232
2205
|
import { PlayStates as PlayStates3, usePlayer as usePlayer10 } from "@behindthemusictree/app-kit/player";
|
|
2233
2206
|
import {
|
|
@@ -2237,7 +2210,7 @@ import {
|
|
|
2237
2210
|
useSongHistory,
|
|
2238
2211
|
useTrackList as useTrackList6
|
|
2239
2212
|
} from "@behindthemusictree/app-kit/genre-tree";
|
|
2240
|
-
import { Fragment as Fragment14, jsx as
|
|
2213
|
+
import { Fragment as Fragment14, jsx as jsx36, jsxs as jsxs25 } from "react/jsx-runtime";
|
|
2241
2214
|
var numberFormat = new Intl.NumberFormat("en");
|
|
2242
2215
|
var dateFormat = new Intl.DateTimeFormat("en", { dateStyle: "medium" });
|
|
2243
2216
|
var externalLink = "text-[var(--color-primary)] hover:underline focus-visible:underline";
|
|
@@ -2245,11 +2218,11 @@ function SongHistory({ uuid, getBackendBaseUrl }) {
|
|
|
2245
2218
|
const [open, setOpen] = useState9(false);
|
|
2246
2219
|
const history = useSongHistory(uuid, getBackendBaseUrl, open);
|
|
2247
2220
|
let body = null;
|
|
2248
|
-
if (history.status === "loading") body = /* @__PURE__ */
|
|
2249
|
-
else if (history.status === "error") body = /* @__PURE__ */
|
|
2221
|
+
if (history.status === "loading") body = /* @__PURE__ */ jsx36(Skeleton6, { className: "h-10", "aria-busy": "true" });
|
|
2222
|
+
else if (history.status === "error") body = /* @__PURE__ */ jsx36("p", { className: "text-red-600", children: "Could not load the history." });
|
|
2250
2223
|
else if (history.status === "success")
|
|
2251
|
-
body = history.entries.length === 0 ? /* @__PURE__ */
|
|
2252
|
-
/* @__PURE__ */
|
|
2224
|
+
body = history.entries.length === 0 ? /* @__PURE__ */ jsx36("p", { className: "text-[var(--color-text-muted)]", children: "No changes yet." }) : /* @__PURE__ */ jsx36("ul", { className: "divide-y divide-[var(--color-border)]", children: history.entries.map((entry) => /* @__PURE__ */ jsxs25("li", { className: "py-1.5 text-body", children: [
|
|
2225
|
+
/* @__PURE__ */ jsx36("span", { className: "font-medium", children: entry.action }),
|
|
2253
2226
|
entry.oldValue !== null || entry.newValue !== null ? /* @__PURE__ */ jsxs25("span", { className: "text-[var(--color-text-muted)]", children: [
|
|
2254
2227
|
" ",
|
|
2255
2228
|
"\u2014 ",
|
|
@@ -2263,9 +2236,9 @@ function SongHistory({ uuid, getBackendBaseUrl }) {
|
|
|
2263
2236
|
dateFormat.format(new Date(entry.createdOn))
|
|
2264
2237
|
] })
|
|
2265
2238
|
] }, entry.uuid)) });
|
|
2266
|
-
return /* @__PURE__ */
|
|
2267
|
-
/* @__PURE__ */
|
|
2268
|
-
/* @__PURE__ */
|
|
2239
|
+
return /* @__PURE__ */ jsx36(PanelBleed3, { padded: true, className: "border-t border-[var(--color-border)]", children: /* @__PURE__ */ jsxs25("details", { onToggle: (event) => setOpen(event.currentTarget.open), className: "pb-2.5", children: [
|
|
2240
|
+
/* @__PURE__ */ jsx36("summary", { className: `mt-2.5 cursor-pointer ${PANEL_LABEL_CLASS}`, children: "History" }),
|
|
2241
|
+
/* @__PURE__ */ jsx36("div", { className: "mt-1.5", children: body })
|
|
2269
2242
|
] }) });
|
|
2270
2243
|
}
|
|
2271
2244
|
function SongPanelContent(props) {
|
|
@@ -2284,13 +2257,13 @@ function SongPanelContent(props) {
|
|
|
2284
2257
|
const genre = song.genre;
|
|
2285
2258
|
fields.push({
|
|
2286
2259
|
label: "Genre",
|
|
2287
|
-
value: onSelectGenre ? /* @__PURE__ */
|
|
2288
|
-
index > 0 && /* @__PURE__ */
|
|
2289
|
-
/* @__PURE__ */
|
|
2260
|
+
value: onSelectGenre ? /* @__PURE__ */ jsx36("button", { type: "button", onClick: () => onSelectGenre(genre), className: "hover:underline", children: genre.name }) : path ? /* @__PURE__ */ jsx36("span", { className: "flex flex-wrap items-center gap-x-1", children: path.map((genrePlaylist, index) => /* @__PURE__ */ jsxs25("span", { children: [
|
|
2261
|
+
index > 0 && /* @__PURE__ */ jsx36("span", { "aria-hidden": "true", children: "\u203A " }),
|
|
2262
|
+
/* @__PURE__ */ jsx36("button", { type: "button", onClick: () => props.onSelectGenrePlaylist?.(genrePlaylist), className: "hover:underline", children: genrePlaylist.name })
|
|
2290
2263
|
] }, genrePlaylist.uuid)) }) : song.genre.name
|
|
2291
2264
|
});
|
|
2292
2265
|
} else {
|
|
2293
|
-
fields.push({ label: "Genre", value: /* @__PURE__ */
|
|
2266
|
+
fields.push({ label: "Genre", value: /* @__PURE__ */ jsx36("span", { className: "text-[var(--color-text-muted)]", children: "No genre" }) });
|
|
2294
2267
|
}
|
|
2295
2268
|
if (song.firstReleaseYear) fields.push({ label: "First released", value: song.firstReleaseYear });
|
|
2296
2269
|
const viewCount = song.youtubeVideo?.viewCount;
|
|
@@ -2300,11 +2273,11 @@ function SongPanelContent(props) {
|
|
|
2300
2273
|
const links = [];
|
|
2301
2274
|
if (musicBrainzUrl)
|
|
2302
2275
|
links.push(
|
|
2303
|
-
/* @__PURE__ */
|
|
2276
|
+
/* @__PURE__ */ jsx36("a", { href: musicBrainzUrl, target: "_blank", rel: "noopener noreferrer", className: externalLink, children: "MusicBrainz" }, "mb")
|
|
2304
2277
|
);
|
|
2305
2278
|
if (song.youtubeVideo)
|
|
2306
2279
|
links.push(
|
|
2307
|
-
/* @__PURE__ */
|
|
2280
|
+
/* @__PURE__ */ jsx36(
|
|
2308
2281
|
"a",
|
|
2309
2282
|
{
|
|
2310
2283
|
href: `https://www.youtube.com/watch?v=${encodeURIComponent(song.youtubeVideo.id)}`,
|
|
@@ -2319,31 +2292,31 @@ function SongPanelContent(props) {
|
|
|
2319
2292
|
if (links.length > 0)
|
|
2320
2293
|
fields.push({
|
|
2321
2294
|
label: "Links",
|
|
2322
|
-
value: /* @__PURE__ */
|
|
2295
|
+
value: /* @__PURE__ */ jsx36("span", { className: "flex gap-3", children: links })
|
|
2323
2296
|
});
|
|
2324
2297
|
return /* @__PURE__ */ jsxs25(Fragment14, { children: [
|
|
2325
|
-
/* @__PURE__ */
|
|
2326
|
-
/* @__PURE__ */
|
|
2298
|
+
/* @__PURE__ */ jsx36(PanelBleed3, { children: /* @__PURE__ */ jsxs25(ActionBand3, { children: [
|
|
2299
|
+
/* @__PURE__ */ jsx36(
|
|
2327
2300
|
ActionButton5,
|
|
2328
2301
|
{
|
|
2329
|
-
icon: isPlaying ? /* @__PURE__ */
|
|
2302
|
+
icon: isPlaying ? /* @__PURE__ */ jsx36(Pause3, { "aria-hidden": "true", className: "w-5 h-5" }) : /* @__PURE__ */ jsx36(Play3, { "aria-hidden": "true", className: "w-5 h-5" }),
|
|
2330
2303
|
label: isPlaying ? "Pause" : "Play",
|
|
2331
2304
|
disabled: !!unplayableReason,
|
|
2332
2305
|
title: unplayableReason ?? void 0,
|
|
2333
2306
|
onClick: () => isCurrent ? handlePlayPauseAction() : playNewTrackListFromTrackUuid(song, scope)
|
|
2334
2307
|
}
|
|
2335
2308
|
),
|
|
2336
|
-
shareUrl && /* @__PURE__ */
|
|
2309
|
+
shareUrl && /* @__PURE__ */ jsx36(ShareActionButton, { target: shareTarget, url: shareUrl })
|
|
2337
2310
|
] }) }),
|
|
2338
|
-
song.artists && song.artists.length > 0 && /* @__PURE__ */
|
|
2339
|
-
/* @__PURE__ */
|
|
2340
|
-
song.essentialGenres && song.essentialGenres.length > 0 && /* @__PURE__ */
|
|
2341
|
-
/* @__PURE__ */
|
|
2311
|
+
song.artists && song.artists.length > 0 && /* @__PURE__ */ jsx36("p", { className: "text-[var(--color-text-muted)]", children: /* @__PURE__ */ jsx36(ArtistNames3, { artists: song.artists, renderArtistLink }) }),
|
|
2312
|
+
/* @__PURE__ */ jsx36(FieldList2, { items: fields }),
|
|
2313
|
+
song.essentialGenres && song.essentialGenres.length > 0 && /* @__PURE__ */ jsx36(PanelSection6, { title: "Essential in", children: /* @__PURE__ */ jsx36("ul", { children: song.essentialGenres.map((genre) => /* @__PURE__ */ jsx36("li", { className: "py-0.5", children: genre.name }, genre.uuid)) }) }),
|
|
2314
|
+
/* @__PURE__ */ jsx36(SongHistory, { uuid: song.uuid, getBackendBaseUrl })
|
|
2342
2315
|
] });
|
|
2343
2316
|
}
|
|
2344
2317
|
|
|
2345
2318
|
// src/genre-tree/song/useSongPanel.tsx
|
|
2346
|
-
import { jsx as
|
|
2319
|
+
import { jsx as jsx37, jsxs as jsxs26 } from "react/jsx-runtime";
|
|
2347
2320
|
function useSongPanel({
|
|
2348
2321
|
uuid,
|
|
2349
2322
|
scope,
|
|
@@ -2365,23 +2338,23 @@ function useSongPanel({
|
|
|
2365
2338
|
...panel,
|
|
2366
2339
|
title: "Song",
|
|
2367
2340
|
content: /* @__PURE__ */ jsxs26("div", { "aria-busy": "true", className: "flex flex-col gap-2.5", children: [
|
|
2368
|
-
/* @__PURE__ */
|
|
2369
|
-
/* @__PURE__ */
|
|
2370
|
-
/* @__PURE__ */
|
|
2371
|
-
/* @__PURE__ */
|
|
2341
|
+
/* @__PURE__ */ jsx37(Skeleton7, { className: "h-3 w-16" }),
|
|
2342
|
+
/* @__PURE__ */ jsx37(Skeleton7, { className: "h-4 w-32" }),
|
|
2343
|
+
/* @__PURE__ */ jsx37(Skeleton7, { className: "h-3 w-16" }),
|
|
2344
|
+
/* @__PURE__ */ jsx37(Skeleton7, { className: "h-4 w-24" })
|
|
2372
2345
|
] })
|
|
2373
2346
|
};
|
|
2374
2347
|
case "not-found":
|
|
2375
2348
|
return {
|
|
2376
2349
|
...panel,
|
|
2377
2350
|
title: "Song not found",
|
|
2378
|
-
content: /* @__PURE__ */
|
|
2351
|
+
content: /* @__PURE__ */ jsx37("p", { className: "text-[var(--color-text-muted)]", children: "This song does not exist." })
|
|
2379
2352
|
};
|
|
2380
2353
|
case "error":
|
|
2381
2354
|
return {
|
|
2382
2355
|
...panel,
|
|
2383
2356
|
title: "Song",
|
|
2384
|
-
content: /* @__PURE__ */
|
|
2357
|
+
content: /* @__PURE__ */ jsx37("p", { className: "text-red-600", children: "Could not load this song." })
|
|
2385
2358
|
};
|
|
2386
2359
|
case "success": {
|
|
2387
2360
|
const { song } = result;
|
|
@@ -2389,7 +2362,7 @@ function useSongPanel({
|
|
|
2389
2362
|
return {
|
|
2390
2363
|
...panel,
|
|
2391
2364
|
title: song.title,
|
|
2392
|
-
content: /* @__PURE__ */
|
|
2365
|
+
content: /* @__PURE__ */ jsx37(
|
|
2393
2366
|
SongPanelContent,
|
|
2394
2367
|
{
|
|
2395
2368
|
song,
|
|
@@ -2442,12 +2415,12 @@ function useEntityPanel({
|
|
|
2442
2415
|
// src/genre-tree/SizeMetricToggle.tsx
|
|
2443
2416
|
import { MdMusicNote, MdVisibility } from "react-icons/md";
|
|
2444
2417
|
import { SegmentedControl } from "@behindthemusictree/ui";
|
|
2445
|
-
import { jsx as
|
|
2418
|
+
import { jsx as jsx38 } from "react/jsx-runtime";
|
|
2446
2419
|
function SizeMetricToggle({
|
|
2447
2420
|
value,
|
|
2448
2421
|
onChange
|
|
2449
2422
|
}) {
|
|
2450
|
-
return /* @__PURE__ */
|
|
2423
|
+
return /* @__PURE__ */ jsx38(
|
|
2451
2424
|
SegmentedControl,
|
|
2452
2425
|
{
|
|
2453
2426
|
variant: "floating",
|
|
@@ -2455,15 +2428,15 @@ function SizeMetricToggle({
|
|
|
2455
2428
|
value,
|
|
2456
2429
|
onChange,
|
|
2457
2430
|
options: [
|
|
2458
|
-
{ value: "songs", label: /* @__PURE__ */
|
|
2459
|
-
{ value: "views", label: /* @__PURE__ */
|
|
2431
|
+
{ value: "songs", label: /* @__PURE__ */ jsx38(MdMusicNote, { size: 18, "aria-hidden": true }), "aria-label": "Size by songs", title: "Node size by song count" },
|
|
2432
|
+
{ value: "views", label: /* @__PURE__ */ jsx38(MdVisibility, { size: 18, "aria-hidden": true }), "aria-label": "Size by views", title: "Node size by song views" }
|
|
2460
2433
|
]
|
|
2461
2434
|
}
|
|
2462
2435
|
);
|
|
2463
2436
|
}
|
|
2464
2437
|
|
|
2465
2438
|
// src/genre-tree/GenreTreeView.tsx
|
|
2466
|
-
import { Fragment as Fragment15, jsx as
|
|
2439
|
+
import { Fragment as Fragment15, jsx as jsx39, jsxs as jsxs27 } from "react/jsx-runtime";
|
|
2467
2440
|
var NO_POP_ROOT_TITLE = "This genre tree has no 'Mainstream Pop' root yet";
|
|
2468
2441
|
var REGIONS_CLASS = "[--gtv-center-left:var(--layout-center-left)] [--gtv-center-right:var(--layout-center-right)] [--gtv-center-top:var(--layout-band-top)]";
|
|
2469
2442
|
var noop = () => {
|
|
@@ -2555,6 +2528,7 @@ function GenreTreeView({
|
|
|
2555
2528
|
isFetching: isTreeFetching,
|
|
2556
2529
|
genrePlaylistByNodeId,
|
|
2557
2530
|
visibleGenrePlaylists,
|
|
2531
|
+
focusUuids,
|
|
2558
2532
|
groupedGenrePlaylistsByRoot,
|
|
2559
2533
|
selectedGenreUuid,
|
|
2560
2534
|
selectGenre,
|
|
@@ -2614,14 +2588,14 @@ function GenreTreeView({
|
|
|
2614
2588
|
const openSongRef = useRef3(openSong);
|
|
2615
2589
|
openSongRef.current = openSong;
|
|
2616
2590
|
const resolvedRenderSongLink = useCallback6(
|
|
2617
|
-
(song) => renderSongLink ? renderSongLink(song) : /* @__PURE__ */
|
|
2591
|
+
(song) => renderSongLink ? renderSongLink(song) : /* @__PURE__ */ jsx39("button", { type: "button", onClick: () => openSongRef.current(song.uuid), className: "hover:underline", children: song.title }),
|
|
2618
2592
|
[renderSongLink]
|
|
2619
2593
|
);
|
|
2620
2594
|
const [expandedSongUuid, setExpandedSongUuid] = useState10(null);
|
|
2621
2595
|
const [expandedArtistUuid, setExpandedArtistUuid] = useState10(null);
|
|
2622
2596
|
const artistBaseUrl = artistSearchBaseUrl ?? getBackendBaseUrl;
|
|
2623
2597
|
const songBaseUrl = getBackendBaseUrl;
|
|
2624
|
-
const resolvedRenderArtistLink = renderArtistLink ?? ((artist) => artist.isSpecialPurpose ? artist.name : /* @__PURE__ */
|
|
2598
|
+
const resolvedRenderArtistLink = renderArtistLink ?? ((artist) => artist.isSpecialPurpose ? artist.name : /* @__PURE__ */ jsx39("button", { type: "button", onClick: () => openArtist(artist.uuid), className: "hover:underline", children: artist.name }));
|
|
2625
2599
|
const getGenrePath = (genre) => {
|
|
2626
2600
|
const path = [];
|
|
2627
2601
|
let current = visibleGenrePlaylists.find((playlist) => playlist.criteria?.uuid === genre.uuid);
|
|
@@ -2663,7 +2637,7 @@ function GenreTreeView({
|
|
|
2663
2637
|
selectGenrePlaylist(genrePlaylist2);
|
|
2664
2638
|
}
|
|
2665
2639
|
});
|
|
2666
|
-
const
|
|
2640
|
+
const otherPanel = overlayPanel ?? (selectedGenreUuid !== null ? void 0 : entityPanel);
|
|
2667
2641
|
const [uncontrolledCollapsed, setUncontrolledCollapsed] = useState10(false);
|
|
2668
2642
|
const [uncontrolledExpanded, setUncontrolledExpanded] = useState10(false);
|
|
2669
2643
|
const isCollapsed = collapsed ?? uncontrolledCollapsed;
|
|
@@ -2691,18 +2665,19 @@ function GenreTreeView({
|
|
|
2691
2665
|
const obscuredInset = useObscuredInset(panelRef);
|
|
2692
2666
|
const hostPanel = { obscuredInset, onNodeStyleResolverChange: handleNodeStyleResolverChange };
|
|
2693
2667
|
const nodeMetric = isArtistFiltered || !canSizeByViews ? "songs" : deferredSizeMetric;
|
|
2694
|
-
const treeNodes = useMemo8(() => toTreeNodes(visibleGenrePlaylists, nodeMetric), [visibleGenrePlaylists, nodeMetric]);
|
|
2668
|
+
const treeNodes = useMemo8(() => toTreeNodes(visibleGenrePlaylists, nodeMetric, focusUuids), [visibleGenrePlaylists, nodeMetric, focusUuids]);
|
|
2695
2669
|
const relations = useGenreNodeRelations(
|
|
2696
2670
|
treeNodes,
|
|
2697
2671
|
!overlayPanel && hasSelectedGenreNode ? selectedNodeId : null,
|
|
2698
2672
|
resolveStyle
|
|
2699
2673
|
);
|
|
2674
|
+
const treeStyles = useMemo8(() => toGenreNodeStyles(relations, visibleGenrePlaylists), [relations, visibleGenrePlaylists]);
|
|
2700
2675
|
const [selectionHistory, setSelectionHistory] = useState10({ current: selectedGenreUuid, previous: null });
|
|
2701
2676
|
if (selectionHistory.current !== selectedGenreUuid) {
|
|
2702
2677
|
setSelectionHistory({ current: selectedGenreUuid, previous: selectionHistory.current ?? selectionHistory.previous });
|
|
2703
2678
|
}
|
|
2704
2679
|
const handlePrevious = selectionHistory.previous ? () => selectGenre(selectionHistory.previous) : void 0;
|
|
2705
|
-
const { showPopup, hidePopup } =
|
|
2680
|
+
const { showPopup, hidePopup } = usePopup4();
|
|
2706
2681
|
const reopenPanel = () => {
|
|
2707
2682
|
setUncontrolledCollapsed(false);
|
|
2708
2683
|
onCollapsedChange?.(false);
|
|
@@ -2742,7 +2717,7 @@ function GenreTreeView({
|
|
|
2742
2717
|
selectGenre(uuid);
|
|
2743
2718
|
},
|
|
2744
2719
|
expanded: isExpanded,
|
|
2745
|
-
|
|
2720
|
+
treeStyles,
|
|
2746
2721
|
playback,
|
|
2747
2722
|
genrePlaylist: selectedGenrePlaylist,
|
|
2748
2723
|
band: {
|
|
@@ -2753,7 +2728,7 @@ function GenreTreeView({
|
|
|
2753
2728
|
onAddChild: readOnly || !criteria ? void 0 : () => handleGenreCreationAction(criteria),
|
|
2754
2729
|
onRename: readOnly || !criteria ? void 0 : () => handleGenreRenameAction(criteria),
|
|
2755
2730
|
onChangeParent: readOnly || !genrePlaylist || !criteria ? void 0 : () => showPopup(
|
|
2756
|
-
/* @__PURE__ */
|
|
2731
|
+
/* @__PURE__ */ jsx39(
|
|
2757
2732
|
ChangeParentPopup,
|
|
2758
2733
|
{
|
|
2759
2734
|
genrePlaylist: { ...genrePlaylist, criteria },
|
|
@@ -2787,15 +2762,15 @@ function GenreTreeView({
|
|
|
2787
2762
|
const isRotationControlled = controlledAllowWheelRotation !== void 0;
|
|
2788
2763
|
const allowWheelRotation = controlledAllowWheelRotation ?? internalAllowWheelRotation;
|
|
2789
2764
|
let activePanel = null;
|
|
2790
|
-
if (
|
|
2765
|
+
if (otherPanel) {
|
|
2791
2766
|
activePanel = {
|
|
2792
|
-
title:
|
|
2793
|
-
content:
|
|
2794
|
-
aside:
|
|
2795
|
-
expanded:
|
|
2796
|
-
onExpandedChange:
|
|
2797
|
-
onClose:
|
|
2798
|
-
|
|
2767
|
+
title: otherPanel.title,
|
|
2768
|
+
content: otherPanel.content,
|
|
2769
|
+
aside: otherPanel.extraContent,
|
|
2770
|
+
expanded: otherPanel.expanded ?? false,
|
|
2771
|
+
onExpandedChange: otherPanel.onExpandedChange,
|
|
2772
|
+
onClose: otherPanel.onClose,
|
|
2773
|
+
searchName: otherPanel.title
|
|
2799
2774
|
};
|
|
2800
2775
|
} else if (selectedGenreUuid) {
|
|
2801
2776
|
activePanel = {
|
|
@@ -2805,38 +2780,28 @@ function GenreTreeView({
|
|
|
2805
2780
|
expanded: isExpanded,
|
|
2806
2781
|
onExpandedChange: changeExpanded,
|
|
2807
2782
|
onClose: clearSelection,
|
|
2808
|
-
|
|
2783
|
+
searchName: genreContent.name,
|
|
2809
2784
|
headerAccent: genreContent.headerAccent
|
|
2810
2785
|
};
|
|
2811
|
-
} else if (builtInPanel) {
|
|
2812
|
-
activePanel = {
|
|
2813
|
-
title: builtInPanel.title,
|
|
2814
|
-
content: builtInPanel.content,
|
|
2815
|
-
aside: builtInPanel.extraContent,
|
|
2816
|
-
expanded: builtInPanel.expanded,
|
|
2817
|
-
onExpandedChange: builtInPanel.onExpandedChange,
|
|
2818
|
-
onClose: builtInPanel.onClose,
|
|
2819
|
-
titleInSearch: true
|
|
2820
|
-
};
|
|
2821
2786
|
}
|
|
2822
2787
|
const isPanelShown = activePanel !== null && (selectedGenreUuid !== null || isTreeReady);
|
|
2823
2788
|
const detailTab = placement === "regions" && activePanel?.onExpandedChange ? {
|
|
2824
2789
|
edge: activePanel.expanded ? { label: "Shrink panel", onClick: () => activePanel.onExpandedChange?.(false) } : isCollapsed ? null : { label: "Hide panel", onClick: () => changeCollapsed(true) },
|
|
2825
2790
|
center: activePanel.expanded ? null : isCollapsed ? { label: "Show panel", onClick: () => changeCollapsed(false) } : activePanel.onExpandedChange ? { label: "Extend panel", onClick: () => activePanel.onExpandedChange?.(true) } : null
|
|
2826
2791
|
} : void 0;
|
|
2827
|
-
const expandButton = placement === "default" && activePanel?.onExpandedChange ? /* @__PURE__ */
|
|
2792
|
+
const expandButton = placement === "default" && activePanel?.onExpandedChange ? /* @__PURE__ */ jsx39(
|
|
2828
2793
|
IconButton2,
|
|
2829
2794
|
{
|
|
2830
2795
|
"aria-label": activePanel.expanded ? "Shrink panel" : "Extend panel",
|
|
2831
2796
|
style: activePanel.headerAccent && { color: "inherit" },
|
|
2832
2797
|
onClick: () => activePanel.onExpandedChange?.(!activePanel.expanded),
|
|
2833
|
-
children: activePanel.expanded ? /* @__PURE__ */
|
|
2798
|
+
children: activePanel.expanded ? /* @__PURE__ */ jsx39(Minimize22, { "aria-hidden": "true", className: "h-4 w-4" }) : /* @__PURE__ */ jsx39(Maximize22, { "aria-hidden": "true", className: "h-4 w-4" })
|
|
2834
2799
|
}
|
|
2835
2800
|
) : null;
|
|
2836
2801
|
const renderArtistFilter = () => {
|
|
2837
2802
|
if (isLoading || !filterArtist) return null;
|
|
2838
2803
|
return /* @__PURE__ */ jsxs27("span", { className: "inline-flex items-center overflow-hidden rounded-full bg-[var(--color-neutral-100)] text-body", children: [
|
|
2839
|
-
/* @__PURE__ */
|
|
2804
|
+
/* @__PURE__ */ jsx39(
|
|
2840
2805
|
"button",
|
|
2841
2806
|
{
|
|
2842
2807
|
type: "button",
|
|
@@ -2848,7 +2813,7 @@ function GenreTreeView({
|
|
|
2848
2813
|
children: filterArtist.name
|
|
2849
2814
|
}
|
|
2850
2815
|
),
|
|
2851
|
-
/* @__PURE__ */
|
|
2816
|
+
/* @__PURE__ */ jsx39(
|
|
2852
2817
|
"button",
|
|
2853
2818
|
{
|
|
2854
2819
|
type: "button",
|
|
@@ -2861,7 +2826,7 @@ function GenreTreeView({
|
|
|
2861
2826
|
] });
|
|
2862
2827
|
};
|
|
2863
2828
|
const actions = /* @__PURE__ */ jsxs27(Fragment15, { children: [
|
|
2864
|
-
!isLoading && !isError && /* @__PURE__ */
|
|
2829
|
+
!isLoading && !isError && /* @__PURE__ */ jsx39(
|
|
2865
2830
|
GenreTreeSearch,
|
|
2866
2831
|
{
|
|
2867
2832
|
artistBaseUrl,
|
|
@@ -2884,9 +2849,9 @@ function GenreTreeView({
|
|
|
2884
2849
|
if (songUuid) changeSong(null);
|
|
2885
2850
|
selectGenre(uuid);
|
|
2886
2851
|
},
|
|
2887
|
-
selectedName:
|
|
2852
|
+
selectedName: activePanel?.searchName ?? null,
|
|
2888
2853
|
onClear: activePanel?.onClose,
|
|
2889
|
-
showClear: activePanel
|
|
2854
|
+
showClear: activePanel !== null,
|
|
2890
2855
|
clearLabel: "Close panel",
|
|
2891
2856
|
onPrevious: handlePrevious,
|
|
2892
2857
|
onQueryChange: onSearchQueryChange,
|
|
@@ -2894,9 +2859,9 @@ function GenreTreeView({
|
|
|
2894
2859
|
extraGroups: extraSearchGroups
|
|
2895
2860
|
}
|
|
2896
2861
|
),
|
|
2897
|
-
!isLoading && !isError && filterArtist && /* @__PURE__ */
|
|
2862
|
+
!isLoading && !isError && filterArtist && /* @__PURE__ */ jsx39("div", { className: "hidden w-full justify-center max-md:flex", children: renderArtistFilter() }),
|
|
2898
2863
|
/* @__PURE__ */ jsxs27("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: [
|
|
2899
|
-
!isLoading && !isError && !isControlled && /* @__PURE__ */
|
|
2864
|
+
!isLoading && !isError && !isControlled && /* @__PURE__ */ jsx39(
|
|
2900
2865
|
SegmentedControl2,
|
|
2901
2866
|
{
|
|
2902
2867
|
"aria-label": "Tree view mode",
|
|
@@ -2910,13 +2875,13 @@ function GenreTreeView({
|
|
|
2910
2875
|
]
|
|
2911
2876
|
}
|
|
2912
2877
|
),
|
|
2913
|
-
!isLoading && !isError && showDisplayOptions && /* @__PURE__ */
|
|
2878
|
+
!isLoading && !isError && showDisplayOptions && /* @__PURE__ */ jsx39(
|
|
2914
2879
|
"div",
|
|
2915
2880
|
{
|
|
2916
2881
|
className: "flex items-center gap-1",
|
|
2917
2882
|
role: "group",
|
|
2918
2883
|
"aria-label": "Tree display options",
|
|
2919
|
-
children: !isRotationControlled && viewMode !== "stacked" && viewMode !== "outline" && /* @__PURE__ */
|
|
2884
|
+
children: !isRotationControlled && viewMode !== "stacked" && viewMode !== "outline" && /* @__PURE__ */ jsx39(
|
|
2920
2885
|
Button,
|
|
2921
2886
|
{
|
|
2922
2887
|
variant: allowWheelRotation ? "default" : "outline",
|
|
@@ -2927,7 +2892,7 @@ function GenreTreeView({
|
|
|
2927
2892
|
)
|
|
2928
2893
|
}
|
|
2929
2894
|
),
|
|
2930
|
-
!isLoading && !isError && !readOnly && showAddRoot && /* @__PURE__ */
|
|
2895
|
+
!isLoading && !isError && !readOnly && showAddRoot && /* @__PURE__ */ jsx39(
|
|
2931
2896
|
IconTextButton,
|
|
2932
2897
|
{
|
|
2933
2898
|
icon: Plus2,
|
|
@@ -2943,36 +2908,37 @@ function GenreTreeView({
|
|
|
2943
2908
|
"data-left-panel": isPanelShown && !isCollapsed ? void 0 : "hidden",
|
|
2944
2909
|
className: ["genre-tree-view relative flex flex-col h-full", placement === "regions" && REGIONS_CLASS, className2].filter(Boolean).join(" "),
|
|
2945
2910
|
children: [
|
|
2946
|
-
/* @__PURE__ */
|
|
2911
|
+
/* @__PURE__ */ jsx39(
|
|
2947
2912
|
"div",
|
|
2948
2913
|
{
|
|
2949
2914
|
className: `actions-container absolute z-30 flex items-center gap-2 ${placement === "regions" ? "left-[calc(var(--layout-gutter)+var(--layout-panel-inset))] top-[calc(var(--layout-gutter)+var(--layout-panel-inset))] md:left-[var(--layout-panel-inset)] md:top-[var(--layout-panel-inset)] max-md:right-[calc(var(--layout-gutter)+var(--layout-panel-inset))] max-md:top-[var(--layout-band-top)] max-md:flex-col max-md:items-stretch" : "left-5 top-5"}`,
|
|
2950
2915
|
children: actions
|
|
2951
2916
|
}
|
|
2952
2917
|
),
|
|
2953
|
-
!isLoading && !isError && filterArtist && /* @__PURE__ */
|
|
2918
|
+
!isLoading && !isError && filterArtist && /* @__PURE__ */ jsx39(
|
|
2954
2919
|
"div",
|
|
2955
2920
|
{
|
|
2956
2921
|
className: `absolute left-1/2 z-30 hidden -translate-x-1/2 md:block ${placement === "regions" ? "top-[calc(var(--layout-gutter)+var(--layout-panel-inset))] md:top-[var(--layout-panel-inset)]" : "top-5"}`,
|
|
2957
2922
|
children: renderArtistFilter()
|
|
2958
2923
|
}
|
|
2959
2924
|
),
|
|
2960
|
-
/* @__PURE__ */
|
|
2961
|
-
!isLoading && !isError && viewMode === "outline" && floatingControlsLeading && /* @__PURE__ */
|
|
2962
|
-
isLoading ? /* @__PURE__ */
|
|
2925
|
+
/* @__PURE__ */ jsx39("div", { className: "content-container flex-1 min-h-0 flex flex-row gap-4", children: /* @__PURE__ */ jsxs27("div", { className: "tree-view-container relative flex-1 min-w-0 flex flex-col h-full", children: [
|
|
2926
|
+
!isLoading && !isError && viewMode === "outline" && floatingControlsLeading && /* @__PURE__ */ jsx39("div", { className: "absolute bottom-3 right-3 z-10", children: floatingControlsLeading }),
|
|
2927
|
+
isLoading ? /* @__PURE__ */ jsx39(GenreTreeViewSkeleton, { viewMode }) : isError ? /* @__PURE__ */ jsxs27("p", { role: "alert", className: "m-auto text-center", children: [
|
|
2963
2928
|
"Couldn't load the genre tree.",
|
|
2964
2929
|
" ",
|
|
2965
|
-
/* @__PURE__ */
|
|
2930
|
+
/* @__PURE__ */ jsx39("button", { type: "button", className: "underline", onClick: refetch, children: "Retry" })
|
|
2966
2931
|
] }) : viewMode === "wheel" ? (
|
|
2967
2932
|
// The info panel's top edge aligns with the tree's; the search bar floats `--layout-panel-inset` below it,
|
|
2968
2933
|
// and the header inset (the bar's height plus that inset) extends the header's fill behind the bar,
|
|
2969
2934
|
// Google Maps style; the 8px bottom padding mirrors the inset above the bar, and the hidden title's height is zeroed.
|
|
2970
2935
|
// The panel's own Zoom in button is hidden: the search bar carries it.
|
|
2971
|
-
/* @__PURE__ */
|
|
2936
|
+
/* @__PURE__ */ jsx39("div", { className: "tree-container search-overlay relative flex-1 w-full min-h-0 ", children: /* @__PURE__ */ jsx39(GenreTreeWheelHandoff, { skeleton: /* @__PURE__ */ jsx39(GenreTreeWheelSkeleton, {}), onRevealedChange: setIsWheelRevealed, children: /* @__PURE__ */ jsx39(
|
|
2972
2937
|
GenrePlaylistTreeWheel,
|
|
2973
2938
|
{
|
|
2974
2939
|
scope,
|
|
2975
2940
|
genrePlaylists: visibleGenrePlaylists,
|
|
2941
|
+
focusUuids,
|
|
2976
2942
|
handleGenreCreationAction,
|
|
2977
2943
|
handleGenreRenameAction,
|
|
2978
2944
|
additionalActions,
|
|
@@ -2987,7 +2953,7 @@ function GenreTreeView({
|
|
|
2987
2953
|
busy,
|
|
2988
2954
|
floatingControlsLeading: floatingControlsLeading || canSizeByViews ? /* @__PURE__ */ jsxs27("div", { className: "flex items-center gap-2", children: [
|
|
2989
2955
|
floatingControlsLeading,
|
|
2990
|
-
canSizeByViews && /* @__PURE__ */
|
|
2956
|
+
canSizeByViews && /* @__PURE__ */ jsx39(SizeMetricToggle, { value: sizeMetric, onChange: changeSizeMetric })
|
|
2991
2957
|
] }) : void 0,
|
|
2992
2958
|
defaultViewport,
|
|
2993
2959
|
viewportRestore,
|
|
@@ -2996,11 +2962,12 @@ function GenreTreeView({
|
|
|
2996
2962
|
) }) })
|
|
2997
2963
|
) : viewMode === "pop-core" ? (
|
|
2998
2964
|
// Same as the wheel: the header inset extends its fill behind the floating search bar, Google Maps style.
|
|
2999
|
-
/* @__PURE__ */
|
|
2965
|
+
/* @__PURE__ */ jsx39("div", { className: "tree-container search-overlay relative flex-1 w-full min-h-0 ", children: /* @__PURE__ */ jsx39(GenreTreeWheelHandoff, { skeleton: /* @__PURE__ */ jsx39(GenreTreeWheelSkeleton, {}), onRevealedChange: setIsWheelRevealed, children: /* @__PURE__ */ jsx39(
|
|
3000
2966
|
GenrePlaylistTreeWheelRadialPopCore,
|
|
3001
2967
|
{
|
|
3002
2968
|
scope,
|
|
3003
2969
|
genrePlaylists: visibleGenrePlaylists,
|
|
2970
|
+
focusUuids,
|
|
3004
2971
|
handleGenreCreationAction,
|
|
3005
2972
|
handleGenreRenameAction,
|
|
3006
2973
|
additionalActions,
|
|
@@ -3015,7 +2982,7 @@ function GenreTreeView({
|
|
|
3015
2982
|
busy,
|
|
3016
2983
|
floatingControlsLeading: floatingControlsLeading || canSizeByViews ? /* @__PURE__ */ jsxs27("div", { className: "flex items-center gap-2", children: [
|
|
3017
2984
|
floatingControlsLeading,
|
|
3018
|
-
canSizeByViews && /* @__PURE__ */
|
|
2985
|
+
canSizeByViews && /* @__PURE__ */ jsx39(SizeMetricToggle, { value: sizeMetric, onChange: changeSizeMetric })
|
|
3019
2986
|
] }) : void 0,
|
|
3020
2987
|
defaultViewport,
|
|
3021
2988
|
viewportRestore,
|
|
@@ -3023,12 +2990,13 @@ function GenreTreeView({
|
|
|
3023
2990
|
...focus
|
|
3024
2991
|
}
|
|
3025
2992
|
) }) })
|
|
3026
|
-
) : viewMode === "outline" ? /* @__PURE__ */
|
|
2993
|
+
) : viewMode === "outline" ? /* @__PURE__ */ jsx39("div", { className: "tree-container flex-1 min-h-0 w-full overflow-y-auto relative", children: /* @__PURE__ */ jsx39(
|
|
3027
2994
|
GenrePlaylistTreeWheelRadialPopCore,
|
|
3028
2995
|
{
|
|
3029
2996
|
outline: true,
|
|
3030
2997
|
scope,
|
|
3031
2998
|
genrePlaylists: visibleGenrePlaylists,
|
|
2999
|
+
focusUuids,
|
|
3032
3000
|
handleGenreCreationAction,
|
|
3033
3001
|
handleGenreRenameAction,
|
|
3034
3002
|
additionalActions,
|
|
@@ -3039,13 +3007,13 @@ function GenreTreeView({
|
|
|
3039
3007
|
selectedNodeId,
|
|
3040
3008
|
readOnly
|
|
3041
3009
|
}
|
|
3042
|
-
) }) : /* @__PURE__ */
|
|
3010
|
+
) }) : /* @__PURE__ */ jsx39("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(
|
|
3043
3011
|
([uuid, genrePlaylistTreePerRoot]) => {
|
|
3044
|
-
return /* @__PURE__ */
|
|
3012
|
+
return /* @__PURE__ */ jsx39(
|
|
3045
3013
|
"div",
|
|
3046
3014
|
{
|
|
3047
3015
|
className: "tree-per-root-container relative shrink-0 h-[28rem] mt-2 mr-16 p-2 bg-[var(--color-neutral-100)] rounded-lg",
|
|
3048
|
-
children: /* @__PURE__ */
|
|
3016
|
+
children: /* @__PURE__ */ jsx39("div", { className: "graph-container relative z-10 h-full", children: /* @__PURE__ */ jsx39(
|
|
3049
3017
|
GenrePlaylistTreePerRoot,
|
|
3050
3018
|
{
|
|
3051
3019
|
scope,
|
|
@@ -3058,6 +3026,7 @@ function GenreTreeView({
|
|
|
3058
3026
|
onNodeHover: handleNodeHover,
|
|
3059
3027
|
...hostPanel,
|
|
3060
3028
|
playback,
|
|
3029
|
+
focusUuids,
|
|
3061
3030
|
selectedNodeId: uuid === selectedGenrePlaylist?.root.uuid ? selectedNodeId : null,
|
|
3062
3031
|
readOnly,
|
|
3063
3032
|
wheelZoom: "modifier",
|
|
@@ -3071,13 +3040,13 @@ function GenreTreeView({
|
|
|
3071
3040
|
);
|
|
3072
3041
|
}
|
|
3073
3042
|
) }),
|
|
3074
|
-
/* @__PURE__ */
|
|
3043
|
+
/* @__PURE__ */ jsx39(
|
|
3075
3044
|
DetailPanel2,
|
|
3076
3045
|
{
|
|
3077
3046
|
ref: panelRef,
|
|
3078
3047
|
side: "left",
|
|
3079
3048
|
title: activePanel?.title ?? "",
|
|
3080
|
-
titleInSearch:
|
|
3049
|
+
titleInSearch: !isLoading && !isError,
|
|
3081
3050
|
headerAccent: activePanel?.headerAccent,
|
|
3082
3051
|
headerActions: expandButton,
|
|
3083
3052
|
onClose: activePanel?.onClose ?? noop,
|
|
@@ -3086,7 +3055,6 @@ function GenreTreeView({
|
|
|
3086
3055
|
onExpandedChange: activePanel?.onExpandedChange,
|
|
3087
3056
|
aside: activePanel?.aside,
|
|
3088
3057
|
edgeTab: detailTab,
|
|
3089
|
-
headerClassName: activePanel?.titleInSearch ? void 0 : "pt-search-clear",
|
|
3090
3058
|
children: activePanel?.aside && !activePanel.expanded ? /* @__PURE__ */ jsxs27(Fragment15, { children: [
|
|
3091
3059
|
activePanel.content,
|
|
3092
3060
|
activePanel.aside
|
|
@@ -3113,7 +3081,7 @@ import { ListMusic } from "lucide-react";
|
|
|
3113
3081
|
import { useTrackList as useTrackList7 } from "@behindthemusictree/app-kit/genre-tree";
|
|
3114
3082
|
import { TrackListOriginType as TrackListOriginType3 } from "@behindthemusictree/app-kit/genre-tree";
|
|
3115
3083
|
import { useTrackNoun as useTrackNoun3 } from "@behindthemusictree/app-kit/track-noun";
|
|
3116
|
-
import { jsx as
|
|
3084
|
+
import { jsx as jsx40, jsxs as jsxs28 } from "react/jsx-runtime";
|
|
3117
3085
|
var useBrowserLayoutEffect = typeof window === "undefined" ? useEffect7 : useLayoutEffect2;
|
|
3118
3086
|
function TrackListSidebar({
|
|
3119
3087
|
className: className2 = "",
|
|
@@ -3225,15 +3193,15 @@ function TrackListSidebar({
|
|
|
3225
3193
|
/* @__PURE__ */ jsxs28("div", { className: "header flex h-16 items-center px-4 py-2 text-[var(--color-text)]", children: [
|
|
3226
3194
|
/* @__PURE__ */ jsxs28("div", { className: "min-w-0 flex flex-1 flex-col justify-center", children: [
|
|
3227
3195
|
/* @__PURE__ */ jsxs28("div", { className: "origin flex text-xl", children: [
|
|
3228
|
-
/* @__PURE__ */
|
|
3229
|
-
/* @__PURE__ */
|
|
3196
|
+
/* @__PURE__ */ jsx40("div", { className: "from h-auto flex flex-col justify-center items-center mr-2", children: "From" }),
|
|
3197
|
+
/* @__PURE__ */ jsx40("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__ */ jsx40("div", { className: "name max-w-full truncate", children: trackList.origin.label }) })
|
|
3230
3198
|
] }),
|
|
3231
3199
|
/* @__PURE__ */ jsxs28("div", { className: "info flex items-center text-body text-[var(--color-text-muted)]", children: [
|
|
3232
3200
|
trackList.origin.type === TrackListOriginType3.GENRE_PLAYLIST ? "Genre \u2022 " : trackList.origin.type === TrackListOriginType3.ARTIST ? "Artist \u2022 " : `${trackNoun.singular} playlist \u2022 `,
|
|
3233
3201
|
`${trackList.total} ${trackList.total > 1 ? trackNoun.plural : trackNoun.singular}`
|
|
3234
3202
|
] })
|
|
3235
3203
|
] }),
|
|
3236
|
-
(isCollapsed && onExpand || !isCollapsed && onMinimize) && /* @__PURE__ */
|
|
3204
|
+
(isCollapsed && onExpand || !isCollapsed && onMinimize) && /* @__PURE__ */ jsx40(
|
|
3237
3205
|
"button",
|
|
3238
3206
|
{
|
|
3239
3207
|
type: "button",
|
|
@@ -3242,7 +3210,7 @@ function TrackListSidebar({
|
|
|
3242
3210
|
"aria-expanded": !isCollapsed,
|
|
3243
3211
|
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"}`,
|
|
3244
3212
|
onClick: isCollapsed ? onExpand : onMinimize,
|
|
3245
|
-
children: /* @__PURE__ */
|
|
3213
|
+
children: /* @__PURE__ */ jsx40(ListMusic, { "aria-hidden": "true", className: "h-5 w-5" })
|
|
3246
3214
|
}
|
|
3247
3215
|
)
|
|
3248
3216
|
] }),
|
|
@@ -3256,7 +3224,7 @@ function TrackListSidebar({
|
|
|
3256
3224
|
onPointerDown: markUserScrollIntent,
|
|
3257
3225
|
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",
|
|
3258
3226
|
children: [
|
|
3259
|
-
trackList.tracks.map((track, index) => /* @__PURE__ */
|
|
3227
|
+
trackList.tracks.map((track, index) => /* @__PURE__ */ jsx40("li", { "data-track-uuid": track.uuid, children: /* @__PURE__ */ jsx40(
|
|
3260
3228
|
TrackItem,
|
|
3261
3229
|
{
|
|
3262
3230
|
track,
|
|
@@ -3267,7 +3235,7 @@ function TrackListSidebar({
|
|
|
3267
3235
|
renderSongLink
|
|
3268
3236
|
}
|
|
3269
3237
|
) }, track.uuid)),
|
|
3270
|
-
hasMore && /* @__PURE__ */
|
|
3238
|
+
hasMore && /* @__PURE__ */ jsx40("li", { ref: loadMoreSentinelRef, "aria-hidden": "true", className: "h-px" })
|
|
3271
3239
|
]
|
|
3272
3240
|
}
|
|
3273
3241
|
)
|
|
@@ -3289,10 +3257,10 @@ import {
|
|
|
3289
3257
|
import { PanelEdgeTab } from "@behindthemusictree/ui";
|
|
3290
3258
|
|
|
3291
3259
|
// src/genre-tree/PlayerControls.tsx
|
|
3292
|
-
import { Pause as Pause4, Play as
|
|
3260
|
+
import { Pause as Pause4, Play as Play4, SkipBack, SkipForward, Volume2, VolumeX } from "lucide-react";
|
|
3293
3261
|
import { formatTime, useTrackList as useTrackList8 } from "@behindthemusictree/app-kit/genre-tree";
|
|
3294
3262
|
import { PlayStates as PlayStates4, useCurrentTime, usePlayer as usePlayer11 } from "@behindthemusictree/app-kit/player";
|
|
3295
|
-
import { jsx as
|
|
3263
|
+
import { jsx as jsx41, jsxs as jsxs29 } from "react/jsx-runtime";
|
|
3296
3264
|
function PlayerControls() {
|
|
3297
3265
|
const {
|
|
3298
3266
|
duration,
|
|
@@ -3318,8 +3286,8 @@ function PlayerControls() {
|
|
|
3318
3286
|
className: "player-controls flex shrink-0 flex-col gap-2 border-b border-zinc-800 px-3 py-2 text-zinc-200",
|
|
3319
3287
|
children: [
|
|
3320
3288
|
/* @__PURE__ */ jsxs29("div", { className: "flex min-w-0 items-center gap-2 text-xs tabular-nums text-zinc-400", children: [
|
|
3321
|
-
/* @__PURE__ */
|
|
3322
|
-
/* @__PURE__ */
|
|
3289
|
+
/* @__PURE__ */ jsx41("span", { "aria-label": "Elapsed time", children: formatTime(safeCurrentTime) }),
|
|
3290
|
+
/* @__PURE__ */ jsx41(
|
|
3323
3291
|
"input",
|
|
3324
3292
|
{
|
|
3325
3293
|
"aria-label": "Seek",
|
|
@@ -3333,11 +3301,11 @@ function PlayerControls() {
|
|
|
3333
3301
|
onChange: (event) => seekTo(Number(event.currentTarget.value))
|
|
3334
3302
|
}
|
|
3335
3303
|
),
|
|
3336
|
-
/* @__PURE__ */
|
|
3304
|
+
/* @__PURE__ */ jsx41("span", { "aria-label": "Duration", children: formatTime(safeDuration) })
|
|
3337
3305
|
] }),
|
|
3338
3306
|
/* @__PURE__ */ jsxs29("div", { className: "grid min-h-9 grid-cols-[1fr_auto_1fr] items-center gap-3", children: [
|
|
3339
3307
|
/* @__PURE__ */ jsxs29("div", { className: "col-start-2 flex items-center justify-center gap-2", children: [
|
|
3340
|
-
/* @__PURE__ */
|
|
3308
|
+
/* @__PURE__ */ jsx41(
|
|
3341
3309
|
"button",
|
|
3342
3310
|
{
|
|
3343
3311
|
type: "button",
|
|
@@ -3346,10 +3314,10 @@ function PlayerControls() {
|
|
|
3346
3314
|
disabled: !isReady || !hasPreviousTrack,
|
|
3347
3315
|
onClick: playPreviousTrack,
|
|
3348
3316
|
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",
|
|
3349
|
-
children: /* @__PURE__ */
|
|
3317
|
+
children: /* @__PURE__ */ jsx41(SkipBack, { "aria-hidden": "true", className: "h-4 w-4" })
|
|
3350
3318
|
}
|
|
3351
3319
|
),
|
|
3352
|
-
/* @__PURE__ */
|
|
3320
|
+
/* @__PURE__ */ jsx41(
|
|
3353
3321
|
"button",
|
|
3354
3322
|
{
|
|
3355
3323
|
type: "button",
|
|
@@ -3358,10 +3326,10 @@ function PlayerControls() {
|
|
|
3358
3326
|
disabled: !isReady,
|
|
3359
3327
|
onClick: handlePlayPauseAction,
|
|
3360
3328
|
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",
|
|
3361
|
-
children: isPlaying ? /* @__PURE__ */
|
|
3329
|
+
children: isPlaying ? /* @__PURE__ */ jsx41(Pause4, { "aria-hidden": "true", className: "h-4 w-4", fill: "currentColor" }) : /* @__PURE__ */ jsx41(Play4, { "aria-hidden": "true", className: "h-4 w-4", fill: "currentColor" })
|
|
3362
3330
|
}
|
|
3363
3331
|
),
|
|
3364
|
-
/* @__PURE__ */
|
|
3332
|
+
/* @__PURE__ */ jsx41(
|
|
3365
3333
|
"button",
|
|
3366
3334
|
{
|
|
3367
3335
|
type: "button",
|
|
@@ -3370,14 +3338,14 @@ function PlayerControls() {
|
|
|
3370
3338
|
disabled: !isReady || !hasNextTrack,
|
|
3371
3339
|
onClick: playNextTrack,
|
|
3372
3340
|
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",
|
|
3373
|
-
children: /* @__PURE__ */
|
|
3341
|
+
children: /* @__PURE__ */ jsx41(SkipForward, { "aria-hidden": "true", className: "h-4 w-4" })
|
|
3374
3342
|
}
|
|
3375
3343
|
)
|
|
3376
3344
|
] }),
|
|
3377
3345
|
/* @__PURE__ */ jsxs29("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: [
|
|
3378
|
-
volume === 0 ? /* @__PURE__ */
|
|
3379
|
-
/* @__PURE__ */
|
|
3380
|
-
/* @__PURE__ */
|
|
3346
|
+
volume === 0 ? /* @__PURE__ */ jsx41(VolumeX, { "aria-hidden": "true", className: "h-[0.7rem] w-[0.7rem] shrink-0" }) : /* @__PURE__ */ jsx41(Volume2, { "aria-hidden": "true", className: "h-[0.7rem] w-[0.7rem] shrink-0" }),
|
|
3347
|
+
/* @__PURE__ */ jsx41("span", { className: "sr-only", children: "Volume" }),
|
|
3348
|
+
/* @__PURE__ */ jsx41(
|
|
3381
3349
|
"input",
|
|
3382
3350
|
{
|
|
3383
3351
|
"aria-label": "Volume",
|
|
@@ -3399,7 +3367,7 @@ function PlayerControls() {
|
|
|
3399
3367
|
}
|
|
3400
3368
|
|
|
3401
3369
|
// src/genre-tree/PlayerPanel.tsx
|
|
3402
|
-
import { jsx as
|
|
3370
|
+
import { jsx as jsx42, jsxs as jsxs30 } from "react/jsx-runtime";
|
|
3403
3371
|
var PANEL_ID = "player-panel";
|
|
3404
3372
|
var DEFAULT_EXTENDED_WIDTH = "calc(100vw - var(--layout-center-left) - var(--layout-gutter))";
|
|
3405
3373
|
function PlayerPanel({
|
|
@@ -3452,7 +3420,7 @@ function PlayerPanel({
|
|
|
3452
3420
|
),
|
|
3453
3421
|
style: isExtended ? { width: extendedWidth } : void 0,
|
|
3454
3422
|
children: [
|
|
3455
|
-
/* @__PURE__ */
|
|
3423
|
+
/* @__PURE__ */ jsx42(
|
|
3456
3424
|
PanelEdgeTab,
|
|
3457
3425
|
{
|
|
3458
3426
|
side: "right",
|
|
@@ -3471,19 +3439,19 @@ function PlayerPanel({
|
|
|
3471
3439
|
),
|
|
3472
3440
|
children: [
|
|
3473
3441
|
/* @__PURE__ */ jsxs30("div", { className: "flex w-[var(--layout-right-w)] shrink-0 flex-col", children: [
|
|
3474
|
-
/* @__PURE__ */
|
|
3442
|
+
/* @__PURE__ */ jsx42("div", { className: "flex shrink-0 items-center justify-between gap-2 border-b border-zinc-800 p-2", children: /* @__PURE__ */ jsx42("span", { className: "min-w-0 truncate text-sm font-semibold", children: loadedTrackTitle || lastLoadedTrackTitle }) }),
|
|
3475
3443
|
/* @__PURE__ */ jsxs30("div", { className: "relative w-full shrink-0", children: [
|
|
3476
|
-
/* @__PURE__ */
|
|
3444
|
+
/* @__PURE__ */ jsx42(PlayerVideoSurface, { className: "aspect-video w-full bg-black" }),
|
|
3477
3445
|
playerTrackObject?.loadError && /* @__PURE__ */ jsxs30("span", { className: "absolute bottom-2 left-2 right-2 text-xs text-red-400", children: [
|
|
3478
3446
|
playerTrackObject.loadError,
|
|
3479
|
-
/* @__PURE__ */
|
|
3447
|
+
/* @__PURE__ */ jsx42("button", { type: "button", className: "ml-2 underline", onClick: () => {
|
|
3480
3448
|
void retryPlayback();
|
|
3481
3449
|
}, children: "Retry" })
|
|
3482
3450
|
] })
|
|
3483
3451
|
] }),
|
|
3484
|
-
/* @__PURE__ */
|
|
3452
|
+
/* @__PURE__ */ jsx42(PlayerControls, {})
|
|
3485
3453
|
] }),
|
|
3486
|
-
/* @__PURE__ */
|
|
3454
|
+
/* @__PURE__ */ jsx42(
|
|
3487
3455
|
TrackListSidebar,
|
|
3488
3456
|
{
|
|
3489
3457
|
layout: "inline",
|
|
@@ -3510,11 +3478,11 @@ function PlayerPanel({
|
|
|
3510
3478
|
import { v4 as uuidv4 } from "uuid";
|
|
3511
3479
|
import { AiFillStar, AiOutlineStar } from "react-icons/ai";
|
|
3512
3480
|
import { FORM_RATING_NULL_VALUE } from "@behindthemusictree/app-kit/genre-tree";
|
|
3513
|
-
import { jsx as
|
|
3481
|
+
import { jsx as jsx43, jsxs as jsxs31 } from "react/jsx-runtime";
|
|
3514
3482
|
function Rating({ rating, handleChange }) {
|
|
3515
3483
|
const instanceId = uuidv4();
|
|
3516
|
-
return /* @__PURE__ */
|
|
3517
|
-
/* @__PURE__ */
|
|
3484
|
+
return /* @__PURE__ */ jsx43("div", { className: "flex items-center", children: [...Array(6)].map((_, i) => /* @__PURE__ */ jsxs31("div", { className: `relative ${i === 0 ? "mr-4" : "mr-1"}`, children: [
|
|
3485
|
+
/* @__PURE__ */ jsx43(
|
|
3518
3486
|
"input",
|
|
3519
3487
|
{
|
|
3520
3488
|
id: `star-${instanceId}-${i}`,
|
|
@@ -3526,16 +3494,16 @@ function Rating({ rating, handleChange }) {
|
|
|
3526
3494
|
onChange: handleChange
|
|
3527
3495
|
}
|
|
3528
3496
|
),
|
|
3529
|
-
/* @__PURE__ */
|
|
3530
|
-
/* @__PURE__ */
|
|
3497
|
+
/* @__PURE__ */ jsx43("label", { htmlFor: `star-${instanceId}-${i}`, className: "cursor-pointer", children: i === 0 ? /* @__PURE__ */ jsxs31("div", { className: "flex", children: [
|
|
3498
|
+
/* @__PURE__ */ jsx43(
|
|
3531
3499
|
AiOutlineStar,
|
|
3532
3500
|
{
|
|
3533
3501
|
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)]"}`
|
|
3534
3502
|
}
|
|
3535
3503
|
),
|
|
3536
|
-
/* @__PURE__ */
|
|
3504
|
+
/* @__PURE__ */ jsx43("span", { className: "flex-grow w-8" }),
|
|
3537
3505
|
" "
|
|
3538
|
-
] }) : /* @__PURE__ */
|
|
3506
|
+
] }) : /* @__PURE__ */ jsx43(
|
|
3539
3507
|
AiFillStar,
|
|
3540
3508
|
{
|
|
3541
3509
|
className: `w-7 h-7 absolute top-0 left-0 ${(rating ?? -1) >= i ? "text-[var(--color-accent-rating)]" : "text-[var(--color-text-muted)]"}`
|
|
@@ -3547,7 +3515,7 @@ function Rating({ rating, handleChange }) {
|
|
|
3547
3515
|
// src/genre-tree/EntityDetailPanel.tsx
|
|
3548
3516
|
import { useState as useState12 } from "react";
|
|
3549
3517
|
import { DetailPanel as DetailPanel3 } from "@behindthemusictree/ui";
|
|
3550
|
-
import { Fragment as Fragment16, jsx as
|
|
3518
|
+
import { Fragment as Fragment16, jsx as jsx44, jsxs as jsxs32 } from "react/jsx-runtime";
|
|
3551
3519
|
function EntityDetailPanel({
|
|
3552
3520
|
scope,
|
|
3553
3521
|
getBackendBaseUrl,
|
|
@@ -3570,8 +3538,8 @@ function EntityDetailPanel({
|
|
|
3570
3538
|
getBackendBaseUrl,
|
|
3571
3539
|
getArtistBackendBaseUrl,
|
|
3572
3540
|
getShareUrl,
|
|
3573
|
-
renderArtistLink: renderArtistLink ?? ((artist) => artist.isSpecialPurpose ? artist.name : /* @__PURE__ */
|
|
3574
|
-
renderSongLink: renderSongLink ?? ((song) => /* @__PURE__ */
|
|
3541
|
+
renderArtistLink: renderArtistLink ?? ((artist) => artist.isSpecialPurpose ? artist.name : /* @__PURE__ */ jsx44("button", { type: "button", onClick: () => onArtistUuidChange(artist.uuid), className: "hover:underline", children: artist.name })),
|
|
3542
|
+
renderSongLink: renderSongLink ?? ((song) => /* @__PURE__ */ jsx44("button", { type: "button", onClick: () => onSongUuidChange(song.uuid), className: "hover:underline", children: song.title })),
|
|
3575
3543
|
song: {
|
|
3576
3544
|
uuid: songUuid,
|
|
3577
3545
|
expanded: songUuid !== null && expandedSongUuid === songUuid,
|
|
@@ -3587,7 +3555,7 @@ function EntityDetailPanel({
|
|
|
3587
3555
|
...navigation
|
|
3588
3556
|
});
|
|
3589
3557
|
if (!panel) return null;
|
|
3590
|
-
return /* @__PURE__ */
|
|
3558
|
+
return /* @__PURE__ */ jsx44(
|
|
3591
3559
|
DetailPanel3,
|
|
3592
3560
|
{
|
|
3593
3561
|
side: "left",
|
|
@@ -3633,4 +3601,4 @@ export {
|
|
|
3633
3601
|
GenreTreeViewSkeleton2 as GenreTreeViewSkeleton,
|
|
3634
3602
|
GenreTreeOutlineSkeleton
|
|
3635
3603
|
};
|
|
3636
|
-
//# sourceMappingURL=chunk-
|
|
3604
|
+
//# sourceMappingURL=chunk-DPYUE6WD.js.map
|