@behindthemusictree/app-kit-ui 40.1.0 → 42.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/README.md +1 -1
- package/dist/{chunk-DPYUE6WD.js → chunk-PVYUC2PN.js} +336 -279
- package/dist/chunk-PVYUC2PN.js.map +1 -0
- package/dist/genre-tree/index.cjs +344 -291
- package/dist/genre-tree/index.cjs.map +1 -1
- package/dist/genre-tree/index.d.ts +15 -7
- package/dist/genre-tree/index.js +1 -1
- package/dist/index.cjs +344 -291
- 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,20 +1735,22 @@ 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
|
|
|
1709
1742
|
// src/genre-tree/artist/useArtistPanel.tsx
|
|
1710
1743
|
import { Skeleton as Skeleton5 } from "@behindthemusictree/ui";
|
|
1711
|
-
import {
|
|
1744
|
+
import {
|
|
1745
|
+
useArtist
|
|
1746
|
+
} from "@behindthemusictree/app-kit/genre-tree";
|
|
1712
1747
|
|
|
1713
1748
|
// src/genre-tree/artist/ArtistActionBand.tsx
|
|
1714
1749
|
import { Pause as Pause2, Play as Play2 } from "lucide-react";
|
|
1715
1750
|
import { ActionBand as ActionBand2, ActionButton as ActionButton4, PanelBleed as PanelBleed2 } from "@behindthemusictree/ui";
|
|
1716
1751
|
import { TrackListOriginType as TrackListOriginType2, useTrackList as useTrackList3 } from "@behindthemusictree/app-kit/genre-tree";
|
|
1717
1752
|
import { usePlayer as usePlayer6 } from "@behindthemusictree/app-kit/player";
|
|
1718
|
-
import { jsx as
|
|
1753
|
+
import { jsx as jsx27, jsxs as jsxs18 } from "react/jsx-runtime";
|
|
1719
1754
|
function ArtistActionBand({ artist, share }) {
|
|
1720
1755
|
const { trackList, playNewTrackListFromArtist } = useTrackList3();
|
|
1721
1756
|
const { isPlaying, setIsPlaying } = usePlayer6();
|
|
@@ -1731,11 +1766,11 @@ function ArtistActionBand({ artist, share }) {
|
|
|
1731
1766
|
console.error("Failed to load artist tracks:", error);
|
|
1732
1767
|
});
|
|
1733
1768
|
};
|
|
1734
|
-
return /* @__PURE__ */
|
|
1735
|
-
/* @__PURE__ */
|
|
1769
|
+
return /* @__PURE__ */ jsx27(PanelBleed2, { children: /* @__PURE__ */ jsxs18(ActionBand2, { children: [
|
|
1770
|
+
/* @__PURE__ */ jsx27(
|
|
1736
1771
|
ActionButton4,
|
|
1737
1772
|
{
|
|
1738
|
-
icon: playing ? /* @__PURE__ */
|
|
1773
|
+
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
1774
|
label: playing ? "Pause" : "Play",
|
|
1740
1775
|
caption: String(artist.playableTracksCount),
|
|
1741
1776
|
disabled: artist.playableTracksCount === 0,
|
|
@@ -1763,7 +1798,7 @@ import {
|
|
|
1763
1798
|
SiYoutube
|
|
1764
1799
|
} from "react-icons/si";
|
|
1765
1800
|
import { Chip } from "@behindthemusictree/ui";
|
|
1766
|
-
import { jsx as
|
|
1801
|
+
import { jsx as jsx28 } from "react/jsx-runtime";
|
|
1767
1802
|
var LINK_KINDS = {
|
|
1768
1803
|
official: { label: "Official website", Icon: Globe },
|
|
1769
1804
|
wikipedia: { label: "Wikipedia", Icon: SiWikipedia2 },
|
|
@@ -1800,7 +1835,7 @@ function artistLinks(artist) {
|
|
|
1800
1835
|
return links;
|
|
1801
1836
|
}
|
|
1802
1837
|
function ArtistLinks({ links }) {
|
|
1803
|
-
return /* @__PURE__ */
|
|
1838
|
+
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
1839
|
}
|
|
1805
1840
|
|
|
1806
1841
|
// src/genre-tree/artist/formatYears.ts
|
|
@@ -1811,45 +1846,59 @@ function formatYears(beginYear, endYear, ended) {
|
|
|
1811
1846
|
}
|
|
1812
1847
|
|
|
1813
1848
|
// src/genre-tree/artist/ArtistHeader.tsx
|
|
1814
|
-
import { jsx as
|
|
1849
|
+
import { Fragment as Fragment12, jsx as jsx29, jsxs as jsxs19 } from "react/jsx-runtime";
|
|
1815
1850
|
var countryNames = new Intl.DisplayNames(["en"], { type: "region" });
|
|
1816
|
-
function
|
|
1851
|
+
function originLabel(artist, origin) {
|
|
1852
|
+
if (origin.source === "area") return "From";
|
|
1853
|
+
if (artist.type === "person") return "Born in";
|
|
1854
|
+
if (artist.type === "group") return "Formed in";
|
|
1855
|
+
return "From";
|
|
1856
|
+
}
|
|
1857
|
+
function OriginValue({
|
|
1858
|
+
origin,
|
|
1859
|
+
country,
|
|
1860
|
+
renderPlaceLink
|
|
1861
|
+
}) {
|
|
1862
|
+
const place = renderPlaceLink && origin.regionId !== null ? renderPlaceLink({ ...origin, regionId: origin.regionId }) : origin.name;
|
|
1863
|
+
return /* @__PURE__ */ jsxs19(Fragment12, { children: [
|
|
1864
|
+
place,
|
|
1865
|
+
country && origin.kind !== "country" && `, ${country}`
|
|
1866
|
+
] });
|
|
1867
|
+
}
|
|
1868
|
+
function ArtistHeader({
|
|
1869
|
+
artist,
|
|
1870
|
+
renderPlaceLink
|
|
1871
|
+
}) {
|
|
1817
1872
|
const fields = [];
|
|
1818
1873
|
if (artist.type) fields.push({ label: "Type", value: artist.type.charAt(0).toUpperCase() + artist.type.slice(1) });
|
|
1819
|
-
const country = artist.country
|
|
1820
|
-
if (
|
|
1874
|
+
const country = artist.country ? countryNames.of(artist.country) : void 0;
|
|
1875
|
+
if (artist.origin) {
|
|
1876
|
+
fields.push({
|
|
1877
|
+
label: originLabel(artist, artist.origin),
|
|
1878
|
+
value: /* @__PURE__ */ jsx29(OriginValue, { origin: artist.origin, country, renderPlaceLink })
|
|
1879
|
+
});
|
|
1880
|
+
}
|
|
1881
|
+
if (country && !artist.origin) fields.push({ label: "Country", value: country });
|
|
1821
1882
|
const years = formatYears(artist.beginYear, artist.endYear, artist.ended);
|
|
1822
1883
|
if (years) fields.push({ label: "Active", value: years });
|
|
1823
1884
|
const links = artistLinks(artist);
|
|
1824
|
-
if (links.length > 0) fields.push({ label: "Links", value: /* @__PURE__ */
|
|
1885
|
+
if (links.length > 0) fields.push({ label: "Links", value: /* @__PURE__ */ jsx29(ArtistLinks, { links }) });
|
|
1825
1886
|
if (fields.length === 0) return null;
|
|
1826
|
-
return /* @__PURE__ */
|
|
1887
|
+
return /* @__PURE__ */ jsx29(FieldList, { items: fields });
|
|
1827
1888
|
}
|
|
1828
1889
|
|
|
1829
1890
|
// 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
|
-
}
|
|
1891
|
+
import { jsx as jsx30 } from "react/jsx-runtime";
|
|
1834
1892
|
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
|
-
] });
|
|
1893
|
+
return /* @__PURE__ */ jsx30(CommonsPhoto, { image, alt: name });
|
|
1845
1894
|
}
|
|
1846
1895
|
|
|
1847
1896
|
// src/genre-tree/artist/ArtistMembers.tsx
|
|
1848
1897
|
import { PanelGroup, PanelSection as PanelSection3 } from "@behindthemusictree/ui";
|
|
1849
|
-
import { jsx as
|
|
1898
|
+
import { jsx as jsx31, jsxs as jsxs20 } from "react/jsx-runtime";
|
|
1850
1899
|
function MembershipList({ title, memberships, renderArtistLink }) {
|
|
1851
1900
|
if (memberships.length === 0) return null;
|
|
1852
|
-
return /* @__PURE__ */
|
|
1901
|
+
return /* @__PURE__ */ jsx31(PanelGroup, { title, children: /* @__PURE__ */ jsx31("ul", { children: memberships.map((membership, index) => {
|
|
1853
1902
|
const details = [
|
|
1854
1903
|
formatYears(membership.beginYear, membership.endYear, membership.ended),
|
|
1855
1904
|
...membership.roles
|
|
@@ -1857,9 +1906,9 @@ function MembershipList({ title, memberships, renderArtistLink }) {
|
|
|
1857
1906
|
const detailsText = details.filter(Boolean).join(" \xB7 ");
|
|
1858
1907
|
return (
|
|
1859
1908
|
// A member can have several periods in the same group.
|
|
1860
|
-
/* @__PURE__ */
|
|
1861
|
-
/* @__PURE__ */
|
|
1862
|
-
detailsText && /* @__PURE__ */
|
|
1909
|
+
/* @__PURE__ */ jsxs20("li", { className: "truncate py-0.5", title: detailsText || void 0, children: [
|
|
1910
|
+
/* @__PURE__ */ jsx31("span", { className: "font-medium text-[var(--color-text)]", children: renderArtistLink(membership.artist) }),
|
|
1911
|
+
detailsText && /* @__PURE__ */ jsxs20("span", { className: "text-[var(--color-text-muted)]", children: [
|
|
1863
1912
|
" \u2014 ",
|
|
1864
1913
|
detailsText
|
|
1865
1914
|
] })
|
|
@@ -1870,9 +1919,9 @@ function MembershipList({ title, memberships, renderArtistLink }) {
|
|
|
1870
1919
|
function ArtistMembers({ title, memberships, renderArtistLink }) {
|
|
1871
1920
|
if (memberships.length === 0) return null;
|
|
1872
1921
|
const isCurrent = (membership) => !membership.ended && membership.endYear === null;
|
|
1873
|
-
return /* @__PURE__ */
|
|
1874
|
-
/* @__PURE__ */
|
|
1875
|
-
/* @__PURE__ */
|
|
1922
|
+
return /* @__PURE__ */ jsxs20(PanelSection3, { title, children: [
|
|
1923
|
+
/* @__PURE__ */ jsx31(MembershipList, { title: "Current", memberships: memberships.filter(isCurrent), renderArtistLink }),
|
|
1924
|
+
/* @__PURE__ */ jsx31(
|
|
1876
1925
|
MembershipList,
|
|
1877
1926
|
{
|
|
1878
1927
|
title: "Past",
|
|
@@ -1885,7 +1934,7 @@ function ArtistMembers({ title, memberships, renderArtistLink }) {
|
|
|
1885
1934
|
|
|
1886
1935
|
// src/genre-tree/artist/ArtistDiscography.tsx
|
|
1887
1936
|
import { PanelGroup as PanelGroup2, PanelSection as PanelSection4 } from "@behindthemusictree/ui";
|
|
1888
|
-
import { jsx as
|
|
1937
|
+
import { jsx as jsx32, jsxs as jsxs21 } from "react/jsx-runtime";
|
|
1889
1938
|
var GROUPS = ["Albums", "EPs", "Singles", "Live", "Compilations", "Other"];
|
|
1890
1939
|
var PRIMARY_GROUPS = { album: "Albums", ep: "EPs", single: "Singles" };
|
|
1891
1940
|
function discographyGroup({ primaryType, secondaryTypes }) {
|
|
@@ -1905,12 +1954,12 @@ function byYear(a, b) {
|
|
|
1905
1954
|
function ArtistDiscography({ albums }) {
|
|
1906
1955
|
if (albums.length === 0) return null;
|
|
1907
1956
|
const sorted = [...albums].sort(byYear);
|
|
1908
|
-
return /* @__PURE__ */
|
|
1957
|
+
return /* @__PURE__ */ jsx32(PanelSection4, { title: "Discography", children: GROUPS.map((group) => {
|
|
1909
1958
|
const groupAlbums = sorted.filter((album) => discographyGroup(album) === group);
|
|
1910
1959
|
if (groupAlbums.length === 0) return null;
|
|
1911
|
-
return /* @__PURE__ */
|
|
1912
|
-
/* @__PURE__ */
|
|
1913
|
-
/* @__PURE__ */
|
|
1960
|
+
return /* @__PURE__ */ jsx32(PanelGroup2, { title: group, children: /* @__PURE__ */ jsx32("ul", { children: groupAlbums.map((album) => /* @__PURE__ */ jsxs21("li", { className: "grid grid-cols-[2.5rem_minmax(0,1fr)] gap-2 py-0.5", children: [
|
|
1961
|
+
/* @__PURE__ */ jsx32("span", { className: "tabular-nums text-[var(--color-text-muted)]", children: album.year ?? "\u2014" }),
|
|
1962
|
+
/* @__PURE__ */ jsx32("span", { className: "truncate text-[var(--color-text)]", title: album.name, children: album.name })
|
|
1914
1963
|
] }, album.uuid)) }) }, group);
|
|
1915
1964
|
}) });
|
|
1916
1965
|
}
|
|
@@ -1936,7 +1985,7 @@ import { useTrackList as useTrackList4 } from "@behindthemusictree/app-kit/genre
|
|
|
1936
1985
|
import { FaPlay as FaPlay2, FaPause as FaPause2 } from "react-icons/fa";
|
|
1937
1986
|
import { usePlayer as usePlayer7 } from "@behindthemusictree/app-kit/player";
|
|
1938
1987
|
import { PlayStates as PlayStates2 } from "@behindthemusictree/app-kit/player";
|
|
1939
|
-
import { jsx as
|
|
1988
|
+
import { jsx as jsx33, jsxs as jsxs22 } from "react/jsx-runtime";
|
|
1940
1989
|
function TrackPositionPlayPause({
|
|
1941
1990
|
position,
|
|
1942
1991
|
uuid,
|
|
@@ -1950,14 +1999,14 @@ function TrackPositionPlayPause({
|
|
|
1950
1999
|
const isPlaying = isThisTrack && isConfirmedPlayable && playState === PlayStates2.PLAYING;
|
|
1951
2000
|
const isPaused = isThisTrack && isConfirmedPlayable && playState === PlayStates2.PAUSED;
|
|
1952
2001
|
const isCurrentTrackActive = isPlaying || isPaused;
|
|
1953
|
-
return /* @__PURE__ */
|
|
2002
|
+
return /* @__PURE__ */ jsxs22(
|
|
1954
2003
|
"div",
|
|
1955
2004
|
{
|
|
1956
2005
|
className: "track-position-play-pause relative flex items-center justify-center gap-2 text-lg w-16 cursor-pointer",
|
|
1957
2006
|
style: { minWidth: "4rem", maxWidth: "4rem" },
|
|
1958
2007
|
onClick: handlePlayPauseClick,
|
|
1959
2008
|
children: [
|
|
1960
|
-
/* @__PURE__ */
|
|
2009
|
+
/* @__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__ */ jsxs22(
|
|
1961
2010
|
"span",
|
|
1962
2011
|
{
|
|
1963
2012
|
className: "track-position-play-pause__bars",
|
|
@@ -1965,18 +2014,18 @@ function TrackPositionPlayPause({
|
|
|
1965
2014
|
role: "img",
|
|
1966
2015
|
"aria-label": isPlaying ? "Playing" : "Paused",
|
|
1967
2016
|
children: [
|
|
1968
|
-
/* @__PURE__ */
|
|
1969
|
-
/* @__PURE__ */
|
|
1970
|
-
/* @__PURE__ */
|
|
2017
|
+
/* @__PURE__ */ jsx33("span", { className: "track-position-play-pause__bar" }),
|
|
2018
|
+
/* @__PURE__ */ jsx33("span", { className: "track-position-play-pause__bar" }),
|
|
2019
|
+
/* @__PURE__ */ jsx33("span", { className: "track-position-play-pause__bar" })
|
|
1971
2020
|
]
|
|
1972
2021
|
}
|
|
1973
2022
|
) : position }),
|
|
1974
|
-
/* @__PURE__ */
|
|
2023
|
+
/* @__PURE__ */ jsx33(
|
|
1975
2024
|
"div",
|
|
1976
2025
|
{
|
|
1977
2026
|
className: `hidden group-hover:flex items-center justify-center ${isCurrentTrackActive ? "" : "absolute inset-0"}`,
|
|
1978
2027
|
"aria-hidden": "true",
|
|
1979
|
-
children: isAwaitingPlayback ? /* @__PURE__ */
|
|
2028
|
+
children: isAwaitingPlayback ? /* @__PURE__ */ jsx33("span", { className: "track-position-play-pause__spinner" }) : isPlaying ? /* @__PURE__ */ jsx33(FaPause2, {}) : /* @__PURE__ */ jsx33(FaPlay2, {})
|
|
1980
2029
|
}
|
|
1981
2030
|
)
|
|
1982
2031
|
]
|
|
@@ -1987,7 +2036,7 @@ function TrackPositionPlayPause({
|
|
|
1987
2036
|
// src/genre-tree/track-list-sidebar/TrackItem.tsx
|
|
1988
2037
|
import { isSong as isSong2, songUnplayableReason as songUnplayableReason2 } from "@behindthemusictree/app-kit/genre-tree";
|
|
1989
2038
|
import { ArtistNames as ArtistNames2 } from "@behindthemusictree/app-kit/genre-tree";
|
|
1990
|
-
import { jsx as
|
|
2039
|
+
import { jsx as jsx34, jsxs as jsxs23 } from "react/jsx-runtime";
|
|
1991
2040
|
function TrackItem({
|
|
1992
2041
|
track,
|
|
1993
2042
|
position,
|
|
@@ -2011,12 +2060,12 @@ function TrackItem({
|
|
|
2011
2060
|
loadTrackForPlayer(track.uuid);
|
|
2012
2061
|
}
|
|
2013
2062
|
};
|
|
2014
|
-
return /* @__PURE__ */
|
|
2063
|
+
return /* @__PURE__ */ jsxs23(
|
|
2015
2064
|
"div",
|
|
2016
2065
|
{
|
|
2017
2066
|
className: `track-item flex h-14 text-[var(--color-text)] ${isUnplayable ? "opacity-50" : "hover:bg-[var(--color-surface-muted)] group"}`,
|
|
2018
2067
|
children: [
|
|
2019
|
-
isUnplayable ? /* @__PURE__ */
|
|
2068
|
+
isUnplayable ? /* @__PURE__ */ jsx34(
|
|
2020
2069
|
"div",
|
|
2021
2070
|
{
|
|
2022
2071
|
className: "flex items-center justify-center text-lg w-16",
|
|
@@ -2024,7 +2073,7 @@ function TrackItem({
|
|
|
2024
2073
|
"aria-disabled": "true",
|
|
2025
2074
|
children: position
|
|
2026
2075
|
}
|
|
2027
|
-
) : /* @__PURE__ */
|
|
2076
|
+
) : /* @__PURE__ */ jsx34(
|
|
2028
2077
|
TrackPositionPlayPause,
|
|
2029
2078
|
{
|
|
2030
2079
|
position,
|
|
@@ -2033,12 +2082,12 @@ function TrackItem({
|
|
|
2033
2082
|
isSelected: selectedTrack?.uuid === track.uuid
|
|
2034
2083
|
}
|
|
2035
2084
|
),
|
|
2036
|
-
/* @__PURE__ */
|
|
2037
|
-
/* @__PURE__ */
|
|
2038
|
-
track.artists && track.artists.length > 0 ? /* @__PURE__ */
|
|
2085
|
+
/* @__PURE__ */ jsxs23("div", { className: "title-artist-container flex flex-col items-start justify-center min-w-0 flex-1", children: [
|
|
2086
|
+
/* @__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 }) }),
|
|
2087
|
+
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
2088
|
] }),
|
|
2040
|
-
/* @__PURE__ */
|
|
2041
|
-
renderDuration && /* @__PURE__ */
|
|
2089
|
+
/* @__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 }) : "" }),
|
|
2090
|
+
renderDuration && /* @__PURE__ */ jsx34(
|
|
2042
2091
|
"div",
|
|
2043
2092
|
{
|
|
2044
2093
|
className: "duration flex text-base w-16 items-center justify-center",
|
|
@@ -2046,14 +2095,14 @@ function TrackItem({
|
|
|
2046
2095
|
children: renderDuration(track)
|
|
2047
2096
|
}
|
|
2048
2097
|
),
|
|
2049
|
-
renderActions && /* @__PURE__ */
|
|
2098
|
+
renderActions && /* @__PURE__ */ jsx34("div", { className: "edit flex text-base w-6 items-center justify-center mr-2 cursor-pointer", children: renderActions(track) })
|
|
2050
2099
|
]
|
|
2051
2100
|
}
|
|
2052
2101
|
);
|
|
2053
2102
|
}
|
|
2054
2103
|
|
|
2055
2104
|
// src/genre-tree/artist/ArtistSongs.tsx
|
|
2056
|
-
import { Fragment as
|
|
2105
|
+
import { Fragment as Fragment13, jsx as jsx35, jsxs as jsxs24 } from "react/jsx-runtime";
|
|
2057
2106
|
var SongPageSchema2 = PaginatedResponseSchema2(SongDetailedSchema2);
|
|
2058
2107
|
var SORTS = [
|
|
2059
2108
|
{ ordering: "title", label: "Title" },
|
|
@@ -2086,8 +2135,8 @@ function ArtistSongs({ artist, getBackendBaseUrl, renderArtistLink, renderSongLi
|
|
|
2086
2135
|
event.stopPropagation();
|
|
2087
2136
|
void play(song.uuid);
|
|
2088
2137
|
};
|
|
2089
|
-
return /* @__PURE__ */
|
|
2090
|
-
/* @__PURE__ */
|
|
2138
|
+
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__ */ jsxs24(Fragment13, { children: [
|
|
2139
|
+
/* @__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
2140
|
"button",
|
|
2092
2141
|
{
|
|
2093
2142
|
type: "button",
|
|
@@ -2101,7 +2150,7 @@ function ArtistSongs({ artist, getBackendBaseUrl, renderArtistLink, renderSongLi
|
|
|
2101
2150
|
},
|
|
2102
2151
|
sort.ordering
|
|
2103
2152
|
)) }) }),
|
|
2104
|
-
/* @__PURE__ */
|
|
2153
|
+
/* @__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
2154
|
TrackItem,
|
|
2106
2155
|
{
|
|
2107
2156
|
track: song,
|
|
@@ -2110,12 +2159,12 @@ function ArtistSongs({ artist, getBackendBaseUrl, renderArtistLink, renderSongLi
|
|
|
2110
2159
|
renderSongLink
|
|
2111
2160
|
}
|
|
2112
2161
|
) }, song.uuid)) }),
|
|
2113
|
-
/* @__PURE__ */
|
|
2162
|
+
/* @__PURE__ */ jsx35(Pagination, { currentPage: page, totalPages: data.totalPages, onPageChange: setPage })
|
|
2114
2163
|
] }) });
|
|
2115
2164
|
}
|
|
2116
2165
|
|
|
2117
2166
|
// src/genre-tree/artist/useArtistPanel.tsx
|
|
2118
|
-
import { Fragment as
|
|
2167
|
+
import { Fragment as Fragment14, jsx as jsx36, jsxs as jsxs25 } from "react/jsx-runtime";
|
|
2119
2168
|
function useArtistPanel({
|
|
2120
2169
|
uuid,
|
|
2121
2170
|
scope,
|
|
@@ -2123,6 +2172,7 @@ function useArtistPanel({
|
|
|
2123
2172
|
getShareUrl,
|
|
2124
2173
|
renderArtistLink,
|
|
2125
2174
|
renderSongLink,
|
|
2175
|
+
renderPlaceLink,
|
|
2126
2176
|
expanded,
|
|
2127
2177
|
onExpandedChange,
|
|
2128
2178
|
onClose
|
|
@@ -2136,26 +2186,26 @@ function useArtistPanel({
|
|
|
2136
2186
|
return {
|
|
2137
2187
|
...panel,
|
|
2138
2188
|
title: "Artist",
|
|
2139
|
-
content: /* @__PURE__ */
|
|
2140
|
-
/* @__PURE__ */
|
|
2141
|
-
/* @__PURE__ */
|
|
2142
|
-
/* @__PURE__ */
|
|
2143
|
-
/* @__PURE__ */
|
|
2144
|
-
/* @__PURE__ */
|
|
2145
|
-
/* @__PURE__ */
|
|
2189
|
+
content: /* @__PURE__ */ jsxs25("div", { "aria-busy": "true", className: "flex flex-col gap-2.5", children: [
|
|
2190
|
+
/* @__PURE__ */ jsx36(Skeleton5, { className: "h-3 w-16" }),
|
|
2191
|
+
/* @__PURE__ */ jsx36(Skeleton5, { className: "h-4 w-32" }),
|
|
2192
|
+
/* @__PURE__ */ jsx36(Skeleton5, { className: "h-3 w-16" }),
|
|
2193
|
+
/* @__PURE__ */ jsx36(Skeleton5, { className: "h-4 w-24" }),
|
|
2194
|
+
/* @__PURE__ */ jsx36(Skeleton5, { className: "h-16 mt-2.5" }),
|
|
2195
|
+
/* @__PURE__ */ jsx36(Skeleton5, { className: "h-16" })
|
|
2146
2196
|
] })
|
|
2147
2197
|
};
|
|
2148
2198
|
case "not-found":
|
|
2149
2199
|
return {
|
|
2150
2200
|
...panel,
|
|
2151
2201
|
title: "Artist not found",
|
|
2152
|
-
content: /* @__PURE__ */
|
|
2202
|
+
content: /* @__PURE__ */ jsx36("p", { className: "text-[var(--color-text-muted)]", children: "This artist does not exist." })
|
|
2153
2203
|
};
|
|
2154
2204
|
case "error":
|
|
2155
2205
|
return {
|
|
2156
2206
|
...panel,
|
|
2157
2207
|
title: "Artist",
|
|
2158
|
-
content: /* @__PURE__ */
|
|
2208
|
+
content: /* @__PURE__ */ jsx36("p", { className: "text-red-600", children: "Could not load this artist." })
|
|
2159
2209
|
};
|
|
2160
2210
|
case "success": {
|
|
2161
2211
|
const { artist } = result;
|
|
@@ -2164,19 +2214,19 @@ function useArtistPanel({
|
|
|
2164
2214
|
return {
|
|
2165
2215
|
...panel,
|
|
2166
2216
|
title: artist.name,
|
|
2167
|
-
content: /* @__PURE__ */
|
|
2168
|
-
/* @__PURE__ */
|
|
2217
|
+
content: /* @__PURE__ */ jsxs25(Fragment14, { children: [
|
|
2218
|
+
/* @__PURE__ */ jsx36(
|
|
2169
2219
|
ArtistActionBand,
|
|
2170
2220
|
{
|
|
2171
2221
|
artist,
|
|
2172
|
-
share: shareTarget && shareUrl ? /* @__PURE__ */
|
|
2222
|
+
share: shareTarget && shareUrl ? /* @__PURE__ */ jsx36(ShareActionButton, { target: shareTarget, url: shareUrl }) : void 0
|
|
2173
2223
|
}
|
|
2174
2224
|
),
|
|
2175
|
-
artist.image && /* @__PURE__ */
|
|
2176
|
-
/* @__PURE__ */
|
|
2177
|
-
/* @__PURE__ */
|
|
2178
|
-
/* @__PURE__ */
|
|
2179
|
-
artist.tracksCount > 0 && /* @__PURE__ */
|
|
2225
|
+
artist.image && /* @__PURE__ */ jsx36(ArtistPhoto, { image: artist.image, name: artist.name }),
|
|
2226
|
+
/* @__PURE__ */ jsx36(ArtistHeader, { artist, renderPlaceLink }),
|
|
2227
|
+
/* @__PURE__ */ jsx36(ArtistMembers, { title: "Members", memberships: artist.members, renderArtistLink }),
|
|
2228
|
+
/* @__PURE__ */ jsx36(ArtistMembers, { title: "Member of", memberships: artist.memberOf, renderArtistLink }),
|
|
2229
|
+
artist.tracksCount > 0 && /* @__PURE__ */ jsx36(
|
|
2180
2230
|
ArtistSongs,
|
|
2181
2231
|
{
|
|
2182
2232
|
artist: { uuid: artist.uuid, name: artist.name },
|
|
@@ -2186,7 +2236,7 @@ function useArtistPanel({
|
|
|
2186
2236
|
}
|
|
2187
2237
|
)
|
|
2188
2238
|
] }),
|
|
2189
|
-
extraContent: artist.albums.length > 0 ? /* @__PURE__ */
|
|
2239
|
+
extraContent: artist.albums.length > 0 ? /* @__PURE__ */ jsx36(ArtistDiscography, { albums: artist.albums }) : void 0
|
|
2190
2240
|
};
|
|
2191
2241
|
}
|
|
2192
2242
|
}
|
|
@@ -2210,7 +2260,7 @@ import {
|
|
|
2210
2260
|
useSongHistory,
|
|
2211
2261
|
useTrackList as useTrackList6
|
|
2212
2262
|
} from "@behindthemusictree/app-kit/genre-tree";
|
|
2213
|
-
import { Fragment as
|
|
2263
|
+
import { Fragment as Fragment15, jsx as jsx37, jsxs as jsxs26 } from "react/jsx-runtime";
|
|
2214
2264
|
var numberFormat = new Intl.NumberFormat("en");
|
|
2215
2265
|
var dateFormat = new Intl.DateTimeFormat("en", { dateStyle: "medium" });
|
|
2216
2266
|
var externalLink = "text-[var(--color-primary)] hover:underline focus-visible:underline";
|
|
@@ -2218,27 +2268,27 @@ function SongHistory({ uuid, getBackendBaseUrl }) {
|
|
|
2218
2268
|
const [open, setOpen] = useState9(false);
|
|
2219
2269
|
const history = useSongHistory(uuid, getBackendBaseUrl, open);
|
|
2220
2270
|
let body = null;
|
|
2221
|
-
if (history.status === "loading") body = /* @__PURE__ */
|
|
2222
|
-
else if (history.status === "error") body = /* @__PURE__ */
|
|
2271
|
+
if (history.status === "loading") body = /* @__PURE__ */ jsx37(Skeleton6, { className: "h-10", "aria-busy": "true" });
|
|
2272
|
+
else if (history.status === "error") body = /* @__PURE__ */ jsx37("p", { className: "text-red-600", children: "Could not load the history." });
|
|
2223
2273
|
else if (history.status === "success")
|
|
2224
|
-
body = history.entries.length === 0 ? /* @__PURE__ */
|
|
2225
|
-
/* @__PURE__ */
|
|
2226
|
-
entry.oldValue !== null || entry.newValue !== null ? /* @__PURE__ */
|
|
2274
|
+
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__ */ jsxs26("li", { className: "py-1.5 text-body", children: [
|
|
2275
|
+
/* @__PURE__ */ jsx37("span", { className: "font-medium", children: entry.action }),
|
|
2276
|
+
entry.oldValue !== null || entry.newValue !== null ? /* @__PURE__ */ jsxs26("span", { className: "text-[var(--color-text-muted)]", children: [
|
|
2227
2277
|
" ",
|
|
2228
2278
|
"\u2014 ",
|
|
2229
2279
|
entry.oldValue ?? "none",
|
|
2230
2280
|
" \u2192 ",
|
|
2231
2281
|
entry.newValue ?? "none"
|
|
2232
2282
|
] }) : null,
|
|
2233
|
-
/* @__PURE__ */
|
|
2283
|
+
/* @__PURE__ */ jsxs26("span", { className: "block text-caption text-[var(--color-text-muted)]", children: [
|
|
2234
2284
|
entry.actorPseudo ?? "Anonymous",
|
|
2235
2285
|
" \xB7 ",
|
|
2236
2286
|
dateFormat.format(new Date(entry.createdOn))
|
|
2237
2287
|
] })
|
|
2238
2288
|
] }, entry.uuid)) });
|
|
2239
|
-
return /* @__PURE__ */
|
|
2240
|
-
/* @__PURE__ */
|
|
2241
|
-
/* @__PURE__ */
|
|
2289
|
+
return /* @__PURE__ */ jsx37(PanelBleed3, { padded: true, className: "border-t border-[var(--color-border)]", children: /* @__PURE__ */ jsxs26("details", { onToggle: (event) => setOpen(event.currentTarget.open), className: "pb-2.5", children: [
|
|
2290
|
+
/* @__PURE__ */ jsx37("summary", { className: `mt-2.5 cursor-pointer ${PANEL_LABEL_CLASS}`, children: "History" }),
|
|
2291
|
+
/* @__PURE__ */ jsx37("div", { className: "mt-1.5", children: body })
|
|
2242
2292
|
] }) });
|
|
2243
2293
|
}
|
|
2244
2294
|
function SongPanelContent(props) {
|
|
@@ -2257,13 +2307,13 @@ function SongPanelContent(props) {
|
|
|
2257
2307
|
const genre = song.genre;
|
|
2258
2308
|
fields.push({
|
|
2259
2309
|
label: "Genre",
|
|
2260
|
-
value: onSelectGenre ? /* @__PURE__ */
|
|
2261
|
-
index > 0 && /* @__PURE__ */
|
|
2262
|
-
/* @__PURE__ */
|
|
2310
|
+
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__ */ jsxs26("span", { children: [
|
|
2311
|
+
index > 0 && /* @__PURE__ */ jsx37("span", { "aria-hidden": "true", children: "\u203A " }),
|
|
2312
|
+
/* @__PURE__ */ jsx37("button", { type: "button", onClick: () => props.onSelectGenrePlaylist?.(genrePlaylist), className: "hover:underline", children: genrePlaylist.name })
|
|
2263
2313
|
] }, genrePlaylist.uuid)) }) : song.genre.name
|
|
2264
2314
|
});
|
|
2265
2315
|
} else {
|
|
2266
|
-
fields.push({ label: "Genre", value: /* @__PURE__ */
|
|
2316
|
+
fields.push({ label: "Genre", value: /* @__PURE__ */ jsx37("span", { className: "text-[var(--color-text-muted)]", children: "No genre" }) });
|
|
2267
2317
|
}
|
|
2268
2318
|
if (song.firstReleaseYear) fields.push({ label: "First released", value: song.firstReleaseYear });
|
|
2269
2319
|
const viewCount = song.youtubeVideo?.viewCount;
|
|
@@ -2273,11 +2323,11 @@ function SongPanelContent(props) {
|
|
|
2273
2323
|
const links = [];
|
|
2274
2324
|
if (musicBrainzUrl)
|
|
2275
2325
|
links.push(
|
|
2276
|
-
/* @__PURE__ */
|
|
2326
|
+
/* @__PURE__ */ jsx37("a", { href: musicBrainzUrl, target: "_blank", rel: "noopener noreferrer", className: externalLink, children: "MusicBrainz" }, "mb")
|
|
2277
2327
|
);
|
|
2278
2328
|
if (song.youtubeVideo)
|
|
2279
2329
|
links.push(
|
|
2280
|
-
/* @__PURE__ */
|
|
2330
|
+
/* @__PURE__ */ jsx37(
|
|
2281
2331
|
"a",
|
|
2282
2332
|
{
|
|
2283
2333
|
href: `https://www.youtube.com/watch?v=${encodeURIComponent(song.youtubeVideo.id)}`,
|
|
@@ -2292,31 +2342,31 @@ function SongPanelContent(props) {
|
|
|
2292
2342
|
if (links.length > 0)
|
|
2293
2343
|
fields.push({
|
|
2294
2344
|
label: "Links",
|
|
2295
|
-
value: /* @__PURE__ */
|
|
2345
|
+
value: /* @__PURE__ */ jsx37("span", { className: "flex gap-3", children: links })
|
|
2296
2346
|
});
|
|
2297
|
-
return /* @__PURE__ */
|
|
2298
|
-
/* @__PURE__ */
|
|
2299
|
-
/* @__PURE__ */
|
|
2347
|
+
return /* @__PURE__ */ jsxs26(Fragment15, { children: [
|
|
2348
|
+
/* @__PURE__ */ jsx37(PanelBleed3, { children: /* @__PURE__ */ jsxs26(ActionBand3, { children: [
|
|
2349
|
+
/* @__PURE__ */ jsx37(
|
|
2300
2350
|
ActionButton5,
|
|
2301
2351
|
{
|
|
2302
|
-
icon: isPlaying ? /* @__PURE__ */
|
|
2352
|
+
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
2353
|
label: isPlaying ? "Pause" : "Play",
|
|
2304
2354
|
disabled: !!unplayableReason,
|
|
2305
2355
|
title: unplayableReason ?? void 0,
|
|
2306
2356
|
onClick: () => isCurrent ? handlePlayPauseAction() : playNewTrackListFromTrackUuid(song, scope)
|
|
2307
2357
|
}
|
|
2308
2358
|
),
|
|
2309
|
-
shareUrl && /* @__PURE__ */
|
|
2359
|
+
shareUrl && /* @__PURE__ */ jsx37(ShareActionButton, { target: shareTarget, url: shareUrl })
|
|
2310
2360
|
] }) }),
|
|
2311
|
-
song.artists && song.artists.length > 0 && /* @__PURE__ */
|
|
2312
|
-
/* @__PURE__ */
|
|
2313
|
-
song.essentialGenres && song.essentialGenres.length > 0 && /* @__PURE__ */
|
|
2314
|
-
/* @__PURE__ */
|
|
2361
|
+
song.artists && song.artists.length > 0 && /* @__PURE__ */ jsx37("p", { className: "text-[var(--color-text-muted)]", children: /* @__PURE__ */ jsx37(ArtistNames3, { artists: song.artists, renderArtistLink }) }),
|
|
2362
|
+
/* @__PURE__ */ jsx37(FieldList2, { items: fields }),
|
|
2363
|
+
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)) }) }),
|
|
2364
|
+
/* @__PURE__ */ jsx37(SongHistory, { uuid: song.uuid, getBackendBaseUrl })
|
|
2315
2365
|
] });
|
|
2316
2366
|
}
|
|
2317
2367
|
|
|
2318
2368
|
// src/genre-tree/song/useSongPanel.tsx
|
|
2319
|
-
import { jsx as
|
|
2369
|
+
import { jsx as jsx38, jsxs as jsxs27 } from "react/jsx-runtime";
|
|
2320
2370
|
function useSongPanel({
|
|
2321
2371
|
uuid,
|
|
2322
2372
|
scope,
|
|
@@ -2337,24 +2387,24 @@ function useSongPanel({
|
|
|
2337
2387
|
return {
|
|
2338
2388
|
...panel,
|
|
2339
2389
|
title: "Song",
|
|
2340
|
-
content: /* @__PURE__ */
|
|
2341
|
-
/* @__PURE__ */
|
|
2342
|
-
/* @__PURE__ */
|
|
2343
|
-
/* @__PURE__ */
|
|
2344
|
-
/* @__PURE__ */
|
|
2390
|
+
content: /* @__PURE__ */ jsxs27("div", { "aria-busy": "true", className: "flex flex-col gap-2.5", children: [
|
|
2391
|
+
/* @__PURE__ */ jsx38(Skeleton7, { className: "h-3 w-16" }),
|
|
2392
|
+
/* @__PURE__ */ jsx38(Skeleton7, { className: "h-4 w-32" }),
|
|
2393
|
+
/* @__PURE__ */ jsx38(Skeleton7, { className: "h-3 w-16" }),
|
|
2394
|
+
/* @__PURE__ */ jsx38(Skeleton7, { className: "h-4 w-24" })
|
|
2345
2395
|
] })
|
|
2346
2396
|
};
|
|
2347
2397
|
case "not-found":
|
|
2348
2398
|
return {
|
|
2349
2399
|
...panel,
|
|
2350
2400
|
title: "Song not found",
|
|
2351
|
-
content: /* @__PURE__ */
|
|
2401
|
+
content: /* @__PURE__ */ jsx38("p", { className: "text-[var(--color-text-muted)]", children: "This song does not exist." })
|
|
2352
2402
|
};
|
|
2353
2403
|
case "error":
|
|
2354
2404
|
return {
|
|
2355
2405
|
...panel,
|
|
2356
2406
|
title: "Song",
|
|
2357
|
-
content: /* @__PURE__ */
|
|
2407
|
+
content: /* @__PURE__ */ jsx38("p", { className: "text-red-600", children: "Could not load this song." })
|
|
2358
2408
|
};
|
|
2359
2409
|
case "success": {
|
|
2360
2410
|
const { song } = result;
|
|
@@ -2362,7 +2412,7 @@ function useSongPanel({
|
|
|
2362
2412
|
return {
|
|
2363
2413
|
...panel,
|
|
2364
2414
|
title: song.title,
|
|
2365
|
-
content: /* @__PURE__ */
|
|
2415
|
+
content: /* @__PURE__ */ jsx38(
|
|
2366
2416
|
SongPanelContent,
|
|
2367
2417
|
{
|
|
2368
2418
|
song,
|
|
@@ -2389,6 +2439,7 @@ function useEntityPanel({
|
|
|
2389
2439
|
getShareUrl,
|
|
2390
2440
|
renderArtistLink,
|
|
2391
2441
|
renderSongLink,
|
|
2442
|
+
renderPlaceLink,
|
|
2392
2443
|
song,
|
|
2393
2444
|
artist,
|
|
2394
2445
|
...navigation
|
|
@@ -2407,7 +2458,8 @@ function useEntityPanel({
|
|
|
2407
2458
|
getBackendBaseUrl: getArtistBackendBaseUrl ?? getBackendBaseUrl,
|
|
2408
2459
|
getShareUrl,
|
|
2409
2460
|
renderArtistLink,
|
|
2410
|
-
renderSongLink
|
|
2461
|
+
renderSongLink,
|
|
2462
|
+
renderPlaceLink
|
|
2411
2463
|
});
|
|
2412
2464
|
return songPanel ?? artistPanel;
|
|
2413
2465
|
}
|
|
@@ -2415,12 +2467,12 @@ function useEntityPanel({
|
|
|
2415
2467
|
// src/genre-tree/SizeMetricToggle.tsx
|
|
2416
2468
|
import { MdMusicNote, MdVisibility } from "react-icons/md";
|
|
2417
2469
|
import { SegmentedControl } from "@behindthemusictree/ui";
|
|
2418
|
-
import { jsx as
|
|
2470
|
+
import { jsx as jsx39 } from "react/jsx-runtime";
|
|
2419
2471
|
function SizeMetricToggle({
|
|
2420
2472
|
value,
|
|
2421
2473
|
onChange
|
|
2422
2474
|
}) {
|
|
2423
|
-
return /* @__PURE__ */
|
|
2475
|
+
return /* @__PURE__ */ jsx39(
|
|
2424
2476
|
SegmentedControl,
|
|
2425
2477
|
{
|
|
2426
2478
|
variant: "floating",
|
|
@@ -2428,15 +2480,15 @@ function SizeMetricToggle({
|
|
|
2428
2480
|
value,
|
|
2429
2481
|
onChange,
|
|
2430
2482
|
options: [
|
|
2431
|
-
{ value: "songs", label: /* @__PURE__ */
|
|
2432
|
-
{ value: "views", label: /* @__PURE__ */
|
|
2483
|
+
{ value: "songs", label: /* @__PURE__ */ jsx39(MdMusicNote, { size: 18, "aria-hidden": true }), "aria-label": "Size by songs", title: "Node size by song count" },
|
|
2484
|
+
{ value: "views", label: /* @__PURE__ */ jsx39(MdVisibility, { size: 18, "aria-hidden": true }), "aria-label": "Size by views", title: "Node size by song views" }
|
|
2433
2485
|
]
|
|
2434
2486
|
}
|
|
2435
2487
|
);
|
|
2436
2488
|
}
|
|
2437
2489
|
|
|
2438
2490
|
// src/genre-tree/GenreTreeView.tsx
|
|
2439
|
-
import { Fragment as
|
|
2491
|
+
import { Fragment as Fragment16, jsx as jsx40, jsxs as jsxs28 } from "react/jsx-runtime";
|
|
2440
2492
|
var NO_POP_ROOT_TITLE = "This genre tree has no 'Mainstream Pop' root yet";
|
|
2441
2493
|
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
2494
|
var noop = () => {
|
|
@@ -2484,6 +2536,7 @@ function GenreTreeView({
|
|
|
2484
2536
|
songSearch = true,
|
|
2485
2537
|
onSongSelect,
|
|
2486
2538
|
renderSongLink,
|
|
2539
|
+
renderPlaceLink,
|
|
2487
2540
|
renderSummary,
|
|
2488
2541
|
renderEssentialTracks,
|
|
2489
2542
|
renderSongLeading,
|
|
@@ -2588,14 +2641,14 @@ function GenreTreeView({
|
|
|
2588
2641
|
const openSongRef = useRef3(openSong);
|
|
2589
2642
|
openSongRef.current = openSong;
|
|
2590
2643
|
const resolvedRenderSongLink = useCallback6(
|
|
2591
|
-
(song) => renderSongLink ? renderSongLink(song) : /* @__PURE__ */
|
|
2644
|
+
(song) => renderSongLink ? renderSongLink(song) : /* @__PURE__ */ jsx40("button", { type: "button", onClick: () => openSongRef.current(song.uuid), className: "hover:underline", children: song.title }),
|
|
2592
2645
|
[renderSongLink]
|
|
2593
2646
|
);
|
|
2594
2647
|
const [expandedSongUuid, setExpandedSongUuid] = useState10(null);
|
|
2595
2648
|
const [expandedArtistUuid, setExpandedArtistUuid] = useState10(null);
|
|
2596
2649
|
const artistBaseUrl = artistSearchBaseUrl ?? getBackendBaseUrl;
|
|
2597
2650
|
const songBaseUrl = getBackendBaseUrl;
|
|
2598
|
-
const resolvedRenderArtistLink = renderArtistLink ?? ((artist) => artist.isSpecialPurpose ? artist.name : /* @__PURE__ */
|
|
2651
|
+
const resolvedRenderArtistLink = renderArtistLink ?? ((artist) => artist.isSpecialPurpose ? artist.name : /* @__PURE__ */ jsx40("button", { type: "button", onClick: () => openArtist(artist.uuid), className: "hover:underline", children: artist.name }));
|
|
2599
2652
|
const getGenrePath = (genre) => {
|
|
2600
2653
|
const path = [];
|
|
2601
2654
|
let current = visibleGenrePlaylists.find((playlist) => playlist.criteria?.uuid === genre.uuid);
|
|
@@ -2613,6 +2666,7 @@ function GenreTreeView({
|
|
|
2613
2666
|
getShareUrl: getShareUrlRef.current,
|
|
2614
2667
|
renderArtistLink: resolvedRenderArtistLink,
|
|
2615
2668
|
renderSongLink: resolvedRenderSongLink,
|
|
2669
|
+
renderPlaceLink,
|
|
2616
2670
|
song: {
|
|
2617
2671
|
uuid: songUuid,
|
|
2618
2672
|
expanded: controlledSongExpanded ?? (songUuid !== null && expandedSongUuid === songUuid),
|
|
@@ -2672,9 +2726,10 @@ function GenreTreeView({
|
|
|
2672
2726
|
resolveStyle
|
|
2673
2727
|
);
|
|
2674
2728
|
const treeStyles = useMemo8(() => toGenreNodeStyles(relations, visibleGenrePlaylists), [relations, visibleGenrePlaylists]);
|
|
2675
|
-
const
|
|
2676
|
-
|
|
2677
|
-
|
|
2729
|
+
const validSelectedGenreUuid = toGenreUuid(selectedGenreUuid);
|
|
2730
|
+
const [selectionHistory, setSelectionHistory] = useState10({ current: validSelectedGenreUuid, previous: null });
|
|
2731
|
+
if (selectionHistory.current !== validSelectedGenreUuid) {
|
|
2732
|
+
setSelectionHistory({ current: validSelectedGenreUuid, previous: selectionHistory.current ?? selectionHistory.previous });
|
|
2678
2733
|
}
|
|
2679
2734
|
const handlePrevious = selectionHistory.previous ? () => selectGenre(selectionHistory.previous) : void 0;
|
|
2680
2735
|
const { showPopup, hidePopup } = usePopup4();
|
|
@@ -2706,7 +2761,7 @@ function GenreTreeView({
|
|
|
2706
2761
|
const canToggleSide = !readOnly && criteria !== void 0 && criteria !== null && parentPlaylist !== void 0 && parentPlaylist.parent === null;
|
|
2707
2762
|
const side = criteria?.side ?? "core";
|
|
2708
2763
|
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 =
|
|
2764
|
+
const shareTarget = validSelectedGenreUuid ? { kind: "genre", genreUuid: validSelectedGenreUuid, name: criteria?.name ?? "Genre", scope, artistUuid } : void 0;
|
|
2710
2765
|
const shareUrl = shareTarget ? getShareUrlRef.current?.(shareTarget) ?? void 0 : void 0;
|
|
2711
2766
|
const genreContent = useGenreDetailContent({
|
|
2712
2767
|
genreUuid: selectedGenreUuid,
|
|
@@ -2728,7 +2783,7 @@ function GenreTreeView({
|
|
|
2728
2783
|
onAddChild: readOnly || !criteria ? void 0 : () => handleGenreCreationAction(criteria),
|
|
2729
2784
|
onRename: readOnly || !criteria ? void 0 : () => handleGenreRenameAction(criteria),
|
|
2730
2785
|
onChangeParent: readOnly || !genrePlaylist || !criteria ? void 0 : () => showPopup(
|
|
2731
|
-
/* @__PURE__ */
|
|
2786
|
+
/* @__PURE__ */ jsx40(
|
|
2732
2787
|
ChangeParentPopup,
|
|
2733
2788
|
{
|
|
2734
2789
|
genrePlaylist: { ...genrePlaylist, criteria },
|
|
@@ -2772,7 +2827,7 @@ function GenreTreeView({
|
|
|
2772
2827
|
onClose: otherPanel.onClose,
|
|
2773
2828
|
searchName: otherPanel.title
|
|
2774
2829
|
};
|
|
2775
|
-
} else if (selectedGenreUuid) {
|
|
2830
|
+
} else if (selectedGenreUuid !== null) {
|
|
2776
2831
|
activePanel = {
|
|
2777
2832
|
title: genreContent.title,
|
|
2778
2833
|
content: genreContent.content,
|
|
@@ -2789,19 +2844,19 @@ function GenreTreeView({
|
|
|
2789
2844
|
edge: activePanel.expanded ? { label: "Shrink panel", onClick: () => activePanel.onExpandedChange?.(false) } : isCollapsed ? null : { label: "Hide panel", onClick: () => changeCollapsed(true) },
|
|
2790
2845
|
center: activePanel.expanded ? null : isCollapsed ? { label: "Show panel", onClick: () => changeCollapsed(false) } : activePanel.onExpandedChange ? { label: "Extend panel", onClick: () => activePanel.onExpandedChange?.(true) } : null
|
|
2791
2846
|
} : void 0;
|
|
2792
|
-
const expandButton = placement === "default" && activePanel?.onExpandedChange ? /* @__PURE__ */
|
|
2847
|
+
const expandButton = placement === "default" && activePanel?.onExpandedChange ? /* @__PURE__ */ jsx40(
|
|
2793
2848
|
IconButton2,
|
|
2794
2849
|
{
|
|
2795
2850
|
"aria-label": activePanel.expanded ? "Shrink panel" : "Extend panel",
|
|
2796
2851
|
style: activePanel.headerAccent && { color: "inherit" },
|
|
2797
2852
|
onClick: () => activePanel.onExpandedChange?.(!activePanel.expanded),
|
|
2798
|
-
children: activePanel.expanded ? /* @__PURE__ */
|
|
2853
|
+
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
2854
|
}
|
|
2800
2855
|
) : null;
|
|
2801
2856
|
const renderArtistFilter = () => {
|
|
2802
2857
|
if (isLoading || !filterArtist) return null;
|
|
2803
|
-
return /* @__PURE__ */
|
|
2804
|
-
/* @__PURE__ */
|
|
2858
|
+
return /* @__PURE__ */ jsxs28("span", { className: "inline-flex items-center overflow-hidden rounded-full bg-[var(--color-neutral-100)] text-body", children: [
|
|
2859
|
+
/* @__PURE__ */ jsx40(
|
|
2805
2860
|
"button",
|
|
2806
2861
|
{
|
|
2807
2862
|
type: "button",
|
|
@@ -2813,7 +2868,7 @@ function GenreTreeView({
|
|
|
2813
2868
|
children: filterArtist.name
|
|
2814
2869
|
}
|
|
2815
2870
|
),
|
|
2816
|
-
/* @__PURE__ */
|
|
2871
|
+
/* @__PURE__ */ jsx40(
|
|
2817
2872
|
"button",
|
|
2818
2873
|
{
|
|
2819
2874
|
type: "button",
|
|
@@ -2825,8 +2880,8 @@ function GenreTreeView({
|
|
|
2825
2880
|
)
|
|
2826
2881
|
] });
|
|
2827
2882
|
};
|
|
2828
|
-
const actions = /* @__PURE__ */
|
|
2829
|
-
!isLoading && !isError && /* @__PURE__ */
|
|
2883
|
+
const actions = /* @__PURE__ */ jsxs28(Fragment16, { children: [
|
|
2884
|
+
!isLoading && !isError && /* @__PURE__ */ jsx40(
|
|
2830
2885
|
GenreTreeSearch,
|
|
2831
2886
|
{
|
|
2832
2887
|
artistBaseUrl,
|
|
@@ -2859,9 +2914,9 @@ function GenreTreeView({
|
|
|
2859
2914
|
extraGroups: extraSearchGroups
|
|
2860
2915
|
}
|
|
2861
2916
|
),
|
|
2862
|
-
!isLoading && !isError && filterArtist && /* @__PURE__ */
|
|
2863
|
-
/* @__PURE__ */
|
|
2864
|
-
!isLoading && !isError && !isControlled && /* @__PURE__ */
|
|
2917
|
+
!isLoading && !isError && filterArtist && /* @__PURE__ */ jsx40("div", { className: "hidden w-full justify-center max-md:flex", children: renderArtistFilter() }),
|
|
2918
|
+
/* @__PURE__ */ jsxs28("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: [
|
|
2919
|
+
!isLoading && !isError && !isControlled && /* @__PURE__ */ jsx40(
|
|
2865
2920
|
SegmentedControl2,
|
|
2866
2921
|
{
|
|
2867
2922
|
"aria-label": "Tree view mode",
|
|
@@ -2875,13 +2930,13 @@ function GenreTreeView({
|
|
|
2875
2930
|
]
|
|
2876
2931
|
}
|
|
2877
2932
|
),
|
|
2878
|
-
!isLoading && !isError && showDisplayOptions && /* @__PURE__ */
|
|
2933
|
+
!isLoading && !isError && showDisplayOptions && /* @__PURE__ */ jsx40(
|
|
2879
2934
|
"div",
|
|
2880
2935
|
{
|
|
2881
2936
|
className: "flex items-center gap-1",
|
|
2882
2937
|
role: "group",
|
|
2883
2938
|
"aria-label": "Tree display options",
|
|
2884
|
-
children: !isRotationControlled && viewMode !== "stacked" && viewMode !== "outline" && /* @__PURE__ */
|
|
2939
|
+
children: !isRotationControlled && viewMode !== "stacked" && viewMode !== "outline" && /* @__PURE__ */ jsx40(
|
|
2885
2940
|
Button,
|
|
2886
2941
|
{
|
|
2887
2942
|
variant: allowWheelRotation ? "default" : "outline",
|
|
@@ -2892,7 +2947,7 @@ function GenreTreeView({
|
|
|
2892
2947
|
)
|
|
2893
2948
|
}
|
|
2894
2949
|
),
|
|
2895
|
-
!isLoading && !isError && !readOnly && showAddRoot && /* @__PURE__ */
|
|
2950
|
+
!isLoading && !isError && !readOnly && showAddRoot && /* @__PURE__ */ jsx40(
|
|
2896
2951
|
IconTextButton,
|
|
2897
2952
|
{
|
|
2898
2953
|
icon: Plus2,
|
|
@@ -2902,38 +2957,38 @@ function GenreTreeView({
|
|
|
2902
2957
|
)
|
|
2903
2958
|
] })
|
|
2904
2959
|
] });
|
|
2905
|
-
return /* @__PURE__ */
|
|
2960
|
+
return /* @__PURE__ */ jsxs28(
|
|
2906
2961
|
"div",
|
|
2907
2962
|
{
|
|
2908
2963
|
"data-left-panel": isPanelShown && !isCollapsed ? void 0 : "hidden",
|
|
2909
2964
|
className: ["genre-tree-view relative flex flex-col h-full", placement === "regions" && REGIONS_CLASS, className2].filter(Boolean).join(" "),
|
|
2910
2965
|
children: [
|
|
2911
|
-
/* @__PURE__ */
|
|
2966
|
+
/* @__PURE__ */ jsx40(
|
|
2912
2967
|
"div",
|
|
2913
2968
|
{
|
|
2914
2969
|
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
2970
|
children: actions
|
|
2916
2971
|
}
|
|
2917
2972
|
),
|
|
2918
|
-
!isLoading && !isError && filterArtist && /* @__PURE__ */
|
|
2973
|
+
!isLoading && !isError && filterArtist && /* @__PURE__ */ jsx40(
|
|
2919
2974
|
"div",
|
|
2920
2975
|
{
|
|
2921
2976
|
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
2977
|
children: renderArtistFilter()
|
|
2923
2978
|
}
|
|
2924
2979
|
),
|
|
2925
|
-
/* @__PURE__ */
|
|
2926
|
-
!isLoading && !isError && viewMode === "outline" && floatingControlsLeading && /* @__PURE__ */
|
|
2927
|
-
isLoading ? /* @__PURE__ */
|
|
2980
|
+
/* @__PURE__ */ jsx40("div", { className: "content-container flex-1 min-h-0 flex flex-row gap-4", children: /* @__PURE__ */ jsxs28("div", { className: "tree-view-container relative flex-1 min-w-0 flex flex-col h-full", children: [
|
|
2981
|
+
!isLoading && !isError && viewMode === "outline" && floatingControlsLeading && /* @__PURE__ */ jsx40("div", { className: "absolute bottom-3 right-3 z-10", children: floatingControlsLeading }),
|
|
2982
|
+
isLoading ? /* @__PURE__ */ jsx40(GenreTreeViewSkeleton, { viewMode }) : isError ? /* @__PURE__ */ jsxs28("p", { role: "alert", className: "m-auto text-center", children: [
|
|
2928
2983
|
"Couldn't load the genre tree.",
|
|
2929
2984
|
" ",
|
|
2930
|
-
/* @__PURE__ */
|
|
2985
|
+
/* @__PURE__ */ jsx40("button", { type: "button", className: "underline", onClick: refetch, children: "Retry" })
|
|
2931
2986
|
] }) : viewMode === "wheel" ? (
|
|
2932
2987
|
// The info panel's top edge aligns with the tree's; the search bar floats `--layout-panel-inset` below it,
|
|
2933
2988
|
// and the header inset (the bar's height plus that inset) extends the header's fill behind the bar,
|
|
2934
2989
|
// Google Maps style; the 8px bottom padding mirrors the inset above the bar, and the hidden title's height is zeroed.
|
|
2935
2990
|
// The panel's own Zoom in button is hidden: the search bar carries it.
|
|
2936
|
-
/* @__PURE__ */
|
|
2991
|
+
/* @__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
2992
|
GenrePlaylistTreeWheel,
|
|
2938
2993
|
{
|
|
2939
2994
|
scope,
|
|
@@ -2951,9 +3006,9 @@ function GenreTreeView({
|
|
|
2951
3006
|
allowWheelRotation,
|
|
2952
3007
|
sizeMetric: isArtistFiltered || !canSizeByViews ? "songs" : deferredSizeMetric,
|
|
2953
3008
|
busy,
|
|
2954
|
-
floatingControlsLeading: floatingControlsLeading || canSizeByViews ? /* @__PURE__ */
|
|
3009
|
+
floatingControlsLeading: floatingControlsLeading || canSizeByViews ? /* @__PURE__ */ jsxs28("div", { className: "flex items-center gap-2", children: [
|
|
2955
3010
|
floatingControlsLeading,
|
|
2956
|
-
canSizeByViews && /* @__PURE__ */
|
|
3011
|
+
canSizeByViews && /* @__PURE__ */ jsx40(SizeMetricToggle, { value: sizeMetric, onChange: changeSizeMetric })
|
|
2957
3012
|
] }) : void 0,
|
|
2958
3013
|
defaultViewport,
|
|
2959
3014
|
viewportRestore,
|
|
@@ -2962,7 +3017,7 @@ function GenreTreeView({
|
|
|
2962
3017
|
) }) })
|
|
2963
3018
|
) : viewMode === "pop-core" ? (
|
|
2964
3019
|
// Same as the wheel: the header inset extends its fill behind the floating search bar, Google Maps style.
|
|
2965
|
-
/* @__PURE__ */
|
|
3020
|
+
/* @__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
3021
|
GenrePlaylistTreeWheelRadialPopCore,
|
|
2967
3022
|
{
|
|
2968
3023
|
scope,
|
|
@@ -2980,9 +3035,9 @@ function GenreTreeView({
|
|
|
2980
3035
|
allowWheelRotation,
|
|
2981
3036
|
sizeMetric: isArtistFiltered || !canSizeByViews ? "songs" : deferredSizeMetric,
|
|
2982
3037
|
busy,
|
|
2983
|
-
floatingControlsLeading: floatingControlsLeading || canSizeByViews ? /* @__PURE__ */
|
|
3038
|
+
floatingControlsLeading: floatingControlsLeading || canSizeByViews ? /* @__PURE__ */ jsxs28("div", { className: "flex items-center gap-2", children: [
|
|
2984
3039
|
floatingControlsLeading,
|
|
2985
|
-
canSizeByViews && /* @__PURE__ */
|
|
3040
|
+
canSizeByViews && /* @__PURE__ */ jsx40(SizeMetricToggle, { value: sizeMetric, onChange: changeSizeMetric })
|
|
2986
3041
|
] }) : void 0,
|
|
2987
3042
|
defaultViewport,
|
|
2988
3043
|
viewportRestore,
|
|
@@ -2990,7 +3045,7 @@ function GenreTreeView({
|
|
|
2990
3045
|
...focus
|
|
2991
3046
|
}
|
|
2992
3047
|
) }) })
|
|
2993
|
-
) : viewMode === "outline" ? /* @__PURE__ */
|
|
3048
|
+
) : viewMode === "outline" ? /* @__PURE__ */ jsx40("div", { className: "tree-container flex-1 min-h-0 w-full overflow-y-auto relative", children: /* @__PURE__ */ jsx40(
|
|
2994
3049
|
GenrePlaylistTreeWheelRadialPopCore,
|
|
2995
3050
|
{
|
|
2996
3051
|
outline: true,
|
|
@@ -3007,13 +3062,13 @@ function GenreTreeView({
|
|
|
3007
3062
|
selectedNodeId,
|
|
3008
3063
|
readOnly
|
|
3009
3064
|
}
|
|
3010
|
-
) }) : /* @__PURE__ */
|
|
3065
|
+
) }) : /* @__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
3066
|
([uuid, genrePlaylistTreePerRoot]) => {
|
|
3012
|
-
return /* @__PURE__ */
|
|
3067
|
+
return /* @__PURE__ */ jsx40(
|
|
3013
3068
|
"div",
|
|
3014
3069
|
{
|
|
3015
3070
|
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__ */
|
|
3071
|
+
children: /* @__PURE__ */ jsx40("div", { className: "graph-container relative z-10 h-full", children: /* @__PURE__ */ jsx40(
|
|
3017
3072
|
GenrePlaylistTreePerRoot,
|
|
3018
3073
|
{
|
|
3019
3074
|
scope,
|
|
@@ -3040,7 +3095,7 @@ function GenreTreeView({
|
|
|
3040
3095
|
);
|
|
3041
3096
|
}
|
|
3042
3097
|
) }),
|
|
3043
|
-
/* @__PURE__ */
|
|
3098
|
+
/* @__PURE__ */ jsx40(
|
|
3044
3099
|
DetailPanel2,
|
|
3045
3100
|
{
|
|
3046
3101
|
ref: panelRef,
|
|
@@ -3055,7 +3110,7 @@ function GenreTreeView({
|
|
|
3055
3110
|
onExpandedChange: activePanel?.onExpandedChange,
|
|
3056
3111
|
aside: activePanel?.aside,
|
|
3057
3112
|
edgeTab: detailTab,
|
|
3058
|
-
children: activePanel?.aside && !activePanel.expanded ? /* @__PURE__ */
|
|
3113
|
+
children: activePanel?.aside && !activePanel.expanded ? /* @__PURE__ */ jsxs28(Fragment16, { children: [
|
|
3059
3114
|
activePanel.content,
|
|
3060
3115
|
activePanel.aside
|
|
3061
3116
|
] }) : activePanel?.content
|
|
@@ -3081,7 +3136,7 @@ import { ListMusic } from "lucide-react";
|
|
|
3081
3136
|
import { useTrackList as useTrackList7 } from "@behindthemusictree/app-kit/genre-tree";
|
|
3082
3137
|
import { TrackListOriginType as TrackListOriginType3 } from "@behindthemusictree/app-kit/genre-tree";
|
|
3083
3138
|
import { useTrackNoun as useTrackNoun3 } from "@behindthemusictree/app-kit/track-noun";
|
|
3084
|
-
import { jsx as
|
|
3139
|
+
import { jsx as jsx41, jsxs as jsxs29 } from "react/jsx-runtime";
|
|
3085
3140
|
var useBrowserLayoutEffect = typeof window === "undefined" ? useEffect7 : useLayoutEffect2;
|
|
3086
3141
|
function TrackListSidebar({
|
|
3087
3142
|
className: className2 = "",
|
|
@@ -3183,25 +3238,25 @@ function TrackListSidebar({
|
|
|
3183
3238
|
}
|
|
3184
3239
|
};
|
|
3185
3240
|
const positionClasses = layout === "inline" ? "relative w-full flex h-full flex-col" : "fixed right-0 w-[50rem] flex flex-col";
|
|
3186
|
-
return trackList ? /* @__PURE__ */
|
|
3241
|
+
return trackList ? /* @__PURE__ */ jsxs29(
|
|
3187
3242
|
"div",
|
|
3188
3243
|
{
|
|
3189
3244
|
"data-theme": "dark",
|
|
3190
3245
|
className: `track-list-sidebar ${positionClasses} rounded-2xl bg-[var(--color-surface)] pb-1 ${className2}`,
|
|
3191
3246
|
style: layout === "fixed" ? { top: "63.5px", maxHeight: "calc(100vh - 63.5px - 79px)" } : void 0,
|
|
3192
3247
|
children: [
|
|
3193
|
-
/* @__PURE__ */
|
|
3194
|
-
/* @__PURE__ */
|
|
3195
|
-
/* @__PURE__ */
|
|
3196
|
-
/* @__PURE__ */
|
|
3197
|
-
/* @__PURE__ */
|
|
3248
|
+
/* @__PURE__ */ jsxs29("div", { className: "header flex h-16 items-center px-4 py-2 text-[var(--color-text)]", children: [
|
|
3249
|
+
/* @__PURE__ */ jsxs29("div", { className: "min-w-0 flex flex-1 flex-col justify-center", children: [
|
|
3250
|
+
/* @__PURE__ */ jsxs29("div", { className: "origin flex text-xl", children: [
|
|
3251
|
+
/* @__PURE__ */ jsx41("div", { className: "from h-auto flex flex-col justify-center items-center mr-2", children: "From" }),
|
|
3252
|
+
/* @__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
3253
|
] }),
|
|
3199
|
-
/* @__PURE__ */
|
|
3254
|
+
/* @__PURE__ */ jsxs29("div", { className: "info flex items-center text-body text-[var(--color-text-muted)]", children: [
|
|
3200
3255
|
trackList.origin.type === TrackListOriginType3.GENRE_PLAYLIST ? "Genre \u2022 " : trackList.origin.type === TrackListOriginType3.ARTIST ? "Artist \u2022 " : `${trackNoun.singular} playlist \u2022 `,
|
|
3201
3256
|
`${trackList.total} ${trackList.total > 1 ? trackNoun.plural : trackNoun.singular}`
|
|
3202
3257
|
] })
|
|
3203
3258
|
] }),
|
|
3204
|
-
(isCollapsed && onExpand || !isCollapsed && onMinimize) && /* @__PURE__ */
|
|
3259
|
+
(isCollapsed && onExpand || !isCollapsed && onMinimize) && /* @__PURE__ */ jsx41(
|
|
3205
3260
|
"button",
|
|
3206
3261
|
{
|
|
3207
3262
|
type: "button",
|
|
@@ -3210,11 +3265,11 @@ function TrackListSidebar({
|
|
|
3210
3265
|
"aria-expanded": !isCollapsed,
|
|
3211
3266
|
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
3267
|
onClick: isCollapsed ? onExpand : onMinimize,
|
|
3213
|
-
children: /* @__PURE__ */
|
|
3268
|
+
children: /* @__PURE__ */ jsx41(ListMusic, { "aria-hidden": "true", className: "h-5 w-5" })
|
|
3214
3269
|
}
|
|
3215
3270
|
)
|
|
3216
3271
|
] }),
|
|
3217
|
-
!isCollapsed && /* @__PURE__ */
|
|
3272
|
+
!isCollapsed && /* @__PURE__ */ jsxs29(
|
|
3218
3273
|
"ul",
|
|
3219
3274
|
{
|
|
3220
3275
|
ref: trackListRef,
|
|
@@ -3224,7 +3279,7 @@ function TrackListSidebar({
|
|
|
3224
3279
|
onPointerDown: markUserScrollIntent,
|
|
3225
3280
|
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
3281
|
children: [
|
|
3227
|
-
trackList.tracks.map((track, index) => /* @__PURE__ */
|
|
3282
|
+
trackList.tracks.map((track, index) => /* @__PURE__ */ jsx41("li", { "data-track-uuid": track.uuid, children: /* @__PURE__ */ jsx41(
|
|
3228
3283
|
TrackItem,
|
|
3229
3284
|
{
|
|
3230
3285
|
track,
|
|
@@ -3235,7 +3290,7 @@ function TrackListSidebar({
|
|
|
3235
3290
|
renderSongLink
|
|
3236
3291
|
}
|
|
3237
3292
|
) }, track.uuid)),
|
|
3238
|
-
hasMore && /* @__PURE__ */
|
|
3293
|
+
hasMore && /* @__PURE__ */ jsx41("li", { ref: loadMoreSentinelRef, "aria-hidden": "true", className: "h-px" })
|
|
3239
3294
|
]
|
|
3240
3295
|
}
|
|
3241
3296
|
)
|
|
@@ -3260,7 +3315,7 @@ import { PanelEdgeTab } from "@behindthemusictree/ui";
|
|
|
3260
3315
|
import { Pause as Pause4, Play as Play4, SkipBack, SkipForward, Volume2, VolumeX } from "lucide-react";
|
|
3261
3316
|
import { formatTime, useTrackList as useTrackList8 } from "@behindthemusictree/app-kit/genre-tree";
|
|
3262
3317
|
import { PlayStates as PlayStates4, useCurrentTime, usePlayer as usePlayer11 } from "@behindthemusictree/app-kit/player";
|
|
3263
|
-
import { jsx as
|
|
3318
|
+
import { jsx as jsx42, jsxs as jsxs30 } from "react/jsx-runtime";
|
|
3264
3319
|
function PlayerControls() {
|
|
3265
3320
|
const {
|
|
3266
3321
|
duration,
|
|
@@ -3279,15 +3334,15 @@ function PlayerControls() {
|
|
|
3279
3334
|
const safeDuration = Number.isFinite(duration) && duration > 0 ? duration : 0;
|
|
3280
3335
|
const safeCurrentTime = Number.isFinite(currentTime) ? Math.max(0, Math.min(currentTime, safeDuration)) : 0;
|
|
3281
3336
|
const isPlaying = playState === PlayStates4.PLAYING;
|
|
3282
|
-
return /* @__PURE__ */
|
|
3337
|
+
return /* @__PURE__ */ jsxs30(
|
|
3283
3338
|
"section",
|
|
3284
3339
|
{
|
|
3285
3340
|
"aria-label": "Player controls",
|
|
3286
3341
|
className: "player-controls flex shrink-0 flex-col gap-2 border-b border-zinc-800 px-3 py-2 text-zinc-200",
|
|
3287
3342
|
children: [
|
|
3288
|
-
/* @__PURE__ */
|
|
3289
|
-
/* @__PURE__ */
|
|
3290
|
-
/* @__PURE__ */
|
|
3343
|
+
/* @__PURE__ */ jsxs30("div", { className: "flex min-w-0 items-center gap-2 text-xs tabular-nums text-zinc-400", children: [
|
|
3344
|
+
/* @__PURE__ */ jsx42("span", { "aria-label": "Elapsed time", children: formatTime(safeCurrentTime) }),
|
|
3345
|
+
/* @__PURE__ */ jsx42(
|
|
3291
3346
|
"input",
|
|
3292
3347
|
{
|
|
3293
3348
|
"aria-label": "Seek",
|
|
@@ -3301,11 +3356,11 @@ function PlayerControls() {
|
|
|
3301
3356
|
onChange: (event) => seekTo(Number(event.currentTarget.value))
|
|
3302
3357
|
}
|
|
3303
3358
|
),
|
|
3304
|
-
/* @__PURE__ */
|
|
3359
|
+
/* @__PURE__ */ jsx42("span", { "aria-label": "Duration", children: formatTime(safeDuration) })
|
|
3305
3360
|
] }),
|
|
3306
|
-
/* @__PURE__ */
|
|
3307
|
-
/* @__PURE__ */
|
|
3308
|
-
/* @__PURE__ */
|
|
3361
|
+
/* @__PURE__ */ jsxs30("div", { className: "grid min-h-9 grid-cols-[1fr_auto_1fr] items-center gap-3", children: [
|
|
3362
|
+
/* @__PURE__ */ jsxs30("div", { className: "col-start-2 flex items-center justify-center gap-2", children: [
|
|
3363
|
+
/* @__PURE__ */ jsx42(
|
|
3309
3364
|
"button",
|
|
3310
3365
|
{
|
|
3311
3366
|
type: "button",
|
|
@@ -3314,10 +3369,10 @@ function PlayerControls() {
|
|
|
3314
3369
|
disabled: !isReady || !hasPreviousTrack,
|
|
3315
3370
|
onClick: playPreviousTrack,
|
|
3316
3371
|
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__ */
|
|
3372
|
+
children: /* @__PURE__ */ jsx42(SkipBack, { "aria-hidden": "true", className: "h-4 w-4" })
|
|
3318
3373
|
}
|
|
3319
3374
|
),
|
|
3320
|
-
/* @__PURE__ */
|
|
3375
|
+
/* @__PURE__ */ jsx42(
|
|
3321
3376
|
"button",
|
|
3322
3377
|
{
|
|
3323
3378
|
type: "button",
|
|
@@ -3326,10 +3381,10 @@ function PlayerControls() {
|
|
|
3326
3381
|
disabled: !isReady,
|
|
3327
3382
|
onClick: handlePlayPauseAction,
|
|
3328
3383
|
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__ */
|
|
3384
|
+
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
3385
|
}
|
|
3331
3386
|
),
|
|
3332
|
-
/* @__PURE__ */
|
|
3387
|
+
/* @__PURE__ */ jsx42(
|
|
3333
3388
|
"button",
|
|
3334
3389
|
{
|
|
3335
3390
|
type: "button",
|
|
@@ -3338,14 +3393,14 @@ function PlayerControls() {
|
|
|
3338
3393
|
disabled: !isReady || !hasNextTrack,
|
|
3339
3394
|
onClick: playNextTrack,
|
|
3340
3395
|
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__ */
|
|
3396
|
+
children: /* @__PURE__ */ jsx42(SkipForward, { "aria-hidden": "true", className: "h-4 w-4" })
|
|
3342
3397
|
}
|
|
3343
3398
|
)
|
|
3344
3399
|
] }),
|
|
3345
|
-
/* @__PURE__ */
|
|
3346
|
-
volume === 0 ? /* @__PURE__ */
|
|
3347
|
-
/* @__PURE__ */
|
|
3348
|
-
/* @__PURE__ */
|
|
3400
|
+
/* @__PURE__ */ jsxs30("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: [
|
|
3401
|
+
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" }),
|
|
3402
|
+
/* @__PURE__ */ jsx42("span", { className: "sr-only", children: "Volume" }),
|
|
3403
|
+
/* @__PURE__ */ jsx42(
|
|
3349
3404
|
"input",
|
|
3350
3405
|
{
|
|
3351
3406
|
"aria-label": "Volume",
|
|
@@ -3367,7 +3422,7 @@ function PlayerControls() {
|
|
|
3367
3422
|
}
|
|
3368
3423
|
|
|
3369
3424
|
// src/genre-tree/PlayerPanel.tsx
|
|
3370
|
-
import { jsx as
|
|
3425
|
+
import { jsx as jsx43, jsxs as jsxs31 } from "react/jsx-runtime";
|
|
3371
3426
|
var PANEL_ID = "player-panel";
|
|
3372
3427
|
var DEFAULT_EXTENDED_WIDTH = "calc(100vw - var(--layout-center-left) - var(--layout-gutter))";
|
|
3373
3428
|
function PlayerPanel({
|
|
@@ -3407,7 +3462,7 @@ function PlayerPanel({
|
|
|
3407
3462
|
onClick: () => setIsExtendRequested(true),
|
|
3408
3463
|
expanded: false
|
|
3409
3464
|
} : null;
|
|
3410
|
-
return /* @__PURE__ */
|
|
3465
|
+
return /* @__PURE__ */ jsxs31(
|
|
3411
3466
|
"div",
|
|
3412
3467
|
{
|
|
3413
3468
|
id: PANEL_ID,
|
|
@@ -3420,7 +3475,7 @@ function PlayerPanel({
|
|
|
3420
3475
|
),
|
|
3421
3476
|
style: isExtended ? { width: extendedWidth } : void 0,
|
|
3422
3477
|
children: [
|
|
3423
|
-
/* @__PURE__ */
|
|
3478
|
+
/* @__PURE__ */ jsx43(
|
|
3424
3479
|
PanelEdgeTab,
|
|
3425
3480
|
{
|
|
3426
3481
|
side: "right",
|
|
@@ -3430,7 +3485,7 @@ function PlayerPanel({
|
|
|
3430
3485
|
className: "absolute right-full top-1/2 -translate-y-1/2"
|
|
3431
3486
|
}
|
|
3432
3487
|
),
|
|
3433
|
-
/* @__PURE__ */
|
|
3488
|
+
/* @__PURE__ */ jsxs31(
|
|
3434
3489
|
"div",
|
|
3435
3490
|
{
|
|
3436
3491
|
className: twMerge(
|
|
@@ -3438,20 +3493,20 @@ function PlayerPanel({
|
|
|
3438
3493
|
isExtended ? "flex-row" : "flex-col"
|
|
3439
3494
|
),
|
|
3440
3495
|
children: [
|
|
3441
|
-
/* @__PURE__ */
|
|
3442
|
-
/* @__PURE__ */
|
|
3443
|
-
/* @__PURE__ */
|
|
3444
|
-
/* @__PURE__ */
|
|
3445
|
-
playerTrackObject?.loadError && /* @__PURE__ */
|
|
3496
|
+
/* @__PURE__ */ jsxs31("div", { className: "flex w-[var(--layout-right-w)] shrink-0 flex-col", children: [
|
|
3497
|
+
/* @__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 }) }),
|
|
3498
|
+
/* @__PURE__ */ jsxs31("div", { className: "relative w-full shrink-0", children: [
|
|
3499
|
+
/* @__PURE__ */ jsx43(PlayerVideoSurface, { className: "aspect-video w-full bg-black" }),
|
|
3500
|
+
playerTrackObject?.loadError && /* @__PURE__ */ jsxs31("span", { className: "absolute bottom-2 left-2 right-2 text-xs text-red-400", children: [
|
|
3446
3501
|
playerTrackObject.loadError,
|
|
3447
|
-
/* @__PURE__ */
|
|
3502
|
+
/* @__PURE__ */ jsx43("button", { type: "button", className: "ml-2 underline", onClick: () => {
|
|
3448
3503
|
void retryPlayback();
|
|
3449
3504
|
}, children: "Retry" })
|
|
3450
3505
|
] })
|
|
3451
3506
|
] }),
|
|
3452
|
-
/* @__PURE__ */
|
|
3507
|
+
/* @__PURE__ */ jsx43(PlayerControls, {})
|
|
3453
3508
|
] }),
|
|
3454
|
-
/* @__PURE__ */
|
|
3509
|
+
/* @__PURE__ */ jsx43(
|
|
3455
3510
|
TrackListSidebar,
|
|
3456
3511
|
{
|
|
3457
3512
|
layout: "inline",
|
|
@@ -3478,11 +3533,11 @@ function PlayerPanel({
|
|
|
3478
3533
|
import { v4 as uuidv4 } from "uuid";
|
|
3479
3534
|
import { AiFillStar, AiOutlineStar } from "react-icons/ai";
|
|
3480
3535
|
import { FORM_RATING_NULL_VALUE } from "@behindthemusictree/app-kit/genre-tree";
|
|
3481
|
-
import { jsx as
|
|
3536
|
+
import { jsx as jsx44, jsxs as jsxs32 } from "react/jsx-runtime";
|
|
3482
3537
|
function Rating({ rating, handleChange }) {
|
|
3483
3538
|
const instanceId = uuidv4();
|
|
3484
|
-
return /* @__PURE__ */
|
|
3485
|
-
/* @__PURE__ */
|
|
3539
|
+
return /* @__PURE__ */ jsx44("div", { className: "flex items-center", children: [...Array(6)].map((_, i) => /* @__PURE__ */ jsxs32("div", { className: `relative ${i === 0 ? "mr-4" : "mr-1"}`, children: [
|
|
3540
|
+
/* @__PURE__ */ jsx44(
|
|
3486
3541
|
"input",
|
|
3487
3542
|
{
|
|
3488
3543
|
id: `star-${instanceId}-${i}`,
|
|
@@ -3494,16 +3549,16 @@ function Rating({ rating, handleChange }) {
|
|
|
3494
3549
|
onChange: handleChange
|
|
3495
3550
|
}
|
|
3496
3551
|
),
|
|
3497
|
-
/* @__PURE__ */
|
|
3498
|
-
/* @__PURE__ */
|
|
3552
|
+
/* @__PURE__ */ jsx44("label", { htmlFor: `star-${instanceId}-${i}`, className: "cursor-pointer", children: i === 0 ? /* @__PURE__ */ jsxs32("div", { className: "flex", children: [
|
|
3553
|
+
/* @__PURE__ */ jsx44(
|
|
3499
3554
|
AiOutlineStar,
|
|
3500
3555
|
{
|
|
3501
3556
|
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
3557
|
}
|
|
3503
3558
|
),
|
|
3504
|
-
/* @__PURE__ */
|
|
3559
|
+
/* @__PURE__ */ jsx44("span", { className: "flex-grow w-8" }),
|
|
3505
3560
|
" "
|
|
3506
|
-
] }) : /* @__PURE__ */
|
|
3561
|
+
] }) : /* @__PURE__ */ jsx44(
|
|
3507
3562
|
AiFillStar,
|
|
3508
3563
|
{
|
|
3509
3564
|
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 +3570,7 @@ function Rating({ rating, handleChange }) {
|
|
|
3515
3570
|
// src/genre-tree/EntityDetailPanel.tsx
|
|
3516
3571
|
import { useState as useState12 } from "react";
|
|
3517
3572
|
import { DetailPanel as DetailPanel3 } from "@behindthemusictree/ui";
|
|
3518
|
-
import { Fragment as
|
|
3573
|
+
import { Fragment as Fragment17, jsx as jsx45, jsxs as jsxs33 } from "react/jsx-runtime";
|
|
3519
3574
|
function EntityDetailPanel({
|
|
3520
3575
|
scope,
|
|
3521
3576
|
getBackendBaseUrl,
|
|
@@ -3527,6 +3582,7 @@ function EntityDetailPanel({
|
|
|
3527
3582
|
onArtistUuidChange,
|
|
3528
3583
|
renderArtistLink,
|
|
3529
3584
|
renderSongLink,
|
|
3585
|
+
renderPlaceLink,
|
|
3530
3586
|
collapsed,
|
|
3531
3587
|
edgeTab,
|
|
3532
3588
|
...navigation
|
|
@@ -3538,8 +3594,9 @@ function EntityDetailPanel({
|
|
|
3538
3594
|
getBackendBaseUrl,
|
|
3539
3595
|
getArtistBackendBaseUrl,
|
|
3540
3596
|
getShareUrl,
|
|
3541
|
-
|
|
3542
|
-
|
|
3597
|
+
renderPlaceLink,
|
|
3598
|
+
renderArtistLink: renderArtistLink ?? ((artist) => artist.isSpecialPurpose ? artist.name : /* @__PURE__ */ jsx45("button", { type: "button", onClick: () => onArtistUuidChange(artist.uuid), className: "hover:underline", children: artist.name })),
|
|
3599
|
+
renderSongLink: renderSongLink ?? ((song) => /* @__PURE__ */ jsx45("button", { type: "button", onClick: () => onSongUuidChange(song.uuid), className: "hover:underline", children: song.title })),
|
|
3543
3600
|
song: {
|
|
3544
3601
|
uuid: songUuid,
|
|
3545
3602
|
expanded: songUuid !== null && expandedSongUuid === songUuid,
|
|
@@ -3555,7 +3612,7 @@ function EntityDetailPanel({
|
|
|
3555
3612
|
...navigation
|
|
3556
3613
|
});
|
|
3557
3614
|
if (!panel) return null;
|
|
3558
|
-
return /* @__PURE__ */
|
|
3615
|
+
return /* @__PURE__ */ jsx45(
|
|
3559
3616
|
DetailPanel3,
|
|
3560
3617
|
{
|
|
3561
3618
|
side: "left",
|
|
@@ -3567,7 +3624,7 @@ function EntityDetailPanel({
|
|
|
3567
3624
|
onExpandedChange: panel.onExpandedChange,
|
|
3568
3625
|
aside: panel.extraContent,
|
|
3569
3626
|
edgeTab,
|
|
3570
|
-
children: panel.extraContent && !panel.expanded ? /* @__PURE__ */
|
|
3627
|
+
children: panel.extraContent && !panel.expanded ? /* @__PURE__ */ jsxs33(Fragment17, { children: [
|
|
3571
3628
|
panel.content,
|
|
3572
3629
|
panel.extraContent
|
|
3573
3630
|
] }) : panel.content
|
|
@@ -3601,4 +3658,4 @@ export {
|
|
|
3601
3658
|
GenreTreeViewSkeleton2 as GenreTreeViewSkeleton,
|
|
3602
3659
|
GenreTreeOutlineSkeleton
|
|
3603
3660
|
};
|
|
3604
|
-
//# sourceMappingURL=chunk-
|
|
3661
|
+
//# sourceMappingURL=chunk-PVYUC2PN.js.map
|