@behindthemusictree/app-kit-ui 40.0.0 → 41.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-I2TEOHVG.js → chunk-GR4PCPCU.js} +295 -279
- package/dist/chunk-GR4PCPCU.js.map +1 -0
- package/dist/genre-tree/index.cjs +345 -331
- package/dist/genre-tree/index.cjs.map +1 -1
- package/dist/genre-tree/index.d.ts +7 -3
- package/dist/genre-tree/index.js +1 -1
- package/dist/index.cjs +345 -331
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +1 -1
- package/package.json +4 -4
- package/dist/chunk-I2TEOHVG.js.map +0 -1
|
@@ -15,6 +15,9 @@ import {
|
|
|
15
15
|
GenreTreeViewSkeleton,
|
|
16
16
|
useGenreNodeRelations
|
|
17
17
|
} from "@behindthemusictree/genre-tree-view";
|
|
18
|
+
import {
|
|
19
|
+
toGenreUuid
|
|
20
|
+
} from "@behindthemusictree/app-kit/genre-tree";
|
|
18
21
|
import { useGenreTreeViewState, useArtist as useArtist2, useUpdateGenre as useUpdateGenre2, genreUpdateMutationKey } from "@behindthemusictree/app-kit/genre-tree";
|
|
19
22
|
import { usePopup as usePopup4 } from "@behindthemusictree/app-kit/popup";
|
|
20
23
|
|
|
@@ -46,6 +49,21 @@ function toTreeNodes(genrePlaylists, sizeMetric, focusUuids) {
|
|
|
46
49
|
}));
|
|
47
50
|
}
|
|
48
51
|
|
|
52
|
+
// src/genre-tree/playlist-tree/toGenreNodeStyles.ts
|
|
53
|
+
function toGenreNodeStyles(relations, genrePlaylists) {
|
|
54
|
+
const styles = /* @__PURE__ */ new Map();
|
|
55
|
+
if (!relations) return styles;
|
|
56
|
+
const genreUuidByPlaylistUuid = new Map(
|
|
57
|
+
genrePlaylists.flatMap((genrePlaylist) => genrePlaylist.criteria ? [[genrePlaylist.uuid, genrePlaylist.criteria.uuid]] : [])
|
|
58
|
+
);
|
|
59
|
+
const drawn = [relations, relations.parentNode, ...relations.childNodes, ...relations.ancestorNodes];
|
|
60
|
+
for (const entry of drawn) {
|
|
61
|
+
const genreUuid = entry && genreUuidByPlaylistUuid.get(entry.node.id);
|
|
62
|
+
if (entry && genreUuid) styles.set(genreUuid, { fill: entry.fill, textColor: entry.textColor });
|
|
63
|
+
}
|
|
64
|
+
return styles;
|
|
65
|
+
}
|
|
66
|
+
|
|
49
67
|
// src/genre-tree/playlist-tree/TreePerRoot.tsx
|
|
50
68
|
import { genrePlaylistTrackCount as genrePlaylistTrackCount2 } from "@behindthemusictree/app-kit/genre-tree";
|
|
51
69
|
import { useCallback as useCallback2, useMemo as useMemo2 } from "react";
|
|
@@ -1145,6 +1163,29 @@ function ClampedText({ children, className: className2 = "" }) {
|
|
|
1145
1163
|
] });
|
|
1146
1164
|
}
|
|
1147
1165
|
|
|
1166
|
+
// src/genre-tree/CommonsPhoto.tsx
|
|
1167
|
+
import { jsx as jsx20, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
1168
|
+
function ExternalLink({ href, children }) {
|
|
1169
|
+
return /* @__PURE__ */ jsx20("a", { href, target: "_blank", rel: "noopener noreferrer", className: "underline-offset-2 hover:underline", children });
|
|
1170
|
+
}
|
|
1171
|
+
function CommonsPhoto({
|
|
1172
|
+
image,
|
|
1173
|
+
alt,
|
|
1174
|
+
creditLabel = "Photo"
|
|
1175
|
+
}) {
|
|
1176
|
+
return /* @__PURE__ */ jsxs12("figure", { className: "flex flex-col gap-1.5", children: [
|
|
1177
|
+
/* @__PURE__ */ jsx20("img", { src: image.url, alt, className: "h-64 w-full object-contain bg-[var(--color-surface-muted)] rounded" }),
|
|
1178
|
+
/* @__PURE__ */ jsxs12("figcaption", { className: "text-caption text-[var(--color-text-muted)]", children: [
|
|
1179
|
+
creditLabel,
|
|
1180
|
+
": ",
|
|
1181
|
+
/* @__PURE__ */ jsx20(ExternalLink, { href: image.pageUrl, children: image.author ?? "Wikimedia Commons" }),
|
|
1182
|
+
",",
|
|
1183
|
+
" ",
|
|
1184
|
+
image.licenseUrl ? /* @__PURE__ */ jsx20(ExternalLink, { href: image.licenseUrl, children: image.license }) : image.license
|
|
1185
|
+
] })
|
|
1186
|
+
] });
|
|
1187
|
+
}
|
|
1188
|
+
|
|
1148
1189
|
// src/genre-tree/GenrePlaylistTracks.tsx
|
|
1149
1190
|
import { useEffect as useEffect4, useState as useState7 } from "react";
|
|
1150
1191
|
import { useInfiniteQuery } from "@tanstack/react-query";
|
|
@@ -1167,15 +1208,15 @@ import { TracksFailureAlreadyReportedError as TracksFailureAlreadyReportedError2
|
|
|
1167
1208
|
|
|
1168
1209
|
// src/genre-tree/MusicBrainzRecordingLink.tsx
|
|
1169
1210
|
import { musicBrainzRecordingUrl } from "@behindthemusictree/app-kit/genre-tree";
|
|
1170
|
-
import { Fragment as Fragment8, jsx as
|
|
1211
|
+
import { Fragment as Fragment8, jsx as jsx21 } from "react/jsx-runtime";
|
|
1171
1212
|
function MusicBrainzRecordingLink({
|
|
1172
1213
|
song,
|
|
1173
1214
|
children,
|
|
1174
1215
|
className: className2 = ""
|
|
1175
1216
|
}) {
|
|
1176
1217
|
const url = musicBrainzRecordingUrl(song);
|
|
1177
|
-
if (!url) return /* @__PURE__ */
|
|
1178
|
-
return /* @__PURE__ */
|
|
1218
|
+
if (!url) return /* @__PURE__ */ jsx21(Fragment8, { children });
|
|
1219
|
+
return /* @__PURE__ */ jsx21(
|
|
1179
1220
|
"a",
|
|
1180
1221
|
{
|
|
1181
1222
|
href: url,
|
|
@@ -1192,7 +1233,7 @@ function MusicBrainzRecordingLink({
|
|
|
1192
1233
|
// src/genre-tree/GenrePlaylistTracks.tsx
|
|
1193
1234
|
import { ArtistNames } from "@behindthemusictree/app-kit/genre-tree";
|
|
1194
1235
|
import { capitalize, useTrackNoun } from "@behindthemusictree/app-kit/track-noun";
|
|
1195
|
-
import { jsx as
|
|
1236
|
+
import { jsx as jsx22, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
1196
1237
|
var CATALOGUE_PAGE_SIZE = 100;
|
|
1197
1238
|
var SongPageSchema = PaginatedResponseSchema(SongDetailedSchema).extend({
|
|
1198
1239
|
overallTotal: z.number().nullable(),
|
|
@@ -1279,35 +1320,35 @@ function GenrePlaylistTracks({
|
|
|
1279
1320
|
started.catch((error) => {
|
|
1280
1321
|
console.error("Failed to play genre playlist:", error);
|
|
1281
1322
|
if (error instanceof TracksFailureAlreadyReportedError2) return;
|
|
1282
|
-
showPopup(/* @__PURE__ */
|
|
1323
|
+
showPopup(/* @__PURE__ */ jsx22(InternalErrorPopup, { errorCode: error instanceof AppError2 ? error.code : ErrorCode2.CLIENT_UNKNOWN }));
|
|
1283
1324
|
});
|
|
1284
1325
|
};
|
|
1285
|
-
return /* @__PURE__ */
|
|
1326
|
+
return /* @__PURE__ */ jsx22(PanelSection, { title: `${capitalize(trackNoun.plural)}${total !== void 0 ? ` (${total})` : ""}`, children: /* @__PURE__ */ jsxs13("div", { children: [
|
|
1286
1327
|
renderTracksToolbar?.(),
|
|
1287
|
-
scope === "me" && !genrePlaylist ? /* @__PURE__ */
|
|
1328
|
+
scope === "me" && !genrePlaylist ? /* @__PURE__ */ jsx22("p", { children: "\u2014" }) : isPending ? /* @__PURE__ */ jsx22(Skeleton, { className: "h-4 w-3/4", "aria-busy": "true" }) : isError && tracks.length === 0 ? /* @__PURE__ */ jsxs13("p", { role: "alert", children: [
|
|
1288
1329
|
"Couldn't load ",
|
|
1289
1330
|
trackNoun.plural,
|
|
1290
1331
|
".",
|
|
1291
1332
|
" ",
|
|
1292
|
-
/* @__PURE__ */
|
|
1293
|
-
] }) : tracks.length === 0 ? /* @__PURE__ */
|
|
1333
|
+
/* @__PURE__ */ jsx22("button", { type: "button", className: "underline", onClick: () => void refetch(), children: "Retry" })
|
|
1334
|
+
] }) : tracks.length === 0 ? /* @__PURE__ */ jsx22("p", { children: "\u2014" }) : /* @__PURE__ */ jsxs13("ul", { className: "mt-1 max-h-64 overflow-y-auto text-body [container-type:inline-size]", "aria-label": `${genreName} ${trackNoun.plural}`, children: [
|
|
1294
1335
|
tracks.map((track, index) => {
|
|
1295
1336
|
const label = track.artists?.length ? `${track.title} \u2014 ${track.artists.map((artist2) => artist2.name).join(", ")}` : track.title;
|
|
1296
1337
|
const isCurrent = playerTrackObject?.track.id === track.uuid;
|
|
1297
1338
|
const isPlaying = isCurrent && playState === PlayStates.PLAYING;
|
|
1298
|
-
const text = /* @__PURE__ */
|
|
1299
|
-
/* @__PURE__ */
|
|
1300
|
-
track.artists?.length ? /* @__PURE__ */
|
|
1301
|
-
/* @__PURE__ */
|
|
1302
|
-
track.album && /* @__PURE__ */
|
|
1339
|
+
const text = /* @__PURE__ */ jsxs13("span", { className: TEXT_CELL, children: [
|
|
1340
|
+
/* @__PURE__ */ jsx22("span", { className: TITLE_CELL, children: renderSongLink ? renderSongLink(track) : isSong(track) ? /* @__PURE__ */ jsx22(MusicBrainzRecordingLink, { song: track, className: "hover:underline focus-visible:underline", children: track.title }) : track.title }),
|
|
1341
|
+
track.artists?.length ? /* @__PURE__ */ jsx22("span", { className: SEPARATOR, children: " \u2014 " }) : null,
|
|
1342
|
+
/* @__PURE__ */ jsx22("span", { className: COLUMN_CELL, children: track.artists?.length ? /* @__PURE__ */ jsx22(ArtistNames, { artists: track.artists, renderArtistLink }) : null }),
|
|
1343
|
+
track.album && /* @__PURE__ */ jsx22("span", { className: ALBUM_CELL, children: track.album.name })
|
|
1303
1344
|
] });
|
|
1304
1345
|
const leading = renderSongLeading?.(track, index);
|
|
1305
1346
|
const actions = renderSongActions?.(track);
|
|
1306
1347
|
const isUnplayable = isSong(track) && songUnplayableReason(track) !== null;
|
|
1307
1348
|
if (isUnplayable) {
|
|
1308
|
-
return /* @__PURE__ */
|
|
1349
|
+
return /* @__PURE__ */ jsxs13("li", { className: "flex min-h-8 items-center gap-1 px-1 opacity-50", children: [
|
|
1309
1350
|
leading,
|
|
1310
|
-
/* @__PURE__ */
|
|
1351
|
+
/* @__PURE__ */ jsx22(
|
|
1311
1352
|
"button",
|
|
1312
1353
|
{
|
|
1313
1354
|
type: "button",
|
|
@@ -1315,27 +1356,27 @@ function GenrePlaylistTracks({
|
|
|
1315
1356
|
"aria-disabled": "true",
|
|
1316
1357
|
"aria-label": label,
|
|
1317
1358
|
className: "flex h-6 w-6 shrink-0 items-center justify-center rounded-full opacity-0 cursor-not-allowed",
|
|
1318
|
-
children: /* @__PURE__ */
|
|
1359
|
+
children: /* @__PURE__ */ jsx22(FaPlay, { size: 10 })
|
|
1319
1360
|
}
|
|
1320
1361
|
),
|
|
1321
1362
|
text,
|
|
1322
1363
|
actions
|
|
1323
1364
|
] }, track.uuid);
|
|
1324
1365
|
}
|
|
1325
|
-
return /* @__PURE__ */
|
|
1366
|
+
return /* @__PURE__ */ jsxs13(
|
|
1326
1367
|
"li",
|
|
1327
1368
|
{
|
|
1328
1369
|
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)]" : ""}`,
|
|
1329
1370
|
children: [
|
|
1330
1371
|
leading,
|
|
1331
|
-
/* @__PURE__ */
|
|
1372
|
+
/* @__PURE__ */ jsx22(
|
|
1332
1373
|
"button",
|
|
1333
1374
|
{
|
|
1334
1375
|
type: "button",
|
|
1335
1376
|
"aria-label": `${isPlaying ? "Pause" : "Play"} ${label}`,
|
|
1336
1377
|
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"}`,
|
|
1337
1378
|
onClick: () => isCurrent ? handlePlayPauseAction() : play(track.uuid),
|
|
1338
|
-
children: isCurrent && playState === PlayStates.LOADING ? /* @__PURE__ */
|
|
1379
|
+
children: isCurrent && playState === PlayStates.LOADING ? /* @__PURE__ */ jsx22(RingLoader, { size: 10 }) : isPlaying ? /* @__PURE__ */ jsx22(FaPause, { size: 10 }) : /* @__PURE__ */ jsx22(FaPlay, { size: 10 })
|
|
1339
1380
|
}
|
|
1340
1381
|
),
|
|
1341
1382
|
text,
|
|
@@ -1345,7 +1386,7 @@ function GenrePlaylistTracks({
|
|
|
1345
1386
|
track.uuid
|
|
1346
1387
|
);
|
|
1347
1388
|
}),
|
|
1348
|
-
hasNextPage && /* @__PURE__ */
|
|
1389
|
+
hasNextPage && /* @__PURE__ */ jsx22("li", { ref: setSentinel, "aria-hidden": "true", className: "h-4" })
|
|
1349
1390
|
] })
|
|
1350
1391
|
] }) });
|
|
1351
1392
|
}
|
|
@@ -1353,7 +1394,7 @@ function GenrePlaylistTracks({
|
|
|
1353
1394
|
// src/genre-tree/GenreDetailExtras.tsx
|
|
1354
1395
|
import { useTrackNoun as useTrackNoun2 } from "@behindthemusictree/app-kit/track-noun";
|
|
1355
1396
|
import { SiWikidata, SiWikipedia } from "react-icons/si";
|
|
1356
|
-
import { Fragment as Fragment9, jsx as
|
|
1397
|
+
import { Fragment as Fragment9, jsx as jsx23, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
1357
1398
|
function GenreDetailExtras({
|
|
1358
1399
|
genreUuid,
|
|
1359
1400
|
genrePlaylist,
|
|
@@ -1379,17 +1420,18 @@ function GenreDetailExtras({
|
|
|
1379
1420
|
criteriaOverviewSchema
|
|
1380
1421
|
);
|
|
1381
1422
|
if (isPending) {
|
|
1382
|
-
return /* @__PURE__ */
|
|
1383
|
-
/* @__PURE__ */
|
|
1423
|
+
return /* @__PURE__ */ jsxs14(Fragment9, { children: [
|
|
1424
|
+
/* @__PURE__ */ jsx23(PanelSection2, { title: "Summary", children: /* @__PURE__ */ jsx23("div", { "aria-busy": "true", "data-testid": "genre-detail-extras-skeleton", children: /* @__PURE__ */ jsx23(Skeleton2, { className: "h-4 w-3/4" }) }) }),
|
|
1384
1425
|
family
|
|
1385
1426
|
] });
|
|
1386
1427
|
}
|
|
1387
|
-
if (!overview) return /* @__PURE__ */
|
|
1388
|
-
const { summary, summarySourceUrl, essentialSongs } = overview;
|
|
1428
|
+
if (!overview) return /* @__PURE__ */ jsx23(Fragment9, { children: family });
|
|
1429
|
+
const { summary, summarySourceUrl, essentialSongs, image } = overview;
|
|
1389
1430
|
const wikidataUrl = wikidataId ? `https://www.wikidata.org/wiki/${encodeURIComponent(wikidataId)}` : null;
|
|
1390
|
-
return /* @__PURE__ */
|
|
1391
|
-
|
|
1392
|
-
|
|
1431
|
+
return /* @__PURE__ */ jsxs14(Fragment9, { children: [
|
|
1432
|
+
image && /* @__PURE__ */ jsx23(CommonsPhoto, { image, alt: overview.name, creditLabel: "Image" }),
|
|
1433
|
+
(summarySourceUrl || wikidataUrl) && /* @__PURE__ */ jsx23(PanelSection2, { title: "Links", children: /* @__PURE__ */ jsxs14("div", { className: "flex flex-wrap gap-x-3 gap-y-1 text-caption text-[var(--color-text)]", children: [
|
|
1434
|
+
summarySourceUrl && /* @__PURE__ */ jsxs14(
|
|
1393
1435
|
"a",
|
|
1394
1436
|
{
|
|
1395
1437
|
href: summarySourceUrl,
|
|
@@ -1397,12 +1439,12 @@ function GenreDetailExtras({
|
|
|
1397
1439
|
rel: "noopener noreferrer",
|
|
1398
1440
|
className: "inline-flex items-center gap-1.5 text-[var(--color-text-muted)] hover:text-[var(--color-text)]",
|
|
1399
1441
|
children: [
|
|
1400
|
-
/* @__PURE__ */
|
|
1442
|
+
/* @__PURE__ */ jsx23(SiWikipedia, { "aria-hidden": "true", className: "h-3.5 w-3.5" }),
|
|
1401
1443
|
"Wikipedia"
|
|
1402
1444
|
]
|
|
1403
1445
|
}
|
|
1404
1446
|
),
|
|
1405
|
-
wikidataUrl && /* @__PURE__ */
|
|
1447
|
+
wikidataUrl && /* @__PURE__ */ jsxs14(
|
|
1406
1448
|
"a",
|
|
1407
1449
|
{
|
|
1408
1450
|
href: wikidataUrl,
|
|
@@ -1410,17 +1452,17 @@ function GenreDetailExtras({
|
|
|
1410
1452
|
rel: "noopener noreferrer",
|
|
1411
1453
|
className: "inline-flex items-center gap-1.5 text-[var(--color-text-muted)] hover:text-[var(--color-text)]",
|
|
1412
1454
|
children: [
|
|
1413
|
-
/* @__PURE__ */
|
|
1455
|
+
/* @__PURE__ */ jsx23(SiWikidata, { "aria-hidden": "true", className: "h-3.5 w-3.5" }),
|
|
1414
1456
|
"Wikidata"
|
|
1415
1457
|
]
|
|
1416
1458
|
}
|
|
1417
1459
|
)
|
|
1418
1460
|
] }) }),
|
|
1419
|
-
/* @__PURE__ */
|
|
1461
|
+
/* @__PURE__ */ jsx23(PanelSection2, { title: "Summary", children: renderSummary ? renderSummary(overview) : /* @__PURE__ */ jsx23(ClampedText, { className: "text-body text-[var(--color-text)]", children: summary ?? "\u2014" }, genreUuid) }),
|
|
1420
1462
|
family,
|
|
1421
1463
|
renderGenreDetailExtras?.(overview),
|
|
1422
|
-
(renderEssentialTracks || essentialSongs) && /* @__PURE__ */
|
|
1423
|
-
/* @__PURE__ */
|
|
1464
|
+
(renderEssentialTracks || essentialSongs) && /* @__PURE__ */ jsx23(PanelSection2, { title: `Essential ${trackNoun.plural}`, children: renderEssentialTracks ? renderEssentialTracks(overview) : essentialSongs && essentialSongs.length > 0 ? /* @__PURE__ */ jsx23("ul", { className: "text-body text-[var(--color-text)]", children: essentialSongs.map((track) => /* @__PURE__ */ jsx23("li", { className: "py-1", children: track.title }, track.uuid)) }) : /* @__PURE__ */ jsx23("p", { className: "text-body text-[var(--color-text)]", children: "\u2014" }) }),
|
|
1465
|
+
/* @__PURE__ */ jsx23(
|
|
1424
1466
|
GenrePlaylistTracks,
|
|
1425
1467
|
{
|
|
1426
1468
|
genreUuid,
|
|
@@ -1438,10 +1480,10 @@ function GenreDetailExtras({
|
|
|
1438
1480
|
}
|
|
1439
1481
|
|
|
1440
1482
|
// src/genre-tree/GenreInfoPanelBody.tsx
|
|
1441
|
-
import { Fragment as Fragment10, jsx as
|
|
1483
|
+
import { Fragment as Fragment10, jsx as jsx24, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
1442
1484
|
import { createElement } from "react";
|
|
1443
1485
|
function GenreNodeActionBand({ genrePlaylist, playback, ...bandProps }) {
|
|
1444
|
-
return /* @__PURE__ */
|
|
1486
|
+
return /* @__PURE__ */ jsx24(GenreActionBand, { ...bandProps, playActions: /* @__PURE__ */ jsx24(GenrePlayActions, { genrePlaylist, playback }) });
|
|
1445
1487
|
}
|
|
1446
1488
|
function GenreInfoPanelBody({
|
|
1447
1489
|
toolbar,
|
|
@@ -1458,9 +1500,9 @@ function GenreInfoPanelBody({
|
|
|
1458
1500
|
}) {
|
|
1459
1501
|
const summary = scope === "reference" ? GenreCatalogueCountsSchema2.parse(genrePlaylist ?? catalogue) : void 0;
|
|
1460
1502
|
const selection = summary ? defaultGenreMusicSelection2(summary) : void 0;
|
|
1461
|
-
return /* @__PURE__ */
|
|
1503
|
+
return /* @__PURE__ */ jsxs15(Fragment10, { children: [
|
|
1462
1504
|
toolbar,
|
|
1463
|
-
genrePlaylist ? /* @__PURE__ */
|
|
1505
|
+
genrePlaylist ? /* @__PURE__ */ jsx24(GenreNodeActionBand, { ...band, genrePlaylist, playback }) : /* @__PURE__ */ jsx24(GenreActionBand, { ...band }),
|
|
1464
1506
|
/* @__PURE__ */ createElement(
|
|
1465
1507
|
GenreDetailExtras,
|
|
1466
1508
|
{
|
|
@@ -1480,7 +1522,7 @@ function GenreInfoPanelBody({
|
|
|
1480
1522
|
}
|
|
1481
1523
|
|
|
1482
1524
|
// src/genre-tree/GenreDetailPanel.tsx
|
|
1483
|
-
import { Fragment as Fragment11, jsx as
|
|
1525
|
+
import { Fragment as Fragment11, jsx as jsx25, jsxs as jsxs16 } from "react/jsx-runtime";
|
|
1484
1526
|
var RELATIVE_ITEM_COUNT = 1;
|
|
1485
1527
|
function toNode(genre, parentId) {
|
|
1486
1528
|
return {
|
|
@@ -1503,27 +1545,21 @@ function useGenreDetailContent({
|
|
|
1503
1545
|
trailing,
|
|
1504
1546
|
genrePlaylist: hostPlaylist,
|
|
1505
1547
|
expanded,
|
|
1506
|
-
|
|
1548
|
+
treeStyles
|
|
1507
1549
|
}) {
|
|
1508
|
-
const
|
|
1550
|
+
const result = useFetchGenreDetail(genreUuid, scope, getBackendBaseUrl);
|
|
1551
|
+
const detail = result.status === "success" ? result.genre : void 0;
|
|
1509
1552
|
const defaultPlayback = useGenrePlaylistPlayback({ scope, genrePlaylists: [], artist: extras?.artist });
|
|
1510
1553
|
const playback = hostPlayback ?? defaultPlayback;
|
|
1511
1554
|
const view = useMemo6(() => {
|
|
1512
1555
|
if (!detail) return null;
|
|
1513
1556
|
const rootColor = getGenreTreeColor2(detail.root.wikidataId);
|
|
1514
|
-
const treeStyles = /* @__PURE__ */ new Map();
|
|
1515
|
-
if (treeRelations) {
|
|
1516
|
-
const drawn = [treeRelations, treeRelations.parentNode, ...treeRelations.childNodes, ...treeRelations.ancestorNodes];
|
|
1517
|
-
for (const entry of drawn) {
|
|
1518
|
-
if (entry) treeStyles.set(entry.node.id, { fill: entry.fill, textColor: entry.textColor });
|
|
1519
|
-
}
|
|
1520
|
-
}
|
|
1521
1557
|
const relative = (genre, parentId) => ({
|
|
1522
1558
|
node: toNode(genre, parentId),
|
|
1523
|
-
...treeStyles
|
|
1559
|
+
...treeStyles?.get(genre.uuid) ?? { fill: tintSurface(rootColor), textColor: TEXT_COLOR }
|
|
1524
1560
|
});
|
|
1525
1561
|
const ancestors2 = [...detail.ascendants].sort((a, b) => b.degree - a.degree);
|
|
1526
|
-
const own = treeStyles
|
|
1562
|
+
const own = treeStyles?.get(detail.uuid) ?? { fill: rootColor, textColor: getTextColorOnFill(rootColor) };
|
|
1527
1563
|
return {
|
|
1528
1564
|
node: {
|
|
1529
1565
|
id: detail.uuid,
|
|
@@ -1540,23 +1576,28 @@ function useGenreDetailContent({
|
|
|
1540
1576
|
({ ascendant }, index) => relative(ascendant, index === 0 ? null : ancestors2[index - 1].ascendant.uuid)
|
|
1541
1577
|
)
|
|
1542
1578
|
};
|
|
1543
|
-
}, [detail, scope,
|
|
1544
|
-
if (
|
|
1579
|
+
}, [detail, scope, treeStyles]);
|
|
1580
|
+
if (result.status === "not-found") return {
|
|
1581
|
+
name: null,
|
|
1582
|
+
title: "Genre not found",
|
|
1583
|
+
content: /* @__PURE__ */ jsx25("p", { className: "text-[var(--color-text-muted)]", children: "This genre does not exist." })
|
|
1584
|
+
};
|
|
1585
|
+
if (result.status === "error") return {
|
|
1545
1586
|
name: null,
|
|
1546
1587
|
title: "Genre unavailable",
|
|
1547
|
-
content: /* @__PURE__ */
|
|
1588
|
+
content: /* @__PURE__ */ jsx25("p", { role: "alert", className: "text-body text-[var(--color-text)]", children: "This genre could not be loaded." })
|
|
1548
1589
|
};
|
|
1549
|
-
if (
|
|
1590
|
+
if (!detail || !view) return {
|
|
1550
1591
|
name: null,
|
|
1551
1592
|
title: "Loading genre\u2026",
|
|
1552
|
-
content: /* @__PURE__ */
|
|
1553
|
-
/* @__PURE__ */
|
|
1554
|
-
/* @__PURE__ */
|
|
1555
|
-
/* @__PURE__ */
|
|
1593
|
+
content: /* @__PURE__ */ jsxs16("div", { className: "flex flex-col gap-3", "aria-busy": "true", "data-testid": "genre-detail-panel-skeleton", children: [
|
|
1594
|
+
/* @__PURE__ */ jsx25(Skeleton3, { className: "h-6 w-2/3" }),
|
|
1595
|
+
/* @__PURE__ */ jsx25(Skeleton3, { className: "h-4 w-full" }),
|
|
1596
|
+
/* @__PURE__ */ jsx25(Skeleton3, { className: "h-4 w-3/4" })
|
|
1556
1597
|
] })
|
|
1557
1598
|
};
|
|
1558
1599
|
const selectGenre = (nodeId) => onSelectGenre(GenreUuidSchema.parse(nodeId));
|
|
1559
|
-
const family = /* @__PURE__ */
|
|
1600
|
+
const family = /* @__PURE__ */ jsx25(
|
|
1560
1601
|
GenreNodeFamily,
|
|
1561
1602
|
{
|
|
1562
1603
|
node: view.node,
|
|
@@ -1567,17 +1608,17 @@ function useGenreDetailContent({
|
|
|
1567
1608
|
onSelectNode: selectGenre
|
|
1568
1609
|
}
|
|
1569
1610
|
);
|
|
1570
|
-
const ancestors = /* @__PURE__ */
|
|
1611
|
+
const ancestors = /* @__PURE__ */ jsx25(GenreNodeAncestors, { ancestorNodes: view.ancestorNodes, onSelectNode: selectGenre });
|
|
1571
1612
|
return {
|
|
1572
1613
|
name: detail.name,
|
|
1573
1614
|
title: detail.name,
|
|
1574
1615
|
headerAccent: { background: view.fill, color: view.textColor },
|
|
1575
1616
|
aside: expanded ? ancestors : void 0,
|
|
1576
|
-
content: /* @__PURE__ */
|
|
1577
|
-
/* @__PURE__ */
|
|
1617
|
+
content: /* @__PURE__ */ jsxs16(Fragment11, { children: [
|
|
1618
|
+
/* @__PURE__ */ jsx25(
|
|
1578
1619
|
GenreInfoPanelBody,
|
|
1579
1620
|
{
|
|
1580
|
-
family: /* @__PURE__ */
|
|
1621
|
+
family: /* @__PURE__ */ jsxs16(Fragment11, { children: [
|
|
1581
1622
|
family,
|
|
1582
1623
|
!expanded && ancestors
|
|
1583
1624
|
] }),
|
|
@@ -1621,7 +1662,7 @@ function GenreDetailPanel({
|
|
|
1621
1662
|
expanded,
|
|
1622
1663
|
band: { onZoomIn, shareUrl, shareTarget: shareUrl ? shareTarget : void 0 }
|
|
1623
1664
|
});
|
|
1624
|
-
return /* @__PURE__ */
|
|
1665
|
+
return /* @__PURE__ */ jsx25(
|
|
1625
1666
|
DetailPanel,
|
|
1626
1667
|
{
|
|
1627
1668
|
side: "left",
|
|
@@ -1634,7 +1675,7 @@ function GenreDetailPanel({
|
|
|
1634
1675
|
edgeTab,
|
|
1635
1676
|
aside: panel.aside,
|
|
1636
1677
|
titleInSearch,
|
|
1637
|
-
headerActions: onExpandedChange ? /* @__PURE__ */
|
|
1678
|
+
headerActions: onExpandedChange ? /* @__PURE__ */ jsx25(IconButton, { "aria-label": expanded ? "Shrink panel" : "Extend panel", onClick: () => onExpandedChange(!expanded), children: expanded ? /* @__PURE__ */ jsx25(Minimize2, { "aria-hidden": "true", className: "h-4 w-4" }) : /* @__PURE__ */ jsx25(Maximize2, { "aria-hidden": "true", className: "h-4 w-4" }) }) : void 0,
|
|
1638
1679
|
children: panel.content
|
|
1639
1680
|
}
|
|
1640
1681
|
);
|
|
@@ -1646,7 +1687,7 @@ import {
|
|
|
1646
1687
|
getReparentCandidates,
|
|
1647
1688
|
useUpdateGenre
|
|
1648
1689
|
} from "@behindthemusictree/app-kit/genre-tree";
|
|
1649
|
-
import { jsx as
|
|
1690
|
+
import { jsx as jsx26, jsxs as jsxs17 } from "react/jsx-runtime";
|
|
1650
1691
|
function ChangeParentPopup({
|
|
1651
1692
|
genrePlaylist,
|
|
1652
1693
|
genrePlaylists,
|
|
@@ -1681,12 +1722,12 @@ function ChangeParentPopup({
|
|
|
1681
1722
|
window.addEventListener("keydown", handleKeyDown);
|
|
1682
1723
|
return () => window.removeEventListener("keydown", handleKeyDown);
|
|
1683
1724
|
}, [onClose]);
|
|
1684
|
-
return /* @__PURE__ */
|
|
1685
|
-
/* @__PURE__ */
|
|
1725
|
+
return /* @__PURE__ */ jsxs17(BasePopup_default, { title: `Change parent of ${genrePlaylist.name}`, onClose, showCancelButton: true, fitContent: true, children: [
|
|
1726
|
+
/* @__PURE__ */ jsxs17("p", { className: "mb-3 text-body text-[var(--color-text-muted)]", children: [
|
|
1686
1727
|
"Current parent: ",
|
|
1687
1728
|
genrePlaylist.parent?.name ?? "none"
|
|
1688
1729
|
] }),
|
|
1689
|
-
/* @__PURE__ */
|
|
1730
|
+
/* @__PURE__ */ jsx26("div", { "aria-busy": isPending, className: isPending ? "pointer-events-none opacity-60" : void 0, children: /* @__PURE__ */ jsx26(
|
|
1690
1731
|
GenreSearch,
|
|
1691
1732
|
{
|
|
1692
1733
|
genrePlaylists: candidates,
|
|
@@ -1694,7 +1735,7 @@ function ChangeParentPopup({
|
|
|
1694
1735
|
placeholder: "Search a new parent\u2026"
|
|
1695
1736
|
}
|
|
1696
1737
|
) }),
|
|
1697
|
-
formErrors.length > 0 && /* @__PURE__ */
|
|
1738
|
+
formErrors.length > 0 && /* @__PURE__ */ jsx26("p", { role: "alert", className: "mt-3 text-body text-[var(--color-red-500)]", children: formErrors.map(({ message }) => message).join(" ") })
|
|
1698
1739
|
] });
|
|
1699
1740
|
}
|
|
1700
1741
|
|
|
@@ -1707,7 +1748,7 @@ import { Pause as Pause2, Play as Play2 } from "lucide-react";
|
|
|
1707
1748
|
import { ActionBand as ActionBand2, ActionButton as ActionButton4, PanelBleed as PanelBleed2 } from "@behindthemusictree/ui";
|
|
1708
1749
|
import { TrackListOriginType as TrackListOriginType2, useTrackList as useTrackList3 } from "@behindthemusictree/app-kit/genre-tree";
|
|
1709
1750
|
import { usePlayer as usePlayer6 } from "@behindthemusictree/app-kit/player";
|
|
1710
|
-
import { jsx as
|
|
1751
|
+
import { jsx as jsx27, jsxs as jsxs18 } from "react/jsx-runtime";
|
|
1711
1752
|
function ArtistActionBand({ artist, share }) {
|
|
1712
1753
|
const { trackList, playNewTrackListFromArtist } = useTrackList3();
|
|
1713
1754
|
const { isPlaying, setIsPlaying } = usePlayer6();
|
|
@@ -1723,11 +1764,11 @@ function ArtistActionBand({ artist, share }) {
|
|
|
1723
1764
|
console.error("Failed to load artist tracks:", error);
|
|
1724
1765
|
});
|
|
1725
1766
|
};
|
|
1726
|
-
return /* @__PURE__ */
|
|
1727
|
-
/* @__PURE__ */
|
|
1767
|
+
return /* @__PURE__ */ jsx27(PanelBleed2, { children: /* @__PURE__ */ jsxs18(ActionBand2, { children: [
|
|
1768
|
+
/* @__PURE__ */ jsx27(
|
|
1728
1769
|
ActionButton4,
|
|
1729
1770
|
{
|
|
1730
|
-
icon: playing ? /* @__PURE__ */
|
|
1771
|
+
icon: playing ? /* @__PURE__ */ jsx27(Pause2, { "aria-hidden": "true", className: "w-5 h-5" }) : /* @__PURE__ */ jsx27(Play2, { "aria-hidden": "true", className: "w-5 h-5" }),
|
|
1731
1772
|
label: playing ? "Pause" : "Play",
|
|
1732
1773
|
caption: String(artist.playableTracksCount),
|
|
1733
1774
|
disabled: artist.playableTracksCount === 0,
|
|
@@ -1755,7 +1796,7 @@ import {
|
|
|
1755
1796
|
SiYoutube
|
|
1756
1797
|
} from "react-icons/si";
|
|
1757
1798
|
import { Chip } from "@behindthemusictree/ui";
|
|
1758
|
-
import { jsx as
|
|
1799
|
+
import { jsx as jsx28 } from "react/jsx-runtime";
|
|
1759
1800
|
var LINK_KINDS = {
|
|
1760
1801
|
official: { label: "Official website", Icon: Globe },
|
|
1761
1802
|
wikipedia: { label: "Wikipedia", Icon: SiWikipedia2 },
|
|
@@ -1792,7 +1833,7 @@ function artistLinks(artist) {
|
|
|
1792
1833
|
return links;
|
|
1793
1834
|
}
|
|
1794
1835
|
function ArtistLinks({ links }) {
|
|
1795
|
-
return /* @__PURE__ */
|
|
1836
|
+
return /* @__PURE__ */ jsx28("ul", { className: "flex flex-wrap gap-1.5", children: links.map(({ key, url, Icon, label }) => /* @__PURE__ */ jsx28("li", { children: /* @__PURE__ */ jsx28(Chip, { href: url, icon: /* @__PURE__ */ jsx28(Icon, { className: "h-3.5 w-3.5 shrink-0", "aria-hidden": "true" }), children: label }) }, key)) });
|
|
1796
1837
|
}
|
|
1797
1838
|
|
|
1798
1839
|
// src/genre-tree/artist/formatYears.ts
|
|
@@ -1803,7 +1844,7 @@ function formatYears(beginYear, endYear, ended) {
|
|
|
1803
1844
|
}
|
|
1804
1845
|
|
|
1805
1846
|
// src/genre-tree/artist/ArtistHeader.tsx
|
|
1806
|
-
import { jsx as
|
|
1847
|
+
import { jsx as jsx29 } from "react/jsx-runtime";
|
|
1807
1848
|
var countryNames = new Intl.DisplayNames(["en"], { type: "region" });
|
|
1808
1849
|
function ArtistHeader({ artist }) {
|
|
1809
1850
|
const fields = [];
|
|
@@ -1813,35 +1854,23 @@ function ArtistHeader({ artist }) {
|
|
|
1813
1854
|
const years = formatYears(artist.beginYear, artist.endYear, artist.ended);
|
|
1814
1855
|
if (years) fields.push({ label: "Active", value: years });
|
|
1815
1856
|
const links = artistLinks(artist);
|
|
1816
|
-
if (links.length > 0) fields.push({ label: "Links", value: /* @__PURE__ */
|
|
1857
|
+
if (links.length > 0) fields.push({ label: "Links", value: /* @__PURE__ */ jsx29(ArtistLinks, { links }) });
|
|
1817
1858
|
if (fields.length === 0) return null;
|
|
1818
|
-
return /* @__PURE__ */
|
|
1859
|
+
return /* @__PURE__ */ jsx29(FieldList, { items: fields });
|
|
1819
1860
|
}
|
|
1820
1861
|
|
|
1821
1862
|
// src/genre-tree/artist/ArtistPhoto.tsx
|
|
1822
|
-
import { jsx as
|
|
1823
|
-
function ExternalLink({ href, children }) {
|
|
1824
|
-
return /* @__PURE__ */ jsx29("a", { href, target: "_blank", rel: "noopener noreferrer", className: "underline-offset-2 hover:underline", children });
|
|
1825
|
-
}
|
|
1863
|
+
import { jsx as jsx30 } from "react/jsx-runtime";
|
|
1826
1864
|
function ArtistPhoto({ image, name }) {
|
|
1827
|
-
return /* @__PURE__ */
|
|
1828
|
-
/* @__PURE__ */ jsx29("img", { src: image.url, alt: name, className: "h-64 w-full object-contain bg-[var(--color-surface-muted)] rounded" }),
|
|
1829
|
-
/* @__PURE__ */ jsxs18("figcaption", { className: "text-caption text-[var(--color-text-muted)]", children: [
|
|
1830
|
-
"Photo: ",
|
|
1831
|
-
/* @__PURE__ */ jsx29(ExternalLink, { href: image.pageUrl, children: image.author ?? "Wikimedia Commons" }),
|
|
1832
|
-
",",
|
|
1833
|
-
" ",
|
|
1834
|
-
image.licenseUrl ? /* @__PURE__ */ jsx29(ExternalLink, { href: image.licenseUrl, children: image.license }) : image.license
|
|
1835
|
-
] })
|
|
1836
|
-
] });
|
|
1865
|
+
return /* @__PURE__ */ jsx30(CommonsPhoto, { image, alt: name });
|
|
1837
1866
|
}
|
|
1838
1867
|
|
|
1839
1868
|
// src/genre-tree/artist/ArtistMembers.tsx
|
|
1840
1869
|
import { PanelGroup, PanelSection as PanelSection3 } from "@behindthemusictree/ui";
|
|
1841
|
-
import { jsx as
|
|
1870
|
+
import { jsx as jsx31, jsxs as jsxs19 } from "react/jsx-runtime";
|
|
1842
1871
|
function MembershipList({ title, memberships, renderArtistLink }) {
|
|
1843
1872
|
if (memberships.length === 0) return null;
|
|
1844
|
-
return /* @__PURE__ */
|
|
1873
|
+
return /* @__PURE__ */ jsx31(PanelGroup, { title, children: /* @__PURE__ */ jsx31("ul", { children: memberships.map((membership, index) => {
|
|
1845
1874
|
const details = [
|
|
1846
1875
|
formatYears(membership.beginYear, membership.endYear, membership.ended),
|
|
1847
1876
|
...membership.roles
|
|
@@ -1850,7 +1879,7 @@ function MembershipList({ title, memberships, renderArtistLink }) {
|
|
|
1850
1879
|
return (
|
|
1851
1880
|
// A member can have several periods in the same group.
|
|
1852
1881
|
/* @__PURE__ */ jsxs19("li", { className: "truncate py-0.5", title: detailsText || void 0, children: [
|
|
1853
|
-
/* @__PURE__ */
|
|
1882
|
+
/* @__PURE__ */ jsx31("span", { className: "font-medium text-[var(--color-text)]", children: renderArtistLink(membership.artist) }),
|
|
1854
1883
|
detailsText && /* @__PURE__ */ jsxs19("span", { className: "text-[var(--color-text-muted)]", children: [
|
|
1855
1884
|
" \u2014 ",
|
|
1856
1885
|
detailsText
|
|
@@ -1863,8 +1892,8 @@ function ArtistMembers({ title, memberships, renderArtistLink }) {
|
|
|
1863
1892
|
if (memberships.length === 0) return null;
|
|
1864
1893
|
const isCurrent = (membership) => !membership.ended && membership.endYear === null;
|
|
1865
1894
|
return /* @__PURE__ */ jsxs19(PanelSection3, { title, children: [
|
|
1866
|
-
/* @__PURE__ */
|
|
1867
|
-
/* @__PURE__ */
|
|
1895
|
+
/* @__PURE__ */ jsx31(MembershipList, { title: "Current", memberships: memberships.filter(isCurrent), renderArtistLink }),
|
|
1896
|
+
/* @__PURE__ */ jsx31(
|
|
1868
1897
|
MembershipList,
|
|
1869
1898
|
{
|
|
1870
1899
|
title: "Past",
|
|
@@ -1877,7 +1906,7 @@ function ArtistMembers({ title, memberships, renderArtistLink }) {
|
|
|
1877
1906
|
|
|
1878
1907
|
// src/genre-tree/artist/ArtistDiscography.tsx
|
|
1879
1908
|
import { PanelGroup as PanelGroup2, PanelSection as PanelSection4 } from "@behindthemusictree/ui";
|
|
1880
|
-
import { jsx as
|
|
1909
|
+
import { jsx as jsx32, jsxs as jsxs20 } from "react/jsx-runtime";
|
|
1881
1910
|
var GROUPS = ["Albums", "EPs", "Singles", "Live", "Compilations", "Other"];
|
|
1882
1911
|
var PRIMARY_GROUPS = { album: "Albums", ep: "EPs", single: "Singles" };
|
|
1883
1912
|
function discographyGroup({ primaryType, secondaryTypes }) {
|
|
@@ -1897,12 +1926,12 @@ function byYear(a, b) {
|
|
|
1897
1926
|
function ArtistDiscography({ albums }) {
|
|
1898
1927
|
if (albums.length === 0) return null;
|
|
1899
1928
|
const sorted = [...albums].sort(byYear);
|
|
1900
|
-
return /* @__PURE__ */
|
|
1929
|
+
return /* @__PURE__ */ jsx32(PanelSection4, { title: "Discography", children: GROUPS.map((group) => {
|
|
1901
1930
|
const groupAlbums = sorted.filter((album) => discographyGroup(album) === group);
|
|
1902
1931
|
if (groupAlbums.length === 0) return null;
|
|
1903
|
-
return /* @__PURE__ */
|
|
1904
|
-
/* @__PURE__ */
|
|
1905
|
-
/* @__PURE__ */
|
|
1932
|
+
return /* @__PURE__ */ jsx32(PanelGroup2, { title: group, children: /* @__PURE__ */ jsx32("ul", { children: groupAlbums.map((album) => /* @__PURE__ */ jsxs20("li", { className: "grid grid-cols-[2.5rem_minmax(0,1fr)] gap-2 py-0.5", children: [
|
|
1933
|
+
/* @__PURE__ */ jsx32("span", { className: "tabular-nums text-[var(--color-text-muted)]", children: album.year ?? "\u2014" }),
|
|
1934
|
+
/* @__PURE__ */ jsx32("span", { className: "truncate text-[var(--color-text)]", title: album.name, children: album.name })
|
|
1906
1935
|
] }, album.uuid)) }) }, group);
|
|
1907
1936
|
}) });
|
|
1908
1937
|
}
|
|
@@ -1910,7 +1939,6 @@ function ArtistDiscography({ albums }) {
|
|
|
1910
1939
|
// src/genre-tree/artist/ArtistSongs.tsx
|
|
1911
1940
|
import { useState as useState8 } from "react";
|
|
1912
1941
|
import { keepPreviousData } from "@tanstack/react-query";
|
|
1913
|
-
import { Play as Play3 } from "lucide-react";
|
|
1914
1942
|
import { Pagination, PanelSection as PanelSection5, Skeleton as Skeleton4 } from "@behindthemusictree/ui";
|
|
1915
1943
|
import { usePlayer as usePlayer9 } from "@behindthemusictree/app-kit/player";
|
|
1916
1944
|
import {
|
|
@@ -1929,7 +1957,7 @@ import { useTrackList as useTrackList4 } from "@behindthemusictree/app-kit/genre
|
|
|
1929
1957
|
import { FaPlay as FaPlay2, FaPause as FaPause2 } from "react-icons/fa";
|
|
1930
1958
|
import { usePlayer as usePlayer7 } from "@behindthemusictree/app-kit/player";
|
|
1931
1959
|
import { PlayStates as PlayStates2 } from "@behindthemusictree/app-kit/player";
|
|
1932
|
-
import { jsx as
|
|
1960
|
+
import { jsx as jsx33, jsxs as jsxs21 } from "react/jsx-runtime";
|
|
1933
1961
|
function TrackPositionPlayPause({
|
|
1934
1962
|
position,
|
|
1935
1963
|
uuid,
|
|
@@ -1950,7 +1978,7 @@ function TrackPositionPlayPause({
|
|
|
1950
1978
|
style: { minWidth: "4rem", maxWidth: "4rem" },
|
|
1951
1979
|
onClick: handlePlayPauseClick,
|
|
1952
1980
|
children: [
|
|
1953
|
-
/* @__PURE__ */
|
|
1981
|
+
/* @__PURE__ */ jsx33("div", { className: "track-position-play-pause__status group-hover:hidden flex items-center justify-center", children: isAwaitingPlayback ? /* @__PURE__ */ jsx33("span", { className: "track-position-play-pause__spinner", role: "status", "aria-label": "Loading track" }) : isCurrentTrackActive ? /* @__PURE__ */ jsxs21(
|
|
1954
1982
|
"span",
|
|
1955
1983
|
{
|
|
1956
1984
|
className: "track-position-play-pause__bars",
|
|
@@ -1958,18 +1986,18 @@ function TrackPositionPlayPause({
|
|
|
1958
1986
|
role: "img",
|
|
1959
1987
|
"aria-label": isPlaying ? "Playing" : "Paused",
|
|
1960
1988
|
children: [
|
|
1961
|
-
/* @__PURE__ */
|
|
1962
|
-
/* @__PURE__ */
|
|
1963
|
-
/* @__PURE__ */
|
|
1989
|
+
/* @__PURE__ */ jsx33("span", { className: "track-position-play-pause__bar" }),
|
|
1990
|
+
/* @__PURE__ */ jsx33("span", { className: "track-position-play-pause__bar" }),
|
|
1991
|
+
/* @__PURE__ */ jsx33("span", { className: "track-position-play-pause__bar" })
|
|
1964
1992
|
]
|
|
1965
1993
|
}
|
|
1966
1994
|
) : position }),
|
|
1967
|
-
/* @__PURE__ */
|
|
1995
|
+
/* @__PURE__ */ jsx33(
|
|
1968
1996
|
"div",
|
|
1969
1997
|
{
|
|
1970
1998
|
className: `hidden group-hover:flex items-center justify-center ${isCurrentTrackActive ? "" : "absolute inset-0"}`,
|
|
1971
1999
|
"aria-hidden": "true",
|
|
1972
|
-
children: isAwaitingPlayback ? /* @__PURE__ */
|
|
2000
|
+
children: isAwaitingPlayback ? /* @__PURE__ */ jsx33("span", { className: "track-position-play-pause__spinner" }) : isPlaying ? /* @__PURE__ */ jsx33(FaPause2, {}) : /* @__PURE__ */ jsx33(FaPlay2, {})
|
|
1973
2001
|
}
|
|
1974
2002
|
)
|
|
1975
2003
|
]
|
|
@@ -1980,7 +2008,7 @@ function TrackPositionPlayPause({
|
|
|
1980
2008
|
// src/genre-tree/track-list-sidebar/TrackItem.tsx
|
|
1981
2009
|
import { isSong as isSong2, songUnplayableReason as songUnplayableReason2 } from "@behindthemusictree/app-kit/genre-tree";
|
|
1982
2010
|
import { ArtistNames as ArtistNames2 } from "@behindthemusictree/app-kit/genre-tree";
|
|
1983
|
-
import { jsx as
|
|
2011
|
+
import { jsx as jsx34, jsxs as jsxs22 } from "react/jsx-runtime";
|
|
1984
2012
|
function TrackItem({
|
|
1985
2013
|
track,
|
|
1986
2014
|
position,
|
|
@@ -2009,7 +2037,7 @@ function TrackItem({
|
|
|
2009
2037
|
{
|
|
2010
2038
|
className: `track-item flex h-14 text-[var(--color-text)] ${isUnplayable ? "opacity-50" : "hover:bg-[var(--color-surface-muted)] group"}`,
|
|
2011
2039
|
children: [
|
|
2012
|
-
isUnplayable ? /* @__PURE__ */
|
|
2040
|
+
isUnplayable ? /* @__PURE__ */ jsx34(
|
|
2013
2041
|
"div",
|
|
2014
2042
|
{
|
|
2015
2043
|
className: "flex items-center justify-center text-lg w-16",
|
|
@@ -2017,7 +2045,7 @@ function TrackItem({
|
|
|
2017
2045
|
"aria-disabled": "true",
|
|
2018
2046
|
children: position
|
|
2019
2047
|
}
|
|
2020
|
-
) : /* @__PURE__ */
|
|
2048
|
+
) : /* @__PURE__ */ jsx34(
|
|
2021
2049
|
TrackPositionPlayPause,
|
|
2022
2050
|
{
|
|
2023
2051
|
position,
|
|
@@ -2027,11 +2055,11 @@ function TrackItem({
|
|
|
2027
2055
|
}
|
|
2028
2056
|
),
|
|
2029
2057
|
/* @__PURE__ */ jsxs22("div", { className: "title-artist-container flex flex-col items-start justify-center min-w-0 flex-1", children: [
|
|
2030
|
-
/* @__PURE__ */
|
|
2031
|
-
track.artists && track.artists.length > 0 ? /* @__PURE__ */
|
|
2058
|
+
/* @__PURE__ */ jsx34("div", { className: "flex max-w-full items-center gap-2", children: /* @__PURE__ */ jsx34("div", { className: "title text-lg font-bold text-[var(--color-text)] max-w-full truncate", children: renderSongLink ? renderSongLink(track) : isSong2(track) ? /* @__PURE__ */ jsx34(MusicBrainzRecordingLink, { song: track, className: "hover:underline focus-visible:underline", children: track.title }) : track.title }) }),
|
|
2059
|
+
track.artists && track.artists.length > 0 ? /* @__PURE__ */ jsx34("div", { className: "artist text-base max-w-full truncate text-[var(--color-text-muted)]", children: /* @__PURE__ */ jsx34(ArtistNames2, { artists: track.artists, renderArtistLink }) }) : ""
|
|
2032
2060
|
] }),
|
|
2033
|
-
/* @__PURE__ */
|
|
2034
|
-
renderDuration && /* @__PURE__ */
|
|
2061
|
+
/* @__PURE__ */ jsx34("div", { className: "genre-name-container flex items-center justify-start w-[21.6%] min-w-0 shrink-0", children: track.genre ? /* @__PURE__ */ jsx34("div", { className: "genre-name max-w-full whitespace-normal break-words p-1 text-caption font-bold", children: track.genre.name }) : "" }),
|
|
2062
|
+
renderDuration && /* @__PURE__ */ jsx34(
|
|
2035
2063
|
"div",
|
|
2036
2064
|
{
|
|
2037
2065
|
className: "duration flex text-base w-16 items-center justify-center",
|
|
@@ -2039,14 +2067,14 @@ function TrackItem({
|
|
|
2039
2067
|
children: renderDuration(track)
|
|
2040
2068
|
}
|
|
2041
2069
|
),
|
|
2042
|
-
renderActions && /* @__PURE__ */
|
|
2070
|
+
renderActions && /* @__PURE__ */ jsx34("div", { className: "edit flex text-base w-6 items-center justify-center mr-2 cursor-pointer", children: renderActions(track) })
|
|
2043
2071
|
]
|
|
2044
2072
|
}
|
|
2045
2073
|
);
|
|
2046
2074
|
}
|
|
2047
2075
|
|
|
2048
2076
|
// src/genre-tree/artist/ArtistSongs.tsx
|
|
2049
|
-
import { Fragment as Fragment12, jsx as
|
|
2077
|
+
import { Fragment as Fragment12, jsx as jsx35, jsxs as jsxs23 } from "react/jsx-runtime";
|
|
2050
2078
|
var SongPageSchema2 = PaginatedResponseSchema2(SongDetailedSchema2);
|
|
2051
2079
|
var SORTS = [
|
|
2052
2080
|
{ ordering: "title", label: "Title" },
|
|
@@ -2079,36 +2107,22 @@ function ArtistSongs({ artist, getBackendBaseUrl, renderArtistLink, renderSongLi
|
|
|
2079
2107
|
event.stopPropagation();
|
|
2080
2108
|
void play(song.uuid);
|
|
2081
2109
|
};
|
|
2082
|
-
return /* @__PURE__ */
|
|
2083
|
-
/* @__PURE__ */
|
|
2084
|
-
|
|
2085
|
-
|
|
2086
|
-
|
|
2087
|
-
|
|
2088
|
-
|
|
2089
|
-
|
|
2090
|
-
|
|
2091
|
-
/* @__PURE__ */ jsx34(Play3, { className: "h-3.5 w-3.5", "aria-hidden": "true" }),
|
|
2092
|
-
"Play all"
|
|
2093
|
-
]
|
|
2094
|
-
}
|
|
2095
|
-
),
|
|
2096
|
-
/* @__PURE__ */ jsx34("div", { role: "group", "aria-label": "Sort songs by", className: "flex gap-1 text-caption", children: SORTS.map((sort) => /* @__PURE__ */ jsx34(
|
|
2097
|
-
"button",
|
|
2098
|
-
{
|
|
2099
|
-
type: "button",
|
|
2100
|
-
"aria-pressed": ordering === sort.ordering,
|
|
2101
|
-
onClick: () => {
|
|
2102
|
-
setOrdering(sort.ordering);
|
|
2103
|
-
setPage(1);
|
|
2104
|
-
},
|
|
2105
|
-
className: "px-2.5 py-0.5 text-[var(--color-text)] rounded-full hover:bg-[var(--color-surface-muted)] aria-pressed:bg-gray-900 aria-pressed:text-white",
|
|
2106
|
-
children: sort.label
|
|
2110
|
+
return /* @__PURE__ */ jsx35(PanelSection5, { title: "Songs", children: isPending ? /* @__PURE__ */ jsx35(Skeleton4, { className: "h-14", "aria-busy": "true" }) : isError ? /* @__PURE__ */ jsx35("p", { className: "text-red-600", children: "Could not load songs." }) : data.results.length === 0 ? /* @__PURE__ */ jsx35("p", { className: "text-[var(--color-text-muted)]", children: "No songs yet." }) : /* @__PURE__ */ jsxs23(Fragment12, { children: [
|
|
2111
|
+
/* @__PURE__ */ jsx35("div", { className: "flex flex-wrap items-center justify-end gap-2 mb-2", children: /* @__PURE__ */ jsx35("div", { role: "group", "aria-label": "Sort songs by", className: "flex gap-1 text-caption", children: SORTS.map((sort) => /* @__PURE__ */ jsx35(
|
|
2112
|
+
"button",
|
|
2113
|
+
{
|
|
2114
|
+
type: "button",
|
|
2115
|
+
"aria-pressed": ordering === sort.ordering,
|
|
2116
|
+
onClick: () => {
|
|
2117
|
+
setOrdering(sort.ordering);
|
|
2118
|
+
setPage(1);
|
|
2107
2119
|
},
|
|
2108
|
-
|
|
2109
|
-
|
|
2110
|
-
|
|
2111
|
-
|
|
2120
|
+
className: "px-2.5 py-0.5 text-[var(--color-text)] rounded-full hover:bg-[var(--color-surface-muted)] aria-pressed:bg-gray-900 aria-pressed:text-white",
|
|
2121
|
+
children: sort.label
|
|
2122
|
+
},
|
|
2123
|
+
sort.ordering
|
|
2124
|
+
)) }) }),
|
|
2125
|
+
/* @__PURE__ */ jsx35("ul", { className: "overflow-hidden mb-2 bg-zinc-950 rounded-lg", children: data.results.map((song, index) => /* @__PURE__ */ jsx35("li", { onClickCapture: (event) => handleRowClickCapture(event, song), children: /* @__PURE__ */ jsx35(
|
|
2112
2126
|
TrackItem,
|
|
2113
2127
|
{
|
|
2114
2128
|
track: song,
|
|
@@ -2117,12 +2131,12 @@ function ArtistSongs({ artist, getBackendBaseUrl, renderArtistLink, renderSongLi
|
|
|
2117
2131
|
renderSongLink
|
|
2118
2132
|
}
|
|
2119
2133
|
) }, song.uuid)) }),
|
|
2120
|
-
/* @__PURE__ */
|
|
2134
|
+
/* @__PURE__ */ jsx35(Pagination, { currentPage: page, totalPages: data.totalPages, onPageChange: setPage })
|
|
2121
2135
|
] }) });
|
|
2122
2136
|
}
|
|
2123
2137
|
|
|
2124
2138
|
// src/genre-tree/artist/useArtistPanel.tsx
|
|
2125
|
-
import { Fragment as Fragment13, jsx as
|
|
2139
|
+
import { Fragment as Fragment13, jsx as jsx36, jsxs as jsxs24 } from "react/jsx-runtime";
|
|
2126
2140
|
function useArtistPanel({
|
|
2127
2141
|
uuid,
|
|
2128
2142
|
scope,
|
|
@@ -2144,25 +2158,25 @@ function useArtistPanel({
|
|
|
2144
2158
|
...panel,
|
|
2145
2159
|
title: "Artist",
|
|
2146
2160
|
content: /* @__PURE__ */ jsxs24("div", { "aria-busy": "true", className: "flex flex-col gap-2.5", children: [
|
|
2147
|
-
/* @__PURE__ */
|
|
2148
|
-
/* @__PURE__ */
|
|
2149
|
-
/* @__PURE__ */
|
|
2150
|
-
/* @__PURE__ */
|
|
2151
|
-
/* @__PURE__ */
|
|
2152
|
-
/* @__PURE__ */
|
|
2161
|
+
/* @__PURE__ */ jsx36(Skeleton5, { className: "h-3 w-16" }),
|
|
2162
|
+
/* @__PURE__ */ jsx36(Skeleton5, { className: "h-4 w-32" }),
|
|
2163
|
+
/* @__PURE__ */ jsx36(Skeleton5, { className: "h-3 w-16" }),
|
|
2164
|
+
/* @__PURE__ */ jsx36(Skeleton5, { className: "h-4 w-24" }),
|
|
2165
|
+
/* @__PURE__ */ jsx36(Skeleton5, { className: "h-16 mt-2.5" }),
|
|
2166
|
+
/* @__PURE__ */ jsx36(Skeleton5, { className: "h-16" })
|
|
2153
2167
|
] })
|
|
2154
2168
|
};
|
|
2155
2169
|
case "not-found":
|
|
2156
2170
|
return {
|
|
2157
2171
|
...panel,
|
|
2158
2172
|
title: "Artist not found",
|
|
2159
|
-
content: /* @__PURE__ */
|
|
2173
|
+
content: /* @__PURE__ */ jsx36("p", { className: "text-[var(--color-text-muted)]", children: "This artist does not exist." })
|
|
2160
2174
|
};
|
|
2161
2175
|
case "error":
|
|
2162
2176
|
return {
|
|
2163
2177
|
...panel,
|
|
2164
2178
|
title: "Artist",
|
|
2165
|
-
content: /* @__PURE__ */
|
|
2179
|
+
content: /* @__PURE__ */ jsx36("p", { className: "text-red-600", children: "Could not load this artist." })
|
|
2166
2180
|
};
|
|
2167
2181
|
case "success": {
|
|
2168
2182
|
const { artist } = result;
|
|
@@ -2172,18 +2186,18 @@ function useArtistPanel({
|
|
|
2172
2186
|
...panel,
|
|
2173
2187
|
title: artist.name,
|
|
2174
2188
|
content: /* @__PURE__ */ jsxs24(Fragment13, { children: [
|
|
2175
|
-
/* @__PURE__ */
|
|
2189
|
+
/* @__PURE__ */ jsx36(
|
|
2176
2190
|
ArtistActionBand,
|
|
2177
2191
|
{
|
|
2178
2192
|
artist,
|
|
2179
|
-
share: shareTarget && shareUrl ? /* @__PURE__ */
|
|
2193
|
+
share: shareTarget && shareUrl ? /* @__PURE__ */ jsx36(ShareActionButton, { target: shareTarget, url: shareUrl }) : void 0
|
|
2180
2194
|
}
|
|
2181
2195
|
),
|
|
2182
|
-
artist.image && /* @__PURE__ */
|
|
2183
|
-
/* @__PURE__ */
|
|
2184
|
-
/* @__PURE__ */
|
|
2185
|
-
/* @__PURE__ */
|
|
2186
|
-
artist.tracksCount > 0 && /* @__PURE__ */
|
|
2196
|
+
artist.image && /* @__PURE__ */ jsx36(ArtistPhoto, { image: artist.image, name: artist.name }),
|
|
2197
|
+
/* @__PURE__ */ jsx36(ArtistHeader, { artist }),
|
|
2198
|
+
/* @__PURE__ */ jsx36(ArtistMembers, { title: "Members", memberships: artist.members, renderArtistLink }),
|
|
2199
|
+
/* @__PURE__ */ jsx36(ArtistMembers, { title: "Member of", memberships: artist.memberOf, renderArtistLink }),
|
|
2200
|
+
artist.tracksCount > 0 && /* @__PURE__ */ jsx36(
|
|
2187
2201
|
ArtistSongs,
|
|
2188
2202
|
{
|
|
2189
2203
|
artist: { uuid: artist.uuid, name: artist.name },
|
|
@@ -2193,7 +2207,7 @@ function useArtistPanel({
|
|
|
2193
2207
|
}
|
|
2194
2208
|
)
|
|
2195
2209
|
] }),
|
|
2196
|
-
extraContent: artist.albums.length > 0 ? /* @__PURE__ */
|
|
2210
|
+
extraContent: artist.albums.length > 0 ? /* @__PURE__ */ jsx36(ArtistDiscography, { albums: artist.albums }) : void 0
|
|
2197
2211
|
};
|
|
2198
2212
|
}
|
|
2199
2213
|
}
|
|
@@ -2207,7 +2221,7 @@ import {
|
|
|
2207
2221
|
|
|
2208
2222
|
// src/genre-tree/song/SongPanelContent.tsx
|
|
2209
2223
|
import { useState as useState9 } from "react";
|
|
2210
|
-
import { Pause as Pause3, Play as
|
|
2224
|
+
import { Pause as Pause3, Play as Play3 } from "lucide-react";
|
|
2211
2225
|
import { ActionBand as ActionBand3, ActionButton as ActionButton5, FieldList as FieldList2, PANEL_LABEL_CLASS, PanelBleed as PanelBleed3, PanelSection as PanelSection6, Skeleton as Skeleton6 } from "@behindthemusictree/ui";
|
|
2212
2226
|
import { PlayStates as PlayStates3, usePlayer as usePlayer10 } from "@behindthemusictree/app-kit/player";
|
|
2213
2227
|
import {
|
|
@@ -2217,7 +2231,7 @@ import {
|
|
|
2217
2231
|
useSongHistory,
|
|
2218
2232
|
useTrackList as useTrackList6
|
|
2219
2233
|
} from "@behindthemusictree/app-kit/genre-tree";
|
|
2220
|
-
import { Fragment as Fragment14, jsx as
|
|
2234
|
+
import { Fragment as Fragment14, jsx as jsx37, jsxs as jsxs25 } from "react/jsx-runtime";
|
|
2221
2235
|
var numberFormat = new Intl.NumberFormat("en");
|
|
2222
2236
|
var dateFormat = new Intl.DateTimeFormat("en", { dateStyle: "medium" });
|
|
2223
2237
|
var externalLink = "text-[var(--color-primary)] hover:underline focus-visible:underline";
|
|
@@ -2225,11 +2239,11 @@ function SongHistory({ uuid, getBackendBaseUrl }) {
|
|
|
2225
2239
|
const [open, setOpen] = useState9(false);
|
|
2226
2240
|
const history = useSongHistory(uuid, getBackendBaseUrl, open);
|
|
2227
2241
|
let body = null;
|
|
2228
|
-
if (history.status === "loading") body = /* @__PURE__ */
|
|
2229
|
-
else if (history.status === "error") body = /* @__PURE__ */
|
|
2242
|
+
if (history.status === "loading") body = /* @__PURE__ */ jsx37(Skeleton6, { className: "h-10", "aria-busy": "true" });
|
|
2243
|
+
else if (history.status === "error") body = /* @__PURE__ */ jsx37("p", { className: "text-red-600", children: "Could not load the history." });
|
|
2230
2244
|
else if (history.status === "success")
|
|
2231
|
-
body = history.entries.length === 0 ? /* @__PURE__ */
|
|
2232
|
-
/* @__PURE__ */
|
|
2245
|
+
body = history.entries.length === 0 ? /* @__PURE__ */ jsx37("p", { className: "text-[var(--color-text-muted)]", children: "No changes yet." }) : /* @__PURE__ */ jsx37("ul", { className: "divide-y divide-[var(--color-border)]", children: history.entries.map((entry) => /* @__PURE__ */ jsxs25("li", { className: "py-1.5 text-body", children: [
|
|
2246
|
+
/* @__PURE__ */ jsx37("span", { className: "font-medium", children: entry.action }),
|
|
2233
2247
|
entry.oldValue !== null || entry.newValue !== null ? /* @__PURE__ */ jsxs25("span", { className: "text-[var(--color-text-muted)]", children: [
|
|
2234
2248
|
" ",
|
|
2235
2249
|
"\u2014 ",
|
|
@@ -2243,9 +2257,9 @@ function SongHistory({ uuid, getBackendBaseUrl }) {
|
|
|
2243
2257
|
dateFormat.format(new Date(entry.createdOn))
|
|
2244
2258
|
] })
|
|
2245
2259
|
] }, entry.uuid)) });
|
|
2246
|
-
return /* @__PURE__ */
|
|
2247
|
-
/* @__PURE__ */
|
|
2248
|
-
/* @__PURE__ */
|
|
2260
|
+
return /* @__PURE__ */ jsx37(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: [
|
|
2261
|
+
/* @__PURE__ */ jsx37("summary", { className: `mt-2.5 cursor-pointer ${PANEL_LABEL_CLASS}`, children: "History" }),
|
|
2262
|
+
/* @__PURE__ */ jsx37("div", { className: "mt-1.5", children: body })
|
|
2249
2263
|
] }) });
|
|
2250
2264
|
}
|
|
2251
2265
|
function SongPanelContent(props) {
|
|
@@ -2264,13 +2278,13 @@ function SongPanelContent(props) {
|
|
|
2264
2278
|
const genre = song.genre;
|
|
2265
2279
|
fields.push({
|
|
2266
2280
|
label: "Genre",
|
|
2267
|
-
value: onSelectGenre ? /* @__PURE__ */
|
|
2268
|
-
index > 0 && /* @__PURE__ */
|
|
2269
|
-
/* @__PURE__ */
|
|
2281
|
+
value: onSelectGenre ? /* @__PURE__ */ jsx37("button", { type: "button", onClick: () => onSelectGenre(genre), className: "hover:underline", children: genre.name }) : path ? /* @__PURE__ */ jsx37("span", { className: "flex flex-wrap items-center gap-x-1", children: path.map((genrePlaylist, index) => /* @__PURE__ */ jsxs25("span", { children: [
|
|
2282
|
+
index > 0 && /* @__PURE__ */ jsx37("span", { "aria-hidden": "true", children: "\u203A " }),
|
|
2283
|
+
/* @__PURE__ */ jsx37("button", { type: "button", onClick: () => props.onSelectGenrePlaylist?.(genrePlaylist), className: "hover:underline", children: genrePlaylist.name })
|
|
2270
2284
|
] }, genrePlaylist.uuid)) }) : song.genre.name
|
|
2271
2285
|
});
|
|
2272
2286
|
} else {
|
|
2273
|
-
fields.push({ label: "Genre", value: /* @__PURE__ */
|
|
2287
|
+
fields.push({ label: "Genre", value: /* @__PURE__ */ jsx37("span", { className: "text-[var(--color-text-muted)]", children: "No genre" }) });
|
|
2274
2288
|
}
|
|
2275
2289
|
if (song.firstReleaseYear) fields.push({ label: "First released", value: song.firstReleaseYear });
|
|
2276
2290
|
const viewCount = song.youtubeVideo?.viewCount;
|
|
@@ -2280,11 +2294,11 @@ function SongPanelContent(props) {
|
|
|
2280
2294
|
const links = [];
|
|
2281
2295
|
if (musicBrainzUrl)
|
|
2282
2296
|
links.push(
|
|
2283
|
-
/* @__PURE__ */
|
|
2297
|
+
/* @__PURE__ */ jsx37("a", { href: musicBrainzUrl, target: "_blank", rel: "noopener noreferrer", className: externalLink, children: "MusicBrainz" }, "mb")
|
|
2284
2298
|
);
|
|
2285
2299
|
if (song.youtubeVideo)
|
|
2286
2300
|
links.push(
|
|
2287
|
-
/* @__PURE__ */
|
|
2301
|
+
/* @__PURE__ */ jsx37(
|
|
2288
2302
|
"a",
|
|
2289
2303
|
{
|
|
2290
2304
|
href: `https://www.youtube.com/watch?v=${encodeURIComponent(song.youtubeVideo.id)}`,
|
|
@@ -2299,31 +2313,31 @@ function SongPanelContent(props) {
|
|
|
2299
2313
|
if (links.length > 0)
|
|
2300
2314
|
fields.push({
|
|
2301
2315
|
label: "Links",
|
|
2302
|
-
value: /* @__PURE__ */
|
|
2316
|
+
value: /* @__PURE__ */ jsx37("span", { className: "flex gap-3", children: links })
|
|
2303
2317
|
});
|
|
2304
2318
|
return /* @__PURE__ */ jsxs25(Fragment14, { children: [
|
|
2305
|
-
/* @__PURE__ */
|
|
2306
|
-
/* @__PURE__ */
|
|
2319
|
+
/* @__PURE__ */ jsx37(PanelBleed3, { children: /* @__PURE__ */ jsxs25(ActionBand3, { children: [
|
|
2320
|
+
/* @__PURE__ */ jsx37(
|
|
2307
2321
|
ActionButton5,
|
|
2308
2322
|
{
|
|
2309
|
-
icon: isPlaying ? /* @__PURE__ */
|
|
2323
|
+
icon: isPlaying ? /* @__PURE__ */ jsx37(Pause3, { "aria-hidden": "true", className: "w-5 h-5" }) : /* @__PURE__ */ jsx37(Play3, { "aria-hidden": "true", className: "w-5 h-5" }),
|
|
2310
2324
|
label: isPlaying ? "Pause" : "Play",
|
|
2311
2325
|
disabled: !!unplayableReason,
|
|
2312
2326
|
title: unplayableReason ?? void 0,
|
|
2313
2327
|
onClick: () => isCurrent ? handlePlayPauseAction() : playNewTrackListFromTrackUuid(song, scope)
|
|
2314
2328
|
}
|
|
2315
2329
|
),
|
|
2316
|
-
shareUrl && /* @__PURE__ */
|
|
2330
|
+
shareUrl && /* @__PURE__ */ jsx37(ShareActionButton, { target: shareTarget, url: shareUrl })
|
|
2317
2331
|
] }) }),
|
|
2318
|
-
song.artists && song.artists.length > 0 && /* @__PURE__ */
|
|
2319
|
-
/* @__PURE__ */
|
|
2320
|
-
song.essentialGenres && song.essentialGenres.length > 0 && /* @__PURE__ */
|
|
2321
|
-
/* @__PURE__ */
|
|
2332
|
+
song.artists && song.artists.length > 0 && /* @__PURE__ */ jsx37("p", { className: "text-[var(--color-text-muted)]", children: /* @__PURE__ */ jsx37(ArtistNames3, { artists: song.artists, renderArtistLink }) }),
|
|
2333
|
+
/* @__PURE__ */ jsx37(FieldList2, { items: fields }),
|
|
2334
|
+
song.essentialGenres && song.essentialGenres.length > 0 && /* @__PURE__ */ jsx37(PanelSection6, { title: "Essential in", children: /* @__PURE__ */ jsx37("ul", { children: song.essentialGenres.map((genre) => /* @__PURE__ */ jsx37("li", { className: "py-0.5", children: genre.name }, genre.uuid)) }) }),
|
|
2335
|
+
/* @__PURE__ */ jsx37(SongHistory, { uuid: song.uuid, getBackendBaseUrl })
|
|
2322
2336
|
] });
|
|
2323
2337
|
}
|
|
2324
2338
|
|
|
2325
2339
|
// src/genre-tree/song/useSongPanel.tsx
|
|
2326
|
-
import { jsx as
|
|
2340
|
+
import { jsx as jsx38, jsxs as jsxs26 } from "react/jsx-runtime";
|
|
2327
2341
|
function useSongPanel({
|
|
2328
2342
|
uuid,
|
|
2329
2343
|
scope,
|
|
@@ -2345,23 +2359,23 @@ function useSongPanel({
|
|
|
2345
2359
|
...panel,
|
|
2346
2360
|
title: "Song",
|
|
2347
2361
|
content: /* @__PURE__ */ jsxs26("div", { "aria-busy": "true", className: "flex flex-col gap-2.5", children: [
|
|
2348
|
-
/* @__PURE__ */
|
|
2349
|
-
/* @__PURE__ */
|
|
2350
|
-
/* @__PURE__ */
|
|
2351
|
-
/* @__PURE__ */
|
|
2362
|
+
/* @__PURE__ */ jsx38(Skeleton7, { className: "h-3 w-16" }),
|
|
2363
|
+
/* @__PURE__ */ jsx38(Skeleton7, { className: "h-4 w-32" }),
|
|
2364
|
+
/* @__PURE__ */ jsx38(Skeleton7, { className: "h-3 w-16" }),
|
|
2365
|
+
/* @__PURE__ */ jsx38(Skeleton7, { className: "h-4 w-24" })
|
|
2352
2366
|
] })
|
|
2353
2367
|
};
|
|
2354
2368
|
case "not-found":
|
|
2355
2369
|
return {
|
|
2356
2370
|
...panel,
|
|
2357
2371
|
title: "Song not found",
|
|
2358
|
-
content: /* @__PURE__ */
|
|
2372
|
+
content: /* @__PURE__ */ jsx38("p", { className: "text-[var(--color-text-muted)]", children: "This song does not exist." })
|
|
2359
2373
|
};
|
|
2360
2374
|
case "error":
|
|
2361
2375
|
return {
|
|
2362
2376
|
...panel,
|
|
2363
2377
|
title: "Song",
|
|
2364
|
-
content: /* @__PURE__ */
|
|
2378
|
+
content: /* @__PURE__ */ jsx38("p", { className: "text-red-600", children: "Could not load this song." })
|
|
2365
2379
|
};
|
|
2366
2380
|
case "success": {
|
|
2367
2381
|
const { song } = result;
|
|
@@ -2369,7 +2383,7 @@ function useSongPanel({
|
|
|
2369
2383
|
return {
|
|
2370
2384
|
...panel,
|
|
2371
2385
|
title: song.title,
|
|
2372
|
-
content: /* @__PURE__ */
|
|
2386
|
+
content: /* @__PURE__ */ jsx38(
|
|
2373
2387
|
SongPanelContent,
|
|
2374
2388
|
{
|
|
2375
2389
|
song,
|
|
@@ -2422,12 +2436,12 @@ function useEntityPanel({
|
|
|
2422
2436
|
// src/genre-tree/SizeMetricToggle.tsx
|
|
2423
2437
|
import { MdMusicNote, MdVisibility } from "react-icons/md";
|
|
2424
2438
|
import { SegmentedControl } from "@behindthemusictree/ui";
|
|
2425
|
-
import { jsx as
|
|
2439
|
+
import { jsx as jsx39 } from "react/jsx-runtime";
|
|
2426
2440
|
function SizeMetricToggle({
|
|
2427
2441
|
value,
|
|
2428
2442
|
onChange
|
|
2429
2443
|
}) {
|
|
2430
|
-
return /* @__PURE__ */
|
|
2444
|
+
return /* @__PURE__ */ jsx39(
|
|
2431
2445
|
SegmentedControl,
|
|
2432
2446
|
{
|
|
2433
2447
|
variant: "floating",
|
|
@@ -2435,15 +2449,15 @@ function SizeMetricToggle({
|
|
|
2435
2449
|
value,
|
|
2436
2450
|
onChange,
|
|
2437
2451
|
options: [
|
|
2438
|
-
{ value: "songs", label: /* @__PURE__ */
|
|
2439
|
-
{ value: "views", label: /* @__PURE__ */
|
|
2452
|
+
{ value: "songs", label: /* @__PURE__ */ jsx39(MdMusicNote, { size: 18, "aria-hidden": true }), "aria-label": "Size by songs", title: "Node size by song count" },
|
|
2453
|
+
{ value: "views", label: /* @__PURE__ */ jsx39(MdVisibility, { size: 18, "aria-hidden": true }), "aria-label": "Size by views", title: "Node size by song views" }
|
|
2440
2454
|
]
|
|
2441
2455
|
}
|
|
2442
2456
|
);
|
|
2443
2457
|
}
|
|
2444
2458
|
|
|
2445
2459
|
// src/genre-tree/GenreTreeView.tsx
|
|
2446
|
-
import { Fragment as Fragment15, jsx as
|
|
2460
|
+
import { Fragment as Fragment15, jsx as jsx40, jsxs as jsxs27 } from "react/jsx-runtime";
|
|
2447
2461
|
var NO_POP_ROOT_TITLE = "This genre tree has no 'Mainstream Pop' root yet";
|
|
2448
2462
|
var REGIONS_CLASS = "[--gtv-center-left:var(--layout-center-left)] [--gtv-center-right:var(--layout-center-right)] [--gtv-center-top:var(--layout-band-top)]";
|
|
2449
2463
|
var noop = () => {
|
|
@@ -2595,14 +2609,14 @@ function GenreTreeView({
|
|
|
2595
2609
|
const openSongRef = useRef3(openSong);
|
|
2596
2610
|
openSongRef.current = openSong;
|
|
2597
2611
|
const resolvedRenderSongLink = useCallback6(
|
|
2598
|
-
(song) => renderSongLink ? renderSongLink(song) : /* @__PURE__ */
|
|
2612
|
+
(song) => renderSongLink ? renderSongLink(song) : /* @__PURE__ */ jsx40("button", { type: "button", onClick: () => openSongRef.current(song.uuid), className: "hover:underline", children: song.title }),
|
|
2599
2613
|
[renderSongLink]
|
|
2600
2614
|
);
|
|
2601
2615
|
const [expandedSongUuid, setExpandedSongUuid] = useState10(null);
|
|
2602
2616
|
const [expandedArtistUuid, setExpandedArtistUuid] = useState10(null);
|
|
2603
2617
|
const artistBaseUrl = artistSearchBaseUrl ?? getBackendBaseUrl;
|
|
2604
2618
|
const songBaseUrl = getBackendBaseUrl;
|
|
2605
|
-
const resolvedRenderArtistLink = renderArtistLink ?? ((artist) => artist.isSpecialPurpose ? artist.name : /* @__PURE__ */
|
|
2619
|
+
const resolvedRenderArtistLink = renderArtistLink ?? ((artist) => artist.isSpecialPurpose ? artist.name : /* @__PURE__ */ jsx40("button", { type: "button", onClick: () => openArtist(artist.uuid), className: "hover:underline", children: artist.name }));
|
|
2606
2620
|
const getGenrePath = (genre) => {
|
|
2607
2621
|
const path = [];
|
|
2608
2622
|
let current = visibleGenrePlaylists.find((playlist) => playlist.criteria?.uuid === genre.uuid);
|
|
@@ -2678,9 +2692,11 @@ function GenreTreeView({
|
|
|
2678
2692
|
!overlayPanel && hasSelectedGenreNode ? selectedNodeId : null,
|
|
2679
2693
|
resolveStyle
|
|
2680
2694
|
);
|
|
2681
|
-
const
|
|
2682
|
-
|
|
2683
|
-
|
|
2695
|
+
const treeStyles = useMemo8(() => toGenreNodeStyles(relations, visibleGenrePlaylists), [relations, visibleGenrePlaylists]);
|
|
2696
|
+
const validSelectedGenreUuid = toGenreUuid(selectedGenreUuid);
|
|
2697
|
+
const [selectionHistory, setSelectionHistory] = useState10({ current: validSelectedGenreUuid, previous: null });
|
|
2698
|
+
if (selectionHistory.current !== validSelectedGenreUuid) {
|
|
2699
|
+
setSelectionHistory({ current: validSelectedGenreUuid, previous: selectionHistory.current ?? selectionHistory.previous });
|
|
2684
2700
|
}
|
|
2685
2701
|
const handlePrevious = selectionHistory.previous ? () => selectGenre(selectionHistory.previous) : void 0;
|
|
2686
2702
|
const { showPopup, hidePopup } = usePopup4();
|
|
@@ -2712,7 +2728,7 @@ function GenreTreeView({
|
|
|
2712
2728
|
const canToggleSide = !readOnly && criteria !== void 0 && criteria !== null && parentPlaylist !== void 0 && parentPlaylist.parent === null;
|
|
2713
2729
|
const side = criteria?.side ?? "core";
|
|
2714
2730
|
const popSibling = canToggleSide && side === "core" ? visibleGenrePlaylists.find((sibling) => sibling.parent?.uuid === parentPlaylist.uuid && sibling.uuid !== genrePlaylist?.uuid && sibling.criteria?.side === "pop") : void 0;
|
|
2715
|
-
const shareTarget =
|
|
2731
|
+
const shareTarget = validSelectedGenreUuid ? { kind: "genre", genreUuid: validSelectedGenreUuid, name: criteria?.name ?? "Genre", scope, artistUuid } : void 0;
|
|
2716
2732
|
const shareUrl = shareTarget ? getShareUrlRef.current?.(shareTarget) ?? void 0 : void 0;
|
|
2717
2733
|
const genreContent = useGenreDetailContent({
|
|
2718
2734
|
genreUuid: selectedGenreUuid,
|
|
@@ -2723,7 +2739,7 @@ function GenreTreeView({
|
|
|
2723
2739
|
selectGenre(uuid);
|
|
2724
2740
|
},
|
|
2725
2741
|
expanded: isExpanded,
|
|
2726
|
-
|
|
2742
|
+
treeStyles,
|
|
2727
2743
|
playback,
|
|
2728
2744
|
genrePlaylist: selectedGenrePlaylist,
|
|
2729
2745
|
band: {
|
|
@@ -2734,7 +2750,7 @@ function GenreTreeView({
|
|
|
2734
2750
|
onAddChild: readOnly || !criteria ? void 0 : () => handleGenreCreationAction(criteria),
|
|
2735
2751
|
onRename: readOnly || !criteria ? void 0 : () => handleGenreRenameAction(criteria),
|
|
2736
2752
|
onChangeParent: readOnly || !genrePlaylist || !criteria ? void 0 : () => showPopup(
|
|
2737
|
-
/* @__PURE__ */
|
|
2753
|
+
/* @__PURE__ */ jsx40(
|
|
2738
2754
|
ChangeParentPopup,
|
|
2739
2755
|
{
|
|
2740
2756
|
genrePlaylist: { ...genrePlaylist, criteria },
|
|
@@ -2778,7 +2794,7 @@ function GenreTreeView({
|
|
|
2778
2794
|
onClose: otherPanel.onClose,
|
|
2779
2795
|
searchName: otherPanel.title
|
|
2780
2796
|
};
|
|
2781
|
-
} else if (selectedGenreUuid) {
|
|
2797
|
+
} else if (selectedGenreUuid !== null) {
|
|
2782
2798
|
activePanel = {
|
|
2783
2799
|
title: genreContent.title,
|
|
2784
2800
|
content: genreContent.content,
|
|
@@ -2795,19 +2811,19 @@ function GenreTreeView({
|
|
|
2795
2811
|
edge: activePanel.expanded ? { label: "Shrink panel", onClick: () => activePanel.onExpandedChange?.(false) } : isCollapsed ? null : { label: "Hide panel", onClick: () => changeCollapsed(true) },
|
|
2796
2812
|
center: activePanel.expanded ? null : isCollapsed ? { label: "Show panel", onClick: () => changeCollapsed(false) } : activePanel.onExpandedChange ? { label: "Extend panel", onClick: () => activePanel.onExpandedChange?.(true) } : null
|
|
2797
2813
|
} : void 0;
|
|
2798
|
-
const expandButton = placement === "default" && activePanel?.onExpandedChange ? /* @__PURE__ */
|
|
2814
|
+
const expandButton = placement === "default" && activePanel?.onExpandedChange ? /* @__PURE__ */ jsx40(
|
|
2799
2815
|
IconButton2,
|
|
2800
2816
|
{
|
|
2801
2817
|
"aria-label": activePanel.expanded ? "Shrink panel" : "Extend panel",
|
|
2802
2818
|
style: activePanel.headerAccent && { color: "inherit" },
|
|
2803
2819
|
onClick: () => activePanel.onExpandedChange?.(!activePanel.expanded),
|
|
2804
|
-
children: activePanel.expanded ? /* @__PURE__ */
|
|
2820
|
+
children: activePanel.expanded ? /* @__PURE__ */ jsx40(Minimize22, { "aria-hidden": "true", className: "h-4 w-4" }) : /* @__PURE__ */ jsx40(Maximize22, { "aria-hidden": "true", className: "h-4 w-4" })
|
|
2805
2821
|
}
|
|
2806
2822
|
) : null;
|
|
2807
2823
|
const renderArtistFilter = () => {
|
|
2808
2824
|
if (isLoading || !filterArtist) return null;
|
|
2809
2825
|
return /* @__PURE__ */ jsxs27("span", { className: "inline-flex items-center overflow-hidden rounded-full bg-[var(--color-neutral-100)] text-body", children: [
|
|
2810
|
-
/* @__PURE__ */
|
|
2826
|
+
/* @__PURE__ */ jsx40(
|
|
2811
2827
|
"button",
|
|
2812
2828
|
{
|
|
2813
2829
|
type: "button",
|
|
@@ -2819,7 +2835,7 @@ function GenreTreeView({
|
|
|
2819
2835
|
children: filterArtist.name
|
|
2820
2836
|
}
|
|
2821
2837
|
),
|
|
2822
|
-
/* @__PURE__ */
|
|
2838
|
+
/* @__PURE__ */ jsx40(
|
|
2823
2839
|
"button",
|
|
2824
2840
|
{
|
|
2825
2841
|
type: "button",
|
|
@@ -2832,7 +2848,7 @@ function GenreTreeView({
|
|
|
2832
2848
|
] });
|
|
2833
2849
|
};
|
|
2834
2850
|
const actions = /* @__PURE__ */ jsxs27(Fragment15, { children: [
|
|
2835
|
-
!isLoading && !isError && /* @__PURE__ */
|
|
2851
|
+
!isLoading && !isError && /* @__PURE__ */ jsx40(
|
|
2836
2852
|
GenreTreeSearch,
|
|
2837
2853
|
{
|
|
2838
2854
|
artistBaseUrl,
|
|
@@ -2865,9 +2881,9 @@ function GenreTreeView({
|
|
|
2865
2881
|
extraGroups: extraSearchGroups
|
|
2866
2882
|
}
|
|
2867
2883
|
),
|
|
2868
|
-
!isLoading && !isError && filterArtist && /* @__PURE__ */
|
|
2884
|
+
!isLoading && !isError && filterArtist && /* @__PURE__ */ jsx40("div", { className: "hidden w-full justify-center max-md:flex", children: renderArtistFilter() }),
|
|
2869
2885
|
/* @__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: [
|
|
2870
|
-
!isLoading && !isError && !isControlled && /* @__PURE__ */
|
|
2886
|
+
!isLoading && !isError && !isControlled && /* @__PURE__ */ jsx40(
|
|
2871
2887
|
SegmentedControl2,
|
|
2872
2888
|
{
|
|
2873
2889
|
"aria-label": "Tree view mode",
|
|
@@ -2881,13 +2897,13 @@ function GenreTreeView({
|
|
|
2881
2897
|
]
|
|
2882
2898
|
}
|
|
2883
2899
|
),
|
|
2884
|
-
!isLoading && !isError && showDisplayOptions && /* @__PURE__ */
|
|
2900
|
+
!isLoading && !isError && showDisplayOptions && /* @__PURE__ */ jsx40(
|
|
2885
2901
|
"div",
|
|
2886
2902
|
{
|
|
2887
2903
|
className: "flex items-center gap-1",
|
|
2888
2904
|
role: "group",
|
|
2889
2905
|
"aria-label": "Tree display options",
|
|
2890
|
-
children: !isRotationControlled && viewMode !== "stacked" && viewMode !== "outline" && /* @__PURE__ */
|
|
2906
|
+
children: !isRotationControlled && viewMode !== "stacked" && viewMode !== "outline" && /* @__PURE__ */ jsx40(
|
|
2891
2907
|
Button,
|
|
2892
2908
|
{
|
|
2893
2909
|
variant: allowWheelRotation ? "default" : "outline",
|
|
@@ -2898,7 +2914,7 @@ function GenreTreeView({
|
|
|
2898
2914
|
)
|
|
2899
2915
|
}
|
|
2900
2916
|
),
|
|
2901
|
-
!isLoading && !isError && !readOnly && showAddRoot && /* @__PURE__ */
|
|
2917
|
+
!isLoading && !isError && !readOnly && showAddRoot && /* @__PURE__ */ jsx40(
|
|
2902
2918
|
IconTextButton,
|
|
2903
2919
|
{
|
|
2904
2920
|
icon: Plus2,
|
|
@@ -2914,32 +2930,32 @@ function GenreTreeView({
|
|
|
2914
2930
|
"data-left-panel": isPanelShown && !isCollapsed ? void 0 : "hidden",
|
|
2915
2931
|
className: ["genre-tree-view relative flex flex-col h-full", placement === "regions" && REGIONS_CLASS, className2].filter(Boolean).join(" "),
|
|
2916
2932
|
children: [
|
|
2917
|
-
/* @__PURE__ */
|
|
2933
|
+
/* @__PURE__ */ jsx40(
|
|
2918
2934
|
"div",
|
|
2919
2935
|
{
|
|
2920
2936
|
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"}`,
|
|
2921
2937
|
children: actions
|
|
2922
2938
|
}
|
|
2923
2939
|
),
|
|
2924
|
-
!isLoading && !isError && filterArtist && /* @__PURE__ */
|
|
2940
|
+
!isLoading && !isError && filterArtist && /* @__PURE__ */ jsx40(
|
|
2925
2941
|
"div",
|
|
2926
2942
|
{
|
|
2927
2943
|
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"}`,
|
|
2928
2944
|
children: renderArtistFilter()
|
|
2929
2945
|
}
|
|
2930
2946
|
),
|
|
2931
|
-
/* @__PURE__ */
|
|
2932
|
-
!isLoading && !isError && viewMode === "outline" && floatingControlsLeading && /* @__PURE__ */
|
|
2933
|
-
isLoading ? /* @__PURE__ */
|
|
2947
|
+
/* @__PURE__ */ jsx40("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: [
|
|
2948
|
+
!isLoading && !isError && viewMode === "outline" && floatingControlsLeading && /* @__PURE__ */ jsx40("div", { className: "absolute bottom-3 right-3 z-10", children: floatingControlsLeading }),
|
|
2949
|
+
isLoading ? /* @__PURE__ */ jsx40(GenreTreeViewSkeleton, { viewMode }) : isError ? /* @__PURE__ */ jsxs27("p", { role: "alert", className: "m-auto text-center", children: [
|
|
2934
2950
|
"Couldn't load the genre tree.",
|
|
2935
2951
|
" ",
|
|
2936
|
-
/* @__PURE__ */
|
|
2952
|
+
/* @__PURE__ */ jsx40("button", { type: "button", className: "underline", onClick: refetch, children: "Retry" })
|
|
2937
2953
|
] }) : viewMode === "wheel" ? (
|
|
2938
2954
|
// The info panel's top edge aligns with the tree's; the search bar floats `--layout-panel-inset` below it,
|
|
2939
2955
|
// and the header inset (the bar's height plus that inset) extends the header's fill behind the bar,
|
|
2940
2956
|
// Google Maps style; the 8px bottom padding mirrors the inset above the bar, and the hidden title's height is zeroed.
|
|
2941
2957
|
// The panel's own Zoom in button is hidden: the search bar carries it.
|
|
2942
|
-
/* @__PURE__ */
|
|
2958
|
+
/* @__PURE__ */ jsx40("div", { className: "tree-container search-overlay relative flex-1 w-full min-h-0 ", children: /* @__PURE__ */ jsx40(GenreTreeWheelHandoff, { skeleton: /* @__PURE__ */ jsx40(GenreTreeWheelSkeleton, {}), onRevealedChange: setIsWheelRevealed, children: /* @__PURE__ */ jsx40(
|
|
2943
2959
|
GenrePlaylistTreeWheel,
|
|
2944
2960
|
{
|
|
2945
2961
|
scope,
|
|
@@ -2959,7 +2975,7 @@ function GenreTreeView({
|
|
|
2959
2975
|
busy,
|
|
2960
2976
|
floatingControlsLeading: floatingControlsLeading || canSizeByViews ? /* @__PURE__ */ jsxs27("div", { className: "flex items-center gap-2", children: [
|
|
2961
2977
|
floatingControlsLeading,
|
|
2962
|
-
canSizeByViews && /* @__PURE__ */
|
|
2978
|
+
canSizeByViews && /* @__PURE__ */ jsx40(SizeMetricToggle, { value: sizeMetric, onChange: changeSizeMetric })
|
|
2963
2979
|
] }) : void 0,
|
|
2964
2980
|
defaultViewport,
|
|
2965
2981
|
viewportRestore,
|
|
@@ -2968,7 +2984,7 @@ function GenreTreeView({
|
|
|
2968
2984
|
) }) })
|
|
2969
2985
|
) : viewMode === "pop-core" ? (
|
|
2970
2986
|
// Same as the wheel: the header inset extends its fill behind the floating search bar, Google Maps style.
|
|
2971
|
-
/* @__PURE__ */
|
|
2987
|
+
/* @__PURE__ */ jsx40("div", { className: "tree-container search-overlay relative flex-1 w-full min-h-0 ", children: /* @__PURE__ */ jsx40(GenreTreeWheelHandoff, { skeleton: /* @__PURE__ */ jsx40(GenreTreeWheelSkeleton, {}), onRevealedChange: setIsWheelRevealed, children: /* @__PURE__ */ jsx40(
|
|
2972
2988
|
GenrePlaylistTreeWheelRadialPopCore,
|
|
2973
2989
|
{
|
|
2974
2990
|
scope,
|
|
@@ -2988,7 +3004,7 @@ function GenreTreeView({
|
|
|
2988
3004
|
busy,
|
|
2989
3005
|
floatingControlsLeading: floatingControlsLeading || canSizeByViews ? /* @__PURE__ */ jsxs27("div", { className: "flex items-center gap-2", children: [
|
|
2990
3006
|
floatingControlsLeading,
|
|
2991
|
-
canSizeByViews && /* @__PURE__ */
|
|
3007
|
+
canSizeByViews && /* @__PURE__ */ jsx40(SizeMetricToggle, { value: sizeMetric, onChange: changeSizeMetric })
|
|
2992
3008
|
] }) : void 0,
|
|
2993
3009
|
defaultViewport,
|
|
2994
3010
|
viewportRestore,
|
|
@@ -2996,7 +3012,7 @@ function GenreTreeView({
|
|
|
2996
3012
|
...focus
|
|
2997
3013
|
}
|
|
2998
3014
|
) }) })
|
|
2999
|
-
) : viewMode === "outline" ? /* @__PURE__ */
|
|
3015
|
+
) : viewMode === "outline" ? /* @__PURE__ */ jsx40("div", { className: "tree-container flex-1 min-h-0 w-full overflow-y-auto relative", children: /* @__PURE__ */ jsx40(
|
|
3000
3016
|
GenrePlaylistTreeWheelRadialPopCore,
|
|
3001
3017
|
{
|
|
3002
3018
|
outline: true,
|
|
@@ -3013,13 +3029,13 @@ function GenreTreeView({
|
|
|
3013
3029
|
selectedNodeId,
|
|
3014
3030
|
readOnly
|
|
3015
3031
|
}
|
|
3016
|
-
) }) : /* @__PURE__ */
|
|
3032
|
+
) }) : /* @__PURE__ */ jsx40("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(
|
|
3017
3033
|
([uuid, genrePlaylistTreePerRoot]) => {
|
|
3018
|
-
return /* @__PURE__ */
|
|
3034
|
+
return /* @__PURE__ */ jsx40(
|
|
3019
3035
|
"div",
|
|
3020
3036
|
{
|
|
3021
3037
|
className: "tree-per-root-container relative shrink-0 h-[28rem] mt-2 mr-16 p-2 bg-[var(--color-neutral-100)] rounded-lg",
|
|
3022
|
-
children: /* @__PURE__ */
|
|
3038
|
+
children: /* @__PURE__ */ jsx40("div", { className: "graph-container relative z-10 h-full", children: /* @__PURE__ */ jsx40(
|
|
3023
3039
|
GenrePlaylistTreePerRoot,
|
|
3024
3040
|
{
|
|
3025
3041
|
scope,
|
|
@@ -3046,7 +3062,7 @@ function GenreTreeView({
|
|
|
3046
3062
|
);
|
|
3047
3063
|
}
|
|
3048
3064
|
) }),
|
|
3049
|
-
/* @__PURE__ */
|
|
3065
|
+
/* @__PURE__ */ jsx40(
|
|
3050
3066
|
DetailPanel2,
|
|
3051
3067
|
{
|
|
3052
3068
|
ref: panelRef,
|
|
@@ -3087,7 +3103,7 @@ import { ListMusic } from "lucide-react";
|
|
|
3087
3103
|
import { useTrackList as useTrackList7 } from "@behindthemusictree/app-kit/genre-tree";
|
|
3088
3104
|
import { TrackListOriginType as TrackListOriginType3 } from "@behindthemusictree/app-kit/genre-tree";
|
|
3089
3105
|
import { useTrackNoun as useTrackNoun3 } from "@behindthemusictree/app-kit/track-noun";
|
|
3090
|
-
import { jsx as
|
|
3106
|
+
import { jsx as jsx41, jsxs as jsxs28 } from "react/jsx-runtime";
|
|
3091
3107
|
var useBrowserLayoutEffect = typeof window === "undefined" ? useEffect7 : useLayoutEffect2;
|
|
3092
3108
|
function TrackListSidebar({
|
|
3093
3109
|
className: className2 = "",
|
|
@@ -3199,15 +3215,15 @@ function TrackListSidebar({
|
|
|
3199
3215
|
/* @__PURE__ */ jsxs28("div", { className: "header flex h-16 items-center px-4 py-2 text-[var(--color-text)]", children: [
|
|
3200
3216
|
/* @__PURE__ */ jsxs28("div", { className: "min-w-0 flex flex-1 flex-col justify-center", children: [
|
|
3201
3217
|
/* @__PURE__ */ jsxs28("div", { className: "origin flex text-xl", children: [
|
|
3202
|
-
/* @__PURE__ */
|
|
3203
|
-
/* @__PURE__ */
|
|
3218
|
+
/* @__PURE__ */ jsx41("div", { className: "from h-auto flex flex-col justify-center items-center mr-2", children: "From" }),
|
|
3219
|
+
/* @__PURE__ */ jsx41("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__ */ jsx41("div", { className: "name max-w-full truncate", children: trackList.origin.label }) })
|
|
3204
3220
|
] }),
|
|
3205
3221
|
/* @__PURE__ */ jsxs28("div", { className: "info flex items-center text-body text-[var(--color-text-muted)]", children: [
|
|
3206
3222
|
trackList.origin.type === TrackListOriginType3.GENRE_PLAYLIST ? "Genre \u2022 " : trackList.origin.type === TrackListOriginType3.ARTIST ? "Artist \u2022 " : `${trackNoun.singular} playlist \u2022 `,
|
|
3207
3223
|
`${trackList.total} ${trackList.total > 1 ? trackNoun.plural : trackNoun.singular}`
|
|
3208
3224
|
] })
|
|
3209
3225
|
] }),
|
|
3210
|
-
(isCollapsed && onExpand || !isCollapsed && onMinimize) && /* @__PURE__ */
|
|
3226
|
+
(isCollapsed && onExpand || !isCollapsed && onMinimize) && /* @__PURE__ */ jsx41(
|
|
3211
3227
|
"button",
|
|
3212
3228
|
{
|
|
3213
3229
|
type: "button",
|
|
@@ -3216,7 +3232,7 @@ function TrackListSidebar({
|
|
|
3216
3232
|
"aria-expanded": !isCollapsed,
|
|
3217
3233
|
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"}`,
|
|
3218
3234
|
onClick: isCollapsed ? onExpand : onMinimize,
|
|
3219
|
-
children: /* @__PURE__ */
|
|
3235
|
+
children: /* @__PURE__ */ jsx41(ListMusic, { "aria-hidden": "true", className: "h-5 w-5" })
|
|
3220
3236
|
}
|
|
3221
3237
|
)
|
|
3222
3238
|
] }),
|
|
@@ -3230,7 +3246,7 @@ function TrackListSidebar({
|
|
|
3230
3246
|
onPointerDown: markUserScrollIntent,
|
|
3231
3247
|
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",
|
|
3232
3248
|
children: [
|
|
3233
|
-
trackList.tracks.map((track, index) => /* @__PURE__ */
|
|
3249
|
+
trackList.tracks.map((track, index) => /* @__PURE__ */ jsx41("li", { "data-track-uuid": track.uuid, children: /* @__PURE__ */ jsx41(
|
|
3234
3250
|
TrackItem,
|
|
3235
3251
|
{
|
|
3236
3252
|
track,
|
|
@@ -3241,7 +3257,7 @@ function TrackListSidebar({
|
|
|
3241
3257
|
renderSongLink
|
|
3242
3258
|
}
|
|
3243
3259
|
) }, track.uuid)),
|
|
3244
|
-
hasMore && /* @__PURE__ */
|
|
3260
|
+
hasMore && /* @__PURE__ */ jsx41("li", { ref: loadMoreSentinelRef, "aria-hidden": "true", className: "h-px" })
|
|
3245
3261
|
]
|
|
3246
3262
|
}
|
|
3247
3263
|
)
|
|
@@ -3263,10 +3279,10 @@ import {
|
|
|
3263
3279
|
import { PanelEdgeTab } from "@behindthemusictree/ui";
|
|
3264
3280
|
|
|
3265
3281
|
// src/genre-tree/PlayerControls.tsx
|
|
3266
|
-
import { Pause as Pause4, Play as
|
|
3282
|
+
import { Pause as Pause4, Play as Play4, SkipBack, SkipForward, Volume2, VolumeX } from "lucide-react";
|
|
3267
3283
|
import { formatTime, useTrackList as useTrackList8 } from "@behindthemusictree/app-kit/genre-tree";
|
|
3268
3284
|
import { PlayStates as PlayStates4, useCurrentTime, usePlayer as usePlayer11 } from "@behindthemusictree/app-kit/player";
|
|
3269
|
-
import { jsx as
|
|
3285
|
+
import { jsx as jsx42, jsxs as jsxs29 } from "react/jsx-runtime";
|
|
3270
3286
|
function PlayerControls() {
|
|
3271
3287
|
const {
|
|
3272
3288
|
duration,
|
|
@@ -3292,8 +3308,8 @@ function PlayerControls() {
|
|
|
3292
3308
|
className: "player-controls flex shrink-0 flex-col gap-2 border-b border-zinc-800 px-3 py-2 text-zinc-200",
|
|
3293
3309
|
children: [
|
|
3294
3310
|
/* @__PURE__ */ jsxs29("div", { className: "flex min-w-0 items-center gap-2 text-xs tabular-nums text-zinc-400", children: [
|
|
3295
|
-
/* @__PURE__ */
|
|
3296
|
-
/* @__PURE__ */
|
|
3311
|
+
/* @__PURE__ */ jsx42("span", { "aria-label": "Elapsed time", children: formatTime(safeCurrentTime) }),
|
|
3312
|
+
/* @__PURE__ */ jsx42(
|
|
3297
3313
|
"input",
|
|
3298
3314
|
{
|
|
3299
3315
|
"aria-label": "Seek",
|
|
@@ -3307,11 +3323,11 @@ function PlayerControls() {
|
|
|
3307
3323
|
onChange: (event) => seekTo(Number(event.currentTarget.value))
|
|
3308
3324
|
}
|
|
3309
3325
|
),
|
|
3310
|
-
/* @__PURE__ */
|
|
3326
|
+
/* @__PURE__ */ jsx42("span", { "aria-label": "Duration", children: formatTime(safeDuration) })
|
|
3311
3327
|
] }),
|
|
3312
3328
|
/* @__PURE__ */ jsxs29("div", { className: "grid min-h-9 grid-cols-[1fr_auto_1fr] items-center gap-3", children: [
|
|
3313
3329
|
/* @__PURE__ */ jsxs29("div", { className: "col-start-2 flex items-center justify-center gap-2", children: [
|
|
3314
|
-
/* @__PURE__ */
|
|
3330
|
+
/* @__PURE__ */ jsx42(
|
|
3315
3331
|
"button",
|
|
3316
3332
|
{
|
|
3317
3333
|
type: "button",
|
|
@@ -3320,10 +3336,10 @@ function PlayerControls() {
|
|
|
3320
3336
|
disabled: !isReady || !hasPreviousTrack,
|
|
3321
3337
|
onClick: playPreviousTrack,
|
|
3322
3338
|
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",
|
|
3323
|
-
children: /* @__PURE__ */
|
|
3339
|
+
children: /* @__PURE__ */ jsx42(SkipBack, { "aria-hidden": "true", className: "h-4 w-4" })
|
|
3324
3340
|
}
|
|
3325
3341
|
),
|
|
3326
|
-
/* @__PURE__ */
|
|
3342
|
+
/* @__PURE__ */ jsx42(
|
|
3327
3343
|
"button",
|
|
3328
3344
|
{
|
|
3329
3345
|
type: "button",
|
|
@@ -3332,10 +3348,10 @@ function PlayerControls() {
|
|
|
3332
3348
|
disabled: !isReady,
|
|
3333
3349
|
onClick: handlePlayPauseAction,
|
|
3334
3350
|
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",
|
|
3335
|
-
children: isPlaying ? /* @__PURE__ */
|
|
3351
|
+
children: isPlaying ? /* @__PURE__ */ jsx42(Pause4, { "aria-hidden": "true", className: "h-4 w-4", fill: "currentColor" }) : /* @__PURE__ */ jsx42(Play4, { "aria-hidden": "true", className: "h-4 w-4", fill: "currentColor" })
|
|
3336
3352
|
}
|
|
3337
3353
|
),
|
|
3338
|
-
/* @__PURE__ */
|
|
3354
|
+
/* @__PURE__ */ jsx42(
|
|
3339
3355
|
"button",
|
|
3340
3356
|
{
|
|
3341
3357
|
type: "button",
|
|
@@ -3344,14 +3360,14 @@ function PlayerControls() {
|
|
|
3344
3360
|
disabled: !isReady || !hasNextTrack,
|
|
3345
3361
|
onClick: playNextTrack,
|
|
3346
3362
|
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",
|
|
3347
|
-
children: /* @__PURE__ */
|
|
3363
|
+
children: /* @__PURE__ */ jsx42(SkipForward, { "aria-hidden": "true", className: "h-4 w-4" })
|
|
3348
3364
|
}
|
|
3349
3365
|
)
|
|
3350
3366
|
] }),
|
|
3351
3367
|
/* @__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: [
|
|
3352
|
-
volume === 0 ? /* @__PURE__ */
|
|
3353
|
-
/* @__PURE__ */
|
|
3354
|
-
/* @__PURE__ */
|
|
3368
|
+
volume === 0 ? /* @__PURE__ */ jsx42(VolumeX, { "aria-hidden": "true", className: "h-[0.7rem] w-[0.7rem] shrink-0" }) : /* @__PURE__ */ jsx42(Volume2, { "aria-hidden": "true", className: "h-[0.7rem] w-[0.7rem] shrink-0" }),
|
|
3369
|
+
/* @__PURE__ */ jsx42("span", { className: "sr-only", children: "Volume" }),
|
|
3370
|
+
/* @__PURE__ */ jsx42(
|
|
3355
3371
|
"input",
|
|
3356
3372
|
{
|
|
3357
3373
|
"aria-label": "Volume",
|
|
@@ -3373,7 +3389,7 @@ function PlayerControls() {
|
|
|
3373
3389
|
}
|
|
3374
3390
|
|
|
3375
3391
|
// src/genre-tree/PlayerPanel.tsx
|
|
3376
|
-
import { jsx as
|
|
3392
|
+
import { jsx as jsx43, jsxs as jsxs30 } from "react/jsx-runtime";
|
|
3377
3393
|
var PANEL_ID = "player-panel";
|
|
3378
3394
|
var DEFAULT_EXTENDED_WIDTH = "calc(100vw - var(--layout-center-left) - var(--layout-gutter))";
|
|
3379
3395
|
function PlayerPanel({
|
|
@@ -3426,7 +3442,7 @@ function PlayerPanel({
|
|
|
3426
3442
|
),
|
|
3427
3443
|
style: isExtended ? { width: extendedWidth } : void 0,
|
|
3428
3444
|
children: [
|
|
3429
|
-
/* @__PURE__ */
|
|
3445
|
+
/* @__PURE__ */ jsx43(
|
|
3430
3446
|
PanelEdgeTab,
|
|
3431
3447
|
{
|
|
3432
3448
|
side: "right",
|
|
@@ -3445,19 +3461,19 @@ function PlayerPanel({
|
|
|
3445
3461
|
),
|
|
3446
3462
|
children: [
|
|
3447
3463
|
/* @__PURE__ */ jsxs30("div", { className: "flex w-[var(--layout-right-w)] shrink-0 flex-col", children: [
|
|
3448
|
-
/* @__PURE__ */
|
|
3464
|
+
/* @__PURE__ */ jsx43("div", { className: "flex shrink-0 items-center justify-between gap-2 border-b border-zinc-800 p-2", children: /* @__PURE__ */ jsx43("span", { className: "min-w-0 truncate text-sm font-semibold", children: loadedTrackTitle || lastLoadedTrackTitle }) }),
|
|
3449
3465
|
/* @__PURE__ */ jsxs30("div", { className: "relative w-full shrink-0", children: [
|
|
3450
|
-
/* @__PURE__ */
|
|
3466
|
+
/* @__PURE__ */ jsx43(PlayerVideoSurface, { className: "aspect-video w-full bg-black" }),
|
|
3451
3467
|
playerTrackObject?.loadError && /* @__PURE__ */ jsxs30("span", { className: "absolute bottom-2 left-2 right-2 text-xs text-red-400", children: [
|
|
3452
3468
|
playerTrackObject.loadError,
|
|
3453
|
-
/* @__PURE__ */
|
|
3469
|
+
/* @__PURE__ */ jsx43("button", { type: "button", className: "ml-2 underline", onClick: () => {
|
|
3454
3470
|
void retryPlayback();
|
|
3455
3471
|
}, children: "Retry" })
|
|
3456
3472
|
] })
|
|
3457
3473
|
] }),
|
|
3458
|
-
/* @__PURE__ */
|
|
3474
|
+
/* @__PURE__ */ jsx43(PlayerControls, {})
|
|
3459
3475
|
] }),
|
|
3460
|
-
/* @__PURE__ */
|
|
3476
|
+
/* @__PURE__ */ jsx43(
|
|
3461
3477
|
TrackListSidebar,
|
|
3462
3478
|
{
|
|
3463
3479
|
layout: "inline",
|
|
@@ -3484,11 +3500,11 @@ function PlayerPanel({
|
|
|
3484
3500
|
import { v4 as uuidv4 } from "uuid";
|
|
3485
3501
|
import { AiFillStar, AiOutlineStar } from "react-icons/ai";
|
|
3486
3502
|
import { FORM_RATING_NULL_VALUE } from "@behindthemusictree/app-kit/genre-tree";
|
|
3487
|
-
import { jsx as
|
|
3503
|
+
import { jsx as jsx44, jsxs as jsxs31 } from "react/jsx-runtime";
|
|
3488
3504
|
function Rating({ rating, handleChange }) {
|
|
3489
3505
|
const instanceId = uuidv4();
|
|
3490
|
-
return /* @__PURE__ */
|
|
3491
|
-
/* @__PURE__ */
|
|
3506
|
+
return /* @__PURE__ */ jsx44("div", { className: "flex items-center", children: [...Array(6)].map((_, i) => /* @__PURE__ */ jsxs31("div", { className: `relative ${i === 0 ? "mr-4" : "mr-1"}`, children: [
|
|
3507
|
+
/* @__PURE__ */ jsx44(
|
|
3492
3508
|
"input",
|
|
3493
3509
|
{
|
|
3494
3510
|
id: `star-${instanceId}-${i}`,
|
|
@@ -3500,16 +3516,16 @@ function Rating({ rating, handleChange }) {
|
|
|
3500
3516
|
onChange: handleChange
|
|
3501
3517
|
}
|
|
3502
3518
|
),
|
|
3503
|
-
/* @__PURE__ */
|
|
3504
|
-
/* @__PURE__ */
|
|
3519
|
+
/* @__PURE__ */ jsx44("label", { htmlFor: `star-${instanceId}-${i}`, className: "cursor-pointer", children: i === 0 ? /* @__PURE__ */ jsxs31("div", { className: "flex", children: [
|
|
3520
|
+
/* @__PURE__ */ jsx44(
|
|
3505
3521
|
AiOutlineStar,
|
|
3506
3522
|
{
|
|
3507
3523
|
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)]"}`
|
|
3508
3524
|
}
|
|
3509
3525
|
),
|
|
3510
|
-
/* @__PURE__ */
|
|
3526
|
+
/* @__PURE__ */ jsx44("span", { className: "flex-grow w-8" }),
|
|
3511
3527
|
" "
|
|
3512
|
-
] }) : /* @__PURE__ */
|
|
3528
|
+
] }) : /* @__PURE__ */ jsx44(
|
|
3513
3529
|
AiFillStar,
|
|
3514
3530
|
{
|
|
3515
3531
|
className: `w-7 h-7 absolute top-0 left-0 ${(rating ?? -1) >= i ? "text-[var(--color-accent-rating)]" : "text-[var(--color-text-muted)]"}`
|
|
@@ -3521,7 +3537,7 @@ function Rating({ rating, handleChange }) {
|
|
|
3521
3537
|
// src/genre-tree/EntityDetailPanel.tsx
|
|
3522
3538
|
import { useState as useState12 } from "react";
|
|
3523
3539
|
import { DetailPanel as DetailPanel3 } from "@behindthemusictree/ui";
|
|
3524
|
-
import { Fragment as Fragment16, jsx as
|
|
3540
|
+
import { Fragment as Fragment16, jsx as jsx45, jsxs as jsxs32 } from "react/jsx-runtime";
|
|
3525
3541
|
function EntityDetailPanel({
|
|
3526
3542
|
scope,
|
|
3527
3543
|
getBackendBaseUrl,
|
|
@@ -3544,8 +3560,8 @@ function EntityDetailPanel({
|
|
|
3544
3560
|
getBackendBaseUrl,
|
|
3545
3561
|
getArtistBackendBaseUrl,
|
|
3546
3562
|
getShareUrl,
|
|
3547
|
-
renderArtistLink: renderArtistLink ?? ((artist) => artist.isSpecialPurpose ? artist.name : /* @__PURE__ */
|
|
3548
|
-
renderSongLink: renderSongLink ?? ((song) => /* @__PURE__ */
|
|
3563
|
+
renderArtistLink: renderArtistLink ?? ((artist) => artist.isSpecialPurpose ? artist.name : /* @__PURE__ */ jsx45("button", { type: "button", onClick: () => onArtistUuidChange(artist.uuid), className: "hover:underline", children: artist.name })),
|
|
3564
|
+
renderSongLink: renderSongLink ?? ((song) => /* @__PURE__ */ jsx45("button", { type: "button", onClick: () => onSongUuidChange(song.uuid), className: "hover:underline", children: song.title })),
|
|
3549
3565
|
song: {
|
|
3550
3566
|
uuid: songUuid,
|
|
3551
3567
|
expanded: songUuid !== null && expandedSongUuid === songUuid,
|
|
@@ -3561,7 +3577,7 @@ function EntityDetailPanel({
|
|
|
3561
3577
|
...navigation
|
|
3562
3578
|
});
|
|
3563
3579
|
if (!panel) return null;
|
|
3564
|
-
return /* @__PURE__ */
|
|
3580
|
+
return /* @__PURE__ */ jsx45(
|
|
3565
3581
|
DetailPanel3,
|
|
3566
3582
|
{
|
|
3567
3583
|
side: "left",
|
|
@@ -3607,4 +3623,4 @@ export {
|
|
|
3607
3623
|
GenreTreeViewSkeleton2 as GenreTreeViewSkeleton,
|
|
3608
3624
|
GenreTreeOutlineSkeleton
|
|
3609
3625
|
};
|
|
3610
|
-
//# sourceMappingURL=chunk-
|
|
3626
|
+
//# sourceMappingURL=chunk-GR4PCPCU.js.map
|