@behindthemusictree/app-kit-ui 40.1.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-DPYUE6WD.js → chunk-GR4PCPCU.js} +260 -238
- package/dist/chunk-GR4PCPCU.js.map +1 -0
- package/dist/genre-tree/index.cjs +307 -287
- 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 +307 -287
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +1 -1
- package/package.json +3 -3
- package/dist/chunk-DPYUE6WD.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
|
|
|
@@ -1160,6 +1163,29 @@ function ClampedText({ children, className: className2 = "" }) {
|
|
|
1160
1163
|
] });
|
|
1161
1164
|
}
|
|
1162
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
|
+
|
|
1163
1189
|
// src/genre-tree/GenrePlaylistTracks.tsx
|
|
1164
1190
|
import { useEffect as useEffect4, useState as useState7 } from "react";
|
|
1165
1191
|
import { useInfiniteQuery } from "@tanstack/react-query";
|
|
@@ -1182,15 +1208,15 @@ import { TracksFailureAlreadyReportedError as TracksFailureAlreadyReportedError2
|
|
|
1182
1208
|
|
|
1183
1209
|
// src/genre-tree/MusicBrainzRecordingLink.tsx
|
|
1184
1210
|
import { musicBrainzRecordingUrl } from "@behindthemusictree/app-kit/genre-tree";
|
|
1185
|
-
import { Fragment as Fragment8, jsx as
|
|
1211
|
+
import { Fragment as Fragment8, jsx as jsx21 } from "react/jsx-runtime";
|
|
1186
1212
|
function MusicBrainzRecordingLink({
|
|
1187
1213
|
song,
|
|
1188
1214
|
children,
|
|
1189
1215
|
className: className2 = ""
|
|
1190
1216
|
}) {
|
|
1191
1217
|
const url = musicBrainzRecordingUrl(song);
|
|
1192
|
-
if (!url) return /* @__PURE__ */
|
|
1193
|
-
return /* @__PURE__ */
|
|
1218
|
+
if (!url) return /* @__PURE__ */ jsx21(Fragment8, { children });
|
|
1219
|
+
return /* @__PURE__ */ jsx21(
|
|
1194
1220
|
"a",
|
|
1195
1221
|
{
|
|
1196
1222
|
href: url,
|
|
@@ -1207,7 +1233,7 @@ function MusicBrainzRecordingLink({
|
|
|
1207
1233
|
// src/genre-tree/GenrePlaylistTracks.tsx
|
|
1208
1234
|
import { ArtistNames } from "@behindthemusictree/app-kit/genre-tree";
|
|
1209
1235
|
import { capitalize, useTrackNoun } from "@behindthemusictree/app-kit/track-noun";
|
|
1210
|
-
import { jsx as
|
|
1236
|
+
import { jsx as jsx22, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
1211
1237
|
var CATALOGUE_PAGE_SIZE = 100;
|
|
1212
1238
|
var SongPageSchema = PaginatedResponseSchema(SongDetailedSchema).extend({
|
|
1213
1239
|
overallTotal: z.number().nullable(),
|
|
@@ -1294,35 +1320,35 @@ function GenrePlaylistTracks({
|
|
|
1294
1320
|
started.catch((error) => {
|
|
1295
1321
|
console.error("Failed to play genre playlist:", error);
|
|
1296
1322
|
if (error instanceof TracksFailureAlreadyReportedError2) return;
|
|
1297
|
-
showPopup(/* @__PURE__ */
|
|
1323
|
+
showPopup(/* @__PURE__ */ jsx22(InternalErrorPopup, { errorCode: error instanceof AppError2 ? error.code : ErrorCode2.CLIENT_UNKNOWN }));
|
|
1298
1324
|
});
|
|
1299
1325
|
};
|
|
1300
|
-
return /* @__PURE__ */
|
|
1326
|
+
return /* @__PURE__ */ jsx22(PanelSection, { title: `${capitalize(trackNoun.plural)}${total !== void 0 ? ` (${total})` : ""}`, children: /* @__PURE__ */ jsxs13("div", { children: [
|
|
1301
1327
|
renderTracksToolbar?.(),
|
|
1302
|
-
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: [
|
|
1303
1329
|
"Couldn't load ",
|
|
1304
1330
|
trackNoun.plural,
|
|
1305
1331
|
".",
|
|
1306
1332
|
" ",
|
|
1307
|
-
/* @__PURE__ */
|
|
1308
|
-
] }) : 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: [
|
|
1309
1335
|
tracks.map((track, index) => {
|
|
1310
1336
|
const label = track.artists?.length ? `${track.title} \u2014 ${track.artists.map((artist2) => artist2.name).join(", ")}` : track.title;
|
|
1311
1337
|
const isCurrent = playerTrackObject?.track.id === track.uuid;
|
|
1312
1338
|
const isPlaying = isCurrent && playState === PlayStates.PLAYING;
|
|
1313
|
-
const text = /* @__PURE__ */
|
|
1314
|
-
/* @__PURE__ */
|
|
1315
|
-
track.artists?.length ? /* @__PURE__ */
|
|
1316
|
-
/* @__PURE__ */
|
|
1317
|
-
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 })
|
|
1318
1344
|
] });
|
|
1319
1345
|
const leading = renderSongLeading?.(track, index);
|
|
1320
1346
|
const actions = renderSongActions?.(track);
|
|
1321
1347
|
const isUnplayable = isSong(track) && songUnplayableReason(track) !== null;
|
|
1322
1348
|
if (isUnplayable) {
|
|
1323
|
-
return /* @__PURE__ */
|
|
1349
|
+
return /* @__PURE__ */ jsxs13("li", { className: "flex min-h-8 items-center gap-1 px-1 opacity-50", children: [
|
|
1324
1350
|
leading,
|
|
1325
|
-
/* @__PURE__ */
|
|
1351
|
+
/* @__PURE__ */ jsx22(
|
|
1326
1352
|
"button",
|
|
1327
1353
|
{
|
|
1328
1354
|
type: "button",
|
|
@@ -1330,27 +1356,27 @@ function GenrePlaylistTracks({
|
|
|
1330
1356
|
"aria-disabled": "true",
|
|
1331
1357
|
"aria-label": label,
|
|
1332
1358
|
className: "flex h-6 w-6 shrink-0 items-center justify-center rounded-full opacity-0 cursor-not-allowed",
|
|
1333
|
-
children: /* @__PURE__ */
|
|
1359
|
+
children: /* @__PURE__ */ jsx22(FaPlay, { size: 10 })
|
|
1334
1360
|
}
|
|
1335
1361
|
),
|
|
1336
1362
|
text,
|
|
1337
1363
|
actions
|
|
1338
1364
|
] }, track.uuid);
|
|
1339
1365
|
}
|
|
1340
|
-
return /* @__PURE__ */
|
|
1366
|
+
return /* @__PURE__ */ jsxs13(
|
|
1341
1367
|
"li",
|
|
1342
1368
|
{
|
|
1343
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)]" : ""}`,
|
|
1344
1370
|
children: [
|
|
1345
1371
|
leading,
|
|
1346
|
-
/* @__PURE__ */
|
|
1372
|
+
/* @__PURE__ */ jsx22(
|
|
1347
1373
|
"button",
|
|
1348
1374
|
{
|
|
1349
1375
|
type: "button",
|
|
1350
1376
|
"aria-label": `${isPlaying ? "Pause" : "Play"} ${label}`,
|
|
1351
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"}`,
|
|
1352
1378
|
onClick: () => isCurrent ? handlePlayPauseAction() : play(track.uuid),
|
|
1353
|
-
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 })
|
|
1354
1380
|
}
|
|
1355
1381
|
),
|
|
1356
1382
|
text,
|
|
@@ -1360,7 +1386,7 @@ function GenrePlaylistTracks({
|
|
|
1360
1386
|
track.uuid
|
|
1361
1387
|
);
|
|
1362
1388
|
}),
|
|
1363
|
-
hasNextPage && /* @__PURE__ */
|
|
1389
|
+
hasNextPage && /* @__PURE__ */ jsx22("li", { ref: setSentinel, "aria-hidden": "true", className: "h-4" })
|
|
1364
1390
|
] })
|
|
1365
1391
|
] }) });
|
|
1366
1392
|
}
|
|
@@ -1368,7 +1394,7 @@ function GenrePlaylistTracks({
|
|
|
1368
1394
|
// src/genre-tree/GenreDetailExtras.tsx
|
|
1369
1395
|
import { useTrackNoun as useTrackNoun2 } from "@behindthemusictree/app-kit/track-noun";
|
|
1370
1396
|
import { SiWikidata, SiWikipedia } from "react-icons/si";
|
|
1371
|
-
import { Fragment as Fragment9, jsx as
|
|
1397
|
+
import { Fragment as Fragment9, jsx as jsx23, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
1372
1398
|
function GenreDetailExtras({
|
|
1373
1399
|
genreUuid,
|
|
1374
1400
|
genrePlaylist,
|
|
@@ -1394,17 +1420,18 @@ function GenreDetailExtras({
|
|
|
1394
1420
|
criteriaOverviewSchema
|
|
1395
1421
|
);
|
|
1396
1422
|
if (isPending) {
|
|
1397
|
-
return /* @__PURE__ */
|
|
1398
|
-
/* @__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" }) }) }),
|
|
1399
1425
|
family
|
|
1400
1426
|
] });
|
|
1401
1427
|
}
|
|
1402
|
-
if (!overview) return /* @__PURE__ */
|
|
1403
|
-
const { summary, summarySourceUrl, essentialSongs } = overview;
|
|
1428
|
+
if (!overview) return /* @__PURE__ */ jsx23(Fragment9, { children: family });
|
|
1429
|
+
const { summary, summarySourceUrl, essentialSongs, image } = overview;
|
|
1404
1430
|
const wikidataUrl = wikidataId ? `https://www.wikidata.org/wiki/${encodeURIComponent(wikidataId)}` : null;
|
|
1405
|
-
return /* @__PURE__ */
|
|
1406
|
-
|
|
1407
|
-
|
|
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(
|
|
1408
1435
|
"a",
|
|
1409
1436
|
{
|
|
1410
1437
|
href: summarySourceUrl,
|
|
@@ -1412,12 +1439,12 @@ function GenreDetailExtras({
|
|
|
1412
1439
|
rel: "noopener noreferrer",
|
|
1413
1440
|
className: "inline-flex items-center gap-1.5 text-[var(--color-text-muted)] hover:text-[var(--color-text)]",
|
|
1414
1441
|
children: [
|
|
1415
|
-
/* @__PURE__ */
|
|
1442
|
+
/* @__PURE__ */ jsx23(SiWikipedia, { "aria-hidden": "true", className: "h-3.5 w-3.5" }),
|
|
1416
1443
|
"Wikipedia"
|
|
1417
1444
|
]
|
|
1418
1445
|
}
|
|
1419
1446
|
),
|
|
1420
|
-
wikidataUrl && /* @__PURE__ */
|
|
1447
|
+
wikidataUrl && /* @__PURE__ */ jsxs14(
|
|
1421
1448
|
"a",
|
|
1422
1449
|
{
|
|
1423
1450
|
href: wikidataUrl,
|
|
@@ -1425,17 +1452,17 @@ function GenreDetailExtras({
|
|
|
1425
1452
|
rel: "noopener noreferrer",
|
|
1426
1453
|
className: "inline-flex items-center gap-1.5 text-[var(--color-text-muted)] hover:text-[var(--color-text)]",
|
|
1427
1454
|
children: [
|
|
1428
|
-
/* @__PURE__ */
|
|
1455
|
+
/* @__PURE__ */ jsx23(SiWikidata, { "aria-hidden": "true", className: "h-3.5 w-3.5" }),
|
|
1429
1456
|
"Wikidata"
|
|
1430
1457
|
]
|
|
1431
1458
|
}
|
|
1432
1459
|
)
|
|
1433
1460
|
] }) }),
|
|
1434
|
-
/* @__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) }),
|
|
1435
1462
|
family,
|
|
1436
1463
|
renderGenreDetailExtras?.(overview),
|
|
1437
|
-
(renderEssentialTracks || essentialSongs) && /* @__PURE__ */
|
|
1438
|
-
/* @__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(
|
|
1439
1466
|
GenrePlaylistTracks,
|
|
1440
1467
|
{
|
|
1441
1468
|
genreUuid,
|
|
@@ -1453,10 +1480,10 @@ function GenreDetailExtras({
|
|
|
1453
1480
|
}
|
|
1454
1481
|
|
|
1455
1482
|
// src/genre-tree/GenreInfoPanelBody.tsx
|
|
1456
|
-
import { Fragment as Fragment10, jsx as
|
|
1483
|
+
import { Fragment as Fragment10, jsx as jsx24, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
1457
1484
|
import { createElement } from "react";
|
|
1458
1485
|
function GenreNodeActionBand({ genrePlaylist, playback, ...bandProps }) {
|
|
1459
|
-
return /* @__PURE__ */
|
|
1486
|
+
return /* @__PURE__ */ jsx24(GenreActionBand, { ...bandProps, playActions: /* @__PURE__ */ jsx24(GenrePlayActions, { genrePlaylist, playback }) });
|
|
1460
1487
|
}
|
|
1461
1488
|
function GenreInfoPanelBody({
|
|
1462
1489
|
toolbar,
|
|
@@ -1473,9 +1500,9 @@ function GenreInfoPanelBody({
|
|
|
1473
1500
|
}) {
|
|
1474
1501
|
const summary = scope === "reference" ? GenreCatalogueCountsSchema2.parse(genrePlaylist ?? catalogue) : void 0;
|
|
1475
1502
|
const selection = summary ? defaultGenreMusicSelection2(summary) : void 0;
|
|
1476
|
-
return /* @__PURE__ */
|
|
1503
|
+
return /* @__PURE__ */ jsxs15(Fragment10, { children: [
|
|
1477
1504
|
toolbar,
|
|
1478
|
-
genrePlaylist ? /* @__PURE__ */
|
|
1505
|
+
genrePlaylist ? /* @__PURE__ */ jsx24(GenreNodeActionBand, { ...band, genrePlaylist, playback }) : /* @__PURE__ */ jsx24(GenreActionBand, { ...band }),
|
|
1479
1506
|
/* @__PURE__ */ createElement(
|
|
1480
1507
|
GenreDetailExtras,
|
|
1481
1508
|
{
|
|
@@ -1495,7 +1522,7 @@ function GenreInfoPanelBody({
|
|
|
1495
1522
|
}
|
|
1496
1523
|
|
|
1497
1524
|
// src/genre-tree/GenreDetailPanel.tsx
|
|
1498
|
-
import { Fragment as Fragment11, jsx as
|
|
1525
|
+
import { Fragment as Fragment11, jsx as jsx25, jsxs as jsxs16 } from "react/jsx-runtime";
|
|
1499
1526
|
var RELATIVE_ITEM_COUNT = 1;
|
|
1500
1527
|
function toNode(genre, parentId) {
|
|
1501
1528
|
return {
|
|
@@ -1520,7 +1547,8 @@ function useGenreDetailContent({
|
|
|
1520
1547
|
expanded,
|
|
1521
1548
|
treeStyles
|
|
1522
1549
|
}) {
|
|
1523
|
-
const
|
|
1550
|
+
const result = useFetchGenreDetail(genreUuid, scope, getBackendBaseUrl);
|
|
1551
|
+
const detail = result.status === "success" ? result.genre : void 0;
|
|
1524
1552
|
const defaultPlayback = useGenrePlaylistPlayback({ scope, genrePlaylists: [], artist: extras?.artist });
|
|
1525
1553
|
const playback = hostPlayback ?? defaultPlayback;
|
|
1526
1554
|
const view = useMemo6(() => {
|
|
@@ -1549,22 +1577,27 @@ function useGenreDetailContent({
|
|
|
1549
1577
|
)
|
|
1550
1578
|
};
|
|
1551
1579
|
}, [detail, scope, treeStyles]);
|
|
1552
|
-
if (
|
|
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 {
|
|
1553
1586
|
name: null,
|
|
1554
1587
|
title: "Genre unavailable",
|
|
1555
|
-
content: /* @__PURE__ */
|
|
1588
|
+
content: /* @__PURE__ */ jsx25("p", { role: "alert", className: "text-body text-[var(--color-text)]", children: "This genre could not be loaded." })
|
|
1556
1589
|
};
|
|
1557
|
-
if (
|
|
1590
|
+
if (!detail || !view) return {
|
|
1558
1591
|
name: null,
|
|
1559
1592
|
title: "Loading genre\u2026",
|
|
1560
|
-
content: /* @__PURE__ */
|
|
1561
|
-
/* @__PURE__ */
|
|
1562
|
-
/* @__PURE__ */
|
|
1563
|
-
/* @__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" })
|
|
1564
1597
|
] })
|
|
1565
1598
|
};
|
|
1566
1599
|
const selectGenre = (nodeId) => onSelectGenre(GenreUuidSchema.parse(nodeId));
|
|
1567
|
-
const family = /* @__PURE__ */
|
|
1600
|
+
const family = /* @__PURE__ */ jsx25(
|
|
1568
1601
|
GenreNodeFamily,
|
|
1569
1602
|
{
|
|
1570
1603
|
node: view.node,
|
|
@@ -1575,17 +1608,17 @@ function useGenreDetailContent({
|
|
|
1575
1608
|
onSelectNode: selectGenre
|
|
1576
1609
|
}
|
|
1577
1610
|
);
|
|
1578
|
-
const ancestors = /* @__PURE__ */
|
|
1611
|
+
const ancestors = /* @__PURE__ */ jsx25(GenreNodeAncestors, { ancestorNodes: view.ancestorNodes, onSelectNode: selectGenre });
|
|
1579
1612
|
return {
|
|
1580
1613
|
name: detail.name,
|
|
1581
1614
|
title: detail.name,
|
|
1582
1615
|
headerAccent: { background: view.fill, color: view.textColor },
|
|
1583
1616
|
aside: expanded ? ancestors : void 0,
|
|
1584
|
-
content: /* @__PURE__ */
|
|
1585
|
-
/* @__PURE__ */
|
|
1617
|
+
content: /* @__PURE__ */ jsxs16(Fragment11, { children: [
|
|
1618
|
+
/* @__PURE__ */ jsx25(
|
|
1586
1619
|
GenreInfoPanelBody,
|
|
1587
1620
|
{
|
|
1588
|
-
family: /* @__PURE__ */
|
|
1621
|
+
family: /* @__PURE__ */ jsxs16(Fragment11, { children: [
|
|
1589
1622
|
family,
|
|
1590
1623
|
!expanded && ancestors
|
|
1591
1624
|
] }),
|
|
@@ -1629,7 +1662,7 @@ function GenreDetailPanel({
|
|
|
1629
1662
|
expanded,
|
|
1630
1663
|
band: { onZoomIn, shareUrl, shareTarget: shareUrl ? shareTarget : void 0 }
|
|
1631
1664
|
});
|
|
1632
|
-
return /* @__PURE__ */
|
|
1665
|
+
return /* @__PURE__ */ jsx25(
|
|
1633
1666
|
DetailPanel,
|
|
1634
1667
|
{
|
|
1635
1668
|
side: "left",
|
|
@@ -1642,7 +1675,7 @@ function GenreDetailPanel({
|
|
|
1642
1675
|
edgeTab,
|
|
1643
1676
|
aside: panel.aside,
|
|
1644
1677
|
titleInSearch,
|
|
1645
|
-
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,
|
|
1646
1679
|
children: panel.content
|
|
1647
1680
|
}
|
|
1648
1681
|
);
|
|
@@ -1654,7 +1687,7 @@ import {
|
|
|
1654
1687
|
getReparentCandidates,
|
|
1655
1688
|
useUpdateGenre
|
|
1656
1689
|
} from "@behindthemusictree/app-kit/genre-tree";
|
|
1657
|
-
import { jsx as
|
|
1690
|
+
import { jsx as jsx26, jsxs as jsxs17 } from "react/jsx-runtime";
|
|
1658
1691
|
function ChangeParentPopup({
|
|
1659
1692
|
genrePlaylist,
|
|
1660
1693
|
genrePlaylists,
|
|
@@ -1689,12 +1722,12 @@ function ChangeParentPopup({
|
|
|
1689
1722
|
window.addEventListener("keydown", handleKeyDown);
|
|
1690
1723
|
return () => window.removeEventListener("keydown", handleKeyDown);
|
|
1691
1724
|
}, [onClose]);
|
|
1692
|
-
return /* @__PURE__ */
|
|
1693
|
-
/* @__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: [
|
|
1694
1727
|
"Current parent: ",
|
|
1695
1728
|
genrePlaylist.parent?.name ?? "none"
|
|
1696
1729
|
] }),
|
|
1697
|
-
/* @__PURE__ */
|
|
1730
|
+
/* @__PURE__ */ jsx26("div", { "aria-busy": isPending, className: isPending ? "pointer-events-none opacity-60" : void 0, children: /* @__PURE__ */ jsx26(
|
|
1698
1731
|
GenreSearch,
|
|
1699
1732
|
{
|
|
1700
1733
|
genrePlaylists: candidates,
|
|
@@ -1702,7 +1735,7 @@ function ChangeParentPopup({
|
|
|
1702
1735
|
placeholder: "Search a new parent\u2026"
|
|
1703
1736
|
}
|
|
1704
1737
|
) }),
|
|
1705
|
-
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(" ") })
|
|
1706
1739
|
] });
|
|
1707
1740
|
}
|
|
1708
1741
|
|
|
@@ -1715,7 +1748,7 @@ import { Pause as Pause2, Play as Play2 } from "lucide-react";
|
|
|
1715
1748
|
import { ActionBand as ActionBand2, ActionButton as ActionButton4, PanelBleed as PanelBleed2 } from "@behindthemusictree/ui";
|
|
1716
1749
|
import { TrackListOriginType as TrackListOriginType2, useTrackList as useTrackList3 } from "@behindthemusictree/app-kit/genre-tree";
|
|
1717
1750
|
import { usePlayer as usePlayer6 } from "@behindthemusictree/app-kit/player";
|
|
1718
|
-
import { jsx as
|
|
1751
|
+
import { jsx as jsx27, jsxs as jsxs18 } from "react/jsx-runtime";
|
|
1719
1752
|
function ArtistActionBand({ artist, share }) {
|
|
1720
1753
|
const { trackList, playNewTrackListFromArtist } = useTrackList3();
|
|
1721
1754
|
const { isPlaying, setIsPlaying } = usePlayer6();
|
|
@@ -1731,11 +1764,11 @@ function ArtistActionBand({ artist, share }) {
|
|
|
1731
1764
|
console.error("Failed to load artist tracks:", error);
|
|
1732
1765
|
});
|
|
1733
1766
|
};
|
|
1734
|
-
return /* @__PURE__ */
|
|
1735
|
-
/* @__PURE__ */
|
|
1767
|
+
return /* @__PURE__ */ jsx27(PanelBleed2, { children: /* @__PURE__ */ jsxs18(ActionBand2, { children: [
|
|
1768
|
+
/* @__PURE__ */ jsx27(
|
|
1736
1769
|
ActionButton4,
|
|
1737
1770
|
{
|
|
1738
|
-
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" }),
|
|
1739
1772
|
label: playing ? "Pause" : "Play",
|
|
1740
1773
|
caption: String(artist.playableTracksCount),
|
|
1741
1774
|
disabled: artist.playableTracksCount === 0,
|
|
@@ -1763,7 +1796,7 @@ import {
|
|
|
1763
1796
|
SiYoutube
|
|
1764
1797
|
} from "react-icons/si";
|
|
1765
1798
|
import { Chip } from "@behindthemusictree/ui";
|
|
1766
|
-
import { jsx as
|
|
1799
|
+
import { jsx as jsx28 } from "react/jsx-runtime";
|
|
1767
1800
|
var LINK_KINDS = {
|
|
1768
1801
|
official: { label: "Official website", Icon: Globe },
|
|
1769
1802
|
wikipedia: { label: "Wikipedia", Icon: SiWikipedia2 },
|
|
@@ -1800,7 +1833,7 @@ function artistLinks(artist) {
|
|
|
1800
1833
|
return links;
|
|
1801
1834
|
}
|
|
1802
1835
|
function ArtistLinks({ links }) {
|
|
1803
|
-
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)) });
|
|
1804
1837
|
}
|
|
1805
1838
|
|
|
1806
1839
|
// src/genre-tree/artist/formatYears.ts
|
|
@@ -1811,7 +1844,7 @@ function formatYears(beginYear, endYear, ended) {
|
|
|
1811
1844
|
}
|
|
1812
1845
|
|
|
1813
1846
|
// src/genre-tree/artist/ArtistHeader.tsx
|
|
1814
|
-
import { jsx as
|
|
1847
|
+
import { jsx as jsx29 } from "react/jsx-runtime";
|
|
1815
1848
|
var countryNames = new Intl.DisplayNames(["en"], { type: "region" });
|
|
1816
1849
|
function ArtistHeader({ artist }) {
|
|
1817
1850
|
const fields = [];
|
|
@@ -1821,35 +1854,23 @@ function ArtistHeader({ artist }) {
|
|
|
1821
1854
|
const years = formatYears(artist.beginYear, artist.endYear, artist.ended);
|
|
1822
1855
|
if (years) fields.push({ label: "Active", value: years });
|
|
1823
1856
|
const links = artistLinks(artist);
|
|
1824
|
-
if (links.length > 0) fields.push({ label: "Links", value: /* @__PURE__ */
|
|
1857
|
+
if (links.length > 0) fields.push({ label: "Links", value: /* @__PURE__ */ jsx29(ArtistLinks, { links }) });
|
|
1825
1858
|
if (fields.length === 0) return null;
|
|
1826
|
-
return /* @__PURE__ */
|
|
1859
|
+
return /* @__PURE__ */ jsx29(FieldList, { items: fields });
|
|
1827
1860
|
}
|
|
1828
1861
|
|
|
1829
1862
|
// src/genre-tree/artist/ArtistPhoto.tsx
|
|
1830
|
-
import { jsx as
|
|
1831
|
-
function ExternalLink({ href, children }) {
|
|
1832
|
-
return /* @__PURE__ */ jsx29("a", { href, target: "_blank", rel: "noopener noreferrer", className: "underline-offset-2 hover:underline", children });
|
|
1833
|
-
}
|
|
1863
|
+
import { jsx as jsx30 } from "react/jsx-runtime";
|
|
1834
1864
|
function ArtistPhoto({ image, name }) {
|
|
1835
|
-
return /* @__PURE__ */
|
|
1836
|
-
/* @__PURE__ */ jsx29("img", { src: image.url, alt: name, className: "h-64 w-full object-contain bg-[var(--color-surface-muted)] rounded" }),
|
|
1837
|
-
/* @__PURE__ */ jsxs18("figcaption", { className: "text-caption text-[var(--color-text-muted)]", children: [
|
|
1838
|
-
"Photo: ",
|
|
1839
|
-
/* @__PURE__ */ jsx29(ExternalLink, { href: image.pageUrl, children: image.author ?? "Wikimedia Commons" }),
|
|
1840
|
-
",",
|
|
1841
|
-
" ",
|
|
1842
|
-
image.licenseUrl ? /* @__PURE__ */ jsx29(ExternalLink, { href: image.licenseUrl, children: image.license }) : image.license
|
|
1843
|
-
] })
|
|
1844
|
-
] });
|
|
1865
|
+
return /* @__PURE__ */ jsx30(CommonsPhoto, { image, alt: name });
|
|
1845
1866
|
}
|
|
1846
1867
|
|
|
1847
1868
|
// src/genre-tree/artist/ArtistMembers.tsx
|
|
1848
1869
|
import { PanelGroup, PanelSection as PanelSection3 } from "@behindthemusictree/ui";
|
|
1849
|
-
import { jsx as
|
|
1870
|
+
import { jsx as jsx31, jsxs as jsxs19 } from "react/jsx-runtime";
|
|
1850
1871
|
function MembershipList({ title, memberships, renderArtistLink }) {
|
|
1851
1872
|
if (memberships.length === 0) return null;
|
|
1852
|
-
return /* @__PURE__ */
|
|
1873
|
+
return /* @__PURE__ */ jsx31(PanelGroup, { title, children: /* @__PURE__ */ jsx31("ul", { children: memberships.map((membership, index) => {
|
|
1853
1874
|
const details = [
|
|
1854
1875
|
formatYears(membership.beginYear, membership.endYear, membership.ended),
|
|
1855
1876
|
...membership.roles
|
|
@@ -1858,7 +1879,7 @@ function MembershipList({ title, memberships, renderArtistLink }) {
|
|
|
1858
1879
|
return (
|
|
1859
1880
|
// A member can have several periods in the same group.
|
|
1860
1881
|
/* @__PURE__ */ jsxs19("li", { className: "truncate py-0.5", title: detailsText || void 0, children: [
|
|
1861
|
-
/* @__PURE__ */
|
|
1882
|
+
/* @__PURE__ */ jsx31("span", { className: "font-medium text-[var(--color-text)]", children: renderArtistLink(membership.artist) }),
|
|
1862
1883
|
detailsText && /* @__PURE__ */ jsxs19("span", { className: "text-[var(--color-text-muted)]", children: [
|
|
1863
1884
|
" \u2014 ",
|
|
1864
1885
|
detailsText
|
|
@@ -1871,8 +1892,8 @@ function ArtistMembers({ title, memberships, renderArtistLink }) {
|
|
|
1871
1892
|
if (memberships.length === 0) return null;
|
|
1872
1893
|
const isCurrent = (membership) => !membership.ended && membership.endYear === null;
|
|
1873
1894
|
return /* @__PURE__ */ jsxs19(PanelSection3, { title, children: [
|
|
1874
|
-
/* @__PURE__ */
|
|
1875
|
-
/* @__PURE__ */
|
|
1895
|
+
/* @__PURE__ */ jsx31(MembershipList, { title: "Current", memberships: memberships.filter(isCurrent), renderArtistLink }),
|
|
1896
|
+
/* @__PURE__ */ jsx31(
|
|
1876
1897
|
MembershipList,
|
|
1877
1898
|
{
|
|
1878
1899
|
title: "Past",
|
|
@@ -1885,7 +1906,7 @@ function ArtistMembers({ title, memberships, renderArtistLink }) {
|
|
|
1885
1906
|
|
|
1886
1907
|
// src/genre-tree/artist/ArtistDiscography.tsx
|
|
1887
1908
|
import { PanelGroup as PanelGroup2, PanelSection as PanelSection4 } from "@behindthemusictree/ui";
|
|
1888
|
-
import { jsx as
|
|
1909
|
+
import { jsx as jsx32, jsxs as jsxs20 } from "react/jsx-runtime";
|
|
1889
1910
|
var GROUPS = ["Albums", "EPs", "Singles", "Live", "Compilations", "Other"];
|
|
1890
1911
|
var PRIMARY_GROUPS = { album: "Albums", ep: "EPs", single: "Singles" };
|
|
1891
1912
|
function discographyGroup({ primaryType, secondaryTypes }) {
|
|
@@ -1905,12 +1926,12 @@ function byYear(a, b) {
|
|
|
1905
1926
|
function ArtistDiscography({ albums }) {
|
|
1906
1927
|
if (albums.length === 0) return null;
|
|
1907
1928
|
const sorted = [...albums].sort(byYear);
|
|
1908
|
-
return /* @__PURE__ */
|
|
1929
|
+
return /* @__PURE__ */ jsx32(PanelSection4, { title: "Discography", children: GROUPS.map((group) => {
|
|
1909
1930
|
const groupAlbums = sorted.filter((album) => discographyGroup(album) === group);
|
|
1910
1931
|
if (groupAlbums.length === 0) return null;
|
|
1911
|
-
return /* @__PURE__ */
|
|
1912
|
-
/* @__PURE__ */
|
|
1913
|
-
/* @__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 })
|
|
1914
1935
|
] }, album.uuid)) }) }, group);
|
|
1915
1936
|
}) });
|
|
1916
1937
|
}
|
|
@@ -1936,7 +1957,7 @@ import { useTrackList as useTrackList4 } from "@behindthemusictree/app-kit/genre
|
|
|
1936
1957
|
import { FaPlay as FaPlay2, FaPause as FaPause2 } from "react-icons/fa";
|
|
1937
1958
|
import { usePlayer as usePlayer7 } from "@behindthemusictree/app-kit/player";
|
|
1938
1959
|
import { PlayStates as PlayStates2 } from "@behindthemusictree/app-kit/player";
|
|
1939
|
-
import { jsx as
|
|
1960
|
+
import { jsx as jsx33, jsxs as jsxs21 } from "react/jsx-runtime";
|
|
1940
1961
|
function TrackPositionPlayPause({
|
|
1941
1962
|
position,
|
|
1942
1963
|
uuid,
|
|
@@ -1957,7 +1978,7 @@ function TrackPositionPlayPause({
|
|
|
1957
1978
|
style: { minWidth: "4rem", maxWidth: "4rem" },
|
|
1958
1979
|
onClick: handlePlayPauseClick,
|
|
1959
1980
|
children: [
|
|
1960
|
-
/* @__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(
|
|
1961
1982
|
"span",
|
|
1962
1983
|
{
|
|
1963
1984
|
className: "track-position-play-pause__bars",
|
|
@@ -1965,18 +1986,18 @@ function TrackPositionPlayPause({
|
|
|
1965
1986
|
role: "img",
|
|
1966
1987
|
"aria-label": isPlaying ? "Playing" : "Paused",
|
|
1967
1988
|
children: [
|
|
1968
|
-
/* @__PURE__ */
|
|
1969
|
-
/* @__PURE__ */
|
|
1970
|
-
/* @__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" })
|
|
1971
1992
|
]
|
|
1972
1993
|
}
|
|
1973
1994
|
) : position }),
|
|
1974
|
-
/* @__PURE__ */
|
|
1995
|
+
/* @__PURE__ */ jsx33(
|
|
1975
1996
|
"div",
|
|
1976
1997
|
{
|
|
1977
1998
|
className: `hidden group-hover:flex items-center justify-center ${isCurrentTrackActive ? "" : "absolute inset-0"}`,
|
|
1978
1999
|
"aria-hidden": "true",
|
|
1979
|
-
children: isAwaitingPlayback ? /* @__PURE__ */
|
|
2000
|
+
children: isAwaitingPlayback ? /* @__PURE__ */ jsx33("span", { className: "track-position-play-pause__spinner" }) : isPlaying ? /* @__PURE__ */ jsx33(FaPause2, {}) : /* @__PURE__ */ jsx33(FaPlay2, {})
|
|
1980
2001
|
}
|
|
1981
2002
|
)
|
|
1982
2003
|
]
|
|
@@ -1987,7 +2008,7 @@ function TrackPositionPlayPause({
|
|
|
1987
2008
|
// src/genre-tree/track-list-sidebar/TrackItem.tsx
|
|
1988
2009
|
import { isSong as isSong2, songUnplayableReason as songUnplayableReason2 } from "@behindthemusictree/app-kit/genre-tree";
|
|
1989
2010
|
import { ArtistNames as ArtistNames2 } from "@behindthemusictree/app-kit/genre-tree";
|
|
1990
|
-
import { jsx as
|
|
2011
|
+
import { jsx as jsx34, jsxs as jsxs22 } from "react/jsx-runtime";
|
|
1991
2012
|
function TrackItem({
|
|
1992
2013
|
track,
|
|
1993
2014
|
position,
|
|
@@ -2016,7 +2037,7 @@ function TrackItem({
|
|
|
2016
2037
|
{
|
|
2017
2038
|
className: `track-item flex h-14 text-[var(--color-text)] ${isUnplayable ? "opacity-50" : "hover:bg-[var(--color-surface-muted)] group"}`,
|
|
2018
2039
|
children: [
|
|
2019
|
-
isUnplayable ? /* @__PURE__ */
|
|
2040
|
+
isUnplayable ? /* @__PURE__ */ jsx34(
|
|
2020
2041
|
"div",
|
|
2021
2042
|
{
|
|
2022
2043
|
className: "flex items-center justify-center text-lg w-16",
|
|
@@ -2024,7 +2045,7 @@ function TrackItem({
|
|
|
2024
2045
|
"aria-disabled": "true",
|
|
2025
2046
|
children: position
|
|
2026
2047
|
}
|
|
2027
|
-
) : /* @__PURE__ */
|
|
2048
|
+
) : /* @__PURE__ */ jsx34(
|
|
2028
2049
|
TrackPositionPlayPause,
|
|
2029
2050
|
{
|
|
2030
2051
|
position,
|
|
@@ -2034,11 +2055,11 @@ function TrackItem({
|
|
|
2034
2055
|
}
|
|
2035
2056
|
),
|
|
2036
2057
|
/* @__PURE__ */ jsxs22("div", { className: "title-artist-container flex flex-col items-start justify-center min-w-0 flex-1", children: [
|
|
2037
|
-
/* @__PURE__ */
|
|
2038
|
-
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 }) }) : ""
|
|
2039
2060
|
] }),
|
|
2040
|
-
/* @__PURE__ */
|
|
2041
|
-
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(
|
|
2042
2063
|
"div",
|
|
2043
2064
|
{
|
|
2044
2065
|
className: "duration flex text-base w-16 items-center justify-center",
|
|
@@ -2046,14 +2067,14 @@ function TrackItem({
|
|
|
2046
2067
|
children: renderDuration(track)
|
|
2047
2068
|
}
|
|
2048
2069
|
),
|
|
2049
|
-
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) })
|
|
2050
2071
|
]
|
|
2051
2072
|
}
|
|
2052
2073
|
);
|
|
2053
2074
|
}
|
|
2054
2075
|
|
|
2055
2076
|
// src/genre-tree/artist/ArtistSongs.tsx
|
|
2056
|
-
import { Fragment as Fragment12, jsx as
|
|
2077
|
+
import { Fragment as Fragment12, jsx as jsx35, jsxs as jsxs23 } from "react/jsx-runtime";
|
|
2057
2078
|
var SongPageSchema2 = PaginatedResponseSchema2(SongDetailedSchema2);
|
|
2058
2079
|
var SORTS = [
|
|
2059
2080
|
{ ordering: "title", label: "Title" },
|
|
@@ -2086,8 +2107,8 @@ function ArtistSongs({ artist, getBackendBaseUrl, renderArtistLink, renderSongLi
|
|
|
2086
2107
|
event.stopPropagation();
|
|
2087
2108
|
void play(song.uuid);
|
|
2088
2109
|
};
|
|
2089
|
-
return /* @__PURE__ */
|
|
2090
|
-
/* @__PURE__ */
|
|
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(
|
|
2091
2112
|
"button",
|
|
2092
2113
|
{
|
|
2093
2114
|
type: "button",
|
|
@@ -2101,7 +2122,7 @@ function ArtistSongs({ artist, getBackendBaseUrl, renderArtistLink, renderSongLi
|
|
|
2101
2122
|
},
|
|
2102
2123
|
sort.ordering
|
|
2103
2124
|
)) }) }),
|
|
2104
|
-
/* @__PURE__ */
|
|
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(
|
|
2105
2126
|
TrackItem,
|
|
2106
2127
|
{
|
|
2107
2128
|
track: song,
|
|
@@ -2110,12 +2131,12 @@ function ArtistSongs({ artist, getBackendBaseUrl, renderArtistLink, renderSongLi
|
|
|
2110
2131
|
renderSongLink
|
|
2111
2132
|
}
|
|
2112
2133
|
) }, song.uuid)) }),
|
|
2113
|
-
/* @__PURE__ */
|
|
2134
|
+
/* @__PURE__ */ jsx35(Pagination, { currentPage: page, totalPages: data.totalPages, onPageChange: setPage })
|
|
2114
2135
|
] }) });
|
|
2115
2136
|
}
|
|
2116
2137
|
|
|
2117
2138
|
// src/genre-tree/artist/useArtistPanel.tsx
|
|
2118
|
-
import { Fragment as Fragment13, jsx as
|
|
2139
|
+
import { Fragment as Fragment13, jsx as jsx36, jsxs as jsxs24 } from "react/jsx-runtime";
|
|
2119
2140
|
function useArtistPanel({
|
|
2120
2141
|
uuid,
|
|
2121
2142
|
scope,
|
|
@@ -2137,25 +2158,25 @@ function useArtistPanel({
|
|
|
2137
2158
|
...panel,
|
|
2138
2159
|
title: "Artist",
|
|
2139
2160
|
content: /* @__PURE__ */ jsxs24("div", { "aria-busy": "true", className: "flex flex-col gap-2.5", children: [
|
|
2140
|
-
/* @__PURE__ */
|
|
2141
|
-
/* @__PURE__ */
|
|
2142
|
-
/* @__PURE__ */
|
|
2143
|
-
/* @__PURE__ */
|
|
2144
|
-
/* @__PURE__ */
|
|
2145
|
-
/* @__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" })
|
|
2146
2167
|
] })
|
|
2147
2168
|
};
|
|
2148
2169
|
case "not-found":
|
|
2149
2170
|
return {
|
|
2150
2171
|
...panel,
|
|
2151
2172
|
title: "Artist not found",
|
|
2152
|
-
content: /* @__PURE__ */
|
|
2173
|
+
content: /* @__PURE__ */ jsx36("p", { className: "text-[var(--color-text-muted)]", children: "This artist does not exist." })
|
|
2153
2174
|
};
|
|
2154
2175
|
case "error":
|
|
2155
2176
|
return {
|
|
2156
2177
|
...panel,
|
|
2157
2178
|
title: "Artist",
|
|
2158
|
-
content: /* @__PURE__ */
|
|
2179
|
+
content: /* @__PURE__ */ jsx36("p", { className: "text-red-600", children: "Could not load this artist." })
|
|
2159
2180
|
};
|
|
2160
2181
|
case "success": {
|
|
2161
2182
|
const { artist } = result;
|
|
@@ -2165,18 +2186,18 @@ function useArtistPanel({
|
|
|
2165
2186
|
...panel,
|
|
2166
2187
|
title: artist.name,
|
|
2167
2188
|
content: /* @__PURE__ */ jsxs24(Fragment13, { children: [
|
|
2168
|
-
/* @__PURE__ */
|
|
2189
|
+
/* @__PURE__ */ jsx36(
|
|
2169
2190
|
ArtistActionBand,
|
|
2170
2191
|
{
|
|
2171
2192
|
artist,
|
|
2172
|
-
share: shareTarget && shareUrl ? /* @__PURE__ */
|
|
2193
|
+
share: shareTarget && shareUrl ? /* @__PURE__ */ jsx36(ShareActionButton, { target: shareTarget, url: shareUrl }) : void 0
|
|
2173
2194
|
}
|
|
2174
2195
|
),
|
|
2175
|
-
artist.image && /* @__PURE__ */
|
|
2176
|
-
/* @__PURE__ */
|
|
2177
|
-
/* @__PURE__ */
|
|
2178
|
-
/* @__PURE__ */
|
|
2179
|
-
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(
|
|
2180
2201
|
ArtistSongs,
|
|
2181
2202
|
{
|
|
2182
2203
|
artist: { uuid: artist.uuid, name: artist.name },
|
|
@@ -2186,7 +2207,7 @@ function useArtistPanel({
|
|
|
2186
2207
|
}
|
|
2187
2208
|
)
|
|
2188
2209
|
] }),
|
|
2189
|
-
extraContent: artist.albums.length > 0 ? /* @__PURE__ */
|
|
2210
|
+
extraContent: artist.albums.length > 0 ? /* @__PURE__ */ jsx36(ArtistDiscography, { albums: artist.albums }) : void 0
|
|
2190
2211
|
};
|
|
2191
2212
|
}
|
|
2192
2213
|
}
|
|
@@ -2210,7 +2231,7 @@ import {
|
|
|
2210
2231
|
useSongHistory,
|
|
2211
2232
|
useTrackList as useTrackList6
|
|
2212
2233
|
} from "@behindthemusictree/app-kit/genre-tree";
|
|
2213
|
-
import { Fragment as Fragment14, jsx as
|
|
2234
|
+
import { Fragment as Fragment14, jsx as jsx37, jsxs as jsxs25 } from "react/jsx-runtime";
|
|
2214
2235
|
var numberFormat = new Intl.NumberFormat("en");
|
|
2215
2236
|
var dateFormat = new Intl.DateTimeFormat("en", { dateStyle: "medium" });
|
|
2216
2237
|
var externalLink = "text-[var(--color-primary)] hover:underline focus-visible:underline";
|
|
@@ -2218,11 +2239,11 @@ function SongHistory({ uuid, getBackendBaseUrl }) {
|
|
|
2218
2239
|
const [open, setOpen] = useState9(false);
|
|
2219
2240
|
const history = useSongHistory(uuid, getBackendBaseUrl, open);
|
|
2220
2241
|
let body = null;
|
|
2221
|
-
if (history.status === "loading") body = /* @__PURE__ */
|
|
2222
|
-
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." });
|
|
2223
2244
|
else if (history.status === "success")
|
|
2224
|
-
body = history.entries.length === 0 ? /* @__PURE__ */
|
|
2225
|
-
/* @__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 }),
|
|
2226
2247
|
entry.oldValue !== null || entry.newValue !== null ? /* @__PURE__ */ jsxs25("span", { className: "text-[var(--color-text-muted)]", children: [
|
|
2227
2248
|
" ",
|
|
2228
2249
|
"\u2014 ",
|
|
@@ -2236,9 +2257,9 @@ function SongHistory({ uuid, getBackendBaseUrl }) {
|
|
|
2236
2257
|
dateFormat.format(new Date(entry.createdOn))
|
|
2237
2258
|
] })
|
|
2238
2259
|
] }, entry.uuid)) });
|
|
2239
|
-
return /* @__PURE__ */
|
|
2240
|
-
/* @__PURE__ */
|
|
2241
|
-
/* @__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 })
|
|
2242
2263
|
] }) });
|
|
2243
2264
|
}
|
|
2244
2265
|
function SongPanelContent(props) {
|
|
@@ -2257,13 +2278,13 @@ function SongPanelContent(props) {
|
|
|
2257
2278
|
const genre = song.genre;
|
|
2258
2279
|
fields.push({
|
|
2259
2280
|
label: "Genre",
|
|
2260
|
-
value: onSelectGenre ? /* @__PURE__ */
|
|
2261
|
-
index > 0 && /* @__PURE__ */
|
|
2262
|
-
/* @__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 })
|
|
2263
2284
|
] }, genrePlaylist.uuid)) }) : song.genre.name
|
|
2264
2285
|
});
|
|
2265
2286
|
} else {
|
|
2266
|
-
fields.push({ label: "Genre", value: /* @__PURE__ */
|
|
2287
|
+
fields.push({ label: "Genre", value: /* @__PURE__ */ jsx37("span", { className: "text-[var(--color-text-muted)]", children: "No genre" }) });
|
|
2267
2288
|
}
|
|
2268
2289
|
if (song.firstReleaseYear) fields.push({ label: "First released", value: song.firstReleaseYear });
|
|
2269
2290
|
const viewCount = song.youtubeVideo?.viewCount;
|
|
@@ -2273,11 +2294,11 @@ function SongPanelContent(props) {
|
|
|
2273
2294
|
const links = [];
|
|
2274
2295
|
if (musicBrainzUrl)
|
|
2275
2296
|
links.push(
|
|
2276
|
-
/* @__PURE__ */
|
|
2297
|
+
/* @__PURE__ */ jsx37("a", { href: musicBrainzUrl, target: "_blank", rel: "noopener noreferrer", className: externalLink, children: "MusicBrainz" }, "mb")
|
|
2277
2298
|
);
|
|
2278
2299
|
if (song.youtubeVideo)
|
|
2279
2300
|
links.push(
|
|
2280
|
-
/* @__PURE__ */
|
|
2301
|
+
/* @__PURE__ */ jsx37(
|
|
2281
2302
|
"a",
|
|
2282
2303
|
{
|
|
2283
2304
|
href: `https://www.youtube.com/watch?v=${encodeURIComponent(song.youtubeVideo.id)}`,
|
|
@@ -2292,31 +2313,31 @@ function SongPanelContent(props) {
|
|
|
2292
2313
|
if (links.length > 0)
|
|
2293
2314
|
fields.push({
|
|
2294
2315
|
label: "Links",
|
|
2295
|
-
value: /* @__PURE__ */
|
|
2316
|
+
value: /* @__PURE__ */ jsx37("span", { className: "flex gap-3", children: links })
|
|
2296
2317
|
});
|
|
2297
2318
|
return /* @__PURE__ */ jsxs25(Fragment14, { children: [
|
|
2298
|
-
/* @__PURE__ */
|
|
2299
|
-
/* @__PURE__ */
|
|
2319
|
+
/* @__PURE__ */ jsx37(PanelBleed3, { children: /* @__PURE__ */ jsxs25(ActionBand3, { children: [
|
|
2320
|
+
/* @__PURE__ */ jsx37(
|
|
2300
2321
|
ActionButton5,
|
|
2301
2322
|
{
|
|
2302
|
-
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" }),
|
|
2303
2324
|
label: isPlaying ? "Pause" : "Play",
|
|
2304
2325
|
disabled: !!unplayableReason,
|
|
2305
2326
|
title: unplayableReason ?? void 0,
|
|
2306
2327
|
onClick: () => isCurrent ? handlePlayPauseAction() : playNewTrackListFromTrackUuid(song, scope)
|
|
2307
2328
|
}
|
|
2308
2329
|
),
|
|
2309
|
-
shareUrl && /* @__PURE__ */
|
|
2330
|
+
shareUrl && /* @__PURE__ */ jsx37(ShareActionButton, { target: shareTarget, url: shareUrl })
|
|
2310
2331
|
] }) }),
|
|
2311
|
-
song.artists && song.artists.length > 0 && /* @__PURE__ */
|
|
2312
|
-
/* @__PURE__ */
|
|
2313
|
-
song.essentialGenres && song.essentialGenres.length > 0 && /* @__PURE__ */
|
|
2314
|
-
/* @__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 })
|
|
2315
2336
|
] });
|
|
2316
2337
|
}
|
|
2317
2338
|
|
|
2318
2339
|
// src/genre-tree/song/useSongPanel.tsx
|
|
2319
|
-
import { jsx as
|
|
2340
|
+
import { jsx as jsx38, jsxs as jsxs26 } from "react/jsx-runtime";
|
|
2320
2341
|
function useSongPanel({
|
|
2321
2342
|
uuid,
|
|
2322
2343
|
scope,
|
|
@@ -2338,23 +2359,23 @@ function useSongPanel({
|
|
|
2338
2359
|
...panel,
|
|
2339
2360
|
title: "Song",
|
|
2340
2361
|
content: /* @__PURE__ */ jsxs26("div", { "aria-busy": "true", className: "flex flex-col gap-2.5", children: [
|
|
2341
|
-
/* @__PURE__ */
|
|
2342
|
-
/* @__PURE__ */
|
|
2343
|
-
/* @__PURE__ */
|
|
2344
|
-
/* @__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" })
|
|
2345
2366
|
] })
|
|
2346
2367
|
};
|
|
2347
2368
|
case "not-found":
|
|
2348
2369
|
return {
|
|
2349
2370
|
...panel,
|
|
2350
2371
|
title: "Song not found",
|
|
2351
|
-
content: /* @__PURE__ */
|
|
2372
|
+
content: /* @__PURE__ */ jsx38("p", { className: "text-[var(--color-text-muted)]", children: "This song does not exist." })
|
|
2352
2373
|
};
|
|
2353
2374
|
case "error":
|
|
2354
2375
|
return {
|
|
2355
2376
|
...panel,
|
|
2356
2377
|
title: "Song",
|
|
2357
|
-
content: /* @__PURE__ */
|
|
2378
|
+
content: /* @__PURE__ */ jsx38("p", { className: "text-red-600", children: "Could not load this song." })
|
|
2358
2379
|
};
|
|
2359
2380
|
case "success": {
|
|
2360
2381
|
const { song } = result;
|
|
@@ -2362,7 +2383,7 @@ function useSongPanel({
|
|
|
2362
2383
|
return {
|
|
2363
2384
|
...panel,
|
|
2364
2385
|
title: song.title,
|
|
2365
|
-
content: /* @__PURE__ */
|
|
2386
|
+
content: /* @__PURE__ */ jsx38(
|
|
2366
2387
|
SongPanelContent,
|
|
2367
2388
|
{
|
|
2368
2389
|
song,
|
|
@@ -2415,12 +2436,12 @@ function useEntityPanel({
|
|
|
2415
2436
|
// src/genre-tree/SizeMetricToggle.tsx
|
|
2416
2437
|
import { MdMusicNote, MdVisibility } from "react-icons/md";
|
|
2417
2438
|
import { SegmentedControl } from "@behindthemusictree/ui";
|
|
2418
|
-
import { jsx as
|
|
2439
|
+
import { jsx as jsx39 } from "react/jsx-runtime";
|
|
2419
2440
|
function SizeMetricToggle({
|
|
2420
2441
|
value,
|
|
2421
2442
|
onChange
|
|
2422
2443
|
}) {
|
|
2423
|
-
return /* @__PURE__ */
|
|
2444
|
+
return /* @__PURE__ */ jsx39(
|
|
2424
2445
|
SegmentedControl,
|
|
2425
2446
|
{
|
|
2426
2447
|
variant: "floating",
|
|
@@ -2428,15 +2449,15 @@ function SizeMetricToggle({
|
|
|
2428
2449
|
value,
|
|
2429
2450
|
onChange,
|
|
2430
2451
|
options: [
|
|
2431
|
-
{ value: "songs", label: /* @__PURE__ */
|
|
2432
|
-
{ 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" }
|
|
2433
2454
|
]
|
|
2434
2455
|
}
|
|
2435
2456
|
);
|
|
2436
2457
|
}
|
|
2437
2458
|
|
|
2438
2459
|
// src/genre-tree/GenreTreeView.tsx
|
|
2439
|
-
import { Fragment as Fragment15, jsx as
|
|
2460
|
+
import { Fragment as Fragment15, jsx as jsx40, jsxs as jsxs27 } from "react/jsx-runtime";
|
|
2440
2461
|
var NO_POP_ROOT_TITLE = "This genre tree has no 'Mainstream Pop' root yet";
|
|
2441
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)]";
|
|
2442
2463
|
var noop = () => {
|
|
@@ -2588,14 +2609,14 @@ function GenreTreeView({
|
|
|
2588
2609
|
const openSongRef = useRef3(openSong);
|
|
2589
2610
|
openSongRef.current = openSong;
|
|
2590
2611
|
const resolvedRenderSongLink = useCallback6(
|
|
2591
|
-
(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 }),
|
|
2592
2613
|
[renderSongLink]
|
|
2593
2614
|
);
|
|
2594
2615
|
const [expandedSongUuid, setExpandedSongUuid] = useState10(null);
|
|
2595
2616
|
const [expandedArtistUuid, setExpandedArtistUuid] = useState10(null);
|
|
2596
2617
|
const artistBaseUrl = artistSearchBaseUrl ?? getBackendBaseUrl;
|
|
2597
2618
|
const songBaseUrl = getBackendBaseUrl;
|
|
2598
|
-
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 }));
|
|
2599
2620
|
const getGenrePath = (genre) => {
|
|
2600
2621
|
const path = [];
|
|
2601
2622
|
let current = visibleGenrePlaylists.find((playlist) => playlist.criteria?.uuid === genre.uuid);
|
|
@@ -2672,9 +2693,10 @@ function GenreTreeView({
|
|
|
2672
2693
|
resolveStyle
|
|
2673
2694
|
);
|
|
2674
2695
|
const treeStyles = useMemo8(() => toGenreNodeStyles(relations, visibleGenrePlaylists), [relations, visibleGenrePlaylists]);
|
|
2675
|
-
const
|
|
2676
|
-
|
|
2677
|
-
|
|
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 });
|
|
2678
2700
|
}
|
|
2679
2701
|
const handlePrevious = selectionHistory.previous ? () => selectGenre(selectionHistory.previous) : void 0;
|
|
2680
2702
|
const { showPopup, hidePopup } = usePopup4();
|
|
@@ -2706,7 +2728,7 @@ function GenreTreeView({
|
|
|
2706
2728
|
const canToggleSide = !readOnly && criteria !== void 0 && criteria !== null && parentPlaylist !== void 0 && parentPlaylist.parent === null;
|
|
2707
2729
|
const side = criteria?.side ?? "core";
|
|
2708
2730
|
const popSibling = canToggleSide && side === "core" ? visibleGenrePlaylists.find((sibling) => sibling.parent?.uuid === parentPlaylist.uuid && sibling.uuid !== genrePlaylist?.uuid && sibling.criteria?.side === "pop") : void 0;
|
|
2709
|
-
const shareTarget =
|
|
2731
|
+
const shareTarget = validSelectedGenreUuid ? { kind: "genre", genreUuid: validSelectedGenreUuid, name: criteria?.name ?? "Genre", scope, artistUuid } : void 0;
|
|
2710
2732
|
const shareUrl = shareTarget ? getShareUrlRef.current?.(shareTarget) ?? void 0 : void 0;
|
|
2711
2733
|
const genreContent = useGenreDetailContent({
|
|
2712
2734
|
genreUuid: selectedGenreUuid,
|
|
@@ -2728,7 +2750,7 @@ function GenreTreeView({
|
|
|
2728
2750
|
onAddChild: readOnly || !criteria ? void 0 : () => handleGenreCreationAction(criteria),
|
|
2729
2751
|
onRename: readOnly || !criteria ? void 0 : () => handleGenreRenameAction(criteria),
|
|
2730
2752
|
onChangeParent: readOnly || !genrePlaylist || !criteria ? void 0 : () => showPopup(
|
|
2731
|
-
/* @__PURE__ */
|
|
2753
|
+
/* @__PURE__ */ jsx40(
|
|
2732
2754
|
ChangeParentPopup,
|
|
2733
2755
|
{
|
|
2734
2756
|
genrePlaylist: { ...genrePlaylist, criteria },
|
|
@@ -2772,7 +2794,7 @@ function GenreTreeView({
|
|
|
2772
2794
|
onClose: otherPanel.onClose,
|
|
2773
2795
|
searchName: otherPanel.title
|
|
2774
2796
|
};
|
|
2775
|
-
} else if (selectedGenreUuid) {
|
|
2797
|
+
} else if (selectedGenreUuid !== null) {
|
|
2776
2798
|
activePanel = {
|
|
2777
2799
|
title: genreContent.title,
|
|
2778
2800
|
content: genreContent.content,
|
|
@@ -2789,19 +2811,19 @@ function GenreTreeView({
|
|
|
2789
2811
|
edge: activePanel.expanded ? { label: "Shrink panel", onClick: () => activePanel.onExpandedChange?.(false) } : isCollapsed ? null : { label: "Hide panel", onClick: () => changeCollapsed(true) },
|
|
2790
2812
|
center: activePanel.expanded ? null : isCollapsed ? { label: "Show panel", onClick: () => changeCollapsed(false) } : activePanel.onExpandedChange ? { label: "Extend panel", onClick: () => activePanel.onExpandedChange?.(true) } : null
|
|
2791
2813
|
} : void 0;
|
|
2792
|
-
const expandButton = placement === "default" && activePanel?.onExpandedChange ? /* @__PURE__ */
|
|
2814
|
+
const expandButton = placement === "default" && activePanel?.onExpandedChange ? /* @__PURE__ */ jsx40(
|
|
2793
2815
|
IconButton2,
|
|
2794
2816
|
{
|
|
2795
2817
|
"aria-label": activePanel.expanded ? "Shrink panel" : "Extend panel",
|
|
2796
2818
|
style: activePanel.headerAccent && { color: "inherit" },
|
|
2797
2819
|
onClick: () => activePanel.onExpandedChange?.(!activePanel.expanded),
|
|
2798
|
-
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" })
|
|
2799
2821
|
}
|
|
2800
2822
|
) : null;
|
|
2801
2823
|
const renderArtistFilter = () => {
|
|
2802
2824
|
if (isLoading || !filterArtist) return null;
|
|
2803
2825
|
return /* @__PURE__ */ jsxs27("span", { className: "inline-flex items-center overflow-hidden rounded-full bg-[var(--color-neutral-100)] text-body", children: [
|
|
2804
|
-
/* @__PURE__ */
|
|
2826
|
+
/* @__PURE__ */ jsx40(
|
|
2805
2827
|
"button",
|
|
2806
2828
|
{
|
|
2807
2829
|
type: "button",
|
|
@@ -2813,7 +2835,7 @@ function GenreTreeView({
|
|
|
2813
2835
|
children: filterArtist.name
|
|
2814
2836
|
}
|
|
2815
2837
|
),
|
|
2816
|
-
/* @__PURE__ */
|
|
2838
|
+
/* @__PURE__ */ jsx40(
|
|
2817
2839
|
"button",
|
|
2818
2840
|
{
|
|
2819
2841
|
type: "button",
|
|
@@ -2826,7 +2848,7 @@ function GenreTreeView({
|
|
|
2826
2848
|
] });
|
|
2827
2849
|
};
|
|
2828
2850
|
const actions = /* @__PURE__ */ jsxs27(Fragment15, { children: [
|
|
2829
|
-
!isLoading && !isError && /* @__PURE__ */
|
|
2851
|
+
!isLoading && !isError && /* @__PURE__ */ jsx40(
|
|
2830
2852
|
GenreTreeSearch,
|
|
2831
2853
|
{
|
|
2832
2854
|
artistBaseUrl,
|
|
@@ -2859,9 +2881,9 @@ function GenreTreeView({
|
|
|
2859
2881
|
extraGroups: extraSearchGroups
|
|
2860
2882
|
}
|
|
2861
2883
|
),
|
|
2862
|
-
!isLoading && !isError && filterArtist && /* @__PURE__ */
|
|
2884
|
+
!isLoading && !isError && filterArtist && /* @__PURE__ */ jsx40("div", { className: "hidden w-full justify-center max-md:flex", children: renderArtistFilter() }),
|
|
2863
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: [
|
|
2864
|
-
!isLoading && !isError && !isControlled && /* @__PURE__ */
|
|
2886
|
+
!isLoading && !isError && !isControlled && /* @__PURE__ */ jsx40(
|
|
2865
2887
|
SegmentedControl2,
|
|
2866
2888
|
{
|
|
2867
2889
|
"aria-label": "Tree view mode",
|
|
@@ -2875,13 +2897,13 @@ function GenreTreeView({
|
|
|
2875
2897
|
]
|
|
2876
2898
|
}
|
|
2877
2899
|
),
|
|
2878
|
-
!isLoading && !isError && showDisplayOptions && /* @__PURE__ */
|
|
2900
|
+
!isLoading && !isError && showDisplayOptions && /* @__PURE__ */ jsx40(
|
|
2879
2901
|
"div",
|
|
2880
2902
|
{
|
|
2881
2903
|
className: "flex items-center gap-1",
|
|
2882
2904
|
role: "group",
|
|
2883
2905
|
"aria-label": "Tree display options",
|
|
2884
|
-
children: !isRotationControlled && viewMode !== "stacked" && viewMode !== "outline" && /* @__PURE__ */
|
|
2906
|
+
children: !isRotationControlled && viewMode !== "stacked" && viewMode !== "outline" && /* @__PURE__ */ jsx40(
|
|
2885
2907
|
Button,
|
|
2886
2908
|
{
|
|
2887
2909
|
variant: allowWheelRotation ? "default" : "outline",
|
|
@@ -2892,7 +2914,7 @@ function GenreTreeView({
|
|
|
2892
2914
|
)
|
|
2893
2915
|
}
|
|
2894
2916
|
),
|
|
2895
|
-
!isLoading && !isError && !readOnly && showAddRoot && /* @__PURE__ */
|
|
2917
|
+
!isLoading && !isError && !readOnly && showAddRoot && /* @__PURE__ */ jsx40(
|
|
2896
2918
|
IconTextButton,
|
|
2897
2919
|
{
|
|
2898
2920
|
icon: Plus2,
|
|
@@ -2908,32 +2930,32 @@ function GenreTreeView({
|
|
|
2908
2930
|
"data-left-panel": isPanelShown && !isCollapsed ? void 0 : "hidden",
|
|
2909
2931
|
className: ["genre-tree-view relative flex flex-col h-full", placement === "regions" && REGIONS_CLASS, className2].filter(Boolean).join(" "),
|
|
2910
2932
|
children: [
|
|
2911
|
-
/* @__PURE__ */
|
|
2933
|
+
/* @__PURE__ */ jsx40(
|
|
2912
2934
|
"div",
|
|
2913
2935
|
{
|
|
2914
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"}`,
|
|
2915
2937
|
children: actions
|
|
2916
2938
|
}
|
|
2917
2939
|
),
|
|
2918
|
-
!isLoading && !isError && filterArtist && /* @__PURE__ */
|
|
2940
|
+
!isLoading && !isError && filterArtist && /* @__PURE__ */ jsx40(
|
|
2919
2941
|
"div",
|
|
2920
2942
|
{
|
|
2921
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"}`,
|
|
2922
2944
|
children: renderArtistFilter()
|
|
2923
2945
|
}
|
|
2924
2946
|
),
|
|
2925
|
-
/* @__PURE__ */
|
|
2926
|
-
!isLoading && !isError && viewMode === "outline" && floatingControlsLeading && /* @__PURE__ */
|
|
2927
|
-
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: [
|
|
2928
2950
|
"Couldn't load the genre tree.",
|
|
2929
2951
|
" ",
|
|
2930
|
-
/* @__PURE__ */
|
|
2952
|
+
/* @__PURE__ */ jsx40("button", { type: "button", className: "underline", onClick: refetch, children: "Retry" })
|
|
2931
2953
|
] }) : viewMode === "wheel" ? (
|
|
2932
2954
|
// The info panel's top edge aligns with the tree's; the search bar floats `--layout-panel-inset` below it,
|
|
2933
2955
|
// and the header inset (the bar's height plus that inset) extends the header's fill behind the bar,
|
|
2934
2956
|
// Google Maps style; the 8px bottom padding mirrors the inset above the bar, and the hidden title's height is zeroed.
|
|
2935
2957
|
// The panel's own Zoom in button is hidden: the search bar carries it.
|
|
2936
|
-
/* @__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(
|
|
2937
2959
|
GenrePlaylistTreeWheel,
|
|
2938
2960
|
{
|
|
2939
2961
|
scope,
|
|
@@ -2953,7 +2975,7 @@ function GenreTreeView({
|
|
|
2953
2975
|
busy,
|
|
2954
2976
|
floatingControlsLeading: floatingControlsLeading || canSizeByViews ? /* @__PURE__ */ jsxs27("div", { className: "flex items-center gap-2", children: [
|
|
2955
2977
|
floatingControlsLeading,
|
|
2956
|
-
canSizeByViews && /* @__PURE__ */
|
|
2978
|
+
canSizeByViews && /* @__PURE__ */ jsx40(SizeMetricToggle, { value: sizeMetric, onChange: changeSizeMetric })
|
|
2957
2979
|
] }) : void 0,
|
|
2958
2980
|
defaultViewport,
|
|
2959
2981
|
viewportRestore,
|
|
@@ -2962,7 +2984,7 @@ function GenreTreeView({
|
|
|
2962
2984
|
) }) })
|
|
2963
2985
|
) : viewMode === "pop-core" ? (
|
|
2964
2986
|
// Same as the wheel: the header inset extends its fill behind the floating search bar, Google Maps style.
|
|
2965
|
-
/* @__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(
|
|
2966
2988
|
GenrePlaylistTreeWheelRadialPopCore,
|
|
2967
2989
|
{
|
|
2968
2990
|
scope,
|
|
@@ -2982,7 +3004,7 @@ function GenreTreeView({
|
|
|
2982
3004
|
busy,
|
|
2983
3005
|
floatingControlsLeading: floatingControlsLeading || canSizeByViews ? /* @__PURE__ */ jsxs27("div", { className: "flex items-center gap-2", children: [
|
|
2984
3006
|
floatingControlsLeading,
|
|
2985
|
-
canSizeByViews && /* @__PURE__ */
|
|
3007
|
+
canSizeByViews && /* @__PURE__ */ jsx40(SizeMetricToggle, { value: sizeMetric, onChange: changeSizeMetric })
|
|
2986
3008
|
] }) : void 0,
|
|
2987
3009
|
defaultViewport,
|
|
2988
3010
|
viewportRestore,
|
|
@@ -2990,7 +3012,7 @@ function GenreTreeView({
|
|
|
2990
3012
|
...focus
|
|
2991
3013
|
}
|
|
2992
3014
|
) }) })
|
|
2993
|
-
) : 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(
|
|
2994
3016
|
GenrePlaylistTreeWheelRadialPopCore,
|
|
2995
3017
|
{
|
|
2996
3018
|
outline: true,
|
|
@@ -3007,13 +3029,13 @@ function GenreTreeView({
|
|
|
3007
3029
|
selectedNodeId,
|
|
3008
3030
|
readOnly
|
|
3009
3031
|
}
|
|
3010
|
-
) }) : /* @__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(
|
|
3011
3033
|
([uuid, genrePlaylistTreePerRoot]) => {
|
|
3012
|
-
return /* @__PURE__ */
|
|
3034
|
+
return /* @__PURE__ */ jsx40(
|
|
3013
3035
|
"div",
|
|
3014
3036
|
{
|
|
3015
3037
|
className: "tree-per-root-container relative shrink-0 h-[28rem] mt-2 mr-16 p-2 bg-[var(--color-neutral-100)] rounded-lg",
|
|
3016
|
-
children: /* @__PURE__ */
|
|
3038
|
+
children: /* @__PURE__ */ jsx40("div", { className: "graph-container relative z-10 h-full", children: /* @__PURE__ */ jsx40(
|
|
3017
3039
|
GenrePlaylistTreePerRoot,
|
|
3018
3040
|
{
|
|
3019
3041
|
scope,
|
|
@@ -3040,7 +3062,7 @@ function GenreTreeView({
|
|
|
3040
3062
|
);
|
|
3041
3063
|
}
|
|
3042
3064
|
) }),
|
|
3043
|
-
/* @__PURE__ */
|
|
3065
|
+
/* @__PURE__ */ jsx40(
|
|
3044
3066
|
DetailPanel2,
|
|
3045
3067
|
{
|
|
3046
3068
|
ref: panelRef,
|
|
@@ -3081,7 +3103,7 @@ import { ListMusic } from "lucide-react";
|
|
|
3081
3103
|
import { useTrackList as useTrackList7 } from "@behindthemusictree/app-kit/genre-tree";
|
|
3082
3104
|
import { TrackListOriginType as TrackListOriginType3 } from "@behindthemusictree/app-kit/genre-tree";
|
|
3083
3105
|
import { useTrackNoun as useTrackNoun3 } from "@behindthemusictree/app-kit/track-noun";
|
|
3084
|
-
import { jsx as
|
|
3106
|
+
import { jsx as jsx41, jsxs as jsxs28 } from "react/jsx-runtime";
|
|
3085
3107
|
var useBrowserLayoutEffect = typeof window === "undefined" ? useEffect7 : useLayoutEffect2;
|
|
3086
3108
|
function TrackListSidebar({
|
|
3087
3109
|
className: className2 = "",
|
|
@@ -3193,15 +3215,15 @@ function TrackListSidebar({
|
|
|
3193
3215
|
/* @__PURE__ */ jsxs28("div", { className: "header flex h-16 items-center px-4 py-2 text-[var(--color-text)]", children: [
|
|
3194
3216
|
/* @__PURE__ */ jsxs28("div", { className: "min-w-0 flex flex-1 flex-col justify-center", children: [
|
|
3195
3217
|
/* @__PURE__ */ jsxs28("div", { className: "origin flex text-xl", children: [
|
|
3196
|
-
/* @__PURE__ */
|
|
3197
|
-
/* @__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 }) })
|
|
3198
3220
|
] }),
|
|
3199
3221
|
/* @__PURE__ */ jsxs28("div", { className: "info flex items-center text-body text-[var(--color-text-muted)]", children: [
|
|
3200
3222
|
trackList.origin.type === TrackListOriginType3.GENRE_PLAYLIST ? "Genre \u2022 " : trackList.origin.type === TrackListOriginType3.ARTIST ? "Artist \u2022 " : `${trackNoun.singular} playlist \u2022 `,
|
|
3201
3223
|
`${trackList.total} ${trackList.total > 1 ? trackNoun.plural : trackNoun.singular}`
|
|
3202
3224
|
] })
|
|
3203
3225
|
] }),
|
|
3204
|
-
(isCollapsed && onExpand || !isCollapsed && onMinimize) && /* @__PURE__ */
|
|
3226
|
+
(isCollapsed && onExpand || !isCollapsed && onMinimize) && /* @__PURE__ */ jsx41(
|
|
3205
3227
|
"button",
|
|
3206
3228
|
{
|
|
3207
3229
|
type: "button",
|
|
@@ -3210,7 +3232,7 @@ function TrackListSidebar({
|
|
|
3210
3232
|
"aria-expanded": !isCollapsed,
|
|
3211
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"}`,
|
|
3212
3234
|
onClick: isCollapsed ? onExpand : onMinimize,
|
|
3213
|
-
children: /* @__PURE__ */
|
|
3235
|
+
children: /* @__PURE__ */ jsx41(ListMusic, { "aria-hidden": "true", className: "h-5 w-5" })
|
|
3214
3236
|
}
|
|
3215
3237
|
)
|
|
3216
3238
|
] }),
|
|
@@ -3224,7 +3246,7 @@ function TrackListSidebar({
|
|
|
3224
3246
|
onPointerDown: markUserScrollIntent,
|
|
3225
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",
|
|
3226
3248
|
children: [
|
|
3227
|
-
trackList.tracks.map((track, index) => /* @__PURE__ */
|
|
3249
|
+
trackList.tracks.map((track, index) => /* @__PURE__ */ jsx41("li", { "data-track-uuid": track.uuid, children: /* @__PURE__ */ jsx41(
|
|
3228
3250
|
TrackItem,
|
|
3229
3251
|
{
|
|
3230
3252
|
track,
|
|
@@ -3235,7 +3257,7 @@ function TrackListSidebar({
|
|
|
3235
3257
|
renderSongLink
|
|
3236
3258
|
}
|
|
3237
3259
|
) }, track.uuid)),
|
|
3238
|
-
hasMore && /* @__PURE__ */
|
|
3260
|
+
hasMore && /* @__PURE__ */ jsx41("li", { ref: loadMoreSentinelRef, "aria-hidden": "true", className: "h-px" })
|
|
3239
3261
|
]
|
|
3240
3262
|
}
|
|
3241
3263
|
)
|
|
@@ -3260,7 +3282,7 @@ import { PanelEdgeTab } from "@behindthemusictree/ui";
|
|
|
3260
3282
|
import { Pause as Pause4, Play as Play4, SkipBack, SkipForward, Volume2, VolumeX } from "lucide-react";
|
|
3261
3283
|
import { formatTime, useTrackList as useTrackList8 } from "@behindthemusictree/app-kit/genre-tree";
|
|
3262
3284
|
import { PlayStates as PlayStates4, useCurrentTime, usePlayer as usePlayer11 } from "@behindthemusictree/app-kit/player";
|
|
3263
|
-
import { jsx as
|
|
3285
|
+
import { jsx as jsx42, jsxs as jsxs29 } from "react/jsx-runtime";
|
|
3264
3286
|
function PlayerControls() {
|
|
3265
3287
|
const {
|
|
3266
3288
|
duration,
|
|
@@ -3286,8 +3308,8 @@ function PlayerControls() {
|
|
|
3286
3308
|
className: "player-controls flex shrink-0 flex-col gap-2 border-b border-zinc-800 px-3 py-2 text-zinc-200",
|
|
3287
3309
|
children: [
|
|
3288
3310
|
/* @__PURE__ */ jsxs29("div", { className: "flex min-w-0 items-center gap-2 text-xs tabular-nums text-zinc-400", children: [
|
|
3289
|
-
/* @__PURE__ */
|
|
3290
|
-
/* @__PURE__ */
|
|
3311
|
+
/* @__PURE__ */ jsx42("span", { "aria-label": "Elapsed time", children: formatTime(safeCurrentTime) }),
|
|
3312
|
+
/* @__PURE__ */ jsx42(
|
|
3291
3313
|
"input",
|
|
3292
3314
|
{
|
|
3293
3315
|
"aria-label": "Seek",
|
|
@@ -3301,11 +3323,11 @@ function PlayerControls() {
|
|
|
3301
3323
|
onChange: (event) => seekTo(Number(event.currentTarget.value))
|
|
3302
3324
|
}
|
|
3303
3325
|
),
|
|
3304
|
-
/* @__PURE__ */
|
|
3326
|
+
/* @__PURE__ */ jsx42("span", { "aria-label": "Duration", children: formatTime(safeDuration) })
|
|
3305
3327
|
] }),
|
|
3306
3328
|
/* @__PURE__ */ jsxs29("div", { className: "grid min-h-9 grid-cols-[1fr_auto_1fr] items-center gap-3", children: [
|
|
3307
3329
|
/* @__PURE__ */ jsxs29("div", { className: "col-start-2 flex items-center justify-center gap-2", children: [
|
|
3308
|
-
/* @__PURE__ */
|
|
3330
|
+
/* @__PURE__ */ jsx42(
|
|
3309
3331
|
"button",
|
|
3310
3332
|
{
|
|
3311
3333
|
type: "button",
|
|
@@ -3314,10 +3336,10 @@ function PlayerControls() {
|
|
|
3314
3336
|
disabled: !isReady || !hasPreviousTrack,
|
|
3315
3337
|
onClick: playPreviousTrack,
|
|
3316
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",
|
|
3317
|
-
children: /* @__PURE__ */
|
|
3339
|
+
children: /* @__PURE__ */ jsx42(SkipBack, { "aria-hidden": "true", className: "h-4 w-4" })
|
|
3318
3340
|
}
|
|
3319
3341
|
),
|
|
3320
|
-
/* @__PURE__ */
|
|
3342
|
+
/* @__PURE__ */ jsx42(
|
|
3321
3343
|
"button",
|
|
3322
3344
|
{
|
|
3323
3345
|
type: "button",
|
|
@@ -3326,10 +3348,10 @@ function PlayerControls() {
|
|
|
3326
3348
|
disabled: !isReady,
|
|
3327
3349
|
onClick: handlePlayPauseAction,
|
|
3328
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",
|
|
3329
|
-
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" })
|
|
3330
3352
|
}
|
|
3331
3353
|
),
|
|
3332
|
-
/* @__PURE__ */
|
|
3354
|
+
/* @__PURE__ */ jsx42(
|
|
3333
3355
|
"button",
|
|
3334
3356
|
{
|
|
3335
3357
|
type: "button",
|
|
@@ -3338,14 +3360,14 @@ function PlayerControls() {
|
|
|
3338
3360
|
disabled: !isReady || !hasNextTrack,
|
|
3339
3361
|
onClick: playNextTrack,
|
|
3340
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",
|
|
3341
|
-
children: /* @__PURE__ */
|
|
3363
|
+
children: /* @__PURE__ */ jsx42(SkipForward, { "aria-hidden": "true", className: "h-4 w-4" })
|
|
3342
3364
|
}
|
|
3343
3365
|
)
|
|
3344
3366
|
] }),
|
|
3345
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: [
|
|
3346
|
-
volume === 0 ? /* @__PURE__ */
|
|
3347
|
-
/* @__PURE__ */
|
|
3348
|
-
/* @__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(
|
|
3349
3371
|
"input",
|
|
3350
3372
|
{
|
|
3351
3373
|
"aria-label": "Volume",
|
|
@@ -3367,7 +3389,7 @@ function PlayerControls() {
|
|
|
3367
3389
|
}
|
|
3368
3390
|
|
|
3369
3391
|
// src/genre-tree/PlayerPanel.tsx
|
|
3370
|
-
import { jsx as
|
|
3392
|
+
import { jsx as jsx43, jsxs as jsxs30 } from "react/jsx-runtime";
|
|
3371
3393
|
var PANEL_ID = "player-panel";
|
|
3372
3394
|
var DEFAULT_EXTENDED_WIDTH = "calc(100vw - var(--layout-center-left) - var(--layout-gutter))";
|
|
3373
3395
|
function PlayerPanel({
|
|
@@ -3420,7 +3442,7 @@ function PlayerPanel({
|
|
|
3420
3442
|
),
|
|
3421
3443
|
style: isExtended ? { width: extendedWidth } : void 0,
|
|
3422
3444
|
children: [
|
|
3423
|
-
/* @__PURE__ */
|
|
3445
|
+
/* @__PURE__ */ jsx43(
|
|
3424
3446
|
PanelEdgeTab,
|
|
3425
3447
|
{
|
|
3426
3448
|
side: "right",
|
|
@@ -3439,19 +3461,19 @@ function PlayerPanel({
|
|
|
3439
3461
|
),
|
|
3440
3462
|
children: [
|
|
3441
3463
|
/* @__PURE__ */ jsxs30("div", { className: "flex w-[var(--layout-right-w)] shrink-0 flex-col", children: [
|
|
3442
|
-
/* @__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 }) }),
|
|
3443
3465
|
/* @__PURE__ */ jsxs30("div", { className: "relative w-full shrink-0", children: [
|
|
3444
|
-
/* @__PURE__ */
|
|
3466
|
+
/* @__PURE__ */ jsx43(PlayerVideoSurface, { className: "aspect-video w-full bg-black" }),
|
|
3445
3467
|
playerTrackObject?.loadError && /* @__PURE__ */ jsxs30("span", { className: "absolute bottom-2 left-2 right-2 text-xs text-red-400", children: [
|
|
3446
3468
|
playerTrackObject.loadError,
|
|
3447
|
-
/* @__PURE__ */
|
|
3469
|
+
/* @__PURE__ */ jsx43("button", { type: "button", className: "ml-2 underline", onClick: () => {
|
|
3448
3470
|
void retryPlayback();
|
|
3449
3471
|
}, children: "Retry" })
|
|
3450
3472
|
] })
|
|
3451
3473
|
] }),
|
|
3452
|
-
/* @__PURE__ */
|
|
3474
|
+
/* @__PURE__ */ jsx43(PlayerControls, {})
|
|
3453
3475
|
] }),
|
|
3454
|
-
/* @__PURE__ */
|
|
3476
|
+
/* @__PURE__ */ jsx43(
|
|
3455
3477
|
TrackListSidebar,
|
|
3456
3478
|
{
|
|
3457
3479
|
layout: "inline",
|
|
@@ -3478,11 +3500,11 @@ function PlayerPanel({
|
|
|
3478
3500
|
import { v4 as uuidv4 } from "uuid";
|
|
3479
3501
|
import { AiFillStar, AiOutlineStar } from "react-icons/ai";
|
|
3480
3502
|
import { FORM_RATING_NULL_VALUE } from "@behindthemusictree/app-kit/genre-tree";
|
|
3481
|
-
import { jsx as
|
|
3503
|
+
import { jsx as jsx44, jsxs as jsxs31 } from "react/jsx-runtime";
|
|
3482
3504
|
function Rating({ rating, handleChange }) {
|
|
3483
3505
|
const instanceId = uuidv4();
|
|
3484
|
-
return /* @__PURE__ */
|
|
3485
|
-
/* @__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(
|
|
3486
3508
|
"input",
|
|
3487
3509
|
{
|
|
3488
3510
|
id: `star-${instanceId}-${i}`,
|
|
@@ -3494,16 +3516,16 @@ function Rating({ rating, handleChange }) {
|
|
|
3494
3516
|
onChange: handleChange
|
|
3495
3517
|
}
|
|
3496
3518
|
),
|
|
3497
|
-
/* @__PURE__ */
|
|
3498
|
-
/* @__PURE__ */
|
|
3519
|
+
/* @__PURE__ */ jsx44("label", { htmlFor: `star-${instanceId}-${i}`, className: "cursor-pointer", children: i === 0 ? /* @__PURE__ */ jsxs31("div", { className: "flex", children: [
|
|
3520
|
+
/* @__PURE__ */ jsx44(
|
|
3499
3521
|
AiOutlineStar,
|
|
3500
3522
|
{
|
|
3501
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)]"}`
|
|
3502
3524
|
}
|
|
3503
3525
|
),
|
|
3504
|
-
/* @__PURE__ */
|
|
3526
|
+
/* @__PURE__ */ jsx44("span", { className: "flex-grow w-8" }),
|
|
3505
3527
|
" "
|
|
3506
|
-
] }) : /* @__PURE__ */
|
|
3528
|
+
] }) : /* @__PURE__ */ jsx44(
|
|
3507
3529
|
AiFillStar,
|
|
3508
3530
|
{
|
|
3509
3531
|
className: `w-7 h-7 absolute top-0 left-0 ${(rating ?? -1) >= i ? "text-[var(--color-accent-rating)]" : "text-[var(--color-text-muted)]"}`
|
|
@@ -3515,7 +3537,7 @@ function Rating({ rating, handleChange }) {
|
|
|
3515
3537
|
// src/genre-tree/EntityDetailPanel.tsx
|
|
3516
3538
|
import { useState as useState12 } from "react";
|
|
3517
3539
|
import { DetailPanel as DetailPanel3 } from "@behindthemusictree/ui";
|
|
3518
|
-
import { Fragment as Fragment16, jsx as
|
|
3540
|
+
import { Fragment as Fragment16, jsx as jsx45, jsxs as jsxs32 } from "react/jsx-runtime";
|
|
3519
3541
|
function EntityDetailPanel({
|
|
3520
3542
|
scope,
|
|
3521
3543
|
getBackendBaseUrl,
|
|
@@ -3538,8 +3560,8 @@ function EntityDetailPanel({
|
|
|
3538
3560
|
getBackendBaseUrl,
|
|
3539
3561
|
getArtistBackendBaseUrl,
|
|
3540
3562
|
getShareUrl,
|
|
3541
|
-
renderArtistLink: renderArtistLink ?? ((artist) => artist.isSpecialPurpose ? artist.name : /* @__PURE__ */
|
|
3542
|
-
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 })),
|
|
3543
3565
|
song: {
|
|
3544
3566
|
uuid: songUuid,
|
|
3545
3567
|
expanded: songUuid !== null && expandedSongUuid === songUuid,
|
|
@@ -3555,7 +3577,7 @@ function EntityDetailPanel({
|
|
|
3555
3577
|
...navigation
|
|
3556
3578
|
});
|
|
3557
3579
|
if (!panel) return null;
|
|
3558
|
-
return /* @__PURE__ */
|
|
3580
|
+
return /* @__PURE__ */ jsx45(
|
|
3559
3581
|
DetailPanel3,
|
|
3560
3582
|
{
|
|
3561
3583
|
side: "left",
|
|
@@ -3601,4 +3623,4 @@ export {
|
|
|
3601
3623
|
GenreTreeViewSkeleton2 as GenreTreeViewSkeleton,
|
|
3602
3624
|
GenreTreeOutlineSkeleton
|
|
3603
3625
|
};
|
|
3604
|
-
//# sourceMappingURL=chunk-
|
|
3626
|
+
//# sourceMappingURL=chunk-GR4PCPCU.js.map
|