@behindthemusictree/app-kit-ui 40.1.0 → 42.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/{chunk-DPYUE6WD.js → chunk-PVYUC2PN.js} +336 -279
- package/dist/chunk-PVYUC2PN.js.map +1 -0
- package/dist/genre-tree/index.cjs +344 -291
- package/dist/genre-tree/index.cjs.map +1 -1
- package/dist/genre-tree/index.d.ts +15 -7
- package/dist/genre-tree/index.js +1 -1
- package/dist/index.cjs +344 -291
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +1 -1
- package/package.json +3 -3
- package/dist/chunk-DPYUE6WD.js.map +0 -1
package/dist/index.cjs
CHANGED
|
@@ -596,6 +596,7 @@ var import_lucide_react18 = require("lucide-react");
|
|
|
596
596
|
var import_ui24 = require("@behindthemusictree/ui");
|
|
597
597
|
var import_genre_tree_view5 = require("@behindthemusictree/genre-tree-view");
|
|
598
598
|
var import_genre_tree30 = require("@behindthemusictree/app-kit/genre-tree");
|
|
599
|
+
var import_genre_tree31 = require("@behindthemusictree/app-kit/genre-tree");
|
|
599
600
|
var import_popup5 = require("@behindthemusictree/app-kit/popup");
|
|
600
601
|
|
|
601
602
|
// src/genre-tree/playlist-tree/size-metric.ts
|
|
@@ -1700,6 +1701,29 @@ function ClampedText({ children, className: className2 = "" }) {
|
|
|
1700
1701
|
] });
|
|
1701
1702
|
}
|
|
1702
1703
|
|
|
1704
|
+
// src/genre-tree/CommonsPhoto.tsx
|
|
1705
|
+
var import_jsx_runtime32 = require("react/jsx-runtime");
|
|
1706
|
+
function ExternalLink({ href, children }) {
|
|
1707
|
+
return /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("a", { href, target: "_blank", rel: "noopener noreferrer", className: "underline-offset-2 hover:underline", children });
|
|
1708
|
+
}
|
|
1709
|
+
function CommonsPhoto({
|
|
1710
|
+
image,
|
|
1711
|
+
alt,
|
|
1712
|
+
creditLabel = "Photo"
|
|
1713
|
+
}) {
|
|
1714
|
+
return /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("figure", { className: "flex flex-col gap-1.5", children: [
|
|
1715
|
+
/* @__PURE__ */ (0, import_jsx_runtime32.jsx)("img", { src: image.url, alt, className: "h-64 w-full object-contain bg-[var(--color-surface-muted)] rounded" }),
|
|
1716
|
+
/* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("figcaption", { className: "text-caption text-[var(--color-text-muted)]", children: [
|
|
1717
|
+
creditLabel,
|
|
1718
|
+
": ",
|
|
1719
|
+
/* @__PURE__ */ (0, import_jsx_runtime32.jsx)(ExternalLink, { href: image.pageUrl, children: image.author ?? "Wikimedia Commons" }),
|
|
1720
|
+
",",
|
|
1721
|
+
" ",
|
|
1722
|
+
image.licenseUrl ? /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(ExternalLink, { href: image.licenseUrl, children: image.license }) : image.license
|
|
1723
|
+
] })
|
|
1724
|
+
] });
|
|
1725
|
+
}
|
|
1726
|
+
|
|
1703
1727
|
// src/genre-tree/GenrePlaylistTracks.tsx
|
|
1704
1728
|
var import_react13 = require("react");
|
|
1705
1729
|
var import_react_query = require("@tanstack/react-query");
|
|
@@ -1722,15 +1746,15 @@ var import_genre_tree16 = require("@behindthemusictree/app-kit/genre-tree");
|
|
|
1722
1746
|
|
|
1723
1747
|
// src/genre-tree/MusicBrainzRecordingLink.tsx
|
|
1724
1748
|
var import_genre_tree11 = require("@behindthemusictree/app-kit/genre-tree");
|
|
1725
|
-
var
|
|
1749
|
+
var import_jsx_runtime33 = require("react/jsx-runtime");
|
|
1726
1750
|
function MusicBrainzRecordingLink({
|
|
1727
1751
|
song,
|
|
1728
1752
|
children,
|
|
1729
1753
|
className: className2 = ""
|
|
1730
1754
|
}) {
|
|
1731
1755
|
const url = (0, import_genre_tree11.musicBrainzRecordingUrl)(song);
|
|
1732
|
-
if (!url) return /* @__PURE__ */ (0,
|
|
1733
|
-
return /* @__PURE__ */ (0,
|
|
1756
|
+
if (!url) return /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(import_jsx_runtime33.Fragment, { children });
|
|
1757
|
+
return /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
|
|
1734
1758
|
"a",
|
|
1735
1759
|
{
|
|
1736
1760
|
href: url,
|
|
@@ -1747,7 +1771,7 @@ function MusicBrainzRecordingLink({
|
|
|
1747
1771
|
// src/genre-tree/GenrePlaylistTracks.tsx
|
|
1748
1772
|
var import_genre_tree17 = require("@behindthemusictree/app-kit/genre-tree");
|
|
1749
1773
|
var import_track_noun2 = require("@behindthemusictree/app-kit/track-noun");
|
|
1750
|
-
var
|
|
1774
|
+
var import_jsx_runtime34 = require("react/jsx-runtime");
|
|
1751
1775
|
var CATALOGUE_PAGE_SIZE = 100;
|
|
1752
1776
|
var SongPageSchema = (0, import_transport5.PaginatedResponseSchema)(import_genre_tree15.SongDetailedSchema).extend({
|
|
1753
1777
|
overallTotal: import_zod.z.number().nullable(),
|
|
@@ -1834,35 +1858,35 @@ function GenrePlaylistTracks({
|
|
|
1834
1858
|
started.catch((error) => {
|
|
1835
1859
|
console.error("Failed to play genre playlist:", error);
|
|
1836
1860
|
if (error instanceof import_genre_tree16.TracksFailureAlreadyReportedError) return;
|
|
1837
|
-
showPopup(/* @__PURE__ */ (0,
|
|
1861
|
+
showPopup(/* @__PURE__ */ (0, import_jsx_runtime34.jsx)(InternalErrorPopup, { errorCode: error instanceof import_transport7.AppError ? error.code : import_transport7.ErrorCode.CLIENT_UNKNOWN }));
|
|
1838
1862
|
});
|
|
1839
1863
|
};
|
|
1840
|
-
return /* @__PURE__ */ (0,
|
|
1864
|
+
return /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(import_ui11.PanelSection, { title: `${(0, import_track_noun2.capitalize)(trackNoun.plural)}${total !== void 0 ? ` (${total})` : ""}`, children: /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("div", { children: [
|
|
1841
1865
|
renderTracksToolbar?.(),
|
|
1842
|
-
scope === "me" && !genrePlaylist ? /* @__PURE__ */ (0,
|
|
1866
|
+
scope === "me" && !genrePlaylist ? /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("p", { children: "\u2014" }) : isPending ? /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(import_ui11.Skeleton, { className: "h-4 w-3/4", "aria-busy": "true" }) : isError && tracks.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("p", { role: "alert", children: [
|
|
1843
1867
|
"Couldn't load ",
|
|
1844
1868
|
trackNoun.plural,
|
|
1845
1869
|
".",
|
|
1846
1870
|
" ",
|
|
1847
|
-
/* @__PURE__ */ (0,
|
|
1848
|
-
] }) : tracks.length === 0 ? /* @__PURE__ */ (0,
|
|
1871
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsx)("button", { type: "button", className: "underline", onClick: () => void refetch(), children: "Retry" })
|
|
1872
|
+
] }) : tracks.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("p", { children: "\u2014" }) : /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("ul", { className: "mt-1 max-h-64 overflow-y-auto text-body [container-type:inline-size]", "aria-label": `${genreName} ${trackNoun.plural}`, children: [
|
|
1849
1873
|
tracks.map((track, index) => {
|
|
1850
1874
|
const label = track.artists?.length ? `${track.title} \u2014 ${track.artists.map((artist2) => artist2.name).join(", ")}` : track.title;
|
|
1851
1875
|
const isCurrent = playerTrackObject?.track.id === track.uuid;
|
|
1852
1876
|
const isPlaying = isCurrent && playState === import_player6.PlayStates.PLAYING;
|
|
1853
|
-
const text = /* @__PURE__ */ (0,
|
|
1854
|
-
/* @__PURE__ */ (0,
|
|
1855
|
-
track.artists?.length ? /* @__PURE__ */ (0,
|
|
1856
|
-
/* @__PURE__ */ (0,
|
|
1857
|
-
track.album && /* @__PURE__ */ (0,
|
|
1877
|
+
const text = /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("span", { className: TEXT_CELL, children: [
|
|
1878
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsx)("span", { className: TITLE_CELL, children: renderSongLink ? renderSongLink(track) : (0, import_genre_tree15.isSong)(track) ? /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(MusicBrainzRecordingLink, { song: track, className: "hover:underline focus-visible:underline", children: track.title }) : track.title }),
|
|
1879
|
+
track.artists?.length ? /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("span", { className: SEPARATOR, children: " \u2014 " }) : null,
|
|
1880
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsx)("span", { className: COLUMN_CELL, children: track.artists?.length ? /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(import_genre_tree17.ArtistNames, { artists: track.artists, renderArtistLink }) : null }),
|
|
1881
|
+
track.album && /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("span", { className: ALBUM_CELL, children: track.album.name })
|
|
1858
1882
|
] });
|
|
1859
1883
|
const leading = renderSongLeading?.(track, index);
|
|
1860
1884
|
const actions = renderSongActions?.(track);
|
|
1861
1885
|
const isUnplayable = (0, import_genre_tree15.isSong)(track) && (0, import_genre_tree15.songUnplayableReason)(track) !== null;
|
|
1862
1886
|
if (isUnplayable) {
|
|
1863
|
-
return /* @__PURE__ */ (0,
|
|
1887
|
+
return /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("li", { className: "flex min-h-8 items-center gap-1 px-1 opacity-50", children: [
|
|
1864
1888
|
leading,
|
|
1865
|
-
/* @__PURE__ */ (0,
|
|
1889
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
|
|
1866
1890
|
"button",
|
|
1867
1891
|
{
|
|
1868
1892
|
type: "button",
|
|
@@ -1870,27 +1894,27 @@ function GenrePlaylistTracks({
|
|
|
1870
1894
|
"aria-disabled": "true",
|
|
1871
1895
|
"aria-label": label,
|
|
1872
1896
|
className: "flex h-6 w-6 shrink-0 items-center justify-center rounded-full opacity-0 cursor-not-allowed",
|
|
1873
|
-
children: /* @__PURE__ */ (0,
|
|
1897
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(import_fa4.FaPlay, { size: 10 })
|
|
1874
1898
|
}
|
|
1875
1899
|
),
|
|
1876
1900
|
text,
|
|
1877
1901
|
actions
|
|
1878
1902
|
] }, track.uuid);
|
|
1879
1903
|
}
|
|
1880
|
-
return /* @__PURE__ */ (0,
|
|
1904
|
+
return /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)(
|
|
1881
1905
|
"li",
|
|
1882
1906
|
{
|
|
1883
1907
|
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)]" : ""}`,
|
|
1884
1908
|
children: [
|
|
1885
1909
|
leading,
|
|
1886
|
-
/* @__PURE__ */ (0,
|
|
1910
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
|
|
1887
1911
|
"button",
|
|
1888
1912
|
{
|
|
1889
1913
|
type: "button",
|
|
1890
1914
|
"aria-label": `${isPlaying ? "Pause" : "Play"} ${label}`,
|
|
1891
1915
|
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"}`,
|
|
1892
1916
|
onClick: () => isCurrent ? handlePlayPauseAction() : play(track.uuid),
|
|
1893
|
-
children: isCurrent && playState === import_player6.PlayStates.LOADING ? /* @__PURE__ */ (0,
|
|
1917
|
+
children: isCurrent && playState === import_player6.PlayStates.LOADING ? /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(import_ui11.RingLoader, { size: 10 }) : isPlaying ? /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(import_fa4.FaPause, { size: 10 }) : /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(import_fa4.FaPlay, { size: 10 })
|
|
1894
1918
|
}
|
|
1895
1919
|
),
|
|
1896
1920
|
text,
|
|
@@ -1900,7 +1924,7 @@ function GenrePlaylistTracks({
|
|
|
1900
1924
|
track.uuid
|
|
1901
1925
|
);
|
|
1902
1926
|
}),
|
|
1903
|
-
hasNextPage && /* @__PURE__ */ (0,
|
|
1927
|
+
hasNextPage && /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("li", { ref: setSentinel, "aria-hidden": "true", className: "h-4" })
|
|
1904
1928
|
] })
|
|
1905
1929
|
] }) });
|
|
1906
1930
|
}
|
|
@@ -1908,7 +1932,7 @@ function GenrePlaylistTracks({
|
|
|
1908
1932
|
// src/genre-tree/GenreDetailExtras.tsx
|
|
1909
1933
|
var import_track_noun3 = require("@behindthemusictree/app-kit/track-noun");
|
|
1910
1934
|
var import_si2 = require("react-icons/si");
|
|
1911
|
-
var
|
|
1935
|
+
var import_jsx_runtime35 = require("react/jsx-runtime");
|
|
1912
1936
|
function GenreDetailExtras({
|
|
1913
1937
|
genreUuid,
|
|
1914
1938
|
genrePlaylist,
|
|
@@ -1934,17 +1958,18 @@ function GenreDetailExtras({
|
|
|
1934
1958
|
criteriaOverviewSchema
|
|
1935
1959
|
);
|
|
1936
1960
|
if (isPending) {
|
|
1937
|
-
return /* @__PURE__ */ (0,
|
|
1938
|
-
/* @__PURE__ */ (0,
|
|
1961
|
+
return /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)(import_jsx_runtime35.Fragment, { children: [
|
|
1962
|
+
/* @__PURE__ */ (0, import_jsx_runtime35.jsx)(import_ui12.PanelSection, { title: "Summary", children: /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("div", { "aria-busy": "true", "data-testid": "genre-detail-extras-skeleton", children: /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(import_ui12.Skeleton, { className: "h-4 w-3/4" }) }) }),
|
|
1939
1963
|
family
|
|
1940
1964
|
] });
|
|
1941
1965
|
}
|
|
1942
|
-
if (!overview) return /* @__PURE__ */ (0,
|
|
1943
|
-
const { summary, summarySourceUrl, essentialSongs } = overview;
|
|
1966
|
+
if (!overview) return /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(import_jsx_runtime35.Fragment, { children: family });
|
|
1967
|
+
const { summary, summarySourceUrl, essentialSongs, image } = overview;
|
|
1944
1968
|
const wikidataUrl = wikidataId ? `https://www.wikidata.org/wiki/${encodeURIComponent(wikidataId)}` : null;
|
|
1945
|
-
return /* @__PURE__ */ (0,
|
|
1946
|
-
|
|
1947
|
-
|
|
1969
|
+
return /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)(import_jsx_runtime35.Fragment, { children: [
|
|
1970
|
+
image && /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(CommonsPhoto, { image, alt: overview.name, creditLabel: "Image" }),
|
|
1971
|
+
(summarySourceUrl || wikidataUrl) && /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(import_ui12.PanelSection, { title: "Links", children: /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("div", { className: "flex flex-wrap gap-x-3 gap-y-1 text-caption text-[var(--color-text)]", children: [
|
|
1972
|
+
summarySourceUrl && /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)(
|
|
1948
1973
|
"a",
|
|
1949
1974
|
{
|
|
1950
1975
|
href: summarySourceUrl,
|
|
@@ -1952,12 +1977,12 @@ function GenreDetailExtras({
|
|
|
1952
1977
|
rel: "noopener noreferrer",
|
|
1953
1978
|
className: "inline-flex items-center gap-1.5 text-[var(--color-text-muted)] hover:text-[var(--color-text)]",
|
|
1954
1979
|
children: [
|
|
1955
|
-
/* @__PURE__ */ (0,
|
|
1980
|
+
/* @__PURE__ */ (0, import_jsx_runtime35.jsx)(import_si2.SiWikipedia, { "aria-hidden": "true", className: "h-3.5 w-3.5" }),
|
|
1956
1981
|
"Wikipedia"
|
|
1957
1982
|
]
|
|
1958
1983
|
}
|
|
1959
1984
|
),
|
|
1960
|
-
wikidataUrl && /* @__PURE__ */ (0,
|
|
1985
|
+
wikidataUrl && /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)(
|
|
1961
1986
|
"a",
|
|
1962
1987
|
{
|
|
1963
1988
|
href: wikidataUrl,
|
|
@@ -1965,17 +1990,17 @@ function GenreDetailExtras({
|
|
|
1965
1990
|
rel: "noopener noreferrer",
|
|
1966
1991
|
className: "inline-flex items-center gap-1.5 text-[var(--color-text-muted)] hover:text-[var(--color-text)]",
|
|
1967
1992
|
children: [
|
|
1968
|
-
/* @__PURE__ */ (0,
|
|
1993
|
+
/* @__PURE__ */ (0, import_jsx_runtime35.jsx)(import_si2.SiWikidata, { "aria-hidden": "true", className: "h-3.5 w-3.5" }),
|
|
1969
1994
|
"Wikidata"
|
|
1970
1995
|
]
|
|
1971
1996
|
}
|
|
1972
1997
|
)
|
|
1973
1998
|
] }) }),
|
|
1974
|
-
/* @__PURE__ */ (0,
|
|
1999
|
+
/* @__PURE__ */ (0, import_jsx_runtime35.jsx)(import_ui12.PanelSection, { title: "Summary", children: renderSummary ? renderSummary(overview) : /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(ClampedText, { className: "text-body text-[var(--color-text)]", children: summary ?? "\u2014" }, genreUuid) }),
|
|
1975
2000
|
family,
|
|
1976
2001
|
renderGenreDetailExtras?.(overview),
|
|
1977
|
-
(renderEssentialTracks || essentialSongs) && /* @__PURE__ */ (0,
|
|
1978
|
-
/* @__PURE__ */ (0,
|
|
2002
|
+
(renderEssentialTracks || essentialSongs) && /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(import_ui12.PanelSection, { title: `Essential ${trackNoun.plural}`, children: renderEssentialTracks ? renderEssentialTracks(overview) : essentialSongs && essentialSongs.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("ul", { className: "text-body text-[var(--color-text)]", children: essentialSongs.map((track) => /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("li", { className: "py-1", children: track.title }, track.uuid)) }) : /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("p", { className: "text-body text-[var(--color-text)]", children: "\u2014" }) }),
|
|
2003
|
+
/* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
|
|
1979
2004
|
GenrePlaylistTracks,
|
|
1980
2005
|
{
|
|
1981
2006
|
genreUuid,
|
|
@@ -1993,10 +2018,10 @@ function GenreDetailExtras({
|
|
|
1993
2018
|
}
|
|
1994
2019
|
|
|
1995
2020
|
// src/genre-tree/GenreInfoPanelBody.tsx
|
|
1996
|
-
var
|
|
2021
|
+
var import_jsx_runtime36 = require("react/jsx-runtime");
|
|
1997
2022
|
var import_react14 = require("react");
|
|
1998
2023
|
function GenreNodeActionBand({ genrePlaylist, playback, ...bandProps }) {
|
|
1999
|
-
return /* @__PURE__ */ (0,
|
|
2024
|
+
return /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(GenreActionBand, { ...bandProps, playActions: /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(GenrePlayActions, { genrePlaylist, playback }) });
|
|
2000
2025
|
}
|
|
2001
2026
|
function GenreInfoPanelBody({
|
|
2002
2027
|
toolbar,
|
|
@@ -2013,9 +2038,9 @@ function GenreInfoPanelBody({
|
|
|
2013
2038
|
}) {
|
|
2014
2039
|
const summary = scope === "reference" ? import_genre_tree19.GenreCatalogueCountsSchema.parse(genrePlaylist ?? catalogue) : void 0;
|
|
2015
2040
|
const selection = summary ? (0, import_genre_tree19.defaultGenreMusicSelection)(summary) : void 0;
|
|
2016
|
-
return /* @__PURE__ */ (0,
|
|
2041
|
+
return /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)(import_jsx_runtime36.Fragment, { children: [
|
|
2017
2042
|
toolbar,
|
|
2018
|
-
genrePlaylist ? /* @__PURE__ */ (0,
|
|
2043
|
+
genrePlaylist ? /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(GenreNodeActionBand, { ...band, genrePlaylist, playback }) : /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(GenreActionBand, { ...band }),
|
|
2019
2044
|
/* @__PURE__ */ (0, import_react14.createElement)(
|
|
2020
2045
|
GenreDetailExtras,
|
|
2021
2046
|
{
|
|
@@ -2035,7 +2060,7 @@ function GenreInfoPanelBody({
|
|
|
2035
2060
|
}
|
|
2036
2061
|
|
|
2037
2062
|
// src/genre-tree/GenreDetailPanel.tsx
|
|
2038
|
-
var
|
|
2063
|
+
var import_jsx_runtime37 = require("react/jsx-runtime");
|
|
2039
2064
|
var RELATIVE_ITEM_COUNT = 1;
|
|
2040
2065
|
function toNode(genre, parentId) {
|
|
2041
2066
|
return {
|
|
@@ -2060,7 +2085,8 @@ function useGenreDetailContent({
|
|
|
2060
2085
|
expanded,
|
|
2061
2086
|
treeStyles
|
|
2062
2087
|
}) {
|
|
2063
|
-
const
|
|
2088
|
+
const result = (0, import_genre_tree20.useFetchGenreDetail)(genreUuid, scope, getBackendBaseUrl);
|
|
2089
|
+
const detail = result.status === "success" ? result.genre : void 0;
|
|
2064
2090
|
const defaultPlayback = useGenrePlaylistPlayback({ scope, genrePlaylists: [], artist: extras?.artist });
|
|
2065
2091
|
const playback = hostPlayback ?? defaultPlayback;
|
|
2066
2092
|
const view = (0, import_react15.useMemo)(() => {
|
|
@@ -2089,22 +2115,27 @@ function useGenreDetailContent({
|
|
|
2089
2115
|
)
|
|
2090
2116
|
};
|
|
2091
2117
|
}, [detail, scope, treeStyles]);
|
|
2092
|
-
if (
|
|
2118
|
+
if (result.status === "not-found") return {
|
|
2119
|
+
name: null,
|
|
2120
|
+
title: "Genre not found",
|
|
2121
|
+
content: /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("p", { className: "text-[var(--color-text-muted)]", children: "This genre does not exist." })
|
|
2122
|
+
};
|
|
2123
|
+
if (result.status === "error") return {
|
|
2093
2124
|
name: null,
|
|
2094
2125
|
title: "Genre unavailable",
|
|
2095
|
-
content: /* @__PURE__ */ (0,
|
|
2126
|
+
content: /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("p", { role: "alert", className: "text-body text-[var(--color-text)]", children: "This genre could not be loaded." })
|
|
2096
2127
|
};
|
|
2097
|
-
if (
|
|
2128
|
+
if (!detail || !view) return {
|
|
2098
2129
|
name: null,
|
|
2099
2130
|
title: "Loading genre\u2026",
|
|
2100
|
-
content: /* @__PURE__ */ (0,
|
|
2101
|
-
/* @__PURE__ */ (0,
|
|
2102
|
-
/* @__PURE__ */ (0,
|
|
2103
|
-
/* @__PURE__ */ (0,
|
|
2131
|
+
content: /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)("div", { className: "flex flex-col gap-3", "aria-busy": "true", "data-testid": "genre-detail-panel-skeleton", children: [
|
|
2132
|
+
/* @__PURE__ */ (0, import_jsx_runtime37.jsx)(import_ui13.Skeleton, { className: "h-6 w-2/3" }),
|
|
2133
|
+
/* @__PURE__ */ (0, import_jsx_runtime37.jsx)(import_ui13.Skeleton, { className: "h-4 w-full" }),
|
|
2134
|
+
/* @__PURE__ */ (0, import_jsx_runtime37.jsx)(import_ui13.Skeleton, { className: "h-4 w-3/4" })
|
|
2104
2135
|
] })
|
|
2105
2136
|
};
|
|
2106
2137
|
const selectGenre = (nodeId) => onSelectGenre(import_genre_tree20.GenreUuidSchema.parse(nodeId));
|
|
2107
|
-
const family = /* @__PURE__ */ (0,
|
|
2138
|
+
const family = /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
|
|
2108
2139
|
import_genre_tree_view4.GenreNodeFamily,
|
|
2109
2140
|
{
|
|
2110
2141
|
node: view.node,
|
|
@@ -2115,17 +2146,17 @@ function useGenreDetailContent({
|
|
|
2115
2146
|
onSelectNode: selectGenre
|
|
2116
2147
|
}
|
|
2117
2148
|
);
|
|
2118
|
-
const ancestors = /* @__PURE__ */ (0,
|
|
2149
|
+
const ancestors = /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(import_genre_tree_view4.GenreNodeAncestors, { ancestorNodes: view.ancestorNodes, onSelectNode: selectGenre });
|
|
2119
2150
|
return {
|
|
2120
2151
|
name: detail.name,
|
|
2121
2152
|
title: detail.name,
|
|
2122
2153
|
headerAccent: { background: view.fill, color: view.textColor },
|
|
2123
2154
|
aside: expanded ? ancestors : void 0,
|
|
2124
|
-
content: /* @__PURE__ */ (0,
|
|
2125
|
-
/* @__PURE__ */ (0,
|
|
2155
|
+
content: /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)(import_jsx_runtime37.Fragment, { children: [
|
|
2156
|
+
/* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
|
|
2126
2157
|
GenreInfoPanelBody,
|
|
2127
2158
|
{
|
|
2128
|
-
family: /* @__PURE__ */ (0,
|
|
2159
|
+
family: /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)(import_jsx_runtime37.Fragment, { children: [
|
|
2129
2160
|
family,
|
|
2130
2161
|
!expanded && ancestors
|
|
2131
2162
|
] }),
|
|
@@ -2169,7 +2200,7 @@ function GenreDetailPanel({
|
|
|
2169
2200
|
expanded,
|
|
2170
2201
|
band: { onZoomIn, shareUrl, shareTarget: shareUrl ? shareTarget : void 0 }
|
|
2171
2202
|
});
|
|
2172
|
-
return /* @__PURE__ */ (0,
|
|
2203
|
+
return /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
|
|
2173
2204
|
import_ui13.DetailPanel,
|
|
2174
2205
|
{
|
|
2175
2206
|
side: "left",
|
|
@@ -2182,7 +2213,7 @@ function GenreDetailPanel({
|
|
|
2182
2213
|
edgeTab,
|
|
2183
2214
|
aside: panel.aside,
|
|
2184
2215
|
titleInSearch,
|
|
2185
|
-
headerActions: onExpandedChange ? /* @__PURE__ */ (0,
|
|
2216
|
+
headerActions: onExpandedChange ? /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(import_ui13.IconButton, { "aria-label": expanded ? "Shrink panel" : "Extend panel", onClick: () => onExpandedChange(!expanded), children: expanded ? /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(import_lucide_react13.Minimize2, { "aria-hidden": "true", className: "h-4 w-4" }) : /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(import_lucide_react13.Maximize2, { "aria-hidden": "true", className: "h-4 w-4" }) }) : void 0,
|
|
2186
2217
|
children: panel.content
|
|
2187
2218
|
}
|
|
2188
2219
|
);
|
|
@@ -2191,7 +2222,7 @@ function GenreDetailPanel({
|
|
|
2191
2222
|
// src/genre-tree/ChangeParentPopup.tsx
|
|
2192
2223
|
var import_react16 = require("react");
|
|
2193
2224
|
var import_genre_tree21 = require("@behindthemusictree/app-kit/genre-tree");
|
|
2194
|
-
var
|
|
2225
|
+
var import_jsx_runtime38 = require("react/jsx-runtime");
|
|
2195
2226
|
function ChangeParentPopup({
|
|
2196
2227
|
genrePlaylist,
|
|
2197
2228
|
genrePlaylists,
|
|
@@ -2226,12 +2257,12 @@ function ChangeParentPopup({
|
|
|
2226
2257
|
window.addEventListener("keydown", handleKeyDown);
|
|
2227
2258
|
return () => window.removeEventListener("keydown", handleKeyDown);
|
|
2228
2259
|
}, [onClose]);
|
|
2229
|
-
return /* @__PURE__ */ (0,
|
|
2230
|
-
/* @__PURE__ */ (0,
|
|
2260
|
+
return /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)(BasePopup_default, { title: `Change parent of ${genrePlaylist.name}`, onClose, showCancelButton: true, fitContent: true, children: [
|
|
2261
|
+
/* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("p", { className: "mb-3 text-body text-[var(--color-text-muted)]", children: [
|
|
2231
2262
|
"Current parent: ",
|
|
2232
2263
|
genrePlaylist.parent?.name ?? "none"
|
|
2233
2264
|
] }),
|
|
2234
|
-
/* @__PURE__ */ (0,
|
|
2265
|
+
/* @__PURE__ */ (0, import_jsx_runtime38.jsx)("div", { "aria-busy": isPending, className: isPending ? "pointer-events-none opacity-60" : void 0, children: /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
|
|
2235
2266
|
GenreSearch,
|
|
2236
2267
|
{
|
|
2237
2268
|
genrePlaylists: candidates,
|
|
@@ -2239,7 +2270,7 @@ function ChangeParentPopup({
|
|
|
2239
2270
|
placeholder: "Search a new parent\u2026"
|
|
2240
2271
|
}
|
|
2241
2272
|
) }),
|
|
2242
|
-
formErrors.length > 0 && /* @__PURE__ */ (0,
|
|
2273
|
+
formErrors.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("p", { role: "alert", className: "mt-3 text-body text-[var(--color-red-500)]", children: formErrors.map(({ message }) => message).join(" ") })
|
|
2243
2274
|
] });
|
|
2244
2275
|
}
|
|
2245
2276
|
|
|
@@ -2252,7 +2283,7 @@ var import_lucide_react14 = require("lucide-react");
|
|
|
2252
2283
|
var import_ui14 = require("@behindthemusictree/ui");
|
|
2253
2284
|
var import_genre_tree22 = require("@behindthemusictree/app-kit/genre-tree");
|
|
2254
2285
|
var import_player7 = require("@behindthemusictree/app-kit/player");
|
|
2255
|
-
var
|
|
2286
|
+
var import_jsx_runtime39 = require("react/jsx-runtime");
|
|
2256
2287
|
function ArtistActionBand({ artist, share }) {
|
|
2257
2288
|
const { trackList, playNewTrackListFromArtist } = (0, import_genre_tree22.useTrackList)();
|
|
2258
2289
|
const { isPlaying, setIsPlaying } = (0, import_player7.usePlayer)();
|
|
@@ -2268,11 +2299,11 @@ function ArtistActionBand({ artist, share }) {
|
|
|
2268
2299
|
console.error("Failed to load artist tracks:", error);
|
|
2269
2300
|
});
|
|
2270
2301
|
};
|
|
2271
|
-
return /* @__PURE__ */ (0,
|
|
2272
|
-
/* @__PURE__ */ (0,
|
|
2302
|
+
return /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(import_ui14.PanelBleed, { children: /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)(import_ui14.ActionBand, { children: [
|
|
2303
|
+
/* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
|
|
2273
2304
|
import_ui14.ActionButton,
|
|
2274
2305
|
{
|
|
2275
|
-
icon: playing ? /* @__PURE__ */ (0,
|
|
2306
|
+
icon: playing ? /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(import_lucide_react14.Pause, { "aria-hidden": "true", className: "w-5 h-5" }) : /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(import_lucide_react14.Play, { "aria-hidden": "true", className: "w-5 h-5" }),
|
|
2276
2307
|
label: playing ? "Pause" : "Play",
|
|
2277
2308
|
caption: String(artist.playableTracksCount),
|
|
2278
2309
|
disabled: artist.playableTracksCount === 0,
|
|
@@ -2291,7 +2322,7 @@ var import_ui16 = require("@behindthemusictree/ui");
|
|
|
2291
2322
|
var import_lucide_react15 = require("lucide-react");
|
|
2292
2323
|
var import_si3 = require("react-icons/si");
|
|
2293
2324
|
var import_ui15 = require("@behindthemusictree/ui");
|
|
2294
|
-
var
|
|
2325
|
+
var import_jsx_runtime40 = require("react/jsx-runtime");
|
|
2295
2326
|
var LINK_KINDS = {
|
|
2296
2327
|
official: { label: "Official website", Icon: import_lucide_react15.Globe },
|
|
2297
2328
|
wikipedia: { label: "Wikipedia", Icon: import_si3.SiWikipedia },
|
|
@@ -2328,7 +2359,7 @@ function artistLinks(artist) {
|
|
|
2328
2359
|
return links;
|
|
2329
2360
|
}
|
|
2330
2361
|
function ArtistLinks({ links }) {
|
|
2331
|
-
return /* @__PURE__ */ (0,
|
|
2362
|
+
return /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("ul", { className: "flex flex-wrap gap-1.5", children: links.map(({ key, url, Icon, label }) => /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(import_ui15.Chip, { href: url, icon: /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(Icon, { className: "h-3.5 w-3.5 shrink-0", "aria-hidden": "true" }), children: label }) }, key)) });
|
|
2332
2363
|
}
|
|
2333
2364
|
|
|
2334
2365
|
// src/genre-tree/artist/formatYears.ts
|
|
@@ -2339,45 +2370,59 @@ function formatYears(beginYear, endYear, ended) {
|
|
|
2339
2370
|
}
|
|
2340
2371
|
|
|
2341
2372
|
// src/genre-tree/artist/ArtistHeader.tsx
|
|
2342
|
-
var
|
|
2373
|
+
var import_jsx_runtime41 = require("react/jsx-runtime");
|
|
2343
2374
|
var countryNames = new Intl.DisplayNames(["en"], { type: "region" });
|
|
2344
|
-
function
|
|
2375
|
+
function originLabel(artist, origin) {
|
|
2376
|
+
if (origin.source === "area") return "From";
|
|
2377
|
+
if (artist.type === "person") return "Born in";
|
|
2378
|
+
if (artist.type === "group") return "Formed in";
|
|
2379
|
+
return "From";
|
|
2380
|
+
}
|
|
2381
|
+
function OriginValue({
|
|
2382
|
+
origin,
|
|
2383
|
+
country,
|
|
2384
|
+
renderPlaceLink
|
|
2385
|
+
}) {
|
|
2386
|
+
const place = renderPlaceLink && origin.regionId !== null ? renderPlaceLink({ ...origin, regionId: origin.regionId }) : origin.name;
|
|
2387
|
+
return /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)(import_jsx_runtime41.Fragment, { children: [
|
|
2388
|
+
place,
|
|
2389
|
+
country && origin.kind !== "country" && `, ${country}`
|
|
2390
|
+
] });
|
|
2391
|
+
}
|
|
2392
|
+
function ArtistHeader({
|
|
2393
|
+
artist,
|
|
2394
|
+
renderPlaceLink
|
|
2395
|
+
}) {
|
|
2345
2396
|
const fields = [];
|
|
2346
2397
|
if (artist.type) fields.push({ label: "Type", value: artist.type.charAt(0).toUpperCase() + artist.type.slice(1) });
|
|
2347
|
-
const country = artist.country
|
|
2348
|
-
if (
|
|
2398
|
+
const country = artist.country ? countryNames.of(artist.country) : void 0;
|
|
2399
|
+
if (artist.origin) {
|
|
2400
|
+
fields.push({
|
|
2401
|
+
label: originLabel(artist, artist.origin),
|
|
2402
|
+
value: /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(OriginValue, { origin: artist.origin, country, renderPlaceLink })
|
|
2403
|
+
});
|
|
2404
|
+
}
|
|
2405
|
+
if (country && !artist.origin) fields.push({ label: "Country", value: country });
|
|
2349
2406
|
const years = formatYears(artist.beginYear, artist.endYear, artist.ended);
|
|
2350
2407
|
if (years) fields.push({ label: "Active", value: years });
|
|
2351
2408
|
const links = artistLinks(artist);
|
|
2352
|
-
if (links.length > 0) fields.push({ label: "Links", value: /* @__PURE__ */ (0,
|
|
2409
|
+
if (links.length > 0) fields.push({ label: "Links", value: /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(ArtistLinks, { links }) });
|
|
2353
2410
|
if (fields.length === 0) return null;
|
|
2354
|
-
return /* @__PURE__ */ (0,
|
|
2411
|
+
return /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(import_ui16.FieldList, { items: fields });
|
|
2355
2412
|
}
|
|
2356
2413
|
|
|
2357
2414
|
// src/genre-tree/artist/ArtistPhoto.tsx
|
|
2358
|
-
var
|
|
2359
|
-
function ExternalLink({ href, children }) {
|
|
2360
|
-
return /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("a", { href, target: "_blank", rel: "noopener noreferrer", className: "underline-offset-2 hover:underline", children });
|
|
2361
|
-
}
|
|
2415
|
+
var import_jsx_runtime42 = require("react/jsx-runtime");
|
|
2362
2416
|
function ArtistPhoto({ image, name }) {
|
|
2363
|
-
return /* @__PURE__ */ (0,
|
|
2364
|
-
/* @__PURE__ */ (0, import_jsx_runtime41.jsx)("img", { src: image.url, alt: name, className: "h-64 w-full object-contain bg-[var(--color-surface-muted)] rounded" }),
|
|
2365
|
-
/* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("figcaption", { className: "text-caption text-[var(--color-text-muted)]", children: [
|
|
2366
|
-
"Photo: ",
|
|
2367
|
-
/* @__PURE__ */ (0, import_jsx_runtime41.jsx)(ExternalLink, { href: image.pageUrl, children: image.author ?? "Wikimedia Commons" }),
|
|
2368
|
-
",",
|
|
2369
|
-
" ",
|
|
2370
|
-
image.licenseUrl ? /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(ExternalLink, { href: image.licenseUrl, children: image.license }) : image.license
|
|
2371
|
-
] })
|
|
2372
|
-
] });
|
|
2417
|
+
return /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(CommonsPhoto, { image, alt: name });
|
|
2373
2418
|
}
|
|
2374
2419
|
|
|
2375
2420
|
// src/genre-tree/artist/ArtistMembers.tsx
|
|
2376
2421
|
var import_ui17 = require("@behindthemusictree/ui");
|
|
2377
|
-
var
|
|
2422
|
+
var import_jsx_runtime43 = require("react/jsx-runtime");
|
|
2378
2423
|
function MembershipList({ title, memberships, renderArtistLink }) {
|
|
2379
2424
|
if (memberships.length === 0) return null;
|
|
2380
|
-
return /* @__PURE__ */ (0,
|
|
2425
|
+
return /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(import_ui17.PanelGroup, { title, children: /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("ul", { children: memberships.map((membership, index) => {
|
|
2381
2426
|
const details = [
|
|
2382
2427
|
formatYears(membership.beginYear, membership.endYear, membership.ended),
|
|
2383
2428
|
...membership.roles
|
|
@@ -2385,9 +2430,9 @@ function MembershipList({ title, memberships, renderArtistLink }) {
|
|
|
2385
2430
|
const detailsText = details.filter(Boolean).join(" \xB7 ");
|
|
2386
2431
|
return (
|
|
2387
2432
|
// A member can have several periods in the same group.
|
|
2388
|
-
/* @__PURE__ */ (0,
|
|
2389
|
-
/* @__PURE__ */ (0,
|
|
2390
|
-
detailsText && /* @__PURE__ */ (0,
|
|
2433
|
+
/* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("li", { className: "truncate py-0.5", title: detailsText || void 0, children: [
|
|
2434
|
+
/* @__PURE__ */ (0, import_jsx_runtime43.jsx)("span", { className: "font-medium text-[var(--color-text)]", children: renderArtistLink(membership.artist) }),
|
|
2435
|
+
detailsText && /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("span", { className: "text-[var(--color-text-muted)]", children: [
|
|
2391
2436
|
" \u2014 ",
|
|
2392
2437
|
detailsText
|
|
2393
2438
|
] })
|
|
@@ -2398,9 +2443,9 @@ function MembershipList({ title, memberships, renderArtistLink }) {
|
|
|
2398
2443
|
function ArtistMembers({ title, memberships, renderArtistLink }) {
|
|
2399
2444
|
if (memberships.length === 0) return null;
|
|
2400
2445
|
const isCurrent = (membership) => !membership.ended && membership.endYear === null;
|
|
2401
|
-
return /* @__PURE__ */ (0,
|
|
2402
|
-
/* @__PURE__ */ (0,
|
|
2403
|
-
/* @__PURE__ */ (0,
|
|
2446
|
+
return /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)(import_ui17.PanelSection, { title, children: [
|
|
2447
|
+
/* @__PURE__ */ (0, import_jsx_runtime43.jsx)(MembershipList, { title: "Current", memberships: memberships.filter(isCurrent), renderArtistLink }),
|
|
2448
|
+
/* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
|
|
2404
2449
|
MembershipList,
|
|
2405
2450
|
{
|
|
2406
2451
|
title: "Past",
|
|
@@ -2413,7 +2458,7 @@ function ArtistMembers({ title, memberships, renderArtistLink }) {
|
|
|
2413
2458
|
|
|
2414
2459
|
// src/genre-tree/artist/ArtistDiscography.tsx
|
|
2415
2460
|
var import_ui18 = require("@behindthemusictree/ui");
|
|
2416
|
-
var
|
|
2461
|
+
var import_jsx_runtime44 = require("react/jsx-runtime");
|
|
2417
2462
|
var GROUPS = ["Albums", "EPs", "Singles", "Live", "Compilations", "Other"];
|
|
2418
2463
|
var PRIMARY_GROUPS = { album: "Albums", ep: "EPs", single: "Singles" };
|
|
2419
2464
|
function discographyGroup({ primaryType, secondaryTypes }) {
|
|
@@ -2433,12 +2478,12 @@ function byYear(a, b) {
|
|
|
2433
2478
|
function ArtistDiscography({ albums }) {
|
|
2434
2479
|
if (albums.length === 0) return null;
|
|
2435
2480
|
const sorted = [...albums].sort(byYear);
|
|
2436
|
-
return /* @__PURE__ */ (0,
|
|
2481
|
+
return /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(import_ui18.PanelSection, { title: "Discography", children: GROUPS.map((group) => {
|
|
2437
2482
|
const groupAlbums = sorted.filter((album) => discographyGroup(album) === group);
|
|
2438
2483
|
if (groupAlbums.length === 0) return null;
|
|
2439
|
-
return /* @__PURE__ */ (0,
|
|
2440
|
-
/* @__PURE__ */ (0,
|
|
2441
|
-
/* @__PURE__ */ (0,
|
|
2484
|
+
return /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(import_ui18.PanelGroup, { title: group, children: /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("ul", { children: groupAlbums.map((album) => /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("li", { className: "grid grid-cols-[2.5rem_minmax(0,1fr)] gap-2 py-0.5", children: [
|
|
2485
|
+
/* @__PURE__ */ (0, import_jsx_runtime44.jsx)("span", { className: "tabular-nums text-[var(--color-text-muted)]", children: album.year ?? "\u2014" }),
|
|
2486
|
+
/* @__PURE__ */ (0, import_jsx_runtime44.jsx)("span", { className: "truncate text-[var(--color-text)]", title: album.name, children: album.name })
|
|
2442
2487
|
] }, album.uuid)) }) }, group);
|
|
2443
2488
|
}) });
|
|
2444
2489
|
}
|
|
@@ -2459,7 +2504,7 @@ var import_genre_tree23 = require("@behindthemusictree/app-kit/genre-tree");
|
|
|
2459
2504
|
var import_fa5 = require("react-icons/fa");
|
|
2460
2505
|
var import_player8 = require("@behindthemusictree/app-kit/player");
|
|
2461
2506
|
var import_player9 = require("@behindthemusictree/app-kit/player");
|
|
2462
|
-
var
|
|
2507
|
+
var import_jsx_runtime45 = require("react/jsx-runtime");
|
|
2463
2508
|
function TrackPositionPlayPause({
|
|
2464
2509
|
position,
|
|
2465
2510
|
uuid,
|
|
@@ -2473,14 +2518,14 @@ function TrackPositionPlayPause({
|
|
|
2473
2518
|
const isPlaying = isThisTrack && isConfirmedPlayable && playState === import_player9.PlayStates.PLAYING;
|
|
2474
2519
|
const isPaused = isThisTrack && isConfirmedPlayable && playState === import_player9.PlayStates.PAUSED;
|
|
2475
2520
|
const isCurrentTrackActive = isPlaying || isPaused;
|
|
2476
|
-
return /* @__PURE__ */ (0,
|
|
2521
|
+
return /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)(
|
|
2477
2522
|
"div",
|
|
2478
2523
|
{
|
|
2479
2524
|
className: "track-position-play-pause relative flex items-center justify-center gap-2 text-lg w-16 cursor-pointer",
|
|
2480
2525
|
style: { minWidth: "4rem", maxWidth: "4rem" },
|
|
2481
2526
|
onClick: handlePlayPauseClick,
|
|
2482
2527
|
children: [
|
|
2483
|
-
/* @__PURE__ */ (0,
|
|
2528
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)("div", { className: "track-position-play-pause__status group-hover:hidden flex items-center justify-center", children: isAwaitingPlayback ? /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("span", { className: "track-position-play-pause__spinner", role: "status", "aria-label": "Loading track" }) : isCurrentTrackActive ? /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)(
|
|
2484
2529
|
"span",
|
|
2485
2530
|
{
|
|
2486
2531
|
className: "track-position-play-pause__bars",
|
|
@@ -2488,18 +2533,18 @@ function TrackPositionPlayPause({
|
|
|
2488
2533
|
role: "img",
|
|
2489
2534
|
"aria-label": isPlaying ? "Playing" : "Paused",
|
|
2490
2535
|
children: [
|
|
2491
|
-
/* @__PURE__ */ (0,
|
|
2492
|
-
/* @__PURE__ */ (0,
|
|
2493
|
-
/* @__PURE__ */ (0,
|
|
2536
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)("span", { className: "track-position-play-pause__bar" }),
|
|
2537
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)("span", { className: "track-position-play-pause__bar" }),
|
|
2538
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)("span", { className: "track-position-play-pause__bar" })
|
|
2494
2539
|
]
|
|
2495
2540
|
}
|
|
2496
2541
|
) : position }),
|
|
2497
|
-
/* @__PURE__ */ (0,
|
|
2542
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
|
|
2498
2543
|
"div",
|
|
2499
2544
|
{
|
|
2500
2545
|
className: `hidden group-hover:flex items-center justify-center ${isCurrentTrackActive ? "" : "absolute inset-0"}`,
|
|
2501
2546
|
"aria-hidden": "true",
|
|
2502
|
-
children: isAwaitingPlayback ? /* @__PURE__ */ (0,
|
|
2547
|
+
children: isAwaitingPlayback ? /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("span", { className: "track-position-play-pause__spinner" }) : isPlaying ? /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(import_fa5.FaPause, {}) : /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(import_fa5.FaPlay, {})
|
|
2503
2548
|
}
|
|
2504
2549
|
)
|
|
2505
2550
|
]
|
|
@@ -2510,7 +2555,7 @@ function TrackPositionPlayPause({
|
|
|
2510
2555
|
// src/genre-tree/track-list-sidebar/TrackItem.tsx
|
|
2511
2556
|
var import_genre_tree24 = require("@behindthemusictree/app-kit/genre-tree");
|
|
2512
2557
|
var import_genre_tree25 = require("@behindthemusictree/app-kit/genre-tree");
|
|
2513
|
-
var
|
|
2558
|
+
var import_jsx_runtime46 = require("react/jsx-runtime");
|
|
2514
2559
|
function TrackItem({
|
|
2515
2560
|
track,
|
|
2516
2561
|
position,
|
|
@@ -2534,12 +2579,12 @@ function TrackItem({
|
|
|
2534
2579
|
loadTrackForPlayer(track.uuid);
|
|
2535
2580
|
}
|
|
2536
2581
|
};
|
|
2537
|
-
return /* @__PURE__ */ (0,
|
|
2582
|
+
return /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)(
|
|
2538
2583
|
"div",
|
|
2539
2584
|
{
|
|
2540
2585
|
className: `track-item flex h-14 text-[var(--color-text)] ${isUnplayable ? "opacity-50" : "hover:bg-[var(--color-surface-muted)] group"}`,
|
|
2541
2586
|
children: [
|
|
2542
|
-
isUnplayable ? /* @__PURE__ */ (0,
|
|
2587
|
+
isUnplayable ? /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(
|
|
2543
2588
|
"div",
|
|
2544
2589
|
{
|
|
2545
2590
|
className: "flex items-center justify-center text-lg w-16",
|
|
@@ -2547,7 +2592,7 @@ function TrackItem({
|
|
|
2547
2592
|
"aria-disabled": "true",
|
|
2548
2593
|
children: position
|
|
2549
2594
|
}
|
|
2550
|
-
) : /* @__PURE__ */ (0,
|
|
2595
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(
|
|
2551
2596
|
TrackPositionPlayPause,
|
|
2552
2597
|
{
|
|
2553
2598
|
position,
|
|
@@ -2556,12 +2601,12 @@ function TrackItem({
|
|
|
2556
2601
|
isSelected: selectedTrack?.uuid === track.uuid
|
|
2557
2602
|
}
|
|
2558
2603
|
),
|
|
2559
|
-
/* @__PURE__ */ (0,
|
|
2560
|
-
/* @__PURE__ */ (0,
|
|
2561
|
-
track.artists && track.artists.length > 0 ? /* @__PURE__ */ (0,
|
|
2604
|
+
/* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("div", { className: "title-artist-container flex flex-col items-start justify-center min-w-0 flex-1", children: [
|
|
2605
|
+
/* @__PURE__ */ (0, import_jsx_runtime46.jsx)("div", { className: "flex max-w-full items-center gap-2", children: /* @__PURE__ */ (0, import_jsx_runtime46.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_runtime46.jsx)(MusicBrainzRecordingLink, { song: track, className: "hover:underline focus-visible:underline", children: track.title }) : track.title }) }),
|
|
2606
|
+
track.artists && track.artists.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("div", { className: "artist text-base max-w-full truncate text-[var(--color-text-muted)]", children: /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(import_genre_tree25.ArtistNames, { artists: track.artists, renderArtistLink }) }) : ""
|
|
2562
2607
|
] }),
|
|
2563
|
-
/* @__PURE__ */ (0,
|
|
2564
|
-
renderDuration && /* @__PURE__ */ (0,
|
|
2608
|
+
/* @__PURE__ */ (0, import_jsx_runtime46.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_runtime46.jsx)("div", { className: "genre-name max-w-full whitespace-normal break-words p-1 text-caption font-bold", children: track.genre.name }) : "" }),
|
|
2609
|
+
renderDuration && /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(
|
|
2565
2610
|
"div",
|
|
2566
2611
|
{
|
|
2567
2612
|
className: "duration flex text-base w-16 items-center justify-center",
|
|
@@ -2569,14 +2614,14 @@ function TrackItem({
|
|
|
2569
2614
|
children: renderDuration(track)
|
|
2570
2615
|
}
|
|
2571
2616
|
),
|
|
2572
|
-
renderActions && /* @__PURE__ */ (0,
|
|
2617
|
+
renderActions && /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("div", { className: "edit flex text-base w-6 items-center justify-center mr-2 cursor-pointer", children: renderActions(track) })
|
|
2573
2618
|
]
|
|
2574
2619
|
}
|
|
2575
2620
|
);
|
|
2576
2621
|
}
|
|
2577
2622
|
|
|
2578
2623
|
// src/genre-tree/artist/ArtistSongs.tsx
|
|
2579
|
-
var
|
|
2624
|
+
var import_jsx_runtime47 = require("react/jsx-runtime");
|
|
2580
2625
|
var SongPageSchema2 = (0, import_transport8.PaginatedResponseSchema)(import_genre_tree26.SongDetailedSchema);
|
|
2581
2626
|
var SORTS = [
|
|
2582
2627
|
{ ordering: "title", label: "Title" },
|
|
@@ -2609,8 +2654,8 @@ function ArtistSongs({ artist, getBackendBaseUrl, renderArtistLink, renderSongLi
|
|
|
2609
2654
|
event.stopPropagation();
|
|
2610
2655
|
void play(song.uuid);
|
|
2611
2656
|
};
|
|
2612
|
-
return /* @__PURE__ */ (0,
|
|
2613
|
-
/* @__PURE__ */ (0,
|
|
2657
|
+
return /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(import_ui19.PanelSection, { title: "Songs", children: isPending ? /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(import_ui19.Skeleton, { className: "h-14", "aria-busy": "true" }) : isError ? /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("p", { className: "text-red-600", children: "Could not load songs." }) : data.results.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("p", { className: "text-[var(--color-text-muted)]", children: "No songs yet." }) : /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)(import_jsx_runtime47.Fragment, { children: [
|
|
2658
|
+
/* @__PURE__ */ (0, import_jsx_runtime47.jsx)("div", { className: "flex flex-wrap items-center justify-end gap-2 mb-2", children: /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("div", { role: "group", "aria-label": "Sort songs by", className: "flex gap-1 text-caption", children: SORTS.map((sort) => /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(
|
|
2614
2659
|
"button",
|
|
2615
2660
|
{
|
|
2616
2661
|
type: "button",
|
|
@@ -2624,7 +2669,7 @@ function ArtistSongs({ artist, getBackendBaseUrl, renderArtistLink, renderSongLi
|
|
|
2624
2669
|
},
|
|
2625
2670
|
sort.ordering
|
|
2626
2671
|
)) }) }),
|
|
2627
|
-
/* @__PURE__ */ (0,
|
|
2672
|
+
/* @__PURE__ */ (0, import_jsx_runtime47.jsx)("ul", { className: "overflow-hidden mb-2 bg-zinc-950 rounded-lg", children: data.results.map((song, index) => /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("li", { onClickCapture: (event) => handleRowClickCapture(event, song), children: /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(
|
|
2628
2673
|
TrackItem,
|
|
2629
2674
|
{
|
|
2630
2675
|
track: song,
|
|
@@ -2633,12 +2678,12 @@ function ArtistSongs({ artist, getBackendBaseUrl, renderArtistLink, renderSongLi
|
|
|
2633
2678
|
renderSongLink
|
|
2634
2679
|
}
|
|
2635
2680
|
) }, song.uuid)) }),
|
|
2636
|
-
/* @__PURE__ */ (0,
|
|
2681
|
+
/* @__PURE__ */ (0, import_jsx_runtime47.jsx)(import_ui19.Pagination, { currentPage: page, totalPages: data.totalPages, onPageChange: setPage })
|
|
2637
2682
|
] }) });
|
|
2638
2683
|
}
|
|
2639
2684
|
|
|
2640
2685
|
// src/genre-tree/artist/useArtistPanel.tsx
|
|
2641
|
-
var
|
|
2686
|
+
var import_jsx_runtime48 = require("react/jsx-runtime");
|
|
2642
2687
|
function useArtistPanel({
|
|
2643
2688
|
uuid,
|
|
2644
2689
|
scope,
|
|
@@ -2646,6 +2691,7 @@ function useArtistPanel({
|
|
|
2646
2691
|
getShareUrl,
|
|
2647
2692
|
renderArtistLink,
|
|
2648
2693
|
renderSongLink,
|
|
2694
|
+
renderPlaceLink,
|
|
2649
2695
|
expanded,
|
|
2650
2696
|
onExpandedChange,
|
|
2651
2697
|
onClose
|
|
@@ -2659,26 +2705,26 @@ function useArtistPanel({
|
|
|
2659
2705
|
return {
|
|
2660
2706
|
...panel,
|
|
2661
2707
|
title: "Artist",
|
|
2662
|
-
content: /* @__PURE__ */ (0,
|
|
2663
|
-
/* @__PURE__ */ (0,
|
|
2664
|
-
/* @__PURE__ */ (0,
|
|
2665
|
-
/* @__PURE__ */ (0,
|
|
2666
|
-
/* @__PURE__ */ (0,
|
|
2667
|
-
/* @__PURE__ */ (0,
|
|
2668
|
-
/* @__PURE__ */ (0,
|
|
2708
|
+
content: /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("div", { "aria-busy": "true", className: "flex flex-col gap-2.5", children: [
|
|
2709
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)(import_ui20.Skeleton, { className: "h-3 w-16" }),
|
|
2710
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)(import_ui20.Skeleton, { className: "h-4 w-32" }),
|
|
2711
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)(import_ui20.Skeleton, { className: "h-3 w-16" }),
|
|
2712
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)(import_ui20.Skeleton, { className: "h-4 w-24" }),
|
|
2713
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)(import_ui20.Skeleton, { className: "h-16 mt-2.5" }),
|
|
2714
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)(import_ui20.Skeleton, { className: "h-16" })
|
|
2669
2715
|
] })
|
|
2670
2716
|
};
|
|
2671
2717
|
case "not-found":
|
|
2672
2718
|
return {
|
|
2673
2719
|
...panel,
|
|
2674
2720
|
title: "Artist not found",
|
|
2675
|
-
content: /* @__PURE__ */ (0,
|
|
2721
|
+
content: /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("p", { className: "text-[var(--color-text-muted)]", children: "This artist does not exist." })
|
|
2676
2722
|
};
|
|
2677
2723
|
case "error":
|
|
2678
2724
|
return {
|
|
2679
2725
|
...panel,
|
|
2680
2726
|
title: "Artist",
|
|
2681
|
-
content: /* @__PURE__ */ (0,
|
|
2727
|
+
content: /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("p", { className: "text-red-600", children: "Could not load this artist." })
|
|
2682
2728
|
};
|
|
2683
2729
|
case "success": {
|
|
2684
2730
|
const { artist } = result;
|
|
@@ -2687,19 +2733,19 @@ function useArtistPanel({
|
|
|
2687
2733
|
return {
|
|
2688
2734
|
...panel,
|
|
2689
2735
|
title: artist.name,
|
|
2690
|
-
content: /* @__PURE__ */ (0,
|
|
2691
|
-
/* @__PURE__ */ (0,
|
|
2736
|
+
content: /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)(import_jsx_runtime48.Fragment, { children: [
|
|
2737
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
|
|
2692
2738
|
ArtistActionBand,
|
|
2693
2739
|
{
|
|
2694
2740
|
artist,
|
|
2695
|
-
share: shareTarget && shareUrl ? /* @__PURE__ */ (0,
|
|
2741
|
+
share: shareTarget && shareUrl ? /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(ShareActionButton, { target: shareTarget, url: shareUrl }) : void 0
|
|
2696
2742
|
}
|
|
2697
2743
|
),
|
|
2698
|
-
artist.image && /* @__PURE__ */ (0,
|
|
2699
|
-
/* @__PURE__ */ (0,
|
|
2700
|
-
/* @__PURE__ */ (0,
|
|
2701
|
-
/* @__PURE__ */ (0,
|
|
2702
|
-
artist.tracksCount > 0 && /* @__PURE__ */ (0,
|
|
2744
|
+
artist.image && /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(ArtistPhoto, { image: artist.image, name: artist.name }),
|
|
2745
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)(ArtistHeader, { artist, renderPlaceLink }),
|
|
2746
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)(ArtistMembers, { title: "Members", memberships: artist.members, renderArtistLink }),
|
|
2747
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)(ArtistMembers, { title: "Member of", memberships: artist.memberOf, renderArtistLink }),
|
|
2748
|
+
artist.tracksCount > 0 && /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
|
|
2703
2749
|
ArtistSongs,
|
|
2704
2750
|
{
|
|
2705
2751
|
artist: { uuid: artist.uuid, name: artist.name },
|
|
@@ -2709,7 +2755,7 @@ function useArtistPanel({
|
|
|
2709
2755
|
}
|
|
2710
2756
|
)
|
|
2711
2757
|
] }),
|
|
2712
|
-
extraContent: artist.albums.length > 0 ? /* @__PURE__ */ (0,
|
|
2758
|
+
extraContent: artist.albums.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(ArtistDiscography, { albums: artist.albums }) : void 0
|
|
2713
2759
|
};
|
|
2714
2760
|
}
|
|
2715
2761
|
}
|
|
@@ -2725,7 +2771,7 @@ var import_lucide_react16 = require("lucide-react");
|
|
|
2725
2771
|
var import_ui21 = require("@behindthemusictree/ui");
|
|
2726
2772
|
var import_player12 = require("@behindthemusictree/app-kit/player");
|
|
2727
2773
|
var import_genre_tree28 = require("@behindthemusictree/app-kit/genre-tree");
|
|
2728
|
-
var
|
|
2774
|
+
var import_jsx_runtime49 = require("react/jsx-runtime");
|
|
2729
2775
|
var numberFormat = new Intl.NumberFormat("en");
|
|
2730
2776
|
var dateFormat = new Intl.DateTimeFormat("en", { dateStyle: "medium" });
|
|
2731
2777
|
var externalLink = "text-[var(--color-primary)] hover:underline focus-visible:underline";
|
|
@@ -2733,27 +2779,27 @@ function SongHistory({ uuid, getBackendBaseUrl }) {
|
|
|
2733
2779
|
const [open, setOpen] = (0, import_react18.useState)(false);
|
|
2734
2780
|
const history = (0, import_genre_tree28.useSongHistory)(uuid, getBackendBaseUrl, open);
|
|
2735
2781
|
let body = null;
|
|
2736
|
-
if (history.status === "loading") body = /* @__PURE__ */ (0,
|
|
2737
|
-
else if (history.status === "error") body = /* @__PURE__ */ (0,
|
|
2782
|
+
if (history.status === "loading") body = /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(import_ui21.Skeleton, { className: "h-10", "aria-busy": "true" });
|
|
2783
|
+
else if (history.status === "error") body = /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("p", { className: "text-red-600", children: "Could not load the history." });
|
|
2738
2784
|
else if (history.status === "success")
|
|
2739
|
-
body = history.entries.length === 0 ? /* @__PURE__ */ (0,
|
|
2740
|
-
/* @__PURE__ */ (0,
|
|
2741
|
-
entry.oldValue !== null || entry.newValue !== null ? /* @__PURE__ */ (0,
|
|
2785
|
+
body = history.entries.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("p", { className: "text-[var(--color-text-muted)]", children: "No changes yet." }) : /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("ul", { className: "divide-y divide-[var(--color-border)]", children: history.entries.map((entry) => /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)("li", { className: "py-1.5 text-body", children: [
|
|
2786
|
+
/* @__PURE__ */ (0, import_jsx_runtime49.jsx)("span", { className: "font-medium", children: entry.action }),
|
|
2787
|
+
entry.oldValue !== null || entry.newValue !== null ? /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)("span", { className: "text-[var(--color-text-muted)]", children: [
|
|
2742
2788
|
" ",
|
|
2743
2789
|
"\u2014 ",
|
|
2744
2790
|
entry.oldValue ?? "none",
|
|
2745
2791
|
" \u2192 ",
|
|
2746
2792
|
entry.newValue ?? "none"
|
|
2747
2793
|
] }) : null,
|
|
2748
|
-
/* @__PURE__ */ (0,
|
|
2794
|
+
/* @__PURE__ */ (0, import_jsx_runtime49.jsxs)("span", { className: "block text-caption text-[var(--color-text-muted)]", children: [
|
|
2749
2795
|
entry.actorPseudo ?? "Anonymous",
|
|
2750
2796
|
" \xB7 ",
|
|
2751
2797
|
dateFormat.format(new Date(entry.createdOn))
|
|
2752
2798
|
] })
|
|
2753
2799
|
] }, entry.uuid)) });
|
|
2754
|
-
return /* @__PURE__ */ (0,
|
|
2755
|
-
/* @__PURE__ */ (0,
|
|
2756
|
-
/* @__PURE__ */ (0,
|
|
2800
|
+
return /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(import_ui21.PanelBleed, { padded: true, className: "border-t border-[var(--color-border)]", children: /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)("details", { onToggle: (event) => setOpen(event.currentTarget.open), className: "pb-2.5", children: [
|
|
2801
|
+
/* @__PURE__ */ (0, import_jsx_runtime49.jsx)("summary", { className: `mt-2.5 cursor-pointer ${import_ui21.PANEL_LABEL_CLASS}`, children: "History" }),
|
|
2802
|
+
/* @__PURE__ */ (0, import_jsx_runtime49.jsx)("div", { className: "mt-1.5", children: body })
|
|
2757
2803
|
] }) });
|
|
2758
2804
|
}
|
|
2759
2805
|
function SongPanelContent(props) {
|
|
@@ -2772,13 +2818,13 @@ function SongPanelContent(props) {
|
|
|
2772
2818
|
const genre = song.genre;
|
|
2773
2819
|
fields.push({
|
|
2774
2820
|
label: "Genre",
|
|
2775
|
-
value: onSelectGenre ? /* @__PURE__ */ (0,
|
|
2776
|
-
index > 0 && /* @__PURE__ */ (0,
|
|
2777
|
-
/* @__PURE__ */ (0,
|
|
2821
|
+
value: onSelectGenre ? /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("button", { type: "button", onClick: () => onSelectGenre(genre), className: "hover:underline", children: genre.name }) : path ? /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("span", { className: "flex flex-wrap items-center gap-x-1", children: path.map((genrePlaylist, index) => /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)("span", { children: [
|
|
2822
|
+
index > 0 && /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("span", { "aria-hidden": "true", children: "\u203A " }),
|
|
2823
|
+
/* @__PURE__ */ (0, import_jsx_runtime49.jsx)("button", { type: "button", onClick: () => props.onSelectGenrePlaylist?.(genrePlaylist), className: "hover:underline", children: genrePlaylist.name })
|
|
2778
2824
|
] }, genrePlaylist.uuid)) }) : song.genre.name
|
|
2779
2825
|
});
|
|
2780
2826
|
} else {
|
|
2781
|
-
fields.push({ label: "Genre", value: /* @__PURE__ */ (0,
|
|
2827
|
+
fields.push({ label: "Genre", value: /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("span", { className: "text-[var(--color-text-muted)]", children: "No genre" }) });
|
|
2782
2828
|
}
|
|
2783
2829
|
if (song.firstReleaseYear) fields.push({ label: "First released", value: song.firstReleaseYear });
|
|
2784
2830
|
const viewCount = song.youtubeVideo?.viewCount;
|
|
@@ -2788,11 +2834,11 @@ function SongPanelContent(props) {
|
|
|
2788
2834
|
const links = [];
|
|
2789
2835
|
if (musicBrainzUrl)
|
|
2790
2836
|
links.push(
|
|
2791
|
-
/* @__PURE__ */ (0,
|
|
2837
|
+
/* @__PURE__ */ (0, import_jsx_runtime49.jsx)("a", { href: musicBrainzUrl, target: "_blank", rel: "noopener noreferrer", className: externalLink, children: "MusicBrainz" }, "mb")
|
|
2792
2838
|
);
|
|
2793
2839
|
if (song.youtubeVideo)
|
|
2794
2840
|
links.push(
|
|
2795
|
-
/* @__PURE__ */ (0,
|
|
2841
|
+
/* @__PURE__ */ (0, import_jsx_runtime49.jsx)(
|
|
2796
2842
|
"a",
|
|
2797
2843
|
{
|
|
2798
2844
|
href: `https://www.youtube.com/watch?v=${encodeURIComponent(song.youtubeVideo.id)}`,
|
|
@@ -2807,31 +2853,31 @@ function SongPanelContent(props) {
|
|
|
2807
2853
|
if (links.length > 0)
|
|
2808
2854
|
fields.push({
|
|
2809
2855
|
label: "Links",
|
|
2810
|
-
value: /* @__PURE__ */ (0,
|
|
2856
|
+
value: /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("span", { className: "flex gap-3", children: links })
|
|
2811
2857
|
});
|
|
2812
|
-
return /* @__PURE__ */ (0,
|
|
2813
|
-
/* @__PURE__ */ (0,
|
|
2814
|
-
/* @__PURE__ */ (0,
|
|
2858
|
+
return /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)(import_jsx_runtime49.Fragment, { children: [
|
|
2859
|
+
/* @__PURE__ */ (0, import_jsx_runtime49.jsx)(import_ui21.PanelBleed, { children: /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)(import_ui21.ActionBand, { children: [
|
|
2860
|
+
/* @__PURE__ */ (0, import_jsx_runtime49.jsx)(
|
|
2815
2861
|
import_ui21.ActionButton,
|
|
2816
2862
|
{
|
|
2817
|
-
icon: isPlaying ? /* @__PURE__ */ (0,
|
|
2863
|
+
icon: isPlaying ? /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(import_lucide_react16.Pause, { "aria-hidden": "true", className: "w-5 h-5" }) : /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(import_lucide_react16.Play, { "aria-hidden": "true", className: "w-5 h-5" }),
|
|
2818
2864
|
label: isPlaying ? "Pause" : "Play",
|
|
2819
2865
|
disabled: !!unplayableReason,
|
|
2820
2866
|
title: unplayableReason ?? void 0,
|
|
2821
2867
|
onClick: () => isCurrent ? handlePlayPauseAction() : playNewTrackListFromTrackUuid(song, scope)
|
|
2822
2868
|
}
|
|
2823
2869
|
),
|
|
2824
|
-
shareUrl && /* @__PURE__ */ (0,
|
|
2870
|
+
shareUrl && /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(ShareActionButton, { target: shareTarget, url: shareUrl })
|
|
2825
2871
|
] }) }),
|
|
2826
|
-
song.artists && song.artists.length > 0 && /* @__PURE__ */ (0,
|
|
2827
|
-
/* @__PURE__ */ (0,
|
|
2828
|
-
song.essentialGenres && song.essentialGenres.length > 0 && /* @__PURE__ */ (0,
|
|
2829
|
-
/* @__PURE__ */ (0,
|
|
2872
|
+
song.artists && song.artists.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("p", { className: "text-[var(--color-text-muted)]", children: /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(import_genre_tree28.ArtistNames, { artists: song.artists, renderArtistLink }) }),
|
|
2873
|
+
/* @__PURE__ */ (0, import_jsx_runtime49.jsx)(import_ui21.FieldList, { items: fields }),
|
|
2874
|
+
song.essentialGenres && song.essentialGenres.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(import_ui21.PanelSection, { title: "Essential in", children: /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("ul", { children: song.essentialGenres.map((genre) => /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("li", { className: "py-0.5", children: genre.name }, genre.uuid)) }) }),
|
|
2875
|
+
/* @__PURE__ */ (0, import_jsx_runtime49.jsx)(SongHistory, { uuid: song.uuid, getBackendBaseUrl })
|
|
2830
2876
|
] });
|
|
2831
2877
|
}
|
|
2832
2878
|
|
|
2833
2879
|
// src/genre-tree/song/useSongPanel.tsx
|
|
2834
|
-
var
|
|
2880
|
+
var import_jsx_runtime50 = require("react/jsx-runtime");
|
|
2835
2881
|
function useSongPanel({
|
|
2836
2882
|
uuid,
|
|
2837
2883
|
scope,
|
|
@@ -2852,24 +2898,24 @@ function useSongPanel({
|
|
|
2852
2898
|
return {
|
|
2853
2899
|
...panel,
|
|
2854
2900
|
title: "Song",
|
|
2855
|
-
content: /* @__PURE__ */ (0,
|
|
2856
|
-
/* @__PURE__ */ (0,
|
|
2857
|
-
/* @__PURE__ */ (0,
|
|
2858
|
-
/* @__PURE__ */ (0,
|
|
2859
|
-
/* @__PURE__ */ (0,
|
|
2901
|
+
content: /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)("div", { "aria-busy": "true", className: "flex flex-col gap-2.5", children: [
|
|
2902
|
+
/* @__PURE__ */ (0, import_jsx_runtime50.jsx)(import_ui22.Skeleton, { className: "h-3 w-16" }),
|
|
2903
|
+
/* @__PURE__ */ (0, import_jsx_runtime50.jsx)(import_ui22.Skeleton, { className: "h-4 w-32" }),
|
|
2904
|
+
/* @__PURE__ */ (0, import_jsx_runtime50.jsx)(import_ui22.Skeleton, { className: "h-3 w-16" }),
|
|
2905
|
+
/* @__PURE__ */ (0, import_jsx_runtime50.jsx)(import_ui22.Skeleton, { className: "h-4 w-24" })
|
|
2860
2906
|
] })
|
|
2861
2907
|
};
|
|
2862
2908
|
case "not-found":
|
|
2863
2909
|
return {
|
|
2864
2910
|
...panel,
|
|
2865
2911
|
title: "Song not found",
|
|
2866
|
-
content: /* @__PURE__ */ (0,
|
|
2912
|
+
content: /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("p", { className: "text-[var(--color-text-muted)]", children: "This song does not exist." })
|
|
2867
2913
|
};
|
|
2868
2914
|
case "error":
|
|
2869
2915
|
return {
|
|
2870
2916
|
...panel,
|
|
2871
2917
|
title: "Song",
|
|
2872
|
-
content: /* @__PURE__ */ (0,
|
|
2918
|
+
content: /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("p", { className: "text-red-600", children: "Could not load this song." })
|
|
2873
2919
|
};
|
|
2874
2920
|
case "success": {
|
|
2875
2921
|
const { song } = result;
|
|
@@ -2877,7 +2923,7 @@ function useSongPanel({
|
|
|
2877
2923
|
return {
|
|
2878
2924
|
...panel,
|
|
2879
2925
|
title: song.title,
|
|
2880
|
-
content: /* @__PURE__ */ (0,
|
|
2926
|
+
content: /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(
|
|
2881
2927
|
SongPanelContent,
|
|
2882
2928
|
{
|
|
2883
2929
|
song,
|
|
@@ -2904,6 +2950,7 @@ function useEntityPanel({
|
|
|
2904
2950
|
getShareUrl,
|
|
2905
2951
|
renderArtistLink,
|
|
2906
2952
|
renderSongLink,
|
|
2953
|
+
renderPlaceLink,
|
|
2907
2954
|
song,
|
|
2908
2955
|
artist,
|
|
2909
2956
|
...navigation
|
|
@@ -2922,7 +2969,8 @@ function useEntityPanel({
|
|
|
2922
2969
|
getBackendBaseUrl: getArtistBackendBaseUrl ?? getBackendBaseUrl,
|
|
2923
2970
|
getShareUrl,
|
|
2924
2971
|
renderArtistLink,
|
|
2925
|
-
renderSongLink
|
|
2972
|
+
renderSongLink,
|
|
2973
|
+
renderPlaceLink
|
|
2926
2974
|
});
|
|
2927
2975
|
return songPanel ?? artistPanel;
|
|
2928
2976
|
}
|
|
@@ -2930,12 +2978,12 @@ function useEntityPanel({
|
|
|
2930
2978
|
// src/genre-tree/SizeMetricToggle.tsx
|
|
2931
2979
|
var import_md2 = require("react-icons/md");
|
|
2932
2980
|
var import_ui23 = require("@behindthemusictree/ui");
|
|
2933
|
-
var
|
|
2981
|
+
var import_jsx_runtime51 = require("react/jsx-runtime");
|
|
2934
2982
|
function SizeMetricToggle({
|
|
2935
2983
|
value,
|
|
2936
2984
|
onChange
|
|
2937
2985
|
}) {
|
|
2938
|
-
return /* @__PURE__ */ (0,
|
|
2986
|
+
return /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(
|
|
2939
2987
|
import_ui23.SegmentedControl,
|
|
2940
2988
|
{
|
|
2941
2989
|
variant: "floating",
|
|
@@ -2943,15 +2991,15 @@ function SizeMetricToggle({
|
|
|
2943
2991
|
value,
|
|
2944
2992
|
onChange,
|
|
2945
2993
|
options: [
|
|
2946
|
-
{ value: "songs", label: /* @__PURE__ */ (0,
|
|
2947
|
-
{ value: "views", label: /* @__PURE__ */ (0,
|
|
2994
|
+
{ value: "songs", label: /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(import_md2.MdMusicNote, { size: 18, "aria-hidden": true }), "aria-label": "Size by songs", title: "Node size by song count" },
|
|
2995
|
+
{ value: "views", label: /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(import_md2.MdVisibility, { size: 18, "aria-hidden": true }), "aria-label": "Size by views", title: "Node size by song views" }
|
|
2948
2996
|
]
|
|
2949
2997
|
}
|
|
2950
2998
|
);
|
|
2951
2999
|
}
|
|
2952
3000
|
|
|
2953
3001
|
// src/genre-tree/GenreTreeView.tsx
|
|
2954
|
-
var
|
|
3002
|
+
var import_jsx_runtime52 = require("react/jsx-runtime");
|
|
2955
3003
|
var NO_POP_ROOT_TITLE = "This genre tree has no 'Mainstream Pop' root yet";
|
|
2956
3004
|
var REGIONS_CLASS = "[--gtv-center-left:var(--layout-center-left)] [--gtv-center-right:var(--layout-center-right)] [--gtv-center-top:var(--layout-band-top)]";
|
|
2957
3005
|
var noop = () => {
|
|
@@ -2999,6 +3047,7 @@ function GenreTreeView({
|
|
|
2999
3047
|
songSearch = true,
|
|
3000
3048
|
onSongSelect,
|
|
3001
3049
|
renderSongLink,
|
|
3050
|
+
renderPlaceLink,
|
|
3002
3051
|
renderSummary,
|
|
3003
3052
|
renderEssentialTracks,
|
|
3004
3053
|
renderSongLeading,
|
|
@@ -3059,7 +3108,7 @@ function GenreTreeView({
|
|
|
3059
3108
|
allowWheelRotation: internalAllowWheelRotation,
|
|
3060
3109
|
toggleWheelRotation,
|
|
3061
3110
|
onNodeHover: handleNodeHover
|
|
3062
|
-
} = (0,
|
|
3111
|
+
} = (0, import_genre_tree31.useGenreTreeViewState)({
|
|
3063
3112
|
scope,
|
|
3064
3113
|
getBackendBaseUrl,
|
|
3065
3114
|
viewMode: controlledViewMode,
|
|
@@ -3078,12 +3127,12 @@ function GenreTreeView({
|
|
|
3078
3127
|
restoreRootUuid = selectedGenrePlaylist.root.uuid;
|
|
3079
3128
|
setStackedRestoreOwner({ revision: restoreRevision, rootUuid: restoreRootUuid });
|
|
3080
3129
|
}
|
|
3081
|
-
const isGenreUpdating = (0, import_react_query3.useIsMutating)({ mutationKey:
|
|
3082
|
-
const { mutate: updateGenre } = (0,
|
|
3130
|
+
const isGenreUpdating = (0, import_react_query3.useIsMutating)({ mutationKey: import_genre_tree31.genreUpdateMutationKey }) > 0;
|
|
3131
|
+
const { mutate: updateGenre } = (0, import_genre_tree31.useUpdateGenre)(scope, getBackendBaseUrl);
|
|
3083
3132
|
const busy = deferredSizeMetric !== sizeMetric || isTreeFetching || isGenreUpdating;
|
|
3084
3133
|
const isArtistFiltered = artistUuid !== null;
|
|
3085
3134
|
const canSizeByViews = !isArtistFiltered && hasViewsCount(visibleGenrePlaylists);
|
|
3086
|
-
const artistResult = (0,
|
|
3135
|
+
const artistResult = (0, import_genre_tree31.useArtist)(artistUuid, artistSearchBaseUrl ?? getBackendBaseUrl);
|
|
3087
3136
|
const filterArtistName = artistResult.status === "success" ? artistResult.artist.name : null;
|
|
3088
3137
|
const filterArtist = (0, import_react19.useMemo)(
|
|
3089
3138
|
() => artistUuid !== null && filterArtistName !== null ? { uuid: artistUuid, name: filterArtistName } : null,
|
|
@@ -3103,14 +3152,14 @@ function GenreTreeView({
|
|
|
3103
3152
|
const openSongRef = (0, import_react19.useRef)(openSong);
|
|
3104
3153
|
openSongRef.current = openSong;
|
|
3105
3154
|
const resolvedRenderSongLink = (0, import_react19.useCallback)(
|
|
3106
|
-
(song) => renderSongLink ? renderSongLink(song) : /* @__PURE__ */ (0,
|
|
3155
|
+
(song) => renderSongLink ? renderSongLink(song) : /* @__PURE__ */ (0, import_jsx_runtime52.jsx)("button", { type: "button", onClick: () => openSongRef.current(song.uuid), className: "hover:underline", children: song.title }),
|
|
3107
3156
|
[renderSongLink]
|
|
3108
3157
|
);
|
|
3109
3158
|
const [expandedSongUuid, setExpandedSongUuid] = (0, import_react19.useState)(null);
|
|
3110
3159
|
const [expandedArtistUuid, setExpandedArtistUuid] = (0, import_react19.useState)(null);
|
|
3111
3160
|
const artistBaseUrl = artistSearchBaseUrl ?? getBackendBaseUrl;
|
|
3112
3161
|
const songBaseUrl = getBackendBaseUrl;
|
|
3113
|
-
const resolvedRenderArtistLink = renderArtistLink ?? ((artist) => artist.isSpecialPurpose ? artist.name : /* @__PURE__ */ (0,
|
|
3162
|
+
const resolvedRenderArtistLink = renderArtistLink ?? ((artist) => artist.isSpecialPurpose ? artist.name : /* @__PURE__ */ (0, import_jsx_runtime52.jsx)("button", { type: "button", onClick: () => openArtist(artist.uuid), className: "hover:underline", children: artist.name }));
|
|
3114
3163
|
const getGenrePath = (genre) => {
|
|
3115
3164
|
const path = [];
|
|
3116
3165
|
let current = visibleGenrePlaylists.find((playlist) => playlist.criteria?.uuid === genre.uuid);
|
|
@@ -3128,6 +3177,7 @@ function GenreTreeView({
|
|
|
3128
3177
|
getShareUrl: getShareUrlRef.current,
|
|
3129
3178
|
renderArtistLink: resolvedRenderArtistLink,
|
|
3130
3179
|
renderSongLink: resolvedRenderSongLink,
|
|
3180
|
+
renderPlaceLink,
|
|
3131
3181
|
song: {
|
|
3132
3182
|
uuid: songUuid,
|
|
3133
3183
|
expanded: controlledSongExpanded ?? (songUuid !== null && expandedSongUuid === songUuid),
|
|
@@ -3187,9 +3237,10 @@ function GenreTreeView({
|
|
|
3187
3237
|
resolveStyle
|
|
3188
3238
|
);
|
|
3189
3239
|
const treeStyles = (0, import_react19.useMemo)(() => toGenreNodeStyles(relations, visibleGenrePlaylists), [relations, visibleGenrePlaylists]);
|
|
3190
|
-
const
|
|
3191
|
-
|
|
3192
|
-
|
|
3240
|
+
const validSelectedGenreUuid = (0, import_genre_tree30.toGenreUuid)(selectedGenreUuid);
|
|
3241
|
+
const [selectionHistory, setSelectionHistory] = (0, import_react19.useState)({ current: validSelectedGenreUuid, previous: null });
|
|
3242
|
+
if (selectionHistory.current !== validSelectedGenreUuid) {
|
|
3243
|
+
setSelectionHistory({ current: validSelectedGenreUuid, previous: selectionHistory.current ?? selectionHistory.previous });
|
|
3193
3244
|
}
|
|
3194
3245
|
const handlePrevious = selectionHistory.previous ? () => selectGenre(selectionHistory.previous) : void 0;
|
|
3195
3246
|
const { showPopup, hidePopup } = (0, import_popup5.usePopup)();
|
|
@@ -3221,7 +3272,7 @@ function GenreTreeView({
|
|
|
3221
3272
|
const canToggleSide = !readOnly && criteria !== void 0 && criteria !== null && parentPlaylist !== void 0 && parentPlaylist.parent === null;
|
|
3222
3273
|
const side = criteria?.side ?? "core";
|
|
3223
3274
|
const popSibling = canToggleSide && side === "core" ? visibleGenrePlaylists.find((sibling) => sibling.parent?.uuid === parentPlaylist.uuid && sibling.uuid !== genrePlaylist?.uuid && sibling.criteria?.side === "pop") : void 0;
|
|
3224
|
-
const shareTarget =
|
|
3275
|
+
const shareTarget = validSelectedGenreUuid ? { kind: "genre", genreUuid: validSelectedGenreUuid, name: criteria?.name ?? "Genre", scope, artistUuid } : void 0;
|
|
3225
3276
|
const shareUrl = shareTarget ? getShareUrlRef.current?.(shareTarget) ?? void 0 : void 0;
|
|
3226
3277
|
const genreContent = useGenreDetailContent({
|
|
3227
3278
|
genreUuid: selectedGenreUuid,
|
|
@@ -3243,7 +3294,7 @@ function GenreTreeView({
|
|
|
3243
3294
|
onAddChild: readOnly || !criteria ? void 0 : () => handleGenreCreationAction(criteria),
|
|
3244
3295
|
onRename: readOnly || !criteria ? void 0 : () => handleGenreRenameAction(criteria),
|
|
3245
3296
|
onChangeParent: readOnly || !genrePlaylist || !criteria ? void 0 : () => showPopup(
|
|
3246
|
-
/* @__PURE__ */ (0,
|
|
3297
|
+
/* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
|
|
3247
3298
|
ChangeParentPopup,
|
|
3248
3299
|
{
|
|
3249
3300
|
genrePlaylist: { ...genrePlaylist, criteria },
|
|
@@ -3287,7 +3338,7 @@ function GenreTreeView({
|
|
|
3287
3338
|
onClose: otherPanel.onClose,
|
|
3288
3339
|
searchName: otherPanel.title
|
|
3289
3340
|
};
|
|
3290
|
-
} else if (selectedGenreUuid) {
|
|
3341
|
+
} else if (selectedGenreUuid !== null) {
|
|
3291
3342
|
activePanel = {
|
|
3292
3343
|
title: genreContent.title,
|
|
3293
3344
|
content: genreContent.content,
|
|
@@ -3304,19 +3355,19 @@ function GenreTreeView({
|
|
|
3304
3355
|
edge: activePanel.expanded ? { label: "Shrink panel", onClick: () => activePanel.onExpandedChange?.(false) } : isCollapsed ? null : { label: "Hide panel", onClick: () => changeCollapsed(true) },
|
|
3305
3356
|
center: activePanel.expanded ? null : isCollapsed ? { label: "Show panel", onClick: () => changeCollapsed(false) } : activePanel.onExpandedChange ? { label: "Extend panel", onClick: () => activePanel.onExpandedChange?.(true) } : null
|
|
3306
3357
|
} : void 0;
|
|
3307
|
-
const expandButton = placement === "default" && activePanel?.onExpandedChange ? /* @__PURE__ */ (0,
|
|
3358
|
+
const expandButton = placement === "default" && activePanel?.onExpandedChange ? /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
|
|
3308
3359
|
import_ui24.IconButton,
|
|
3309
3360
|
{
|
|
3310
3361
|
"aria-label": activePanel.expanded ? "Shrink panel" : "Extend panel",
|
|
3311
3362
|
style: activePanel.headerAccent && { color: "inherit" },
|
|
3312
3363
|
onClick: () => activePanel.onExpandedChange?.(!activePanel.expanded),
|
|
3313
|
-
children: activePanel.expanded ? /* @__PURE__ */ (0,
|
|
3364
|
+
children: activePanel.expanded ? /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(import_lucide_react18.Minimize2, { "aria-hidden": "true", className: "h-4 w-4" }) : /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(import_lucide_react18.Maximize2, { "aria-hidden": "true", className: "h-4 w-4" })
|
|
3314
3365
|
}
|
|
3315
3366
|
) : null;
|
|
3316
3367
|
const renderArtistFilter = () => {
|
|
3317
3368
|
if (isLoading || !filterArtist) return null;
|
|
3318
|
-
return /* @__PURE__ */ (0,
|
|
3319
|
-
/* @__PURE__ */ (0,
|
|
3369
|
+
return /* @__PURE__ */ (0, import_jsx_runtime52.jsxs)("span", { className: "inline-flex items-center overflow-hidden rounded-full bg-[var(--color-neutral-100)] text-body", children: [
|
|
3370
|
+
/* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
|
|
3320
3371
|
"button",
|
|
3321
3372
|
{
|
|
3322
3373
|
type: "button",
|
|
@@ -3328,7 +3379,7 @@ function GenreTreeView({
|
|
|
3328
3379
|
children: filterArtist.name
|
|
3329
3380
|
}
|
|
3330
3381
|
),
|
|
3331
|
-
/* @__PURE__ */ (0,
|
|
3382
|
+
/* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
|
|
3332
3383
|
"button",
|
|
3333
3384
|
{
|
|
3334
3385
|
type: "button",
|
|
@@ -3340,8 +3391,8 @@ function GenreTreeView({
|
|
|
3340
3391
|
)
|
|
3341
3392
|
] });
|
|
3342
3393
|
};
|
|
3343
|
-
const actions = /* @__PURE__ */ (0,
|
|
3344
|
-
!isLoading && !isError && /* @__PURE__ */ (0,
|
|
3394
|
+
const actions = /* @__PURE__ */ (0, import_jsx_runtime52.jsxs)(import_jsx_runtime52.Fragment, { children: [
|
|
3395
|
+
!isLoading && !isError && /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
|
|
3345
3396
|
GenreTreeSearch,
|
|
3346
3397
|
{
|
|
3347
3398
|
artistBaseUrl,
|
|
@@ -3374,9 +3425,9 @@ function GenreTreeView({
|
|
|
3374
3425
|
extraGroups: extraSearchGroups
|
|
3375
3426
|
}
|
|
3376
3427
|
),
|
|
3377
|
-
!isLoading && !isError && filterArtist && /* @__PURE__ */ (0,
|
|
3378
|
-
/* @__PURE__ */ (0,
|
|
3379
|
-
!isLoading && !isError && !isControlled && /* @__PURE__ */ (0,
|
|
3428
|
+
!isLoading && !isError && filterArtist && /* @__PURE__ */ (0, import_jsx_runtime52.jsx)("div", { className: "hidden w-full justify-center max-md:flex", children: renderArtistFilter() }),
|
|
3429
|
+
/* @__PURE__ */ (0, import_jsx_runtime52.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: [
|
|
3430
|
+
!isLoading && !isError && !isControlled && /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
|
|
3380
3431
|
import_ui24.SegmentedControl,
|
|
3381
3432
|
{
|
|
3382
3433
|
"aria-label": "Tree view mode",
|
|
@@ -3390,13 +3441,13 @@ function GenreTreeView({
|
|
|
3390
3441
|
]
|
|
3391
3442
|
}
|
|
3392
3443
|
),
|
|
3393
|
-
!isLoading && !isError && showDisplayOptions && /* @__PURE__ */ (0,
|
|
3444
|
+
!isLoading && !isError && showDisplayOptions && /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
|
|
3394
3445
|
"div",
|
|
3395
3446
|
{
|
|
3396
3447
|
className: "flex items-center gap-1",
|
|
3397
3448
|
role: "group",
|
|
3398
3449
|
"aria-label": "Tree display options",
|
|
3399
|
-
children: !isRotationControlled && viewMode !== "stacked" && viewMode !== "outline" && /* @__PURE__ */ (0,
|
|
3450
|
+
children: !isRotationControlled && viewMode !== "stacked" && viewMode !== "outline" && /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
|
|
3400
3451
|
import_ui24.Button,
|
|
3401
3452
|
{
|
|
3402
3453
|
variant: allowWheelRotation ? "default" : "outline",
|
|
@@ -3407,7 +3458,7 @@ function GenreTreeView({
|
|
|
3407
3458
|
)
|
|
3408
3459
|
}
|
|
3409
3460
|
),
|
|
3410
|
-
!isLoading && !isError && !readOnly && showAddRoot && /* @__PURE__ */ (0,
|
|
3461
|
+
!isLoading && !isError && !readOnly && showAddRoot && /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
|
|
3411
3462
|
import_ui24.IconTextButton,
|
|
3412
3463
|
{
|
|
3413
3464
|
icon: import_lucide_react17.Plus,
|
|
@@ -3417,38 +3468,38 @@ function GenreTreeView({
|
|
|
3417
3468
|
)
|
|
3418
3469
|
] })
|
|
3419
3470
|
] });
|
|
3420
|
-
return /* @__PURE__ */ (0,
|
|
3471
|
+
return /* @__PURE__ */ (0, import_jsx_runtime52.jsxs)(
|
|
3421
3472
|
"div",
|
|
3422
3473
|
{
|
|
3423
3474
|
"data-left-panel": isPanelShown && !isCollapsed ? void 0 : "hidden",
|
|
3424
3475
|
className: ["genre-tree-view relative flex flex-col h-full", placement === "regions" && REGIONS_CLASS, className2].filter(Boolean).join(" "),
|
|
3425
3476
|
children: [
|
|
3426
|
-
/* @__PURE__ */ (0,
|
|
3477
|
+
/* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
|
|
3427
3478
|
"div",
|
|
3428
3479
|
{
|
|
3429
3480
|
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"}`,
|
|
3430
3481
|
children: actions
|
|
3431
3482
|
}
|
|
3432
3483
|
),
|
|
3433
|
-
!isLoading && !isError && filterArtist && /* @__PURE__ */ (0,
|
|
3484
|
+
!isLoading && !isError && filterArtist && /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
|
|
3434
3485
|
"div",
|
|
3435
3486
|
{
|
|
3436
3487
|
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"}`,
|
|
3437
3488
|
children: renderArtistFilter()
|
|
3438
3489
|
}
|
|
3439
3490
|
),
|
|
3440
|
-
/* @__PURE__ */ (0,
|
|
3441
|
-
!isLoading && !isError && viewMode === "outline" && floatingControlsLeading && /* @__PURE__ */ (0,
|
|
3442
|
-
isLoading ? /* @__PURE__ */ (0,
|
|
3491
|
+
/* @__PURE__ */ (0, import_jsx_runtime52.jsx)("div", { className: "content-container flex-1 min-h-0 flex flex-row gap-4", children: /* @__PURE__ */ (0, import_jsx_runtime52.jsxs)("div", { className: "tree-view-container relative flex-1 min-w-0 flex flex-col h-full", children: [
|
|
3492
|
+
!isLoading && !isError && viewMode === "outline" && floatingControlsLeading && /* @__PURE__ */ (0, import_jsx_runtime52.jsx)("div", { className: "absolute bottom-3 right-3 z-10", children: floatingControlsLeading }),
|
|
3493
|
+
isLoading ? /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(import_genre_tree_view5.GenreTreeViewSkeleton, { viewMode }) : isError ? /* @__PURE__ */ (0, import_jsx_runtime52.jsxs)("p", { role: "alert", className: "m-auto text-center", children: [
|
|
3443
3494
|
"Couldn't load the genre tree.",
|
|
3444
3495
|
" ",
|
|
3445
|
-
/* @__PURE__ */ (0,
|
|
3496
|
+
/* @__PURE__ */ (0, import_jsx_runtime52.jsx)("button", { type: "button", className: "underline", onClick: refetch, children: "Retry" })
|
|
3446
3497
|
] }) : viewMode === "wheel" ? (
|
|
3447
3498
|
// The info panel's top edge aligns with the tree's; the search bar floats `--layout-panel-inset` below it,
|
|
3448
3499
|
// and the header inset (the bar's height plus that inset) extends the header's fill behind the bar,
|
|
3449
3500
|
// Google Maps style; the 8px bottom padding mirrors the inset above the bar, and the hidden title's height is zeroed.
|
|
3450
3501
|
// The panel's own Zoom in button is hidden: the search bar carries it.
|
|
3451
|
-
/* @__PURE__ */ (0,
|
|
3502
|
+
/* @__PURE__ */ (0, import_jsx_runtime52.jsx)("div", { className: "tree-container search-overlay relative flex-1 w-full min-h-0 ", children: /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(GenreTreeWheelHandoff, { skeleton: /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(import_genre_tree_view5.GenreTreeWheelSkeleton, {}), onRevealedChange: setIsWheelRevealed, children: /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
|
|
3452
3503
|
GenrePlaylistTreeWheel,
|
|
3453
3504
|
{
|
|
3454
3505
|
scope,
|
|
@@ -3466,9 +3517,9 @@ function GenreTreeView({
|
|
|
3466
3517
|
allowWheelRotation,
|
|
3467
3518
|
sizeMetric: isArtistFiltered || !canSizeByViews ? "songs" : deferredSizeMetric,
|
|
3468
3519
|
busy,
|
|
3469
|
-
floatingControlsLeading: floatingControlsLeading || canSizeByViews ? /* @__PURE__ */ (0,
|
|
3520
|
+
floatingControlsLeading: floatingControlsLeading || canSizeByViews ? /* @__PURE__ */ (0, import_jsx_runtime52.jsxs)("div", { className: "flex items-center gap-2", children: [
|
|
3470
3521
|
floatingControlsLeading,
|
|
3471
|
-
canSizeByViews && /* @__PURE__ */ (0,
|
|
3522
|
+
canSizeByViews && /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(SizeMetricToggle, { value: sizeMetric, onChange: changeSizeMetric })
|
|
3472
3523
|
] }) : void 0,
|
|
3473
3524
|
defaultViewport,
|
|
3474
3525
|
viewportRestore,
|
|
@@ -3477,7 +3528,7 @@ function GenreTreeView({
|
|
|
3477
3528
|
) }) })
|
|
3478
3529
|
) : viewMode === "pop-core" ? (
|
|
3479
3530
|
// Same as the wheel: the header inset extends its fill behind the floating search bar, Google Maps style.
|
|
3480
|
-
/* @__PURE__ */ (0,
|
|
3531
|
+
/* @__PURE__ */ (0, import_jsx_runtime52.jsx)("div", { className: "tree-container search-overlay relative flex-1 w-full min-h-0 ", children: /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(GenreTreeWheelHandoff, { skeleton: /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(import_genre_tree_view5.GenreTreeWheelSkeleton, {}), onRevealedChange: setIsWheelRevealed, children: /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
|
|
3481
3532
|
GenrePlaylistTreeWheelRadialPopCore,
|
|
3482
3533
|
{
|
|
3483
3534
|
scope,
|
|
@@ -3495,9 +3546,9 @@ function GenreTreeView({
|
|
|
3495
3546
|
allowWheelRotation,
|
|
3496
3547
|
sizeMetric: isArtistFiltered || !canSizeByViews ? "songs" : deferredSizeMetric,
|
|
3497
3548
|
busy,
|
|
3498
|
-
floatingControlsLeading: floatingControlsLeading || canSizeByViews ? /* @__PURE__ */ (0,
|
|
3549
|
+
floatingControlsLeading: floatingControlsLeading || canSizeByViews ? /* @__PURE__ */ (0, import_jsx_runtime52.jsxs)("div", { className: "flex items-center gap-2", children: [
|
|
3499
3550
|
floatingControlsLeading,
|
|
3500
|
-
canSizeByViews && /* @__PURE__ */ (0,
|
|
3551
|
+
canSizeByViews && /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(SizeMetricToggle, { value: sizeMetric, onChange: changeSizeMetric })
|
|
3501
3552
|
] }) : void 0,
|
|
3502
3553
|
defaultViewport,
|
|
3503
3554
|
viewportRestore,
|
|
@@ -3505,7 +3556,7 @@ function GenreTreeView({
|
|
|
3505
3556
|
...focus
|
|
3506
3557
|
}
|
|
3507
3558
|
) }) })
|
|
3508
|
-
) : viewMode === "outline" ? /* @__PURE__ */ (0,
|
|
3559
|
+
) : viewMode === "outline" ? /* @__PURE__ */ (0, import_jsx_runtime52.jsx)("div", { className: "tree-container flex-1 min-h-0 w-full overflow-y-auto relative", children: /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
|
|
3509
3560
|
GenrePlaylistTreeWheelRadialPopCore,
|
|
3510
3561
|
{
|
|
3511
3562
|
outline: true,
|
|
@@ -3522,13 +3573,13 @@ function GenreTreeView({
|
|
|
3522
3573
|
selectedNodeId,
|
|
3523
3574
|
readOnly
|
|
3524
3575
|
}
|
|
3525
|
-
) }) : /* @__PURE__ */ (0,
|
|
3576
|
+
) }) : /* @__PURE__ */ (0, import_jsx_runtime52.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(
|
|
3526
3577
|
([uuid, genrePlaylistTreePerRoot]) => {
|
|
3527
|
-
return /* @__PURE__ */ (0,
|
|
3578
|
+
return /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
|
|
3528
3579
|
"div",
|
|
3529
3580
|
{
|
|
3530
3581
|
className: "tree-per-root-container relative shrink-0 h-[28rem] mt-2 mr-16 p-2 bg-[var(--color-neutral-100)] rounded-lg",
|
|
3531
|
-
children: /* @__PURE__ */ (0,
|
|
3582
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime52.jsx)("div", { className: "graph-container relative z-10 h-full", children: /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
|
|
3532
3583
|
GenrePlaylistTreePerRoot,
|
|
3533
3584
|
{
|
|
3534
3585
|
scope,
|
|
@@ -3555,7 +3606,7 @@ function GenreTreeView({
|
|
|
3555
3606
|
);
|
|
3556
3607
|
}
|
|
3557
3608
|
) }),
|
|
3558
|
-
/* @__PURE__ */ (0,
|
|
3609
|
+
/* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
|
|
3559
3610
|
import_ui24.DetailPanel,
|
|
3560
3611
|
{
|
|
3561
3612
|
ref: panelRef,
|
|
@@ -3570,7 +3621,7 @@ function GenreTreeView({
|
|
|
3570
3621
|
onExpandedChange: activePanel?.onExpandedChange,
|
|
3571
3622
|
aside: activePanel?.aside,
|
|
3572
3623
|
edgeTab: detailTab,
|
|
3573
|
-
children: activePanel?.aside && !activePanel.expanded ? /* @__PURE__ */ (0,
|
|
3624
|
+
children: activePanel?.aside && !activePanel.expanded ? /* @__PURE__ */ (0, import_jsx_runtime52.jsxs)(import_jsx_runtime52.Fragment, { children: [
|
|
3574
3625
|
activePanel.content,
|
|
3575
3626
|
activePanel.aside
|
|
3576
3627
|
] }) : activePanel?.content
|
|
@@ -3588,10 +3639,10 @@ var import_genre_tree_view6 = require("@behindthemusictree/genre-tree-view");
|
|
|
3588
3639
|
// src/genre-tree/track-list-sidebar/TrackListSidebar.tsx
|
|
3589
3640
|
var import_react20 = require("react");
|
|
3590
3641
|
var import_lucide_react19 = require("lucide-react");
|
|
3591
|
-
var import_genre_tree31 = require("@behindthemusictree/app-kit/genre-tree");
|
|
3592
3642
|
var import_genre_tree32 = require("@behindthemusictree/app-kit/genre-tree");
|
|
3643
|
+
var import_genre_tree33 = require("@behindthemusictree/app-kit/genre-tree");
|
|
3593
3644
|
var import_track_noun4 = require("@behindthemusictree/app-kit/track-noun");
|
|
3594
|
-
var
|
|
3645
|
+
var import_jsx_runtime53 = require("react/jsx-runtime");
|
|
3595
3646
|
var useBrowserLayoutEffect = typeof window === "undefined" ? import_react20.useEffect : import_react20.useLayoutEffect;
|
|
3596
3647
|
function TrackListSidebar({
|
|
3597
3648
|
className: className2 = "",
|
|
@@ -3604,7 +3655,7 @@ function TrackListSidebar({
|
|
|
3604
3655
|
renderArtistLink,
|
|
3605
3656
|
renderSongLink
|
|
3606
3657
|
}) {
|
|
3607
|
-
const { trackList, loadMore, autoAdvanceScrollRequest } = (0,
|
|
3658
|
+
const { trackList, loadMore, autoAdvanceScrollRequest } = (0, import_genre_tree32.useTrackList)();
|
|
3608
3659
|
const trackNoun = (0, import_track_noun4.useTrackNoun)();
|
|
3609
3660
|
const trackListRef = (0, import_react20.useRef)(null);
|
|
3610
3661
|
const previousOriginRef = (0, import_react20.useRef)(trackList?.origin ?? null);
|
|
@@ -3693,25 +3744,25 @@ function TrackListSidebar({
|
|
|
3693
3744
|
}
|
|
3694
3745
|
};
|
|
3695
3746
|
const positionClasses = layout === "inline" ? "relative w-full flex h-full flex-col" : "fixed right-0 w-[50rem] flex flex-col";
|
|
3696
|
-
return trackList ? /* @__PURE__ */ (0,
|
|
3747
|
+
return trackList ? /* @__PURE__ */ (0, import_jsx_runtime53.jsxs)(
|
|
3697
3748
|
"div",
|
|
3698
3749
|
{
|
|
3699
3750
|
"data-theme": "dark",
|
|
3700
3751
|
className: `track-list-sidebar ${positionClasses} rounded-2xl bg-[var(--color-surface)] pb-1 ${className2}`,
|
|
3701
3752
|
style: layout === "fixed" ? { top: "63.5px", maxHeight: "calc(100vh - 63.5px - 79px)" } : void 0,
|
|
3702
3753
|
children: [
|
|
3703
|
-
/* @__PURE__ */ (0,
|
|
3704
|
-
/* @__PURE__ */ (0,
|
|
3705
|
-
/* @__PURE__ */ (0,
|
|
3706
|
-
/* @__PURE__ */ (0,
|
|
3707
|
-
/* @__PURE__ */ (0,
|
|
3754
|
+
/* @__PURE__ */ (0, import_jsx_runtime53.jsxs)("div", { className: "header flex h-16 items-center px-4 py-2 text-[var(--color-text)]", children: [
|
|
3755
|
+
/* @__PURE__ */ (0, import_jsx_runtime53.jsxs)("div", { className: "min-w-0 flex flex-1 flex-col justify-center", children: [
|
|
3756
|
+
/* @__PURE__ */ (0, import_jsx_runtime53.jsxs)("div", { className: "origin flex text-xl", children: [
|
|
3757
|
+
/* @__PURE__ */ (0, import_jsx_runtime53.jsx)("div", { className: "from h-auto flex flex-col justify-center items-center mr-2", children: "From" }),
|
|
3758
|
+
/* @__PURE__ */ (0, import_jsx_runtime53.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_runtime53.jsx)("div", { className: "name max-w-full truncate", children: trackList.origin.label }) })
|
|
3708
3759
|
] }),
|
|
3709
|
-
/* @__PURE__ */ (0,
|
|
3710
|
-
trackList.origin.type ===
|
|
3760
|
+
/* @__PURE__ */ (0, import_jsx_runtime53.jsxs)("div", { className: "info flex items-center text-body text-[var(--color-text-muted)]", children: [
|
|
3761
|
+
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 `,
|
|
3711
3762
|
`${trackList.total} ${trackList.total > 1 ? trackNoun.plural : trackNoun.singular}`
|
|
3712
3763
|
] })
|
|
3713
3764
|
] }),
|
|
3714
|
-
(isCollapsed && onExpand || !isCollapsed && onMinimize) && /* @__PURE__ */ (0,
|
|
3765
|
+
(isCollapsed && onExpand || !isCollapsed && onMinimize) && /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
|
|
3715
3766
|
"button",
|
|
3716
3767
|
{
|
|
3717
3768
|
type: "button",
|
|
@@ -3720,11 +3771,11 @@ function TrackListSidebar({
|
|
|
3720
3771
|
"aria-expanded": !isCollapsed,
|
|
3721
3772
|
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"}`,
|
|
3722
3773
|
onClick: isCollapsed ? onExpand : onMinimize,
|
|
3723
|
-
children: /* @__PURE__ */ (0,
|
|
3774
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(import_lucide_react19.ListMusic, { "aria-hidden": "true", className: "h-5 w-5" })
|
|
3724
3775
|
}
|
|
3725
3776
|
)
|
|
3726
3777
|
] }),
|
|
3727
|
-
!isCollapsed && /* @__PURE__ */ (0,
|
|
3778
|
+
!isCollapsed && /* @__PURE__ */ (0, import_jsx_runtime53.jsxs)(
|
|
3728
3779
|
"ul",
|
|
3729
3780
|
{
|
|
3730
3781
|
ref: trackListRef,
|
|
@@ -3734,7 +3785,7 @@ function TrackListSidebar({
|
|
|
3734
3785
|
onPointerDown: markUserScrollIntent,
|
|
3735
3786
|
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",
|
|
3736
3787
|
children: [
|
|
3737
|
-
trackList.tracks.map((track, index) => /* @__PURE__ */ (0,
|
|
3788
|
+
trackList.tracks.map((track, index) => /* @__PURE__ */ (0, import_jsx_runtime53.jsx)("li", { "data-track-uuid": track.uuid, children: /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
|
|
3738
3789
|
TrackItem,
|
|
3739
3790
|
{
|
|
3740
3791
|
track,
|
|
@@ -3745,7 +3796,7 @@ function TrackListSidebar({
|
|
|
3745
3796
|
renderSongLink
|
|
3746
3797
|
}
|
|
3747
3798
|
) }, track.uuid)),
|
|
3748
|
-
hasMore && /* @__PURE__ */ (0,
|
|
3799
|
+
hasMore && /* @__PURE__ */ (0, import_jsx_runtime53.jsx)("li", { ref: loadMoreSentinelRef, "aria-hidden": "true", className: "h-px" })
|
|
3749
3800
|
]
|
|
3750
3801
|
}
|
|
3751
3802
|
)
|
|
@@ -3758,14 +3809,14 @@ function TrackListSidebar({
|
|
|
3758
3809
|
var import_react21 = require("react");
|
|
3759
3810
|
var import_tailwind_merge = require("tailwind-merge");
|
|
3760
3811
|
var import_player14 = require("@behindthemusictree/app-kit/player");
|
|
3761
|
-
var
|
|
3812
|
+
var import_genre_tree35 = require("@behindthemusictree/app-kit/genre-tree");
|
|
3762
3813
|
var import_ui25 = require("@behindthemusictree/ui");
|
|
3763
3814
|
|
|
3764
3815
|
// src/genre-tree/PlayerControls.tsx
|
|
3765
3816
|
var import_lucide_react20 = require("lucide-react");
|
|
3766
|
-
var
|
|
3817
|
+
var import_genre_tree34 = require("@behindthemusictree/app-kit/genre-tree");
|
|
3767
3818
|
var import_player13 = require("@behindthemusictree/app-kit/player");
|
|
3768
|
-
var
|
|
3819
|
+
var import_jsx_runtime54 = require("react/jsx-runtime");
|
|
3769
3820
|
function PlayerControls() {
|
|
3770
3821
|
const {
|
|
3771
3822
|
duration,
|
|
@@ -3777,22 +3828,22 @@ function PlayerControls() {
|
|
|
3777
3828
|
setVolume,
|
|
3778
3829
|
volume
|
|
3779
3830
|
} = (0, import_player13.usePlayer)();
|
|
3780
|
-
const { hasNextTrack, hasPreviousTrack, playNextTrack, playPreviousTrack } = (0,
|
|
3831
|
+
const { hasNextTrack, hasPreviousTrack, playNextTrack, playPreviousTrack } = (0, import_genre_tree34.useTrackList)();
|
|
3781
3832
|
const currentTime = (0, import_player13.useCurrentTime)();
|
|
3782
3833
|
const isBusy = isLoading || playState === import_player13.PlayStates.LOADING;
|
|
3783
3834
|
const isReady = !!playerTrackObject?.isReady && !isBusy && !playerTrackObject.loadError;
|
|
3784
3835
|
const safeDuration = Number.isFinite(duration) && duration > 0 ? duration : 0;
|
|
3785
3836
|
const safeCurrentTime = Number.isFinite(currentTime) ? Math.max(0, Math.min(currentTime, safeDuration)) : 0;
|
|
3786
3837
|
const isPlaying = playState === import_player13.PlayStates.PLAYING;
|
|
3787
|
-
return /* @__PURE__ */ (0,
|
|
3838
|
+
return /* @__PURE__ */ (0, import_jsx_runtime54.jsxs)(
|
|
3788
3839
|
"section",
|
|
3789
3840
|
{
|
|
3790
3841
|
"aria-label": "Player controls",
|
|
3791
3842
|
className: "player-controls flex shrink-0 flex-col gap-2 border-b border-zinc-800 px-3 py-2 text-zinc-200",
|
|
3792
3843
|
children: [
|
|
3793
|
-
/* @__PURE__ */ (0,
|
|
3794
|
-
/* @__PURE__ */ (0,
|
|
3795
|
-
/* @__PURE__ */ (0,
|
|
3844
|
+
/* @__PURE__ */ (0, import_jsx_runtime54.jsxs)("div", { className: "flex min-w-0 items-center gap-2 text-xs tabular-nums text-zinc-400", children: [
|
|
3845
|
+
/* @__PURE__ */ (0, import_jsx_runtime54.jsx)("span", { "aria-label": "Elapsed time", children: (0, import_genre_tree34.formatTime)(safeCurrentTime) }),
|
|
3846
|
+
/* @__PURE__ */ (0, import_jsx_runtime54.jsx)(
|
|
3796
3847
|
"input",
|
|
3797
3848
|
{
|
|
3798
3849
|
"aria-label": "Seek",
|
|
@@ -3806,11 +3857,11 @@ function PlayerControls() {
|
|
|
3806
3857
|
onChange: (event) => seekTo(Number(event.currentTarget.value))
|
|
3807
3858
|
}
|
|
3808
3859
|
),
|
|
3809
|
-
/* @__PURE__ */ (0,
|
|
3860
|
+
/* @__PURE__ */ (0, import_jsx_runtime54.jsx)("span", { "aria-label": "Duration", children: (0, import_genre_tree34.formatTime)(safeDuration) })
|
|
3810
3861
|
] }),
|
|
3811
|
-
/* @__PURE__ */ (0,
|
|
3812
|
-
/* @__PURE__ */ (0,
|
|
3813
|
-
/* @__PURE__ */ (0,
|
|
3862
|
+
/* @__PURE__ */ (0, import_jsx_runtime54.jsxs)("div", { className: "grid min-h-9 grid-cols-[1fr_auto_1fr] items-center gap-3", children: [
|
|
3863
|
+
/* @__PURE__ */ (0, import_jsx_runtime54.jsxs)("div", { className: "col-start-2 flex items-center justify-center gap-2", children: [
|
|
3864
|
+
/* @__PURE__ */ (0, import_jsx_runtime54.jsx)(
|
|
3814
3865
|
"button",
|
|
3815
3866
|
{
|
|
3816
3867
|
type: "button",
|
|
@@ -3819,10 +3870,10 @@ function PlayerControls() {
|
|
|
3819
3870
|
disabled: !isReady || !hasPreviousTrack,
|
|
3820
3871
|
onClick: playPreviousTrack,
|
|
3821
3872
|
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",
|
|
3822
|
-
children: /* @__PURE__ */ (0,
|
|
3873
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(import_lucide_react20.SkipBack, { "aria-hidden": "true", className: "h-4 w-4" })
|
|
3823
3874
|
}
|
|
3824
3875
|
),
|
|
3825
|
-
/* @__PURE__ */ (0,
|
|
3876
|
+
/* @__PURE__ */ (0, import_jsx_runtime54.jsx)(
|
|
3826
3877
|
"button",
|
|
3827
3878
|
{
|
|
3828
3879
|
type: "button",
|
|
@@ -3831,10 +3882,10 @@ function PlayerControls() {
|
|
|
3831
3882
|
disabled: !isReady,
|
|
3832
3883
|
onClick: handlePlayPauseAction,
|
|
3833
3884
|
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",
|
|
3834
|
-
children: isPlaying ? /* @__PURE__ */ (0,
|
|
3885
|
+
children: isPlaying ? /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(import_lucide_react20.Pause, { "aria-hidden": "true", className: "h-4 w-4", fill: "currentColor" }) : /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(import_lucide_react20.Play, { "aria-hidden": "true", className: "h-4 w-4", fill: "currentColor" })
|
|
3835
3886
|
}
|
|
3836
3887
|
),
|
|
3837
|
-
/* @__PURE__ */ (0,
|
|
3888
|
+
/* @__PURE__ */ (0, import_jsx_runtime54.jsx)(
|
|
3838
3889
|
"button",
|
|
3839
3890
|
{
|
|
3840
3891
|
type: "button",
|
|
@@ -3843,14 +3894,14 @@ function PlayerControls() {
|
|
|
3843
3894
|
disabled: !isReady || !hasNextTrack,
|
|
3844
3895
|
onClick: playNextTrack,
|
|
3845
3896
|
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",
|
|
3846
|
-
children: /* @__PURE__ */ (0,
|
|
3897
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(import_lucide_react20.SkipForward, { "aria-hidden": "true", className: "h-4 w-4" })
|
|
3847
3898
|
}
|
|
3848
3899
|
)
|
|
3849
3900
|
] }),
|
|
3850
|
-
/* @__PURE__ */ (0,
|
|
3851
|
-
volume === 0 ? /* @__PURE__ */ (0,
|
|
3852
|
-
/* @__PURE__ */ (0,
|
|
3853
|
-
/* @__PURE__ */ (0,
|
|
3901
|
+
/* @__PURE__ */ (0, import_jsx_runtime54.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: [
|
|
3902
|
+
volume === 0 ? /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(import_lucide_react20.VolumeX, { "aria-hidden": "true", className: "h-[0.7rem] w-[0.7rem] shrink-0" }) : /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(import_lucide_react20.Volume2, { "aria-hidden": "true", className: "h-[0.7rem] w-[0.7rem] shrink-0" }),
|
|
3903
|
+
/* @__PURE__ */ (0, import_jsx_runtime54.jsx)("span", { className: "sr-only", children: "Volume" }),
|
|
3904
|
+
/* @__PURE__ */ (0, import_jsx_runtime54.jsx)(
|
|
3854
3905
|
"input",
|
|
3855
3906
|
{
|
|
3856
3907
|
"aria-label": "Volume",
|
|
@@ -3872,7 +3923,7 @@ function PlayerControls() {
|
|
|
3872
3923
|
}
|
|
3873
3924
|
|
|
3874
3925
|
// src/genre-tree/PlayerPanel.tsx
|
|
3875
|
-
var
|
|
3926
|
+
var import_jsx_runtime55 = require("react/jsx-runtime");
|
|
3876
3927
|
var PANEL_ID = "player-panel";
|
|
3877
3928
|
var DEFAULT_EXTENDED_WIDTH = "calc(100vw - var(--layout-center-left) - var(--layout-gutter))";
|
|
3878
3929
|
function PlayerPanel({
|
|
@@ -3885,7 +3936,7 @@ function PlayerPanel({
|
|
|
3885
3936
|
renderSongLink
|
|
3886
3937
|
}) {
|
|
3887
3938
|
const { playerTrackObject, retryPlayback } = (0, import_player14.usePlayer)();
|
|
3888
|
-
const { toggleTrackListSidebar, isTrackListSidebarVisible } = (0,
|
|
3939
|
+
const { toggleTrackListSidebar, isTrackListSidebarVisible } = (0, import_genre_tree35.useTrackListSidebarVisibility)();
|
|
3889
3940
|
const [lastLoadedTrackTitle, setLastLoadedTrackTitle] = (0, import_react21.useState)("");
|
|
3890
3941
|
const loadedTrackTitle = playerTrackObject?.track.title;
|
|
3891
3942
|
(0, import_react21.useEffect)(() => {
|
|
@@ -3912,7 +3963,7 @@ function PlayerPanel({
|
|
|
3912
3963
|
onClick: () => setIsExtendRequested(true),
|
|
3913
3964
|
expanded: false
|
|
3914
3965
|
} : null;
|
|
3915
|
-
return /* @__PURE__ */ (0,
|
|
3966
|
+
return /* @__PURE__ */ (0, import_jsx_runtime55.jsxs)(
|
|
3916
3967
|
"div",
|
|
3917
3968
|
{
|
|
3918
3969
|
id: PANEL_ID,
|
|
@@ -3925,7 +3976,7 @@ function PlayerPanel({
|
|
|
3925
3976
|
),
|
|
3926
3977
|
style: isExtended ? { width: extendedWidth } : void 0,
|
|
3927
3978
|
children: [
|
|
3928
|
-
/* @__PURE__ */ (0,
|
|
3979
|
+
/* @__PURE__ */ (0, import_jsx_runtime55.jsx)(
|
|
3929
3980
|
import_ui25.PanelEdgeTab,
|
|
3930
3981
|
{
|
|
3931
3982
|
side: "right",
|
|
@@ -3935,7 +3986,7 @@ function PlayerPanel({
|
|
|
3935
3986
|
className: "absolute right-full top-1/2 -translate-y-1/2"
|
|
3936
3987
|
}
|
|
3937
3988
|
),
|
|
3938
|
-
/* @__PURE__ */ (0,
|
|
3989
|
+
/* @__PURE__ */ (0, import_jsx_runtime55.jsxs)(
|
|
3939
3990
|
"div",
|
|
3940
3991
|
{
|
|
3941
3992
|
className: (0, import_tailwind_merge.twMerge)(
|
|
@@ -3943,20 +3994,20 @@ function PlayerPanel({
|
|
|
3943
3994
|
isExtended ? "flex-row" : "flex-col"
|
|
3944
3995
|
),
|
|
3945
3996
|
children: [
|
|
3946
|
-
/* @__PURE__ */ (0,
|
|
3947
|
-
/* @__PURE__ */ (0,
|
|
3948
|
-
/* @__PURE__ */ (0,
|
|
3949
|
-
/* @__PURE__ */ (0,
|
|
3950
|
-
playerTrackObject?.loadError && /* @__PURE__ */ (0,
|
|
3997
|
+
/* @__PURE__ */ (0, import_jsx_runtime55.jsxs)("div", { className: "flex w-[var(--layout-right-w)] shrink-0 flex-col", children: [
|
|
3998
|
+
/* @__PURE__ */ (0, import_jsx_runtime55.jsx)("div", { className: "flex shrink-0 items-center justify-between gap-2 border-b border-zinc-800 p-2", children: /* @__PURE__ */ (0, import_jsx_runtime55.jsx)("span", { className: "min-w-0 truncate text-sm font-semibold", children: loadedTrackTitle || lastLoadedTrackTitle }) }),
|
|
3999
|
+
/* @__PURE__ */ (0, import_jsx_runtime55.jsxs)("div", { className: "relative w-full shrink-0", children: [
|
|
4000
|
+
/* @__PURE__ */ (0, import_jsx_runtime55.jsx)(import_player14.PlayerVideoSurface, { className: "aspect-video w-full bg-black" }),
|
|
4001
|
+
playerTrackObject?.loadError && /* @__PURE__ */ (0, import_jsx_runtime55.jsxs)("span", { className: "absolute bottom-2 left-2 right-2 text-xs text-red-400", children: [
|
|
3951
4002
|
playerTrackObject.loadError,
|
|
3952
|
-
/* @__PURE__ */ (0,
|
|
4003
|
+
/* @__PURE__ */ (0, import_jsx_runtime55.jsx)("button", { type: "button", className: "ml-2 underline", onClick: () => {
|
|
3953
4004
|
void retryPlayback();
|
|
3954
4005
|
}, children: "Retry" })
|
|
3955
4006
|
] })
|
|
3956
4007
|
] }),
|
|
3957
|
-
/* @__PURE__ */ (0,
|
|
4008
|
+
/* @__PURE__ */ (0, import_jsx_runtime55.jsx)(PlayerControls, {})
|
|
3958
4009
|
] }),
|
|
3959
|
-
/* @__PURE__ */ (0,
|
|
4010
|
+
/* @__PURE__ */ (0, import_jsx_runtime55.jsx)(
|
|
3960
4011
|
TrackListSidebar,
|
|
3961
4012
|
{
|
|
3962
4013
|
layout: "inline",
|
|
@@ -3982,33 +4033,33 @@ function PlayerPanel({
|
|
|
3982
4033
|
// src/genre-tree/Rating.tsx
|
|
3983
4034
|
var import_uuid = require("uuid");
|
|
3984
4035
|
var import_ai = require("react-icons/ai");
|
|
3985
|
-
var
|
|
3986
|
-
var
|
|
4036
|
+
var import_genre_tree36 = require("@behindthemusictree/app-kit/genre-tree");
|
|
4037
|
+
var import_jsx_runtime56 = require("react/jsx-runtime");
|
|
3987
4038
|
function Rating({ rating, handleChange }) {
|
|
3988
4039
|
const instanceId = (0, import_uuid.v4)();
|
|
3989
|
-
return /* @__PURE__ */ (0,
|
|
3990
|
-
/* @__PURE__ */ (0,
|
|
4040
|
+
return /* @__PURE__ */ (0, import_jsx_runtime56.jsx)("div", { className: "flex items-center", children: [...Array(6)].map((_, i) => /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)("div", { className: `relative ${i === 0 ? "mr-4" : "mr-1"}`, children: [
|
|
4041
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsx)(
|
|
3991
4042
|
"input",
|
|
3992
4043
|
{
|
|
3993
4044
|
id: `star-${instanceId}-${i}`,
|
|
3994
4045
|
className: "w-6 h-6 opacity-0",
|
|
3995
4046
|
type: "radio",
|
|
3996
4047
|
name: "rating",
|
|
3997
|
-
value: i === 0 ?
|
|
4048
|
+
value: i === 0 ? import_genre_tree36.FORM_RATING_NULL_VALUE : i,
|
|
3998
4049
|
checked: rating === (i === 0 ? null : i),
|
|
3999
4050
|
onChange: handleChange
|
|
4000
4051
|
}
|
|
4001
4052
|
),
|
|
4002
|
-
/* @__PURE__ */ (0,
|
|
4003
|
-
/* @__PURE__ */ (0,
|
|
4053
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsx)("label", { htmlFor: `star-${instanceId}-${i}`, className: "cursor-pointer", children: i === 0 ? /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)("div", { className: "flex", children: [
|
|
4054
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsx)(
|
|
4004
4055
|
import_ai.AiOutlineStar,
|
|
4005
4056
|
{
|
|
4006
|
-
className: `w-7 h-7 absolute top-0 left-0 ${rating ===
|
|
4057
|
+
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)]"}`
|
|
4007
4058
|
}
|
|
4008
4059
|
),
|
|
4009
|
-
/* @__PURE__ */ (0,
|
|
4060
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsx)("span", { className: "flex-grow w-8" }),
|
|
4010
4061
|
" "
|
|
4011
|
-
] }) : /* @__PURE__ */ (0,
|
|
4062
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(
|
|
4012
4063
|
import_ai.AiFillStar,
|
|
4013
4064
|
{
|
|
4014
4065
|
className: `w-7 h-7 absolute top-0 left-0 ${(rating ?? -1) >= i ? "text-[var(--color-accent-rating)]" : "text-[var(--color-text-muted)]"}`
|
|
@@ -4020,7 +4071,7 @@ function Rating({ rating, handleChange }) {
|
|
|
4020
4071
|
// src/genre-tree/EntityDetailPanel.tsx
|
|
4021
4072
|
var import_react22 = require("react");
|
|
4022
4073
|
var import_ui26 = require("@behindthemusictree/ui");
|
|
4023
|
-
var
|
|
4074
|
+
var import_jsx_runtime57 = require("react/jsx-runtime");
|
|
4024
4075
|
function EntityDetailPanel({
|
|
4025
4076
|
scope,
|
|
4026
4077
|
getBackendBaseUrl,
|
|
@@ -4032,6 +4083,7 @@ function EntityDetailPanel({
|
|
|
4032
4083
|
onArtistUuidChange,
|
|
4033
4084
|
renderArtistLink,
|
|
4034
4085
|
renderSongLink,
|
|
4086
|
+
renderPlaceLink,
|
|
4035
4087
|
collapsed,
|
|
4036
4088
|
edgeTab,
|
|
4037
4089
|
...navigation
|
|
@@ -4043,8 +4095,9 @@ function EntityDetailPanel({
|
|
|
4043
4095
|
getBackendBaseUrl,
|
|
4044
4096
|
getArtistBackendBaseUrl,
|
|
4045
4097
|
getShareUrl,
|
|
4046
|
-
|
|
4047
|
-
|
|
4098
|
+
renderPlaceLink,
|
|
4099
|
+
renderArtistLink: renderArtistLink ?? ((artist) => artist.isSpecialPurpose ? artist.name : /* @__PURE__ */ (0, import_jsx_runtime57.jsx)("button", { type: "button", onClick: () => onArtistUuidChange(artist.uuid), className: "hover:underline", children: artist.name })),
|
|
4100
|
+
renderSongLink: renderSongLink ?? ((song) => /* @__PURE__ */ (0, import_jsx_runtime57.jsx)("button", { type: "button", onClick: () => onSongUuidChange(song.uuid), className: "hover:underline", children: song.title })),
|
|
4048
4101
|
song: {
|
|
4049
4102
|
uuid: songUuid,
|
|
4050
4103
|
expanded: songUuid !== null && expandedSongUuid === songUuid,
|
|
@@ -4060,7 +4113,7 @@ function EntityDetailPanel({
|
|
|
4060
4113
|
...navigation
|
|
4061
4114
|
});
|
|
4062
4115
|
if (!panel) return null;
|
|
4063
|
-
return /* @__PURE__ */ (0,
|
|
4116
|
+
return /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(
|
|
4064
4117
|
import_ui26.DetailPanel,
|
|
4065
4118
|
{
|
|
4066
4119
|
side: "left",
|
|
@@ -4072,7 +4125,7 @@ function EntityDetailPanel({
|
|
|
4072
4125
|
onExpandedChange: panel.onExpandedChange,
|
|
4073
4126
|
aside: panel.extraContent,
|
|
4074
4127
|
edgeTab,
|
|
4075
|
-
children: panel.extraContent && !panel.expanded ? /* @__PURE__ */ (0,
|
|
4128
|
+
children: panel.extraContent && !panel.expanded ? /* @__PURE__ */ (0, import_jsx_runtime57.jsxs)(import_jsx_runtime57.Fragment, { children: [
|
|
4076
4129
|
panel.content,
|
|
4077
4130
|
panel.extraContent
|
|
4078
4131
|
] }) : panel.content
|