@behindthemusictree/app-kit-ui 33.1.0 → 33.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-2M4Q2IJU.js → chunk-FHGQGTCN.js} +512 -460
- package/dist/chunk-FHGQGTCN.js.map +1 -0
- package/dist/genre-tree/index.cjs +592 -535
- package/dist/genre-tree/index.cjs.map +1 -1
- package/dist/genre-tree/index.d.ts +70 -20
- package/dist/genre-tree/index.js +15 -3
- package/dist/index.cjs +590 -533
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +15 -3
- package/package.json +5 -5
- package/dist/chunk-2M4Q2IJU.js.map +0 -1
|
@@ -17,11 +17,6 @@ import {
|
|
|
17
17
|
GenreTreeViewSkeleton,
|
|
18
18
|
useGenreNodeRelations
|
|
19
19
|
} from "@behindthemusictree/genre-tree-view";
|
|
20
|
-
import {
|
|
21
|
-
useArtistSearch,
|
|
22
|
-
useSongSearch,
|
|
23
|
-
isSongSearchResultPlayable
|
|
24
|
-
} from "@behindthemusictree/app-kit/genre-tree";
|
|
25
20
|
import { useGenreTreeViewState, useArtist as useArtist2, useUpdateGenre as useUpdateGenre2, genreUpdateMutationKey } from "@behindthemusictree/app-kit/genre-tree";
|
|
26
21
|
import { usePopup as usePopup5 } from "@behindthemusictree/app-kit/popup";
|
|
27
22
|
|
|
@@ -465,11 +460,148 @@ function GenreTreeWheelHandoff({ skeleton, children, onRevealedChange }) {
|
|
|
465
460
|
}
|
|
466
461
|
|
|
467
462
|
// src/genre-tree/GenreSearch.tsx
|
|
468
|
-
import {
|
|
469
|
-
import {
|
|
470
|
-
import { Combobox } from "@behindthemusictree/ui";
|
|
463
|
+
import { ArrowLeft } from "lucide-react";
|
|
464
|
+
import { SEARCH_LEADING_BUTTON_CLASS } from "@behindthemusictree/ui";
|
|
471
465
|
import { useGenreSearch } from "@behindthemusictree/app-kit/genre-tree";
|
|
472
|
-
|
|
466
|
+
|
|
467
|
+
// src/genre-tree/search/SearchBox.tsx
|
|
468
|
+
import { useState as useState2 } from "react";
|
|
469
|
+
import { SearchCombobox } from "@behindthemusictree/ui";
|
|
470
|
+
import { jsx as jsx5 } from "react/jsx-runtime";
|
|
471
|
+
function SearchBox({
|
|
472
|
+
label,
|
|
473
|
+
placeholder,
|
|
474
|
+
value,
|
|
475
|
+
onValueChange,
|
|
476
|
+
groups,
|
|
477
|
+
onPicked,
|
|
478
|
+
onClear,
|
|
479
|
+
leading,
|
|
480
|
+
className: className2,
|
|
481
|
+
onFocus
|
|
482
|
+
}) {
|
|
483
|
+
const [open, setOpen] = useState2(false);
|
|
484
|
+
const loading = groups.some((group) => group.loading);
|
|
485
|
+
const status = groups.map((group) => group.status).filter(Boolean).join(". ");
|
|
486
|
+
const handlePick = (groupKey, itemKey) => {
|
|
487
|
+
setOpen(false);
|
|
488
|
+
groups.find((group) => group.key === groupKey)?.items.find((item) => item.key === itemKey)?.onSelect();
|
|
489
|
+
onPicked?.(groupKey, itemKey);
|
|
490
|
+
};
|
|
491
|
+
return /* @__PURE__ */ jsx5("div", { className: className2, onFocusCapture: onFocus, children: /* @__PURE__ */ jsx5(
|
|
492
|
+
SearchCombobox,
|
|
493
|
+
{
|
|
494
|
+
ariaLabel: label,
|
|
495
|
+
listLabel: `${label} results`,
|
|
496
|
+
value,
|
|
497
|
+
placeholder: placeholder ?? `${label}\u2026`,
|
|
498
|
+
groups: groups.map((group) => ({
|
|
499
|
+
key: group.key,
|
|
500
|
+
label: group.label,
|
|
501
|
+
options: group.items.map((item) => ({ key: item.key, content: item.content }))
|
|
502
|
+
})),
|
|
503
|
+
open,
|
|
504
|
+
onOpenChange: setOpen,
|
|
505
|
+
onValueChange,
|
|
506
|
+
onPick: handlePick,
|
|
507
|
+
status,
|
|
508
|
+
loading,
|
|
509
|
+
onClear,
|
|
510
|
+
leading,
|
|
511
|
+
inputClassName: "focus-visible:ring-0"
|
|
512
|
+
}
|
|
513
|
+
) });
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
// src/genre-tree/search/SearchGroup.ts
|
|
517
|
+
var SEARCH_FAILED_STATUS = "Search failed";
|
|
518
|
+
var searchStatus = (state, count, noun) => state.isError ? SEARCH_FAILED_STATUS : state.settled && count === 0 ? `No ${noun} found` : "";
|
|
519
|
+
|
|
520
|
+
// src/genre-tree/search/useArtistSearchGroup.tsx
|
|
521
|
+
import { useArtistSearch } from "@behindthemusictree/app-kit/genre-tree";
|
|
522
|
+
import { Fragment, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
523
|
+
function useArtistSearchGroup(getBaseUrl, text, onSelect, enabled = true) {
|
|
524
|
+
const search = useArtistSearch(getBaseUrl, enabled ? text : "");
|
|
525
|
+
if (!enabled) return void 0;
|
|
526
|
+
return {
|
|
527
|
+
key: "artists",
|
|
528
|
+
label: "Artists",
|
|
529
|
+
items: search.artists.map((artist) => ({
|
|
530
|
+
key: artist.uuid,
|
|
531
|
+
content: /* @__PURE__ */ jsxs2(Fragment, { children: [
|
|
532
|
+
/* @__PURE__ */ jsxs2("span", { className: "block truncate font-medium", children: [
|
|
533
|
+
artist.name,
|
|
534
|
+
artist.disambiguation && /* @__PURE__ */ jsxs2("span", { className: "font-normal text-[var(--color-neutral-500)]", children: [
|
|
535
|
+
" \xB7 ",
|
|
536
|
+
artist.disambiguation
|
|
537
|
+
] })
|
|
538
|
+
] }),
|
|
539
|
+
artist.matchedAlias && /* @__PURE__ */ jsxs2("span", { className: "block truncate text-xs text-[var(--color-neutral-500)]", children: [
|
|
540
|
+
"also known as ",
|
|
541
|
+
artist.matchedAlias
|
|
542
|
+
] })
|
|
543
|
+
] }),
|
|
544
|
+
onSelect: () => onSelect(artist)
|
|
545
|
+
})),
|
|
546
|
+
status: searchStatus(search, search.artists.length, "artists"),
|
|
547
|
+
loading: search.pending
|
|
548
|
+
};
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
// src/genre-tree/search/useSongSearchGroup.tsx
|
|
552
|
+
import {
|
|
553
|
+
isSongSearchResultPlayable,
|
|
554
|
+
useSongSearch
|
|
555
|
+
} from "@behindthemusictree/app-kit/genre-tree";
|
|
556
|
+
import { jsx as jsx6, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
557
|
+
function useSongSearchGroup(getBaseUrl, text, onSelect, enabled = true) {
|
|
558
|
+
const search = useSongSearch(getBaseUrl, enabled ? text : "");
|
|
559
|
+
if (!enabled) return void 0;
|
|
560
|
+
return {
|
|
561
|
+
key: "songs",
|
|
562
|
+
label: "Songs",
|
|
563
|
+
items: search.songs.map((song) => ({
|
|
564
|
+
key: song.uuid,
|
|
565
|
+
content: /* @__PURE__ */ jsxs3("span", { className: isSongSearchResultPlayable(song) ? void 0 : "opacity-60", children: [
|
|
566
|
+
/* @__PURE__ */ jsx6("span", { className: "block truncate font-medium", children: song.title }),
|
|
567
|
+
/* @__PURE__ */ jsx6("span", { className: "block truncate text-xs text-[var(--color-neutral-500)]", children: [song.artists.map((artist) => artist.name).join(", "), song.genre?.name ?? "No genre"].filter(Boolean).join(" \xB7 ") })
|
|
568
|
+
] }),
|
|
569
|
+
onSelect: () => onSelect(song)
|
|
570
|
+
})),
|
|
571
|
+
status: searchStatus(search, search.songs.length, "songs"),
|
|
572
|
+
loading: search.pending
|
|
573
|
+
};
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
// src/genre-tree/search/useGenreRemoteSearchGroup.tsx
|
|
577
|
+
import {
|
|
578
|
+
useGenreRemoteSearch
|
|
579
|
+
} from "@behindthemusictree/app-kit/genre-tree";
|
|
580
|
+
import { Fragment as Fragment2, jsx as jsx7, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
581
|
+
function useGenreRemoteSearchGroup(getBaseUrl, text, onSelect, { key = "genres", label = "Genres", filter, describe, ...options } = {}) {
|
|
582
|
+
const search = useGenreRemoteSearch(getBaseUrl, text, options);
|
|
583
|
+
const genres = filter ? search.genres.filter(filter) : search.genres;
|
|
584
|
+
return {
|
|
585
|
+
key,
|
|
586
|
+
label,
|
|
587
|
+
items: genres.map((genre) => ({
|
|
588
|
+
key: genre.uuid,
|
|
589
|
+
content: /* @__PURE__ */ jsxs4(Fragment2, { children: [
|
|
590
|
+
/* @__PURE__ */ jsxs4("span", { className: "block truncate font-medium", children: [
|
|
591
|
+
genre.name,
|
|
592
|
+
genre.isUmbrella && /* @__PURE__ */ jsx7("span", { className: "ml-2 text-xs font-normal italic text-[var(--color-text-muted)]", children: "umbrella" })
|
|
593
|
+
] }),
|
|
594
|
+
/* @__PURE__ */ jsx7("span", { className: "block truncate text-xs text-[var(--color-neutral-500)]", children: describe?.(genre) ?? `${genre.treeName} \xB7 ${genre.root.name}` })
|
|
595
|
+
] }),
|
|
596
|
+
onSelect: () => onSelect(genre)
|
|
597
|
+
})),
|
|
598
|
+
status: searchStatus(search, genres.length, "genres"),
|
|
599
|
+
loading: search.pending
|
|
600
|
+
};
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
// src/genre-tree/GenreSearch.tsx
|
|
604
|
+
import { Fragment as Fragment3, jsx as jsx8, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
473
605
|
function GenreSearch({
|
|
474
606
|
genrePlaylists,
|
|
475
607
|
onSelect,
|
|
@@ -478,7 +610,8 @@ function GenreSearch({
|
|
|
478
610
|
onPrevious,
|
|
479
611
|
placeholder,
|
|
480
612
|
onQueryChange,
|
|
481
|
-
extraGroups = []
|
|
613
|
+
extraGroups = [],
|
|
614
|
+
onFocus
|
|
482
615
|
}) {
|
|
483
616
|
const { query, setQuery, results, canClear, clear, select } = useGenreSearch({
|
|
484
617
|
genrePlaylists,
|
|
@@ -486,112 +619,49 @@ function GenreSearch({
|
|
|
486
619
|
selectedName,
|
|
487
620
|
onClear
|
|
488
621
|
});
|
|
489
|
-
const [open, setOpen] = useState2(false);
|
|
490
622
|
const active = query !== "" && query !== selectedName;
|
|
491
623
|
const hasExtras = extraGroups.length > 0;
|
|
492
624
|
const label = hasExtras ? "Search" : "Search a genre";
|
|
493
|
-
const loading = active && extraGroups.some((group) => group.loading);
|
|
494
|
-
const status = active ? extraGroups.map((group) => group.status).filter(Boolean).join(". ") : "";
|
|
495
625
|
const groups = [
|
|
496
626
|
{
|
|
497
627
|
key: "genres",
|
|
498
628
|
label: hasExtras ? "Genres" : void 0,
|
|
499
|
-
|
|
629
|
+
items: results.map((genrePlaylist) => ({
|
|
500
630
|
key: genrePlaylist.uuid,
|
|
501
|
-
content: /* @__PURE__ */
|
|
631
|
+
content: /* @__PURE__ */ jsxs5(Fragment3, { children: [
|
|
502
632
|
genrePlaylist.name,
|
|
503
|
-
genrePlaylist.isUmbrella && /* @__PURE__ */
|
|
504
|
-
] })
|
|
633
|
+
genrePlaylist.isUmbrella && /* @__PURE__ */ jsx8("span", { className: "ml-2 text-xs italic text-[var(--color-text-muted)]", children: "umbrella" })
|
|
634
|
+
] }),
|
|
635
|
+
onSelect: () => select(genrePlaylist)
|
|
505
636
|
}))
|
|
506
637
|
},
|
|
507
|
-
...extraGroups.map(
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
options: active ? group.items.map((item) => ({ key: item.key, content: item.content })) : []
|
|
511
|
-
}))
|
|
638
|
+
...extraGroups.map(
|
|
639
|
+
(group) => active ? group : { ...group, items: [], status: "", loading: false }
|
|
640
|
+
)
|
|
512
641
|
];
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
642
|
+
return /* @__PURE__ */ jsx8("div", { className: "genre-search w-[calc(var(--layout-detail-panel-w,25.5rem)-2*var(--layout-panel-inset,1rem))] shrink-0 max-md:w-full", children: /* @__PURE__ */ jsx8(
|
|
643
|
+
SearchBox,
|
|
644
|
+
{
|
|
645
|
+
label,
|
|
646
|
+
placeholder,
|
|
647
|
+
value: query,
|
|
648
|
+
onValueChange: (value) => {
|
|
649
|
+
setQuery(value);
|
|
650
|
+
onQueryChange?.(value);
|
|
651
|
+
},
|
|
652
|
+
groups,
|
|
653
|
+
onPicked: (groupKey) => {
|
|
654
|
+
if (groupKey !== "genres") setQuery("");
|
|
655
|
+
onQueryChange?.("");
|
|
656
|
+
},
|
|
657
|
+
onClear: canClear ? () => {
|
|
658
|
+
clear();
|
|
659
|
+
onQueryChange?.("");
|
|
660
|
+
} : void 0,
|
|
661
|
+
leading: onPrevious && /* @__PURE__ */ jsx8("button", { type: "button", "aria-label": "Previous", title: "Previous", className: SEARCH_LEADING_BUTTON_CLASS, onClick: onPrevious, children: /* @__PURE__ */ jsx8(ArrowLeft, { "aria-hidden": "true", className: "h-4 w-4" }) }),
|
|
662
|
+
onFocus
|
|
521
663
|
}
|
|
522
|
-
|
|
523
|
-
if (!item) return;
|
|
524
|
-
setQuery("");
|
|
525
|
-
onQueryChange?.("");
|
|
526
|
-
item.onSelect();
|
|
527
|
-
};
|
|
528
|
-
return /* @__PURE__ */ jsxs2("div", { className: "genre-search relative w-[calc(var(--layout-detail-panel-w,25.5rem)-2*var(--layout-panel-inset,1rem))] shrink-0 max-md:w-full", children: [
|
|
529
|
-
onPrevious && /* @__PURE__ */ jsx5(
|
|
530
|
-
"button",
|
|
531
|
-
{
|
|
532
|
-
type: "button",
|
|
533
|
-
"aria-label": "Previous",
|
|
534
|
-
title: "Previous",
|
|
535
|
-
className: "genre-search-previous absolute left-2 top-1/2 z-10 flex items-center justify-center p-1.5 [@media(pointer:coarse)]:min-h-[var(--layout-touch-target)] [@media(pointer:coarse)]:min-w-[var(--layout-touch-target)] text-[var(--color-text-muted)] rounded-full -translate-y-1/2 hover:bg-[var(--color-surface-muted)] hover:text-[var(--color-text)]",
|
|
536
|
-
onClick: onPrevious,
|
|
537
|
-
children: /* @__PURE__ */ jsx5(ArrowLeft, { "aria-hidden": "true", className: "w-4 h-4" })
|
|
538
|
-
}
|
|
539
|
-
),
|
|
540
|
-
/* @__PURE__ */ jsx5(
|
|
541
|
-
Combobox,
|
|
542
|
-
{
|
|
543
|
-
ariaLabel: label,
|
|
544
|
-
listLabel: `${label} results`,
|
|
545
|
-
value: query,
|
|
546
|
-
placeholder: placeholder ?? `${label}\u2026`,
|
|
547
|
-
groups,
|
|
548
|
-
open,
|
|
549
|
-
onOpenChange: setOpen,
|
|
550
|
-
onValueChange: (value) => {
|
|
551
|
-
setQuery(value);
|
|
552
|
-
onQueryChange?.(value);
|
|
553
|
-
},
|
|
554
|
-
onPick: handlePick,
|
|
555
|
-
status,
|
|
556
|
-
loading: loading ? "Searching\u2026" : void 0,
|
|
557
|
-
inputClassName: `h-[var(--layout-search-h,3rem)] ${onPrevious ? "pl-11" : "pl-6"} pr-20 text-base transition-[padding] duration-200 ease-out motion-reduce:transition-none bg-[var(--color-surface)] border-[var(--color-border)] rounded-full shadow-md focus-visible:ring-0`,
|
|
558
|
-
className: "genre-search-results z-40 rounded-xl shadow-md",
|
|
559
|
-
listClassName: "max-h-[min(20rem,50dvh)]",
|
|
560
|
-
optionClassName: "[@media(pointer:coarse)]:min-h-[var(--layout-touch-target)]"
|
|
561
|
-
}
|
|
562
|
-
),
|
|
563
|
-
/* @__PURE__ */ jsxs2("div", { className: "absolute right-3 top-1/2 flex items-center -translate-y-1/2", children: [
|
|
564
|
-
/* @__PURE__ */ jsxs2("span", { "data-loading": loading, className: "relative p-2 text-[var(--color-text-muted)] pointer-events-none", children: [
|
|
565
|
-
/* @__PURE__ */ jsx5(
|
|
566
|
-
Search,
|
|
567
|
-
{
|
|
568
|
-
"aria-hidden": "true",
|
|
569
|
-
className: `w-6 h-6 transition-opacity duration-200 motion-reduce:transition-none ${loading ? "opacity-0" : ""}`
|
|
570
|
-
}
|
|
571
|
-
),
|
|
572
|
-
/* @__PURE__ */ jsx5(
|
|
573
|
-
LoaderCircle,
|
|
574
|
-
{
|
|
575
|
-
"aria-hidden": "true",
|
|
576
|
-
className: `absolute inset-2 w-6 h-6 transition-opacity duration-200 motion-reduce:transition-none ${loading ? "opacity-100 delay-300 animate-spin motion-reduce:animate-none" : "opacity-0"}`
|
|
577
|
-
}
|
|
578
|
-
)
|
|
579
|
-
] }),
|
|
580
|
-
canClear && /* @__PURE__ */ jsx5(
|
|
581
|
-
"button",
|
|
582
|
-
{
|
|
583
|
-
type: "button",
|
|
584
|
-
"aria-label": "Clear search",
|
|
585
|
-
className: "flex items-center justify-center p-2 [@media(pointer:coarse)]:min-h-[var(--layout-touch-target)] [@media(pointer:coarse)]:min-w-[var(--layout-touch-target)] text-[var(--color-text-muted)] rounded-full hover:bg-[var(--color-surface-muted)] hover:text-[var(--color-text)]",
|
|
586
|
-
onClick: () => {
|
|
587
|
-
clear();
|
|
588
|
-
onQueryChange?.("");
|
|
589
|
-
},
|
|
590
|
-
children: /* @__PURE__ */ jsx5(X, { "aria-hidden": "true", className: "w-6 h-6" })
|
|
591
|
-
}
|
|
592
|
-
)
|
|
593
|
-
] })
|
|
594
|
-
] });
|
|
664
|
+
) });
|
|
595
665
|
}
|
|
596
666
|
|
|
597
667
|
// src/genre-tree/GenreInfoPanelBody.tsx
|
|
@@ -611,12 +681,12 @@ import { FaWhatsapp } from "react-icons/fa";
|
|
|
611
681
|
import { SiGmail } from "react-icons/si";
|
|
612
682
|
|
|
613
683
|
// src/genre-tree/ShareDestinationButton.tsx
|
|
614
|
-
import { Fragment as
|
|
684
|
+
import { Fragment as Fragment4, jsx as jsx9, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
615
685
|
var className = "group flex min-w-0 flex-1 flex-col items-center justify-center gap-1.5 rounded-xl px-2 py-2 text-xs text-[var(--color-text)] transition-colors hover:bg-[var(--color-surface-muted)] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-focus-ring)] disabled:cursor-not-allowed disabled:opacity-50";
|
|
616
686
|
function Contents({ icon, label }) {
|
|
617
|
-
return /* @__PURE__ */
|
|
618
|
-
/* @__PURE__ */
|
|
619
|
-
/* @__PURE__ */
|
|
687
|
+
return /* @__PURE__ */ jsxs6(Fragment4, { children: [
|
|
688
|
+
/* @__PURE__ */ jsx9("span", { className: "flex h-12 w-12 items-center justify-center rounded-full bg-[var(--color-surface-muted)] transition-colors group-hover:bg-[var(--color-border)]", children: icon }),
|
|
689
|
+
/* @__PURE__ */ jsx9("span", { className: "max-w-full truncate", children: label })
|
|
620
690
|
] });
|
|
621
691
|
}
|
|
622
692
|
function ShareDestinationButton({
|
|
@@ -628,29 +698,29 @@ function ShareDestinationButton({
|
|
|
628
698
|
ariaLabel
|
|
629
699
|
}) {
|
|
630
700
|
if (href) {
|
|
631
|
-
return /* @__PURE__ */
|
|
701
|
+
return /* @__PURE__ */ jsx9("a", { href, target: "_blank", rel: "noopener noreferrer", "aria-label": ariaLabel, className, children: /* @__PURE__ */ jsx9(Contents, { icon, label }) });
|
|
632
702
|
}
|
|
633
|
-
return /* @__PURE__ */
|
|
703
|
+
return /* @__PURE__ */ jsx9("button", { type: "button", onClick, disabled, "aria-label": ariaLabel, className, children: /* @__PURE__ */ jsx9(Contents, { icon, label }) });
|
|
634
704
|
}
|
|
635
705
|
|
|
636
706
|
// src/genre-tree/SharePreviewCard.tsx
|
|
637
707
|
import { Music, Music2, UserRound } from "lucide-react";
|
|
638
|
-
import { jsx as
|
|
708
|
+
import { jsx as jsx10, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
639
709
|
function SharePreviewCard({ target, url }) {
|
|
640
710
|
const Icon = { genre: Music2, artist: UserRound, song: Music }[target.kind];
|
|
641
711
|
const typeLabel = { genre: "Genre", artist: "Artist", song: "Song" }[target.kind];
|
|
642
|
-
return /* @__PURE__ */
|
|
643
|
-
/* @__PURE__ */
|
|
644
|
-
/* @__PURE__ */
|
|
645
|
-
/* @__PURE__ */
|
|
646
|
-
/* @__PURE__ */
|
|
647
|
-
/* @__PURE__ */
|
|
712
|
+
return /* @__PURE__ */ jsx10("div", { className: "rounded-3xl bg-[var(--color-surface-muted)] p-4", children: /* @__PURE__ */ jsxs7("div", { className: "flex min-h-32 overflow-hidden rounded-2xl bg-[var(--color-surface)] shadow-lg", children: [
|
|
713
|
+
/* @__PURE__ */ jsx10("div", { className: "flex w-28 shrink-0 items-center justify-center bg-[var(--color-primary)]/15 text-[var(--color-primary)]", children: /* @__PURE__ */ jsx10(Icon, { "aria-hidden": "true", className: "h-10 w-10" }) }),
|
|
714
|
+
/* @__PURE__ */ jsxs7("div", { className: "flex min-w-0 flex-1 flex-col justify-center gap-1 p-4", children: [
|
|
715
|
+
/* @__PURE__ */ jsx10("span", { className: "text-xs font-medium uppercase tracking-wide text-[var(--color-text-muted)]", children: typeLabel }),
|
|
716
|
+
/* @__PURE__ */ jsx10("span", { className: "truncate text-base font-semibold text-[var(--color-text)]", title: target.name, children: target.name }),
|
|
717
|
+
/* @__PURE__ */ jsx10("span", { className: "truncate text-sm text-[var(--color-primary)]", title: url, children: url })
|
|
648
718
|
] })
|
|
649
719
|
] }) });
|
|
650
720
|
}
|
|
651
721
|
|
|
652
722
|
// src/genre-tree/SharePopup.tsx
|
|
653
|
-
import { Fragment as
|
|
723
|
+
import { Fragment as Fragment5, jsx as jsx11, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
654
724
|
function resolveAbsoluteUrl(url) {
|
|
655
725
|
try {
|
|
656
726
|
const parsed = new URL(url, window.location.href);
|
|
@@ -725,8 +795,8 @@ function SharePopup({ target, url, onClose }) {
|
|
|
725
795
|
setShareError("Could not open the share options.");
|
|
726
796
|
}
|
|
727
797
|
};
|
|
728
|
-
return /* @__PURE__ */
|
|
729
|
-
/* @__PURE__ */
|
|
798
|
+
return /* @__PURE__ */ jsxs8(Fragment5, { children: [
|
|
799
|
+
/* @__PURE__ */ jsx11(
|
|
730
800
|
BasePopup_default,
|
|
731
801
|
{
|
|
732
802
|
title: "Share",
|
|
@@ -741,67 +811,67 @@ function SharePopup({ target, url, onClose }) {
|
|
|
741
811
|
titleTextClassName: "!text-xl !font-semibold !text-[var(--color-text)]",
|
|
742
812
|
closeButtonClassName: "!h-10 !w-10 !rounded-none !border-0 !bg-transparent !p-0 !text-[var(--color-text)] hover:!bg-transparent hover:!text-[var(--color-text)]",
|
|
743
813
|
contentClassName: "!rounded-none !bg-transparent !px-6 !pb-6 !pt-2",
|
|
744
|
-
children: /* @__PURE__ */
|
|
745
|
-
/* @__PURE__ */
|
|
746
|
-
/* @__PURE__ */
|
|
747
|
-
/* @__PURE__ */
|
|
814
|
+
children: /* @__PURE__ */ jsxs8("div", { className: "flex flex-col gap-4", children: [
|
|
815
|
+
/* @__PURE__ */ jsx11(SharePreviewCard, { target, url: absoluteUrl || url }),
|
|
816
|
+
/* @__PURE__ */ jsxs8("div", { className: "grid grid-cols-3 gap-1 rounded-3xl bg-[var(--color-surface)] p-3 sm:grid-cols-4", children: [
|
|
817
|
+
/* @__PURE__ */ jsx11(
|
|
748
818
|
ShareDestinationButton,
|
|
749
819
|
{
|
|
750
820
|
label: "Copy Link",
|
|
751
|
-
icon: /* @__PURE__ */
|
|
821
|
+
icon: /* @__PURE__ */ jsx11(Link2, { "aria-hidden": "true", className: "h-6 w-6" }),
|
|
752
822
|
onClick: () => void handleCopy(),
|
|
753
823
|
ariaLabel: "Copy link",
|
|
754
824
|
disabled: !absoluteUrl
|
|
755
825
|
}
|
|
756
826
|
),
|
|
757
|
-
/* @__PURE__ */
|
|
827
|
+
/* @__PURE__ */ jsx11(
|
|
758
828
|
ShareDestinationButton,
|
|
759
829
|
{
|
|
760
830
|
label: "WhatsApp",
|
|
761
|
-
icon: /* @__PURE__ */
|
|
831
|
+
icon: /* @__PURE__ */ jsx11(FaWhatsapp, { "aria-hidden": "true", className: "h-9 w-9 text-[#25D366]" }),
|
|
762
832
|
href: destinationUrls?.whatsapp,
|
|
763
833
|
ariaLabel: `Share ${target.name} via WhatsApp`,
|
|
764
834
|
disabled: !absoluteUrl
|
|
765
835
|
}
|
|
766
836
|
),
|
|
767
|
-
/* @__PURE__ */
|
|
837
|
+
/* @__PURE__ */ jsx11(
|
|
768
838
|
ShareDestinationButton,
|
|
769
839
|
{
|
|
770
840
|
label: "Gmail",
|
|
771
|
-
icon: /* @__PURE__ */
|
|
841
|
+
icon: /* @__PURE__ */ jsx11(SiGmail, { "aria-hidden": "true", className: "h-8 w-8 text-[#EA4335]" }),
|
|
772
842
|
href: destinationUrls?.gmail,
|
|
773
843
|
ariaLabel: `Email ${target.name} with Gmail`,
|
|
774
844
|
disabled: !absoluteUrl
|
|
775
845
|
}
|
|
776
846
|
),
|
|
777
|
-
canUseNativeShare && /* @__PURE__ */
|
|
847
|
+
canUseNativeShare && /* @__PURE__ */ jsx11(
|
|
778
848
|
ShareDestinationButton,
|
|
779
849
|
{
|
|
780
850
|
label: "More",
|
|
781
|
-
icon: /* @__PURE__ */
|
|
851
|
+
icon: /* @__PURE__ */ jsx11(Share2, { "aria-hidden": "true", className: "h-6 w-6" }),
|
|
782
852
|
onClick: () => void handleNativeShare(),
|
|
783
853
|
ariaLabel: "More sharing options",
|
|
784
854
|
disabled: !absoluteUrl
|
|
785
855
|
}
|
|
786
856
|
)
|
|
787
857
|
] }),
|
|
788
|
-
copyStatus === "failed" && /* @__PURE__ */
|
|
789
|
-
shareError && /* @__PURE__ */
|
|
858
|
+
copyStatus === "failed" && /* @__PURE__ */ jsx11("p", { role: "alert", className: "text-center text-sm text-[var(--color-red-500)]", children: "Could not copy the link." }),
|
|
859
|
+
shareError && /* @__PURE__ */ jsx11("p", { role: "alert", className: "text-center text-sm text-[var(--color-red-500)]", children: shareError })
|
|
790
860
|
] })
|
|
791
861
|
}
|
|
792
862
|
),
|
|
793
|
-
toastId > 0 && /* @__PURE__ */
|
|
863
|
+
toastId > 0 && /* @__PURE__ */ jsx11(Toast, { message: "Link copied", onClose: dismissToast }, toastId)
|
|
794
864
|
] });
|
|
795
865
|
}
|
|
796
866
|
|
|
797
867
|
// src/genre-tree/ShareActionButton.tsx
|
|
798
|
-
import { jsx as
|
|
868
|
+
import { jsx as jsx12, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
799
869
|
function ShareActionButton({ target, url }) {
|
|
800
870
|
const { showPopup, hidePopup } = usePopup3();
|
|
801
871
|
const openSharePopup = () => {
|
|
802
|
-
showPopup(/* @__PURE__ */
|
|
872
|
+
showPopup(/* @__PURE__ */ jsx12(SharePopup, { target, url, onClose: hidePopup }));
|
|
803
873
|
};
|
|
804
|
-
return /* @__PURE__ */
|
|
874
|
+
return /* @__PURE__ */ jsxs9(
|
|
805
875
|
"button",
|
|
806
876
|
{
|
|
807
877
|
type: "button",
|
|
@@ -810,7 +880,7 @@ function ShareActionButton({ target, url }) {
|
|
|
810
880
|
"aria-label": `Share ${target.name}`,
|
|
811
881
|
title: `Share ${target.name}`,
|
|
812
882
|
children: [
|
|
813
|
-
/* @__PURE__ */
|
|
883
|
+
/* @__PURE__ */ jsx12("span", { className: "flex items-center justify-center w-10 h-10 rounded-full group-focus-visible:ring-2 group-focus-visible:ring-[var(--color-focus-ring)] bg-[var(--color-surface-muted)] transition-colors group-hover:bg-[var(--color-border)]", children: /* @__PURE__ */ jsx12(Share22, { "aria-hidden": "true", className: "w-5 h-5" }) }),
|
|
814
884
|
"Share"
|
|
815
885
|
]
|
|
816
886
|
}
|
|
@@ -818,7 +888,7 @@ function ShareActionButton({ target, url }) {
|
|
|
818
888
|
}
|
|
819
889
|
|
|
820
890
|
// src/genre-tree/GenreActionBand.tsx
|
|
821
|
-
import { jsx as
|
|
891
|
+
import { jsx as jsx13, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
822
892
|
function GenreActionBand({
|
|
823
893
|
node,
|
|
824
894
|
onPlayPause,
|
|
@@ -840,7 +910,7 @@ function GenreActionBand({
|
|
|
840
910
|
items.push({
|
|
841
911
|
key: "play-pause",
|
|
842
912
|
label: isPlaying ? "Pause" : "Play",
|
|
843
|
-
icon: isPlaying ? /* @__PURE__ */
|
|
913
|
+
icon: isPlaying ? /* @__PURE__ */ jsx13(Pause, { "aria-hidden": "true", className: "w-5 h-5" }) : /* @__PURE__ */ jsx13(Play, { "aria-hidden": "true", className: "w-5 h-5" }),
|
|
844
914
|
onClick: onPlayPause
|
|
845
915
|
});
|
|
846
916
|
}
|
|
@@ -848,24 +918,24 @@ function GenreActionBand({
|
|
|
848
918
|
items.push({
|
|
849
919
|
key: "zoom-in",
|
|
850
920
|
label: "Focus",
|
|
851
|
-
icon: /* @__PURE__ */
|
|
921
|
+
icon: /* @__PURE__ */ jsx13(ZoomIn, { "aria-hidden": "true", className: "w-5 h-5" }),
|
|
852
922
|
onClick: onZoomIn
|
|
853
923
|
});
|
|
854
924
|
}
|
|
855
925
|
if (onAddChild) {
|
|
856
|
-
adminItems.push({ key: "add-child", label: "Add", icon: /* @__PURE__ */
|
|
926
|
+
adminItems.push({ key: "add-child", label: "Add", icon: /* @__PURE__ */ jsx13(Plus, { "aria-hidden": "true", className: "w-5 h-5" }), onClick: onAddChild });
|
|
857
927
|
}
|
|
858
928
|
if (onRename) {
|
|
859
|
-
adminItems.push({ key: "rename", label: "Rename", icon: /* @__PURE__ */
|
|
929
|
+
adminItems.push({ key: "rename", label: "Rename", icon: /* @__PURE__ */ jsx13(Pencil, { "aria-hidden": "true", className: "w-5 h-5" }), onClick: onRename });
|
|
860
930
|
}
|
|
861
931
|
if (onChangeParent) {
|
|
862
|
-
adminItems.push({ key: "change-parent", label: "Parent", icon: /* @__PURE__ */
|
|
932
|
+
adminItems.push({ key: "change-parent", label: "Parent", icon: /* @__PURE__ */ jsx13(MoveUpRight, { "aria-hidden": "true", className: "w-5 h-5" }), onClick: onChangeParent });
|
|
863
933
|
}
|
|
864
934
|
if (onToggleSide) {
|
|
865
935
|
adminItems.push({
|
|
866
936
|
key: "toggle-side",
|
|
867
937
|
label: side === "pop" ? "Make core" : "Make pop",
|
|
868
|
-
icon: /* @__PURE__ */
|
|
938
|
+
icon: /* @__PURE__ */ jsx13(ArrowLeftRight, { "aria-hidden": "true", className: "w-5 h-5" }),
|
|
869
939
|
onClick: onToggleSide,
|
|
870
940
|
disabled: !!toggleSideDisabledReason,
|
|
871
941
|
title: toggleSideDisabledReason
|
|
@@ -881,7 +951,7 @@ function GenreActionBand({
|
|
|
881
951
|
});
|
|
882
952
|
}
|
|
883
953
|
if (items.length === 0 && (!shareTarget || !shareUrl) && adminItems.length === 0) return null;
|
|
884
|
-
const renderItems = (list) => list.map((item) => /* @__PURE__ */
|
|
954
|
+
const renderItems = (list) => list.map((item) => /* @__PURE__ */ jsxs10(
|
|
885
955
|
"button",
|
|
886
956
|
{
|
|
887
957
|
type: "button",
|
|
@@ -890,25 +960,25 @@ function GenreActionBand({
|
|
|
890
960
|
onClick: item.onClick,
|
|
891
961
|
className: "group flex flex-col items-center gap-1 w-16 text-xs text-center text-[var(--color-text)] focus-visible:outline-none disabled:opacity-50",
|
|
892
962
|
children: [
|
|
893
|
-
/* @__PURE__ */
|
|
963
|
+
/* @__PURE__ */ jsx13("span", { className: "flex items-center justify-center w-10 h-10 rounded-full group-focus-visible:ring-2 group-focus-visible:ring-[var(--color-focus-ring)] bg-[var(--color-surface-muted)] transition-colors group-hover:bg-[var(--color-border)] group-disabled:group-hover:bg-[var(--color-surface-muted)]", children: item.icon }),
|
|
894
964
|
item.label
|
|
895
965
|
]
|
|
896
966
|
},
|
|
897
967
|
item.key
|
|
898
968
|
));
|
|
899
|
-
return /* @__PURE__ */
|
|
900
|
-
(items.length > 0 || shareTarget && shareUrl) && /* @__PURE__ */
|
|
969
|
+
return /* @__PURE__ */ jsxs10("div", { className: "genre-action-band border-b border-[var(--color-border)]", children: [
|
|
970
|
+
(items.length > 0 || shareTarget && shareUrl) && /* @__PURE__ */ jsxs10("div", { className: "flex flex-wrap gap-1 px-3.5 py-3", children: [
|
|
901
971
|
renderItems(items),
|
|
902
|
-
shareTarget && shareUrl && /* @__PURE__ */
|
|
972
|
+
shareTarget && shareUrl && /* @__PURE__ */ jsx13(ShareActionButton, { target: shareTarget, url: shareUrl })
|
|
903
973
|
] }),
|
|
904
|
-
adminItems.length > 0 && /* @__PURE__ */
|
|
974
|
+
adminItems.length > 0 && /* @__PURE__ */ jsxs10(
|
|
905
975
|
"section",
|
|
906
976
|
{
|
|
907
977
|
"aria-label": "Admin actions",
|
|
908
978
|
className: `px-3.5 py-3 ${items.length > 0 ? "border-t border-[var(--color-border)]" : ""}`,
|
|
909
979
|
children: [
|
|
910
|
-
/* @__PURE__ */
|
|
911
|
-
/* @__PURE__ */
|
|
980
|
+
/* @__PURE__ */ jsx13("h3", { className: "mb-2 text-xs font-semibold uppercase tracking-wide text-[var(--color-text-muted)]", children: "Admin" }),
|
|
981
|
+
/* @__PURE__ */ jsx13("div", { className: "flex flex-wrap gap-1", children: renderItems(adminItems) })
|
|
912
982
|
]
|
|
913
983
|
}
|
|
914
984
|
)
|
|
@@ -921,7 +991,7 @@ import { useFetchGenreOverview } from "@behindthemusictree/app-kit/genre-tree";
|
|
|
921
991
|
|
|
922
992
|
// src/genre-tree/ClampedText.tsx
|
|
923
993
|
import { useLayoutEffect, useRef as useRef2, useState as useState4 } from "react";
|
|
924
|
-
import { Fragment as
|
|
994
|
+
import { Fragment as Fragment6, jsx as jsx14, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
925
995
|
function ClampedText({ children, className: className2 = "" }) {
|
|
926
996
|
const ref = useRef2(null);
|
|
927
997
|
const [expanded, setExpanded] = useState4(false);
|
|
@@ -931,9 +1001,9 @@ function ClampedText({ children, className: className2 = "" }) {
|
|
|
931
1001
|
if (!element || expanded) return;
|
|
932
1002
|
setOverflows(element.scrollHeight > element.clientHeight);
|
|
933
1003
|
}, [children, expanded]);
|
|
934
|
-
return /* @__PURE__ */
|
|
935
|
-
/* @__PURE__ */
|
|
936
|
-
(overflows || expanded) && /* @__PURE__ */
|
|
1004
|
+
return /* @__PURE__ */ jsxs11(Fragment6, { children: [
|
|
1005
|
+
/* @__PURE__ */ jsx14("p", { ref, className: `${className2} ${expanded ? "" : "line-clamp-3"}`, children }),
|
|
1006
|
+
(overflows || expanded) && /* @__PURE__ */ jsx14(
|
|
937
1007
|
"button",
|
|
938
1008
|
{
|
|
939
1009
|
type: "button",
|
|
@@ -967,15 +1037,15 @@ import { useTrackList as useTrackList2 } from "@behindthemusictree/app-kit/genre
|
|
|
967
1037
|
|
|
968
1038
|
// src/genre-tree/MusicBrainzRecordingLink.tsx
|
|
969
1039
|
import { musicBrainzRecordingUrl } from "@behindthemusictree/app-kit/genre-tree";
|
|
970
|
-
import { Fragment as
|
|
1040
|
+
import { Fragment as Fragment7, jsx as jsx15 } from "react/jsx-runtime";
|
|
971
1041
|
function MusicBrainzRecordingLink({
|
|
972
1042
|
song,
|
|
973
1043
|
children,
|
|
974
1044
|
className: className2 = ""
|
|
975
1045
|
}) {
|
|
976
1046
|
const url = musicBrainzRecordingUrl(song);
|
|
977
|
-
if (!url) return /* @__PURE__ */
|
|
978
|
-
return /* @__PURE__ */
|
|
1047
|
+
if (!url) return /* @__PURE__ */ jsx15(Fragment7, { children });
|
|
1048
|
+
return /* @__PURE__ */ jsx15(
|
|
979
1049
|
"a",
|
|
980
1050
|
{
|
|
981
1051
|
href: url,
|
|
@@ -992,7 +1062,7 @@ function MusicBrainzRecordingLink({
|
|
|
992
1062
|
// src/genre-tree/GenrePlaylistTracks.tsx
|
|
993
1063
|
import { ArtistNames } from "@behindthemusictree/app-kit/genre-tree";
|
|
994
1064
|
import { capitalize, useTrackNoun } from "@behindthemusictree/app-kit/track-noun";
|
|
995
|
-
import { jsx as
|
|
1065
|
+
import { jsx as jsx16, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
996
1066
|
var CATALOGUE_PAGE_SIZE = 100;
|
|
997
1067
|
var SongPageSchema = PaginatedResponseSchema(SongDetailedSchema).extend({
|
|
998
1068
|
overallTotal: z.number().nullable(),
|
|
@@ -1065,35 +1135,35 @@ function GenrePlaylistTracks({
|
|
|
1065
1135
|
const started = artist ? playNewTrackListFromArtist(artist, scope, { startSongUuid, ordering: "title", genreUuid }) : playNewTrackListFromGenrePlaylist(genrePlaylist, scope, { startSongUuid });
|
|
1066
1136
|
started.catch((error) => {
|
|
1067
1137
|
console.error("Failed to play genre playlist:", error);
|
|
1068
|
-
showPopup(/* @__PURE__ */
|
|
1138
|
+
showPopup(/* @__PURE__ */ jsx16(InternalErrorPopup, { errorCode: ErrorCode3.CLIENT_UNKNOWN }));
|
|
1069
1139
|
});
|
|
1070
1140
|
};
|
|
1071
|
-
return /* @__PURE__ */
|
|
1141
|
+
return /* @__PURE__ */ jsx16(PanelSection, { title: `${capitalize(trackNoun.plural)}${total !== void 0 ? ` (${total})` : ""}`, children: /* @__PURE__ */ jsxs12("div", { children: [
|
|
1072
1142
|
renderTracksToolbar?.(),
|
|
1073
|
-
isPending ? /* @__PURE__ */
|
|
1143
|
+
isPending ? /* @__PURE__ */ jsx16(Skeleton, { className: "h-4 w-3/4", "aria-busy": "true" }) : isError && tracks.length === 0 ? /* @__PURE__ */ jsxs12("p", { role: "alert", children: [
|
|
1074
1144
|
"Couldn't load ",
|
|
1075
1145
|
trackNoun.plural,
|
|
1076
1146
|
".",
|
|
1077
1147
|
" ",
|
|
1078
|
-
/* @__PURE__ */
|
|
1079
|
-
] }) : tracks.length === 0 ? /* @__PURE__ */
|
|
1148
|
+
/* @__PURE__ */ jsx16("button", { type: "button", className: "underline", onClick: () => void refetch(), children: "Retry" })
|
|
1149
|
+
] }) : tracks.length === 0 ? /* @__PURE__ */ jsx16("p", { children: "\u2014" }) : /* @__PURE__ */ jsxs12("ul", { className: "mt-1 max-h-64 overflow-y-auto text-[0.8125rem] leading-[1.45] [container-type:inline-size]", "aria-label": `${genrePlaylist.name} ${trackNoun.plural}`, children: [
|
|
1080
1150
|
tracks.map((track, index) => {
|
|
1081
1151
|
const label = track.artists?.length ? `${track.title} \u2014 ${track.artists.map((artist2) => artist2.name).join(", ")}` : track.title;
|
|
1082
1152
|
const isCurrent = playerTrackObject?.track.id === track.uuid;
|
|
1083
1153
|
const isPlaying = isCurrent && playState === PlayStates.PLAYING;
|
|
1084
|
-
const text = /* @__PURE__ */
|
|
1085
|
-
/* @__PURE__ */
|
|
1086
|
-
track.artists?.length ? /* @__PURE__ */
|
|
1087
|
-
/* @__PURE__ */
|
|
1088
|
-
track.album && /* @__PURE__ */
|
|
1154
|
+
const text = /* @__PURE__ */ jsxs12("span", { className: TEXT_CELL, children: [
|
|
1155
|
+
/* @__PURE__ */ jsx16("span", { className: TITLE_CELL, children: renderSongLink ? renderSongLink(track) : isSong(track) ? /* @__PURE__ */ jsx16(MusicBrainzRecordingLink, { song: track, className: "hover:underline focus-visible:underline", children: track.title }) : track.title }),
|
|
1156
|
+
track.artists?.length ? /* @__PURE__ */ jsx16("span", { className: SEPARATOR, children: " \u2014 " }) : null,
|
|
1157
|
+
/* @__PURE__ */ jsx16("span", { className: COLUMN_CELL, children: track.artists?.length ? /* @__PURE__ */ jsx16(ArtistNames, { artists: track.artists, renderArtistLink }) : null }),
|
|
1158
|
+
track.album && /* @__PURE__ */ jsx16("span", { className: ALBUM_CELL, children: track.album.name })
|
|
1089
1159
|
] });
|
|
1090
1160
|
const leading = renderSongLeading?.(track, index);
|
|
1091
1161
|
const actions = renderSongActions?.(track);
|
|
1092
1162
|
const isUnplayable = isSong(track) && songUnplayableReason(track) !== null;
|
|
1093
1163
|
if (isUnplayable) {
|
|
1094
|
-
return /* @__PURE__ */
|
|
1164
|
+
return /* @__PURE__ */ jsxs12("li", { className: "flex min-h-8 items-center gap-1 px-1 opacity-50", children: [
|
|
1095
1165
|
leading,
|
|
1096
|
-
/* @__PURE__ */
|
|
1166
|
+
/* @__PURE__ */ jsx16(
|
|
1097
1167
|
"button",
|
|
1098
1168
|
{
|
|
1099
1169
|
type: "button",
|
|
@@ -1101,27 +1171,27 @@ function GenrePlaylistTracks({
|
|
|
1101
1171
|
"aria-disabled": "true",
|
|
1102
1172
|
"aria-label": label,
|
|
1103
1173
|
className: "flex h-6 w-6 shrink-0 items-center justify-center rounded-full opacity-0 cursor-not-allowed",
|
|
1104
|
-
children: /* @__PURE__ */
|
|
1174
|
+
children: /* @__PURE__ */ jsx16(FaPlay, { size: 10 })
|
|
1105
1175
|
}
|
|
1106
1176
|
),
|
|
1107
1177
|
text,
|
|
1108
1178
|
actions
|
|
1109
1179
|
] }, track.uuid);
|
|
1110
1180
|
}
|
|
1111
|
-
return /* @__PURE__ */
|
|
1181
|
+
return /* @__PURE__ */ jsxs12(
|
|
1112
1182
|
"li",
|
|
1113
1183
|
{
|
|
1114
1184
|
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)]" : ""}`,
|
|
1115
1185
|
children: [
|
|
1116
1186
|
leading,
|
|
1117
|
-
/* @__PURE__ */
|
|
1187
|
+
/* @__PURE__ */ jsx16(
|
|
1118
1188
|
"button",
|
|
1119
1189
|
{
|
|
1120
1190
|
type: "button",
|
|
1121
1191
|
"aria-label": `${isPlaying ? "Pause" : "Play"} ${label}`,
|
|
1122
1192
|
className: `flex h-6 w-6 shrink-0 items-center justify-center rounded-full cursor-pointer group-hover:opacity-100 focus-visible:opacity-100 ${isCurrent && playState !== PlayStates.STOPPED ? "opacity-100" : "opacity-0 [@media(pointer:coarse)]:opacity-100"}`,
|
|
1123
1193
|
onClick: () => isCurrent ? handlePlayPauseAction() : play(track.uuid),
|
|
1124
|
-
children: isCurrent && playState === PlayStates.LOADING ? /* @__PURE__ */
|
|
1194
|
+
children: isCurrent && playState === PlayStates.LOADING ? /* @__PURE__ */ jsx16(RingLoader, { size: 10 }) : isPlaying ? /* @__PURE__ */ jsx16(FaPause, { size: 10 }) : /* @__PURE__ */ jsx16(FaPlay, { size: 10 })
|
|
1125
1195
|
}
|
|
1126
1196
|
),
|
|
1127
1197
|
text,
|
|
@@ -1131,7 +1201,7 @@ function GenrePlaylistTracks({
|
|
|
1131
1201
|
track.uuid
|
|
1132
1202
|
);
|
|
1133
1203
|
}),
|
|
1134
|
-
hasNextPage && /* @__PURE__ */
|
|
1204
|
+
hasNextPage && /* @__PURE__ */ jsx16("li", { ref: setSentinel, "aria-hidden": "true", className: "h-4" })
|
|
1135
1205
|
] })
|
|
1136
1206
|
] }) });
|
|
1137
1207
|
}
|
|
@@ -1139,7 +1209,7 @@ function GenrePlaylistTracks({
|
|
|
1139
1209
|
// src/genre-tree/GenreDetailExtras.tsx
|
|
1140
1210
|
import { useTrackNoun as useTrackNoun2 } from "@behindthemusictree/app-kit/track-noun";
|
|
1141
1211
|
import { SiWikidata, SiWikipedia } from "react-icons/si";
|
|
1142
|
-
import { Fragment as
|
|
1212
|
+
import { Fragment as Fragment8, jsx as jsx17, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
1143
1213
|
function GenreDetailExtras({
|
|
1144
1214
|
genreUuid,
|
|
1145
1215
|
genrePlaylist,
|
|
@@ -1163,17 +1233,17 @@ function GenreDetailExtras({
|
|
|
1163
1233
|
criteriaOverviewSchema
|
|
1164
1234
|
);
|
|
1165
1235
|
if (isPending) {
|
|
1166
|
-
return /* @__PURE__ */
|
|
1167
|
-
/* @__PURE__ */
|
|
1236
|
+
return /* @__PURE__ */ jsxs13(Fragment8, { children: [
|
|
1237
|
+
/* @__PURE__ */ jsx17(PanelSection2, { title: "Summary", children: /* @__PURE__ */ jsx17("div", { "aria-busy": "true", "data-testid": "genre-detail-extras-skeleton", children: /* @__PURE__ */ jsx17(Skeleton2, { className: "h-4 w-3/4" }) }) }),
|
|
1168
1238
|
family
|
|
1169
1239
|
] });
|
|
1170
1240
|
}
|
|
1171
|
-
if (!overview) return /* @__PURE__ */
|
|
1241
|
+
if (!overview) return /* @__PURE__ */ jsx17(Fragment8, { children: family });
|
|
1172
1242
|
const { summary, summarySourceUrl, essentialSongs } = overview;
|
|
1173
1243
|
const wikidataUrl = wikidataId ? `https://www.wikidata.org/wiki/${encodeURIComponent(wikidataId)}` : null;
|
|
1174
|
-
return /* @__PURE__ */
|
|
1175
|
-
(summarySourceUrl || wikidataUrl) && /* @__PURE__ */
|
|
1176
|
-
summarySourceUrl && /* @__PURE__ */
|
|
1244
|
+
return /* @__PURE__ */ jsxs13(Fragment8, { children: [
|
|
1245
|
+
(summarySourceUrl || wikidataUrl) && /* @__PURE__ */ jsx17(PanelSection2, { title: "Links", children: /* @__PURE__ */ jsxs13("div", { className: "flex flex-wrap gap-x-3 gap-y-1 text-xs text-[var(--color-text)]", children: [
|
|
1246
|
+
summarySourceUrl && /* @__PURE__ */ jsxs13(
|
|
1177
1247
|
"a",
|
|
1178
1248
|
{
|
|
1179
1249
|
href: summarySourceUrl,
|
|
@@ -1181,12 +1251,12 @@ function GenreDetailExtras({
|
|
|
1181
1251
|
rel: "noopener noreferrer",
|
|
1182
1252
|
className: "inline-flex items-center gap-1.5 text-[var(--color-text-muted)] hover:text-[var(--color-text)]",
|
|
1183
1253
|
children: [
|
|
1184
|
-
/* @__PURE__ */
|
|
1254
|
+
/* @__PURE__ */ jsx17(SiWikipedia, { "aria-hidden": "true", className: "h-3.5 w-3.5" }),
|
|
1185
1255
|
"Wikipedia"
|
|
1186
1256
|
]
|
|
1187
1257
|
}
|
|
1188
1258
|
),
|
|
1189
|
-
wikidataUrl && /* @__PURE__ */
|
|
1259
|
+
wikidataUrl && /* @__PURE__ */ jsxs13(
|
|
1190
1260
|
"a",
|
|
1191
1261
|
{
|
|
1192
1262
|
href: wikidataUrl,
|
|
@@ -1194,17 +1264,17 @@ function GenreDetailExtras({
|
|
|
1194
1264
|
rel: "noopener noreferrer",
|
|
1195
1265
|
className: "inline-flex items-center gap-1.5 text-[var(--color-text-muted)] hover:text-[var(--color-text)]",
|
|
1196
1266
|
children: [
|
|
1197
|
-
/* @__PURE__ */
|
|
1267
|
+
/* @__PURE__ */ jsx17(SiWikidata, { "aria-hidden": "true", className: "h-3.5 w-3.5" }),
|
|
1198
1268
|
"Wikidata"
|
|
1199
1269
|
]
|
|
1200
1270
|
}
|
|
1201
1271
|
)
|
|
1202
1272
|
] }) }),
|
|
1203
|
-
/* @__PURE__ */
|
|
1273
|
+
/* @__PURE__ */ jsx17(PanelSection2, { title: "Summary", children: renderSummary ? renderSummary(overview) : /* @__PURE__ */ jsx17(ClampedText, { className: "text-[0.8125rem] leading-[1.45] text-[var(--color-text)]", children: summary ?? "\u2014" }, genreUuid) }),
|
|
1204
1274
|
family,
|
|
1205
1275
|
renderGenreDetailExtras?.(overview),
|
|
1206
|
-
(renderEssentialTracks || essentialSongs) && /* @__PURE__ */
|
|
1207
|
-
/* @__PURE__ */
|
|
1276
|
+
(renderEssentialTracks || essentialSongs) && /* @__PURE__ */ jsx17(PanelSection2, { title: `Essential ${trackNoun.plural}`, children: renderEssentialTracks ? renderEssentialTracks(overview) : essentialSongs && essentialSongs.length > 0 ? /* @__PURE__ */ jsx17("ul", { className: "text-[0.8125rem] leading-[1.45] text-[var(--color-text)]", children: essentialSongs.map((track) => /* @__PURE__ */ jsx17("li", { className: "py-1", children: track.title }, track.uuid)) }) : /* @__PURE__ */ jsx17("p", { className: "text-[0.8125rem] leading-[1.45] text-[var(--color-text)]", children: "\u2014" }) }),
|
|
1277
|
+
/* @__PURE__ */ jsx17(
|
|
1208
1278
|
GenrePlaylistTracks,
|
|
1209
1279
|
{
|
|
1210
1280
|
genreUuid,
|
|
@@ -1220,7 +1290,7 @@ function GenreDetailExtras({
|
|
|
1220
1290
|
}
|
|
1221
1291
|
|
|
1222
1292
|
// src/genre-tree/GenreInfoPanelBody.tsx
|
|
1223
|
-
import { Fragment as
|
|
1293
|
+
import { Fragment as Fragment9, jsx as jsx18, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
1224
1294
|
import { createElement } from "react";
|
|
1225
1295
|
function GenreNodeActionBand({ genrePlaylist, playback, ...bandProps }) {
|
|
1226
1296
|
const { isPlaying, setIsPlaying } = usePlayer5();
|
|
@@ -1234,7 +1304,7 @@ function GenreNodeActionBand({ genrePlaylist, playback, ...bandProps }) {
|
|
|
1234
1304
|
console.error("Failed to load genre playlist tracks:", error);
|
|
1235
1305
|
});
|
|
1236
1306
|
};
|
|
1237
|
-
return /* @__PURE__ */
|
|
1307
|
+
return /* @__PURE__ */ jsx18(
|
|
1238
1308
|
GenreActionBand,
|
|
1239
1309
|
{
|
|
1240
1310
|
...bandProps,
|
|
@@ -1255,9 +1325,9 @@ function GenreInfoPanelBody({
|
|
|
1255
1325
|
band,
|
|
1256
1326
|
extras
|
|
1257
1327
|
}) {
|
|
1258
|
-
return /* @__PURE__ */
|
|
1328
|
+
return /* @__PURE__ */ jsxs14(Fragment9, { children: [
|
|
1259
1329
|
toolbar,
|
|
1260
|
-
/* @__PURE__ */
|
|
1330
|
+
/* @__PURE__ */ jsx18(GenreNodeActionBand, { ...band, genrePlaylist, playback }),
|
|
1261
1331
|
/* @__PURE__ */ createElement(
|
|
1262
1332
|
GenreDetailExtras,
|
|
1263
1333
|
{
|
|
@@ -1280,7 +1350,7 @@ import {
|
|
|
1280
1350
|
getReparentCandidates,
|
|
1281
1351
|
useUpdateGenre
|
|
1282
1352
|
} from "@behindthemusictree/app-kit/genre-tree";
|
|
1283
|
-
import { jsx as
|
|
1353
|
+
import { jsx as jsx19, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
1284
1354
|
function ChangeParentPopup({
|
|
1285
1355
|
genrePlaylist,
|
|
1286
1356
|
genrePlaylists,
|
|
@@ -1315,12 +1385,12 @@ function ChangeParentPopup({
|
|
|
1315
1385
|
window.addEventListener("keydown", handleKeyDown);
|
|
1316
1386
|
return () => window.removeEventListener("keydown", handleKeyDown);
|
|
1317
1387
|
}, [onClose]);
|
|
1318
|
-
return /* @__PURE__ */
|
|
1319
|
-
/* @__PURE__ */
|
|
1388
|
+
return /* @__PURE__ */ jsxs15(BasePopup_default, { title: `Change parent of ${genrePlaylist.name}`, onClose, showCancelButton: true, fitContent: true, children: [
|
|
1389
|
+
/* @__PURE__ */ jsxs15("p", { className: "mb-3 text-sm text-[var(--color-text-muted)]", children: [
|
|
1320
1390
|
"Current parent: ",
|
|
1321
1391
|
genrePlaylist.parent?.name ?? "none"
|
|
1322
1392
|
] }),
|
|
1323
|
-
/* @__PURE__ */
|
|
1393
|
+
/* @__PURE__ */ jsx19("div", { "aria-busy": isPending, className: isPending ? "pointer-events-none opacity-60" : void 0, children: /* @__PURE__ */ jsx19(
|
|
1324
1394
|
GenreSearch,
|
|
1325
1395
|
{
|
|
1326
1396
|
genrePlaylists: candidates,
|
|
@@ -1328,7 +1398,7 @@ function ChangeParentPopup({
|
|
|
1328
1398
|
placeholder: "Search a new parent\u2026"
|
|
1329
1399
|
}
|
|
1330
1400
|
) }),
|
|
1331
|
-
formErrors.length > 0 && /* @__PURE__ */
|
|
1401
|
+
formErrors.length > 0 && /* @__PURE__ */ jsx19("p", { role: "alert", className: "mt-3 text-sm text-[var(--color-red-500)]", children: formErrors.map(({ message }) => message).join(" ") })
|
|
1332
1402
|
] });
|
|
1333
1403
|
}
|
|
1334
1404
|
|
|
@@ -1352,7 +1422,7 @@ import {
|
|
|
1352
1422
|
SiYoutube
|
|
1353
1423
|
} from "react-icons/si";
|
|
1354
1424
|
import { Chip } from "@behindthemusictree/ui";
|
|
1355
|
-
import { jsx as
|
|
1425
|
+
import { jsx as jsx20 } from "react/jsx-runtime";
|
|
1356
1426
|
var LINK_KINDS = {
|
|
1357
1427
|
official: { label: "Official website", Icon: Globe },
|
|
1358
1428
|
wikipedia: { label: "Wikipedia", Icon: SiWikipedia2 },
|
|
@@ -1389,7 +1459,7 @@ function artistLinks(artist) {
|
|
|
1389
1459
|
return links;
|
|
1390
1460
|
}
|
|
1391
1461
|
function ArtistLinks({ links }) {
|
|
1392
|
-
return /* @__PURE__ */
|
|
1462
|
+
return /* @__PURE__ */ jsx20("ul", { className: "flex flex-wrap gap-1.5", children: links.map(({ key, url, Icon, label }) => /* @__PURE__ */ jsx20("li", { children: /* @__PURE__ */ jsx20(Chip, { href: url, icon: /* @__PURE__ */ jsx20(Icon, { className: "h-3.5 w-3.5 shrink-0", "aria-hidden": "true" }), children: label }) }, key)) });
|
|
1393
1463
|
}
|
|
1394
1464
|
|
|
1395
1465
|
// src/genre-tree/artist/formatYears.ts
|
|
@@ -1400,7 +1470,7 @@ function formatYears(beginYear, endYear, ended) {
|
|
|
1400
1470
|
}
|
|
1401
1471
|
|
|
1402
1472
|
// src/genre-tree/artist/ArtistHeader.tsx
|
|
1403
|
-
import { jsx as
|
|
1473
|
+
import { jsx as jsx21 } from "react/jsx-runtime";
|
|
1404
1474
|
var countryNames = new Intl.DisplayNames(["en"], { type: "region" });
|
|
1405
1475
|
function ArtistHeader({ artist }) {
|
|
1406
1476
|
const fields = [];
|
|
@@ -1410,35 +1480,35 @@ function ArtistHeader({ artist }) {
|
|
|
1410
1480
|
const years = formatYears(artist.beginYear, artist.endYear, artist.ended);
|
|
1411
1481
|
if (years) fields.push({ label: "Active", value: years });
|
|
1412
1482
|
const links = artistLinks(artist);
|
|
1413
|
-
if (links.length > 0) fields.push({ label: "Links", value: /* @__PURE__ */
|
|
1483
|
+
if (links.length > 0) fields.push({ label: "Links", value: /* @__PURE__ */ jsx21(ArtistLinks, { links }) });
|
|
1414
1484
|
if (fields.length === 0) return null;
|
|
1415
|
-
return /* @__PURE__ */
|
|
1485
|
+
return /* @__PURE__ */ jsx21(FieldList, { items: fields });
|
|
1416
1486
|
}
|
|
1417
1487
|
|
|
1418
1488
|
// src/genre-tree/artist/ArtistPhoto.tsx
|
|
1419
|
-
import { jsx as
|
|
1489
|
+
import { jsx as jsx22, jsxs as jsxs16 } from "react/jsx-runtime";
|
|
1420
1490
|
function ExternalLink({ href, children }) {
|
|
1421
|
-
return /* @__PURE__ */
|
|
1491
|
+
return /* @__PURE__ */ jsx22("a", { href, target: "_blank", rel: "noopener noreferrer", className: "underline-offset-2 hover:underline", children });
|
|
1422
1492
|
}
|
|
1423
1493
|
function ArtistPhoto({ image, name }) {
|
|
1424
|
-
return /* @__PURE__ */
|
|
1425
|
-
/* @__PURE__ */
|
|
1426
|
-
/* @__PURE__ */
|
|
1494
|
+
return /* @__PURE__ */ jsxs16("figure", { className: "flex flex-col gap-1.5 px-6 py-2.5", children: [
|
|
1495
|
+
/* @__PURE__ */ jsx22("img", { src: image.url, alt: name, className: "h-64 w-full object-contain bg-[var(--color-surface-muted)] rounded" }),
|
|
1496
|
+
/* @__PURE__ */ jsxs16("figcaption", { className: "text-xs text-[var(--color-text-muted)]", children: [
|
|
1427
1497
|
"Photo: ",
|
|
1428
|
-
/* @__PURE__ */
|
|
1498
|
+
/* @__PURE__ */ jsx22(ExternalLink, { href: image.pageUrl, children: image.author ?? "Wikimedia Commons" }),
|
|
1429
1499
|
",",
|
|
1430
1500
|
" ",
|
|
1431
|
-
image.licenseUrl ? /* @__PURE__ */
|
|
1501
|
+
image.licenseUrl ? /* @__PURE__ */ jsx22(ExternalLink, { href: image.licenseUrl, children: image.license }) : image.license
|
|
1432
1502
|
] })
|
|
1433
1503
|
] });
|
|
1434
1504
|
}
|
|
1435
1505
|
|
|
1436
1506
|
// src/genre-tree/artist/ArtistMembers.tsx
|
|
1437
1507
|
import { PanelGroup, PanelSection as PanelSection3 } from "@behindthemusictree/ui";
|
|
1438
|
-
import { jsx as
|
|
1508
|
+
import { jsx as jsx23, jsxs as jsxs17 } from "react/jsx-runtime";
|
|
1439
1509
|
function MembershipList({ title, memberships, renderArtistLink }) {
|
|
1440
1510
|
if (memberships.length === 0) return null;
|
|
1441
|
-
return /* @__PURE__ */
|
|
1511
|
+
return /* @__PURE__ */ jsx23(PanelGroup, { title, children: /* @__PURE__ */ jsx23("ul", { children: memberships.map((membership, index) => {
|
|
1442
1512
|
const details = [
|
|
1443
1513
|
formatYears(membership.beginYear, membership.endYear, membership.ended),
|
|
1444
1514
|
...membership.roles
|
|
@@ -1446,9 +1516,9 @@ function MembershipList({ title, memberships, renderArtistLink }) {
|
|
|
1446
1516
|
const detailsText = details.filter(Boolean).join(" \xB7 ");
|
|
1447
1517
|
return (
|
|
1448
1518
|
// A member can have several periods in the same group.
|
|
1449
|
-
/* @__PURE__ */
|
|
1450
|
-
/* @__PURE__ */
|
|
1451
|
-
detailsText && /* @__PURE__ */
|
|
1519
|
+
/* @__PURE__ */ jsxs17("li", { className: "truncate py-0.5", title: detailsText || void 0, children: [
|
|
1520
|
+
/* @__PURE__ */ jsx23("span", { className: "font-medium text-[var(--color-text)]", children: renderArtistLink(membership.artist) }),
|
|
1521
|
+
detailsText && /* @__PURE__ */ jsxs17("span", { className: "text-[var(--color-text-muted)]", children: [
|
|
1452
1522
|
" \u2014 ",
|
|
1453
1523
|
detailsText
|
|
1454
1524
|
] })
|
|
@@ -1459,9 +1529,9 @@ function MembershipList({ title, memberships, renderArtistLink }) {
|
|
|
1459
1529
|
function ArtistMembers({ title, memberships, renderArtistLink }) {
|
|
1460
1530
|
if (memberships.length === 0) return null;
|
|
1461
1531
|
const isCurrent = (membership) => !membership.ended && membership.endYear === null;
|
|
1462
|
-
return /* @__PURE__ */
|
|
1463
|
-
/* @__PURE__ */
|
|
1464
|
-
/* @__PURE__ */
|
|
1532
|
+
return /* @__PURE__ */ jsxs17(PanelSection3, { title, children: [
|
|
1533
|
+
/* @__PURE__ */ jsx23(MembershipList, { title: "Current", memberships: memberships.filter(isCurrent), renderArtistLink }),
|
|
1534
|
+
/* @__PURE__ */ jsx23(
|
|
1465
1535
|
MembershipList,
|
|
1466
1536
|
{
|
|
1467
1537
|
title: "Past",
|
|
@@ -1474,7 +1544,7 @@ function ArtistMembers({ title, memberships, renderArtistLink }) {
|
|
|
1474
1544
|
|
|
1475
1545
|
// src/genre-tree/artist/ArtistDiscography.tsx
|
|
1476
1546
|
import { PanelGroup as PanelGroup2, PanelSection as PanelSection4 } from "@behindthemusictree/ui";
|
|
1477
|
-
import { jsx as
|
|
1547
|
+
import { jsx as jsx24, jsxs as jsxs18 } from "react/jsx-runtime";
|
|
1478
1548
|
var GROUPS = ["Albums", "EPs", "Singles", "Live", "Compilations", "Other"];
|
|
1479
1549
|
var PRIMARY_GROUPS = { album: "Albums", ep: "EPs", single: "Singles" };
|
|
1480
1550
|
function discographyGroup({ primaryType, secondaryTypes }) {
|
|
@@ -1494,12 +1564,12 @@ function byYear(a, b) {
|
|
|
1494
1564
|
function ArtistDiscography({ albums }) {
|
|
1495
1565
|
if (albums.length === 0) return null;
|
|
1496
1566
|
const sorted = [...albums].sort(byYear);
|
|
1497
|
-
return /* @__PURE__ */
|
|
1567
|
+
return /* @__PURE__ */ jsx24(PanelSection4, { title: "Discography", children: GROUPS.map((group) => {
|
|
1498
1568
|
const groupAlbums = sorted.filter((album) => discographyGroup(album) === group);
|
|
1499
1569
|
if (groupAlbums.length === 0) return null;
|
|
1500
|
-
return /* @__PURE__ */
|
|
1501
|
-
/* @__PURE__ */
|
|
1502
|
-
/* @__PURE__ */
|
|
1570
|
+
return /* @__PURE__ */ jsx24(PanelGroup2, { title: group, children: /* @__PURE__ */ jsx24("ul", { children: groupAlbums.map((album) => /* @__PURE__ */ jsxs18("li", { className: "grid grid-cols-[2.5rem_minmax(0,1fr)] gap-2 py-0.5", children: [
|
|
1571
|
+
/* @__PURE__ */ jsx24("span", { className: "tabular-nums text-[var(--color-text-muted)]", children: album.year ?? "\u2014" }),
|
|
1572
|
+
/* @__PURE__ */ jsx24("span", { className: "truncate text-[var(--color-text)]", title: album.name, children: album.name })
|
|
1503
1573
|
] }, album.uuid)) }) }, group);
|
|
1504
1574
|
}) });
|
|
1505
1575
|
}
|
|
@@ -1526,7 +1596,7 @@ import { useTrackList as useTrackList3 } from "@behindthemusictree/app-kit/genre
|
|
|
1526
1596
|
import { FaPlay as FaPlay2, FaPause as FaPause2 } from "react-icons/fa";
|
|
1527
1597
|
import { usePlayer as usePlayer6 } from "@behindthemusictree/app-kit/player";
|
|
1528
1598
|
import { PlayStates as PlayStates2 } from "@behindthemusictree/app-kit/player";
|
|
1529
|
-
import { jsx as
|
|
1599
|
+
import { jsx as jsx25, jsxs as jsxs19 } from "react/jsx-runtime";
|
|
1530
1600
|
function TrackPositionPlayPause({
|
|
1531
1601
|
position,
|
|
1532
1602
|
uuid,
|
|
@@ -1540,14 +1610,14 @@ function TrackPositionPlayPause({
|
|
|
1540
1610
|
const isPlaying = isThisTrack && isConfirmedPlayable && playState === PlayStates2.PLAYING;
|
|
1541
1611
|
const isPaused = isThisTrack && isConfirmedPlayable && playState === PlayStates2.PAUSED;
|
|
1542
1612
|
const isCurrentTrackActive = isPlaying || isPaused;
|
|
1543
|
-
return /* @__PURE__ */
|
|
1613
|
+
return /* @__PURE__ */ jsxs19(
|
|
1544
1614
|
"div",
|
|
1545
1615
|
{
|
|
1546
1616
|
className: "track-position-play-pause relative flex items-center justify-center gap-2 text-lg w-16 cursor-pointer",
|
|
1547
1617
|
style: { minWidth: "4rem", maxWidth: "4rem" },
|
|
1548
1618
|
onClick: handlePlayPauseClick,
|
|
1549
1619
|
children: [
|
|
1550
|
-
/* @__PURE__ */
|
|
1620
|
+
/* @__PURE__ */ jsx25("div", { className: "track-position-play-pause__status group-hover:hidden flex items-center justify-center", children: isAwaitingPlayback ? /* @__PURE__ */ jsx25("span", { className: "track-position-play-pause__spinner", role: "status", "aria-label": "Loading track" }) : isCurrentTrackActive ? /* @__PURE__ */ jsxs19(
|
|
1551
1621
|
"span",
|
|
1552
1622
|
{
|
|
1553
1623
|
className: "track-position-play-pause__bars",
|
|
@@ -1555,18 +1625,18 @@ function TrackPositionPlayPause({
|
|
|
1555
1625
|
role: "img",
|
|
1556
1626
|
"aria-label": isPlaying ? "Playing" : "Paused",
|
|
1557
1627
|
children: [
|
|
1558
|
-
/* @__PURE__ */
|
|
1559
|
-
/* @__PURE__ */
|
|
1560
|
-
/* @__PURE__ */
|
|
1628
|
+
/* @__PURE__ */ jsx25("span", { className: "track-position-play-pause__bar" }),
|
|
1629
|
+
/* @__PURE__ */ jsx25("span", { className: "track-position-play-pause__bar" }),
|
|
1630
|
+
/* @__PURE__ */ jsx25("span", { className: "track-position-play-pause__bar" })
|
|
1561
1631
|
]
|
|
1562
1632
|
}
|
|
1563
1633
|
) : position }),
|
|
1564
|
-
/* @__PURE__ */
|
|
1634
|
+
/* @__PURE__ */ jsx25(
|
|
1565
1635
|
"div",
|
|
1566
1636
|
{
|
|
1567
1637
|
className: `hidden group-hover:flex items-center justify-center ${isCurrentTrackActive ? "" : "absolute inset-0"}`,
|
|
1568
1638
|
"aria-hidden": "true",
|
|
1569
|
-
children: isAwaitingPlayback ? /* @__PURE__ */
|
|
1639
|
+
children: isAwaitingPlayback ? /* @__PURE__ */ jsx25("span", { className: "track-position-play-pause__spinner" }) : isPlaying ? /* @__PURE__ */ jsx25(FaPause2, {}) : /* @__PURE__ */ jsx25(FaPlay2, {})
|
|
1570
1640
|
}
|
|
1571
1641
|
)
|
|
1572
1642
|
]
|
|
@@ -1577,7 +1647,7 @@ function TrackPositionPlayPause({
|
|
|
1577
1647
|
// src/genre-tree/track-list-sidebar/TrackItem.tsx
|
|
1578
1648
|
import { isSong as isSong2, songUnplayableReason as songUnplayableReason2 } from "@behindthemusictree/app-kit/genre-tree";
|
|
1579
1649
|
import { ArtistNames as ArtistNames2 } from "@behindthemusictree/app-kit/genre-tree";
|
|
1580
|
-
import { jsx as
|
|
1650
|
+
import { jsx as jsx26, jsxs as jsxs20 } from "react/jsx-runtime";
|
|
1581
1651
|
function TrackItem({
|
|
1582
1652
|
track,
|
|
1583
1653
|
position,
|
|
@@ -1601,12 +1671,12 @@ function TrackItem({
|
|
|
1601
1671
|
loadTrackForPlayer(track.uuid);
|
|
1602
1672
|
}
|
|
1603
1673
|
};
|
|
1604
|
-
return /* @__PURE__ */
|
|
1674
|
+
return /* @__PURE__ */ jsxs20(
|
|
1605
1675
|
"div",
|
|
1606
1676
|
{
|
|
1607
1677
|
className: `track-item flex h-14 text-[var(--color-text)] ${isUnplayable ? "opacity-50" : "hover:bg-[var(--color-surface-muted)] group"}`,
|
|
1608
1678
|
children: [
|
|
1609
|
-
isUnplayable ? /* @__PURE__ */
|
|
1679
|
+
isUnplayable ? /* @__PURE__ */ jsx26(
|
|
1610
1680
|
"div",
|
|
1611
1681
|
{
|
|
1612
1682
|
className: "flex items-center justify-center text-lg w-16",
|
|
@@ -1614,7 +1684,7 @@ function TrackItem({
|
|
|
1614
1684
|
"aria-disabled": "true",
|
|
1615
1685
|
children: position
|
|
1616
1686
|
}
|
|
1617
|
-
) : /* @__PURE__ */
|
|
1687
|
+
) : /* @__PURE__ */ jsx26(
|
|
1618
1688
|
TrackPositionPlayPause,
|
|
1619
1689
|
{
|
|
1620
1690
|
position,
|
|
@@ -1623,12 +1693,12 @@ function TrackItem({
|
|
|
1623
1693
|
isSelected: selectedTrack?.uuid === track.uuid
|
|
1624
1694
|
}
|
|
1625
1695
|
),
|
|
1626
|
-
/* @__PURE__ */
|
|
1627
|
-
/* @__PURE__ */
|
|
1628
|
-
track.artists && track.artists.length > 0 ? /* @__PURE__ */
|
|
1696
|
+
/* @__PURE__ */ jsxs20("div", { className: "title-artist-container flex flex-col items-start justify-center min-w-0 flex-1", children: [
|
|
1697
|
+
/* @__PURE__ */ jsx26("div", { className: "flex max-w-full items-center gap-2", children: /* @__PURE__ */ jsx26("div", { className: "title text-lg font-bold text-[var(--color-text)] max-w-full truncate", children: renderSongLink ? renderSongLink(track) : isSong2(track) ? /* @__PURE__ */ jsx26(MusicBrainzRecordingLink, { song: track, className: "hover:underline focus-visible:underline", children: track.title }) : track.title }) }),
|
|
1698
|
+
track.artists && track.artists.length > 0 ? /* @__PURE__ */ jsx26("div", { className: "artist text-base max-w-full truncate text-[var(--color-text-muted)]", children: /* @__PURE__ */ jsx26(ArtistNames2, { artists: track.artists, renderArtistLink }) }) : ""
|
|
1629
1699
|
] }),
|
|
1630
|
-
/* @__PURE__ */
|
|
1631
|
-
renderDuration && /* @__PURE__ */
|
|
1700
|
+
/* @__PURE__ */ jsx26("div", { className: "genre-name-container flex items-center justify-start w-[21.6%] min-w-0 shrink-0", children: track.genre ? /* @__PURE__ */ jsx26("div", { className: "genre-name max-w-full whitespace-normal break-words p-1 text-xs font-bold", children: track.genre.name }) : "" }),
|
|
1701
|
+
renderDuration && /* @__PURE__ */ jsx26(
|
|
1632
1702
|
"div",
|
|
1633
1703
|
{
|
|
1634
1704
|
className: "duration flex text-base w-16 items-center justify-center",
|
|
@@ -1636,14 +1706,14 @@ function TrackItem({
|
|
|
1636
1706
|
children: renderDuration(track)
|
|
1637
1707
|
}
|
|
1638
1708
|
),
|
|
1639
|
-
renderActions && /* @__PURE__ */
|
|
1709
|
+
renderActions && /* @__PURE__ */ jsx26("div", { className: "edit flex text-base w-6 items-center justify-center mr-2 cursor-pointer", children: renderActions(track) })
|
|
1640
1710
|
]
|
|
1641
1711
|
}
|
|
1642
1712
|
);
|
|
1643
1713
|
}
|
|
1644
1714
|
|
|
1645
1715
|
// src/genre-tree/artist/ArtistSongs.tsx
|
|
1646
|
-
import { Fragment as
|
|
1716
|
+
import { Fragment as Fragment10, jsx as jsx27, jsxs as jsxs21 } from "react/jsx-runtime";
|
|
1647
1717
|
var SongPageSchema2 = PaginatedResponseSchema2(SongDetailedSchema2);
|
|
1648
1718
|
var SORTS = [
|
|
1649
1719
|
{ ordering: "title", label: "Title" },
|
|
@@ -1676,21 +1746,21 @@ function ArtistSongs({ artist, getBackendBaseUrl, renderArtistLink, renderSongLi
|
|
|
1676
1746
|
event.stopPropagation();
|
|
1677
1747
|
void play(song.uuid);
|
|
1678
1748
|
};
|
|
1679
|
-
return /* @__PURE__ */
|
|
1680
|
-
/* @__PURE__ */
|
|
1681
|
-
/* @__PURE__ */
|
|
1749
|
+
return /* @__PURE__ */ jsx27(PanelSection5, { title: "Songs", children: isPending ? /* @__PURE__ */ jsx27(Skeleton3, { className: "h-14", "aria-busy": "true" }) : isError ? /* @__PURE__ */ jsx27("p", { className: "text-red-600", children: "Could not load songs." }) : data.results.length === 0 ? /* @__PURE__ */ jsx27("p", { className: "text-[var(--color-text-muted)]", children: "No songs yet." }) : /* @__PURE__ */ jsxs21(Fragment10, { children: [
|
|
1750
|
+
/* @__PURE__ */ jsxs21("div", { className: "flex flex-wrap items-center justify-between gap-2 mb-2", children: [
|
|
1751
|
+
/* @__PURE__ */ jsxs21(
|
|
1682
1752
|
"button",
|
|
1683
1753
|
{
|
|
1684
1754
|
type: "button",
|
|
1685
1755
|
onClick: () => void play(),
|
|
1686
1756
|
className: "flex w-fit items-center gap-1.5 px-3 py-1 text-xs font-medium bg-gray-900 text-white rounded-full hover:bg-gray-700",
|
|
1687
1757
|
children: [
|
|
1688
|
-
/* @__PURE__ */
|
|
1758
|
+
/* @__PURE__ */ jsx27(Play2, { className: "h-3.5 w-3.5", "aria-hidden": "true" }),
|
|
1689
1759
|
"Play all"
|
|
1690
1760
|
]
|
|
1691
1761
|
}
|
|
1692
1762
|
),
|
|
1693
|
-
/* @__PURE__ */
|
|
1763
|
+
/* @__PURE__ */ jsx27("div", { role: "group", "aria-label": "Sort songs by", className: "flex gap-1 text-xs", children: SORTS.map((sort) => /* @__PURE__ */ jsx27(
|
|
1694
1764
|
"button",
|
|
1695
1765
|
{
|
|
1696
1766
|
type: "button",
|
|
@@ -1705,7 +1775,7 @@ function ArtistSongs({ artist, getBackendBaseUrl, renderArtistLink, renderSongLi
|
|
|
1705
1775
|
sort.ordering
|
|
1706
1776
|
)) })
|
|
1707
1777
|
] }),
|
|
1708
|
-
/* @__PURE__ */
|
|
1778
|
+
/* @__PURE__ */ jsx27("ul", { className: "overflow-hidden mb-2 bg-zinc-950 rounded-lg", children: data.results.map((song, index) => /* @__PURE__ */ jsx27("li", { onClickCapture: (event) => handleRowClickCapture(event, song), children: /* @__PURE__ */ jsx27(
|
|
1709
1779
|
TrackItem,
|
|
1710
1780
|
{
|
|
1711
1781
|
track: song,
|
|
@@ -1714,12 +1784,12 @@ function ArtistSongs({ artist, getBackendBaseUrl, renderArtistLink, renderSongLi
|
|
|
1714
1784
|
renderSongLink
|
|
1715
1785
|
}
|
|
1716
1786
|
) }, song.uuid)) }),
|
|
1717
|
-
/* @__PURE__ */
|
|
1787
|
+
/* @__PURE__ */ jsx27(Pagination, { currentPage: page, totalPages: data.totalPages, onPageChange: setPage })
|
|
1718
1788
|
] }) });
|
|
1719
1789
|
}
|
|
1720
1790
|
|
|
1721
1791
|
// src/genre-tree/artist/useArtistPanel.tsx
|
|
1722
|
-
import { Fragment as
|
|
1792
|
+
import { Fragment as Fragment11, jsx as jsx28, jsxs as jsxs22 } from "react/jsx-runtime";
|
|
1723
1793
|
function useArtistPanel({
|
|
1724
1794
|
uuid,
|
|
1725
1795
|
scope,
|
|
@@ -1740,26 +1810,26 @@ function useArtistPanel({
|
|
|
1740
1810
|
return {
|
|
1741
1811
|
...panel,
|
|
1742
1812
|
title: "Artist",
|
|
1743
|
-
content: /* @__PURE__ */
|
|
1744
|
-
/* @__PURE__ */
|
|
1745
|
-
/* @__PURE__ */
|
|
1746
|
-
/* @__PURE__ */
|
|
1747
|
-
/* @__PURE__ */
|
|
1748
|
-
/* @__PURE__ */
|
|
1749
|
-
/* @__PURE__ */
|
|
1813
|
+
content: /* @__PURE__ */ jsxs22("div", { "aria-busy": "true", className: "flex flex-col gap-2.5 px-6 py-2.5", children: [
|
|
1814
|
+
/* @__PURE__ */ jsx28(Skeleton4, { className: "h-3 w-16" }),
|
|
1815
|
+
/* @__PURE__ */ jsx28(Skeleton4, { className: "h-4 w-32" }),
|
|
1816
|
+
/* @__PURE__ */ jsx28(Skeleton4, { className: "h-3 w-16" }),
|
|
1817
|
+
/* @__PURE__ */ jsx28(Skeleton4, { className: "h-4 w-24" }),
|
|
1818
|
+
/* @__PURE__ */ jsx28(Skeleton4, { className: "h-16 mt-2.5" }),
|
|
1819
|
+
/* @__PURE__ */ jsx28(Skeleton4, { className: "h-16" })
|
|
1750
1820
|
] })
|
|
1751
1821
|
};
|
|
1752
1822
|
case "not-found":
|
|
1753
1823
|
return {
|
|
1754
1824
|
...panel,
|
|
1755
1825
|
title: "Artist not found",
|
|
1756
|
-
content: /* @__PURE__ */
|
|
1826
|
+
content: /* @__PURE__ */ jsx28("p", { className: "px-6 py-2.5 text-[var(--color-text-muted)]", children: "This artist does not exist." })
|
|
1757
1827
|
};
|
|
1758
1828
|
case "error":
|
|
1759
1829
|
return {
|
|
1760
1830
|
...panel,
|
|
1761
1831
|
title: "Artist",
|
|
1762
|
-
content: /* @__PURE__ */
|
|
1832
|
+
content: /* @__PURE__ */ jsx28("p", { className: "px-6 py-2.5 text-red-600", children: "Could not load this artist." })
|
|
1763
1833
|
};
|
|
1764
1834
|
case "success": {
|
|
1765
1835
|
const { artist } = result;
|
|
@@ -1768,13 +1838,13 @@ function useArtistPanel({
|
|
|
1768
1838
|
return {
|
|
1769
1839
|
...panel,
|
|
1770
1840
|
title: artist.name,
|
|
1771
|
-
content: /* @__PURE__ */
|
|
1772
|
-
shareUrl && /* @__PURE__ */
|
|
1773
|
-
artist.image && /* @__PURE__ */
|
|
1774
|
-
/* @__PURE__ */
|
|
1775
|
-
/* @__PURE__ */
|
|
1776
|
-
/* @__PURE__ */
|
|
1777
|
-
artist.tracksCount > 0 && /* @__PURE__ */
|
|
1841
|
+
content: /* @__PURE__ */ jsxs22(Fragment11, { children: [
|
|
1842
|
+
shareUrl && /* @__PURE__ */ jsx28("div", { className: "genre-action-band border-b border-[var(--color-border)]", children: /* @__PURE__ */ jsx28("div", { className: "flex flex-wrap gap-1 px-3.5 py-3", children: shareTarget && /* @__PURE__ */ jsx28(ShareActionButton, { target: shareTarget, url: shareUrl }) }) }),
|
|
1843
|
+
artist.image && /* @__PURE__ */ jsx28(ArtistPhoto, { image: artist.image, name: artist.name }),
|
|
1844
|
+
/* @__PURE__ */ jsx28(ArtistHeader, { artist }),
|
|
1845
|
+
/* @__PURE__ */ jsx28(ArtistMembers, { title: "Members", memberships: artist.members, renderArtistLink }),
|
|
1846
|
+
/* @__PURE__ */ jsx28(ArtistMembers, { title: "Member of", memberships: artist.memberOf, renderArtistLink }),
|
|
1847
|
+
artist.tracksCount > 0 && /* @__PURE__ */ jsx28(
|
|
1778
1848
|
ArtistSongs,
|
|
1779
1849
|
{
|
|
1780
1850
|
artist: { uuid: artist.uuid, name: artist.name },
|
|
@@ -1784,7 +1854,7 @@ function useArtistPanel({
|
|
|
1784
1854
|
}
|
|
1785
1855
|
)
|
|
1786
1856
|
] }),
|
|
1787
|
-
extraContent: artist.albums.length > 0 ? /* @__PURE__ */
|
|
1857
|
+
extraContent: artist.albums.length > 0 ? /* @__PURE__ */ jsx28(ArtistDiscography, { albums: artist.albums }) : void 0
|
|
1788
1858
|
};
|
|
1789
1859
|
}
|
|
1790
1860
|
}
|
|
@@ -1808,7 +1878,7 @@ import {
|
|
|
1808
1878
|
useSongHistory,
|
|
1809
1879
|
useTrackList as useTrackList5
|
|
1810
1880
|
} from "@behindthemusictree/app-kit/genre-tree";
|
|
1811
|
-
import { Fragment as
|
|
1881
|
+
import { Fragment as Fragment12, jsx as jsx29, jsxs as jsxs23 } from "react/jsx-runtime";
|
|
1812
1882
|
var numberFormat = new Intl.NumberFormat("en");
|
|
1813
1883
|
var dateFormat = new Intl.DateTimeFormat("en", { dateStyle: "medium" });
|
|
1814
1884
|
var externalLink = "text-[var(--color-primary)] hover:underline focus-visible:underline";
|
|
@@ -1816,32 +1886,32 @@ function SongHistory({ uuid, getBackendBaseUrl }) {
|
|
|
1816
1886
|
const [open, setOpen] = useState7(false);
|
|
1817
1887
|
const history = useSongHistory(uuid, getBackendBaseUrl, open);
|
|
1818
1888
|
let body = null;
|
|
1819
|
-
if (history.status === "loading") body = /* @__PURE__ */
|
|
1820
|
-
else if (history.status === "error") body = /* @__PURE__ */
|
|
1889
|
+
if (history.status === "loading") body = /* @__PURE__ */ jsx29(Skeleton5, { className: "h-10", "aria-busy": "true" });
|
|
1890
|
+
else if (history.status === "error") body = /* @__PURE__ */ jsx29("p", { className: "text-red-600", children: "Could not load the history." });
|
|
1821
1891
|
else if (history.status === "success")
|
|
1822
|
-
body = history.entries.length === 0 ? /* @__PURE__ */
|
|
1823
|
-
/* @__PURE__ */
|
|
1824
|
-
entry.oldValue !== null || entry.newValue !== null ? /* @__PURE__ */
|
|
1892
|
+
body = history.entries.length === 0 ? /* @__PURE__ */ jsx29("p", { className: "text-[var(--color-text-muted)]", children: "No changes yet." }) : /* @__PURE__ */ jsx29("ul", { className: "divide-y divide-[var(--color-border)]", children: history.entries.map((entry) => /* @__PURE__ */ jsxs23("li", { className: "py-1.5 text-sm", children: [
|
|
1893
|
+
/* @__PURE__ */ jsx29("span", { className: "font-medium", children: entry.action }),
|
|
1894
|
+
entry.oldValue !== null || entry.newValue !== null ? /* @__PURE__ */ jsxs23("span", { className: "text-[var(--color-text-muted)]", children: [
|
|
1825
1895
|
" ",
|
|
1826
1896
|
"\u2014 ",
|
|
1827
1897
|
entry.oldValue ?? "none",
|
|
1828
1898
|
" \u2192 ",
|
|
1829
1899
|
entry.newValue ?? "none"
|
|
1830
1900
|
] }) : null,
|
|
1831
|
-
/* @__PURE__ */
|
|
1901
|
+
/* @__PURE__ */ jsxs23("span", { className: "block text-xs text-[var(--color-text-muted)]", children: [
|
|
1832
1902
|
entry.actorPseudo ?? "Anonymous",
|
|
1833
1903
|
" \xB7 ",
|
|
1834
1904
|
dateFormat.format(new Date(entry.createdOn))
|
|
1835
1905
|
] })
|
|
1836
1906
|
] }, entry.uuid)) });
|
|
1837
|
-
return /* @__PURE__ */
|
|
1907
|
+
return /* @__PURE__ */ jsxs23(
|
|
1838
1908
|
"details",
|
|
1839
1909
|
{
|
|
1840
1910
|
onToggle: (event) => setOpen(event.currentTarget.open),
|
|
1841
1911
|
className: "px-6 pb-2.5 mt-2.5 border-t border-[var(--color-border)]",
|
|
1842
1912
|
children: [
|
|
1843
|
-
/* @__PURE__ */
|
|
1844
|
-
/* @__PURE__ */
|
|
1913
|
+
/* @__PURE__ */ jsx29("summary", { className: "mt-2.5 cursor-pointer text-[0.6875rem] font-semibold uppercase text-[var(--color-text-muted)]", children: "History" }),
|
|
1914
|
+
/* @__PURE__ */ jsx29("div", { className: "mt-1.5", children: body })
|
|
1845
1915
|
]
|
|
1846
1916
|
}
|
|
1847
1917
|
);
|
|
@@ -1867,13 +1937,13 @@ function SongPanelContent({
|
|
|
1867
1937
|
const path = genrePath.length > 0 ? genrePath : null;
|
|
1868
1938
|
fields.push({
|
|
1869
1939
|
label: "Genre",
|
|
1870
|
-
value: path ? /* @__PURE__ */
|
|
1871
|
-
index > 0 && /* @__PURE__ */
|
|
1872
|
-
/* @__PURE__ */
|
|
1940
|
+
value: path ? /* @__PURE__ */ jsx29("span", { className: "flex flex-wrap items-center gap-x-1", children: path.map((genrePlaylist, index) => /* @__PURE__ */ jsxs23("span", { children: [
|
|
1941
|
+
index > 0 && /* @__PURE__ */ jsx29("span", { "aria-hidden": "true", children: "\u203A " }),
|
|
1942
|
+
/* @__PURE__ */ jsx29("button", { type: "button", onClick: () => onSelectGenre(genrePlaylist), className: "hover:underline", children: genrePlaylist.name })
|
|
1873
1943
|
] }, genrePlaylist.uuid)) }) : song.genre.name
|
|
1874
1944
|
});
|
|
1875
1945
|
} else {
|
|
1876
|
-
fields.push({ label: "Genre", value: /* @__PURE__ */
|
|
1946
|
+
fields.push({ label: "Genre", value: /* @__PURE__ */ jsx29("span", { className: "text-[var(--color-text-muted)]", children: "No genre" }) });
|
|
1877
1947
|
}
|
|
1878
1948
|
if (song.firstReleaseYear) fields.push({ label: "First released", value: song.firstReleaseYear });
|
|
1879
1949
|
const viewCount = song.youtubeVideo?.viewCount;
|
|
@@ -1883,11 +1953,11 @@ function SongPanelContent({
|
|
|
1883
1953
|
const links = [];
|
|
1884
1954
|
if (musicBrainzUrl)
|
|
1885
1955
|
links.push(
|
|
1886
|
-
/* @__PURE__ */
|
|
1956
|
+
/* @__PURE__ */ jsx29("a", { href: musicBrainzUrl, target: "_blank", rel: "noopener noreferrer", className: externalLink, children: "MusicBrainz" }, "mb")
|
|
1887
1957
|
);
|
|
1888
1958
|
if (song.youtubeVideo)
|
|
1889
1959
|
links.push(
|
|
1890
|
-
/* @__PURE__ */
|
|
1960
|
+
/* @__PURE__ */ jsx29(
|
|
1891
1961
|
"a",
|
|
1892
1962
|
{
|
|
1893
1963
|
href: `https://www.youtube.com/watch?v=${encodeURIComponent(song.youtubeVideo.id)}`,
|
|
@@ -1902,33 +1972,33 @@ function SongPanelContent({
|
|
|
1902
1972
|
if (links.length > 0)
|
|
1903
1973
|
fields.push({
|
|
1904
1974
|
label: "Links",
|
|
1905
|
-
value: /* @__PURE__ */
|
|
1975
|
+
value: /* @__PURE__ */ jsx29("span", { className: "flex gap-3", children: links })
|
|
1906
1976
|
});
|
|
1907
|
-
return /* @__PURE__ */
|
|
1908
|
-
/* @__PURE__ */
|
|
1909
|
-
unplayableReason ? /* @__PURE__ */
|
|
1977
|
+
return /* @__PURE__ */ jsxs23(Fragment12, { children: [
|
|
1978
|
+
/* @__PURE__ */ jsx29("div", { className: "genre-action-band border-b border-[var(--color-border)]", children: /* @__PURE__ */ jsxs23("div", { className: "flex flex-wrap gap-1 px-3.5 py-3", children: [
|
|
1979
|
+
unplayableReason ? /* @__PURE__ */ jsx29("p", { className: "flex items-center px-2.5 text-sm text-[var(--color-text-muted)]", children: unplayableReason }) : /* @__PURE__ */ jsxs23(
|
|
1910
1980
|
"button",
|
|
1911
1981
|
{
|
|
1912
1982
|
type: "button",
|
|
1913
1983
|
onClick: () => isCurrent ? handlePlayPauseAction() : playNewTrackListFromTrackUuid(song, scope),
|
|
1914
1984
|
className: "group flex flex-col items-center gap-1 w-16 text-xs text-center text-[var(--color-text)] focus-visible:outline-none",
|
|
1915
1985
|
children: [
|
|
1916
|
-
/* @__PURE__ */
|
|
1986
|
+
/* @__PURE__ */ jsx29("span", { className: "flex items-center justify-center w-10 h-10 rounded-full group-focus-visible:ring-2 group-focus-visible:ring-[var(--color-focus-ring)] bg-[var(--color-surface-muted)] transition-colors group-hover:bg-[var(--color-border)]", children: isPlaying ? /* @__PURE__ */ jsx29(Pause2, { "aria-hidden": "true", className: "w-5 h-5" }) : /* @__PURE__ */ jsx29(Play3, { "aria-hidden": "true", className: "w-5 h-5" }) }),
|
|
1917
1987
|
isPlaying ? "Pause" : "Play"
|
|
1918
1988
|
]
|
|
1919
1989
|
}
|
|
1920
1990
|
),
|
|
1921
|
-
shareUrl && /* @__PURE__ */
|
|
1991
|
+
shareUrl && /* @__PURE__ */ jsx29(ShareActionButton, { target: shareTarget, url: shareUrl })
|
|
1922
1992
|
] }) }),
|
|
1923
|
-
song.artists && song.artists.length > 0 && /* @__PURE__ */
|
|
1924
|
-
/* @__PURE__ */
|
|
1925
|
-
song.essentialGenres && song.essentialGenres.length > 0 && /* @__PURE__ */
|
|
1926
|
-
/* @__PURE__ */
|
|
1993
|
+
song.artists && song.artists.length > 0 && /* @__PURE__ */ jsx29("p", { className: "px-6 pt-2.5 text-[var(--color-text-muted)]", children: /* @__PURE__ */ jsx29(ArtistNames3, { artists: song.artists, renderArtistLink }) }),
|
|
1994
|
+
/* @__PURE__ */ jsx29(FieldList2, { items: fields }),
|
|
1995
|
+
song.essentialGenres && song.essentialGenres.length > 0 && /* @__PURE__ */ jsx29(PanelSection6, { title: "Essential in", children: /* @__PURE__ */ jsx29("ul", { children: song.essentialGenres.map((genre) => /* @__PURE__ */ jsx29("li", { className: "py-0.5", children: genre.name }, genre.uuid)) }) }),
|
|
1996
|
+
/* @__PURE__ */ jsx29(SongHistory, { uuid: song.uuid, getBackendBaseUrl })
|
|
1927
1997
|
] });
|
|
1928
1998
|
}
|
|
1929
1999
|
|
|
1930
2000
|
// src/genre-tree/song/useSongPanel.tsx
|
|
1931
|
-
import { jsx as
|
|
2001
|
+
import { jsx as jsx30, jsxs as jsxs24 } from "react/jsx-runtime";
|
|
1932
2002
|
function useSongPanel({
|
|
1933
2003
|
uuid,
|
|
1934
2004
|
scope,
|
|
@@ -1950,24 +2020,24 @@ function useSongPanel({
|
|
|
1950
2020
|
return {
|
|
1951
2021
|
...panel,
|
|
1952
2022
|
title: "Song",
|
|
1953
|
-
content: /* @__PURE__ */
|
|
1954
|
-
/* @__PURE__ */
|
|
1955
|
-
/* @__PURE__ */
|
|
1956
|
-
/* @__PURE__ */
|
|
1957
|
-
/* @__PURE__ */
|
|
2023
|
+
content: /* @__PURE__ */ jsxs24("div", { "aria-busy": "true", className: "flex flex-col gap-2.5 px-6 py-2.5", children: [
|
|
2024
|
+
/* @__PURE__ */ jsx30(Skeleton6, { className: "h-3 w-16" }),
|
|
2025
|
+
/* @__PURE__ */ jsx30(Skeleton6, { className: "h-4 w-32" }),
|
|
2026
|
+
/* @__PURE__ */ jsx30(Skeleton6, { className: "h-3 w-16" }),
|
|
2027
|
+
/* @__PURE__ */ jsx30(Skeleton6, { className: "h-4 w-24" })
|
|
1958
2028
|
] })
|
|
1959
2029
|
};
|
|
1960
2030
|
case "not-found":
|
|
1961
2031
|
return {
|
|
1962
2032
|
...panel,
|
|
1963
2033
|
title: "Song not found",
|
|
1964
|
-
content: /* @__PURE__ */
|
|
2034
|
+
content: /* @__PURE__ */ jsx30("p", { className: "px-6 py-2.5 text-[var(--color-text-muted)]", children: "This song does not exist." })
|
|
1965
2035
|
};
|
|
1966
2036
|
case "error":
|
|
1967
2037
|
return {
|
|
1968
2038
|
...panel,
|
|
1969
2039
|
title: "Song",
|
|
1970
|
-
content: /* @__PURE__ */
|
|
2040
|
+
content: /* @__PURE__ */ jsx30("p", { className: "px-6 py-2.5 text-red-600", children: "Could not load this song." })
|
|
1971
2041
|
};
|
|
1972
2042
|
case "success": {
|
|
1973
2043
|
const { song } = result;
|
|
@@ -1975,7 +2045,7 @@ function useSongPanel({
|
|
|
1975
2045
|
return {
|
|
1976
2046
|
...panel,
|
|
1977
2047
|
title: song.title,
|
|
1978
|
-
content: /* @__PURE__ */
|
|
2048
|
+
content: /* @__PURE__ */ jsx30(
|
|
1979
2049
|
SongPanelContent,
|
|
1980
2050
|
{
|
|
1981
2051
|
song,
|
|
@@ -1995,12 +2065,12 @@ function useSongPanel({
|
|
|
1995
2065
|
// src/genre-tree/SizeMetricToggle.tsx
|
|
1996
2066
|
import { MdMusicNote, MdVisibility } from "react-icons/md";
|
|
1997
2067
|
import { SegmentedControl } from "@behindthemusictree/ui";
|
|
1998
|
-
import { jsx as
|
|
2068
|
+
import { jsx as jsx31 } from "react/jsx-runtime";
|
|
1999
2069
|
function SizeMetricToggle({
|
|
2000
2070
|
value,
|
|
2001
2071
|
onChange
|
|
2002
2072
|
}) {
|
|
2003
|
-
return /* @__PURE__ */
|
|
2073
|
+
return /* @__PURE__ */ jsx31(
|
|
2004
2074
|
SegmentedControl,
|
|
2005
2075
|
{
|
|
2006
2076
|
variant: "floating",
|
|
@@ -2008,15 +2078,15 @@ function SizeMetricToggle({
|
|
|
2008
2078
|
value,
|
|
2009
2079
|
onChange,
|
|
2010
2080
|
options: [
|
|
2011
|
-
{ value: "songs", label: /* @__PURE__ */
|
|
2012
|
-
{ value: "views", label: /* @__PURE__ */
|
|
2081
|
+
{ value: "songs", label: /* @__PURE__ */ jsx31(MdMusicNote, { size: 18, "aria-hidden": true }), "aria-label": "Size by songs", title: "Node size by song count" },
|
|
2082
|
+
{ value: "views", label: /* @__PURE__ */ jsx31(MdVisibility, { size: 18, "aria-hidden": true }), "aria-label": "Size by views", title: "Node size by song views" }
|
|
2013
2083
|
]
|
|
2014
2084
|
}
|
|
2015
2085
|
);
|
|
2016
2086
|
}
|
|
2017
2087
|
|
|
2018
2088
|
// src/genre-tree/GenreTreeView.tsx
|
|
2019
|
-
import { Fragment as
|
|
2089
|
+
import { Fragment as Fragment13, jsx as jsx32, jsxs as jsxs25 } from "react/jsx-runtime";
|
|
2020
2090
|
var NO_POP_ROOT_TITLE = "This genre tree has no 'Mainstream Pop' root yet";
|
|
2021
2091
|
var REGIONS_CLASS = "[--gtv-center-left:var(--layout-center-left)] [--gtv-center-right:var(--layout-center-right)] [--gtv-center-top:var(--layout-band-top)]";
|
|
2022
2092
|
var noop = () => {
|
|
@@ -2050,6 +2120,7 @@ function GenreTreeView({
|
|
|
2050
2120
|
artistExpanded: controlledArtistExpanded,
|
|
2051
2121
|
onArtistExpandedChange,
|
|
2052
2122
|
getShareUrl,
|
|
2123
|
+
extraSearchGroups = [],
|
|
2053
2124
|
artistSearch = true,
|
|
2054
2125
|
onArtistSelect,
|
|
2055
2126
|
artistSearchBaseUrl,
|
|
@@ -2159,7 +2230,7 @@ function GenreTreeView({
|
|
|
2159
2230
|
const openSongRef = useRef3(openSong);
|
|
2160
2231
|
openSongRef.current = openSong;
|
|
2161
2232
|
const resolvedRenderSongLink = useCallback6(
|
|
2162
|
-
(song) => renderSongLink ? renderSongLink(song) : /* @__PURE__ */
|
|
2233
|
+
(song) => renderSongLink ? renderSongLink(song) : /* @__PURE__ */ jsx32("button", { type: "button", onClick: () => openSongRef.current(song.uuid), className: "hover:underline", children: song.title }),
|
|
2163
2234
|
[renderSongLink]
|
|
2164
2235
|
);
|
|
2165
2236
|
const [expandedSongUuid, setExpandedSongUuid] = useState8(null);
|
|
@@ -2171,7 +2242,7 @@ function GenreTreeView({
|
|
|
2171
2242
|
scope,
|
|
2172
2243
|
getBackendBaseUrl: artistBaseUrl,
|
|
2173
2244
|
getShareUrl: getShareUrlRef.current,
|
|
2174
|
-
renderArtistLink: renderArtistLink ?? ((artist) => artist.isSpecialPurpose ? artist.name : /* @__PURE__ */
|
|
2245
|
+
renderArtistLink: renderArtistLink ?? ((artist) => artist.isSpecialPurpose ? artist.name : /* @__PURE__ */ jsx32("button", { type: "button", onClick: () => openArtist(artist.uuid), className: "hover:underline", children: artist.name })),
|
|
2175
2246
|
expanded: controlledArtistExpanded ?? (artistUuid !== null && expandedArtistUuid === artistUuid),
|
|
2176
2247
|
onExpandedChange: (on) => {
|
|
2177
2248
|
if (controlledArtistExpanded === void 0) setExpandedArtistUuid(on ? artistUuid : null);
|
|
@@ -2180,7 +2251,7 @@ function GenreTreeView({
|
|
|
2180
2251
|
renderSongLink: resolvedRenderSongLink,
|
|
2181
2252
|
onClose: () => changeArtist(null)
|
|
2182
2253
|
});
|
|
2183
|
-
const resolvedRenderArtistLink = renderArtistLink ?? ((artist) => artist.isSpecialPurpose ? artist.name : /* @__PURE__ */
|
|
2254
|
+
const resolvedRenderArtistLink = renderArtistLink ?? ((artist) => artist.isSpecialPurpose ? artist.name : /* @__PURE__ */ jsx32("button", { type: "button", onClick: () => openArtist(artist.uuid), className: "hover:underline", children: artist.name }));
|
|
2184
2255
|
const getGenrePath = (genre) => {
|
|
2185
2256
|
const path = [];
|
|
2186
2257
|
let current = visibleGenrePlaylists.find((playlist) => playlist.criteria?.uuid === genre.uuid);
|
|
@@ -2259,52 +2330,27 @@ function GenreTreeView({
|
|
|
2259
2330
|
const handlePrevious = previousPlaylist && visibleGenrePlaylists.includes(previousPlaylist) ? () => handleGenreSearchSelect(previousPlaylist) : void 0;
|
|
2260
2331
|
const { showPopup, hidePopup } = usePopup5();
|
|
2261
2332
|
const [searchText, setSearchText] = useState8("");
|
|
2262
|
-
const
|
|
2263
|
-
|
|
2264
|
-
|
|
2265
|
-
|
|
2266
|
-
|
|
2267
|
-
|
|
2268
|
-
|
|
2269
|
-
|
|
2270
|
-
|
|
2271
|
-
|
|
2272
|
-
|
|
2273
|
-
|
|
2274
|
-
|
|
2275
|
-
|
|
2276
|
-
|
|
2277
|
-
|
|
2278
|
-
|
|
2279
|
-
|
|
2280
|
-
|
|
2281
|
-
|
|
2282
|
-
|
|
2283
|
-
onArtistSelect?.(artist);
|
|
2284
|
-
}
|
|
2285
|
-
})),
|
|
2286
|
-
status: artistSearchResult.isError ? "Search failed" : artistSearchResult.settled && artistSearchResult.artists.length === 0 ? "No artists found" : "",
|
|
2287
|
-
loading: artistSearchResult.pending
|
|
2288
|
-
} : void 0;
|
|
2289
|
-
const songSearchResult = useSongSearch(songBaseUrl, songSearch ? searchText : "");
|
|
2290
|
-
const songGroup = songSearch ? {
|
|
2291
|
-
key: "songs",
|
|
2292
|
-
label: "Songs",
|
|
2293
|
-
items: songSearchResult.songs.map((song) => ({
|
|
2294
|
-
key: song.uuid,
|
|
2295
|
-
content: /* @__PURE__ */ jsxs22("span", { className: isSongSearchResultPlayable(song) ? void 0 : "opacity-60", children: [
|
|
2296
|
-
/* @__PURE__ */ jsx29("span", { className: "block truncate font-medium", children: song.title }),
|
|
2297
|
-
/* @__PURE__ */ jsx29("span", { className: "block truncate text-xs text-[var(--color-neutral-500)]", children: [song.artists.map((artist) => artist.name).join(", "), song.genre?.name ?? "No genre"].filter(Boolean).join(" \xB7 ") })
|
|
2298
|
-
] }),
|
|
2299
|
-
onSelect: () => {
|
|
2300
|
-
openSong(song.uuid);
|
|
2301
|
-
onSongSelect?.(song);
|
|
2302
|
-
}
|
|
2303
|
-
})),
|
|
2304
|
-
status: songSearchResult.isError ? "Search failed" : songSearchResult.settled && songSearchResult.songs.length === 0 ? "No songs found" : "",
|
|
2305
|
-
loading: songSearchResult.pending
|
|
2306
|
-
} : void 0;
|
|
2307
|
-
const extraGroups = [artistGroup, songGroup].filter((group) => group !== void 0);
|
|
2333
|
+
const artistGroup = useArtistSearchGroup(
|
|
2334
|
+
artistBaseUrl,
|
|
2335
|
+
searchText,
|
|
2336
|
+
(artist) => {
|
|
2337
|
+
openArtist(artist.uuid);
|
|
2338
|
+
onArtistSelect?.(artist);
|
|
2339
|
+
},
|
|
2340
|
+
Boolean(artistSearch)
|
|
2341
|
+
);
|
|
2342
|
+
const songGroup = useSongSearchGroup(
|
|
2343
|
+
songBaseUrl,
|
|
2344
|
+
searchText,
|
|
2345
|
+
(song) => {
|
|
2346
|
+
openSong(song.uuid);
|
|
2347
|
+
onSongSelect?.(song);
|
|
2348
|
+
},
|
|
2349
|
+
Boolean(songSearch)
|
|
2350
|
+
);
|
|
2351
|
+
const extraGroups = [...extraSearchGroups, artistGroup, songGroup].filter(
|
|
2352
|
+
(group) => group !== void 0
|
|
2353
|
+
);
|
|
2308
2354
|
const handleSelectedNodeChange = (node) => {
|
|
2309
2355
|
if (node !== null && songUuid !== null) changeSong(null);
|
|
2310
2356
|
selectNode(node);
|
|
@@ -2328,7 +2374,7 @@ function GenreTreeView({
|
|
|
2328
2374
|
};
|
|
2329
2375
|
const renderGenreBody = (relation) => {
|
|
2330
2376
|
const { node } = relation;
|
|
2331
|
-
const family = /* @__PURE__ */
|
|
2377
|
+
const family = /* @__PURE__ */ jsx32(
|
|
2332
2378
|
GenreNodeFamily,
|
|
2333
2379
|
{
|
|
2334
2380
|
node,
|
|
@@ -2339,10 +2385,10 @@ function GenreTreeView({
|
|
|
2339
2385
|
onSelectNode: selectGenreFromPanel
|
|
2340
2386
|
}
|
|
2341
2387
|
);
|
|
2342
|
-
const ancestors = /* @__PURE__ */
|
|
2388
|
+
const ancestors = /* @__PURE__ */ jsx32(GenreNodeAncestors, { ancestorNodes: relation.ancestorNodes, onSelectNode: selectGenreFromPanel });
|
|
2343
2389
|
const genrePlaylist = genrePlaylistByNodeId.get(node.id);
|
|
2344
2390
|
const criteria = genrePlaylist?.criteria;
|
|
2345
|
-
if (!genrePlaylist || !criteria) return { primary: /* @__PURE__ */
|
|
2391
|
+
if (!genrePlaylist || !criteria) return { primary: /* @__PURE__ */ jsxs25(Fragment13, { children: [
|
|
2346
2392
|
family,
|
|
2347
2393
|
ancestors
|
|
2348
2394
|
] }) };
|
|
@@ -2362,11 +2408,11 @@ function GenreTreeView({
|
|
|
2362
2408
|
(sibling) => sibling.parent?.uuid === parentPlaylist.uuid && sibling.uuid !== genrePlaylist.uuid && sibling.criteria?.side === "pop"
|
|
2363
2409
|
) : void 0;
|
|
2364
2410
|
return {
|
|
2365
|
-
primary: /* @__PURE__ */
|
|
2366
|
-
/* @__PURE__ */
|
|
2411
|
+
primary: /* @__PURE__ */ jsxs25(Fragment13, { children: [
|
|
2412
|
+
/* @__PURE__ */ jsx32(
|
|
2367
2413
|
GenreInfoPanelBody,
|
|
2368
2414
|
{
|
|
2369
|
-
family: /* @__PURE__ */
|
|
2415
|
+
family: /* @__PURE__ */ jsxs25(Fragment13, { children: [
|
|
2370
2416
|
family,
|
|
2371
2417
|
ancestors
|
|
2372
2418
|
] }),
|
|
@@ -2384,7 +2430,7 @@ function GenreTreeView({
|
|
|
2384
2430
|
onAddChild: readOnly ? void 0 : () => handleGenreCreationAction(criteria),
|
|
2385
2431
|
onRename: readOnly ? void 0 : () => handleGenreRenameAction(criteria),
|
|
2386
2432
|
onChangeParent: readOnly ? void 0 : () => showPopup(
|
|
2387
|
-
/* @__PURE__ */
|
|
2433
|
+
/* @__PURE__ */ jsx32(
|
|
2388
2434
|
ChangeParentPopup,
|
|
2389
2435
|
{
|
|
2390
2436
|
genrePlaylist: { ...genrePlaylist, criteria },
|
|
@@ -2459,19 +2505,19 @@ function GenreTreeView({
|
|
|
2459
2505
|
edge: activePanel.expanded ? { label: "Shrink panel", onClick: () => activePanel.onExpandedChange?.(false) } : isCollapsed ? null : { label: "Hide panel", onClick: () => changeCollapsed(true) },
|
|
2460
2506
|
center: activePanel.expanded ? null : isCollapsed ? { label: "Show panel", onClick: () => changeCollapsed(false) } : activePanel.onExpandedChange ? { label: "Extend panel", onClick: () => activePanel.onExpandedChange?.(true) } : null
|
|
2461
2507
|
} : void 0;
|
|
2462
|
-
const expandButton = placement === "default" && activePanel?.onExpandedChange ? /* @__PURE__ */
|
|
2508
|
+
const expandButton = placement === "default" && activePanel?.onExpandedChange ? /* @__PURE__ */ jsx32(
|
|
2463
2509
|
IconButton,
|
|
2464
2510
|
{
|
|
2465
2511
|
"aria-label": activePanel.expanded ? "Shrink panel" : "Extend panel",
|
|
2466
2512
|
style: activePanel.headerAccent && { color: "inherit" },
|
|
2467
2513
|
onClick: () => activePanel.onExpandedChange?.(!activePanel.expanded),
|
|
2468
|
-
children: activePanel.expanded ? /* @__PURE__ */
|
|
2514
|
+
children: activePanel.expanded ? /* @__PURE__ */ jsx32(Minimize2, { "aria-hidden": "true", className: "h-4 w-4" }) : /* @__PURE__ */ jsx32(Maximize2, { "aria-hidden": "true", className: "h-4 w-4" })
|
|
2469
2515
|
}
|
|
2470
2516
|
) : null;
|
|
2471
2517
|
const renderArtistFilter = () => {
|
|
2472
2518
|
if (isLoading || !filterArtist) return null;
|
|
2473
|
-
return /* @__PURE__ */
|
|
2474
|
-
/* @__PURE__ */
|
|
2519
|
+
return /* @__PURE__ */ jsxs25("span", { className: "inline-flex items-center overflow-hidden rounded-full bg-[var(--color-neutral-100)] text-sm", children: [
|
|
2520
|
+
/* @__PURE__ */ jsx32(
|
|
2475
2521
|
"button",
|
|
2476
2522
|
{
|
|
2477
2523
|
type: "button",
|
|
@@ -2483,7 +2529,7 @@ function GenreTreeView({
|
|
|
2483
2529
|
children: filterArtist.name
|
|
2484
2530
|
}
|
|
2485
2531
|
),
|
|
2486
|
-
/* @__PURE__ */
|
|
2532
|
+
/* @__PURE__ */ jsx32(
|
|
2487
2533
|
"button",
|
|
2488
2534
|
{
|
|
2489
2535
|
type: "button",
|
|
@@ -2495,8 +2541,8 @@ function GenreTreeView({
|
|
|
2495
2541
|
)
|
|
2496
2542
|
] });
|
|
2497
2543
|
};
|
|
2498
|
-
const actions = /* @__PURE__ */
|
|
2499
|
-
!isLoading && /* @__PURE__ */
|
|
2544
|
+
const actions = /* @__PURE__ */ jsxs25(Fragment13, { children: [
|
|
2545
|
+
!isLoading && /* @__PURE__ */ jsx32(
|
|
2500
2546
|
GenreSearch,
|
|
2501
2547
|
{
|
|
2502
2548
|
genrePlaylists: visibleGenrePlaylists,
|
|
@@ -2504,13 +2550,13 @@ function GenreTreeView({
|
|
|
2504
2550
|
selectedName: selectedGenrePlaylist?.name ?? (typeof builtInPanel?.title === "string" ? builtInPanel.title : null),
|
|
2505
2551
|
onClear: builtInSongPanel ? () => changeSong(null) : builtInArtistPanel ? () => changeArtist(null) : handleGenreSearchClear,
|
|
2506
2552
|
onPrevious: handlePrevious,
|
|
2507
|
-
onQueryChange: artistSearch || songSearch ? setSearchText : void 0,
|
|
2553
|
+
onQueryChange: artistSearch || songSearch || extraSearchGroups.length > 0 ? setSearchText : void 0,
|
|
2508
2554
|
extraGroups
|
|
2509
2555
|
}
|
|
2510
2556
|
),
|
|
2511
|
-
!isLoading && filterArtist && /* @__PURE__ */
|
|
2512
|
-
/* @__PURE__ */
|
|
2513
|
-
!isLoading && !isControlled && /* @__PURE__ */
|
|
2557
|
+
!isLoading && filterArtist && /* @__PURE__ */ jsx32("div", { className: "hidden w-full justify-center max-md:flex", children: renderArtistFilter() }),
|
|
2558
|
+
/* @__PURE__ */ jsxs25("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: [
|
|
2559
|
+
!isLoading && !isControlled && /* @__PURE__ */ jsx32(
|
|
2514
2560
|
SegmentedControl2,
|
|
2515
2561
|
{
|
|
2516
2562
|
"aria-label": "Tree view mode",
|
|
@@ -2524,13 +2570,13 @@ function GenreTreeView({
|
|
|
2524
2570
|
]
|
|
2525
2571
|
}
|
|
2526
2572
|
),
|
|
2527
|
-
!isLoading && showDisplayOptions && /* @__PURE__ */
|
|
2573
|
+
!isLoading && showDisplayOptions && /* @__PURE__ */ jsx32(
|
|
2528
2574
|
"div",
|
|
2529
2575
|
{
|
|
2530
2576
|
className: "flex items-center gap-1",
|
|
2531
2577
|
role: "group",
|
|
2532
2578
|
"aria-label": "Tree display options",
|
|
2533
|
-
children: !isRotationControlled && viewMode !== "stacked" && viewMode !== "outline" && /* @__PURE__ */
|
|
2579
|
+
children: !isRotationControlled && viewMode !== "stacked" && viewMode !== "outline" && /* @__PURE__ */ jsx32(
|
|
2534
2580
|
Button,
|
|
2535
2581
|
{
|
|
2536
2582
|
variant: allowWheelRotation ? "default" : "outline",
|
|
@@ -2541,7 +2587,7 @@ function GenreTreeView({
|
|
|
2541
2587
|
)
|
|
2542
2588
|
}
|
|
2543
2589
|
),
|
|
2544
|
-
!isLoading && !readOnly && showAddRoot && /* @__PURE__ */
|
|
2590
|
+
!isLoading && !readOnly && showAddRoot && /* @__PURE__ */ jsx32(
|
|
2545
2591
|
IconTextButton,
|
|
2546
2592
|
{
|
|
2547
2593
|
icon: Plus2,
|
|
@@ -2551,34 +2597,34 @@ function GenreTreeView({
|
|
|
2551
2597
|
)
|
|
2552
2598
|
] })
|
|
2553
2599
|
] });
|
|
2554
|
-
return /* @__PURE__ */
|
|
2600
|
+
return /* @__PURE__ */ jsxs25(
|
|
2555
2601
|
"div",
|
|
2556
2602
|
{
|
|
2557
2603
|
"data-left-panel": isPanelShown && !isCollapsed ? void 0 : "hidden",
|
|
2558
2604
|
className: ["genre-tree-view relative flex flex-col h-full", placement === "regions" && REGIONS_CLASS, className2].filter(Boolean).join(" "),
|
|
2559
2605
|
children: [
|
|
2560
|
-
/* @__PURE__ */
|
|
2606
|
+
/* @__PURE__ */ jsx32(
|
|
2561
2607
|
"div",
|
|
2562
2608
|
{
|
|
2563
2609
|
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))] 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"}`,
|
|
2564
2610
|
children: actions
|
|
2565
2611
|
}
|
|
2566
2612
|
),
|
|
2567
|
-
!isLoading && filterArtist && /* @__PURE__ */
|
|
2613
|
+
!isLoading && filterArtist && /* @__PURE__ */ jsx32(
|
|
2568
2614
|
"div",
|
|
2569
2615
|
{
|
|
2570
2616
|
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))]" : "top-5"}`,
|
|
2571
2617
|
children: renderArtistFilter()
|
|
2572
2618
|
}
|
|
2573
2619
|
),
|
|
2574
|
-
/* @__PURE__ */
|
|
2575
|
-
!isLoading && viewMode === "outline" && floatingControlsLeading && /* @__PURE__ */
|
|
2576
|
-
isLoading ? /* @__PURE__ */
|
|
2620
|
+
/* @__PURE__ */ jsx32("div", { className: "content-container flex-1 min-h-0 flex flex-row gap-4", children: /* @__PURE__ */ jsxs25("div", { className: "tree-view-container relative flex-1 min-w-0 flex flex-col h-full", children: [
|
|
2621
|
+
!isLoading && viewMode === "outline" && floatingControlsLeading && /* @__PURE__ */ jsx32("div", { className: "absolute bottom-3 right-3 z-10", children: floatingControlsLeading }),
|
|
2622
|
+
isLoading ? /* @__PURE__ */ jsx32(GenreTreeViewSkeleton, { viewMode }) : viewMode === "wheel" ? (
|
|
2577
2623
|
// The info panel's top edge aligns with the tree's; the search bar floats `--layout-panel-inset` below it,
|
|
2578
2624
|
// and the header inset (the bar's height plus that inset) extends the header's fill behind the bar,
|
|
2579
2625
|
// Google Maps style; the 8px bottom padding mirrors the inset above the bar, and the hidden title's height is zeroed.
|
|
2580
2626
|
// The panel's own Zoom in button is hidden: the search bar carries it.
|
|
2581
|
-
/* @__PURE__ */
|
|
2627
|
+
/* @__PURE__ */ jsx32("div", { className: "tree-container search-overlay relative flex-1 w-full min-h-0 ", children: /* @__PURE__ */ jsx32(GenreTreeWheelHandoff, { skeleton: /* @__PURE__ */ jsx32(GenreTreeWheelSkeleton, {}), onRevealedChange: setIsWheelRevealed, children: /* @__PURE__ */ jsx32(
|
|
2582
2628
|
GenrePlaylistTreeWheel,
|
|
2583
2629
|
{
|
|
2584
2630
|
scope,
|
|
@@ -2595,9 +2641,9 @@ function GenreTreeView({
|
|
|
2595
2641
|
allowWheelRotation,
|
|
2596
2642
|
sizeMetric: isArtistFiltered || !canSizeByViews ? "songs" : deferredSizeMetric,
|
|
2597
2643
|
busy,
|
|
2598
|
-
floatingControlsLeading: floatingControlsLeading || canSizeByViews ? /* @__PURE__ */
|
|
2644
|
+
floatingControlsLeading: floatingControlsLeading || canSizeByViews ? /* @__PURE__ */ jsxs25("div", { className: "flex items-center gap-2", children: [
|
|
2599
2645
|
floatingControlsLeading,
|
|
2600
|
-
canSizeByViews && /* @__PURE__ */
|
|
2646
|
+
canSizeByViews && /* @__PURE__ */ jsx32(SizeMetricToggle, { value: sizeMetric, onChange: changeSizeMetric })
|
|
2601
2647
|
] }) : void 0,
|
|
2602
2648
|
defaultViewport,
|
|
2603
2649
|
viewportRestore,
|
|
@@ -2606,7 +2652,7 @@ function GenreTreeView({
|
|
|
2606
2652
|
) }) })
|
|
2607
2653
|
) : viewMode === "pop-core" ? (
|
|
2608
2654
|
// Same as the wheel: the header inset extends its fill behind the floating search bar, Google Maps style.
|
|
2609
|
-
/* @__PURE__ */
|
|
2655
|
+
/* @__PURE__ */ jsx32("div", { className: "tree-container search-overlay relative flex-1 w-full min-h-0 ", children: /* @__PURE__ */ jsx32(GenreTreeWheelHandoff, { skeleton: /* @__PURE__ */ jsx32(GenreTreeWheelSkeleton, {}), onRevealedChange: setIsWheelRevealed, children: /* @__PURE__ */ jsx32(
|
|
2610
2656
|
GenrePlaylistTreeWheelRadialPopCore,
|
|
2611
2657
|
{
|
|
2612
2658
|
scope,
|
|
@@ -2623,9 +2669,9 @@ function GenreTreeView({
|
|
|
2623
2669
|
allowWheelRotation,
|
|
2624
2670
|
sizeMetric: isArtistFiltered || !canSizeByViews ? "songs" : deferredSizeMetric,
|
|
2625
2671
|
busy,
|
|
2626
|
-
floatingControlsLeading: floatingControlsLeading || canSizeByViews ? /* @__PURE__ */
|
|
2672
|
+
floatingControlsLeading: floatingControlsLeading || canSizeByViews ? /* @__PURE__ */ jsxs25("div", { className: "flex items-center gap-2", children: [
|
|
2627
2673
|
floatingControlsLeading,
|
|
2628
|
-
canSizeByViews && /* @__PURE__ */
|
|
2674
|
+
canSizeByViews && /* @__PURE__ */ jsx32(SizeMetricToggle, { value: sizeMetric, onChange: changeSizeMetric })
|
|
2629
2675
|
] }) : void 0,
|
|
2630
2676
|
defaultViewport,
|
|
2631
2677
|
viewportRestore,
|
|
@@ -2633,7 +2679,7 @@ function GenreTreeView({
|
|
|
2633
2679
|
...focus
|
|
2634
2680
|
}
|
|
2635
2681
|
) }) })
|
|
2636
|
-
) : viewMode === "outline" ? /* @__PURE__ */
|
|
2682
|
+
) : viewMode === "outline" ? /* @__PURE__ */ jsx32("div", { className: "tree-container flex-1 min-h-0 w-full overflow-y-auto relative", children: /* @__PURE__ */ jsx32(
|
|
2637
2683
|
GenrePlaylistTreeWheelRadialPopCore,
|
|
2638
2684
|
{
|
|
2639
2685
|
outline: true,
|
|
@@ -2649,13 +2695,13 @@ function GenreTreeView({
|
|
|
2649
2695
|
selectedNodeId,
|
|
2650
2696
|
readOnly
|
|
2651
2697
|
}
|
|
2652
|
-
) }) : /* @__PURE__ */
|
|
2698
|
+
) }) : /* @__PURE__ */ jsx32("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(
|
|
2653
2699
|
([uuid, genrePlaylistTreePerRoot]) => {
|
|
2654
|
-
return /* @__PURE__ */
|
|
2700
|
+
return /* @__PURE__ */ jsx32(
|
|
2655
2701
|
"div",
|
|
2656
2702
|
{
|
|
2657
2703
|
className: "tree-per-root-container relative shrink-0 h-[28rem] mt-2 mr-16 p-2 bg-[var(--color-neutral-100)] rounded-lg",
|
|
2658
|
-
children: /* @__PURE__ */
|
|
2704
|
+
children: /* @__PURE__ */ jsx32("div", { className: "graph-container relative z-10 h-full", children: /* @__PURE__ */ jsx32(
|
|
2659
2705
|
GenrePlaylistTreePerRoot,
|
|
2660
2706
|
{
|
|
2661
2707
|
scope,
|
|
@@ -2681,7 +2727,7 @@ function GenreTreeView({
|
|
|
2681
2727
|
);
|
|
2682
2728
|
}
|
|
2683
2729
|
) }),
|
|
2684
|
-
/* @__PURE__ */
|
|
2730
|
+
/* @__PURE__ */ jsx32(
|
|
2685
2731
|
DetailPanel,
|
|
2686
2732
|
{
|
|
2687
2733
|
ref: panelRef,
|
|
@@ -2698,7 +2744,7 @@ function GenreTreeView({
|
|
|
2698
2744
|
aside: activePanel?.aside,
|
|
2699
2745
|
edgeTab: detailTab,
|
|
2700
2746
|
headerClassName: activePanel?.compact ? "pt-[calc(var(--layout-search-h)+var(--layout-panel-inset)+0.5rem)]" : void 0,
|
|
2701
|
-
children: activePanel?.aside && !activePanel.expanded ? /* @__PURE__ */
|
|
2747
|
+
children: activePanel?.aside && !activePanel.expanded ? /* @__PURE__ */ jsxs25(Fragment13, { children: [
|
|
2702
2748
|
activePanel.content,
|
|
2703
2749
|
activePanel.aside
|
|
2704
2750
|
] }) : activePanel?.content
|
|
@@ -2725,7 +2771,7 @@ import { Maximize2 as Maximize22, Minimize2 as Minimize22 } from "lucide-react";
|
|
|
2725
2771
|
import {
|
|
2726
2772
|
useFetchGenreDetail
|
|
2727
2773
|
} from "@behindthemusictree/app-kit/genre-tree";
|
|
2728
|
-
import { Fragment as
|
|
2774
|
+
import { Fragment as Fragment14, jsx as jsx33, jsxs as jsxs26 } from "react/jsx-runtime";
|
|
2729
2775
|
var RELATIVE_ITEM_COUNT = 1;
|
|
2730
2776
|
function toNode(genre, parentId) {
|
|
2731
2777
|
return {
|
|
@@ -2780,17 +2826,17 @@ function GenreDetailPanel({
|
|
|
2780
2826
|
};
|
|
2781
2827
|
}, [detail]);
|
|
2782
2828
|
if (isError) {
|
|
2783
|
-
return /* @__PURE__ */
|
|
2829
|
+
return /* @__PURE__ */ jsx33("div", { role: "alert", className: "p-4 text-sm text-[var(--color-text)]", children: "This genre could not be loaded." });
|
|
2784
2830
|
}
|
|
2785
2831
|
if (isPending || !detail || !view) {
|
|
2786
|
-
return /* @__PURE__ */
|
|
2787
|
-
/* @__PURE__ */
|
|
2788
|
-
/* @__PURE__ */
|
|
2789
|
-
/* @__PURE__ */
|
|
2832
|
+
return /* @__PURE__ */ jsxs26("div", { className: "flex flex-col gap-3 p-4", "aria-busy": "true", "data-testid": "genre-detail-panel-skeleton", children: [
|
|
2833
|
+
/* @__PURE__ */ jsx33(Skeleton7, { className: "h-6 w-2/3" }),
|
|
2834
|
+
/* @__PURE__ */ jsx33(Skeleton7, { className: "h-4 w-full" }),
|
|
2835
|
+
/* @__PURE__ */ jsx33(Skeleton7, { className: "h-4 w-3/4" })
|
|
2790
2836
|
] });
|
|
2791
2837
|
}
|
|
2792
2838
|
const selectGenre = (nodeId) => onSelectGenre(nodeId);
|
|
2793
|
-
const family = /* @__PURE__ */
|
|
2839
|
+
const family = /* @__PURE__ */ jsx33(
|
|
2794
2840
|
GenreNodeFamily2,
|
|
2795
2841
|
{
|
|
2796
2842
|
node: view.node,
|
|
@@ -2801,20 +2847,20 @@ function GenreDetailPanel({
|
|
|
2801
2847
|
onSelectNode: selectGenre
|
|
2802
2848
|
}
|
|
2803
2849
|
);
|
|
2804
|
-
const ancestors = /* @__PURE__ */
|
|
2805
|
-
return /* @__PURE__ */
|
|
2850
|
+
const ancestors = /* @__PURE__ */ jsx33(GenreNodeAncestors2, { ancestorNodes: view.ancestorNodes, onSelectNode: selectGenre });
|
|
2851
|
+
return /* @__PURE__ */ jsxs26(
|
|
2806
2852
|
DetailPanel2,
|
|
2807
2853
|
{
|
|
2808
2854
|
side: "left",
|
|
2809
2855
|
title: view.node.name,
|
|
2810
2856
|
headerAccent: { background: view.fill, color: ACCENT_TEXT_COLOR },
|
|
2811
|
-
headerActions: onExpandedChange ? /* @__PURE__ */
|
|
2857
|
+
headerActions: onExpandedChange ? /* @__PURE__ */ jsx33(
|
|
2812
2858
|
IconButton2,
|
|
2813
2859
|
{
|
|
2814
2860
|
"aria-label": expanded ? "Shrink panel" : "Extend panel",
|
|
2815
2861
|
style: { color: "inherit" },
|
|
2816
2862
|
onClick: () => onExpandedChange(!expanded),
|
|
2817
|
-
children: expanded ? /* @__PURE__ */
|
|
2863
|
+
children: expanded ? /* @__PURE__ */ jsx33(Minimize22, { "aria-hidden": "true", className: "h-4 w-4" }) : /* @__PURE__ */ jsx33(Maximize22, { "aria-hidden": "true", className: "h-4 w-4" })
|
|
2818
2864
|
}
|
|
2819
2865
|
) : void 0,
|
|
2820
2866
|
onClose,
|
|
@@ -2823,10 +2869,10 @@ function GenreDetailPanel({
|
|
|
2823
2869
|
onExpandedChange,
|
|
2824
2870
|
edgeTab,
|
|
2825
2871
|
children: [
|
|
2826
|
-
/* @__PURE__ */
|
|
2872
|
+
/* @__PURE__ */ jsx33(
|
|
2827
2873
|
GenreInfoPanelBody,
|
|
2828
2874
|
{
|
|
2829
|
-
family: /* @__PURE__ */
|
|
2875
|
+
family: /* @__PURE__ */ jsxs26(Fragment14, { children: [
|
|
2830
2876
|
family,
|
|
2831
2877
|
ancestors
|
|
2832
2878
|
] }),
|
|
@@ -2860,7 +2906,7 @@ import { ListMusic } from "lucide-react";
|
|
|
2860
2906
|
import { useTrackList as useTrackList6 } from "@behindthemusictree/app-kit/genre-tree";
|
|
2861
2907
|
import { TrackListOriginType as TrackListOriginType2 } from "@behindthemusictree/app-kit/genre-tree";
|
|
2862
2908
|
import { useTrackNoun as useTrackNoun3 } from "@behindthemusictree/app-kit/track-noun";
|
|
2863
|
-
import { jsx as
|
|
2909
|
+
import { jsx as jsx34, jsxs as jsxs27 } from "react/jsx-runtime";
|
|
2864
2910
|
var useBrowserLayoutEffect = typeof window === "undefined" ? useEffect6 : useLayoutEffect2;
|
|
2865
2911
|
function TrackListSidebar({
|
|
2866
2912
|
className: className2 = "",
|
|
@@ -2962,25 +3008,25 @@ function TrackListSidebar({
|
|
|
2962
3008
|
}
|
|
2963
3009
|
};
|
|
2964
3010
|
const positionClasses = layout === "inline" ? "relative w-full flex h-full flex-col" : "fixed right-0 w-[50rem] flex flex-col";
|
|
2965
|
-
return trackList ? /* @__PURE__ */
|
|
3011
|
+
return trackList ? /* @__PURE__ */ jsxs27(
|
|
2966
3012
|
"div",
|
|
2967
3013
|
{
|
|
2968
3014
|
"data-theme": "dark",
|
|
2969
3015
|
className: `track-list-sidebar ${positionClasses} rounded-2xl bg-[var(--color-surface)] pb-1 ${className2}`,
|
|
2970
3016
|
style: layout === "fixed" ? { top: "63.5px", maxHeight: "calc(100vh - 63.5px - 79px)" } : void 0,
|
|
2971
3017
|
children: [
|
|
2972
|
-
/* @__PURE__ */
|
|
2973
|
-
/* @__PURE__ */
|
|
2974
|
-
/* @__PURE__ */
|
|
2975
|
-
/* @__PURE__ */
|
|
2976
|
-
/* @__PURE__ */
|
|
3018
|
+
/* @__PURE__ */ jsxs27("div", { className: "header flex h-16 items-center px-4 py-2 text-[var(--color-text)]", children: [
|
|
3019
|
+
/* @__PURE__ */ jsxs27("div", { className: "min-w-0 flex flex-1 flex-col justify-center", children: [
|
|
3020
|
+
/* @__PURE__ */ jsxs27("div", { className: "origin flex text-xl", children: [
|
|
3021
|
+
/* @__PURE__ */ jsx34("div", { className: "from h-auto flex flex-col justify-center items-center mr-2", children: "From" }),
|
|
3022
|
+
/* @__PURE__ */ jsx34("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__ */ jsx34("div", { className: "name max-w-full truncate", children: trackList.origin.label }) })
|
|
2977
3023
|
] }),
|
|
2978
|
-
/* @__PURE__ */
|
|
3024
|
+
/* @__PURE__ */ jsxs27("div", { className: "info flex items-center text-sm text-[var(--color-text-muted)]", children: [
|
|
2979
3025
|
trackList.origin.type === TrackListOriginType2.GENRE_PLAYLIST ? "Genre \u2022 " : trackList.origin.type === TrackListOriginType2.ARTIST ? "Artist \u2022 " : `${trackNoun.singular} playlist \u2022 `,
|
|
2980
3026
|
`${trackList.total} ${trackList.total > 1 ? trackNoun.plural : trackNoun.singular}`
|
|
2981
3027
|
] })
|
|
2982
3028
|
] }),
|
|
2983
|
-
(isCollapsed && onExpand || !isCollapsed && onMinimize) && /* @__PURE__ */
|
|
3029
|
+
(isCollapsed && onExpand || !isCollapsed && onMinimize) && /* @__PURE__ */ jsx34(
|
|
2984
3030
|
"button",
|
|
2985
3031
|
{
|
|
2986
3032
|
type: "button",
|
|
@@ -2989,11 +3035,11 @@ function TrackListSidebar({
|
|
|
2989
3035
|
"aria-expanded": !isCollapsed,
|
|
2990
3036
|
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"}`,
|
|
2991
3037
|
onClick: isCollapsed ? onExpand : onMinimize,
|
|
2992
|
-
children: /* @__PURE__ */
|
|
3038
|
+
children: /* @__PURE__ */ jsx34(ListMusic, { "aria-hidden": "true", className: "h-5 w-5" })
|
|
2993
3039
|
}
|
|
2994
3040
|
)
|
|
2995
3041
|
] }),
|
|
2996
|
-
!isCollapsed && /* @__PURE__ */
|
|
3042
|
+
!isCollapsed && /* @__PURE__ */ jsxs27(
|
|
2997
3043
|
"ul",
|
|
2998
3044
|
{
|
|
2999
3045
|
ref: trackListRef,
|
|
@@ -3003,7 +3049,7 @@ function TrackListSidebar({
|
|
|
3003
3049
|
onPointerDown: markUserScrollIntent,
|
|
3004
3050
|
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",
|
|
3005
3051
|
children: [
|
|
3006
|
-
trackList.tracks.map((track, index) => /* @__PURE__ */
|
|
3052
|
+
trackList.tracks.map((track, index) => /* @__PURE__ */ jsx34("li", { "data-track-uuid": track.uuid, children: /* @__PURE__ */ jsx34(
|
|
3007
3053
|
TrackItem,
|
|
3008
3054
|
{
|
|
3009
3055
|
track,
|
|
@@ -3014,7 +3060,7 @@ function TrackListSidebar({
|
|
|
3014
3060
|
renderSongLink
|
|
3015
3061
|
}
|
|
3016
3062
|
) }, track.uuid)),
|
|
3017
|
-
hasMore && /* @__PURE__ */
|
|
3063
|
+
hasMore && /* @__PURE__ */ jsx34("li", { ref: loadMoreSentinelRef, "aria-hidden": "true", className: "h-px" })
|
|
3018
3064
|
]
|
|
3019
3065
|
}
|
|
3020
3066
|
)
|
|
@@ -3039,7 +3085,7 @@ import { PanelEdgeTab } from "@behindthemusictree/ui";
|
|
|
3039
3085
|
import { Pause as Pause3, Play as Play4, SkipBack, SkipForward, Volume2, VolumeX } from "lucide-react";
|
|
3040
3086
|
import { formatTime, useTrackList as useTrackList7 } from "@behindthemusictree/app-kit/genre-tree";
|
|
3041
3087
|
import { PlayStates as PlayStates4, useCurrentTime, usePlayer as usePlayer10 } from "@behindthemusictree/app-kit/player";
|
|
3042
|
-
import { jsx as
|
|
3088
|
+
import { jsx as jsx35, jsxs as jsxs28 } from "react/jsx-runtime";
|
|
3043
3089
|
function PlayerControls() {
|
|
3044
3090
|
const {
|
|
3045
3091
|
duration,
|
|
@@ -3058,15 +3104,15 @@ function PlayerControls() {
|
|
|
3058
3104
|
const safeDuration = Number.isFinite(duration) && duration > 0 ? duration : 0;
|
|
3059
3105
|
const safeCurrentTime = Number.isFinite(currentTime) ? Math.max(0, Math.min(currentTime, safeDuration)) : 0;
|
|
3060
3106
|
const isPlaying = playState === PlayStates4.PLAYING;
|
|
3061
|
-
return /* @__PURE__ */
|
|
3107
|
+
return /* @__PURE__ */ jsxs28(
|
|
3062
3108
|
"section",
|
|
3063
3109
|
{
|
|
3064
3110
|
"aria-label": "Player controls",
|
|
3065
3111
|
className: "player-controls flex shrink-0 flex-col gap-2 border-b border-zinc-800 px-3 py-2 text-zinc-200",
|
|
3066
3112
|
children: [
|
|
3067
|
-
/* @__PURE__ */
|
|
3068
|
-
/* @__PURE__ */
|
|
3069
|
-
/* @__PURE__ */
|
|
3113
|
+
/* @__PURE__ */ jsxs28("div", { className: "flex min-w-0 items-center gap-2 text-xs tabular-nums text-zinc-400", children: [
|
|
3114
|
+
/* @__PURE__ */ jsx35("span", { "aria-label": "Elapsed time", children: formatTime(safeCurrentTime) }),
|
|
3115
|
+
/* @__PURE__ */ jsx35(
|
|
3070
3116
|
"input",
|
|
3071
3117
|
{
|
|
3072
3118
|
"aria-label": "Seek",
|
|
@@ -3080,11 +3126,11 @@ function PlayerControls() {
|
|
|
3080
3126
|
onChange: (event) => seekTo(Number(event.currentTarget.value))
|
|
3081
3127
|
}
|
|
3082
3128
|
),
|
|
3083
|
-
/* @__PURE__ */
|
|
3129
|
+
/* @__PURE__ */ jsx35("span", { "aria-label": "Duration", children: formatTime(safeDuration) })
|
|
3084
3130
|
] }),
|
|
3085
|
-
/* @__PURE__ */
|
|
3086
|
-
/* @__PURE__ */
|
|
3087
|
-
/* @__PURE__ */
|
|
3131
|
+
/* @__PURE__ */ jsxs28("div", { className: "grid min-h-9 grid-cols-[1fr_auto_1fr] items-center gap-3", children: [
|
|
3132
|
+
/* @__PURE__ */ jsxs28("div", { className: "col-start-2 flex items-center justify-center gap-2", children: [
|
|
3133
|
+
/* @__PURE__ */ jsx35(
|
|
3088
3134
|
"button",
|
|
3089
3135
|
{
|
|
3090
3136
|
type: "button",
|
|
@@ -3093,10 +3139,10 @@ function PlayerControls() {
|
|
|
3093
3139
|
disabled: !isReady || !hasPreviousTrack,
|
|
3094
3140
|
onClick: playPreviousTrack,
|
|
3095
3141
|
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",
|
|
3096
|
-
children: /* @__PURE__ */
|
|
3142
|
+
children: /* @__PURE__ */ jsx35(SkipBack, { "aria-hidden": "true", className: "h-4 w-4" })
|
|
3097
3143
|
}
|
|
3098
3144
|
),
|
|
3099
|
-
/* @__PURE__ */
|
|
3145
|
+
/* @__PURE__ */ jsx35(
|
|
3100
3146
|
"button",
|
|
3101
3147
|
{
|
|
3102
3148
|
type: "button",
|
|
@@ -3105,10 +3151,10 @@ function PlayerControls() {
|
|
|
3105
3151
|
disabled: !isReady,
|
|
3106
3152
|
onClick: handlePlayPauseAction,
|
|
3107
3153
|
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",
|
|
3108
|
-
children: isPlaying ? /* @__PURE__ */
|
|
3154
|
+
children: isPlaying ? /* @__PURE__ */ jsx35(Pause3, { "aria-hidden": "true", className: "h-4 w-4", fill: "currentColor" }) : /* @__PURE__ */ jsx35(Play4, { "aria-hidden": "true", className: "h-4 w-4", fill: "currentColor" })
|
|
3109
3155
|
}
|
|
3110
3156
|
),
|
|
3111
|
-
/* @__PURE__ */
|
|
3157
|
+
/* @__PURE__ */ jsx35(
|
|
3112
3158
|
"button",
|
|
3113
3159
|
{
|
|
3114
3160
|
type: "button",
|
|
@@ -3117,14 +3163,14 @@ function PlayerControls() {
|
|
|
3117
3163
|
disabled: !isReady || !hasNextTrack,
|
|
3118
3164
|
onClick: playNextTrack,
|
|
3119
3165
|
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",
|
|
3120
|
-
children: /* @__PURE__ */
|
|
3166
|
+
children: /* @__PURE__ */ jsx35(SkipForward, { "aria-hidden": "true", className: "h-4 w-4" })
|
|
3121
3167
|
}
|
|
3122
3168
|
)
|
|
3123
3169
|
] }),
|
|
3124
|
-
/* @__PURE__ */
|
|
3125
|
-
volume === 0 ? /* @__PURE__ */
|
|
3126
|
-
/* @__PURE__ */
|
|
3127
|
-
/* @__PURE__ */
|
|
3170
|
+
/* @__PURE__ */ jsxs28("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: [
|
|
3171
|
+
volume === 0 ? /* @__PURE__ */ jsx35(VolumeX, { "aria-hidden": "true", className: "h-[0.7rem] w-[0.7rem] shrink-0" }) : /* @__PURE__ */ jsx35(Volume2, { "aria-hidden": "true", className: "h-[0.7rem] w-[0.7rem] shrink-0" }),
|
|
3172
|
+
/* @__PURE__ */ jsx35("span", { className: "sr-only", children: "Volume" }),
|
|
3173
|
+
/* @__PURE__ */ jsx35(
|
|
3128
3174
|
"input",
|
|
3129
3175
|
{
|
|
3130
3176
|
"aria-label": "Volume",
|
|
@@ -3146,7 +3192,7 @@ function PlayerControls() {
|
|
|
3146
3192
|
}
|
|
3147
3193
|
|
|
3148
3194
|
// src/genre-tree/PlayerPanel.tsx
|
|
3149
|
-
import { jsx as
|
|
3195
|
+
import { jsx as jsx36, jsxs as jsxs29 } from "react/jsx-runtime";
|
|
3150
3196
|
var PANEL_ID = "player-panel";
|
|
3151
3197
|
var DEFAULT_EXTENDED_WIDTH = "calc(100vw - var(--layout-center-left) - var(--layout-gutter))";
|
|
3152
3198
|
function PlayerPanel({
|
|
@@ -3186,7 +3232,7 @@ function PlayerPanel({
|
|
|
3186
3232
|
onClick: () => setIsExtendRequested(true),
|
|
3187
3233
|
expanded: false
|
|
3188
3234
|
} : null;
|
|
3189
|
-
return /* @__PURE__ */
|
|
3235
|
+
return /* @__PURE__ */ jsxs29(
|
|
3190
3236
|
"div",
|
|
3191
3237
|
{
|
|
3192
3238
|
id: PANEL_ID,
|
|
@@ -3199,7 +3245,7 @@ function PlayerPanel({
|
|
|
3199
3245
|
),
|
|
3200
3246
|
style: isExtended ? { width: extendedWidth } : void 0,
|
|
3201
3247
|
children: [
|
|
3202
|
-
/* @__PURE__ */
|
|
3248
|
+
/* @__PURE__ */ jsx36(
|
|
3203
3249
|
PanelEdgeTab,
|
|
3204
3250
|
{
|
|
3205
3251
|
side: "right",
|
|
@@ -3209,7 +3255,7 @@ function PlayerPanel({
|
|
|
3209
3255
|
className: "absolute right-full top-1/2 -translate-y-1/2"
|
|
3210
3256
|
}
|
|
3211
3257
|
),
|
|
3212
|
-
/* @__PURE__ */
|
|
3258
|
+
/* @__PURE__ */ jsxs29(
|
|
3213
3259
|
"div",
|
|
3214
3260
|
{
|
|
3215
3261
|
className: twMerge(
|
|
@@ -3217,20 +3263,20 @@ function PlayerPanel({
|
|
|
3217
3263
|
isExtended ? "flex-row" : "flex-col"
|
|
3218
3264
|
),
|
|
3219
3265
|
children: [
|
|
3220
|
-
/* @__PURE__ */
|
|
3221
|
-
/* @__PURE__ */
|
|
3222
|
-
/* @__PURE__ */
|
|
3223
|
-
/* @__PURE__ */
|
|
3224
|
-
playerTrackObject?.loadError && /* @__PURE__ */
|
|
3266
|
+
/* @__PURE__ */ jsxs29("div", { className: "flex w-[var(--layout-right-w)] shrink-0 flex-col", children: [
|
|
3267
|
+
/* @__PURE__ */ jsx36("div", { className: "flex shrink-0 items-center justify-between gap-2 border-b border-zinc-800 p-2", children: /* @__PURE__ */ jsx36("span", { className: "min-w-0 truncate text-sm font-semibold", children: loadedTrackTitle || lastLoadedTrackTitle }) }),
|
|
3268
|
+
/* @__PURE__ */ jsxs29("div", { className: "relative w-full shrink-0", children: [
|
|
3269
|
+
/* @__PURE__ */ jsx36(PlayerVideoSurface, { className: "aspect-video w-full bg-black" }),
|
|
3270
|
+
playerTrackObject?.loadError && /* @__PURE__ */ jsxs29("span", { className: "absolute bottom-2 left-2 right-2 text-xs text-red-400", children: [
|
|
3225
3271
|
playerTrackObject.loadError,
|
|
3226
|
-
/* @__PURE__ */
|
|
3272
|
+
/* @__PURE__ */ jsx36("button", { type: "button", className: "ml-2 underline", onClick: () => {
|
|
3227
3273
|
void retryPlayback();
|
|
3228
3274
|
}, children: "Retry" })
|
|
3229
3275
|
] })
|
|
3230
3276
|
] }),
|
|
3231
|
-
/* @__PURE__ */
|
|
3277
|
+
/* @__PURE__ */ jsx36(PlayerControls, {})
|
|
3232
3278
|
] }),
|
|
3233
|
-
/* @__PURE__ */
|
|
3279
|
+
/* @__PURE__ */ jsx36(
|
|
3234
3280
|
TrackListSidebar,
|
|
3235
3281
|
{
|
|
3236
3282
|
layout: "inline",
|
|
@@ -3257,11 +3303,11 @@ function PlayerPanel({
|
|
|
3257
3303
|
import { v4 as uuidv4 } from "uuid";
|
|
3258
3304
|
import { AiFillStar, AiOutlineStar } from "react-icons/ai";
|
|
3259
3305
|
import { FORM_RATING_NULL_VALUE } from "@behindthemusictree/app-kit/genre-tree";
|
|
3260
|
-
import { jsx as
|
|
3306
|
+
import { jsx as jsx37, jsxs as jsxs30 } from "react/jsx-runtime";
|
|
3261
3307
|
function Rating({ rating, handleChange }) {
|
|
3262
3308
|
const instanceId = uuidv4();
|
|
3263
|
-
return /* @__PURE__ */
|
|
3264
|
-
/* @__PURE__ */
|
|
3309
|
+
return /* @__PURE__ */ jsx37("div", { className: "flex items-center", children: [...Array(6)].map((_, i) => /* @__PURE__ */ jsxs30("div", { className: `relative ${i === 0 ? "mr-4" : "mr-1"}`, children: [
|
|
3310
|
+
/* @__PURE__ */ jsx37(
|
|
3265
3311
|
"input",
|
|
3266
3312
|
{
|
|
3267
3313
|
id: `star-${instanceId}-${i}`,
|
|
@@ -3273,16 +3319,16 @@ function Rating({ rating, handleChange }) {
|
|
|
3273
3319
|
onChange: handleChange
|
|
3274
3320
|
}
|
|
3275
3321
|
),
|
|
3276
|
-
/* @__PURE__ */
|
|
3277
|
-
/* @__PURE__ */
|
|
3322
|
+
/* @__PURE__ */ jsx37("label", { htmlFor: `star-${instanceId}-${i}`, className: "cursor-pointer", children: i === 0 ? /* @__PURE__ */ jsxs30("div", { className: "flex", children: [
|
|
3323
|
+
/* @__PURE__ */ jsx37(
|
|
3278
3324
|
AiOutlineStar,
|
|
3279
3325
|
{
|
|
3280
3326
|
className: `w-7 h-7 absolute top-0 left-0 ${rating === FORM_RATING_NULL_VALUE ? "text-[var(--color-accent-rating)]" : "text-[var(--color-text-muted)]"}`
|
|
3281
3327
|
}
|
|
3282
3328
|
),
|
|
3283
|
-
/* @__PURE__ */
|
|
3329
|
+
/* @__PURE__ */ jsx37("span", { className: "flex-grow w-8" }),
|
|
3284
3330
|
" "
|
|
3285
|
-
] }) : /* @__PURE__ */
|
|
3331
|
+
] }) : /* @__PURE__ */ jsx37(
|
|
3286
3332
|
AiFillStar,
|
|
3287
3333
|
{
|
|
3288
3334
|
className: `w-7 h-7 absolute top-0 left-0 ${(rating ?? -1) >= i ? "text-[var(--color-accent-rating)]" : "text-[var(--color-text-muted)]"}`
|
|
@@ -3294,6 +3340,12 @@ function Rating({ rating, handleChange }) {
|
|
|
3294
3340
|
export {
|
|
3295
3341
|
useGenrePlaylistPlayback,
|
|
3296
3342
|
GenrePlaylistTreePerRoot,
|
|
3343
|
+
SearchBox,
|
|
3344
|
+
SEARCH_FAILED_STATUS,
|
|
3345
|
+
searchStatus,
|
|
3346
|
+
useArtistSearchGroup,
|
|
3347
|
+
useSongSearchGroup,
|
|
3348
|
+
useGenreRemoteSearchGroup,
|
|
3297
3349
|
GenreSearch,
|
|
3298
3350
|
GenreNodeActionBand,
|
|
3299
3351
|
GenreInfoPanelBody,
|
|
@@ -3309,4 +3361,4 @@ export {
|
|
|
3309
3361
|
GenreTreeViewSkeleton2 as GenreTreeViewSkeleton,
|
|
3310
3362
|
GenreTreeOutlineSkeleton
|
|
3311
3363
|
};
|
|
3312
|
-
//# sourceMappingURL=chunk-
|
|
3364
|
+
//# sourceMappingURL=chunk-FHGQGTCN.js.map
|