@behindthemusictree/app-kit-ui 40.0.0 → 41.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-I2TEOHVG.js → chunk-GR4PCPCU.js} +295 -279
- package/dist/chunk-GR4PCPCU.js.map +1 -0
- package/dist/genre-tree/index.cjs +345 -331
- package/dist/genre-tree/index.cjs.map +1 -1
- package/dist/genre-tree/index.d.ts +7 -3
- package/dist/genre-tree/index.js +1 -1
- package/dist/index.cjs +345 -331
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +1 -1
- package/package.json +4 -4
- package/dist/chunk-I2TEOHVG.js.map +0 -1
|
@@ -50,11 +50,12 @@ module.exports = __toCommonJS(genre_tree_exports);
|
|
|
50
50
|
// src/genre-tree/GenreTreeView.tsx
|
|
51
51
|
var import_react19 = require("react");
|
|
52
52
|
var import_react_query3 = require("@tanstack/react-query");
|
|
53
|
+
var import_lucide_react13 = require("lucide-react");
|
|
53
54
|
var import_lucide_react14 = require("lucide-react");
|
|
54
|
-
var import_lucide_react15 = require("lucide-react");
|
|
55
55
|
var import_ui21 = require("@behindthemusictree/ui");
|
|
56
56
|
var import_genre_tree_view5 = require("@behindthemusictree/genre-tree-view");
|
|
57
57
|
var import_genre_tree30 = require("@behindthemusictree/app-kit/genre-tree");
|
|
58
|
+
var import_genre_tree31 = require("@behindthemusictree/app-kit/genre-tree");
|
|
58
59
|
var import_popup4 = require("@behindthemusictree/app-kit/popup");
|
|
59
60
|
|
|
60
61
|
// src/genre-tree/playlist-tree/size-metric.ts
|
|
@@ -85,6 +86,21 @@ function toTreeNodes(genrePlaylists, sizeMetric, focusUuids) {
|
|
|
85
86
|
}));
|
|
86
87
|
}
|
|
87
88
|
|
|
89
|
+
// src/genre-tree/playlist-tree/toGenreNodeStyles.ts
|
|
90
|
+
function toGenreNodeStyles(relations, genrePlaylists) {
|
|
91
|
+
const styles = /* @__PURE__ */ new Map();
|
|
92
|
+
if (!relations) return styles;
|
|
93
|
+
const genreUuidByPlaylistUuid = new Map(
|
|
94
|
+
genrePlaylists.flatMap((genrePlaylist) => genrePlaylist.criteria ? [[genrePlaylist.uuid, genrePlaylist.criteria.uuid]] : [])
|
|
95
|
+
);
|
|
96
|
+
const drawn = [relations, relations.parentNode, ...relations.childNodes, ...relations.ancestorNodes];
|
|
97
|
+
for (const entry of drawn) {
|
|
98
|
+
const genreUuid = entry && genreUuidByPlaylistUuid.get(entry.node.id);
|
|
99
|
+
if (entry && genreUuid) styles.set(genreUuid, { fill: entry.fill, textColor: entry.textColor });
|
|
100
|
+
}
|
|
101
|
+
return styles;
|
|
102
|
+
}
|
|
103
|
+
|
|
88
104
|
// src/genre-tree/playlist-tree/TreePerRoot.tsx
|
|
89
105
|
var import_genre_tree3 = require("@behindthemusictree/app-kit/genre-tree");
|
|
90
106
|
var import_react3 = require("react");
|
|
@@ -1387,6 +1403,29 @@ function ClampedText({ children, className: className2 = "" }) {
|
|
|
1387
1403
|
] });
|
|
1388
1404
|
}
|
|
1389
1405
|
|
|
1406
|
+
// src/genre-tree/CommonsPhoto.tsx
|
|
1407
|
+
var import_jsx_runtime26 = require("react/jsx-runtime");
|
|
1408
|
+
function ExternalLink({ href, children }) {
|
|
1409
|
+
return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("a", { href, target: "_blank", rel: "noopener noreferrer", className: "underline-offset-2 hover:underline", children });
|
|
1410
|
+
}
|
|
1411
|
+
function CommonsPhoto({
|
|
1412
|
+
image,
|
|
1413
|
+
alt,
|
|
1414
|
+
creditLabel = "Photo"
|
|
1415
|
+
}) {
|
|
1416
|
+
return /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("figure", { className: "flex flex-col gap-1.5", children: [
|
|
1417
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)("img", { src: image.url, alt, className: "h-64 w-full object-contain bg-[var(--color-surface-muted)] rounded" }),
|
|
1418
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("figcaption", { className: "text-caption text-[var(--color-text-muted)]", children: [
|
|
1419
|
+
creditLabel,
|
|
1420
|
+
": ",
|
|
1421
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)(ExternalLink, { href: image.pageUrl, children: image.author ?? "Wikimedia Commons" }),
|
|
1422
|
+
",",
|
|
1423
|
+
" ",
|
|
1424
|
+
image.licenseUrl ? /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(ExternalLink, { href: image.licenseUrl, children: image.license }) : image.license
|
|
1425
|
+
] })
|
|
1426
|
+
] });
|
|
1427
|
+
}
|
|
1428
|
+
|
|
1390
1429
|
// src/genre-tree/GenrePlaylistTracks.tsx
|
|
1391
1430
|
var import_react13 = require("react");
|
|
1392
1431
|
var import_react_query = require("@tanstack/react-query");
|
|
@@ -1409,15 +1448,15 @@ var import_genre_tree16 = require("@behindthemusictree/app-kit/genre-tree");
|
|
|
1409
1448
|
|
|
1410
1449
|
// src/genre-tree/MusicBrainzRecordingLink.tsx
|
|
1411
1450
|
var import_genre_tree11 = require("@behindthemusictree/app-kit/genre-tree");
|
|
1412
|
-
var
|
|
1451
|
+
var import_jsx_runtime27 = require("react/jsx-runtime");
|
|
1413
1452
|
function MusicBrainzRecordingLink({
|
|
1414
1453
|
song,
|
|
1415
1454
|
children,
|
|
1416
1455
|
className: className2 = ""
|
|
1417
1456
|
}) {
|
|
1418
1457
|
const url = (0, import_genre_tree11.musicBrainzRecordingUrl)(song);
|
|
1419
|
-
if (!url) return /* @__PURE__ */ (0,
|
|
1420
|
-
return /* @__PURE__ */ (0,
|
|
1458
|
+
if (!url) return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_jsx_runtime27.Fragment, { children });
|
|
1459
|
+
return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
|
|
1421
1460
|
"a",
|
|
1422
1461
|
{
|
|
1423
1462
|
href: url,
|
|
@@ -1434,7 +1473,7 @@ function MusicBrainzRecordingLink({
|
|
|
1434
1473
|
// src/genre-tree/GenrePlaylistTracks.tsx
|
|
1435
1474
|
var import_genre_tree17 = require("@behindthemusictree/app-kit/genre-tree");
|
|
1436
1475
|
var import_track_noun = require("@behindthemusictree/app-kit/track-noun");
|
|
1437
|
-
var
|
|
1476
|
+
var import_jsx_runtime28 = require("react/jsx-runtime");
|
|
1438
1477
|
var CATALOGUE_PAGE_SIZE = 100;
|
|
1439
1478
|
var SongPageSchema = (0, import_transport3.PaginatedResponseSchema)(import_genre_tree15.SongDetailedSchema).extend({
|
|
1440
1479
|
overallTotal: import_zod.z.number().nullable(),
|
|
@@ -1521,35 +1560,35 @@ function GenrePlaylistTracks({
|
|
|
1521
1560
|
started.catch((error) => {
|
|
1522
1561
|
console.error("Failed to play genre playlist:", error);
|
|
1523
1562
|
if (error instanceof import_genre_tree16.TracksFailureAlreadyReportedError) return;
|
|
1524
|
-
showPopup(/* @__PURE__ */ (0,
|
|
1563
|
+
showPopup(/* @__PURE__ */ (0, import_jsx_runtime28.jsx)(InternalErrorPopup, { errorCode: error instanceof import_transport5.AppError ? error.code : import_transport5.ErrorCode.CLIENT_UNKNOWN }));
|
|
1525
1564
|
});
|
|
1526
1565
|
};
|
|
1527
|
-
return /* @__PURE__ */ (0,
|
|
1566
|
+
return /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_ui8.PanelSection, { title: `${(0, import_track_noun.capitalize)(trackNoun.plural)}${total !== void 0 ? ` (${total})` : ""}`, children: /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("div", { children: [
|
|
1528
1567
|
renderTracksToolbar?.(),
|
|
1529
|
-
scope === "me" && !genrePlaylist ? /* @__PURE__ */ (0,
|
|
1568
|
+
scope === "me" && !genrePlaylist ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("p", { children: "\u2014" }) : isPending ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_ui8.Skeleton, { className: "h-4 w-3/4", "aria-busy": "true" }) : isError && tracks.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("p", { role: "alert", children: [
|
|
1530
1569
|
"Couldn't load ",
|
|
1531
1570
|
trackNoun.plural,
|
|
1532
1571
|
".",
|
|
1533
1572
|
" ",
|
|
1534
|
-
/* @__PURE__ */ (0,
|
|
1535
|
-
] }) : tracks.length === 0 ? /* @__PURE__ */ (0,
|
|
1573
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)("button", { type: "button", className: "underline", onClick: () => void refetch(), children: "Retry" })
|
|
1574
|
+
] }) : tracks.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("p", { children: "\u2014" }) : /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("ul", { className: "mt-1 max-h-64 overflow-y-auto text-body [container-type:inline-size]", "aria-label": `${genreName} ${trackNoun.plural}`, children: [
|
|
1536
1575
|
tracks.map((track, index) => {
|
|
1537
1576
|
const label = track.artists?.length ? `${track.title} \u2014 ${track.artists.map((artist2) => artist2.name).join(", ")}` : track.title;
|
|
1538
1577
|
const isCurrent = playerTrackObject?.track.id === track.uuid;
|
|
1539
1578
|
const isPlaying = isCurrent && playState === import_player6.PlayStates.PLAYING;
|
|
1540
|
-
const text = /* @__PURE__ */ (0,
|
|
1541
|
-
/* @__PURE__ */ (0,
|
|
1542
|
-
track.artists?.length ? /* @__PURE__ */ (0,
|
|
1543
|
-
/* @__PURE__ */ (0,
|
|
1544
|
-
track.album && /* @__PURE__ */ (0,
|
|
1579
|
+
const text = /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("span", { className: TEXT_CELL, children: [
|
|
1580
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)("span", { className: TITLE_CELL, children: renderSongLink ? renderSongLink(track) : (0, import_genre_tree15.isSong)(track) ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(MusicBrainzRecordingLink, { song: track, className: "hover:underline focus-visible:underline", children: track.title }) : track.title }),
|
|
1581
|
+
track.artists?.length ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("span", { className: SEPARATOR, children: " \u2014 " }) : null,
|
|
1582
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)("span", { className: COLUMN_CELL, children: track.artists?.length ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_genre_tree17.ArtistNames, { artists: track.artists, renderArtistLink }) : null }),
|
|
1583
|
+
track.album && /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("span", { className: ALBUM_CELL, children: track.album.name })
|
|
1545
1584
|
] });
|
|
1546
1585
|
const leading = renderSongLeading?.(track, index);
|
|
1547
1586
|
const actions = renderSongActions?.(track);
|
|
1548
1587
|
const isUnplayable = (0, import_genre_tree15.isSong)(track) && (0, import_genre_tree15.songUnplayableReason)(track) !== null;
|
|
1549
1588
|
if (isUnplayable) {
|
|
1550
|
-
return /* @__PURE__ */ (0,
|
|
1589
|
+
return /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("li", { className: "flex min-h-8 items-center gap-1 px-1 opacity-50", children: [
|
|
1551
1590
|
leading,
|
|
1552
|
-
/* @__PURE__ */ (0,
|
|
1591
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
|
|
1553
1592
|
"button",
|
|
1554
1593
|
{
|
|
1555
1594
|
type: "button",
|
|
@@ -1557,27 +1596,27 @@ function GenrePlaylistTracks({
|
|
|
1557
1596
|
"aria-disabled": "true",
|
|
1558
1597
|
"aria-label": label,
|
|
1559
1598
|
className: "flex h-6 w-6 shrink-0 items-center justify-center rounded-full opacity-0 cursor-not-allowed",
|
|
1560
|
-
children: /* @__PURE__ */ (0,
|
|
1599
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_fa2.FaPlay, { size: 10 })
|
|
1561
1600
|
}
|
|
1562
1601
|
),
|
|
1563
1602
|
text,
|
|
1564
1603
|
actions
|
|
1565
1604
|
] }, track.uuid);
|
|
1566
1605
|
}
|
|
1567
|
-
return /* @__PURE__ */ (0,
|
|
1606
|
+
return /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(
|
|
1568
1607
|
"li",
|
|
1569
1608
|
{
|
|
1570
1609
|
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)]" : ""}`,
|
|
1571
1610
|
children: [
|
|
1572
1611
|
leading,
|
|
1573
|
-
/* @__PURE__ */ (0,
|
|
1612
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
|
|
1574
1613
|
"button",
|
|
1575
1614
|
{
|
|
1576
1615
|
type: "button",
|
|
1577
1616
|
"aria-label": `${isPlaying ? "Pause" : "Play"} ${label}`,
|
|
1578
1617
|
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 !== import_player6.PlayStates.STOPPED ? "opacity-100" : "opacity-0 [@media(pointer:coarse)]:opacity-100"}`,
|
|
1579
1618
|
onClick: () => isCurrent ? handlePlayPauseAction() : play(track.uuid),
|
|
1580
|
-
children: isCurrent && playState === import_player6.PlayStates.LOADING ? /* @__PURE__ */ (0,
|
|
1619
|
+
children: isCurrent && playState === import_player6.PlayStates.LOADING ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_ui8.RingLoader, { size: 10 }) : isPlaying ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_fa2.FaPause, { size: 10 }) : /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_fa2.FaPlay, { size: 10 })
|
|
1581
1620
|
}
|
|
1582
1621
|
),
|
|
1583
1622
|
text,
|
|
@@ -1587,7 +1626,7 @@ function GenrePlaylistTracks({
|
|
|
1587
1626
|
track.uuid
|
|
1588
1627
|
);
|
|
1589
1628
|
}),
|
|
1590
|
-
hasNextPage && /* @__PURE__ */ (0,
|
|
1629
|
+
hasNextPage && /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("li", { ref: setSentinel, "aria-hidden": "true", className: "h-4" })
|
|
1591
1630
|
] })
|
|
1592
1631
|
] }) });
|
|
1593
1632
|
}
|
|
@@ -1595,7 +1634,7 @@ function GenrePlaylistTracks({
|
|
|
1595
1634
|
// src/genre-tree/GenreDetailExtras.tsx
|
|
1596
1635
|
var import_track_noun2 = require("@behindthemusictree/app-kit/track-noun");
|
|
1597
1636
|
var import_si2 = require("react-icons/si");
|
|
1598
|
-
var
|
|
1637
|
+
var import_jsx_runtime29 = require("react/jsx-runtime");
|
|
1599
1638
|
function GenreDetailExtras({
|
|
1600
1639
|
genreUuid,
|
|
1601
1640
|
genrePlaylist,
|
|
@@ -1621,17 +1660,18 @@ function GenreDetailExtras({
|
|
|
1621
1660
|
criteriaOverviewSchema
|
|
1622
1661
|
);
|
|
1623
1662
|
if (isPending) {
|
|
1624
|
-
return /* @__PURE__ */ (0,
|
|
1625
|
-
/* @__PURE__ */ (0,
|
|
1663
|
+
return /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(import_jsx_runtime29.Fragment, { children: [
|
|
1664
|
+
/* @__PURE__ */ (0, import_jsx_runtime29.jsx)(import_ui9.PanelSection, { title: "Summary", children: /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("div", { "aria-busy": "true", "data-testid": "genre-detail-extras-skeleton", children: /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(import_ui9.Skeleton, { className: "h-4 w-3/4" }) }) }),
|
|
1626
1665
|
family
|
|
1627
1666
|
] });
|
|
1628
1667
|
}
|
|
1629
|
-
if (!overview) return /* @__PURE__ */ (0,
|
|
1630
|
-
const { summary, summarySourceUrl, essentialSongs } = overview;
|
|
1668
|
+
if (!overview) return /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(import_jsx_runtime29.Fragment, { children: family });
|
|
1669
|
+
const { summary, summarySourceUrl, essentialSongs, image } = overview;
|
|
1631
1670
|
const wikidataUrl = wikidataId ? `https://www.wikidata.org/wiki/${encodeURIComponent(wikidataId)}` : null;
|
|
1632
|
-
return /* @__PURE__ */ (0,
|
|
1633
|
-
|
|
1634
|
-
|
|
1671
|
+
return /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(import_jsx_runtime29.Fragment, { children: [
|
|
1672
|
+
image && /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(CommonsPhoto, { image, alt: overview.name, creditLabel: "Image" }),
|
|
1673
|
+
(summarySourceUrl || wikidataUrl) && /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(import_ui9.PanelSection, { title: "Links", children: /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("div", { className: "flex flex-wrap gap-x-3 gap-y-1 text-caption text-[var(--color-text)]", children: [
|
|
1674
|
+
summarySourceUrl && /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(
|
|
1635
1675
|
"a",
|
|
1636
1676
|
{
|
|
1637
1677
|
href: summarySourceUrl,
|
|
@@ -1639,12 +1679,12 @@ function GenreDetailExtras({
|
|
|
1639
1679
|
rel: "noopener noreferrer",
|
|
1640
1680
|
className: "inline-flex items-center gap-1.5 text-[var(--color-text-muted)] hover:text-[var(--color-text)]",
|
|
1641
1681
|
children: [
|
|
1642
|
-
/* @__PURE__ */ (0,
|
|
1682
|
+
/* @__PURE__ */ (0, import_jsx_runtime29.jsx)(import_si2.SiWikipedia, { "aria-hidden": "true", className: "h-3.5 w-3.5" }),
|
|
1643
1683
|
"Wikipedia"
|
|
1644
1684
|
]
|
|
1645
1685
|
}
|
|
1646
1686
|
),
|
|
1647
|
-
wikidataUrl && /* @__PURE__ */ (0,
|
|
1687
|
+
wikidataUrl && /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(
|
|
1648
1688
|
"a",
|
|
1649
1689
|
{
|
|
1650
1690
|
href: wikidataUrl,
|
|
@@ -1652,17 +1692,17 @@ function GenreDetailExtras({
|
|
|
1652
1692
|
rel: "noopener noreferrer",
|
|
1653
1693
|
className: "inline-flex items-center gap-1.5 text-[var(--color-text-muted)] hover:text-[var(--color-text)]",
|
|
1654
1694
|
children: [
|
|
1655
|
-
/* @__PURE__ */ (0,
|
|
1695
|
+
/* @__PURE__ */ (0, import_jsx_runtime29.jsx)(import_si2.SiWikidata, { "aria-hidden": "true", className: "h-3.5 w-3.5" }),
|
|
1656
1696
|
"Wikidata"
|
|
1657
1697
|
]
|
|
1658
1698
|
}
|
|
1659
1699
|
)
|
|
1660
1700
|
] }) }),
|
|
1661
|
-
/* @__PURE__ */ (0,
|
|
1701
|
+
/* @__PURE__ */ (0, import_jsx_runtime29.jsx)(import_ui9.PanelSection, { title: "Summary", children: renderSummary ? renderSummary(overview) : /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(ClampedText, { className: "text-body text-[var(--color-text)]", children: summary ?? "\u2014" }, genreUuid) }),
|
|
1662
1702
|
family,
|
|
1663
1703
|
renderGenreDetailExtras?.(overview),
|
|
1664
|
-
(renderEssentialTracks || essentialSongs) && /* @__PURE__ */ (0,
|
|
1665
|
-
/* @__PURE__ */ (0,
|
|
1704
|
+
(renderEssentialTracks || essentialSongs) && /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(import_ui9.PanelSection, { title: `Essential ${trackNoun.plural}`, children: renderEssentialTracks ? renderEssentialTracks(overview) : essentialSongs && essentialSongs.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("ul", { className: "text-body text-[var(--color-text)]", children: essentialSongs.map((track) => /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("li", { className: "py-1", children: track.title }, track.uuid)) }) : /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("p", { className: "text-body text-[var(--color-text)]", children: "\u2014" }) }),
|
|
1705
|
+
/* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
|
|
1666
1706
|
GenrePlaylistTracks,
|
|
1667
1707
|
{
|
|
1668
1708
|
genreUuid,
|
|
@@ -1680,10 +1720,10 @@ function GenreDetailExtras({
|
|
|
1680
1720
|
}
|
|
1681
1721
|
|
|
1682
1722
|
// src/genre-tree/GenreInfoPanelBody.tsx
|
|
1683
|
-
var
|
|
1723
|
+
var import_jsx_runtime30 = require("react/jsx-runtime");
|
|
1684
1724
|
var import_react14 = require("react");
|
|
1685
1725
|
function GenreNodeActionBand({ genrePlaylist, playback, ...bandProps }) {
|
|
1686
|
-
return /* @__PURE__ */ (0,
|
|
1726
|
+
return /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(GenreActionBand, { ...bandProps, playActions: /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(GenrePlayActions, { genrePlaylist, playback }) });
|
|
1687
1727
|
}
|
|
1688
1728
|
function GenreInfoPanelBody({
|
|
1689
1729
|
toolbar,
|
|
@@ -1700,9 +1740,9 @@ function GenreInfoPanelBody({
|
|
|
1700
1740
|
}) {
|
|
1701
1741
|
const summary = scope === "reference" ? import_genre_tree19.GenreCatalogueCountsSchema.parse(genrePlaylist ?? catalogue) : void 0;
|
|
1702
1742
|
const selection = summary ? (0, import_genre_tree19.defaultGenreMusicSelection)(summary) : void 0;
|
|
1703
|
-
return /* @__PURE__ */ (0,
|
|
1743
|
+
return /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)(import_jsx_runtime30.Fragment, { children: [
|
|
1704
1744
|
toolbar,
|
|
1705
|
-
genrePlaylist ? /* @__PURE__ */ (0,
|
|
1745
|
+
genrePlaylist ? /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(GenreNodeActionBand, { ...band, genrePlaylist, playback }) : /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(GenreActionBand, { ...band }),
|
|
1706
1746
|
/* @__PURE__ */ (0, import_react14.createElement)(
|
|
1707
1747
|
GenreDetailExtras,
|
|
1708
1748
|
{
|
|
@@ -1722,7 +1762,7 @@ function GenreInfoPanelBody({
|
|
|
1722
1762
|
}
|
|
1723
1763
|
|
|
1724
1764
|
// src/genre-tree/GenreDetailPanel.tsx
|
|
1725
|
-
var
|
|
1765
|
+
var import_jsx_runtime31 = require("react/jsx-runtime");
|
|
1726
1766
|
var RELATIVE_ITEM_COUNT = 1;
|
|
1727
1767
|
function toNode(genre, parentId) {
|
|
1728
1768
|
return {
|
|
@@ -1745,27 +1785,21 @@ function useGenreDetailContent({
|
|
|
1745
1785
|
trailing,
|
|
1746
1786
|
genrePlaylist: hostPlaylist,
|
|
1747
1787
|
expanded,
|
|
1748
|
-
|
|
1788
|
+
treeStyles
|
|
1749
1789
|
}) {
|
|
1750
|
-
const
|
|
1790
|
+
const result = (0, import_genre_tree20.useFetchGenreDetail)(genreUuid, scope, getBackendBaseUrl);
|
|
1791
|
+
const detail = result.status === "success" ? result.genre : void 0;
|
|
1751
1792
|
const defaultPlayback = useGenrePlaylistPlayback({ scope, genrePlaylists: [], artist: extras?.artist });
|
|
1752
1793
|
const playback = hostPlayback ?? defaultPlayback;
|
|
1753
1794
|
const view = (0, import_react15.useMemo)(() => {
|
|
1754
1795
|
if (!detail) return null;
|
|
1755
1796
|
const rootColor = (0, import_genre_tree_view4.getGenreTreeColor)(detail.root.wikidataId);
|
|
1756
|
-
const treeStyles = /* @__PURE__ */ new Map();
|
|
1757
|
-
if (treeRelations) {
|
|
1758
|
-
const drawn = [treeRelations, treeRelations.parentNode, ...treeRelations.childNodes, ...treeRelations.ancestorNodes];
|
|
1759
|
-
for (const entry of drawn) {
|
|
1760
|
-
if (entry) treeStyles.set(entry.node.id, { fill: entry.fill, textColor: entry.textColor });
|
|
1761
|
-
}
|
|
1762
|
-
}
|
|
1763
1797
|
const relative = (genre, parentId) => ({
|
|
1764
1798
|
node: toNode(genre, parentId),
|
|
1765
|
-
...treeStyles
|
|
1799
|
+
...treeStyles?.get(genre.uuid) ?? { fill: (0, import_genre_tree_view4.tintSurface)(rootColor), textColor: import_genre_tree_view4.TEXT_COLOR }
|
|
1766
1800
|
});
|
|
1767
1801
|
const ancestors2 = [...detail.ascendants].sort((a, b) => b.degree - a.degree);
|
|
1768
|
-
const own = treeStyles
|
|
1802
|
+
const own = treeStyles?.get(detail.uuid) ?? { fill: rootColor, textColor: (0, import_genre_tree_view4.getTextColorOnFill)(rootColor) };
|
|
1769
1803
|
return {
|
|
1770
1804
|
node: {
|
|
1771
1805
|
id: detail.uuid,
|
|
@@ -1782,23 +1816,28 @@ function useGenreDetailContent({
|
|
|
1782
1816
|
({ ascendant }, index) => relative(ascendant, index === 0 ? null : ancestors2[index - 1].ascendant.uuid)
|
|
1783
1817
|
)
|
|
1784
1818
|
};
|
|
1785
|
-
}, [detail, scope,
|
|
1786
|
-
if (
|
|
1819
|
+
}, [detail, scope, treeStyles]);
|
|
1820
|
+
if (result.status === "not-found") return {
|
|
1821
|
+
name: null,
|
|
1822
|
+
title: "Genre not found",
|
|
1823
|
+
content: /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("p", { className: "text-[var(--color-text-muted)]", children: "This genre does not exist." })
|
|
1824
|
+
};
|
|
1825
|
+
if (result.status === "error") return {
|
|
1787
1826
|
name: null,
|
|
1788
1827
|
title: "Genre unavailable",
|
|
1789
|
-
content: /* @__PURE__ */ (0,
|
|
1828
|
+
content: /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("p", { role: "alert", className: "text-body text-[var(--color-text)]", children: "This genre could not be loaded." })
|
|
1790
1829
|
};
|
|
1791
|
-
if (
|
|
1830
|
+
if (!detail || !view) return {
|
|
1792
1831
|
name: null,
|
|
1793
1832
|
title: "Loading genre\u2026",
|
|
1794
|
-
content: /* @__PURE__ */ (0,
|
|
1795
|
-
/* @__PURE__ */ (0,
|
|
1796
|
-
/* @__PURE__ */ (0,
|
|
1797
|
-
/* @__PURE__ */ (0,
|
|
1833
|
+
content: /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)("div", { className: "flex flex-col gap-3", "aria-busy": "true", "data-testid": "genre-detail-panel-skeleton", children: [
|
|
1834
|
+
/* @__PURE__ */ (0, import_jsx_runtime31.jsx)(import_ui10.Skeleton, { className: "h-6 w-2/3" }),
|
|
1835
|
+
/* @__PURE__ */ (0, import_jsx_runtime31.jsx)(import_ui10.Skeleton, { className: "h-4 w-full" }),
|
|
1836
|
+
/* @__PURE__ */ (0, import_jsx_runtime31.jsx)(import_ui10.Skeleton, { className: "h-4 w-3/4" })
|
|
1798
1837
|
] })
|
|
1799
1838
|
};
|
|
1800
1839
|
const selectGenre = (nodeId) => onSelectGenre(import_genre_tree20.GenreUuidSchema.parse(nodeId));
|
|
1801
|
-
const family = /* @__PURE__ */ (0,
|
|
1840
|
+
const family = /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
|
|
1802
1841
|
import_genre_tree_view4.GenreNodeFamily,
|
|
1803
1842
|
{
|
|
1804
1843
|
node: view.node,
|
|
@@ -1809,17 +1848,17 @@ function useGenreDetailContent({
|
|
|
1809
1848
|
onSelectNode: selectGenre
|
|
1810
1849
|
}
|
|
1811
1850
|
);
|
|
1812
|
-
const ancestors = /* @__PURE__ */ (0,
|
|
1851
|
+
const ancestors = /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(import_genre_tree_view4.GenreNodeAncestors, { ancestorNodes: view.ancestorNodes, onSelectNode: selectGenre });
|
|
1813
1852
|
return {
|
|
1814
1853
|
name: detail.name,
|
|
1815
1854
|
title: detail.name,
|
|
1816
1855
|
headerAccent: { background: view.fill, color: view.textColor },
|
|
1817
1856
|
aside: expanded ? ancestors : void 0,
|
|
1818
|
-
content: /* @__PURE__ */ (0,
|
|
1819
|
-
/* @__PURE__ */ (0,
|
|
1857
|
+
content: /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)(import_jsx_runtime31.Fragment, { children: [
|
|
1858
|
+
/* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
|
|
1820
1859
|
GenreInfoPanelBody,
|
|
1821
1860
|
{
|
|
1822
|
-
family: /* @__PURE__ */ (0,
|
|
1861
|
+
family: /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)(import_jsx_runtime31.Fragment, { children: [
|
|
1823
1862
|
family,
|
|
1824
1863
|
!expanded && ancestors
|
|
1825
1864
|
] }),
|
|
@@ -1863,7 +1902,7 @@ function GenreDetailPanel({
|
|
|
1863
1902
|
expanded,
|
|
1864
1903
|
band: { onZoomIn, shareUrl, shareTarget: shareUrl ? shareTarget : void 0 }
|
|
1865
1904
|
});
|
|
1866
|
-
return /* @__PURE__ */ (0,
|
|
1905
|
+
return /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
|
|
1867
1906
|
import_ui10.DetailPanel,
|
|
1868
1907
|
{
|
|
1869
1908
|
side: "left",
|
|
@@ -1876,7 +1915,7 @@ function GenreDetailPanel({
|
|
|
1876
1915
|
edgeTab,
|
|
1877
1916
|
aside: panel.aside,
|
|
1878
1917
|
titleInSearch,
|
|
1879
|
-
headerActions: onExpandedChange ? /* @__PURE__ */ (0,
|
|
1918
|
+
headerActions: onExpandedChange ? /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(import_ui10.IconButton, { "aria-label": expanded ? "Shrink panel" : "Extend panel", onClick: () => onExpandedChange(!expanded), children: expanded ? /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(import_lucide_react9.Minimize2, { "aria-hidden": "true", className: "h-4 w-4" }) : /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(import_lucide_react9.Maximize2, { "aria-hidden": "true", className: "h-4 w-4" }) }) : void 0,
|
|
1880
1919
|
children: panel.content
|
|
1881
1920
|
}
|
|
1882
1921
|
);
|
|
@@ -1885,7 +1924,7 @@ function GenreDetailPanel({
|
|
|
1885
1924
|
// src/genre-tree/ChangeParentPopup.tsx
|
|
1886
1925
|
var import_react16 = require("react");
|
|
1887
1926
|
var import_genre_tree21 = require("@behindthemusictree/app-kit/genre-tree");
|
|
1888
|
-
var
|
|
1927
|
+
var import_jsx_runtime32 = require("react/jsx-runtime");
|
|
1889
1928
|
function ChangeParentPopup({
|
|
1890
1929
|
genrePlaylist,
|
|
1891
1930
|
genrePlaylists,
|
|
@@ -1920,12 +1959,12 @@ function ChangeParentPopup({
|
|
|
1920
1959
|
window.addEventListener("keydown", handleKeyDown);
|
|
1921
1960
|
return () => window.removeEventListener("keydown", handleKeyDown);
|
|
1922
1961
|
}, [onClose]);
|
|
1923
|
-
return /* @__PURE__ */ (0,
|
|
1924
|
-
/* @__PURE__ */ (0,
|
|
1962
|
+
return /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)(BasePopup_default, { title: `Change parent of ${genrePlaylist.name}`, onClose, showCancelButton: true, fitContent: true, children: [
|
|
1963
|
+
/* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("p", { className: "mb-3 text-body text-[var(--color-text-muted)]", children: [
|
|
1925
1964
|
"Current parent: ",
|
|
1926
1965
|
genrePlaylist.parent?.name ?? "none"
|
|
1927
1966
|
] }),
|
|
1928
|
-
/* @__PURE__ */ (0,
|
|
1967
|
+
/* @__PURE__ */ (0, import_jsx_runtime32.jsx)("div", { "aria-busy": isPending, className: isPending ? "pointer-events-none opacity-60" : void 0, children: /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
|
|
1929
1968
|
GenreSearch,
|
|
1930
1969
|
{
|
|
1931
1970
|
genrePlaylists: candidates,
|
|
@@ -1933,7 +1972,7 @@ function ChangeParentPopup({
|
|
|
1933
1972
|
placeholder: "Search a new parent\u2026"
|
|
1934
1973
|
}
|
|
1935
1974
|
) }),
|
|
1936
|
-
formErrors.length > 0 && /* @__PURE__ */ (0,
|
|
1975
|
+
formErrors.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("p", { role: "alert", className: "mt-3 text-body text-[var(--color-red-500)]", children: formErrors.map(({ message }) => message).join(" ") })
|
|
1937
1976
|
] });
|
|
1938
1977
|
}
|
|
1939
1978
|
|
|
@@ -1946,7 +1985,7 @@ var import_lucide_react10 = require("lucide-react");
|
|
|
1946
1985
|
var import_ui11 = require("@behindthemusictree/ui");
|
|
1947
1986
|
var import_genre_tree22 = require("@behindthemusictree/app-kit/genre-tree");
|
|
1948
1987
|
var import_player7 = require("@behindthemusictree/app-kit/player");
|
|
1949
|
-
var
|
|
1988
|
+
var import_jsx_runtime33 = require("react/jsx-runtime");
|
|
1950
1989
|
function ArtistActionBand({ artist, share }) {
|
|
1951
1990
|
const { trackList, playNewTrackListFromArtist } = (0, import_genre_tree22.useTrackList)();
|
|
1952
1991
|
const { isPlaying, setIsPlaying } = (0, import_player7.usePlayer)();
|
|
@@ -1962,11 +2001,11 @@ function ArtistActionBand({ artist, share }) {
|
|
|
1962
2001
|
console.error("Failed to load artist tracks:", error);
|
|
1963
2002
|
});
|
|
1964
2003
|
};
|
|
1965
|
-
return /* @__PURE__ */ (0,
|
|
1966
|
-
/* @__PURE__ */ (0,
|
|
2004
|
+
return /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(import_ui11.PanelBleed, { children: /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(import_ui11.ActionBand, { children: [
|
|
2005
|
+
/* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
|
|
1967
2006
|
import_ui11.ActionButton,
|
|
1968
2007
|
{
|
|
1969
|
-
icon: playing ? /* @__PURE__ */ (0,
|
|
2008
|
+
icon: playing ? /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(import_lucide_react10.Pause, { "aria-hidden": "true", className: "w-5 h-5" }) : /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(import_lucide_react10.Play, { "aria-hidden": "true", className: "w-5 h-5" }),
|
|
1970
2009
|
label: playing ? "Pause" : "Play",
|
|
1971
2010
|
caption: String(artist.playableTracksCount),
|
|
1972
2011
|
disabled: artist.playableTracksCount === 0,
|
|
@@ -1985,7 +2024,7 @@ var import_ui13 = require("@behindthemusictree/ui");
|
|
|
1985
2024
|
var import_lucide_react11 = require("lucide-react");
|
|
1986
2025
|
var import_si3 = require("react-icons/si");
|
|
1987
2026
|
var import_ui12 = require("@behindthemusictree/ui");
|
|
1988
|
-
var
|
|
2027
|
+
var import_jsx_runtime34 = require("react/jsx-runtime");
|
|
1989
2028
|
var LINK_KINDS = {
|
|
1990
2029
|
official: { label: "Official website", Icon: import_lucide_react11.Globe },
|
|
1991
2030
|
wikipedia: { label: "Wikipedia", Icon: import_si3.SiWikipedia },
|
|
@@ -2022,7 +2061,7 @@ function artistLinks(artist) {
|
|
|
2022
2061
|
return links;
|
|
2023
2062
|
}
|
|
2024
2063
|
function ArtistLinks({ links }) {
|
|
2025
|
-
return /* @__PURE__ */ (0,
|
|
2064
|
+
return /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("ul", { className: "flex flex-wrap gap-1.5", children: links.map(({ key, url, Icon, label }) => /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(import_ui12.Chip, { href: url, icon: /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(Icon, { className: "h-3.5 w-3.5 shrink-0", "aria-hidden": "true" }), children: label }) }, key)) });
|
|
2026
2065
|
}
|
|
2027
2066
|
|
|
2028
2067
|
// src/genre-tree/artist/formatYears.ts
|
|
@@ -2033,7 +2072,7 @@ function formatYears(beginYear, endYear, ended) {
|
|
|
2033
2072
|
}
|
|
2034
2073
|
|
|
2035
2074
|
// src/genre-tree/artist/ArtistHeader.tsx
|
|
2036
|
-
var
|
|
2075
|
+
var import_jsx_runtime35 = require("react/jsx-runtime");
|
|
2037
2076
|
var countryNames = new Intl.DisplayNames(["en"], { type: "region" });
|
|
2038
2077
|
function ArtistHeader({ artist }) {
|
|
2039
2078
|
const fields = [];
|
|
@@ -2043,35 +2082,23 @@ function ArtistHeader({ artist }) {
|
|
|
2043
2082
|
const years = formatYears(artist.beginYear, artist.endYear, artist.ended);
|
|
2044
2083
|
if (years) fields.push({ label: "Active", value: years });
|
|
2045
2084
|
const links = artistLinks(artist);
|
|
2046
|
-
if (links.length > 0) fields.push({ label: "Links", value: /* @__PURE__ */ (0,
|
|
2085
|
+
if (links.length > 0) fields.push({ label: "Links", value: /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(ArtistLinks, { links }) });
|
|
2047
2086
|
if (fields.length === 0) return null;
|
|
2048
|
-
return /* @__PURE__ */ (0,
|
|
2087
|
+
return /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(import_ui13.FieldList, { items: fields });
|
|
2049
2088
|
}
|
|
2050
2089
|
|
|
2051
2090
|
// src/genre-tree/artist/ArtistPhoto.tsx
|
|
2052
|
-
var
|
|
2053
|
-
function ExternalLink({ href, children }) {
|
|
2054
|
-
return /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("a", { href, target: "_blank", rel: "noopener noreferrer", className: "underline-offset-2 hover:underline", children });
|
|
2055
|
-
}
|
|
2091
|
+
var import_jsx_runtime36 = require("react/jsx-runtime");
|
|
2056
2092
|
function ArtistPhoto({ image, name }) {
|
|
2057
|
-
return /* @__PURE__ */ (0,
|
|
2058
|
-
/* @__PURE__ */ (0, import_jsx_runtime35.jsx)("img", { src: image.url, alt: name, className: "h-64 w-full object-contain bg-[var(--color-surface-muted)] rounded" }),
|
|
2059
|
-
/* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("figcaption", { className: "text-caption text-[var(--color-text-muted)]", children: [
|
|
2060
|
-
"Photo: ",
|
|
2061
|
-
/* @__PURE__ */ (0, import_jsx_runtime35.jsx)(ExternalLink, { href: image.pageUrl, children: image.author ?? "Wikimedia Commons" }),
|
|
2062
|
-
",",
|
|
2063
|
-
" ",
|
|
2064
|
-
image.licenseUrl ? /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(ExternalLink, { href: image.licenseUrl, children: image.license }) : image.license
|
|
2065
|
-
] })
|
|
2066
|
-
] });
|
|
2093
|
+
return /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(CommonsPhoto, { image, alt: name });
|
|
2067
2094
|
}
|
|
2068
2095
|
|
|
2069
2096
|
// src/genre-tree/artist/ArtistMembers.tsx
|
|
2070
2097
|
var import_ui14 = require("@behindthemusictree/ui");
|
|
2071
|
-
var
|
|
2098
|
+
var import_jsx_runtime37 = require("react/jsx-runtime");
|
|
2072
2099
|
function MembershipList({ title, memberships, renderArtistLink }) {
|
|
2073
2100
|
if (memberships.length === 0) return null;
|
|
2074
|
-
return /* @__PURE__ */ (0,
|
|
2101
|
+
return /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(import_ui14.PanelGroup, { title, children: /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("ul", { children: memberships.map((membership, index) => {
|
|
2075
2102
|
const details = [
|
|
2076
2103
|
formatYears(membership.beginYear, membership.endYear, membership.ended),
|
|
2077
2104
|
...membership.roles
|
|
@@ -2079,9 +2106,9 @@ function MembershipList({ title, memberships, renderArtistLink }) {
|
|
|
2079
2106
|
const detailsText = details.filter(Boolean).join(" \xB7 ");
|
|
2080
2107
|
return (
|
|
2081
2108
|
// A member can have several periods in the same group.
|
|
2082
|
-
/* @__PURE__ */ (0,
|
|
2083
|
-
/* @__PURE__ */ (0,
|
|
2084
|
-
detailsText && /* @__PURE__ */ (0,
|
|
2109
|
+
/* @__PURE__ */ (0, import_jsx_runtime37.jsxs)("li", { className: "truncate py-0.5", title: detailsText || void 0, children: [
|
|
2110
|
+
/* @__PURE__ */ (0, import_jsx_runtime37.jsx)("span", { className: "font-medium text-[var(--color-text)]", children: renderArtistLink(membership.artist) }),
|
|
2111
|
+
detailsText && /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)("span", { className: "text-[var(--color-text-muted)]", children: [
|
|
2085
2112
|
" \u2014 ",
|
|
2086
2113
|
detailsText
|
|
2087
2114
|
] })
|
|
@@ -2092,9 +2119,9 @@ function MembershipList({ title, memberships, renderArtistLink }) {
|
|
|
2092
2119
|
function ArtistMembers({ title, memberships, renderArtistLink }) {
|
|
2093
2120
|
if (memberships.length === 0) return null;
|
|
2094
2121
|
const isCurrent = (membership) => !membership.ended && membership.endYear === null;
|
|
2095
|
-
return /* @__PURE__ */ (0,
|
|
2096
|
-
/* @__PURE__ */ (0,
|
|
2097
|
-
/* @__PURE__ */ (0,
|
|
2122
|
+
return /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)(import_ui14.PanelSection, { title, children: [
|
|
2123
|
+
/* @__PURE__ */ (0, import_jsx_runtime37.jsx)(MembershipList, { title: "Current", memberships: memberships.filter(isCurrent), renderArtistLink }),
|
|
2124
|
+
/* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
|
|
2098
2125
|
MembershipList,
|
|
2099
2126
|
{
|
|
2100
2127
|
title: "Past",
|
|
@@ -2107,7 +2134,7 @@ function ArtistMembers({ title, memberships, renderArtistLink }) {
|
|
|
2107
2134
|
|
|
2108
2135
|
// src/genre-tree/artist/ArtistDiscography.tsx
|
|
2109
2136
|
var import_ui15 = require("@behindthemusictree/ui");
|
|
2110
|
-
var
|
|
2137
|
+
var import_jsx_runtime38 = require("react/jsx-runtime");
|
|
2111
2138
|
var GROUPS = ["Albums", "EPs", "Singles", "Live", "Compilations", "Other"];
|
|
2112
2139
|
var PRIMARY_GROUPS = { album: "Albums", ep: "EPs", single: "Singles" };
|
|
2113
2140
|
function discographyGroup({ primaryType, secondaryTypes }) {
|
|
@@ -2127,12 +2154,12 @@ function byYear(a, b) {
|
|
|
2127
2154
|
function ArtistDiscography({ albums }) {
|
|
2128
2155
|
if (albums.length === 0) return null;
|
|
2129
2156
|
const sorted = [...albums].sort(byYear);
|
|
2130
|
-
return /* @__PURE__ */ (0,
|
|
2157
|
+
return /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(import_ui15.PanelSection, { title: "Discography", children: GROUPS.map((group) => {
|
|
2131
2158
|
const groupAlbums = sorted.filter((album) => discographyGroup(album) === group);
|
|
2132
2159
|
if (groupAlbums.length === 0) return null;
|
|
2133
|
-
return /* @__PURE__ */ (0,
|
|
2134
|
-
/* @__PURE__ */ (0,
|
|
2135
|
-
/* @__PURE__ */ (0,
|
|
2160
|
+
return /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(import_ui15.PanelGroup, { title: group, children: /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("ul", { children: groupAlbums.map((album) => /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("li", { className: "grid grid-cols-[2.5rem_minmax(0,1fr)] gap-2 py-0.5", children: [
|
|
2161
|
+
/* @__PURE__ */ (0, import_jsx_runtime38.jsx)("span", { className: "tabular-nums text-[var(--color-text-muted)]", children: album.year ?? "\u2014" }),
|
|
2162
|
+
/* @__PURE__ */ (0, import_jsx_runtime38.jsx)("span", { className: "truncate text-[var(--color-text)]", title: album.name, children: album.name })
|
|
2136
2163
|
] }, album.uuid)) }) }, group);
|
|
2137
2164
|
}) });
|
|
2138
2165
|
}
|
|
@@ -2140,7 +2167,6 @@ function ArtistDiscography({ albums }) {
|
|
|
2140
2167
|
// src/genre-tree/artist/ArtistSongs.tsx
|
|
2141
2168
|
var import_react17 = require("react");
|
|
2142
2169
|
var import_react_query2 = require("@tanstack/react-query");
|
|
2143
|
-
var import_lucide_react12 = require("lucide-react");
|
|
2144
2170
|
var import_ui16 = require("@behindthemusictree/ui");
|
|
2145
2171
|
var import_player11 = require("@behindthemusictree/app-kit/player");
|
|
2146
2172
|
var import_genre_tree26 = require("@behindthemusictree/app-kit/genre-tree");
|
|
@@ -2154,7 +2180,7 @@ var import_genre_tree23 = require("@behindthemusictree/app-kit/genre-tree");
|
|
|
2154
2180
|
var import_fa3 = require("react-icons/fa");
|
|
2155
2181
|
var import_player8 = require("@behindthemusictree/app-kit/player");
|
|
2156
2182
|
var import_player9 = require("@behindthemusictree/app-kit/player");
|
|
2157
|
-
var
|
|
2183
|
+
var import_jsx_runtime39 = require("react/jsx-runtime");
|
|
2158
2184
|
function TrackPositionPlayPause({
|
|
2159
2185
|
position,
|
|
2160
2186
|
uuid,
|
|
@@ -2168,14 +2194,14 @@ function TrackPositionPlayPause({
|
|
|
2168
2194
|
const isPlaying = isThisTrack && isConfirmedPlayable && playState === import_player9.PlayStates.PLAYING;
|
|
2169
2195
|
const isPaused = isThisTrack && isConfirmedPlayable && playState === import_player9.PlayStates.PAUSED;
|
|
2170
2196
|
const isCurrentTrackActive = isPlaying || isPaused;
|
|
2171
|
-
return /* @__PURE__ */ (0,
|
|
2197
|
+
return /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)(
|
|
2172
2198
|
"div",
|
|
2173
2199
|
{
|
|
2174
2200
|
className: "track-position-play-pause relative flex items-center justify-center gap-2 text-lg w-16 cursor-pointer",
|
|
2175
2201
|
style: { minWidth: "4rem", maxWidth: "4rem" },
|
|
2176
2202
|
onClick: handlePlayPauseClick,
|
|
2177
2203
|
children: [
|
|
2178
|
-
/* @__PURE__ */ (0,
|
|
2204
|
+
/* @__PURE__ */ (0, import_jsx_runtime39.jsx)("div", { className: "track-position-play-pause__status group-hover:hidden flex items-center justify-center", children: isAwaitingPlayback ? /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("span", { className: "track-position-play-pause__spinner", role: "status", "aria-label": "Loading track" }) : isCurrentTrackActive ? /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)(
|
|
2179
2205
|
"span",
|
|
2180
2206
|
{
|
|
2181
2207
|
className: "track-position-play-pause__bars",
|
|
@@ -2183,18 +2209,18 @@ function TrackPositionPlayPause({
|
|
|
2183
2209
|
role: "img",
|
|
2184
2210
|
"aria-label": isPlaying ? "Playing" : "Paused",
|
|
2185
2211
|
children: [
|
|
2186
|
-
/* @__PURE__ */ (0,
|
|
2187
|
-
/* @__PURE__ */ (0,
|
|
2188
|
-
/* @__PURE__ */ (0,
|
|
2212
|
+
/* @__PURE__ */ (0, import_jsx_runtime39.jsx)("span", { className: "track-position-play-pause__bar" }),
|
|
2213
|
+
/* @__PURE__ */ (0, import_jsx_runtime39.jsx)("span", { className: "track-position-play-pause__bar" }),
|
|
2214
|
+
/* @__PURE__ */ (0, import_jsx_runtime39.jsx)("span", { className: "track-position-play-pause__bar" })
|
|
2189
2215
|
]
|
|
2190
2216
|
}
|
|
2191
2217
|
) : position }),
|
|
2192
|
-
/* @__PURE__ */ (0,
|
|
2218
|
+
/* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
|
|
2193
2219
|
"div",
|
|
2194
2220
|
{
|
|
2195
2221
|
className: `hidden group-hover:flex items-center justify-center ${isCurrentTrackActive ? "" : "absolute inset-0"}`,
|
|
2196
2222
|
"aria-hidden": "true",
|
|
2197
|
-
children: isAwaitingPlayback ? /* @__PURE__ */ (0,
|
|
2223
|
+
children: isAwaitingPlayback ? /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("span", { className: "track-position-play-pause__spinner" }) : isPlaying ? /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(import_fa3.FaPause, {}) : /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(import_fa3.FaPlay, {})
|
|
2198
2224
|
}
|
|
2199
2225
|
)
|
|
2200
2226
|
]
|
|
@@ -2205,7 +2231,7 @@ function TrackPositionPlayPause({
|
|
|
2205
2231
|
// src/genre-tree/track-list-sidebar/TrackItem.tsx
|
|
2206
2232
|
var import_genre_tree24 = require("@behindthemusictree/app-kit/genre-tree");
|
|
2207
2233
|
var import_genre_tree25 = require("@behindthemusictree/app-kit/genre-tree");
|
|
2208
|
-
var
|
|
2234
|
+
var import_jsx_runtime40 = require("react/jsx-runtime");
|
|
2209
2235
|
function TrackItem({
|
|
2210
2236
|
track,
|
|
2211
2237
|
position,
|
|
@@ -2229,12 +2255,12 @@ function TrackItem({
|
|
|
2229
2255
|
loadTrackForPlayer(track.uuid);
|
|
2230
2256
|
}
|
|
2231
2257
|
};
|
|
2232
|
-
return /* @__PURE__ */ (0,
|
|
2258
|
+
return /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)(
|
|
2233
2259
|
"div",
|
|
2234
2260
|
{
|
|
2235
2261
|
className: `track-item flex h-14 text-[var(--color-text)] ${isUnplayable ? "opacity-50" : "hover:bg-[var(--color-surface-muted)] group"}`,
|
|
2236
2262
|
children: [
|
|
2237
|
-
isUnplayable ? /* @__PURE__ */ (0,
|
|
2263
|
+
isUnplayable ? /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
|
|
2238
2264
|
"div",
|
|
2239
2265
|
{
|
|
2240
2266
|
className: "flex items-center justify-center text-lg w-16",
|
|
@@ -2242,7 +2268,7 @@ function TrackItem({
|
|
|
2242
2268
|
"aria-disabled": "true",
|
|
2243
2269
|
children: position
|
|
2244
2270
|
}
|
|
2245
|
-
) : /* @__PURE__ */ (0,
|
|
2271
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
|
|
2246
2272
|
TrackPositionPlayPause,
|
|
2247
2273
|
{
|
|
2248
2274
|
position,
|
|
@@ -2251,12 +2277,12 @@ function TrackItem({
|
|
|
2251
2277
|
isSelected: selectedTrack?.uuid === track.uuid
|
|
2252
2278
|
}
|
|
2253
2279
|
),
|
|
2254
|
-
/* @__PURE__ */ (0,
|
|
2255
|
-
/* @__PURE__ */ (0,
|
|
2256
|
-
track.artists && track.artists.length > 0 ? /* @__PURE__ */ (0,
|
|
2280
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("div", { className: "title-artist-container flex flex-col items-start justify-center min-w-0 flex-1", children: [
|
|
2281
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsx)("div", { className: "flex max-w-full items-center gap-2", children: /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("div", { className: "title text-lg font-bold text-[var(--color-text)] max-w-full truncate", children: renderSongLink ? renderSongLink(track) : (0, import_genre_tree24.isSong)(track) ? /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(MusicBrainzRecordingLink, { song: track, className: "hover:underline focus-visible:underline", children: track.title }) : track.title }) }),
|
|
2282
|
+
track.artists && track.artists.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("div", { className: "artist text-base max-w-full truncate text-[var(--color-text-muted)]", children: /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(import_genre_tree25.ArtistNames, { artists: track.artists, renderArtistLink }) }) : ""
|
|
2257
2283
|
] }),
|
|
2258
|
-
/* @__PURE__ */ (0,
|
|
2259
|
-
renderDuration && /* @__PURE__ */ (0,
|
|
2284
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsx)("div", { className: "genre-name-container flex items-center justify-start w-[21.6%] min-w-0 shrink-0", children: track.genre ? /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("div", { className: "genre-name max-w-full whitespace-normal break-words p-1 text-caption font-bold", children: track.genre.name }) : "" }),
|
|
2285
|
+
renderDuration && /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
|
|
2260
2286
|
"div",
|
|
2261
2287
|
{
|
|
2262
2288
|
className: "duration flex text-base w-16 items-center justify-center",
|
|
@@ -2264,14 +2290,14 @@ function TrackItem({
|
|
|
2264
2290
|
children: renderDuration(track)
|
|
2265
2291
|
}
|
|
2266
2292
|
),
|
|
2267
|
-
renderActions && /* @__PURE__ */ (0,
|
|
2293
|
+
renderActions && /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("div", { className: "edit flex text-base w-6 items-center justify-center mr-2 cursor-pointer", children: renderActions(track) })
|
|
2268
2294
|
]
|
|
2269
2295
|
}
|
|
2270
2296
|
);
|
|
2271
2297
|
}
|
|
2272
2298
|
|
|
2273
2299
|
// src/genre-tree/artist/ArtistSongs.tsx
|
|
2274
|
-
var
|
|
2300
|
+
var import_jsx_runtime41 = require("react/jsx-runtime");
|
|
2275
2301
|
var SongPageSchema2 = (0, import_transport6.PaginatedResponseSchema)(import_genre_tree26.SongDetailedSchema);
|
|
2276
2302
|
var SORTS = [
|
|
2277
2303
|
{ ordering: "title", label: "Title" },
|
|
@@ -2304,36 +2330,22 @@ function ArtistSongs({ artist, getBackendBaseUrl, renderArtistLink, renderSongLi
|
|
|
2304
2330
|
event.stopPropagation();
|
|
2305
2331
|
void play(song.uuid);
|
|
2306
2332
|
};
|
|
2307
|
-
return /* @__PURE__ */ (0,
|
|
2308
|
-
/* @__PURE__ */ (0,
|
|
2309
|
-
|
|
2310
|
-
|
|
2311
|
-
|
|
2312
|
-
|
|
2313
|
-
|
|
2314
|
-
|
|
2315
|
-
|
|
2316
|
-
/* @__PURE__ */ (0, import_jsx_runtime40.jsx)(import_lucide_react12.Play, { className: "h-3.5 w-3.5", "aria-hidden": "true" }),
|
|
2317
|
-
"Play all"
|
|
2318
|
-
]
|
|
2319
|
-
}
|
|
2320
|
-
),
|
|
2321
|
-
/* @__PURE__ */ (0, import_jsx_runtime40.jsx)("div", { role: "group", "aria-label": "Sort songs by", className: "flex gap-1 text-caption", children: SORTS.map((sort) => /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
|
|
2322
|
-
"button",
|
|
2323
|
-
{
|
|
2324
|
-
type: "button",
|
|
2325
|
-
"aria-pressed": ordering === sort.ordering,
|
|
2326
|
-
onClick: () => {
|
|
2327
|
-
setOrdering(sort.ordering);
|
|
2328
|
-
setPage(1);
|
|
2329
|
-
},
|
|
2330
|
-
className: "px-2.5 py-0.5 text-[var(--color-text)] rounded-full hover:bg-[var(--color-surface-muted)] aria-pressed:bg-gray-900 aria-pressed:text-white",
|
|
2331
|
-
children: sort.label
|
|
2333
|
+
return /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(import_ui16.PanelSection, { title: "Songs", children: isPending ? /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(import_ui16.Skeleton, { className: "h-14", "aria-busy": "true" }) : isError ? /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("p", { className: "text-red-600", children: "Could not load songs." }) : data.results.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("p", { className: "text-[var(--color-text-muted)]", children: "No songs yet." }) : /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)(import_jsx_runtime41.Fragment, { children: [
|
|
2334
|
+
/* @__PURE__ */ (0, import_jsx_runtime41.jsx)("div", { className: "flex flex-wrap items-center justify-end gap-2 mb-2", children: /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("div", { role: "group", "aria-label": "Sort songs by", className: "flex gap-1 text-caption", children: SORTS.map((sort) => /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
|
|
2335
|
+
"button",
|
|
2336
|
+
{
|
|
2337
|
+
type: "button",
|
|
2338
|
+
"aria-pressed": ordering === sort.ordering,
|
|
2339
|
+
onClick: () => {
|
|
2340
|
+
setOrdering(sort.ordering);
|
|
2341
|
+
setPage(1);
|
|
2332
2342
|
},
|
|
2333
|
-
|
|
2334
|
-
|
|
2335
|
-
|
|
2336
|
-
|
|
2343
|
+
className: "px-2.5 py-0.5 text-[var(--color-text)] rounded-full hover:bg-[var(--color-surface-muted)] aria-pressed:bg-gray-900 aria-pressed:text-white",
|
|
2344
|
+
children: sort.label
|
|
2345
|
+
},
|
|
2346
|
+
sort.ordering
|
|
2347
|
+
)) }) }),
|
|
2348
|
+
/* @__PURE__ */ (0, import_jsx_runtime41.jsx)("ul", { className: "overflow-hidden mb-2 bg-zinc-950 rounded-lg", children: data.results.map((song, index) => /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("li", { onClickCapture: (event) => handleRowClickCapture(event, song), children: /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
|
|
2337
2349
|
TrackItem,
|
|
2338
2350
|
{
|
|
2339
2351
|
track: song,
|
|
@@ -2342,12 +2354,12 @@ function ArtistSongs({ artist, getBackendBaseUrl, renderArtistLink, renderSongLi
|
|
|
2342
2354
|
renderSongLink
|
|
2343
2355
|
}
|
|
2344
2356
|
) }, song.uuid)) }),
|
|
2345
|
-
/* @__PURE__ */ (0,
|
|
2357
|
+
/* @__PURE__ */ (0, import_jsx_runtime41.jsx)(import_ui16.Pagination, { currentPage: page, totalPages: data.totalPages, onPageChange: setPage })
|
|
2346
2358
|
] }) });
|
|
2347
2359
|
}
|
|
2348
2360
|
|
|
2349
2361
|
// src/genre-tree/artist/useArtistPanel.tsx
|
|
2350
|
-
var
|
|
2362
|
+
var import_jsx_runtime42 = require("react/jsx-runtime");
|
|
2351
2363
|
function useArtistPanel({
|
|
2352
2364
|
uuid,
|
|
2353
2365
|
scope,
|
|
@@ -2368,26 +2380,26 @@ function useArtistPanel({
|
|
|
2368
2380
|
return {
|
|
2369
2381
|
...panel,
|
|
2370
2382
|
title: "Artist",
|
|
2371
|
-
content: /* @__PURE__ */ (0,
|
|
2372
|
-
/* @__PURE__ */ (0,
|
|
2373
|
-
/* @__PURE__ */ (0,
|
|
2374
|
-
/* @__PURE__ */ (0,
|
|
2375
|
-
/* @__PURE__ */ (0,
|
|
2376
|
-
/* @__PURE__ */ (0,
|
|
2377
|
-
/* @__PURE__ */ (0,
|
|
2383
|
+
content: /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { "aria-busy": "true", className: "flex flex-col gap-2.5", children: [
|
|
2384
|
+
/* @__PURE__ */ (0, import_jsx_runtime42.jsx)(import_ui17.Skeleton, { className: "h-3 w-16" }),
|
|
2385
|
+
/* @__PURE__ */ (0, import_jsx_runtime42.jsx)(import_ui17.Skeleton, { className: "h-4 w-32" }),
|
|
2386
|
+
/* @__PURE__ */ (0, import_jsx_runtime42.jsx)(import_ui17.Skeleton, { className: "h-3 w-16" }),
|
|
2387
|
+
/* @__PURE__ */ (0, import_jsx_runtime42.jsx)(import_ui17.Skeleton, { className: "h-4 w-24" }),
|
|
2388
|
+
/* @__PURE__ */ (0, import_jsx_runtime42.jsx)(import_ui17.Skeleton, { className: "h-16 mt-2.5" }),
|
|
2389
|
+
/* @__PURE__ */ (0, import_jsx_runtime42.jsx)(import_ui17.Skeleton, { className: "h-16" })
|
|
2378
2390
|
] })
|
|
2379
2391
|
};
|
|
2380
2392
|
case "not-found":
|
|
2381
2393
|
return {
|
|
2382
2394
|
...panel,
|
|
2383
2395
|
title: "Artist not found",
|
|
2384
|
-
content: /* @__PURE__ */ (0,
|
|
2396
|
+
content: /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("p", { className: "text-[var(--color-text-muted)]", children: "This artist does not exist." })
|
|
2385
2397
|
};
|
|
2386
2398
|
case "error":
|
|
2387
2399
|
return {
|
|
2388
2400
|
...panel,
|
|
2389
2401
|
title: "Artist",
|
|
2390
|
-
content: /* @__PURE__ */ (0,
|
|
2402
|
+
content: /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("p", { className: "text-red-600", children: "Could not load this artist." })
|
|
2391
2403
|
};
|
|
2392
2404
|
case "success": {
|
|
2393
2405
|
const { artist } = result;
|
|
@@ -2396,19 +2408,19 @@ function useArtistPanel({
|
|
|
2396
2408
|
return {
|
|
2397
2409
|
...panel,
|
|
2398
2410
|
title: artist.name,
|
|
2399
|
-
content: /* @__PURE__ */ (0,
|
|
2400
|
-
/* @__PURE__ */ (0,
|
|
2411
|
+
content: /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)(import_jsx_runtime42.Fragment, { children: [
|
|
2412
|
+
/* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
|
|
2401
2413
|
ArtistActionBand,
|
|
2402
2414
|
{
|
|
2403
2415
|
artist,
|
|
2404
|
-
share: shareTarget && shareUrl ? /* @__PURE__ */ (0,
|
|
2416
|
+
share: shareTarget && shareUrl ? /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(ShareActionButton, { target: shareTarget, url: shareUrl }) : void 0
|
|
2405
2417
|
}
|
|
2406
2418
|
),
|
|
2407
|
-
artist.image && /* @__PURE__ */ (0,
|
|
2408
|
-
/* @__PURE__ */ (0,
|
|
2409
|
-
/* @__PURE__ */ (0,
|
|
2410
|
-
/* @__PURE__ */ (0,
|
|
2411
|
-
artist.tracksCount > 0 && /* @__PURE__ */ (0,
|
|
2419
|
+
artist.image && /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(ArtistPhoto, { image: artist.image, name: artist.name }),
|
|
2420
|
+
/* @__PURE__ */ (0, import_jsx_runtime42.jsx)(ArtistHeader, { artist }),
|
|
2421
|
+
/* @__PURE__ */ (0, import_jsx_runtime42.jsx)(ArtistMembers, { title: "Members", memberships: artist.members, renderArtistLink }),
|
|
2422
|
+
/* @__PURE__ */ (0, import_jsx_runtime42.jsx)(ArtistMembers, { title: "Member of", memberships: artist.memberOf, renderArtistLink }),
|
|
2423
|
+
artist.tracksCount > 0 && /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
|
|
2412
2424
|
ArtistSongs,
|
|
2413
2425
|
{
|
|
2414
2426
|
artist: { uuid: artist.uuid, name: artist.name },
|
|
@@ -2418,7 +2430,7 @@ function useArtistPanel({
|
|
|
2418
2430
|
}
|
|
2419
2431
|
)
|
|
2420
2432
|
] }),
|
|
2421
|
-
extraContent: artist.albums.length > 0 ? /* @__PURE__ */ (0,
|
|
2433
|
+
extraContent: artist.albums.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(ArtistDiscography, { albums: artist.albums }) : void 0
|
|
2422
2434
|
};
|
|
2423
2435
|
}
|
|
2424
2436
|
}
|
|
@@ -2430,11 +2442,11 @@ var import_genre_tree29 = require("@behindthemusictree/app-kit/genre-tree");
|
|
|
2430
2442
|
|
|
2431
2443
|
// src/genre-tree/song/SongPanelContent.tsx
|
|
2432
2444
|
var import_react18 = require("react");
|
|
2433
|
-
var
|
|
2445
|
+
var import_lucide_react12 = require("lucide-react");
|
|
2434
2446
|
var import_ui18 = require("@behindthemusictree/ui");
|
|
2435
2447
|
var import_player12 = require("@behindthemusictree/app-kit/player");
|
|
2436
2448
|
var import_genre_tree28 = require("@behindthemusictree/app-kit/genre-tree");
|
|
2437
|
-
var
|
|
2449
|
+
var import_jsx_runtime43 = require("react/jsx-runtime");
|
|
2438
2450
|
var numberFormat = new Intl.NumberFormat("en");
|
|
2439
2451
|
var dateFormat = new Intl.DateTimeFormat("en", { dateStyle: "medium" });
|
|
2440
2452
|
var externalLink = "text-[var(--color-primary)] hover:underline focus-visible:underline";
|
|
@@ -2442,27 +2454,27 @@ function SongHistory({ uuid, getBackendBaseUrl }) {
|
|
|
2442
2454
|
const [open, setOpen] = (0, import_react18.useState)(false);
|
|
2443
2455
|
const history = (0, import_genre_tree28.useSongHistory)(uuid, getBackendBaseUrl, open);
|
|
2444
2456
|
let body = null;
|
|
2445
|
-
if (history.status === "loading") body = /* @__PURE__ */ (0,
|
|
2446
|
-
else if (history.status === "error") body = /* @__PURE__ */ (0,
|
|
2457
|
+
if (history.status === "loading") body = /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(import_ui18.Skeleton, { className: "h-10", "aria-busy": "true" });
|
|
2458
|
+
else if (history.status === "error") body = /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("p", { className: "text-red-600", children: "Could not load the history." });
|
|
2447
2459
|
else if (history.status === "success")
|
|
2448
|
-
body = history.entries.length === 0 ? /* @__PURE__ */ (0,
|
|
2449
|
-
/* @__PURE__ */ (0,
|
|
2450
|
-
entry.oldValue !== null || entry.newValue !== null ? /* @__PURE__ */ (0,
|
|
2460
|
+
body = history.entries.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("p", { className: "text-[var(--color-text-muted)]", children: "No changes yet." }) : /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("ul", { className: "divide-y divide-[var(--color-border)]", children: history.entries.map((entry) => /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("li", { className: "py-1.5 text-body", children: [
|
|
2461
|
+
/* @__PURE__ */ (0, import_jsx_runtime43.jsx)("span", { className: "font-medium", children: entry.action }),
|
|
2462
|
+
entry.oldValue !== null || entry.newValue !== null ? /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("span", { className: "text-[var(--color-text-muted)]", children: [
|
|
2451
2463
|
" ",
|
|
2452
2464
|
"\u2014 ",
|
|
2453
2465
|
entry.oldValue ?? "none",
|
|
2454
2466
|
" \u2192 ",
|
|
2455
2467
|
entry.newValue ?? "none"
|
|
2456
2468
|
] }) : null,
|
|
2457
|
-
/* @__PURE__ */ (0,
|
|
2469
|
+
/* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("span", { className: "block text-caption text-[var(--color-text-muted)]", children: [
|
|
2458
2470
|
entry.actorPseudo ?? "Anonymous",
|
|
2459
2471
|
" \xB7 ",
|
|
2460
2472
|
dateFormat.format(new Date(entry.createdOn))
|
|
2461
2473
|
] })
|
|
2462
2474
|
] }, entry.uuid)) });
|
|
2463
|
-
return /* @__PURE__ */ (0,
|
|
2464
|
-
/* @__PURE__ */ (0,
|
|
2465
|
-
/* @__PURE__ */ (0,
|
|
2475
|
+
return /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(import_ui18.PanelBleed, { padded: true, className: "border-t border-[var(--color-border)]", children: /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("details", { onToggle: (event) => setOpen(event.currentTarget.open), className: "pb-2.5", children: [
|
|
2476
|
+
/* @__PURE__ */ (0, import_jsx_runtime43.jsx)("summary", { className: `mt-2.5 cursor-pointer ${import_ui18.PANEL_LABEL_CLASS}`, children: "History" }),
|
|
2477
|
+
/* @__PURE__ */ (0, import_jsx_runtime43.jsx)("div", { className: "mt-1.5", children: body })
|
|
2466
2478
|
] }) });
|
|
2467
2479
|
}
|
|
2468
2480
|
function SongPanelContent(props) {
|
|
@@ -2481,13 +2493,13 @@ function SongPanelContent(props) {
|
|
|
2481
2493
|
const genre = song.genre;
|
|
2482
2494
|
fields.push({
|
|
2483
2495
|
label: "Genre",
|
|
2484
|
-
value: onSelectGenre ? /* @__PURE__ */ (0,
|
|
2485
|
-
index > 0 && /* @__PURE__ */ (0,
|
|
2486
|
-
/* @__PURE__ */ (0,
|
|
2496
|
+
value: onSelectGenre ? /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("button", { type: "button", onClick: () => onSelectGenre(genre), className: "hover:underline", children: genre.name }) : path ? /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("span", { className: "flex flex-wrap items-center gap-x-1", children: path.map((genrePlaylist, index) => /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("span", { children: [
|
|
2497
|
+
index > 0 && /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("span", { "aria-hidden": "true", children: "\u203A " }),
|
|
2498
|
+
/* @__PURE__ */ (0, import_jsx_runtime43.jsx)("button", { type: "button", onClick: () => props.onSelectGenrePlaylist?.(genrePlaylist), className: "hover:underline", children: genrePlaylist.name })
|
|
2487
2499
|
] }, genrePlaylist.uuid)) }) : song.genre.name
|
|
2488
2500
|
});
|
|
2489
2501
|
} else {
|
|
2490
|
-
fields.push({ label: "Genre", value: /* @__PURE__ */ (0,
|
|
2502
|
+
fields.push({ label: "Genre", value: /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("span", { className: "text-[var(--color-text-muted)]", children: "No genre" }) });
|
|
2491
2503
|
}
|
|
2492
2504
|
if (song.firstReleaseYear) fields.push({ label: "First released", value: song.firstReleaseYear });
|
|
2493
2505
|
const viewCount = song.youtubeVideo?.viewCount;
|
|
@@ -2497,11 +2509,11 @@ function SongPanelContent(props) {
|
|
|
2497
2509
|
const links = [];
|
|
2498
2510
|
if (musicBrainzUrl)
|
|
2499
2511
|
links.push(
|
|
2500
|
-
/* @__PURE__ */ (0,
|
|
2512
|
+
/* @__PURE__ */ (0, import_jsx_runtime43.jsx)("a", { href: musicBrainzUrl, target: "_blank", rel: "noopener noreferrer", className: externalLink, children: "MusicBrainz" }, "mb")
|
|
2501
2513
|
);
|
|
2502
2514
|
if (song.youtubeVideo)
|
|
2503
2515
|
links.push(
|
|
2504
|
-
/* @__PURE__ */ (0,
|
|
2516
|
+
/* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
|
|
2505
2517
|
"a",
|
|
2506
2518
|
{
|
|
2507
2519
|
href: `https://www.youtube.com/watch?v=${encodeURIComponent(song.youtubeVideo.id)}`,
|
|
@@ -2516,31 +2528,31 @@ function SongPanelContent(props) {
|
|
|
2516
2528
|
if (links.length > 0)
|
|
2517
2529
|
fields.push({
|
|
2518
2530
|
label: "Links",
|
|
2519
|
-
value: /* @__PURE__ */ (0,
|
|
2531
|
+
value: /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("span", { className: "flex gap-3", children: links })
|
|
2520
2532
|
});
|
|
2521
|
-
return /* @__PURE__ */ (0,
|
|
2522
|
-
/* @__PURE__ */ (0,
|
|
2523
|
-
/* @__PURE__ */ (0,
|
|
2533
|
+
return /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)(import_jsx_runtime43.Fragment, { children: [
|
|
2534
|
+
/* @__PURE__ */ (0, import_jsx_runtime43.jsx)(import_ui18.PanelBleed, { children: /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)(import_ui18.ActionBand, { children: [
|
|
2535
|
+
/* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
|
|
2524
2536
|
import_ui18.ActionButton,
|
|
2525
2537
|
{
|
|
2526
|
-
icon: isPlaying ? /* @__PURE__ */ (0,
|
|
2538
|
+
icon: isPlaying ? /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(import_lucide_react12.Pause, { "aria-hidden": "true", className: "w-5 h-5" }) : /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(import_lucide_react12.Play, { "aria-hidden": "true", className: "w-5 h-5" }),
|
|
2527
2539
|
label: isPlaying ? "Pause" : "Play",
|
|
2528
2540
|
disabled: !!unplayableReason,
|
|
2529
2541
|
title: unplayableReason ?? void 0,
|
|
2530
2542
|
onClick: () => isCurrent ? handlePlayPauseAction() : playNewTrackListFromTrackUuid(song, scope)
|
|
2531
2543
|
}
|
|
2532
2544
|
),
|
|
2533
|
-
shareUrl && /* @__PURE__ */ (0,
|
|
2545
|
+
shareUrl && /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(ShareActionButton, { target: shareTarget, url: shareUrl })
|
|
2534
2546
|
] }) }),
|
|
2535
|
-
song.artists && song.artists.length > 0 && /* @__PURE__ */ (0,
|
|
2536
|
-
/* @__PURE__ */ (0,
|
|
2537
|
-
song.essentialGenres && song.essentialGenres.length > 0 && /* @__PURE__ */ (0,
|
|
2538
|
-
/* @__PURE__ */ (0,
|
|
2547
|
+
song.artists && song.artists.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("p", { className: "text-[var(--color-text-muted)]", children: /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(import_genre_tree28.ArtistNames, { artists: song.artists, renderArtistLink }) }),
|
|
2548
|
+
/* @__PURE__ */ (0, import_jsx_runtime43.jsx)(import_ui18.FieldList, { items: fields }),
|
|
2549
|
+
song.essentialGenres && song.essentialGenres.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(import_ui18.PanelSection, { title: "Essential in", children: /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("ul", { children: song.essentialGenres.map((genre) => /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("li", { className: "py-0.5", children: genre.name }, genre.uuid)) }) }),
|
|
2550
|
+
/* @__PURE__ */ (0, import_jsx_runtime43.jsx)(SongHistory, { uuid: song.uuid, getBackendBaseUrl })
|
|
2539
2551
|
] });
|
|
2540
2552
|
}
|
|
2541
2553
|
|
|
2542
2554
|
// src/genre-tree/song/useSongPanel.tsx
|
|
2543
|
-
var
|
|
2555
|
+
var import_jsx_runtime44 = require("react/jsx-runtime");
|
|
2544
2556
|
function useSongPanel({
|
|
2545
2557
|
uuid,
|
|
2546
2558
|
scope,
|
|
@@ -2561,24 +2573,24 @@ function useSongPanel({
|
|
|
2561
2573
|
return {
|
|
2562
2574
|
...panel,
|
|
2563
2575
|
title: "Song",
|
|
2564
|
-
content: /* @__PURE__ */ (0,
|
|
2565
|
-
/* @__PURE__ */ (0,
|
|
2566
|
-
/* @__PURE__ */ (0,
|
|
2567
|
-
/* @__PURE__ */ (0,
|
|
2568
|
-
/* @__PURE__ */ (0,
|
|
2576
|
+
content: /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("div", { "aria-busy": "true", className: "flex flex-col gap-2.5", children: [
|
|
2577
|
+
/* @__PURE__ */ (0, import_jsx_runtime44.jsx)(import_ui19.Skeleton, { className: "h-3 w-16" }),
|
|
2578
|
+
/* @__PURE__ */ (0, import_jsx_runtime44.jsx)(import_ui19.Skeleton, { className: "h-4 w-32" }),
|
|
2579
|
+
/* @__PURE__ */ (0, import_jsx_runtime44.jsx)(import_ui19.Skeleton, { className: "h-3 w-16" }),
|
|
2580
|
+
/* @__PURE__ */ (0, import_jsx_runtime44.jsx)(import_ui19.Skeleton, { className: "h-4 w-24" })
|
|
2569
2581
|
] })
|
|
2570
2582
|
};
|
|
2571
2583
|
case "not-found":
|
|
2572
2584
|
return {
|
|
2573
2585
|
...panel,
|
|
2574
2586
|
title: "Song not found",
|
|
2575
|
-
content: /* @__PURE__ */ (0,
|
|
2587
|
+
content: /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("p", { className: "text-[var(--color-text-muted)]", children: "This song does not exist." })
|
|
2576
2588
|
};
|
|
2577
2589
|
case "error":
|
|
2578
2590
|
return {
|
|
2579
2591
|
...panel,
|
|
2580
2592
|
title: "Song",
|
|
2581
|
-
content: /* @__PURE__ */ (0,
|
|
2593
|
+
content: /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("p", { className: "text-red-600", children: "Could not load this song." })
|
|
2582
2594
|
};
|
|
2583
2595
|
case "success": {
|
|
2584
2596
|
const { song } = result;
|
|
@@ -2586,7 +2598,7 @@ function useSongPanel({
|
|
|
2586
2598
|
return {
|
|
2587
2599
|
...panel,
|
|
2588
2600
|
title: song.title,
|
|
2589
|
-
content: /* @__PURE__ */ (0,
|
|
2601
|
+
content: /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
|
|
2590
2602
|
SongPanelContent,
|
|
2591
2603
|
{
|
|
2592
2604
|
song,
|
|
@@ -2639,12 +2651,12 @@ function useEntityPanel({
|
|
|
2639
2651
|
// src/genre-tree/SizeMetricToggle.tsx
|
|
2640
2652
|
var import_md = require("react-icons/md");
|
|
2641
2653
|
var import_ui20 = require("@behindthemusictree/ui");
|
|
2642
|
-
var
|
|
2654
|
+
var import_jsx_runtime45 = require("react/jsx-runtime");
|
|
2643
2655
|
function SizeMetricToggle({
|
|
2644
2656
|
value,
|
|
2645
2657
|
onChange
|
|
2646
2658
|
}) {
|
|
2647
|
-
return /* @__PURE__ */ (0,
|
|
2659
|
+
return /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
|
|
2648
2660
|
import_ui20.SegmentedControl,
|
|
2649
2661
|
{
|
|
2650
2662
|
variant: "floating",
|
|
@@ -2652,15 +2664,15 @@ function SizeMetricToggle({
|
|
|
2652
2664
|
value,
|
|
2653
2665
|
onChange,
|
|
2654
2666
|
options: [
|
|
2655
|
-
{ value: "songs", label: /* @__PURE__ */ (0,
|
|
2656
|
-
{ value: "views", label: /* @__PURE__ */ (0,
|
|
2667
|
+
{ value: "songs", label: /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(import_md.MdMusicNote, { size: 18, "aria-hidden": true }), "aria-label": "Size by songs", title: "Node size by song count" },
|
|
2668
|
+
{ value: "views", label: /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(import_md.MdVisibility, { size: 18, "aria-hidden": true }), "aria-label": "Size by views", title: "Node size by song views" }
|
|
2657
2669
|
]
|
|
2658
2670
|
}
|
|
2659
2671
|
);
|
|
2660
2672
|
}
|
|
2661
2673
|
|
|
2662
2674
|
// src/genre-tree/GenreTreeView.tsx
|
|
2663
|
-
var
|
|
2675
|
+
var import_jsx_runtime46 = require("react/jsx-runtime");
|
|
2664
2676
|
var NO_POP_ROOT_TITLE = "This genre tree has no 'Mainstream Pop' root yet";
|
|
2665
2677
|
var REGIONS_CLASS = "[--gtv-center-left:var(--layout-center-left)] [--gtv-center-right:var(--layout-center-right)] [--gtv-center-top:var(--layout-band-top)]";
|
|
2666
2678
|
var noop = () => {
|
|
@@ -2768,7 +2780,7 @@ function GenreTreeView({
|
|
|
2768
2780
|
allowWheelRotation: internalAllowWheelRotation,
|
|
2769
2781
|
toggleWheelRotation,
|
|
2770
2782
|
onNodeHover: handleNodeHover
|
|
2771
|
-
} = (0,
|
|
2783
|
+
} = (0, import_genre_tree31.useGenreTreeViewState)({
|
|
2772
2784
|
scope,
|
|
2773
2785
|
getBackendBaseUrl,
|
|
2774
2786
|
viewMode: controlledViewMode,
|
|
@@ -2787,12 +2799,12 @@ function GenreTreeView({
|
|
|
2787
2799
|
restoreRootUuid = selectedGenrePlaylist.root.uuid;
|
|
2788
2800
|
setStackedRestoreOwner({ revision: restoreRevision, rootUuid: restoreRootUuid });
|
|
2789
2801
|
}
|
|
2790
|
-
const isGenreUpdating = (0, import_react_query3.useIsMutating)({ mutationKey:
|
|
2791
|
-
const { mutate: updateGenre } = (0,
|
|
2802
|
+
const isGenreUpdating = (0, import_react_query3.useIsMutating)({ mutationKey: import_genre_tree31.genreUpdateMutationKey }) > 0;
|
|
2803
|
+
const { mutate: updateGenre } = (0, import_genre_tree31.useUpdateGenre)(scope, getBackendBaseUrl);
|
|
2792
2804
|
const busy = deferredSizeMetric !== sizeMetric || isTreeFetching || isGenreUpdating;
|
|
2793
2805
|
const isArtistFiltered = artistUuid !== null;
|
|
2794
2806
|
const canSizeByViews = !isArtistFiltered && hasViewsCount(visibleGenrePlaylists);
|
|
2795
|
-
const artistResult = (0,
|
|
2807
|
+
const artistResult = (0, import_genre_tree31.useArtist)(artistUuid, artistSearchBaseUrl ?? getBackendBaseUrl);
|
|
2796
2808
|
const filterArtistName = artistResult.status === "success" ? artistResult.artist.name : null;
|
|
2797
2809
|
const filterArtist = (0, import_react19.useMemo)(
|
|
2798
2810
|
() => artistUuid !== null && filterArtistName !== null ? { uuid: artistUuid, name: filterArtistName } : null,
|
|
@@ -2812,14 +2824,14 @@ function GenreTreeView({
|
|
|
2812
2824
|
const openSongRef = (0, import_react19.useRef)(openSong);
|
|
2813
2825
|
openSongRef.current = openSong;
|
|
2814
2826
|
const resolvedRenderSongLink = (0, import_react19.useCallback)(
|
|
2815
|
-
(song) => renderSongLink ? renderSongLink(song) : /* @__PURE__ */ (0,
|
|
2827
|
+
(song) => renderSongLink ? renderSongLink(song) : /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("button", { type: "button", onClick: () => openSongRef.current(song.uuid), className: "hover:underline", children: song.title }),
|
|
2816
2828
|
[renderSongLink]
|
|
2817
2829
|
);
|
|
2818
2830
|
const [expandedSongUuid, setExpandedSongUuid] = (0, import_react19.useState)(null);
|
|
2819
2831
|
const [expandedArtistUuid, setExpandedArtistUuid] = (0, import_react19.useState)(null);
|
|
2820
2832
|
const artistBaseUrl = artistSearchBaseUrl ?? getBackendBaseUrl;
|
|
2821
2833
|
const songBaseUrl = getBackendBaseUrl;
|
|
2822
|
-
const resolvedRenderArtistLink = renderArtistLink ?? ((artist) => artist.isSpecialPurpose ? artist.name : /* @__PURE__ */ (0,
|
|
2834
|
+
const resolvedRenderArtistLink = renderArtistLink ?? ((artist) => artist.isSpecialPurpose ? artist.name : /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("button", { type: "button", onClick: () => openArtist(artist.uuid), className: "hover:underline", children: artist.name }));
|
|
2823
2835
|
const getGenrePath = (genre) => {
|
|
2824
2836
|
const path = [];
|
|
2825
2837
|
let current = visibleGenrePlaylists.find((playlist) => playlist.criteria?.uuid === genre.uuid);
|
|
@@ -2895,9 +2907,11 @@ function GenreTreeView({
|
|
|
2895
2907
|
!overlayPanel && hasSelectedGenreNode ? selectedNodeId : null,
|
|
2896
2908
|
resolveStyle
|
|
2897
2909
|
);
|
|
2898
|
-
const
|
|
2899
|
-
|
|
2900
|
-
|
|
2910
|
+
const treeStyles = (0, import_react19.useMemo)(() => toGenreNodeStyles(relations, visibleGenrePlaylists), [relations, visibleGenrePlaylists]);
|
|
2911
|
+
const validSelectedGenreUuid = (0, import_genre_tree30.toGenreUuid)(selectedGenreUuid);
|
|
2912
|
+
const [selectionHistory, setSelectionHistory] = (0, import_react19.useState)({ current: validSelectedGenreUuid, previous: null });
|
|
2913
|
+
if (selectionHistory.current !== validSelectedGenreUuid) {
|
|
2914
|
+
setSelectionHistory({ current: validSelectedGenreUuid, previous: selectionHistory.current ?? selectionHistory.previous });
|
|
2901
2915
|
}
|
|
2902
2916
|
const handlePrevious = selectionHistory.previous ? () => selectGenre(selectionHistory.previous) : void 0;
|
|
2903
2917
|
const { showPopup, hidePopup } = (0, import_popup4.usePopup)();
|
|
@@ -2929,7 +2943,7 @@ function GenreTreeView({
|
|
|
2929
2943
|
const canToggleSide = !readOnly && criteria !== void 0 && criteria !== null && parentPlaylist !== void 0 && parentPlaylist.parent === null;
|
|
2930
2944
|
const side = criteria?.side ?? "core";
|
|
2931
2945
|
const popSibling = canToggleSide && side === "core" ? visibleGenrePlaylists.find((sibling) => sibling.parent?.uuid === parentPlaylist.uuid && sibling.uuid !== genrePlaylist?.uuid && sibling.criteria?.side === "pop") : void 0;
|
|
2932
|
-
const shareTarget =
|
|
2946
|
+
const shareTarget = validSelectedGenreUuid ? { kind: "genre", genreUuid: validSelectedGenreUuid, name: criteria?.name ?? "Genre", scope, artistUuid } : void 0;
|
|
2933
2947
|
const shareUrl = shareTarget ? getShareUrlRef.current?.(shareTarget) ?? void 0 : void 0;
|
|
2934
2948
|
const genreContent = useGenreDetailContent({
|
|
2935
2949
|
genreUuid: selectedGenreUuid,
|
|
@@ -2940,7 +2954,7 @@ function GenreTreeView({
|
|
|
2940
2954
|
selectGenre(uuid);
|
|
2941
2955
|
},
|
|
2942
2956
|
expanded: isExpanded,
|
|
2943
|
-
|
|
2957
|
+
treeStyles,
|
|
2944
2958
|
playback,
|
|
2945
2959
|
genrePlaylist: selectedGenrePlaylist,
|
|
2946
2960
|
band: {
|
|
@@ -2951,7 +2965,7 @@ function GenreTreeView({
|
|
|
2951
2965
|
onAddChild: readOnly || !criteria ? void 0 : () => handleGenreCreationAction(criteria),
|
|
2952
2966
|
onRename: readOnly || !criteria ? void 0 : () => handleGenreRenameAction(criteria),
|
|
2953
2967
|
onChangeParent: readOnly || !genrePlaylist || !criteria ? void 0 : () => showPopup(
|
|
2954
|
-
/* @__PURE__ */ (0,
|
|
2968
|
+
/* @__PURE__ */ (0, import_jsx_runtime46.jsx)(
|
|
2955
2969
|
ChangeParentPopup,
|
|
2956
2970
|
{
|
|
2957
2971
|
genrePlaylist: { ...genrePlaylist, criteria },
|
|
@@ -2995,7 +3009,7 @@ function GenreTreeView({
|
|
|
2995
3009
|
onClose: otherPanel.onClose,
|
|
2996
3010
|
searchName: otherPanel.title
|
|
2997
3011
|
};
|
|
2998
|
-
} else if (selectedGenreUuid) {
|
|
3012
|
+
} else if (selectedGenreUuid !== null) {
|
|
2999
3013
|
activePanel = {
|
|
3000
3014
|
title: genreContent.title,
|
|
3001
3015
|
content: genreContent.content,
|
|
@@ -3012,19 +3026,19 @@ function GenreTreeView({
|
|
|
3012
3026
|
edge: activePanel.expanded ? { label: "Shrink panel", onClick: () => activePanel.onExpandedChange?.(false) } : isCollapsed ? null : { label: "Hide panel", onClick: () => changeCollapsed(true) },
|
|
3013
3027
|
center: activePanel.expanded ? null : isCollapsed ? { label: "Show panel", onClick: () => changeCollapsed(false) } : activePanel.onExpandedChange ? { label: "Extend panel", onClick: () => activePanel.onExpandedChange?.(true) } : null
|
|
3014
3028
|
} : void 0;
|
|
3015
|
-
const expandButton = placement === "default" && activePanel?.onExpandedChange ? /* @__PURE__ */ (0,
|
|
3029
|
+
const expandButton = placement === "default" && activePanel?.onExpandedChange ? /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(
|
|
3016
3030
|
import_ui21.IconButton,
|
|
3017
3031
|
{
|
|
3018
3032
|
"aria-label": activePanel.expanded ? "Shrink panel" : "Extend panel",
|
|
3019
3033
|
style: activePanel.headerAccent && { color: "inherit" },
|
|
3020
3034
|
onClick: () => activePanel.onExpandedChange?.(!activePanel.expanded),
|
|
3021
|
-
children: activePanel.expanded ? /* @__PURE__ */ (0,
|
|
3035
|
+
children: activePanel.expanded ? /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(import_lucide_react14.Minimize2, { "aria-hidden": "true", className: "h-4 w-4" }) : /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(import_lucide_react14.Maximize2, { "aria-hidden": "true", className: "h-4 w-4" })
|
|
3022
3036
|
}
|
|
3023
3037
|
) : null;
|
|
3024
3038
|
const renderArtistFilter = () => {
|
|
3025
3039
|
if (isLoading || !filterArtist) return null;
|
|
3026
|
-
return /* @__PURE__ */ (0,
|
|
3027
|
-
/* @__PURE__ */ (0,
|
|
3040
|
+
return /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("span", { className: "inline-flex items-center overflow-hidden rounded-full bg-[var(--color-neutral-100)] text-body", children: [
|
|
3041
|
+
/* @__PURE__ */ (0, import_jsx_runtime46.jsx)(
|
|
3028
3042
|
"button",
|
|
3029
3043
|
{
|
|
3030
3044
|
type: "button",
|
|
@@ -3036,7 +3050,7 @@ function GenreTreeView({
|
|
|
3036
3050
|
children: filterArtist.name
|
|
3037
3051
|
}
|
|
3038
3052
|
),
|
|
3039
|
-
/* @__PURE__ */ (0,
|
|
3053
|
+
/* @__PURE__ */ (0, import_jsx_runtime46.jsx)(
|
|
3040
3054
|
"button",
|
|
3041
3055
|
{
|
|
3042
3056
|
type: "button",
|
|
@@ -3048,8 +3062,8 @@ function GenreTreeView({
|
|
|
3048
3062
|
)
|
|
3049
3063
|
] });
|
|
3050
3064
|
};
|
|
3051
|
-
const actions = /* @__PURE__ */ (0,
|
|
3052
|
-
!isLoading && !isError && /* @__PURE__ */ (0,
|
|
3065
|
+
const actions = /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)(import_jsx_runtime46.Fragment, { children: [
|
|
3066
|
+
!isLoading && !isError && /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(
|
|
3053
3067
|
GenreTreeSearch,
|
|
3054
3068
|
{
|
|
3055
3069
|
artistBaseUrl,
|
|
@@ -3082,9 +3096,9 @@ function GenreTreeView({
|
|
|
3082
3096
|
extraGroups: extraSearchGroups
|
|
3083
3097
|
}
|
|
3084
3098
|
),
|
|
3085
|
-
!isLoading && !isError && filterArtist && /* @__PURE__ */ (0,
|
|
3086
|
-
/* @__PURE__ */ (0,
|
|
3087
|
-
!isLoading && !isError && !isControlled && /* @__PURE__ */ (0,
|
|
3099
|
+
!isLoading && !isError && filterArtist && /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("div", { className: "hidden w-full justify-center max-md:flex", children: renderArtistFilter() }),
|
|
3100
|
+
/* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("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: [
|
|
3101
|
+
!isLoading && !isError && !isControlled && /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(
|
|
3088
3102
|
import_ui21.SegmentedControl,
|
|
3089
3103
|
{
|
|
3090
3104
|
"aria-label": "Tree view mode",
|
|
@@ -3098,13 +3112,13 @@ function GenreTreeView({
|
|
|
3098
3112
|
]
|
|
3099
3113
|
}
|
|
3100
3114
|
),
|
|
3101
|
-
!isLoading && !isError && showDisplayOptions && /* @__PURE__ */ (0,
|
|
3115
|
+
!isLoading && !isError && showDisplayOptions && /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(
|
|
3102
3116
|
"div",
|
|
3103
3117
|
{
|
|
3104
3118
|
className: "flex items-center gap-1",
|
|
3105
3119
|
role: "group",
|
|
3106
3120
|
"aria-label": "Tree display options",
|
|
3107
|
-
children: !isRotationControlled && viewMode !== "stacked" && viewMode !== "outline" && /* @__PURE__ */ (0,
|
|
3121
|
+
children: !isRotationControlled && viewMode !== "stacked" && viewMode !== "outline" && /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(
|
|
3108
3122
|
import_ui21.Button,
|
|
3109
3123
|
{
|
|
3110
3124
|
variant: allowWheelRotation ? "default" : "outline",
|
|
@@ -3115,48 +3129,48 @@ function GenreTreeView({
|
|
|
3115
3129
|
)
|
|
3116
3130
|
}
|
|
3117
3131
|
),
|
|
3118
|
-
!isLoading && !isError && !readOnly && showAddRoot && /* @__PURE__ */ (0,
|
|
3132
|
+
!isLoading && !isError && !readOnly && showAddRoot && /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(
|
|
3119
3133
|
import_ui21.IconTextButton,
|
|
3120
3134
|
{
|
|
3121
|
-
icon:
|
|
3135
|
+
icon: import_lucide_react13.Plus,
|
|
3122
3136
|
text: "Add root",
|
|
3123
3137
|
onClick: () => handleGenreCreationAction(null)
|
|
3124
3138
|
}
|
|
3125
3139
|
)
|
|
3126
3140
|
] })
|
|
3127
3141
|
] });
|
|
3128
|
-
return /* @__PURE__ */ (0,
|
|
3142
|
+
return /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)(
|
|
3129
3143
|
"div",
|
|
3130
3144
|
{
|
|
3131
3145
|
"data-left-panel": isPanelShown && !isCollapsed ? void 0 : "hidden",
|
|
3132
3146
|
className: ["genre-tree-view relative flex flex-col h-full", placement === "regions" && REGIONS_CLASS, className2].filter(Boolean).join(" "),
|
|
3133
3147
|
children: [
|
|
3134
|
-
/* @__PURE__ */ (0,
|
|
3148
|
+
/* @__PURE__ */ (0, import_jsx_runtime46.jsx)(
|
|
3135
3149
|
"div",
|
|
3136
3150
|
{
|
|
3137
3151
|
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"}`,
|
|
3138
3152
|
children: actions
|
|
3139
3153
|
}
|
|
3140
3154
|
),
|
|
3141
|
-
!isLoading && !isError && filterArtist && /* @__PURE__ */ (0,
|
|
3155
|
+
!isLoading && !isError && filterArtist && /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(
|
|
3142
3156
|
"div",
|
|
3143
3157
|
{
|
|
3144
3158
|
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"}`,
|
|
3145
3159
|
children: renderArtistFilter()
|
|
3146
3160
|
}
|
|
3147
3161
|
),
|
|
3148
|
-
/* @__PURE__ */ (0,
|
|
3149
|
-
!isLoading && !isError && viewMode === "outline" && floatingControlsLeading && /* @__PURE__ */ (0,
|
|
3150
|
-
isLoading ? /* @__PURE__ */ (0,
|
|
3162
|
+
/* @__PURE__ */ (0, import_jsx_runtime46.jsx)("div", { className: "content-container flex-1 min-h-0 flex flex-row gap-4", children: /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("div", { className: "tree-view-container relative flex-1 min-w-0 flex flex-col h-full", children: [
|
|
3163
|
+
!isLoading && !isError && viewMode === "outline" && floatingControlsLeading && /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("div", { className: "absolute bottom-3 right-3 z-10", children: floatingControlsLeading }),
|
|
3164
|
+
isLoading ? /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(import_genre_tree_view5.GenreTreeViewSkeleton, { viewMode }) : isError ? /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("p", { role: "alert", className: "m-auto text-center", children: [
|
|
3151
3165
|
"Couldn't load the genre tree.",
|
|
3152
3166
|
" ",
|
|
3153
|
-
/* @__PURE__ */ (0,
|
|
3167
|
+
/* @__PURE__ */ (0, import_jsx_runtime46.jsx)("button", { type: "button", className: "underline", onClick: refetch, children: "Retry" })
|
|
3154
3168
|
] }) : viewMode === "wheel" ? (
|
|
3155
3169
|
// The info panel's top edge aligns with the tree's; the search bar floats `--layout-panel-inset` below it,
|
|
3156
3170
|
// and the header inset (the bar's height plus that inset) extends the header's fill behind the bar,
|
|
3157
3171
|
// Google Maps style; the 8px bottom padding mirrors the inset above the bar, and the hidden title's height is zeroed.
|
|
3158
3172
|
// The panel's own Zoom in button is hidden: the search bar carries it.
|
|
3159
|
-
/* @__PURE__ */ (0,
|
|
3173
|
+
/* @__PURE__ */ (0, import_jsx_runtime46.jsx)("div", { className: "tree-container search-overlay relative flex-1 w-full min-h-0 ", children: /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(GenreTreeWheelHandoff, { skeleton: /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(import_genre_tree_view5.GenreTreeWheelSkeleton, {}), onRevealedChange: setIsWheelRevealed, children: /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(
|
|
3160
3174
|
GenrePlaylistTreeWheel,
|
|
3161
3175
|
{
|
|
3162
3176
|
scope,
|
|
@@ -3174,9 +3188,9 @@ function GenreTreeView({
|
|
|
3174
3188
|
allowWheelRotation,
|
|
3175
3189
|
sizeMetric: isArtistFiltered || !canSizeByViews ? "songs" : deferredSizeMetric,
|
|
3176
3190
|
busy,
|
|
3177
|
-
floatingControlsLeading: floatingControlsLeading || canSizeByViews ? /* @__PURE__ */ (0,
|
|
3191
|
+
floatingControlsLeading: floatingControlsLeading || canSizeByViews ? /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("div", { className: "flex items-center gap-2", children: [
|
|
3178
3192
|
floatingControlsLeading,
|
|
3179
|
-
canSizeByViews && /* @__PURE__ */ (0,
|
|
3193
|
+
canSizeByViews && /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(SizeMetricToggle, { value: sizeMetric, onChange: changeSizeMetric })
|
|
3180
3194
|
] }) : void 0,
|
|
3181
3195
|
defaultViewport,
|
|
3182
3196
|
viewportRestore,
|
|
@@ -3185,7 +3199,7 @@ function GenreTreeView({
|
|
|
3185
3199
|
) }) })
|
|
3186
3200
|
) : viewMode === "pop-core" ? (
|
|
3187
3201
|
// Same as the wheel: the header inset extends its fill behind the floating search bar, Google Maps style.
|
|
3188
|
-
/* @__PURE__ */ (0,
|
|
3202
|
+
/* @__PURE__ */ (0, import_jsx_runtime46.jsx)("div", { className: "tree-container search-overlay relative flex-1 w-full min-h-0 ", children: /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(GenreTreeWheelHandoff, { skeleton: /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(import_genre_tree_view5.GenreTreeWheelSkeleton, {}), onRevealedChange: setIsWheelRevealed, children: /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(
|
|
3189
3203
|
GenrePlaylistTreeWheelRadialPopCore,
|
|
3190
3204
|
{
|
|
3191
3205
|
scope,
|
|
@@ -3203,9 +3217,9 @@ function GenreTreeView({
|
|
|
3203
3217
|
allowWheelRotation,
|
|
3204
3218
|
sizeMetric: isArtistFiltered || !canSizeByViews ? "songs" : deferredSizeMetric,
|
|
3205
3219
|
busy,
|
|
3206
|
-
floatingControlsLeading: floatingControlsLeading || canSizeByViews ? /* @__PURE__ */ (0,
|
|
3220
|
+
floatingControlsLeading: floatingControlsLeading || canSizeByViews ? /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("div", { className: "flex items-center gap-2", children: [
|
|
3207
3221
|
floatingControlsLeading,
|
|
3208
|
-
canSizeByViews && /* @__PURE__ */ (0,
|
|
3222
|
+
canSizeByViews && /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(SizeMetricToggle, { value: sizeMetric, onChange: changeSizeMetric })
|
|
3209
3223
|
] }) : void 0,
|
|
3210
3224
|
defaultViewport,
|
|
3211
3225
|
viewportRestore,
|
|
@@ -3213,7 +3227,7 @@ function GenreTreeView({
|
|
|
3213
3227
|
...focus
|
|
3214
3228
|
}
|
|
3215
3229
|
) }) })
|
|
3216
|
-
) : viewMode === "outline" ? /* @__PURE__ */ (0,
|
|
3230
|
+
) : viewMode === "outline" ? /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("div", { className: "tree-container flex-1 min-h-0 w-full overflow-y-auto relative", children: /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(
|
|
3217
3231
|
GenrePlaylistTreeWheelRadialPopCore,
|
|
3218
3232
|
{
|
|
3219
3233
|
outline: true,
|
|
@@ -3230,13 +3244,13 @@ function GenreTreeView({
|
|
|
3230
3244
|
selectedNodeId,
|
|
3231
3245
|
readOnly
|
|
3232
3246
|
}
|
|
3233
|
-
) }) : /* @__PURE__ */ (0,
|
|
3247
|
+
) }) : /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("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(
|
|
3234
3248
|
([uuid, genrePlaylistTreePerRoot]) => {
|
|
3235
|
-
return /* @__PURE__ */ (0,
|
|
3249
|
+
return /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(
|
|
3236
3250
|
"div",
|
|
3237
3251
|
{
|
|
3238
3252
|
className: "tree-per-root-container relative shrink-0 h-[28rem] mt-2 mr-16 p-2 bg-[var(--color-neutral-100)] rounded-lg",
|
|
3239
|
-
children: /* @__PURE__ */ (0,
|
|
3253
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("div", { className: "graph-container relative z-10 h-full", children: /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(
|
|
3240
3254
|
GenrePlaylistTreePerRoot,
|
|
3241
3255
|
{
|
|
3242
3256
|
scope,
|
|
@@ -3263,7 +3277,7 @@ function GenreTreeView({
|
|
|
3263
3277
|
);
|
|
3264
3278
|
}
|
|
3265
3279
|
) }),
|
|
3266
|
-
/* @__PURE__ */ (0,
|
|
3280
|
+
/* @__PURE__ */ (0, import_jsx_runtime46.jsx)(
|
|
3267
3281
|
import_ui21.DetailPanel,
|
|
3268
3282
|
{
|
|
3269
3283
|
ref: panelRef,
|
|
@@ -3278,7 +3292,7 @@ function GenreTreeView({
|
|
|
3278
3292
|
onExpandedChange: activePanel?.onExpandedChange,
|
|
3279
3293
|
aside: activePanel?.aside,
|
|
3280
3294
|
edgeTab: detailTab,
|
|
3281
|
-
children: activePanel?.aside && !activePanel.expanded ? /* @__PURE__ */ (0,
|
|
3295
|
+
children: activePanel?.aside && !activePanel.expanded ? /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)(import_jsx_runtime46.Fragment, { children: [
|
|
3282
3296
|
activePanel.content,
|
|
3283
3297
|
activePanel.aside
|
|
3284
3298
|
] }) : activePanel?.content
|
|
@@ -3295,11 +3309,11 @@ var import_genre_tree_view6 = require("@behindthemusictree/genre-tree-view");
|
|
|
3295
3309
|
|
|
3296
3310
|
// src/genre-tree/track-list-sidebar/TrackListSidebar.tsx
|
|
3297
3311
|
var import_react20 = require("react");
|
|
3298
|
-
var
|
|
3299
|
-
var import_genre_tree31 = require("@behindthemusictree/app-kit/genre-tree");
|
|
3312
|
+
var import_lucide_react15 = require("lucide-react");
|
|
3300
3313
|
var import_genre_tree32 = require("@behindthemusictree/app-kit/genre-tree");
|
|
3314
|
+
var import_genre_tree33 = require("@behindthemusictree/app-kit/genre-tree");
|
|
3301
3315
|
var import_track_noun3 = require("@behindthemusictree/app-kit/track-noun");
|
|
3302
|
-
var
|
|
3316
|
+
var import_jsx_runtime47 = require("react/jsx-runtime");
|
|
3303
3317
|
var useBrowserLayoutEffect = typeof window === "undefined" ? import_react20.useEffect : import_react20.useLayoutEffect;
|
|
3304
3318
|
function TrackListSidebar({
|
|
3305
3319
|
className: className2 = "",
|
|
@@ -3312,7 +3326,7 @@ function TrackListSidebar({
|
|
|
3312
3326
|
renderArtistLink,
|
|
3313
3327
|
renderSongLink
|
|
3314
3328
|
}) {
|
|
3315
|
-
const { trackList, loadMore, autoAdvanceScrollRequest } = (0,
|
|
3329
|
+
const { trackList, loadMore, autoAdvanceScrollRequest } = (0, import_genre_tree32.useTrackList)();
|
|
3316
3330
|
const trackNoun = (0, import_track_noun3.useTrackNoun)();
|
|
3317
3331
|
const trackListRef = (0, import_react20.useRef)(null);
|
|
3318
3332
|
const previousOriginRef = (0, import_react20.useRef)(trackList?.origin ?? null);
|
|
@@ -3401,25 +3415,25 @@ function TrackListSidebar({
|
|
|
3401
3415
|
}
|
|
3402
3416
|
};
|
|
3403
3417
|
const positionClasses = layout === "inline" ? "relative w-full flex h-full flex-col" : "fixed right-0 w-[50rem] flex flex-col";
|
|
3404
|
-
return trackList ? /* @__PURE__ */ (0,
|
|
3418
|
+
return trackList ? /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)(
|
|
3405
3419
|
"div",
|
|
3406
3420
|
{
|
|
3407
3421
|
"data-theme": "dark",
|
|
3408
3422
|
className: `track-list-sidebar ${positionClasses} rounded-2xl bg-[var(--color-surface)] pb-1 ${className2}`,
|
|
3409
3423
|
style: layout === "fixed" ? { top: "63.5px", maxHeight: "calc(100vh - 63.5px - 79px)" } : void 0,
|
|
3410
3424
|
children: [
|
|
3411
|
-
/* @__PURE__ */ (0,
|
|
3412
|
-
/* @__PURE__ */ (0,
|
|
3413
|
-
/* @__PURE__ */ (0,
|
|
3414
|
-
/* @__PURE__ */ (0,
|
|
3415
|
-
/* @__PURE__ */ (0,
|
|
3425
|
+
/* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("div", { className: "header flex h-16 items-center px-4 py-2 text-[var(--color-text)]", children: [
|
|
3426
|
+
/* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("div", { className: "min-w-0 flex flex-1 flex-col justify-center", children: [
|
|
3427
|
+
/* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("div", { className: "origin flex text-xl", children: [
|
|
3428
|
+
/* @__PURE__ */ (0, import_jsx_runtime47.jsx)("div", { className: "from h-auto flex flex-col justify-center items-center mr-2", children: "From" }),
|
|
3429
|
+
/* @__PURE__ */ (0, import_jsx_runtime47.jsx)("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__ */ (0, import_jsx_runtime47.jsx)("div", { className: "name max-w-full truncate", children: trackList.origin.label }) })
|
|
3416
3430
|
] }),
|
|
3417
|
-
/* @__PURE__ */ (0,
|
|
3418
|
-
trackList.origin.type ===
|
|
3431
|
+
/* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("div", { className: "info flex items-center text-body text-[var(--color-text-muted)]", children: [
|
|
3432
|
+
trackList.origin.type === import_genre_tree33.TrackListOriginType.GENRE_PLAYLIST ? "Genre \u2022 " : trackList.origin.type === import_genre_tree33.TrackListOriginType.ARTIST ? "Artist \u2022 " : `${trackNoun.singular} playlist \u2022 `,
|
|
3419
3433
|
`${trackList.total} ${trackList.total > 1 ? trackNoun.plural : trackNoun.singular}`
|
|
3420
3434
|
] })
|
|
3421
3435
|
] }),
|
|
3422
|
-
(isCollapsed && onExpand || !isCollapsed && onMinimize) && /* @__PURE__ */ (0,
|
|
3436
|
+
(isCollapsed && onExpand || !isCollapsed && onMinimize) && /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(
|
|
3423
3437
|
"button",
|
|
3424
3438
|
{
|
|
3425
3439
|
type: "button",
|
|
@@ -3428,11 +3442,11 @@ function TrackListSidebar({
|
|
|
3428
3442
|
"aria-expanded": !isCollapsed,
|
|
3429
3443
|
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"}`,
|
|
3430
3444
|
onClick: isCollapsed ? onExpand : onMinimize,
|
|
3431
|
-
children: /* @__PURE__ */ (0,
|
|
3445
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(import_lucide_react15.ListMusic, { "aria-hidden": "true", className: "h-5 w-5" })
|
|
3432
3446
|
}
|
|
3433
3447
|
)
|
|
3434
3448
|
] }),
|
|
3435
|
-
!isCollapsed && /* @__PURE__ */ (0,
|
|
3449
|
+
!isCollapsed && /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)(
|
|
3436
3450
|
"ul",
|
|
3437
3451
|
{
|
|
3438
3452
|
ref: trackListRef,
|
|
@@ -3442,7 +3456,7 @@ function TrackListSidebar({
|
|
|
3442
3456
|
onPointerDown: markUserScrollIntent,
|
|
3443
3457
|
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",
|
|
3444
3458
|
children: [
|
|
3445
|
-
trackList.tracks.map((track, index) => /* @__PURE__ */ (0,
|
|
3459
|
+
trackList.tracks.map((track, index) => /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("li", { "data-track-uuid": track.uuid, children: /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(
|
|
3446
3460
|
TrackItem,
|
|
3447
3461
|
{
|
|
3448
3462
|
track,
|
|
@@ -3453,7 +3467,7 @@ function TrackListSidebar({
|
|
|
3453
3467
|
renderSongLink
|
|
3454
3468
|
}
|
|
3455
3469
|
) }, track.uuid)),
|
|
3456
|
-
hasMore && /* @__PURE__ */ (0,
|
|
3470
|
+
hasMore && /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("li", { ref: loadMoreSentinelRef, "aria-hidden": "true", className: "h-px" })
|
|
3457
3471
|
]
|
|
3458
3472
|
}
|
|
3459
3473
|
)
|
|
@@ -3466,14 +3480,14 @@ function TrackListSidebar({
|
|
|
3466
3480
|
var import_react21 = require("react");
|
|
3467
3481
|
var import_tailwind_merge = require("tailwind-merge");
|
|
3468
3482
|
var import_player14 = require("@behindthemusictree/app-kit/player");
|
|
3469
|
-
var
|
|
3483
|
+
var import_genre_tree35 = require("@behindthemusictree/app-kit/genre-tree");
|
|
3470
3484
|
var import_ui22 = require("@behindthemusictree/ui");
|
|
3471
3485
|
|
|
3472
3486
|
// src/genre-tree/PlayerControls.tsx
|
|
3473
|
-
var
|
|
3474
|
-
var
|
|
3487
|
+
var import_lucide_react16 = require("lucide-react");
|
|
3488
|
+
var import_genre_tree34 = require("@behindthemusictree/app-kit/genre-tree");
|
|
3475
3489
|
var import_player13 = require("@behindthemusictree/app-kit/player");
|
|
3476
|
-
var
|
|
3490
|
+
var import_jsx_runtime48 = require("react/jsx-runtime");
|
|
3477
3491
|
function PlayerControls() {
|
|
3478
3492
|
const {
|
|
3479
3493
|
duration,
|
|
@@ -3485,22 +3499,22 @@ function PlayerControls() {
|
|
|
3485
3499
|
setVolume,
|
|
3486
3500
|
volume
|
|
3487
3501
|
} = (0, import_player13.usePlayer)();
|
|
3488
|
-
const { hasNextTrack, hasPreviousTrack, playNextTrack, playPreviousTrack } = (0,
|
|
3502
|
+
const { hasNextTrack, hasPreviousTrack, playNextTrack, playPreviousTrack } = (0, import_genre_tree34.useTrackList)();
|
|
3489
3503
|
const currentTime = (0, import_player13.useCurrentTime)();
|
|
3490
3504
|
const isBusy = isLoading || playState === import_player13.PlayStates.LOADING;
|
|
3491
3505
|
const isReady = !!playerTrackObject?.isReady && !isBusy && !playerTrackObject.loadError;
|
|
3492
3506
|
const safeDuration = Number.isFinite(duration) && duration > 0 ? duration : 0;
|
|
3493
3507
|
const safeCurrentTime = Number.isFinite(currentTime) ? Math.max(0, Math.min(currentTime, safeDuration)) : 0;
|
|
3494
3508
|
const isPlaying = playState === import_player13.PlayStates.PLAYING;
|
|
3495
|
-
return /* @__PURE__ */ (0,
|
|
3509
|
+
return /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)(
|
|
3496
3510
|
"section",
|
|
3497
3511
|
{
|
|
3498
3512
|
"aria-label": "Player controls",
|
|
3499
3513
|
className: "player-controls flex shrink-0 flex-col gap-2 border-b border-zinc-800 px-3 py-2 text-zinc-200",
|
|
3500
3514
|
children: [
|
|
3501
|
-
/* @__PURE__ */ (0,
|
|
3502
|
-
/* @__PURE__ */ (0,
|
|
3503
|
-
/* @__PURE__ */ (0,
|
|
3515
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("div", { className: "flex min-w-0 items-center gap-2 text-xs tabular-nums text-zinc-400", children: [
|
|
3516
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)("span", { "aria-label": "Elapsed time", children: (0, import_genre_tree34.formatTime)(safeCurrentTime) }),
|
|
3517
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
|
|
3504
3518
|
"input",
|
|
3505
3519
|
{
|
|
3506
3520
|
"aria-label": "Seek",
|
|
@@ -3514,11 +3528,11 @@ function PlayerControls() {
|
|
|
3514
3528
|
onChange: (event) => seekTo(Number(event.currentTarget.value))
|
|
3515
3529
|
}
|
|
3516
3530
|
),
|
|
3517
|
-
/* @__PURE__ */ (0,
|
|
3531
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)("span", { "aria-label": "Duration", children: (0, import_genre_tree34.formatTime)(safeDuration) })
|
|
3518
3532
|
] }),
|
|
3519
|
-
/* @__PURE__ */ (0,
|
|
3520
|
-
/* @__PURE__ */ (0,
|
|
3521
|
-
/* @__PURE__ */ (0,
|
|
3533
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("div", { className: "grid min-h-9 grid-cols-[1fr_auto_1fr] items-center gap-3", children: [
|
|
3534
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("div", { className: "col-start-2 flex items-center justify-center gap-2", children: [
|
|
3535
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
|
|
3522
3536
|
"button",
|
|
3523
3537
|
{
|
|
3524
3538
|
type: "button",
|
|
@@ -3527,10 +3541,10 @@ function PlayerControls() {
|
|
|
3527
3541
|
disabled: !isReady || !hasPreviousTrack,
|
|
3528
3542
|
onClick: playPreviousTrack,
|
|
3529
3543
|
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",
|
|
3530
|
-
children: /* @__PURE__ */ (0,
|
|
3544
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(import_lucide_react16.SkipBack, { "aria-hidden": "true", className: "h-4 w-4" })
|
|
3531
3545
|
}
|
|
3532
3546
|
),
|
|
3533
|
-
/* @__PURE__ */ (0,
|
|
3547
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
|
|
3534
3548
|
"button",
|
|
3535
3549
|
{
|
|
3536
3550
|
type: "button",
|
|
@@ -3539,10 +3553,10 @@ function PlayerControls() {
|
|
|
3539
3553
|
disabled: !isReady,
|
|
3540
3554
|
onClick: handlePlayPauseAction,
|
|
3541
3555
|
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",
|
|
3542
|
-
children: isPlaying ? /* @__PURE__ */ (0,
|
|
3556
|
+
children: isPlaying ? /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(import_lucide_react16.Pause, { "aria-hidden": "true", className: "h-4 w-4", fill: "currentColor" }) : /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(import_lucide_react16.Play, { "aria-hidden": "true", className: "h-4 w-4", fill: "currentColor" })
|
|
3543
3557
|
}
|
|
3544
3558
|
),
|
|
3545
|
-
/* @__PURE__ */ (0,
|
|
3559
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
|
|
3546
3560
|
"button",
|
|
3547
3561
|
{
|
|
3548
3562
|
type: "button",
|
|
@@ -3551,14 +3565,14 @@ function PlayerControls() {
|
|
|
3551
3565
|
disabled: !isReady || !hasNextTrack,
|
|
3552
3566
|
onClick: playNextTrack,
|
|
3553
3567
|
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",
|
|
3554
|
-
children: /* @__PURE__ */ (0,
|
|
3568
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(import_lucide_react16.SkipForward, { "aria-hidden": "true", className: "h-4 w-4" })
|
|
3555
3569
|
}
|
|
3556
3570
|
)
|
|
3557
3571
|
] }),
|
|
3558
|
-
/* @__PURE__ */ (0,
|
|
3559
|
-
volume === 0 ? /* @__PURE__ */ (0,
|
|
3560
|
-
/* @__PURE__ */ (0,
|
|
3561
|
-
/* @__PURE__ */ (0,
|
|
3572
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("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: [
|
|
3573
|
+
volume === 0 ? /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(import_lucide_react16.VolumeX, { "aria-hidden": "true", className: "h-[0.7rem] w-[0.7rem] shrink-0" }) : /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(import_lucide_react16.Volume2, { "aria-hidden": "true", className: "h-[0.7rem] w-[0.7rem] shrink-0" }),
|
|
3574
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)("span", { className: "sr-only", children: "Volume" }),
|
|
3575
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
|
|
3562
3576
|
"input",
|
|
3563
3577
|
{
|
|
3564
3578
|
"aria-label": "Volume",
|
|
@@ -3580,7 +3594,7 @@ function PlayerControls() {
|
|
|
3580
3594
|
}
|
|
3581
3595
|
|
|
3582
3596
|
// src/genre-tree/PlayerPanel.tsx
|
|
3583
|
-
var
|
|
3597
|
+
var import_jsx_runtime49 = require("react/jsx-runtime");
|
|
3584
3598
|
var PANEL_ID = "player-panel";
|
|
3585
3599
|
var DEFAULT_EXTENDED_WIDTH = "calc(100vw - var(--layout-center-left) - var(--layout-gutter))";
|
|
3586
3600
|
function PlayerPanel({
|
|
@@ -3593,7 +3607,7 @@ function PlayerPanel({
|
|
|
3593
3607
|
renderSongLink
|
|
3594
3608
|
}) {
|
|
3595
3609
|
const { playerTrackObject, retryPlayback } = (0, import_player14.usePlayer)();
|
|
3596
|
-
const { toggleTrackListSidebar, isTrackListSidebarVisible } = (0,
|
|
3610
|
+
const { toggleTrackListSidebar, isTrackListSidebarVisible } = (0, import_genre_tree35.useTrackListSidebarVisibility)();
|
|
3597
3611
|
const [lastLoadedTrackTitle, setLastLoadedTrackTitle] = (0, import_react21.useState)("");
|
|
3598
3612
|
const loadedTrackTitle = playerTrackObject?.track.title;
|
|
3599
3613
|
(0, import_react21.useEffect)(() => {
|
|
@@ -3620,7 +3634,7 @@ function PlayerPanel({
|
|
|
3620
3634
|
onClick: () => setIsExtendRequested(true),
|
|
3621
3635
|
expanded: false
|
|
3622
3636
|
} : null;
|
|
3623
|
-
return /* @__PURE__ */ (0,
|
|
3637
|
+
return /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)(
|
|
3624
3638
|
"div",
|
|
3625
3639
|
{
|
|
3626
3640
|
id: PANEL_ID,
|
|
@@ -3633,7 +3647,7 @@ function PlayerPanel({
|
|
|
3633
3647
|
),
|
|
3634
3648
|
style: isExtended ? { width: extendedWidth } : void 0,
|
|
3635
3649
|
children: [
|
|
3636
|
-
/* @__PURE__ */ (0,
|
|
3650
|
+
/* @__PURE__ */ (0, import_jsx_runtime49.jsx)(
|
|
3637
3651
|
import_ui22.PanelEdgeTab,
|
|
3638
3652
|
{
|
|
3639
3653
|
side: "right",
|
|
@@ -3643,7 +3657,7 @@ function PlayerPanel({
|
|
|
3643
3657
|
className: "absolute right-full top-1/2 -translate-y-1/2"
|
|
3644
3658
|
}
|
|
3645
3659
|
),
|
|
3646
|
-
/* @__PURE__ */ (0,
|
|
3660
|
+
/* @__PURE__ */ (0, import_jsx_runtime49.jsxs)(
|
|
3647
3661
|
"div",
|
|
3648
3662
|
{
|
|
3649
3663
|
className: (0, import_tailwind_merge.twMerge)(
|
|
@@ -3651,20 +3665,20 @@ function PlayerPanel({
|
|
|
3651
3665
|
isExtended ? "flex-row" : "flex-col"
|
|
3652
3666
|
),
|
|
3653
3667
|
children: [
|
|
3654
|
-
/* @__PURE__ */ (0,
|
|
3655
|
-
/* @__PURE__ */ (0,
|
|
3656
|
-
/* @__PURE__ */ (0,
|
|
3657
|
-
/* @__PURE__ */ (0,
|
|
3658
|
-
playerTrackObject?.loadError && /* @__PURE__ */ (0,
|
|
3668
|
+
/* @__PURE__ */ (0, import_jsx_runtime49.jsxs)("div", { className: "flex w-[var(--layout-right-w)] shrink-0 flex-col", children: [
|
|
3669
|
+
/* @__PURE__ */ (0, import_jsx_runtime49.jsx)("div", { className: "flex shrink-0 items-center justify-between gap-2 border-b border-zinc-800 p-2", children: /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("span", { className: "min-w-0 truncate text-sm font-semibold", children: loadedTrackTitle || lastLoadedTrackTitle }) }),
|
|
3670
|
+
/* @__PURE__ */ (0, import_jsx_runtime49.jsxs)("div", { className: "relative w-full shrink-0", children: [
|
|
3671
|
+
/* @__PURE__ */ (0, import_jsx_runtime49.jsx)(import_player14.PlayerVideoSurface, { className: "aspect-video w-full bg-black" }),
|
|
3672
|
+
playerTrackObject?.loadError && /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)("span", { className: "absolute bottom-2 left-2 right-2 text-xs text-red-400", children: [
|
|
3659
3673
|
playerTrackObject.loadError,
|
|
3660
|
-
/* @__PURE__ */ (0,
|
|
3674
|
+
/* @__PURE__ */ (0, import_jsx_runtime49.jsx)("button", { type: "button", className: "ml-2 underline", onClick: () => {
|
|
3661
3675
|
void retryPlayback();
|
|
3662
3676
|
}, children: "Retry" })
|
|
3663
3677
|
] })
|
|
3664
3678
|
] }),
|
|
3665
|
-
/* @__PURE__ */ (0,
|
|
3679
|
+
/* @__PURE__ */ (0, import_jsx_runtime49.jsx)(PlayerControls, {})
|
|
3666
3680
|
] }),
|
|
3667
|
-
/* @__PURE__ */ (0,
|
|
3681
|
+
/* @__PURE__ */ (0, import_jsx_runtime49.jsx)(
|
|
3668
3682
|
TrackListSidebar,
|
|
3669
3683
|
{
|
|
3670
3684
|
layout: "inline",
|
|
@@ -3690,33 +3704,33 @@ function PlayerPanel({
|
|
|
3690
3704
|
// src/genre-tree/Rating.tsx
|
|
3691
3705
|
var import_uuid = require("uuid");
|
|
3692
3706
|
var import_ai = require("react-icons/ai");
|
|
3693
|
-
var
|
|
3694
|
-
var
|
|
3707
|
+
var import_genre_tree36 = require("@behindthemusictree/app-kit/genre-tree");
|
|
3708
|
+
var import_jsx_runtime50 = require("react/jsx-runtime");
|
|
3695
3709
|
function Rating({ rating, handleChange }) {
|
|
3696
3710
|
const instanceId = (0, import_uuid.v4)();
|
|
3697
|
-
return /* @__PURE__ */ (0,
|
|
3698
|
-
/* @__PURE__ */ (0,
|
|
3711
|
+
return /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("div", { className: "flex items-center", children: [...Array(6)].map((_, i) => /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)("div", { className: `relative ${i === 0 ? "mr-4" : "mr-1"}`, children: [
|
|
3712
|
+
/* @__PURE__ */ (0, import_jsx_runtime50.jsx)(
|
|
3699
3713
|
"input",
|
|
3700
3714
|
{
|
|
3701
3715
|
id: `star-${instanceId}-${i}`,
|
|
3702
3716
|
className: "w-6 h-6 opacity-0",
|
|
3703
3717
|
type: "radio",
|
|
3704
3718
|
name: "rating",
|
|
3705
|
-
value: i === 0 ?
|
|
3719
|
+
value: i === 0 ? import_genre_tree36.FORM_RATING_NULL_VALUE : i,
|
|
3706
3720
|
checked: rating === (i === 0 ? null : i),
|
|
3707
3721
|
onChange: handleChange
|
|
3708
3722
|
}
|
|
3709
3723
|
),
|
|
3710
|
-
/* @__PURE__ */ (0,
|
|
3711
|
-
/* @__PURE__ */ (0,
|
|
3724
|
+
/* @__PURE__ */ (0, import_jsx_runtime50.jsx)("label", { htmlFor: `star-${instanceId}-${i}`, className: "cursor-pointer", children: i === 0 ? /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)("div", { className: "flex", children: [
|
|
3725
|
+
/* @__PURE__ */ (0, import_jsx_runtime50.jsx)(
|
|
3712
3726
|
import_ai.AiOutlineStar,
|
|
3713
3727
|
{
|
|
3714
|
-
className: `w-7 h-7 absolute top-0 left-0 ${rating ===
|
|
3728
|
+
className: `w-7 h-7 absolute top-0 left-0 ${rating === import_genre_tree36.FORM_RATING_NULL_VALUE ? "text-[var(--color-accent-rating)]" : "text-[var(--color-text-muted)]"}`
|
|
3715
3729
|
}
|
|
3716
3730
|
),
|
|
3717
|
-
/* @__PURE__ */ (0,
|
|
3731
|
+
/* @__PURE__ */ (0, import_jsx_runtime50.jsx)("span", { className: "flex-grow w-8" }),
|
|
3718
3732
|
" "
|
|
3719
|
-
] }) : /* @__PURE__ */ (0,
|
|
3733
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(
|
|
3720
3734
|
import_ai.AiFillStar,
|
|
3721
3735
|
{
|
|
3722
3736
|
className: `w-7 h-7 absolute top-0 left-0 ${(rating ?? -1) >= i ? "text-[var(--color-accent-rating)]" : "text-[var(--color-text-muted)]"}`
|
|
@@ -3728,7 +3742,7 @@ function Rating({ rating, handleChange }) {
|
|
|
3728
3742
|
// src/genre-tree/EntityDetailPanel.tsx
|
|
3729
3743
|
var import_react22 = require("react");
|
|
3730
3744
|
var import_ui23 = require("@behindthemusictree/ui");
|
|
3731
|
-
var
|
|
3745
|
+
var import_jsx_runtime51 = require("react/jsx-runtime");
|
|
3732
3746
|
function EntityDetailPanel({
|
|
3733
3747
|
scope,
|
|
3734
3748
|
getBackendBaseUrl,
|
|
@@ -3751,8 +3765,8 @@ function EntityDetailPanel({
|
|
|
3751
3765
|
getBackendBaseUrl,
|
|
3752
3766
|
getArtistBackendBaseUrl,
|
|
3753
3767
|
getShareUrl,
|
|
3754
|
-
renderArtistLink: renderArtistLink ?? ((artist) => artist.isSpecialPurpose ? artist.name : /* @__PURE__ */ (0,
|
|
3755
|
-
renderSongLink: renderSongLink ?? ((song) => /* @__PURE__ */ (0,
|
|
3768
|
+
renderArtistLink: renderArtistLink ?? ((artist) => artist.isSpecialPurpose ? artist.name : /* @__PURE__ */ (0, import_jsx_runtime51.jsx)("button", { type: "button", onClick: () => onArtistUuidChange(artist.uuid), className: "hover:underline", children: artist.name })),
|
|
3769
|
+
renderSongLink: renderSongLink ?? ((song) => /* @__PURE__ */ (0, import_jsx_runtime51.jsx)("button", { type: "button", onClick: () => onSongUuidChange(song.uuid), className: "hover:underline", children: song.title })),
|
|
3756
3770
|
song: {
|
|
3757
3771
|
uuid: songUuid,
|
|
3758
3772
|
expanded: songUuid !== null && expandedSongUuid === songUuid,
|
|
@@ -3768,7 +3782,7 @@ function EntityDetailPanel({
|
|
|
3768
3782
|
...navigation
|
|
3769
3783
|
});
|
|
3770
3784
|
if (!panel) return null;
|
|
3771
|
-
return /* @__PURE__ */ (0,
|
|
3785
|
+
return /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(
|
|
3772
3786
|
import_ui23.DetailPanel,
|
|
3773
3787
|
{
|
|
3774
3788
|
side: "left",
|
|
@@ -3780,7 +3794,7 @@ function EntityDetailPanel({
|
|
|
3780
3794
|
onExpandedChange: panel.onExpandedChange,
|
|
3781
3795
|
aside: panel.extraContent,
|
|
3782
3796
|
edgeTab,
|
|
3783
|
-
children: panel.extraContent && !panel.expanded ? /* @__PURE__ */ (0,
|
|
3797
|
+
children: panel.extraContent && !panel.expanded ? /* @__PURE__ */ (0, import_jsx_runtime51.jsxs)(import_jsx_runtime51.Fragment, { children: [
|
|
3784
3798
|
panel.content,
|
|
3785
3799
|
panel.extraContent
|
|
3786
3800
|
] }) : panel.content
|