@behindthemusictree/app-kit-ui 39.0.0 → 40.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-2K2SQOUJ.js → chunk-I2TEOHVG.js} +345 -371
- package/dist/chunk-I2TEOHVG.js.map +1 -0
- package/dist/genre-tree/index.cjs +426 -453
- 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 +421 -448
- 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,7 +41,8 @@ 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
|
|
|
@@ -53,24 +54,27 @@ import {
|
|
|
53
54
|
getGenreTreeColor
|
|
54
55
|
} from "@behindthemusictree/genre-tree-view";
|
|
55
56
|
import { usePlayer } from "@behindthemusictree/app-kit/player";
|
|
56
|
-
import { usePopup } from "@behindthemusictree/app-kit/popup";
|
|
57
|
-
import { ErrorCode } from "@behindthemusictree/app-kit/transport";
|
|
58
57
|
|
|
59
|
-
// src/genre-tree/playlist-tree/useGenrePlaylistPlayback.
|
|
58
|
+
// src/genre-tree/playlist-tree/useGenrePlaylistPlayback.tsx
|
|
60
59
|
import { useCallback, useMemo } from "react";
|
|
61
60
|
import {
|
|
62
61
|
TrackListOriginType,
|
|
62
|
+
TracksFailureAlreadyReportedError,
|
|
63
63
|
useTrackList,
|
|
64
64
|
GenreCatalogueCountsSchema,
|
|
65
65
|
defaultGenreMusicSelection,
|
|
66
66
|
genreMusicSelectionKey
|
|
67
67
|
} from "@behindthemusictree/app-kit/genre-tree";
|
|
68
|
+
import { usePopup } from "@behindthemusictree/app-kit/popup";
|
|
69
|
+
import { AppError, ErrorCode } from "@behindthemusictree/app-kit/transport";
|
|
70
|
+
import { jsx } from "react/jsx-runtime";
|
|
68
71
|
function useGenrePlaylistPlayback({
|
|
69
72
|
scope,
|
|
70
73
|
genrePlaylists,
|
|
71
74
|
artist = null
|
|
72
75
|
}) {
|
|
73
76
|
const { trackList, playNewTrackListFromGenrePlaylist } = useTrackList();
|
|
77
|
+
const { showPopup } = usePopup();
|
|
74
78
|
const origin = trackList?.origin;
|
|
75
79
|
const playing = useMemo(() => {
|
|
76
80
|
if (!origin || origin.type !== TrackListOriginType.GENRE_PLAYLIST || origin.scope !== scope) return null;
|
|
@@ -82,14 +86,20 @@ function useGenrePlaylistPlayback({
|
|
|
82
86
|
}, [origin, artist, genrePlaylists, scope]);
|
|
83
87
|
const play = useCallback(async (playlist, requested) => {
|
|
84
88
|
if (artist && !playlist.criteria) return;
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
89
|
+
try {
|
|
90
|
+
const selection = scope === "reference" && playlist.criteria !== null ? requested ?? defaultGenreMusicSelection(GenreCatalogueCountsSchema.parse(playlist)) : void 0;
|
|
91
|
+
await (selection || artist ? playNewTrackListFromGenrePlaylist(playlist, scope, { selection, ...artist && { artistUuid: artist.uuid } }) : playNewTrackListFromGenrePlaylist(playlist, scope));
|
|
92
|
+
} catch (error) {
|
|
93
|
+
console.error("Failed to load genre playlist tracks:", error);
|
|
94
|
+
if (error instanceof TracksFailureAlreadyReportedError) return;
|
|
95
|
+
showPopup(/* @__PURE__ */ jsx(InternalErrorPopup, { errorCode: error instanceof AppError ? error.code : ErrorCode.CLIENT_UNKNOWN }));
|
|
96
|
+
}
|
|
97
|
+
}, [artist, scope, playNewTrackListFromGenrePlaylist, showPopup]);
|
|
88
98
|
return useMemo(() => ({ playing, play }), [playing, play]);
|
|
89
99
|
}
|
|
90
100
|
|
|
91
101
|
// src/genre-tree/playlist-tree/TreePerRoot.tsx
|
|
92
|
-
import { jsx } from "react/jsx-runtime";
|
|
102
|
+
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
93
103
|
function GenrePlaylistTreePerRoot({
|
|
94
104
|
scope,
|
|
95
105
|
className: className2,
|
|
@@ -108,25 +118,16 @@ function GenrePlaylistTreePerRoot({
|
|
|
108
118
|
viewportRestore,
|
|
109
119
|
onViewportChange,
|
|
110
120
|
playback,
|
|
121
|
+
focusUuids,
|
|
111
122
|
...hostPanel
|
|
112
123
|
}) {
|
|
113
124
|
const { isPlaying, setIsPlaying } = usePlayer();
|
|
114
125
|
const defaultPlayback = useGenrePlaylistPlayback({ scope, genrePlaylists: genrePlaylistTreePerRoot });
|
|
115
126
|
const { playing, play } = playback ?? defaultPlayback;
|
|
116
127
|
const playingNodeId = playing?.uuid ?? null;
|
|
117
|
-
const { showPopup } = usePopup();
|
|
118
128
|
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]
|
|
129
|
+
() => toTreeNodes(genrePlaylistTreePerRoot, "songs", focusUuids),
|
|
130
|
+
[genrePlaylistTreePerRoot, focusUuids]
|
|
130
131
|
);
|
|
131
132
|
const handlePlayPause = useCallback2(
|
|
132
133
|
(nodeId) => {
|
|
@@ -139,18 +140,14 @@ function GenrePlaylistTreePerRoot({
|
|
|
139
140
|
if (genrePlaylistTrackCount2(genrePlaylist) === 0) {
|
|
140
141
|
return;
|
|
141
142
|
}
|
|
142
|
-
play(genrePlaylist)
|
|
143
|
-
console.error("Failed to load genre playlist tracks:", error);
|
|
144
|
-
showPopup(/* @__PURE__ */ jsx(InternalErrorPopup, { errorCode: ErrorCode.CLIENT_UNKNOWN }));
|
|
145
|
-
});
|
|
143
|
+
void play(genrePlaylist);
|
|
146
144
|
},
|
|
147
145
|
[
|
|
148
146
|
genrePlaylistTreePerRoot,
|
|
149
147
|
playingNodeId,
|
|
150
148
|
isPlaying,
|
|
151
149
|
setIsPlaying,
|
|
152
|
-
play
|
|
153
|
-
showPopup
|
|
150
|
+
play
|
|
154
151
|
]
|
|
155
152
|
);
|
|
156
153
|
const handleAddChild = useCallback2(
|
|
@@ -173,7 +170,7 @@ function GenrePlaylistTreePerRoot({
|
|
|
173
170
|
if (confirm(`Are you sure you want to delete "${node.name}"?`)) {
|
|
174
171
|
}
|
|
175
172
|
}, []);
|
|
176
|
-
return /* @__PURE__ */
|
|
173
|
+
return /* @__PURE__ */ jsx2(
|
|
177
174
|
GenreTree,
|
|
178
175
|
{
|
|
179
176
|
className: className2,
|
|
@@ -206,9 +203,7 @@ import {
|
|
|
206
203
|
GenreTreeWheel
|
|
207
204
|
} from "@behindthemusictree/genre-tree-view";
|
|
208
205
|
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";
|
|
206
|
+
import { jsx as jsx3 } from "react/jsx-runtime";
|
|
212
207
|
function GenrePlaylistTreeWheel({
|
|
213
208
|
scope,
|
|
214
209
|
className: className2,
|
|
@@ -229,24 +224,16 @@ function GenrePlaylistTreeWheel({
|
|
|
229
224
|
viewportRestore,
|
|
230
225
|
onViewportChange,
|
|
231
226
|
playback,
|
|
227
|
+
focusUuids,
|
|
232
228
|
...hostPanel
|
|
233
229
|
}) {
|
|
234
230
|
const { isPlaying, setIsPlaying } = usePlayer2();
|
|
235
231
|
const defaultPlayback = useGenrePlaylistPlayback({ scope, genrePlaylists });
|
|
236
232
|
const { playing, play } = playback ?? defaultPlayback;
|
|
237
233
|
const playingNodeId = playing?.uuid ?? null;
|
|
238
|
-
const { showPopup } = usePopup2();
|
|
239
234
|
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]
|
|
235
|
+
() => toTreeNodes(genrePlaylists, sizeMetric, focusUuids),
|
|
236
|
+
[genrePlaylists, sizeMetric, focusUuids]
|
|
250
237
|
);
|
|
251
238
|
const handlePlayPause = useCallback3(
|
|
252
239
|
(nodeId) => {
|
|
@@ -259,18 +246,14 @@ function GenrePlaylistTreeWheel({
|
|
|
259
246
|
if (genrePlaylistTrackCount3(genrePlaylist) === 0) {
|
|
260
247
|
return;
|
|
261
248
|
}
|
|
262
|
-
play(genrePlaylist)
|
|
263
|
-
console.error("Failed to load genre playlist tracks:", error);
|
|
264
|
-
showPopup(/* @__PURE__ */ jsx2(InternalErrorPopup, { errorCode: ErrorCode2.CLIENT_UNKNOWN }));
|
|
265
|
-
});
|
|
249
|
+
void play(genrePlaylist);
|
|
266
250
|
},
|
|
267
251
|
[
|
|
268
252
|
genrePlaylists,
|
|
269
253
|
playingNodeId,
|
|
270
254
|
isPlaying,
|
|
271
255
|
setIsPlaying,
|
|
272
|
-
play
|
|
273
|
-
showPopup
|
|
256
|
+
play
|
|
274
257
|
]
|
|
275
258
|
);
|
|
276
259
|
const handleAddChild = useCallback3(
|
|
@@ -293,7 +276,7 @@ function GenrePlaylistTreeWheel({
|
|
|
293
276
|
if (confirm(`Are you sure you want to delete "${node.name}"?`)) {
|
|
294
277
|
}
|
|
295
278
|
}, []);
|
|
296
|
-
return /* @__PURE__ */
|
|
279
|
+
return /* @__PURE__ */ jsx3(
|
|
297
280
|
GenreTreeWheel,
|
|
298
281
|
{
|
|
299
282
|
className: className2,
|
|
@@ -328,7 +311,7 @@ import {
|
|
|
328
311
|
GenreTreeWheelRadialPopCore
|
|
329
312
|
} from "@behindthemusictree/genre-tree-view";
|
|
330
313
|
import { usePlayer as usePlayer3 } from "@behindthemusictree/app-kit/player";
|
|
331
|
-
import { jsx as
|
|
314
|
+
import { jsx as jsx4 } from "react/jsx-runtime";
|
|
332
315
|
function GenrePlaylistTreeWheelRadialPopCore(props) {
|
|
333
316
|
const {
|
|
334
317
|
scope,
|
|
@@ -361,7 +344,7 @@ function GenrePlaylistTreeWheelRadialPopCore(props) {
|
|
|
361
344
|
const defaultPlayback = useGenrePlaylistPlayback({ scope, genrePlaylists });
|
|
362
345
|
const { playing, play } = playback ?? defaultPlayback;
|
|
363
346
|
const playingNodeId = playing?.uuid ?? null;
|
|
364
|
-
const nodes = useMemo4(() => toTreeNodes(genrePlaylists, sizeMetric), [genrePlaylists, sizeMetric]);
|
|
347
|
+
const nodes = useMemo4(() => toTreeNodes(genrePlaylists, sizeMetric, props.focusUuids), [genrePlaylists, sizeMetric, props.focusUuids]);
|
|
365
348
|
const handlePlayPause = useCallback4(
|
|
366
349
|
(nodeId) => {
|
|
367
350
|
const genrePlaylist = genrePlaylists.find((g) => g.uuid === nodeId);
|
|
@@ -373,9 +356,7 @@ function GenrePlaylistTreeWheelRadialPopCore(props) {
|
|
|
373
356
|
if (genrePlaylistTrackCount4(genrePlaylist) === 0) {
|
|
374
357
|
return;
|
|
375
358
|
}
|
|
376
|
-
play(genrePlaylist)
|
|
377
|
-
console.error("Failed to load genre playlist tracks:", error);
|
|
378
|
-
});
|
|
359
|
+
void play(genrePlaylist);
|
|
379
360
|
},
|
|
380
361
|
[genrePlaylists, playingNodeId, isPlaying, setIsPlaying, play]
|
|
381
362
|
);
|
|
@@ -415,7 +396,7 @@ function GenrePlaylistTreeWheelRadialPopCore(props) {
|
|
|
415
396
|
onSelectedNodeChange,
|
|
416
397
|
...hostPanel
|
|
417
398
|
};
|
|
418
|
-
return outline ? /* @__PURE__ */
|
|
399
|
+
return outline ? /* @__PURE__ */ jsx4(GenreTreeOutline, { ...treeProps }) : /* @__PURE__ */ jsx4(
|
|
419
400
|
GenreTreeWheelRadialPopCore,
|
|
420
401
|
{
|
|
421
402
|
...treeProps,
|
|
@@ -432,7 +413,7 @@ function GenrePlaylistTreeWheelRadialPopCore(props) {
|
|
|
432
413
|
|
|
433
414
|
// src/genre-tree/GenreTreeWheelHandoff.tsx
|
|
434
415
|
import { useEffect, useRef, useState } from "react";
|
|
435
|
-
import { jsx as
|
|
416
|
+
import { jsx as jsx5, jsxs } from "react/jsx-runtime";
|
|
436
417
|
function GenreTreeWheelHandoff({ skeleton, children, onRevealedChange }) {
|
|
437
418
|
const [revealed, setRevealed] = useState(false);
|
|
438
419
|
const onRevealedChangeRef = useRef(onRevealedChange);
|
|
@@ -452,7 +433,7 @@ function GenreTreeWheelHandoff({ skeleton, children, onRevealedChange }) {
|
|
|
452
433
|
};
|
|
453
434
|
}, []);
|
|
454
435
|
return /* @__PURE__ */ jsxs("div", { className: "relative w-full h-full", children: [
|
|
455
|
-
/* @__PURE__ */
|
|
436
|
+
/* @__PURE__ */ jsx5(
|
|
456
437
|
"div",
|
|
457
438
|
{
|
|
458
439
|
className: "absolute inset-0 transition-opacity duration-150 ease-out",
|
|
@@ -461,7 +442,7 @@ function GenreTreeWheelHandoff({ skeleton, children, onRevealedChange }) {
|
|
|
461
442
|
children
|
|
462
443
|
}
|
|
463
444
|
),
|
|
464
|
-
!revealed && /* @__PURE__ */
|
|
445
|
+
!revealed && /* @__PURE__ */ jsx5("div", { className: "absolute inset-0", "aria-hidden": "true", children: skeleton })
|
|
465
446
|
] });
|
|
466
447
|
}
|
|
467
448
|
|
|
@@ -476,7 +457,7 @@ import { useGenreSearch } from "@behindthemusictree/app-kit/genre-tree";
|
|
|
476
457
|
// src/genre-tree/search/SearchBox.tsx
|
|
477
458
|
import { useState as useState2 } from "react";
|
|
478
459
|
import { SearchCombobox } from "@behindthemusictree/ui";
|
|
479
|
-
import { jsx as
|
|
460
|
+
import { jsx as jsx6 } from "react/jsx-runtime";
|
|
480
461
|
function SearchBox({
|
|
481
462
|
label,
|
|
482
463
|
placeholder,
|
|
@@ -498,7 +479,7 @@ function SearchBox({
|
|
|
498
479
|
groups.find((group) => group.key === groupKey)?.items.find((item) => item.key === itemKey)?.onSelect();
|
|
499
480
|
onPicked?.(groupKey, itemKey);
|
|
500
481
|
};
|
|
501
|
-
return /* @__PURE__ */
|
|
482
|
+
return /* @__PURE__ */ jsx6("div", { className: className2, onFocusCapture: onFocus, children: /* @__PURE__ */ jsx6(
|
|
502
483
|
SearchCombobox,
|
|
503
484
|
{
|
|
504
485
|
ariaLabel: label,
|
|
@@ -564,7 +545,7 @@ import {
|
|
|
564
545
|
isSongSearchResultPlayable,
|
|
565
546
|
useSongSearch
|
|
566
547
|
} from "@behindthemusictree/app-kit/genre-tree";
|
|
567
|
-
import { jsx as
|
|
548
|
+
import { jsx as jsx7, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
568
549
|
function useSongSearchGroup(getBaseUrl, text, onSelect, enabled = true) {
|
|
569
550
|
const search = useSongSearch(getBaseUrl, enabled ? text : "");
|
|
570
551
|
if (!enabled) return void 0;
|
|
@@ -574,8 +555,8 @@ function useSongSearchGroup(getBaseUrl, text, onSelect, enabled = true) {
|
|
|
574
555
|
items: search.songs.map((song) => ({
|
|
575
556
|
key: song.uuid,
|
|
576
557
|
content: /* @__PURE__ */ jsxs3("span", { className: isSongSearchResultPlayable(song) ? void 0 : "opacity-60", children: [
|
|
577
|
-
/* @__PURE__ */
|
|
578
|
-
/* @__PURE__ */
|
|
558
|
+
/* @__PURE__ */ jsx7("span", { className: "block truncate font-medium", children: song.title }),
|
|
559
|
+
/* @__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
560
|
] }),
|
|
580
561
|
onSelect: () => onSelect(song)
|
|
581
562
|
})),
|
|
@@ -588,7 +569,7 @@ function useSongSearchGroup(getBaseUrl, text, onSelect, enabled = true) {
|
|
|
588
569
|
import {
|
|
589
570
|
useGenreRemoteSearch
|
|
590
571
|
} from "@behindthemusictree/app-kit/genre-tree";
|
|
591
|
-
import { Fragment as Fragment2, jsx as
|
|
572
|
+
import { Fragment as Fragment2, jsx as jsx8, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
592
573
|
function useGenreRemoteSearchGroup(getBaseUrl, text, onSelect, { key = "genres", label = "Genres", filter, describe, ...options } = {}) {
|
|
593
574
|
const search = useGenreRemoteSearch(getBaseUrl, text, options);
|
|
594
575
|
const genres = filter ? search.genres.filter(filter) : search.genres;
|
|
@@ -600,9 +581,9 @@ function useGenreRemoteSearchGroup(getBaseUrl, text, onSelect, { key = "genres",
|
|
|
600
581
|
content: /* @__PURE__ */ jsxs4(Fragment2, { children: [
|
|
601
582
|
/* @__PURE__ */ jsxs4("span", { className: "block truncate font-medium", children: [
|
|
602
583
|
genre.name,
|
|
603
|
-
genre.isUmbrella && /* @__PURE__ */
|
|
584
|
+
genre.isUmbrella && /* @__PURE__ */ jsx8("span", { className: "ml-2 text-caption font-normal italic text-[var(--color-text-muted)]", children: "umbrella" })
|
|
604
585
|
] }),
|
|
605
|
-
/* @__PURE__ */
|
|
586
|
+
/* @__PURE__ */ jsx8("span", { className: "block truncate text-caption text-[var(--color-neutral-500)]", children: describe?.(genre) ?? `${genre.treeName} \xB7 ${genre.root.name}` })
|
|
606
587
|
] }),
|
|
607
588
|
onSelect: () => onSelect(genre)
|
|
608
589
|
})),
|
|
@@ -612,7 +593,7 @@ function useGenreRemoteSearchGroup(getBaseUrl, text, onSelect, { key = "genres",
|
|
|
612
593
|
}
|
|
613
594
|
|
|
614
595
|
// src/genre-tree/GenreSearch.tsx
|
|
615
|
-
import { Fragment as Fragment3, jsx as
|
|
596
|
+
import { Fragment as Fragment3, jsx as jsx9, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
616
597
|
function GenreSearch({
|
|
617
598
|
genrePlaylists,
|
|
618
599
|
onSelect,
|
|
@@ -643,7 +624,7 @@ function GenreSearch({
|
|
|
643
624
|
key: genrePlaylist.uuid,
|
|
644
625
|
content: /* @__PURE__ */ jsxs5(Fragment3, { children: [
|
|
645
626
|
genrePlaylist.name,
|
|
646
|
-
genrePlaylist.isUmbrella && /* @__PURE__ */
|
|
627
|
+
genrePlaylist.isUmbrella && /* @__PURE__ */ jsx9("span", { className: "ml-2 text-caption italic text-[var(--color-text-muted)]", children: "umbrella" })
|
|
647
628
|
] }),
|
|
648
629
|
onSelect: () => select(genrePlaylist)
|
|
649
630
|
}))
|
|
@@ -652,7 +633,7 @@ function GenreSearch({
|
|
|
652
633
|
(group) => active ? group : { ...group, items: [], status: "", loading: false }
|
|
653
634
|
)
|
|
654
635
|
];
|
|
655
|
-
return /* @__PURE__ */
|
|
636
|
+
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
637
|
SearchBox,
|
|
657
638
|
{
|
|
658
639
|
label,
|
|
@@ -672,14 +653,14 @@ function GenreSearch({
|
|
|
672
653
|
clear();
|
|
673
654
|
onQueryChange?.("");
|
|
674
655
|
} : void 0,
|
|
675
|
-
leading: onPrevious && /* @__PURE__ */
|
|
656
|
+
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
657
|
onFocus
|
|
677
658
|
}
|
|
678
659
|
) });
|
|
679
660
|
}
|
|
680
661
|
|
|
681
662
|
// src/genre-tree/GenreTreeSearch.tsx
|
|
682
|
-
import { jsx as
|
|
663
|
+
import { jsx as jsx10 } from "react/jsx-runtime";
|
|
683
664
|
function GenreTreeSearch({
|
|
684
665
|
artistBaseUrl,
|
|
685
666
|
songBaseUrl,
|
|
@@ -699,7 +680,7 @@ function GenreTreeSearch({
|
|
|
699
680
|
const deferredQuery = useDeferredValue(query);
|
|
700
681
|
const artistGroup = useArtistSearchGroup(artistBaseUrl, deferredQuery, onArtistSelect, artistSearch);
|
|
701
682
|
const songGroup = useSongSearchGroup(songBaseUrl, deferredQuery, onSongSelect, songSearch);
|
|
702
|
-
const render = (hostGroups) => /* @__PURE__ */
|
|
683
|
+
const render = (hostGroups) => /* @__PURE__ */ jsx10(
|
|
703
684
|
GenreSearch,
|
|
704
685
|
{
|
|
705
686
|
...props,
|
|
@@ -714,7 +695,7 @@ function GenreTreeSearch({
|
|
|
714
695
|
extraGroups: [...extraGroups, ...hostGroups, artistGroup, songGroup].filter((group) => group !== void 0)
|
|
715
696
|
}
|
|
716
697
|
);
|
|
717
|
-
return SearchGroups ? /* @__PURE__ */
|
|
698
|
+
return SearchGroups ? /* @__PURE__ */ jsx10(SearchGroups, { query: deferredQuery, focused, onSelectGenre, children: render }) : render([]);
|
|
718
699
|
}
|
|
719
700
|
|
|
720
701
|
// src/genre-tree/GenreDetailPanel.tsx
|
|
@@ -751,7 +732,7 @@ import { ActionBand, ActionButton as ActionButton2, PanelBleed } from "@behindth
|
|
|
751
732
|
// src/genre-tree/ShareActionButton.tsx
|
|
752
733
|
import { Share2 as Share22 } from "lucide-react";
|
|
753
734
|
import { ActionButton } from "@behindthemusictree/ui";
|
|
754
|
-
import { usePopup as
|
|
735
|
+
import { usePopup as usePopup2 } from "@behindthemusictree/app-kit/popup";
|
|
755
736
|
|
|
756
737
|
// src/genre-tree/SharePopup.tsx
|
|
757
738
|
import { useCallback as useCallback5, useEffect as useEffect2, useMemo as useMemo5, useState as useState4 } from "react";
|
|
@@ -760,12 +741,12 @@ import { FaWhatsapp } from "react-icons/fa";
|
|
|
760
741
|
import { SiGmail } from "react-icons/si";
|
|
761
742
|
|
|
762
743
|
// src/genre-tree/ShareDestinationButton.tsx
|
|
763
|
-
import { Fragment as Fragment4, jsx as
|
|
744
|
+
import { Fragment as Fragment4, jsx as jsx11, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
764
745
|
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
746
|
function Contents({ icon, label }) {
|
|
766
747
|
return /* @__PURE__ */ jsxs6(Fragment4, { children: [
|
|
767
|
-
/* @__PURE__ */
|
|
768
|
-
/* @__PURE__ */
|
|
748
|
+
/* @__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 }),
|
|
749
|
+
/* @__PURE__ */ jsx11("span", { className: "max-w-full truncate", children: label })
|
|
769
750
|
] });
|
|
770
751
|
}
|
|
771
752
|
function ShareDestinationButton({
|
|
@@ -777,29 +758,29 @@ function ShareDestinationButton({
|
|
|
777
758
|
ariaLabel
|
|
778
759
|
}) {
|
|
779
760
|
if (href) {
|
|
780
|
-
return /* @__PURE__ */
|
|
761
|
+
return /* @__PURE__ */ jsx11("a", { href, target: "_blank", rel: "noopener noreferrer", "aria-label": ariaLabel, className, children: /* @__PURE__ */ jsx11(Contents, { icon, label }) });
|
|
781
762
|
}
|
|
782
|
-
return /* @__PURE__ */
|
|
763
|
+
return /* @__PURE__ */ jsx11("button", { type: "button", onClick, disabled, "aria-label": ariaLabel, className, children: /* @__PURE__ */ jsx11(Contents, { icon, label }) });
|
|
783
764
|
}
|
|
784
765
|
|
|
785
766
|
// src/genre-tree/SharePreviewCard.tsx
|
|
786
767
|
import { Music, Music2, UserRound } from "lucide-react";
|
|
787
|
-
import { jsx as
|
|
768
|
+
import { jsx as jsx12, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
788
769
|
function SharePreviewCard({ target, url }) {
|
|
789
770
|
const Icon = { genre: Music2, artist: UserRound, song: Music }[target.kind];
|
|
790
771
|
const typeLabel = { genre: "Genre", artist: "Artist", song: "Song" }[target.kind];
|
|
791
|
-
return /* @__PURE__ */
|
|
792
|
-
/* @__PURE__ */
|
|
772
|
+
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: [
|
|
773
|
+
/* @__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
774
|
/* @__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__ */
|
|
775
|
+
/* @__PURE__ */ jsx12("span", { className: "text-caption font-medium uppercase tracking-wide text-[var(--color-text-muted)]", children: typeLabel }),
|
|
776
|
+
/* @__PURE__ */ jsx12("span", { className: "truncate text-base font-semibold text-[var(--color-text)]", title: target.name, children: target.name }),
|
|
777
|
+
/* @__PURE__ */ jsx12("span", { className: "truncate text-body text-[var(--color-primary)]", title: url, children: url })
|
|
797
778
|
] })
|
|
798
779
|
] }) });
|
|
799
780
|
}
|
|
800
781
|
|
|
801
782
|
// src/genre-tree/SharePopup.tsx
|
|
802
|
-
import { Fragment as Fragment5, jsx as
|
|
783
|
+
import { Fragment as Fragment5, jsx as jsx13, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
803
784
|
function resolveAbsoluteUrl(url) {
|
|
804
785
|
try {
|
|
805
786
|
const parsed = new URL(url, window.location.href);
|
|
@@ -875,7 +856,7 @@ function SharePopup({ target, url, onClose }) {
|
|
|
875
856
|
}
|
|
876
857
|
};
|
|
877
858
|
return /* @__PURE__ */ jsxs8(Fragment5, { children: [
|
|
878
|
-
/* @__PURE__ */
|
|
859
|
+
/* @__PURE__ */ jsx13(
|
|
879
860
|
BasePopup_default,
|
|
880
861
|
{
|
|
881
862
|
title: "Share",
|
|
@@ -891,69 +872,69 @@ function SharePopup({ target, url, onClose }) {
|
|
|
891
872
|
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
873
|
contentClassName: "!rounded-none !bg-transparent !px-6 !pb-6 !pt-2",
|
|
893
874
|
children: /* @__PURE__ */ jsxs8("div", { className: "flex flex-col gap-4", children: [
|
|
894
|
-
/* @__PURE__ */
|
|
875
|
+
/* @__PURE__ */ jsx13(SharePreviewCard, { target, url: absoluteUrl || url }),
|
|
895
876
|
/* @__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__ */
|
|
877
|
+
/* @__PURE__ */ jsx13(
|
|
897
878
|
ShareDestinationButton,
|
|
898
879
|
{
|
|
899
880
|
label: "Copy Link",
|
|
900
|
-
icon: /* @__PURE__ */
|
|
881
|
+
icon: /* @__PURE__ */ jsx13(Link2, { "aria-hidden": "true", className: "h-6 w-6" }),
|
|
901
882
|
onClick: () => void handleCopy(),
|
|
902
883
|
ariaLabel: "Copy link",
|
|
903
884
|
disabled: !absoluteUrl
|
|
904
885
|
}
|
|
905
886
|
),
|
|
906
|
-
/* @__PURE__ */
|
|
887
|
+
/* @__PURE__ */ jsx13(
|
|
907
888
|
ShareDestinationButton,
|
|
908
889
|
{
|
|
909
890
|
label: "WhatsApp",
|
|
910
|
-
icon: /* @__PURE__ */
|
|
891
|
+
icon: /* @__PURE__ */ jsx13(FaWhatsapp, { "aria-hidden": "true", className: "h-9 w-9 text-[#25D366]" }),
|
|
911
892
|
href: destinationUrls?.whatsapp,
|
|
912
893
|
ariaLabel: `Share ${target.name} via WhatsApp`,
|
|
913
894
|
disabled: !absoluteUrl
|
|
914
895
|
}
|
|
915
896
|
),
|
|
916
|
-
/* @__PURE__ */
|
|
897
|
+
/* @__PURE__ */ jsx13(
|
|
917
898
|
ShareDestinationButton,
|
|
918
899
|
{
|
|
919
900
|
label: "Gmail",
|
|
920
|
-
icon: /* @__PURE__ */
|
|
901
|
+
icon: /* @__PURE__ */ jsx13(SiGmail, { "aria-hidden": "true", className: "h-8 w-8 text-[#EA4335]" }),
|
|
921
902
|
href: destinationUrls?.gmail,
|
|
922
903
|
ariaLabel: `Email ${target.name} with Gmail`,
|
|
923
904
|
disabled: !absoluteUrl
|
|
924
905
|
}
|
|
925
906
|
),
|
|
926
|
-
canUseNativeShare && /* @__PURE__ */
|
|
907
|
+
canUseNativeShare && /* @__PURE__ */ jsx13(
|
|
927
908
|
ShareDestinationButton,
|
|
928
909
|
{
|
|
929
910
|
label: "More",
|
|
930
|
-
icon: /* @__PURE__ */
|
|
911
|
+
icon: /* @__PURE__ */ jsx13(Share2, { "aria-hidden": "true", className: "h-6 w-6" }),
|
|
931
912
|
onClick: () => void handleNativeShare(),
|
|
932
913
|
ariaLabel: "More sharing options",
|
|
933
914
|
disabled: !absoluteUrl
|
|
934
915
|
}
|
|
935
916
|
)
|
|
936
917
|
] }),
|
|
937
|
-
copyStatus === "failed" && /* @__PURE__ */
|
|
938
|
-
shareError && /* @__PURE__ */
|
|
918
|
+
copyStatus === "failed" && /* @__PURE__ */ jsx13("p", { role: "alert", className: "text-center text-body text-[var(--color-red-500)]", children: "Could not copy the link." }),
|
|
919
|
+
shareError && /* @__PURE__ */ jsx13("p", { role: "alert", className: "text-center text-body text-[var(--color-red-500)]", children: shareError })
|
|
939
920
|
] })
|
|
940
921
|
}
|
|
941
922
|
),
|
|
942
|
-
toastId > 0 && /* @__PURE__ */
|
|
923
|
+
toastId > 0 && /* @__PURE__ */ jsx13(Toast, { message: "Link copied", onClose: dismissToast }, toastId)
|
|
943
924
|
] });
|
|
944
925
|
}
|
|
945
926
|
|
|
946
927
|
// src/genre-tree/ShareActionButton.tsx
|
|
947
|
-
import { jsx as
|
|
928
|
+
import { jsx as jsx14 } from "react/jsx-runtime";
|
|
948
929
|
function ShareActionButton({ target, url }) {
|
|
949
|
-
const { showPopup, hidePopup } =
|
|
930
|
+
const { showPopup, hidePopup } = usePopup2();
|
|
950
931
|
const openSharePopup = () => {
|
|
951
|
-
showPopup(/* @__PURE__ */
|
|
932
|
+
showPopup(/* @__PURE__ */ jsx14(SharePopup, { target, url, onClose: hidePopup }));
|
|
952
933
|
};
|
|
953
|
-
return /* @__PURE__ */
|
|
934
|
+
return /* @__PURE__ */ jsx14(
|
|
954
935
|
ActionButton,
|
|
955
936
|
{
|
|
956
|
-
icon: /* @__PURE__ */
|
|
937
|
+
icon: /* @__PURE__ */ jsx14(Share22, { "aria-hidden": "true", className: "w-5 h-5" }),
|
|
957
938
|
label: "Share",
|
|
958
939
|
"aria-label": `Share ${target.name}`,
|
|
959
940
|
title: `Share ${target.name}`,
|
|
@@ -963,7 +944,7 @@ function ShareActionButton({ target, url }) {
|
|
|
963
944
|
}
|
|
964
945
|
|
|
965
946
|
// src/genre-tree/GenreActionBand.tsx
|
|
966
|
-
import { jsx as
|
|
947
|
+
import { jsx as jsx15, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
967
948
|
function GenreActionBand({
|
|
968
949
|
node,
|
|
969
950
|
playActions,
|
|
@@ -984,24 +965,24 @@ function GenreActionBand({
|
|
|
984
965
|
items.push({
|
|
985
966
|
key: "zoom-in",
|
|
986
967
|
label: "Focus",
|
|
987
|
-
icon: /* @__PURE__ */
|
|
968
|
+
icon: /* @__PURE__ */ jsx15(ZoomIn, { "aria-hidden": "true", className: "w-5 h-5" }),
|
|
988
969
|
onClick: onZoomIn
|
|
989
970
|
});
|
|
990
971
|
}
|
|
991
972
|
if (onAddChild) {
|
|
992
|
-
adminItems.push({ key: "add-child", label: "Add", icon: /* @__PURE__ */
|
|
973
|
+
adminItems.push({ key: "add-child", label: "Add", icon: /* @__PURE__ */ jsx15(Plus, { "aria-hidden": "true", className: "w-5 h-5" }), onClick: onAddChild });
|
|
993
974
|
}
|
|
994
975
|
if (onRename) {
|
|
995
|
-
adminItems.push({ key: "rename", label: "Rename", icon: /* @__PURE__ */
|
|
976
|
+
adminItems.push({ key: "rename", label: "Rename", icon: /* @__PURE__ */ jsx15(Pencil, { "aria-hidden": "true", className: "w-5 h-5" }), onClick: onRename });
|
|
996
977
|
}
|
|
997
978
|
if (onChangeParent) {
|
|
998
|
-
adminItems.push({ key: "change-parent", label: "Parent", icon: /* @__PURE__ */
|
|
979
|
+
adminItems.push({ key: "change-parent", label: "Parent", icon: /* @__PURE__ */ jsx15(MoveUpRight, { "aria-hidden": "true", className: "w-5 h-5" }), onClick: onChangeParent });
|
|
999
980
|
}
|
|
1000
981
|
if (onToggleSide) {
|
|
1001
982
|
adminItems.push({
|
|
1002
983
|
key: "toggle-side",
|
|
1003
984
|
label: side === "pop" ? "Make core" : "Make pop",
|
|
1004
|
-
icon: /* @__PURE__ */
|
|
985
|
+
icon: /* @__PURE__ */ jsx15(ArrowLeftRight, { "aria-hidden": "true", className: "w-5 h-5" }),
|
|
1005
986
|
onClick: onToggleSide,
|
|
1006
987
|
disabled: !!toggleSideDisabledReason,
|
|
1007
988
|
title: toggleSideDisabledReason
|
|
@@ -1016,9 +997,9 @@ function GenreActionBand({
|
|
|
1016
997
|
disabled: action.enabled ? !action.enabled(node) : false
|
|
1017
998
|
});
|
|
1018
999
|
}
|
|
1019
|
-
const renderItems = (list) => list.map((item) => /* @__PURE__ */
|
|
1000
|
+
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
1001
|
if (!playActions && items.length === 0 && adminItems.length === 0 && !(shareTarget && shareUrl)) return null;
|
|
1021
|
-
return /* @__PURE__ */
|
|
1002
|
+
return /* @__PURE__ */ jsx15(PanelBleed, { children: /* @__PURE__ */ jsxs9(
|
|
1022
1003
|
ActionBand,
|
|
1023
1004
|
{
|
|
1024
1005
|
className: "genre-action-band",
|
|
@@ -1026,7 +1007,7 @@ function GenreActionBand({
|
|
|
1026
1007
|
children: [
|
|
1027
1008
|
playActions,
|
|
1028
1009
|
renderItems(items),
|
|
1029
|
-
shareTarget && shareUrl && /* @__PURE__ */
|
|
1010
|
+
shareTarget && shareUrl && /* @__PURE__ */ jsx15(ShareActionButton, { target: shareTarget, url: shareUrl })
|
|
1030
1011
|
]
|
|
1031
1012
|
}
|
|
1032
1013
|
) });
|
|
@@ -1053,7 +1034,7 @@ var REGION_GLOBE_PATHS = {
|
|
|
1053
1034
|
var REGION_GLOBES = ["africa", "americas", "asia"];
|
|
1054
1035
|
|
|
1055
1036
|
// src/genre-tree/RegionGlobeIcon.tsx
|
|
1056
|
-
import { jsx as
|
|
1037
|
+
import { jsx as jsx16 } from "react/jsx-runtime";
|
|
1057
1038
|
var ROTATION_INTERVAL_MS = 3e3;
|
|
1058
1039
|
function RegionGlobeIcon({ className: className2 }) {
|
|
1059
1040
|
const [index, setIndex] = useState5(0);
|
|
@@ -1071,29 +1052,29 @@ function RegionGlobeIcon({ className: className2 }) {
|
|
|
1071
1052
|
clearInterval(timer);
|
|
1072
1053
|
};
|
|
1073
1054
|
}, []);
|
|
1074
|
-
return /* @__PURE__ */
|
|
1055
|
+
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
1056
|
}
|
|
1076
1057
|
|
|
1077
1058
|
// src/genre-tree/treeMarkPath.ts
|
|
1078
1059
|
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
1060
|
|
|
1080
1061
|
// src/genre-tree/TreeMarkIcon.tsx
|
|
1081
|
-
import { jsx as
|
|
1062
|
+
import { jsx as jsx17 } from "react/jsx-runtime";
|
|
1082
1063
|
function TreeMarkIcon({ className: className2 }) {
|
|
1083
|
-
return /* @__PURE__ */
|
|
1064
|
+
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
1065
|
}
|
|
1085
1066
|
|
|
1086
1067
|
// src/genre-tree/GenrePlayActions.tsx
|
|
1087
|
-
import { Fragment as Fragment6, jsx as
|
|
1068
|
+
import { Fragment as Fragment6, jsx as jsx18, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
1088
1069
|
function PlayIcon({ kind }) {
|
|
1089
1070
|
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__ */
|
|
1071
|
+
kind === "tree" && /* @__PURE__ */ jsx18(TreeMarkIcon, { className: "absolute -left-1.5 -top-1.5 w-8 h-8 opacity-35" }),
|
|
1072
|
+
kind === "map" && /* @__PURE__ */ jsx18(RegionGlobeIcon, { className: "absolute -left-1.5 -top-1.5 w-8 h-8 opacity-35" }),
|
|
1092
1073
|
kind === "tree-map" && /* @__PURE__ */ jsxs10(Fragment6, { children: [
|
|
1093
|
-
/* @__PURE__ */
|
|
1094
|
-
/* @__PURE__ */
|
|
1074
|
+
/* @__PURE__ */ jsx18(TreeMarkIcon, { className: "absolute -left-1.5 -top-1.5 w-8 h-8 opacity-35 [clip-path:inset(0_50%_0_0)]" }),
|
|
1075
|
+
/* @__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
1076
|
] }),
|
|
1096
|
-
/* @__PURE__ */
|
|
1077
|
+
/* @__PURE__ */ jsx18(Play, { className: "relative w-5 h-5 fill-[var(--color-surface)]" })
|
|
1097
1078
|
] });
|
|
1098
1079
|
}
|
|
1099
1080
|
function playOptions(playlist) {
|
|
@@ -1109,13 +1090,13 @@ function playOptions(playlist) {
|
|
|
1109
1090
|
function GenrePlayActions({ genrePlaylist, playback }) {
|
|
1110
1091
|
const { isPlaying, setIsPlaying } = usePlayer4();
|
|
1111
1092
|
const options = playOptions(genrePlaylist);
|
|
1112
|
-
return /* @__PURE__ */
|
|
1093
|
+
return /* @__PURE__ */ jsx18(Fragment6, { children: options.map((option) => {
|
|
1113
1094
|
const isCurrent = playback.playing?.uuid === genrePlaylist.uuid && (option.selection === void 0 || playback.playing.selectionKey === "" || playback.playing.selectionKey === genreMusicSelectionKey2(option.selection).join());
|
|
1114
1095
|
const playing = isCurrent && isPlaying;
|
|
1115
|
-
return /* @__PURE__ */
|
|
1096
|
+
return /* @__PURE__ */ jsx18(
|
|
1116
1097
|
ActionButton3,
|
|
1117
1098
|
{
|
|
1118
|
-
icon: playing ? /* @__PURE__ */
|
|
1099
|
+
icon: playing ? /* @__PURE__ */ jsx18(Pause, { "aria-hidden": "true", className: "w-5 h-5" }) : /* @__PURE__ */ jsx18(PlayIcon, { kind: option.icon }),
|
|
1119
1100
|
label: playing ? "Pause" : option.label,
|
|
1120
1101
|
caption: String(option.count),
|
|
1121
1102
|
disabled: option.count === 0,
|
|
@@ -1125,9 +1106,7 @@ function GenrePlayActions({ genrePlaylist, playback }) {
|
|
|
1125
1106
|
setIsPlaying(!isPlaying);
|
|
1126
1107
|
return;
|
|
1127
1108
|
}
|
|
1128
|
-
playback.play(genrePlaylist, option.selection)
|
|
1129
|
-
console.error("Failed to load genre playlist tracks:", error);
|
|
1130
|
-
});
|
|
1109
|
+
void playback.play(genrePlaylist, option.selection);
|
|
1131
1110
|
}
|
|
1132
1111
|
},
|
|
1133
1112
|
option.key
|
|
@@ -1141,7 +1120,7 @@ import { useFetchGenreOverview } from "@behindthemusictree/app-kit/genre-tree";
|
|
|
1141
1120
|
|
|
1142
1121
|
// src/genre-tree/ClampedText.tsx
|
|
1143
1122
|
import { useLayoutEffect, useRef as useRef2, useState as useState6 } from "react";
|
|
1144
|
-
import { Fragment as Fragment7, jsx as
|
|
1123
|
+
import { Fragment as Fragment7, jsx as jsx19, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
1145
1124
|
function ClampedText({ children, className: className2 = "" }) {
|
|
1146
1125
|
const ref = useRef2(null);
|
|
1147
1126
|
const [expanded, setExpanded] = useState6(false);
|
|
@@ -1152,8 +1131,8 @@ function ClampedText({ children, className: className2 = "" }) {
|
|
|
1152
1131
|
setOverflows(element.scrollHeight > element.clientHeight);
|
|
1153
1132
|
}, [children, expanded]);
|
|
1154
1133
|
return /* @__PURE__ */ jsxs11(Fragment7, { children: [
|
|
1155
|
-
/* @__PURE__ */
|
|
1156
|
-
(overflows || expanded) && /* @__PURE__ */
|
|
1134
|
+
/* @__PURE__ */ jsx19("p", { ref, className: `${className2} ${expanded ? "" : "line-clamp-3"}`, children }),
|
|
1135
|
+
(overflows || expanded) && /* @__PURE__ */ jsx19(
|
|
1157
1136
|
"button",
|
|
1158
1137
|
{
|
|
1159
1138
|
type: "button",
|
|
@@ -1178,25 +1157,25 @@ import { PaginatedResponseSchema } from "@behindthemusictree/app-kit/transport";
|
|
|
1178
1157
|
import { parseWithLog } from "@behindthemusictree/app-kit/transport";
|
|
1179
1158
|
import { usePlayer as usePlayer5 } from "@behindthemusictree/app-kit/player";
|
|
1180
1159
|
import { PlayStates } from "@behindthemusictree/app-kit/player";
|
|
1181
|
-
import { usePopup as
|
|
1182
|
-
import { ErrorCode as
|
|
1160
|
+
import { usePopup as usePopup3 } from "@behindthemusictree/app-kit/popup";
|
|
1161
|
+
import { AppError as AppError2, ErrorCode as ErrorCode2 } from "@behindthemusictree/app-kit/transport";
|
|
1183
1162
|
import { genreMusicQueryParams } from "@behindthemusictree/app-kit/genre-tree";
|
|
1184
1163
|
import { genrePlaylistQueryKeys } from "@behindthemusictree/app-kit/genre-tree";
|
|
1185
1164
|
import { libraryEndpoints, libraryQueryKeys } from "@behindthemusictree/app-kit/genre-tree";
|
|
1186
1165
|
import { isSong, songUnplayableReason, SongDetailedSchema } from "@behindthemusictree/app-kit/genre-tree";
|
|
1187
|
-
import { useTrackList as useTrackList2 } from "@behindthemusictree/app-kit/genre-tree";
|
|
1166
|
+
import { TracksFailureAlreadyReportedError as TracksFailureAlreadyReportedError2, useTrackList as useTrackList2 } from "@behindthemusictree/app-kit/genre-tree";
|
|
1188
1167
|
|
|
1189
1168
|
// src/genre-tree/MusicBrainzRecordingLink.tsx
|
|
1190
1169
|
import { musicBrainzRecordingUrl } from "@behindthemusictree/app-kit/genre-tree";
|
|
1191
|
-
import { Fragment as Fragment8, jsx as
|
|
1170
|
+
import { Fragment as Fragment8, jsx as jsx20 } from "react/jsx-runtime";
|
|
1192
1171
|
function MusicBrainzRecordingLink({
|
|
1193
1172
|
song,
|
|
1194
1173
|
children,
|
|
1195
1174
|
className: className2 = ""
|
|
1196
1175
|
}) {
|
|
1197
1176
|
const url = musicBrainzRecordingUrl(song);
|
|
1198
|
-
if (!url) return /* @__PURE__ */
|
|
1199
|
-
return /* @__PURE__ */
|
|
1177
|
+
if (!url) return /* @__PURE__ */ jsx20(Fragment8, { children });
|
|
1178
|
+
return /* @__PURE__ */ jsx20(
|
|
1200
1179
|
"a",
|
|
1201
1180
|
{
|
|
1202
1181
|
href: url,
|
|
@@ -1213,7 +1192,7 @@ function MusicBrainzRecordingLink({
|
|
|
1213
1192
|
// src/genre-tree/GenrePlaylistTracks.tsx
|
|
1214
1193
|
import { ArtistNames } from "@behindthemusictree/app-kit/genre-tree";
|
|
1215
1194
|
import { capitalize, useTrackNoun } from "@behindthemusictree/app-kit/track-noun";
|
|
1216
|
-
import { jsx as
|
|
1195
|
+
import { jsx as jsx21, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
1217
1196
|
var CATALOGUE_PAGE_SIZE = 100;
|
|
1218
1197
|
var SongPageSchema = PaginatedResponseSchema(SongDetailedSchema).extend({
|
|
1219
1198
|
overallTotal: z.number().nullable(),
|
|
@@ -1247,7 +1226,7 @@ function GenrePlaylistTracks({
|
|
|
1247
1226
|
const { fetchGenrePlaylistTracksPage, playNewTrackListFromGenrePlaylist, playNewTrackListFromArtist, playNewTrackListFromGenreCatalogue } = useTrackList2();
|
|
1248
1227
|
const { session, sessionRestored } = useSession();
|
|
1249
1228
|
const { playerTrackObject, playState, handlePlayPauseAction } = usePlayer5();
|
|
1250
|
-
const { showPopup } =
|
|
1229
|
+
const { showPopup } = usePopup3();
|
|
1251
1230
|
const trackNoun = useTrackNoun();
|
|
1252
1231
|
const uuid = genrePlaylist?.uuid;
|
|
1253
1232
|
const genreName = selectedGenreName ?? genrePlaylist?.name ?? "Genre";
|
|
@@ -1299,27 +1278,28 @@ function GenrePlaylistTracks({
|
|
|
1299
1278
|
}) : 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
1279
|
started.catch((error) => {
|
|
1301
1280
|
console.error("Failed to play genre playlist:", error);
|
|
1302
|
-
|
|
1281
|
+
if (error instanceof TracksFailureAlreadyReportedError2) return;
|
|
1282
|
+
showPopup(/* @__PURE__ */ jsx21(InternalErrorPopup, { errorCode: error instanceof AppError2 ? error.code : ErrorCode2.CLIENT_UNKNOWN }));
|
|
1303
1283
|
});
|
|
1304
1284
|
};
|
|
1305
|
-
return /* @__PURE__ */
|
|
1285
|
+
return /* @__PURE__ */ jsx21(PanelSection, { title: `${capitalize(trackNoun.plural)}${total !== void 0 ? ` (${total})` : ""}`, children: /* @__PURE__ */ jsxs12("div", { children: [
|
|
1306
1286
|
renderTracksToolbar?.(),
|
|
1307
|
-
scope === "me" && !genrePlaylist ? /* @__PURE__ */
|
|
1287
|
+
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
1288
|
"Couldn't load ",
|
|
1309
1289
|
trackNoun.plural,
|
|
1310
1290
|
".",
|
|
1311
1291
|
" ",
|
|
1312
|
-
/* @__PURE__ */
|
|
1313
|
-
] }) : tracks.length === 0 ? /* @__PURE__ */
|
|
1292
|
+
/* @__PURE__ */ jsx21("button", { type: "button", className: "underline", onClick: () => void refetch(), children: "Retry" })
|
|
1293
|
+
] }) : 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
1294
|
tracks.map((track, index) => {
|
|
1315
1295
|
const label = track.artists?.length ? `${track.title} \u2014 ${track.artists.map((artist2) => artist2.name).join(", ")}` : track.title;
|
|
1316
1296
|
const isCurrent = playerTrackObject?.track.id === track.uuid;
|
|
1317
1297
|
const isPlaying = isCurrent && playState === PlayStates.PLAYING;
|
|
1318
1298
|
const text = /* @__PURE__ */ jsxs12("span", { className: TEXT_CELL, children: [
|
|
1319
|
-
/* @__PURE__ */
|
|
1320
|
-
track.artists?.length ? /* @__PURE__ */
|
|
1321
|
-
/* @__PURE__ */
|
|
1322
|
-
track.album && /* @__PURE__ */
|
|
1299
|
+
/* @__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 }),
|
|
1300
|
+
track.artists?.length ? /* @__PURE__ */ jsx21("span", { className: SEPARATOR, children: " \u2014 " }) : null,
|
|
1301
|
+
/* @__PURE__ */ jsx21("span", { className: COLUMN_CELL, children: track.artists?.length ? /* @__PURE__ */ jsx21(ArtistNames, { artists: track.artists, renderArtistLink }) : null }),
|
|
1302
|
+
track.album && /* @__PURE__ */ jsx21("span", { className: ALBUM_CELL, children: track.album.name })
|
|
1323
1303
|
] });
|
|
1324
1304
|
const leading = renderSongLeading?.(track, index);
|
|
1325
1305
|
const actions = renderSongActions?.(track);
|
|
@@ -1327,7 +1307,7 @@ function GenrePlaylistTracks({
|
|
|
1327
1307
|
if (isUnplayable) {
|
|
1328
1308
|
return /* @__PURE__ */ jsxs12("li", { className: "flex min-h-8 items-center gap-1 px-1 opacity-50", children: [
|
|
1329
1309
|
leading,
|
|
1330
|
-
/* @__PURE__ */
|
|
1310
|
+
/* @__PURE__ */ jsx21(
|
|
1331
1311
|
"button",
|
|
1332
1312
|
{
|
|
1333
1313
|
type: "button",
|
|
@@ -1335,7 +1315,7 @@ function GenrePlaylistTracks({
|
|
|
1335
1315
|
"aria-disabled": "true",
|
|
1336
1316
|
"aria-label": label,
|
|
1337
1317
|
className: "flex h-6 w-6 shrink-0 items-center justify-center rounded-full opacity-0 cursor-not-allowed",
|
|
1338
|
-
children: /* @__PURE__ */
|
|
1318
|
+
children: /* @__PURE__ */ jsx21(FaPlay, { size: 10 })
|
|
1339
1319
|
}
|
|
1340
1320
|
),
|
|
1341
1321
|
text,
|
|
@@ -1348,14 +1328,14 @@ function GenrePlaylistTracks({
|
|
|
1348
1328
|
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
1329
|
children: [
|
|
1350
1330
|
leading,
|
|
1351
|
-
/* @__PURE__ */
|
|
1331
|
+
/* @__PURE__ */ jsx21(
|
|
1352
1332
|
"button",
|
|
1353
1333
|
{
|
|
1354
1334
|
type: "button",
|
|
1355
1335
|
"aria-label": `${isPlaying ? "Pause" : "Play"} ${label}`,
|
|
1356
1336
|
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
1337
|
onClick: () => isCurrent ? handlePlayPauseAction() : play(track.uuid),
|
|
1358
|
-
children: isCurrent && playState === PlayStates.LOADING ? /* @__PURE__ */
|
|
1338
|
+
children: isCurrent && playState === PlayStates.LOADING ? /* @__PURE__ */ jsx21(RingLoader, { size: 10 }) : isPlaying ? /* @__PURE__ */ jsx21(FaPause, { size: 10 }) : /* @__PURE__ */ jsx21(FaPlay, { size: 10 })
|
|
1359
1339
|
}
|
|
1360
1340
|
),
|
|
1361
1341
|
text,
|
|
@@ -1365,7 +1345,7 @@ function GenrePlaylistTracks({
|
|
|
1365
1345
|
track.uuid
|
|
1366
1346
|
);
|
|
1367
1347
|
}),
|
|
1368
|
-
hasNextPage && /* @__PURE__ */
|
|
1348
|
+
hasNextPage && /* @__PURE__ */ jsx21("li", { ref: setSentinel, "aria-hidden": "true", className: "h-4" })
|
|
1369
1349
|
] })
|
|
1370
1350
|
] }) });
|
|
1371
1351
|
}
|
|
@@ -1373,7 +1353,7 @@ function GenrePlaylistTracks({
|
|
|
1373
1353
|
// src/genre-tree/GenreDetailExtras.tsx
|
|
1374
1354
|
import { useTrackNoun as useTrackNoun2 } from "@behindthemusictree/app-kit/track-noun";
|
|
1375
1355
|
import { SiWikidata, SiWikipedia } from "react-icons/si";
|
|
1376
|
-
import { Fragment as Fragment9, jsx as
|
|
1356
|
+
import { Fragment as Fragment9, jsx as jsx22, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
1377
1357
|
function GenreDetailExtras({
|
|
1378
1358
|
genreUuid,
|
|
1379
1359
|
genrePlaylist,
|
|
@@ -1400,15 +1380,15 @@ function GenreDetailExtras({
|
|
|
1400
1380
|
);
|
|
1401
1381
|
if (isPending) {
|
|
1402
1382
|
return /* @__PURE__ */ jsxs13(Fragment9, { children: [
|
|
1403
|
-
/* @__PURE__ */
|
|
1383
|
+
/* @__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
1384
|
family
|
|
1405
1385
|
] });
|
|
1406
1386
|
}
|
|
1407
|
-
if (!overview) return /* @__PURE__ */
|
|
1387
|
+
if (!overview) return /* @__PURE__ */ jsx22(Fragment9, { children: family });
|
|
1408
1388
|
const { summary, summarySourceUrl, essentialSongs } = overview;
|
|
1409
1389
|
const wikidataUrl = wikidataId ? `https://www.wikidata.org/wiki/${encodeURIComponent(wikidataId)}` : null;
|
|
1410
1390
|
return /* @__PURE__ */ jsxs13(Fragment9, { children: [
|
|
1411
|
-
(summarySourceUrl || wikidataUrl) && /* @__PURE__ */
|
|
1391
|
+
(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
1392
|
summarySourceUrl && /* @__PURE__ */ jsxs13(
|
|
1413
1393
|
"a",
|
|
1414
1394
|
{
|
|
@@ -1417,7 +1397,7 @@ function GenreDetailExtras({
|
|
|
1417
1397
|
rel: "noopener noreferrer",
|
|
1418
1398
|
className: "inline-flex items-center gap-1.5 text-[var(--color-text-muted)] hover:text-[var(--color-text)]",
|
|
1419
1399
|
children: [
|
|
1420
|
-
/* @__PURE__ */
|
|
1400
|
+
/* @__PURE__ */ jsx22(SiWikipedia, { "aria-hidden": "true", className: "h-3.5 w-3.5" }),
|
|
1421
1401
|
"Wikipedia"
|
|
1422
1402
|
]
|
|
1423
1403
|
}
|
|
@@ -1430,17 +1410,17 @@ function GenreDetailExtras({
|
|
|
1430
1410
|
rel: "noopener noreferrer",
|
|
1431
1411
|
className: "inline-flex items-center gap-1.5 text-[var(--color-text-muted)] hover:text-[var(--color-text)]",
|
|
1432
1412
|
children: [
|
|
1433
|
-
/* @__PURE__ */
|
|
1413
|
+
/* @__PURE__ */ jsx22(SiWikidata, { "aria-hidden": "true", className: "h-3.5 w-3.5" }),
|
|
1434
1414
|
"Wikidata"
|
|
1435
1415
|
]
|
|
1436
1416
|
}
|
|
1437
1417
|
)
|
|
1438
1418
|
] }) }),
|
|
1439
|
-
/* @__PURE__ */
|
|
1419
|
+
/* @__PURE__ */ jsx22(PanelSection2, { title: "Summary", children: renderSummary ? renderSummary(overview) : /* @__PURE__ */ jsx22(ClampedText, { className: "text-body text-[var(--color-text)]", children: summary ?? "\u2014" }, genreUuid) }),
|
|
1440
1420
|
family,
|
|
1441
1421
|
renderGenreDetailExtras?.(overview),
|
|
1442
|
-
(renderEssentialTracks || essentialSongs) && /* @__PURE__ */
|
|
1443
|
-
/* @__PURE__ */
|
|
1422
|
+
(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" }) }),
|
|
1423
|
+
/* @__PURE__ */ jsx22(
|
|
1444
1424
|
GenrePlaylistTracks,
|
|
1445
1425
|
{
|
|
1446
1426
|
genreUuid,
|
|
@@ -1458,10 +1438,10 @@ function GenreDetailExtras({
|
|
|
1458
1438
|
}
|
|
1459
1439
|
|
|
1460
1440
|
// src/genre-tree/GenreInfoPanelBody.tsx
|
|
1461
|
-
import { Fragment as Fragment10, jsx as
|
|
1441
|
+
import { Fragment as Fragment10, jsx as jsx23, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
1462
1442
|
import { createElement } from "react";
|
|
1463
1443
|
function GenreNodeActionBand({ genrePlaylist, playback, ...bandProps }) {
|
|
1464
|
-
return /* @__PURE__ */
|
|
1444
|
+
return /* @__PURE__ */ jsx23(GenreActionBand, { ...bandProps, playActions: /* @__PURE__ */ jsx23(GenrePlayActions, { genrePlaylist, playback }) });
|
|
1465
1445
|
}
|
|
1466
1446
|
function GenreInfoPanelBody({
|
|
1467
1447
|
toolbar,
|
|
@@ -1480,7 +1460,7 @@ function GenreInfoPanelBody({
|
|
|
1480
1460
|
const selection = summary ? defaultGenreMusicSelection2(summary) : void 0;
|
|
1481
1461
|
return /* @__PURE__ */ jsxs14(Fragment10, { children: [
|
|
1482
1462
|
toolbar,
|
|
1483
|
-
genrePlaylist ? /* @__PURE__ */
|
|
1463
|
+
genrePlaylist ? /* @__PURE__ */ jsx23(GenreNodeActionBand, { ...band, genrePlaylist, playback }) : /* @__PURE__ */ jsx23(GenreActionBand, { ...band }),
|
|
1484
1464
|
/* @__PURE__ */ createElement(
|
|
1485
1465
|
GenreDetailExtras,
|
|
1486
1466
|
{
|
|
@@ -1500,7 +1480,7 @@ function GenreInfoPanelBody({
|
|
|
1500
1480
|
}
|
|
1501
1481
|
|
|
1502
1482
|
// src/genre-tree/GenreDetailPanel.tsx
|
|
1503
|
-
import { Fragment as Fragment11, jsx as
|
|
1483
|
+
import { Fragment as Fragment11, jsx as jsx24, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
1504
1484
|
var RELATIVE_ITEM_COUNT = 1;
|
|
1505
1485
|
function toNode(genre, parentId) {
|
|
1506
1486
|
return {
|
|
@@ -1564,19 +1544,19 @@ function useGenreDetailContent({
|
|
|
1564
1544
|
if (isError) return {
|
|
1565
1545
|
name: null,
|
|
1566
1546
|
title: "Genre unavailable",
|
|
1567
|
-
content: /* @__PURE__ */
|
|
1547
|
+
content: /* @__PURE__ */ jsx24("p", { role: "alert", className: "text-body text-[var(--color-text)]", children: "This genre could not be loaded." })
|
|
1568
1548
|
};
|
|
1569
1549
|
if (isPending || !detail || !view) return {
|
|
1570
1550
|
name: null,
|
|
1571
1551
|
title: "Loading genre\u2026",
|
|
1572
1552
|
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__ */
|
|
1553
|
+
/* @__PURE__ */ jsx24(Skeleton3, { className: "h-6 w-2/3" }),
|
|
1554
|
+
/* @__PURE__ */ jsx24(Skeleton3, { className: "h-4 w-full" }),
|
|
1555
|
+
/* @__PURE__ */ jsx24(Skeleton3, { className: "h-4 w-3/4" })
|
|
1576
1556
|
] })
|
|
1577
1557
|
};
|
|
1578
1558
|
const selectGenre = (nodeId) => onSelectGenre(GenreUuidSchema.parse(nodeId));
|
|
1579
|
-
const family = /* @__PURE__ */
|
|
1559
|
+
const family = /* @__PURE__ */ jsx24(
|
|
1580
1560
|
GenreNodeFamily,
|
|
1581
1561
|
{
|
|
1582
1562
|
node: view.node,
|
|
@@ -1587,14 +1567,14 @@ function useGenreDetailContent({
|
|
|
1587
1567
|
onSelectNode: selectGenre
|
|
1588
1568
|
}
|
|
1589
1569
|
);
|
|
1590
|
-
const ancestors = /* @__PURE__ */
|
|
1570
|
+
const ancestors = /* @__PURE__ */ jsx24(GenreNodeAncestors, { ancestorNodes: view.ancestorNodes, onSelectNode: selectGenre });
|
|
1591
1571
|
return {
|
|
1592
1572
|
name: detail.name,
|
|
1593
1573
|
title: detail.name,
|
|
1594
1574
|
headerAccent: { background: view.fill, color: view.textColor },
|
|
1595
1575
|
aside: expanded ? ancestors : void 0,
|
|
1596
1576
|
content: /* @__PURE__ */ jsxs15(Fragment11, { children: [
|
|
1597
|
-
/* @__PURE__ */
|
|
1577
|
+
/* @__PURE__ */ jsx24(
|
|
1598
1578
|
GenreInfoPanelBody,
|
|
1599
1579
|
{
|
|
1600
1580
|
family: /* @__PURE__ */ jsxs15(Fragment11, { children: [
|
|
@@ -1641,7 +1621,7 @@ function GenreDetailPanel({
|
|
|
1641
1621
|
expanded,
|
|
1642
1622
|
band: { onZoomIn, shareUrl, shareTarget: shareUrl ? shareTarget : void 0 }
|
|
1643
1623
|
});
|
|
1644
|
-
return /* @__PURE__ */
|
|
1624
|
+
return /* @__PURE__ */ jsx24(
|
|
1645
1625
|
DetailPanel,
|
|
1646
1626
|
{
|
|
1647
1627
|
side: "left",
|
|
@@ -1654,7 +1634,7 @@ function GenreDetailPanel({
|
|
|
1654
1634
|
edgeTab,
|
|
1655
1635
|
aside: panel.aside,
|
|
1656
1636
|
titleInSearch,
|
|
1657
|
-
headerActions: onExpandedChange ? /* @__PURE__ */
|
|
1637
|
+
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
1638
|
children: panel.content
|
|
1659
1639
|
}
|
|
1660
1640
|
);
|
|
@@ -1666,7 +1646,7 @@ import {
|
|
|
1666
1646
|
getReparentCandidates,
|
|
1667
1647
|
useUpdateGenre
|
|
1668
1648
|
} from "@behindthemusictree/app-kit/genre-tree";
|
|
1669
|
-
import { jsx as
|
|
1649
|
+
import { jsx as jsx25, jsxs as jsxs16 } from "react/jsx-runtime";
|
|
1670
1650
|
function ChangeParentPopup({
|
|
1671
1651
|
genrePlaylist,
|
|
1672
1652
|
genrePlaylists,
|
|
@@ -1706,7 +1686,7 @@ function ChangeParentPopup({
|
|
|
1706
1686
|
"Current parent: ",
|
|
1707
1687
|
genrePlaylist.parent?.name ?? "none"
|
|
1708
1688
|
] }),
|
|
1709
|
-
/* @__PURE__ */
|
|
1689
|
+
/* @__PURE__ */ jsx25("div", { "aria-busy": isPending, className: isPending ? "pointer-events-none opacity-60" : void 0, children: /* @__PURE__ */ jsx25(
|
|
1710
1690
|
GenreSearch,
|
|
1711
1691
|
{
|
|
1712
1692
|
genrePlaylists: candidates,
|
|
@@ -1714,7 +1694,7 @@ function ChangeParentPopup({
|
|
|
1714
1694
|
placeholder: "Search a new parent\u2026"
|
|
1715
1695
|
}
|
|
1716
1696
|
) }),
|
|
1717
|
-
formErrors.length > 0 && /* @__PURE__ */
|
|
1697
|
+
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
1698
|
] });
|
|
1719
1699
|
}
|
|
1720
1700
|
|
|
@@ -1727,7 +1707,7 @@ import { Pause as Pause2, Play as Play2 } from "lucide-react";
|
|
|
1727
1707
|
import { ActionBand as ActionBand2, ActionButton as ActionButton4, PanelBleed as PanelBleed2 } from "@behindthemusictree/ui";
|
|
1728
1708
|
import { TrackListOriginType as TrackListOriginType2, useTrackList as useTrackList3 } from "@behindthemusictree/app-kit/genre-tree";
|
|
1729
1709
|
import { usePlayer as usePlayer6 } from "@behindthemusictree/app-kit/player";
|
|
1730
|
-
import { jsx as
|
|
1710
|
+
import { jsx as jsx26, jsxs as jsxs17 } from "react/jsx-runtime";
|
|
1731
1711
|
function ArtistActionBand({ artist, share }) {
|
|
1732
1712
|
const { trackList, playNewTrackListFromArtist } = useTrackList3();
|
|
1733
1713
|
const { isPlaying, setIsPlaying } = usePlayer6();
|
|
@@ -1743,11 +1723,11 @@ function ArtistActionBand({ artist, share }) {
|
|
|
1743
1723
|
console.error("Failed to load artist tracks:", error);
|
|
1744
1724
|
});
|
|
1745
1725
|
};
|
|
1746
|
-
return /* @__PURE__ */
|
|
1747
|
-
/* @__PURE__ */
|
|
1726
|
+
return /* @__PURE__ */ jsx26(PanelBleed2, { children: /* @__PURE__ */ jsxs17(ActionBand2, { children: [
|
|
1727
|
+
/* @__PURE__ */ jsx26(
|
|
1748
1728
|
ActionButton4,
|
|
1749
1729
|
{
|
|
1750
|
-
icon: playing ? /* @__PURE__ */
|
|
1730
|
+
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
1731
|
label: playing ? "Pause" : "Play",
|
|
1752
1732
|
caption: String(artist.playableTracksCount),
|
|
1753
1733
|
disabled: artist.playableTracksCount === 0,
|
|
@@ -1775,7 +1755,7 @@ import {
|
|
|
1775
1755
|
SiYoutube
|
|
1776
1756
|
} from "react-icons/si";
|
|
1777
1757
|
import { Chip } from "@behindthemusictree/ui";
|
|
1778
|
-
import { jsx as
|
|
1758
|
+
import { jsx as jsx27 } from "react/jsx-runtime";
|
|
1779
1759
|
var LINK_KINDS = {
|
|
1780
1760
|
official: { label: "Official website", Icon: Globe },
|
|
1781
1761
|
wikipedia: { label: "Wikipedia", Icon: SiWikipedia2 },
|
|
@@ -1812,7 +1792,7 @@ function artistLinks(artist) {
|
|
|
1812
1792
|
return links;
|
|
1813
1793
|
}
|
|
1814
1794
|
function ArtistLinks({ links }) {
|
|
1815
|
-
return /* @__PURE__ */
|
|
1795
|
+
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
1796
|
}
|
|
1817
1797
|
|
|
1818
1798
|
// src/genre-tree/artist/formatYears.ts
|
|
@@ -1823,7 +1803,7 @@ function formatYears(beginYear, endYear, ended) {
|
|
|
1823
1803
|
}
|
|
1824
1804
|
|
|
1825
1805
|
// src/genre-tree/artist/ArtistHeader.tsx
|
|
1826
|
-
import { jsx as
|
|
1806
|
+
import { jsx as jsx28 } from "react/jsx-runtime";
|
|
1827
1807
|
var countryNames = new Intl.DisplayNames(["en"], { type: "region" });
|
|
1828
1808
|
function ArtistHeader({ artist }) {
|
|
1829
1809
|
const fields = [];
|
|
@@ -1833,35 +1813,35 @@ function ArtistHeader({ artist }) {
|
|
|
1833
1813
|
const years = formatYears(artist.beginYear, artist.endYear, artist.ended);
|
|
1834
1814
|
if (years) fields.push({ label: "Active", value: years });
|
|
1835
1815
|
const links = artistLinks(artist);
|
|
1836
|
-
if (links.length > 0) fields.push({ label: "Links", value: /* @__PURE__ */
|
|
1816
|
+
if (links.length > 0) fields.push({ label: "Links", value: /* @__PURE__ */ jsx28(ArtistLinks, { links }) });
|
|
1837
1817
|
if (fields.length === 0) return null;
|
|
1838
|
-
return /* @__PURE__ */
|
|
1818
|
+
return /* @__PURE__ */ jsx28(FieldList, { items: fields });
|
|
1839
1819
|
}
|
|
1840
1820
|
|
|
1841
1821
|
// src/genre-tree/artist/ArtistPhoto.tsx
|
|
1842
|
-
import { jsx as
|
|
1822
|
+
import { jsx as jsx29, jsxs as jsxs18 } from "react/jsx-runtime";
|
|
1843
1823
|
function ExternalLink({ href, children }) {
|
|
1844
|
-
return /* @__PURE__ */
|
|
1824
|
+
return /* @__PURE__ */ jsx29("a", { href, target: "_blank", rel: "noopener noreferrer", className: "underline-offset-2 hover:underline", children });
|
|
1845
1825
|
}
|
|
1846
1826
|
function ArtistPhoto({ image, name }) {
|
|
1847
1827
|
return /* @__PURE__ */ jsxs18("figure", { className: "flex flex-col gap-1.5", children: [
|
|
1848
|
-
/* @__PURE__ */
|
|
1828
|
+
/* @__PURE__ */ jsx29("img", { src: image.url, alt: name, className: "h-64 w-full object-contain bg-[var(--color-surface-muted)] rounded" }),
|
|
1849
1829
|
/* @__PURE__ */ jsxs18("figcaption", { className: "text-caption text-[var(--color-text-muted)]", children: [
|
|
1850
1830
|
"Photo: ",
|
|
1851
|
-
/* @__PURE__ */
|
|
1831
|
+
/* @__PURE__ */ jsx29(ExternalLink, { href: image.pageUrl, children: image.author ?? "Wikimedia Commons" }),
|
|
1852
1832
|
",",
|
|
1853
1833
|
" ",
|
|
1854
|
-
image.licenseUrl ? /* @__PURE__ */
|
|
1834
|
+
image.licenseUrl ? /* @__PURE__ */ jsx29(ExternalLink, { href: image.licenseUrl, children: image.license }) : image.license
|
|
1855
1835
|
] })
|
|
1856
1836
|
] });
|
|
1857
1837
|
}
|
|
1858
1838
|
|
|
1859
1839
|
// src/genre-tree/artist/ArtistMembers.tsx
|
|
1860
1840
|
import { PanelGroup, PanelSection as PanelSection3 } from "@behindthemusictree/ui";
|
|
1861
|
-
import { jsx as
|
|
1841
|
+
import { jsx as jsx30, jsxs as jsxs19 } from "react/jsx-runtime";
|
|
1862
1842
|
function MembershipList({ title, memberships, renderArtistLink }) {
|
|
1863
1843
|
if (memberships.length === 0) return null;
|
|
1864
|
-
return /* @__PURE__ */
|
|
1844
|
+
return /* @__PURE__ */ jsx30(PanelGroup, { title, children: /* @__PURE__ */ jsx30("ul", { children: memberships.map((membership, index) => {
|
|
1865
1845
|
const details = [
|
|
1866
1846
|
formatYears(membership.beginYear, membership.endYear, membership.ended),
|
|
1867
1847
|
...membership.roles
|
|
@@ -1870,7 +1850,7 @@ function MembershipList({ title, memberships, renderArtistLink }) {
|
|
|
1870
1850
|
return (
|
|
1871
1851
|
// A member can have several periods in the same group.
|
|
1872
1852
|
/* @__PURE__ */ jsxs19("li", { className: "truncate py-0.5", title: detailsText || void 0, children: [
|
|
1873
|
-
/* @__PURE__ */
|
|
1853
|
+
/* @__PURE__ */ jsx30("span", { className: "font-medium text-[var(--color-text)]", children: renderArtistLink(membership.artist) }),
|
|
1874
1854
|
detailsText && /* @__PURE__ */ jsxs19("span", { className: "text-[var(--color-text-muted)]", children: [
|
|
1875
1855
|
" \u2014 ",
|
|
1876
1856
|
detailsText
|
|
@@ -1883,8 +1863,8 @@ function ArtistMembers({ title, memberships, renderArtistLink }) {
|
|
|
1883
1863
|
if (memberships.length === 0) return null;
|
|
1884
1864
|
const isCurrent = (membership) => !membership.ended && membership.endYear === null;
|
|
1885
1865
|
return /* @__PURE__ */ jsxs19(PanelSection3, { title, children: [
|
|
1886
|
-
/* @__PURE__ */
|
|
1887
|
-
/* @__PURE__ */
|
|
1866
|
+
/* @__PURE__ */ jsx30(MembershipList, { title: "Current", memberships: memberships.filter(isCurrent), renderArtistLink }),
|
|
1867
|
+
/* @__PURE__ */ jsx30(
|
|
1888
1868
|
MembershipList,
|
|
1889
1869
|
{
|
|
1890
1870
|
title: "Past",
|
|
@@ -1897,7 +1877,7 @@ function ArtistMembers({ title, memberships, renderArtistLink }) {
|
|
|
1897
1877
|
|
|
1898
1878
|
// src/genre-tree/artist/ArtistDiscography.tsx
|
|
1899
1879
|
import { PanelGroup as PanelGroup2, PanelSection as PanelSection4 } from "@behindthemusictree/ui";
|
|
1900
|
-
import { jsx as
|
|
1880
|
+
import { jsx as jsx31, jsxs as jsxs20 } from "react/jsx-runtime";
|
|
1901
1881
|
var GROUPS = ["Albums", "EPs", "Singles", "Live", "Compilations", "Other"];
|
|
1902
1882
|
var PRIMARY_GROUPS = { album: "Albums", ep: "EPs", single: "Singles" };
|
|
1903
1883
|
function discographyGroup({ primaryType, secondaryTypes }) {
|
|
@@ -1917,12 +1897,12 @@ function byYear(a, b) {
|
|
|
1917
1897
|
function ArtistDiscography({ albums }) {
|
|
1918
1898
|
if (albums.length === 0) return null;
|
|
1919
1899
|
const sorted = [...albums].sort(byYear);
|
|
1920
|
-
return /* @__PURE__ */
|
|
1900
|
+
return /* @__PURE__ */ jsx31(PanelSection4, { title: "Discography", children: GROUPS.map((group) => {
|
|
1921
1901
|
const groupAlbums = sorted.filter((album) => discographyGroup(album) === group);
|
|
1922
1902
|
if (groupAlbums.length === 0) return null;
|
|
1923
|
-
return /* @__PURE__ */
|
|
1924
|
-
/* @__PURE__ */
|
|
1925
|
-
/* @__PURE__ */
|
|
1903
|
+
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: [
|
|
1904
|
+
/* @__PURE__ */ jsx31("span", { className: "tabular-nums text-[var(--color-text-muted)]", children: album.year ?? "\u2014" }),
|
|
1905
|
+
/* @__PURE__ */ jsx31("span", { className: "truncate text-[var(--color-text)]", title: album.name, children: album.name })
|
|
1926
1906
|
] }, album.uuid)) }) }, group);
|
|
1927
1907
|
}) });
|
|
1928
1908
|
}
|
|
@@ -1949,7 +1929,7 @@ import { useTrackList as useTrackList4 } from "@behindthemusictree/app-kit/genre
|
|
|
1949
1929
|
import { FaPlay as FaPlay2, FaPause as FaPause2 } from "react-icons/fa";
|
|
1950
1930
|
import { usePlayer as usePlayer7 } from "@behindthemusictree/app-kit/player";
|
|
1951
1931
|
import { PlayStates as PlayStates2 } from "@behindthemusictree/app-kit/player";
|
|
1952
|
-
import { jsx as
|
|
1932
|
+
import { jsx as jsx32, jsxs as jsxs21 } from "react/jsx-runtime";
|
|
1953
1933
|
function TrackPositionPlayPause({
|
|
1954
1934
|
position,
|
|
1955
1935
|
uuid,
|
|
@@ -1970,7 +1950,7 @@ function TrackPositionPlayPause({
|
|
|
1970
1950
|
style: { minWidth: "4rem", maxWidth: "4rem" },
|
|
1971
1951
|
onClick: handlePlayPauseClick,
|
|
1972
1952
|
children: [
|
|
1973
|
-
/* @__PURE__ */
|
|
1953
|
+
/* @__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
1954
|
"span",
|
|
1975
1955
|
{
|
|
1976
1956
|
className: "track-position-play-pause__bars",
|
|
@@ -1978,18 +1958,18 @@ function TrackPositionPlayPause({
|
|
|
1978
1958
|
role: "img",
|
|
1979
1959
|
"aria-label": isPlaying ? "Playing" : "Paused",
|
|
1980
1960
|
children: [
|
|
1981
|
-
/* @__PURE__ */
|
|
1982
|
-
/* @__PURE__ */
|
|
1983
|
-
/* @__PURE__ */
|
|
1961
|
+
/* @__PURE__ */ jsx32("span", { className: "track-position-play-pause__bar" }),
|
|
1962
|
+
/* @__PURE__ */ jsx32("span", { className: "track-position-play-pause__bar" }),
|
|
1963
|
+
/* @__PURE__ */ jsx32("span", { className: "track-position-play-pause__bar" })
|
|
1984
1964
|
]
|
|
1985
1965
|
}
|
|
1986
1966
|
) : position }),
|
|
1987
|
-
/* @__PURE__ */
|
|
1967
|
+
/* @__PURE__ */ jsx32(
|
|
1988
1968
|
"div",
|
|
1989
1969
|
{
|
|
1990
1970
|
className: `hidden group-hover:flex items-center justify-center ${isCurrentTrackActive ? "" : "absolute inset-0"}`,
|
|
1991
1971
|
"aria-hidden": "true",
|
|
1992
|
-
children: isAwaitingPlayback ? /* @__PURE__ */
|
|
1972
|
+
children: isAwaitingPlayback ? /* @__PURE__ */ jsx32("span", { className: "track-position-play-pause__spinner" }) : isPlaying ? /* @__PURE__ */ jsx32(FaPause2, {}) : /* @__PURE__ */ jsx32(FaPlay2, {})
|
|
1993
1973
|
}
|
|
1994
1974
|
)
|
|
1995
1975
|
]
|
|
@@ -2000,7 +1980,7 @@ function TrackPositionPlayPause({
|
|
|
2000
1980
|
// src/genre-tree/track-list-sidebar/TrackItem.tsx
|
|
2001
1981
|
import { isSong as isSong2, songUnplayableReason as songUnplayableReason2 } from "@behindthemusictree/app-kit/genre-tree";
|
|
2002
1982
|
import { ArtistNames as ArtistNames2 } from "@behindthemusictree/app-kit/genre-tree";
|
|
2003
|
-
import { jsx as
|
|
1983
|
+
import { jsx as jsx33, jsxs as jsxs22 } from "react/jsx-runtime";
|
|
2004
1984
|
function TrackItem({
|
|
2005
1985
|
track,
|
|
2006
1986
|
position,
|
|
@@ -2029,7 +2009,7 @@ function TrackItem({
|
|
|
2029
2009
|
{
|
|
2030
2010
|
className: `track-item flex h-14 text-[var(--color-text)] ${isUnplayable ? "opacity-50" : "hover:bg-[var(--color-surface-muted)] group"}`,
|
|
2031
2011
|
children: [
|
|
2032
|
-
isUnplayable ? /* @__PURE__ */
|
|
2012
|
+
isUnplayable ? /* @__PURE__ */ jsx33(
|
|
2033
2013
|
"div",
|
|
2034
2014
|
{
|
|
2035
2015
|
className: "flex items-center justify-center text-lg w-16",
|
|
@@ -2037,7 +2017,7 @@ function TrackItem({
|
|
|
2037
2017
|
"aria-disabled": "true",
|
|
2038
2018
|
children: position
|
|
2039
2019
|
}
|
|
2040
|
-
) : /* @__PURE__ */
|
|
2020
|
+
) : /* @__PURE__ */ jsx33(
|
|
2041
2021
|
TrackPositionPlayPause,
|
|
2042
2022
|
{
|
|
2043
2023
|
position,
|
|
@@ -2047,11 +2027,11 @@ function TrackItem({
|
|
|
2047
2027
|
}
|
|
2048
2028
|
),
|
|
2049
2029
|
/* @__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__ */
|
|
2030
|
+
/* @__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 }) }),
|
|
2031
|
+
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
2032
|
] }),
|
|
2053
|
-
/* @__PURE__ */
|
|
2054
|
-
renderDuration && /* @__PURE__ */
|
|
2033
|
+
/* @__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 }) : "" }),
|
|
2034
|
+
renderDuration && /* @__PURE__ */ jsx33(
|
|
2055
2035
|
"div",
|
|
2056
2036
|
{
|
|
2057
2037
|
className: "duration flex text-base w-16 items-center justify-center",
|
|
@@ -2059,14 +2039,14 @@ function TrackItem({
|
|
|
2059
2039
|
children: renderDuration(track)
|
|
2060
2040
|
}
|
|
2061
2041
|
),
|
|
2062
|
-
renderActions && /* @__PURE__ */
|
|
2042
|
+
renderActions && /* @__PURE__ */ jsx33("div", { className: "edit flex text-base w-6 items-center justify-center mr-2 cursor-pointer", children: renderActions(track) })
|
|
2063
2043
|
]
|
|
2064
2044
|
}
|
|
2065
2045
|
);
|
|
2066
2046
|
}
|
|
2067
2047
|
|
|
2068
2048
|
// src/genre-tree/artist/ArtistSongs.tsx
|
|
2069
|
-
import { Fragment as Fragment12, jsx as
|
|
2049
|
+
import { Fragment as Fragment12, jsx as jsx34, jsxs as jsxs23 } from "react/jsx-runtime";
|
|
2070
2050
|
var SongPageSchema2 = PaginatedResponseSchema2(SongDetailedSchema2);
|
|
2071
2051
|
var SORTS = [
|
|
2072
2052
|
{ ordering: "title", label: "Title" },
|
|
@@ -2099,7 +2079,7 @@ function ArtistSongs({ artist, getBackendBaseUrl, renderArtistLink, renderSongLi
|
|
|
2099
2079
|
event.stopPropagation();
|
|
2100
2080
|
void play(song.uuid);
|
|
2101
2081
|
};
|
|
2102
|
-
return /* @__PURE__ */
|
|
2082
|
+
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: [
|
|
2103
2083
|
/* @__PURE__ */ jsxs23("div", { className: "flex flex-wrap items-center justify-between gap-2 mb-2", children: [
|
|
2104
2084
|
/* @__PURE__ */ jsxs23(
|
|
2105
2085
|
"button",
|
|
@@ -2108,12 +2088,12 @@ function ArtistSongs({ artist, getBackendBaseUrl, renderArtistLink, renderSongLi
|
|
|
2108
2088
|
onClick: () => void play(),
|
|
2109
2089
|
className: "flex w-fit items-center gap-1.5 px-3 py-1 text-caption font-medium bg-gray-900 text-white rounded-full hover:bg-gray-700",
|
|
2110
2090
|
children: [
|
|
2111
|
-
/* @__PURE__ */
|
|
2091
|
+
/* @__PURE__ */ jsx34(Play3, { className: "h-3.5 w-3.5", "aria-hidden": "true" }),
|
|
2112
2092
|
"Play all"
|
|
2113
2093
|
]
|
|
2114
2094
|
}
|
|
2115
2095
|
),
|
|
2116
|
-
/* @__PURE__ */
|
|
2096
|
+
/* @__PURE__ */ jsx34("div", { role: "group", "aria-label": "Sort songs by", className: "flex gap-1 text-caption", children: SORTS.map((sort) => /* @__PURE__ */ jsx34(
|
|
2117
2097
|
"button",
|
|
2118
2098
|
{
|
|
2119
2099
|
type: "button",
|
|
@@ -2128,7 +2108,7 @@ function ArtistSongs({ artist, getBackendBaseUrl, renderArtistLink, renderSongLi
|
|
|
2128
2108
|
sort.ordering
|
|
2129
2109
|
)) })
|
|
2130
2110
|
] }),
|
|
2131
|
-
/* @__PURE__ */
|
|
2111
|
+
/* @__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
2112
|
TrackItem,
|
|
2133
2113
|
{
|
|
2134
2114
|
track: song,
|
|
@@ -2137,12 +2117,12 @@ function ArtistSongs({ artist, getBackendBaseUrl, renderArtistLink, renderSongLi
|
|
|
2137
2117
|
renderSongLink
|
|
2138
2118
|
}
|
|
2139
2119
|
) }, song.uuid)) }),
|
|
2140
|
-
/* @__PURE__ */
|
|
2120
|
+
/* @__PURE__ */ jsx34(Pagination, { currentPage: page, totalPages: data.totalPages, onPageChange: setPage })
|
|
2141
2121
|
] }) });
|
|
2142
2122
|
}
|
|
2143
2123
|
|
|
2144
2124
|
// src/genre-tree/artist/useArtistPanel.tsx
|
|
2145
|
-
import { Fragment as Fragment13, jsx as
|
|
2125
|
+
import { Fragment as Fragment13, jsx as jsx35, jsxs as jsxs24 } from "react/jsx-runtime";
|
|
2146
2126
|
function useArtistPanel({
|
|
2147
2127
|
uuid,
|
|
2148
2128
|
scope,
|
|
@@ -2164,25 +2144,25 @@ function useArtistPanel({
|
|
|
2164
2144
|
...panel,
|
|
2165
2145
|
title: "Artist",
|
|
2166
2146
|
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__ */
|
|
2147
|
+
/* @__PURE__ */ jsx35(Skeleton5, { className: "h-3 w-16" }),
|
|
2148
|
+
/* @__PURE__ */ jsx35(Skeleton5, { className: "h-4 w-32" }),
|
|
2149
|
+
/* @__PURE__ */ jsx35(Skeleton5, { className: "h-3 w-16" }),
|
|
2150
|
+
/* @__PURE__ */ jsx35(Skeleton5, { className: "h-4 w-24" }),
|
|
2151
|
+
/* @__PURE__ */ jsx35(Skeleton5, { className: "h-16 mt-2.5" }),
|
|
2152
|
+
/* @__PURE__ */ jsx35(Skeleton5, { className: "h-16" })
|
|
2173
2153
|
] })
|
|
2174
2154
|
};
|
|
2175
2155
|
case "not-found":
|
|
2176
2156
|
return {
|
|
2177
2157
|
...panel,
|
|
2178
2158
|
title: "Artist not found",
|
|
2179
|
-
content: /* @__PURE__ */
|
|
2159
|
+
content: /* @__PURE__ */ jsx35("p", { className: "text-[var(--color-text-muted)]", children: "This artist does not exist." })
|
|
2180
2160
|
};
|
|
2181
2161
|
case "error":
|
|
2182
2162
|
return {
|
|
2183
2163
|
...panel,
|
|
2184
2164
|
title: "Artist",
|
|
2185
|
-
content: /* @__PURE__ */
|
|
2165
|
+
content: /* @__PURE__ */ jsx35("p", { className: "text-red-600", children: "Could not load this artist." })
|
|
2186
2166
|
};
|
|
2187
2167
|
case "success": {
|
|
2188
2168
|
const { artist } = result;
|
|
@@ -2192,18 +2172,18 @@ function useArtistPanel({
|
|
|
2192
2172
|
...panel,
|
|
2193
2173
|
title: artist.name,
|
|
2194
2174
|
content: /* @__PURE__ */ jsxs24(Fragment13, { children: [
|
|
2195
|
-
/* @__PURE__ */
|
|
2175
|
+
/* @__PURE__ */ jsx35(
|
|
2196
2176
|
ArtistActionBand,
|
|
2197
2177
|
{
|
|
2198
2178
|
artist,
|
|
2199
|
-
share: shareTarget && shareUrl ? /* @__PURE__ */
|
|
2179
|
+
share: shareTarget && shareUrl ? /* @__PURE__ */ jsx35(ShareActionButton, { target: shareTarget, url: shareUrl }) : void 0
|
|
2200
2180
|
}
|
|
2201
2181
|
),
|
|
2202
|
-
artist.image && /* @__PURE__ */
|
|
2203
|
-
/* @__PURE__ */
|
|
2204
|
-
/* @__PURE__ */
|
|
2205
|
-
/* @__PURE__ */
|
|
2206
|
-
artist.tracksCount > 0 && /* @__PURE__ */
|
|
2182
|
+
artist.image && /* @__PURE__ */ jsx35(ArtistPhoto, { image: artist.image, name: artist.name }),
|
|
2183
|
+
/* @__PURE__ */ jsx35(ArtistHeader, { artist }),
|
|
2184
|
+
/* @__PURE__ */ jsx35(ArtistMembers, { title: "Members", memberships: artist.members, renderArtistLink }),
|
|
2185
|
+
/* @__PURE__ */ jsx35(ArtistMembers, { title: "Member of", memberships: artist.memberOf, renderArtistLink }),
|
|
2186
|
+
artist.tracksCount > 0 && /* @__PURE__ */ jsx35(
|
|
2207
2187
|
ArtistSongs,
|
|
2208
2188
|
{
|
|
2209
2189
|
artist: { uuid: artist.uuid, name: artist.name },
|
|
@@ -2213,7 +2193,7 @@ function useArtistPanel({
|
|
|
2213
2193
|
}
|
|
2214
2194
|
)
|
|
2215
2195
|
] }),
|
|
2216
|
-
extraContent: artist.albums.length > 0 ? /* @__PURE__ */
|
|
2196
|
+
extraContent: artist.albums.length > 0 ? /* @__PURE__ */ jsx35(ArtistDiscography, { albums: artist.albums }) : void 0
|
|
2217
2197
|
};
|
|
2218
2198
|
}
|
|
2219
2199
|
}
|
|
@@ -2237,7 +2217,7 @@ import {
|
|
|
2237
2217
|
useSongHistory,
|
|
2238
2218
|
useTrackList as useTrackList6
|
|
2239
2219
|
} from "@behindthemusictree/app-kit/genre-tree";
|
|
2240
|
-
import { Fragment as Fragment14, jsx as
|
|
2220
|
+
import { Fragment as Fragment14, jsx as jsx36, jsxs as jsxs25 } from "react/jsx-runtime";
|
|
2241
2221
|
var numberFormat = new Intl.NumberFormat("en");
|
|
2242
2222
|
var dateFormat = new Intl.DateTimeFormat("en", { dateStyle: "medium" });
|
|
2243
2223
|
var externalLink = "text-[var(--color-primary)] hover:underline focus-visible:underline";
|
|
@@ -2245,11 +2225,11 @@ function SongHistory({ uuid, getBackendBaseUrl }) {
|
|
|
2245
2225
|
const [open, setOpen] = useState9(false);
|
|
2246
2226
|
const history = useSongHistory(uuid, getBackendBaseUrl, open);
|
|
2247
2227
|
let body = null;
|
|
2248
|
-
if (history.status === "loading") body = /* @__PURE__ */
|
|
2249
|
-
else if (history.status === "error") body = /* @__PURE__ */
|
|
2228
|
+
if (history.status === "loading") body = /* @__PURE__ */ jsx36(Skeleton6, { className: "h-10", "aria-busy": "true" });
|
|
2229
|
+
else if (history.status === "error") body = /* @__PURE__ */ jsx36("p", { className: "text-red-600", children: "Could not load the history." });
|
|
2250
2230
|
else if (history.status === "success")
|
|
2251
|
-
body = history.entries.length === 0 ? /* @__PURE__ */
|
|
2252
|
-
/* @__PURE__ */
|
|
2231
|
+
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: [
|
|
2232
|
+
/* @__PURE__ */ jsx36("span", { className: "font-medium", children: entry.action }),
|
|
2253
2233
|
entry.oldValue !== null || entry.newValue !== null ? /* @__PURE__ */ jsxs25("span", { className: "text-[var(--color-text-muted)]", children: [
|
|
2254
2234
|
" ",
|
|
2255
2235
|
"\u2014 ",
|
|
@@ -2263,9 +2243,9 @@ function SongHistory({ uuid, getBackendBaseUrl }) {
|
|
|
2263
2243
|
dateFormat.format(new Date(entry.createdOn))
|
|
2264
2244
|
] })
|
|
2265
2245
|
] }, entry.uuid)) });
|
|
2266
|
-
return /* @__PURE__ */
|
|
2267
|
-
/* @__PURE__ */
|
|
2268
|
-
/* @__PURE__ */
|
|
2246
|
+
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: [
|
|
2247
|
+
/* @__PURE__ */ jsx36("summary", { className: `mt-2.5 cursor-pointer ${PANEL_LABEL_CLASS}`, children: "History" }),
|
|
2248
|
+
/* @__PURE__ */ jsx36("div", { className: "mt-1.5", children: body })
|
|
2269
2249
|
] }) });
|
|
2270
2250
|
}
|
|
2271
2251
|
function SongPanelContent(props) {
|
|
@@ -2284,13 +2264,13 @@ function SongPanelContent(props) {
|
|
|
2284
2264
|
const genre = song.genre;
|
|
2285
2265
|
fields.push({
|
|
2286
2266
|
label: "Genre",
|
|
2287
|
-
value: onSelectGenre ? /* @__PURE__ */
|
|
2288
|
-
index > 0 && /* @__PURE__ */
|
|
2289
|
-
/* @__PURE__ */
|
|
2267
|
+
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: [
|
|
2268
|
+
index > 0 && /* @__PURE__ */ jsx36("span", { "aria-hidden": "true", children: "\u203A " }),
|
|
2269
|
+
/* @__PURE__ */ jsx36("button", { type: "button", onClick: () => props.onSelectGenrePlaylist?.(genrePlaylist), className: "hover:underline", children: genrePlaylist.name })
|
|
2290
2270
|
] }, genrePlaylist.uuid)) }) : song.genre.name
|
|
2291
2271
|
});
|
|
2292
2272
|
} else {
|
|
2293
|
-
fields.push({ label: "Genre", value: /* @__PURE__ */
|
|
2273
|
+
fields.push({ label: "Genre", value: /* @__PURE__ */ jsx36("span", { className: "text-[var(--color-text-muted)]", children: "No genre" }) });
|
|
2294
2274
|
}
|
|
2295
2275
|
if (song.firstReleaseYear) fields.push({ label: "First released", value: song.firstReleaseYear });
|
|
2296
2276
|
const viewCount = song.youtubeVideo?.viewCount;
|
|
@@ -2300,11 +2280,11 @@ function SongPanelContent(props) {
|
|
|
2300
2280
|
const links = [];
|
|
2301
2281
|
if (musicBrainzUrl)
|
|
2302
2282
|
links.push(
|
|
2303
|
-
/* @__PURE__ */
|
|
2283
|
+
/* @__PURE__ */ jsx36("a", { href: musicBrainzUrl, target: "_blank", rel: "noopener noreferrer", className: externalLink, children: "MusicBrainz" }, "mb")
|
|
2304
2284
|
);
|
|
2305
2285
|
if (song.youtubeVideo)
|
|
2306
2286
|
links.push(
|
|
2307
|
-
/* @__PURE__ */
|
|
2287
|
+
/* @__PURE__ */ jsx36(
|
|
2308
2288
|
"a",
|
|
2309
2289
|
{
|
|
2310
2290
|
href: `https://www.youtube.com/watch?v=${encodeURIComponent(song.youtubeVideo.id)}`,
|
|
@@ -2319,31 +2299,31 @@ function SongPanelContent(props) {
|
|
|
2319
2299
|
if (links.length > 0)
|
|
2320
2300
|
fields.push({
|
|
2321
2301
|
label: "Links",
|
|
2322
|
-
value: /* @__PURE__ */
|
|
2302
|
+
value: /* @__PURE__ */ jsx36("span", { className: "flex gap-3", children: links })
|
|
2323
2303
|
});
|
|
2324
2304
|
return /* @__PURE__ */ jsxs25(Fragment14, { children: [
|
|
2325
|
-
/* @__PURE__ */
|
|
2326
|
-
/* @__PURE__ */
|
|
2305
|
+
/* @__PURE__ */ jsx36(PanelBleed3, { children: /* @__PURE__ */ jsxs25(ActionBand3, { children: [
|
|
2306
|
+
/* @__PURE__ */ jsx36(
|
|
2327
2307
|
ActionButton5,
|
|
2328
2308
|
{
|
|
2329
|
-
icon: isPlaying ? /* @__PURE__ */
|
|
2309
|
+
icon: isPlaying ? /* @__PURE__ */ jsx36(Pause3, { "aria-hidden": "true", className: "w-5 h-5" }) : /* @__PURE__ */ jsx36(Play4, { "aria-hidden": "true", className: "w-5 h-5" }),
|
|
2330
2310
|
label: isPlaying ? "Pause" : "Play",
|
|
2331
2311
|
disabled: !!unplayableReason,
|
|
2332
2312
|
title: unplayableReason ?? void 0,
|
|
2333
2313
|
onClick: () => isCurrent ? handlePlayPauseAction() : playNewTrackListFromTrackUuid(song, scope)
|
|
2334
2314
|
}
|
|
2335
2315
|
),
|
|
2336
|
-
shareUrl && /* @__PURE__ */
|
|
2316
|
+
shareUrl && /* @__PURE__ */ jsx36(ShareActionButton, { target: shareTarget, url: shareUrl })
|
|
2337
2317
|
] }) }),
|
|
2338
|
-
song.artists && song.artists.length > 0 && /* @__PURE__ */
|
|
2339
|
-
/* @__PURE__ */
|
|
2340
|
-
song.essentialGenres && song.essentialGenres.length > 0 && /* @__PURE__ */
|
|
2341
|
-
/* @__PURE__ */
|
|
2318
|
+
song.artists && song.artists.length > 0 && /* @__PURE__ */ jsx36("p", { className: "text-[var(--color-text-muted)]", children: /* @__PURE__ */ jsx36(ArtistNames3, { artists: song.artists, renderArtistLink }) }),
|
|
2319
|
+
/* @__PURE__ */ jsx36(FieldList2, { items: fields }),
|
|
2320
|
+
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)) }) }),
|
|
2321
|
+
/* @__PURE__ */ jsx36(SongHistory, { uuid: song.uuid, getBackendBaseUrl })
|
|
2342
2322
|
] });
|
|
2343
2323
|
}
|
|
2344
2324
|
|
|
2345
2325
|
// src/genre-tree/song/useSongPanel.tsx
|
|
2346
|
-
import { jsx as
|
|
2326
|
+
import { jsx as jsx37, jsxs as jsxs26 } from "react/jsx-runtime";
|
|
2347
2327
|
function useSongPanel({
|
|
2348
2328
|
uuid,
|
|
2349
2329
|
scope,
|
|
@@ -2365,23 +2345,23 @@ function useSongPanel({
|
|
|
2365
2345
|
...panel,
|
|
2366
2346
|
title: "Song",
|
|
2367
2347
|
content: /* @__PURE__ */ jsxs26("div", { "aria-busy": "true", className: "flex flex-col gap-2.5", children: [
|
|
2368
|
-
/* @__PURE__ */
|
|
2369
|
-
/* @__PURE__ */
|
|
2370
|
-
/* @__PURE__ */
|
|
2371
|
-
/* @__PURE__ */
|
|
2348
|
+
/* @__PURE__ */ jsx37(Skeleton7, { className: "h-3 w-16" }),
|
|
2349
|
+
/* @__PURE__ */ jsx37(Skeleton7, { className: "h-4 w-32" }),
|
|
2350
|
+
/* @__PURE__ */ jsx37(Skeleton7, { className: "h-3 w-16" }),
|
|
2351
|
+
/* @__PURE__ */ jsx37(Skeleton7, { className: "h-4 w-24" })
|
|
2372
2352
|
] })
|
|
2373
2353
|
};
|
|
2374
2354
|
case "not-found":
|
|
2375
2355
|
return {
|
|
2376
2356
|
...panel,
|
|
2377
2357
|
title: "Song not found",
|
|
2378
|
-
content: /* @__PURE__ */
|
|
2358
|
+
content: /* @__PURE__ */ jsx37("p", { className: "text-[var(--color-text-muted)]", children: "This song does not exist." })
|
|
2379
2359
|
};
|
|
2380
2360
|
case "error":
|
|
2381
2361
|
return {
|
|
2382
2362
|
...panel,
|
|
2383
2363
|
title: "Song",
|
|
2384
|
-
content: /* @__PURE__ */
|
|
2364
|
+
content: /* @__PURE__ */ jsx37("p", { className: "text-red-600", children: "Could not load this song." })
|
|
2385
2365
|
};
|
|
2386
2366
|
case "success": {
|
|
2387
2367
|
const { song } = result;
|
|
@@ -2389,7 +2369,7 @@ function useSongPanel({
|
|
|
2389
2369
|
return {
|
|
2390
2370
|
...panel,
|
|
2391
2371
|
title: song.title,
|
|
2392
|
-
content: /* @__PURE__ */
|
|
2372
|
+
content: /* @__PURE__ */ jsx37(
|
|
2393
2373
|
SongPanelContent,
|
|
2394
2374
|
{
|
|
2395
2375
|
song,
|
|
@@ -2442,12 +2422,12 @@ function useEntityPanel({
|
|
|
2442
2422
|
// src/genre-tree/SizeMetricToggle.tsx
|
|
2443
2423
|
import { MdMusicNote, MdVisibility } from "react-icons/md";
|
|
2444
2424
|
import { SegmentedControl } from "@behindthemusictree/ui";
|
|
2445
|
-
import { jsx as
|
|
2425
|
+
import { jsx as jsx38 } from "react/jsx-runtime";
|
|
2446
2426
|
function SizeMetricToggle({
|
|
2447
2427
|
value,
|
|
2448
2428
|
onChange
|
|
2449
2429
|
}) {
|
|
2450
|
-
return /* @__PURE__ */
|
|
2430
|
+
return /* @__PURE__ */ jsx38(
|
|
2451
2431
|
SegmentedControl,
|
|
2452
2432
|
{
|
|
2453
2433
|
variant: "floating",
|
|
@@ -2455,15 +2435,15 @@ function SizeMetricToggle({
|
|
|
2455
2435
|
value,
|
|
2456
2436
|
onChange,
|
|
2457
2437
|
options: [
|
|
2458
|
-
{ value: "songs", label: /* @__PURE__ */
|
|
2459
|
-
{ value: "views", label: /* @__PURE__ */
|
|
2438
|
+
{ value: "songs", label: /* @__PURE__ */ jsx38(MdMusicNote, { size: 18, "aria-hidden": true }), "aria-label": "Size by songs", title: "Node size by song count" },
|
|
2439
|
+
{ value: "views", label: /* @__PURE__ */ jsx38(MdVisibility, { size: 18, "aria-hidden": true }), "aria-label": "Size by views", title: "Node size by song views" }
|
|
2460
2440
|
]
|
|
2461
2441
|
}
|
|
2462
2442
|
);
|
|
2463
2443
|
}
|
|
2464
2444
|
|
|
2465
2445
|
// src/genre-tree/GenreTreeView.tsx
|
|
2466
|
-
import { Fragment as Fragment15, jsx as
|
|
2446
|
+
import { Fragment as Fragment15, jsx as jsx39, jsxs as jsxs27 } from "react/jsx-runtime";
|
|
2467
2447
|
var NO_POP_ROOT_TITLE = "This genre tree has no 'Mainstream Pop' root yet";
|
|
2468
2448
|
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
2449
|
var noop = () => {
|
|
@@ -2555,6 +2535,7 @@ function GenreTreeView({
|
|
|
2555
2535
|
isFetching: isTreeFetching,
|
|
2556
2536
|
genrePlaylistByNodeId,
|
|
2557
2537
|
visibleGenrePlaylists,
|
|
2538
|
+
focusUuids,
|
|
2558
2539
|
groupedGenrePlaylistsByRoot,
|
|
2559
2540
|
selectedGenreUuid,
|
|
2560
2541
|
selectGenre,
|
|
@@ -2614,14 +2595,14 @@ function GenreTreeView({
|
|
|
2614
2595
|
const openSongRef = useRef3(openSong);
|
|
2615
2596
|
openSongRef.current = openSong;
|
|
2616
2597
|
const resolvedRenderSongLink = useCallback6(
|
|
2617
|
-
(song) => renderSongLink ? renderSongLink(song) : /* @__PURE__ */
|
|
2598
|
+
(song) => renderSongLink ? renderSongLink(song) : /* @__PURE__ */ jsx39("button", { type: "button", onClick: () => openSongRef.current(song.uuid), className: "hover:underline", children: song.title }),
|
|
2618
2599
|
[renderSongLink]
|
|
2619
2600
|
);
|
|
2620
2601
|
const [expandedSongUuid, setExpandedSongUuid] = useState10(null);
|
|
2621
2602
|
const [expandedArtistUuid, setExpandedArtistUuid] = useState10(null);
|
|
2622
2603
|
const artistBaseUrl = artistSearchBaseUrl ?? getBackendBaseUrl;
|
|
2623
2604
|
const songBaseUrl = getBackendBaseUrl;
|
|
2624
|
-
const resolvedRenderArtistLink = renderArtistLink ?? ((artist) => artist.isSpecialPurpose ? artist.name : /* @__PURE__ */
|
|
2605
|
+
const resolvedRenderArtistLink = renderArtistLink ?? ((artist) => artist.isSpecialPurpose ? artist.name : /* @__PURE__ */ jsx39("button", { type: "button", onClick: () => openArtist(artist.uuid), className: "hover:underline", children: artist.name }));
|
|
2625
2606
|
const getGenrePath = (genre) => {
|
|
2626
2607
|
const path = [];
|
|
2627
2608
|
let current = visibleGenrePlaylists.find((playlist) => playlist.criteria?.uuid === genre.uuid);
|
|
@@ -2663,7 +2644,7 @@ function GenreTreeView({
|
|
|
2663
2644
|
selectGenrePlaylist(genrePlaylist2);
|
|
2664
2645
|
}
|
|
2665
2646
|
});
|
|
2666
|
-
const
|
|
2647
|
+
const otherPanel = overlayPanel ?? (selectedGenreUuid !== null ? void 0 : entityPanel);
|
|
2667
2648
|
const [uncontrolledCollapsed, setUncontrolledCollapsed] = useState10(false);
|
|
2668
2649
|
const [uncontrolledExpanded, setUncontrolledExpanded] = useState10(false);
|
|
2669
2650
|
const isCollapsed = collapsed ?? uncontrolledCollapsed;
|
|
@@ -2691,7 +2672,7 @@ function GenreTreeView({
|
|
|
2691
2672
|
const obscuredInset = useObscuredInset(panelRef);
|
|
2692
2673
|
const hostPanel = { obscuredInset, onNodeStyleResolverChange: handleNodeStyleResolverChange };
|
|
2693
2674
|
const nodeMetric = isArtistFiltered || !canSizeByViews ? "songs" : deferredSizeMetric;
|
|
2694
|
-
const treeNodes = useMemo8(() => toTreeNodes(visibleGenrePlaylists, nodeMetric), [visibleGenrePlaylists, nodeMetric]);
|
|
2675
|
+
const treeNodes = useMemo8(() => toTreeNodes(visibleGenrePlaylists, nodeMetric, focusUuids), [visibleGenrePlaylists, nodeMetric, focusUuids]);
|
|
2695
2676
|
const relations = useGenreNodeRelations(
|
|
2696
2677
|
treeNodes,
|
|
2697
2678
|
!overlayPanel && hasSelectedGenreNode ? selectedNodeId : null,
|
|
@@ -2702,7 +2683,7 @@ function GenreTreeView({
|
|
|
2702
2683
|
setSelectionHistory({ current: selectedGenreUuid, previous: selectionHistory.current ?? selectionHistory.previous });
|
|
2703
2684
|
}
|
|
2704
2685
|
const handlePrevious = selectionHistory.previous ? () => selectGenre(selectionHistory.previous) : void 0;
|
|
2705
|
-
const { showPopup, hidePopup } =
|
|
2686
|
+
const { showPopup, hidePopup } = usePopup4();
|
|
2706
2687
|
const reopenPanel = () => {
|
|
2707
2688
|
setUncontrolledCollapsed(false);
|
|
2708
2689
|
onCollapsedChange?.(false);
|
|
@@ -2753,7 +2734,7 @@ function GenreTreeView({
|
|
|
2753
2734
|
onAddChild: readOnly || !criteria ? void 0 : () => handleGenreCreationAction(criteria),
|
|
2754
2735
|
onRename: readOnly || !criteria ? void 0 : () => handleGenreRenameAction(criteria),
|
|
2755
2736
|
onChangeParent: readOnly || !genrePlaylist || !criteria ? void 0 : () => showPopup(
|
|
2756
|
-
/* @__PURE__ */
|
|
2737
|
+
/* @__PURE__ */ jsx39(
|
|
2757
2738
|
ChangeParentPopup,
|
|
2758
2739
|
{
|
|
2759
2740
|
genrePlaylist: { ...genrePlaylist, criteria },
|
|
@@ -2787,15 +2768,15 @@ function GenreTreeView({
|
|
|
2787
2768
|
const isRotationControlled = controlledAllowWheelRotation !== void 0;
|
|
2788
2769
|
const allowWheelRotation = controlledAllowWheelRotation ?? internalAllowWheelRotation;
|
|
2789
2770
|
let activePanel = null;
|
|
2790
|
-
if (
|
|
2771
|
+
if (otherPanel) {
|
|
2791
2772
|
activePanel = {
|
|
2792
|
-
title:
|
|
2793
|
-
content:
|
|
2794
|
-
aside:
|
|
2795
|
-
expanded:
|
|
2796
|
-
onExpandedChange:
|
|
2797
|
-
onClose:
|
|
2798
|
-
|
|
2773
|
+
title: otherPanel.title,
|
|
2774
|
+
content: otherPanel.content,
|
|
2775
|
+
aside: otherPanel.extraContent,
|
|
2776
|
+
expanded: otherPanel.expanded ?? false,
|
|
2777
|
+
onExpandedChange: otherPanel.onExpandedChange,
|
|
2778
|
+
onClose: otherPanel.onClose,
|
|
2779
|
+
searchName: otherPanel.title
|
|
2799
2780
|
};
|
|
2800
2781
|
} else if (selectedGenreUuid) {
|
|
2801
2782
|
activePanel = {
|
|
@@ -2805,38 +2786,28 @@ function GenreTreeView({
|
|
|
2805
2786
|
expanded: isExpanded,
|
|
2806
2787
|
onExpandedChange: changeExpanded,
|
|
2807
2788
|
onClose: clearSelection,
|
|
2808
|
-
|
|
2789
|
+
searchName: genreContent.name,
|
|
2809
2790
|
headerAccent: genreContent.headerAccent
|
|
2810
2791
|
};
|
|
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
2792
|
}
|
|
2822
2793
|
const isPanelShown = activePanel !== null && (selectedGenreUuid !== null || isTreeReady);
|
|
2823
2794
|
const detailTab = placement === "regions" && activePanel?.onExpandedChange ? {
|
|
2824
2795
|
edge: activePanel.expanded ? { label: "Shrink panel", onClick: () => activePanel.onExpandedChange?.(false) } : isCollapsed ? null : { label: "Hide panel", onClick: () => changeCollapsed(true) },
|
|
2825
2796
|
center: activePanel.expanded ? null : isCollapsed ? { label: "Show panel", onClick: () => changeCollapsed(false) } : activePanel.onExpandedChange ? { label: "Extend panel", onClick: () => activePanel.onExpandedChange?.(true) } : null
|
|
2826
2797
|
} : void 0;
|
|
2827
|
-
const expandButton = placement === "default" && activePanel?.onExpandedChange ? /* @__PURE__ */
|
|
2798
|
+
const expandButton = placement === "default" && activePanel?.onExpandedChange ? /* @__PURE__ */ jsx39(
|
|
2828
2799
|
IconButton2,
|
|
2829
2800
|
{
|
|
2830
2801
|
"aria-label": activePanel.expanded ? "Shrink panel" : "Extend panel",
|
|
2831
2802
|
style: activePanel.headerAccent && { color: "inherit" },
|
|
2832
2803
|
onClick: () => activePanel.onExpandedChange?.(!activePanel.expanded),
|
|
2833
|
-
children: activePanel.expanded ? /* @__PURE__ */
|
|
2804
|
+
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
2805
|
}
|
|
2835
2806
|
) : null;
|
|
2836
2807
|
const renderArtistFilter = () => {
|
|
2837
2808
|
if (isLoading || !filterArtist) return null;
|
|
2838
2809
|
return /* @__PURE__ */ jsxs27("span", { className: "inline-flex items-center overflow-hidden rounded-full bg-[var(--color-neutral-100)] text-body", children: [
|
|
2839
|
-
/* @__PURE__ */
|
|
2810
|
+
/* @__PURE__ */ jsx39(
|
|
2840
2811
|
"button",
|
|
2841
2812
|
{
|
|
2842
2813
|
type: "button",
|
|
@@ -2848,7 +2819,7 @@ function GenreTreeView({
|
|
|
2848
2819
|
children: filterArtist.name
|
|
2849
2820
|
}
|
|
2850
2821
|
),
|
|
2851
|
-
/* @__PURE__ */
|
|
2822
|
+
/* @__PURE__ */ jsx39(
|
|
2852
2823
|
"button",
|
|
2853
2824
|
{
|
|
2854
2825
|
type: "button",
|
|
@@ -2861,7 +2832,7 @@ function GenreTreeView({
|
|
|
2861
2832
|
] });
|
|
2862
2833
|
};
|
|
2863
2834
|
const actions = /* @__PURE__ */ jsxs27(Fragment15, { children: [
|
|
2864
|
-
!isLoading && !isError && /* @__PURE__ */
|
|
2835
|
+
!isLoading && !isError && /* @__PURE__ */ jsx39(
|
|
2865
2836
|
GenreTreeSearch,
|
|
2866
2837
|
{
|
|
2867
2838
|
artistBaseUrl,
|
|
@@ -2884,9 +2855,9 @@ function GenreTreeView({
|
|
|
2884
2855
|
if (songUuid) changeSong(null);
|
|
2885
2856
|
selectGenre(uuid);
|
|
2886
2857
|
},
|
|
2887
|
-
selectedName:
|
|
2858
|
+
selectedName: activePanel?.searchName ?? null,
|
|
2888
2859
|
onClear: activePanel?.onClose,
|
|
2889
|
-
showClear: activePanel
|
|
2860
|
+
showClear: activePanel !== null,
|
|
2890
2861
|
clearLabel: "Close panel",
|
|
2891
2862
|
onPrevious: handlePrevious,
|
|
2892
2863
|
onQueryChange: onSearchQueryChange,
|
|
@@ -2894,9 +2865,9 @@ function GenreTreeView({
|
|
|
2894
2865
|
extraGroups: extraSearchGroups
|
|
2895
2866
|
}
|
|
2896
2867
|
),
|
|
2897
|
-
!isLoading && !isError && filterArtist && /* @__PURE__ */
|
|
2868
|
+
!isLoading && !isError && filterArtist && /* @__PURE__ */ jsx39("div", { className: "hidden w-full justify-center max-md:flex", children: renderArtistFilter() }),
|
|
2898
2869
|
/* @__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__ */
|
|
2870
|
+
!isLoading && !isError && !isControlled && /* @__PURE__ */ jsx39(
|
|
2900
2871
|
SegmentedControl2,
|
|
2901
2872
|
{
|
|
2902
2873
|
"aria-label": "Tree view mode",
|
|
@@ -2910,13 +2881,13 @@ function GenreTreeView({
|
|
|
2910
2881
|
]
|
|
2911
2882
|
}
|
|
2912
2883
|
),
|
|
2913
|
-
!isLoading && !isError && showDisplayOptions && /* @__PURE__ */
|
|
2884
|
+
!isLoading && !isError && showDisplayOptions && /* @__PURE__ */ jsx39(
|
|
2914
2885
|
"div",
|
|
2915
2886
|
{
|
|
2916
2887
|
className: "flex items-center gap-1",
|
|
2917
2888
|
role: "group",
|
|
2918
2889
|
"aria-label": "Tree display options",
|
|
2919
|
-
children: !isRotationControlled && viewMode !== "stacked" && viewMode !== "outline" && /* @__PURE__ */
|
|
2890
|
+
children: !isRotationControlled && viewMode !== "stacked" && viewMode !== "outline" && /* @__PURE__ */ jsx39(
|
|
2920
2891
|
Button,
|
|
2921
2892
|
{
|
|
2922
2893
|
variant: allowWheelRotation ? "default" : "outline",
|
|
@@ -2927,7 +2898,7 @@ function GenreTreeView({
|
|
|
2927
2898
|
)
|
|
2928
2899
|
}
|
|
2929
2900
|
),
|
|
2930
|
-
!isLoading && !isError && !readOnly && showAddRoot && /* @__PURE__ */
|
|
2901
|
+
!isLoading && !isError && !readOnly && showAddRoot && /* @__PURE__ */ jsx39(
|
|
2931
2902
|
IconTextButton,
|
|
2932
2903
|
{
|
|
2933
2904
|
icon: Plus2,
|
|
@@ -2943,36 +2914,37 @@ function GenreTreeView({
|
|
|
2943
2914
|
"data-left-panel": isPanelShown && !isCollapsed ? void 0 : "hidden",
|
|
2944
2915
|
className: ["genre-tree-view relative flex flex-col h-full", placement === "regions" && REGIONS_CLASS, className2].filter(Boolean).join(" "),
|
|
2945
2916
|
children: [
|
|
2946
|
-
/* @__PURE__ */
|
|
2917
|
+
/* @__PURE__ */ jsx39(
|
|
2947
2918
|
"div",
|
|
2948
2919
|
{
|
|
2949
2920
|
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
2921
|
children: actions
|
|
2951
2922
|
}
|
|
2952
2923
|
),
|
|
2953
|
-
!isLoading && !isError && filterArtist && /* @__PURE__ */
|
|
2924
|
+
!isLoading && !isError && filterArtist && /* @__PURE__ */ jsx39(
|
|
2954
2925
|
"div",
|
|
2955
2926
|
{
|
|
2956
2927
|
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
2928
|
children: renderArtistFilter()
|
|
2958
2929
|
}
|
|
2959
2930
|
),
|
|
2960
|
-
/* @__PURE__ */
|
|
2961
|
-
!isLoading && !isError && viewMode === "outline" && floatingControlsLeading && /* @__PURE__ */
|
|
2962
|
-
isLoading ? /* @__PURE__ */
|
|
2931
|
+
/* @__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: [
|
|
2932
|
+
!isLoading && !isError && viewMode === "outline" && floatingControlsLeading && /* @__PURE__ */ jsx39("div", { className: "absolute bottom-3 right-3 z-10", children: floatingControlsLeading }),
|
|
2933
|
+
isLoading ? /* @__PURE__ */ jsx39(GenreTreeViewSkeleton, { viewMode }) : isError ? /* @__PURE__ */ jsxs27("p", { role: "alert", className: "m-auto text-center", children: [
|
|
2963
2934
|
"Couldn't load the genre tree.",
|
|
2964
2935
|
" ",
|
|
2965
|
-
/* @__PURE__ */
|
|
2936
|
+
/* @__PURE__ */ jsx39("button", { type: "button", className: "underline", onClick: refetch, children: "Retry" })
|
|
2966
2937
|
] }) : viewMode === "wheel" ? (
|
|
2967
2938
|
// The info panel's top edge aligns with the tree's; the search bar floats `--layout-panel-inset` below it,
|
|
2968
2939
|
// and the header inset (the bar's height plus that inset) extends the header's fill behind the bar,
|
|
2969
2940
|
// Google Maps style; the 8px bottom padding mirrors the inset above the bar, and the hidden title's height is zeroed.
|
|
2970
2941
|
// The panel's own Zoom in button is hidden: the search bar carries it.
|
|
2971
|
-
/* @__PURE__ */
|
|
2942
|
+
/* @__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
2943
|
GenrePlaylistTreeWheel,
|
|
2973
2944
|
{
|
|
2974
2945
|
scope,
|
|
2975
2946
|
genrePlaylists: visibleGenrePlaylists,
|
|
2947
|
+
focusUuids,
|
|
2976
2948
|
handleGenreCreationAction,
|
|
2977
2949
|
handleGenreRenameAction,
|
|
2978
2950
|
additionalActions,
|
|
@@ -2987,7 +2959,7 @@ function GenreTreeView({
|
|
|
2987
2959
|
busy,
|
|
2988
2960
|
floatingControlsLeading: floatingControlsLeading || canSizeByViews ? /* @__PURE__ */ jsxs27("div", { className: "flex items-center gap-2", children: [
|
|
2989
2961
|
floatingControlsLeading,
|
|
2990
|
-
canSizeByViews && /* @__PURE__ */
|
|
2962
|
+
canSizeByViews && /* @__PURE__ */ jsx39(SizeMetricToggle, { value: sizeMetric, onChange: changeSizeMetric })
|
|
2991
2963
|
] }) : void 0,
|
|
2992
2964
|
defaultViewport,
|
|
2993
2965
|
viewportRestore,
|
|
@@ -2996,11 +2968,12 @@ function GenreTreeView({
|
|
|
2996
2968
|
) }) })
|
|
2997
2969
|
) : viewMode === "pop-core" ? (
|
|
2998
2970
|
// Same as the wheel: the header inset extends its fill behind the floating search bar, Google Maps style.
|
|
2999
|
-
/* @__PURE__ */
|
|
2971
|
+
/* @__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
2972
|
GenrePlaylistTreeWheelRadialPopCore,
|
|
3001
2973
|
{
|
|
3002
2974
|
scope,
|
|
3003
2975
|
genrePlaylists: visibleGenrePlaylists,
|
|
2976
|
+
focusUuids,
|
|
3004
2977
|
handleGenreCreationAction,
|
|
3005
2978
|
handleGenreRenameAction,
|
|
3006
2979
|
additionalActions,
|
|
@@ -3015,7 +2988,7 @@ function GenreTreeView({
|
|
|
3015
2988
|
busy,
|
|
3016
2989
|
floatingControlsLeading: floatingControlsLeading || canSizeByViews ? /* @__PURE__ */ jsxs27("div", { className: "flex items-center gap-2", children: [
|
|
3017
2990
|
floatingControlsLeading,
|
|
3018
|
-
canSizeByViews && /* @__PURE__ */
|
|
2991
|
+
canSizeByViews && /* @__PURE__ */ jsx39(SizeMetricToggle, { value: sizeMetric, onChange: changeSizeMetric })
|
|
3019
2992
|
] }) : void 0,
|
|
3020
2993
|
defaultViewport,
|
|
3021
2994
|
viewportRestore,
|
|
@@ -3023,12 +2996,13 @@ function GenreTreeView({
|
|
|
3023
2996
|
...focus
|
|
3024
2997
|
}
|
|
3025
2998
|
) }) })
|
|
3026
|
-
) : viewMode === "outline" ? /* @__PURE__ */
|
|
2999
|
+
) : viewMode === "outline" ? /* @__PURE__ */ jsx39("div", { className: "tree-container flex-1 min-h-0 w-full overflow-y-auto relative", children: /* @__PURE__ */ jsx39(
|
|
3027
3000
|
GenrePlaylistTreeWheelRadialPopCore,
|
|
3028
3001
|
{
|
|
3029
3002
|
outline: true,
|
|
3030
3003
|
scope,
|
|
3031
3004
|
genrePlaylists: visibleGenrePlaylists,
|
|
3005
|
+
focusUuids,
|
|
3032
3006
|
handleGenreCreationAction,
|
|
3033
3007
|
handleGenreRenameAction,
|
|
3034
3008
|
additionalActions,
|
|
@@ -3039,13 +3013,13 @@ function GenreTreeView({
|
|
|
3039
3013
|
selectedNodeId,
|
|
3040
3014
|
readOnly
|
|
3041
3015
|
}
|
|
3042
|
-
) }) : /* @__PURE__ */
|
|
3016
|
+
) }) : /* @__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
3017
|
([uuid, genrePlaylistTreePerRoot]) => {
|
|
3044
|
-
return /* @__PURE__ */
|
|
3018
|
+
return /* @__PURE__ */ jsx39(
|
|
3045
3019
|
"div",
|
|
3046
3020
|
{
|
|
3047
3021
|
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__ */
|
|
3022
|
+
children: /* @__PURE__ */ jsx39("div", { className: "graph-container relative z-10 h-full", children: /* @__PURE__ */ jsx39(
|
|
3049
3023
|
GenrePlaylistTreePerRoot,
|
|
3050
3024
|
{
|
|
3051
3025
|
scope,
|
|
@@ -3058,6 +3032,7 @@ function GenreTreeView({
|
|
|
3058
3032
|
onNodeHover: handleNodeHover,
|
|
3059
3033
|
...hostPanel,
|
|
3060
3034
|
playback,
|
|
3035
|
+
focusUuids,
|
|
3061
3036
|
selectedNodeId: uuid === selectedGenrePlaylist?.root.uuid ? selectedNodeId : null,
|
|
3062
3037
|
readOnly,
|
|
3063
3038
|
wheelZoom: "modifier",
|
|
@@ -3071,13 +3046,13 @@ function GenreTreeView({
|
|
|
3071
3046
|
);
|
|
3072
3047
|
}
|
|
3073
3048
|
) }),
|
|
3074
|
-
/* @__PURE__ */
|
|
3049
|
+
/* @__PURE__ */ jsx39(
|
|
3075
3050
|
DetailPanel2,
|
|
3076
3051
|
{
|
|
3077
3052
|
ref: panelRef,
|
|
3078
3053
|
side: "left",
|
|
3079
3054
|
title: activePanel?.title ?? "",
|
|
3080
|
-
titleInSearch:
|
|
3055
|
+
titleInSearch: !isLoading && !isError,
|
|
3081
3056
|
headerAccent: activePanel?.headerAccent,
|
|
3082
3057
|
headerActions: expandButton,
|
|
3083
3058
|
onClose: activePanel?.onClose ?? noop,
|
|
@@ -3086,7 +3061,6 @@ function GenreTreeView({
|
|
|
3086
3061
|
onExpandedChange: activePanel?.onExpandedChange,
|
|
3087
3062
|
aside: activePanel?.aside,
|
|
3088
3063
|
edgeTab: detailTab,
|
|
3089
|
-
headerClassName: activePanel?.titleInSearch ? void 0 : "pt-search-clear",
|
|
3090
3064
|
children: activePanel?.aside && !activePanel.expanded ? /* @__PURE__ */ jsxs27(Fragment15, { children: [
|
|
3091
3065
|
activePanel.content,
|
|
3092
3066
|
activePanel.aside
|
|
@@ -3113,7 +3087,7 @@ import { ListMusic } from "lucide-react";
|
|
|
3113
3087
|
import { useTrackList as useTrackList7 } from "@behindthemusictree/app-kit/genre-tree";
|
|
3114
3088
|
import { TrackListOriginType as TrackListOriginType3 } from "@behindthemusictree/app-kit/genre-tree";
|
|
3115
3089
|
import { useTrackNoun as useTrackNoun3 } from "@behindthemusictree/app-kit/track-noun";
|
|
3116
|
-
import { jsx as
|
|
3090
|
+
import { jsx as jsx40, jsxs as jsxs28 } from "react/jsx-runtime";
|
|
3117
3091
|
var useBrowserLayoutEffect = typeof window === "undefined" ? useEffect7 : useLayoutEffect2;
|
|
3118
3092
|
function TrackListSidebar({
|
|
3119
3093
|
className: className2 = "",
|
|
@@ -3225,15 +3199,15 @@ function TrackListSidebar({
|
|
|
3225
3199
|
/* @__PURE__ */ jsxs28("div", { className: "header flex h-16 items-center px-4 py-2 text-[var(--color-text)]", children: [
|
|
3226
3200
|
/* @__PURE__ */ jsxs28("div", { className: "min-w-0 flex flex-1 flex-col justify-center", children: [
|
|
3227
3201
|
/* @__PURE__ */ jsxs28("div", { className: "origin flex text-xl", children: [
|
|
3228
|
-
/* @__PURE__ */
|
|
3229
|
-
/* @__PURE__ */
|
|
3202
|
+
/* @__PURE__ */ jsx40("div", { className: "from h-auto flex flex-col justify-center items-center mr-2", children: "From" }),
|
|
3203
|
+
/* @__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
3204
|
] }),
|
|
3231
3205
|
/* @__PURE__ */ jsxs28("div", { className: "info flex items-center text-body text-[var(--color-text-muted)]", children: [
|
|
3232
3206
|
trackList.origin.type === TrackListOriginType3.GENRE_PLAYLIST ? "Genre \u2022 " : trackList.origin.type === TrackListOriginType3.ARTIST ? "Artist \u2022 " : `${trackNoun.singular} playlist \u2022 `,
|
|
3233
3207
|
`${trackList.total} ${trackList.total > 1 ? trackNoun.plural : trackNoun.singular}`
|
|
3234
3208
|
] })
|
|
3235
3209
|
] }),
|
|
3236
|
-
(isCollapsed && onExpand || !isCollapsed && onMinimize) && /* @__PURE__ */
|
|
3210
|
+
(isCollapsed && onExpand || !isCollapsed && onMinimize) && /* @__PURE__ */ jsx40(
|
|
3237
3211
|
"button",
|
|
3238
3212
|
{
|
|
3239
3213
|
type: "button",
|
|
@@ -3242,7 +3216,7 @@ function TrackListSidebar({
|
|
|
3242
3216
|
"aria-expanded": !isCollapsed,
|
|
3243
3217
|
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
3218
|
onClick: isCollapsed ? onExpand : onMinimize,
|
|
3245
|
-
children: /* @__PURE__ */
|
|
3219
|
+
children: /* @__PURE__ */ jsx40(ListMusic, { "aria-hidden": "true", className: "h-5 w-5" })
|
|
3246
3220
|
}
|
|
3247
3221
|
)
|
|
3248
3222
|
] }),
|
|
@@ -3256,7 +3230,7 @@ function TrackListSidebar({
|
|
|
3256
3230
|
onPointerDown: markUserScrollIntent,
|
|
3257
3231
|
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
3232
|
children: [
|
|
3259
|
-
trackList.tracks.map((track, index) => /* @__PURE__ */
|
|
3233
|
+
trackList.tracks.map((track, index) => /* @__PURE__ */ jsx40("li", { "data-track-uuid": track.uuid, children: /* @__PURE__ */ jsx40(
|
|
3260
3234
|
TrackItem,
|
|
3261
3235
|
{
|
|
3262
3236
|
track,
|
|
@@ -3267,7 +3241,7 @@ function TrackListSidebar({
|
|
|
3267
3241
|
renderSongLink
|
|
3268
3242
|
}
|
|
3269
3243
|
) }, track.uuid)),
|
|
3270
|
-
hasMore && /* @__PURE__ */
|
|
3244
|
+
hasMore && /* @__PURE__ */ jsx40("li", { ref: loadMoreSentinelRef, "aria-hidden": "true", className: "h-px" })
|
|
3271
3245
|
]
|
|
3272
3246
|
}
|
|
3273
3247
|
)
|
|
@@ -3292,7 +3266,7 @@ import { PanelEdgeTab } from "@behindthemusictree/ui";
|
|
|
3292
3266
|
import { Pause as Pause4, Play as Play5, SkipBack, SkipForward, Volume2, VolumeX } from "lucide-react";
|
|
3293
3267
|
import { formatTime, useTrackList as useTrackList8 } from "@behindthemusictree/app-kit/genre-tree";
|
|
3294
3268
|
import { PlayStates as PlayStates4, useCurrentTime, usePlayer as usePlayer11 } from "@behindthemusictree/app-kit/player";
|
|
3295
|
-
import { jsx as
|
|
3269
|
+
import { jsx as jsx41, jsxs as jsxs29 } from "react/jsx-runtime";
|
|
3296
3270
|
function PlayerControls() {
|
|
3297
3271
|
const {
|
|
3298
3272
|
duration,
|
|
@@ -3318,8 +3292,8 @@ function PlayerControls() {
|
|
|
3318
3292
|
className: "player-controls flex shrink-0 flex-col gap-2 border-b border-zinc-800 px-3 py-2 text-zinc-200",
|
|
3319
3293
|
children: [
|
|
3320
3294
|
/* @__PURE__ */ jsxs29("div", { className: "flex min-w-0 items-center gap-2 text-xs tabular-nums text-zinc-400", children: [
|
|
3321
|
-
/* @__PURE__ */
|
|
3322
|
-
/* @__PURE__ */
|
|
3295
|
+
/* @__PURE__ */ jsx41("span", { "aria-label": "Elapsed time", children: formatTime(safeCurrentTime) }),
|
|
3296
|
+
/* @__PURE__ */ jsx41(
|
|
3323
3297
|
"input",
|
|
3324
3298
|
{
|
|
3325
3299
|
"aria-label": "Seek",
|
|
@@ -3333,11 +3307,11 @@ function PlayerControls() {
|
|
|
3333
3307
|
onChange: (event) => seekTo(Number(event.currentTarget.value))
|
|
3334
3308
|
}
|
|
3335
3309
|
),
|
|
3336
|
-
/* @__PURE__ */
|
|
3310
|
+
/* @__PURE__ */ jsx41("span", { "aria-label": "Duration", children: formatTime(safeDuration) })
|
|
3337
3311
|
] }),
|
|
3338
3312
|
/* @__PURE__ */ jsxs29("div", { className: "grid min-h-9 grid-cols-[1fr_auto_1fr] items-center gap-3", children: [
|
|
3339
3313
|
/* @__PURE__ */ jsxs29("div", { className: "col-start-2 flex items-center justify-center gap-2", children: [
|
|
3340
|
-
/* @__PURE__ */
|
|
3314
|
+
/* @__PURE__ */ jsx41(
|
|
3341
3315
|
"button",
|
|
3342
3316
|
{
|
|
3343
3317
|
type: "button",
|
|
@@ -3346,10 +3320,10 @@ function PlayerControls() {
|
|
|
3346
3320
|
disabled: !isReady || !hasPreviousTrack,
|
|
3347
3321
|
onClick: playPreviousTrack,
|
|
3348
3322
|
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__ */
|
|
3323
|
+
children: /* @__PURE__ */ jsx41(SkipBack, { "aria-hidden": "true", className: "h-4 w-4" })
|
|
3350
3324
|
}
|
|
3351
3325
|
),
|
|
3352
|
-
/* @__PURE__ */
|
|
3326
|
+
/* @__PURE__ */ jsx41(
|
|
3353
3327
|
"button",
|
|
3354
3328
|
{
|
|
3355
3329
|
type: "button",
|
|
@@ -3358,10 +3332,10 @@ function PlayerControls() {
|
|
|
3358
3332
|
disabled: !isReady,
|
|
3359
3333
|
onClick: handlePlayPauseAction,
|
|
3360
3334
|
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__ */
|
|
3335
|
+
children: isPlaying ? /* @__PURE__ */ jsx41(Pause4, { "aria-hidden": "true", className: "h-4 w-4", fill: "currentColor" }) : /* @__PURE__ */ jsx41(Play5, { "aria-hidden": "true", className: "h-4 w-4", fill: "currentColor" })
|
|
3362
3336
|
}
|
|
3363
3337
|
),
|
|
3364
|
-
/* @__PURE__ */
|
|
3338
|
+
/* @__PURE__ */ jsx41(
|
|
3365
3339
|
"button",
|
|
3366
3340
|
{
|
|
3367
3341
|
type: "button",
|
|
@@ -3370,14 +3344,14 @@ function PlayerControls() {
|
|
|
3370
3344
|
disabled: !isReady || !hasNextTrack,
|
|
3371
3345
|
onClick: playNextTrack,
|
|
3372
3346
|
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__ */
|
|
3347
|
+
children: /* @__PURE__ */ jsx41(SkipForward, { "aria-hidden": "true", className: "h-4 w-4" })
|
|
3374
3348
|
}
|
|
3375
3349
|
)
|
|
3376
3350
|
] }),
|
|
3377
3351
|
/* @__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__ */
|
|
3352
|
+
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" }),
|
|
3353
|
+
/* @__PURE__ */ jsx41("span", { className: "sr-only", children: "Volume" }),
|
|
3354
|
+
/* @__PURE__ */ jsx41(
|
|
3381
3355
|
"input",
|
|
3382
3356
|
{
|
|
3383
3357
|
"aria-label": "Volume",
|
|
@@ -3399,7 +3373,7 @@ function PlayerControls() {
|
|
|
3399
3373
|
}
|
|
3400
3374
|
|
|
3401
3375
|
// src/genre-tree/PlayerPanel.tsx
|
|
3402
|
-
import { jsx as
|
|
3376
|
+
import { jsx as jsx42, jsxs as jsxs30 } from "react/jsx-runtime";
|
|
3403
3377
|
var PANEL_ID = "player-panel";
|
|
3404
3378
|
var DEFAULT_EXTENDED_WIDTH = "calc(100vw - var(--layout-center-left) - var(--layout-gutter))";
|
|
3405
3379
|
function PlayerPanel({
|
|
@@ -3452,7 +3426,7 @@ function PlayerPanel({
|
|
|
3452
3426
|
),
|
|
3453
3427
|
style: isExtended ? { width: extendedWidth } : void 0,
|
|
3454
3428
|
children: [
|
|
3455
|
-
/* @__PURE__ */
|
|
3429
|
+
/* @__PURE__ */ jsx42(
|
|
3456
3430
|
PanelEdgeTab,
|
|
3457
3431
|
{
|
|
3458
3432
|
side: "right",
|
|
@@ -3471,19 +3445,19 @@ function PlayerPanel({
|
|
|
3471
3445
|
),
|
|
3472
3446
|
children: [
|
|
3473
3447
|
/* @__PURE__ */ jsxs30("div", { className: "flex w-[var(--layout-right-w)] shrink-0 flex-col", children: [
|
|
3474
|
-
/* @__PURE__ */
|
|
3448
|
+
/* @__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
3449
|
/* @__PURE__ */ jsxs30("div", { className: "relative w-full shrink-0", children: [
|
|
3476
|
-
/* @__PURE__ */
|
|
3450
|
+
/* @__PURE__ */ jsx42(PlayerVideoSurface, { className: "aspect-video w-full bg-black" }),
|
|
3477
3451
|
playerTrackObject?.loadError && /* @__PURE__ */ jsxs30("span", { className: "absolute bottom-2 left-2 right-2 text-xs text-red-400", children: [
|
|
3478
3452
|
playerTrackObject.loadError,
|
|
3479
|
-
/* @__PURE__ */
|
|
3453
|
+
/* @__PURE__ */ jsx42("button", { type: "button", className: "ml-2 underline", onClick: () => {
|
|
3480
3454
|
void retryPlayback();
|
|
3481
3455
|
}, children: "Retry" })
|
|
3482
3456
|
] })
|
|
3483
3457
|
] }),
|
|
3484
|
-
/* @__PURE__ */
|
|
3458
|
+
/* @__PURE__ */ jsx42(PlayerControls, {})
|
|
3485
3459
|
] }),
|
|
3486
|
-
/* @__PURE__ */
|
|
3460
|
+
/* @__PURE__ */ jsx42(
|
|
3487
3461
|
TrackListSidebar,
|
|
3488
3462
|
{
|
|
3489
3463
|
layout: "inline",
|
|
@@ -3510,11 +3484,11 @@ function PlayerPanel({
|
|
|
3510
3484
|
import { v4 as uuidv4 } from "uuid";
|
|
3511
3485
|
import { AiFillStar, AiOutlineStar } from "react-icons/ai";
|
|
3512
3486
|
import { FORM_RATING_NULL_VALUE } from "@behindthemusictree/app-kit/genre-tree";
|
|
3513
|
-
import { jsx as
|
|
3487
|
+
import { jsx as jsx43, jsxs as jsxs31 } from "react/jsx-runtime";
|
|
3514
3488
|
function Rating({ rating, handleChange }) {
|
|
3515
3489
|
const instanceId = uuidv4();
|
|
3516
|
-
return /* @__PURE__ */
|
|
3517
|
-
/* @__PURE__ */
|
|
3490
|
+
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: [
|
|
3491
|
+
/* @__PURE__ */ jsx43(
|
|
3518
3492
|
"input",
|
|
3519
3493
|
{
|
|
3520
3494
|
id: `star-${instanceId}-${i}`,
|
|
@@ -3526,16 +3500,16 @@ function Rating({ rating, handleChange }) {
|
|
|
3526
3500
|
onChange: handleChange
|
|
3527
3501
|
}
|
|
3528
3502
|
),
|
|
3529
|
-
/* @__PURE__ */
|
|
3530
|
-
/* @__PURE__ */
|
|
3503
|
+
/* @__PURE__ */ jsx43("label", { htmlFor: `star-${instanceId}-${i}`, className: "cursor-pointer", children: i === 0 ? /* @__PURE__ */ jsxs31("div", { className: "flex", children: [
|
|
3504
|
+
/* @__PURE__ */ jsx43(
|
|
3531
3505
|
AiOutlineStar,
|
|
3532
3506
|
{
|
|
3533
3507
|
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
3508
|
}
|
|
3535
3509
|
),
|
|
3536
|
-
/* @__PURE__ */
|
|
3510
|
+
/* @__PURE__ */ jsx43("span", { className: "flex-grow w-8" }),
|
|
3537
3511
|
" "
|
|
3538
|
-
] }) : /* @__PURE__ */
|
|
3512
|
+
] }) : /* @__PURE__ */ jsx43(
|
|
3539
3513
|
AiFillStar,
|
|
3540
3514
|
{
|
|
3541
3515
|
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 +3521,7 @@ function Rating({ rating, handleChange }) {
|
|
|
3547
3521
|
// src/genre-tree/EntityDetailPanel.tsx
|
|
3548
3522
|
import { useState as useState12 } from "react";
|
|
3549
3523
|
import { DetailPanel as DetailPanel3 } from "@behindthemusictree/ui";
|
|
3550
|
-
import { Fragment as Fragment16, jsx as
|
|
3524
|
+
import { Fragment as Fragment16, jsx as jsx44, jsxs as jsxs32 } from "react/jsx-runtime";
|
|
3551
3525
|
function EntityDetailPanel({
|
|
3552
3526
|
scope,
|
|
3553
3527
|
getBackendBaseUrl,
|
|
@@ -3570,8 +3544,8 @@ function EntityDetailPanel({
|
|
|
3570
3544
|
getBackendBaseUrl,
|
|
3571
3545
|
getArtistBackendBaseUrl,
|
|
3572
3546
|
getShareUrl,
|
|
3573
|
-
renderArtistLink: renderArtistLink ?? ((artist) => artist.isSpecialPurpose ? artist.name : /* @__PURE__ */
|
|
3574
|
-
renderSongLink: renderSongLink ?? ((song) => /* @__PURE__ */
|
|
3547
|
+
renderArtistLink: renderArtistLink ?? ((artist) => artist.isSpecialPurpose ? artist.name : /* @__PURE__ */ jsx44("button", { type: "button", onClick: () => onArtistUuidChange(artist.uuid), className: "hover:underline", children: artist.name })),
|
|
3548
|
+
renderSongLink: renderSongLink ?? ((song) => /* @__PURE__ */ jsx44("button", { type: "button", onClick: () => onSongUuidChange(song.uuid), className: "hover:underline", children: song.title })),
|
|
3575
3549
|
song: {
|
|
3576
3550
|
uuid: songUuid,
|
|
3577
3551
|
expanded: songUuid !== null && expandedSongUuid === songUuid,
|
|
@@ -3587,7 +3561,7 @@ function EntityDetailPanel({
|
|
|
3587
3561
|
...navigation
|
|
3588
3562
|
});
|
|
3589
3563
|
if (!panel) return null;
|
|
3590
|
-
return /* @__PURE__ */
|
|
3564
|
+
return /* @__PURE__ */ jsx44(
|
|
3591
3565
|
DetailPanel3,
|
|
3592
3566
|
{
|
|
3593
3567
|
side: "left",
|
|
@@ -3633,4 +3607,4 @@ export {
|
|
|
3633
3607
|
GenreTreeViewSkeleton2 as GenreTreeViewSkeleton,
|
|
3634
3608
|
GenreTreeOutlineSkeleton
|
|
3635
3609
|
};
|
|
3636
|
-
//# sourceMappingURL=chunk-
|
|
3610
|
+
//# sourceMappingURL=chunk-I2TEOHVG.js.map
|