@behindthemusictree/app-kit-ui 34.0.0 → 34.1.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.
@@ -5,7 +5,7 @@ import {
5
5
  } from "./chunk-DKQQLLMY.js";
6
6
 
7
7
  // src/genre-tree/GenreTreeView.tsx
8
- import { useCallback as useCallback6, useDeferredValue, useEffect as useEffect5, useMemo as useMemo7, useRef as useRef3, useState as useState8 } from "react";
8
+ import { useCallback as useCallback6, useDeferredValue as useDeferredValue2, useEffect as useEffect5, useMemo as useMemo7, useRef as useRef3, useState as useState9 } from "react";
9
9
  import { useIsMutating } from "@tanstack/react-query";
10
10
  import { Plus as Plus2 } from "lucide-react";
11
11
  import { Maximize2, Minimize2 } from "lucide-react";
@@ -465,6 +465,9 @@ function GenreTreeWheelHandoff({ skeleton, children, onRevealedChange }) {
465
465
  ] });
466
466
  }
467
467
 
468
+ // src/genre-tree/GenreTreeSearch.tsx
469
+ import { useDeferredValue, useState as useState3 } from "react";
470
+
468
471
  // src/genre-tree/GenreSearch.tsx
469
472
  import { ArrowLeft } from "lucide-react";
470
473
  import { SEARCH_LEADING_BUTTON_CLASS } from "@behindthemusictree/ui";
@@ -670,6 +673,44 @@ function GenreSearch({
670
673
  ) });
671
674
  }
672
675
 
676
+ // src/genre-tree/GenreTreeSearch.tsx
677
+ import { jsx as jsx9 } from "react/jsx-runtime";
678
+ function GenreTreeSearch({
679
+ artistBaseUrl,
680
+ songBaseUrl,
681
+ onArtistSelect,
682
+ onSongSelect,
683
+ artistSearch,
684
+ songSearch,
685
+ SearchGroups,
686
+ extraGroups = [],
687
+ onQueryChange,
688
+ onFocus,
689
+ ...props
690
+ }) {
691
+ const [query, setQuery] = useState3("");
692
+ const [focused, setFocused] = useState3(false);
693
+ const deferredQuery = useDeferredValue(query);
694
+ const artistGroup = useArtistSearchGroup(artistBaseUrl, deferredQuery, onArtistSelect, artistSearch);
695
+ const songGroup = useSongSearchGroup(songBaseUrl, deferredQuery, onSongSelect, songSearch);
696
+ const render = (hostGroups) => /* @__PURE__ */ jsx9(
697
+ GenreSearch,
698
+ {
699
+ ...props,
700
+ onQueryChange: (text) => {
701
+ setQuery(text);
702
+ onQueryChange?.(text);
703
+ },
704
+ onFocus: () => {
705
+ setFocused(true);
706
+ onFocus?.();
707
+ },
708
+ extraGroups: [...extraGroups, ...hostGroups, artistGroup, songGroup].filter((group) => group !== void 0)
709
+ }
710
+ );
711
+ return SearchGroups ? /* @__PURE__ */ jsx9(SearchGroups, { query: deferredQuery, focused, children: render }) : render([]);
712
+ }
713
+
673
714
  // src/genre-tree/GenreInfoPanelBody.tsx
674
715
  import {
675
716
  genreMusicCount,
@@ -687,18 +728,18 @@ import { Share2 as Share22 } from "lucide-react";
687
728
  import { usePopup as usePopup3 } from "@behindthemusictree/app-kit/popup";
688
729
 
689
730
  // src/genre-tree/SharePopup.tsx
690
- import { useCallback as useCallback5, useEffect as useEffect2, useMemo as useMemo5, useState as useState3 } from "react";
731
+ import { useCallback as useCallback5, useEffect as useEffect2, useMemo as useMemo5, useState as useState4 } from "react";
691
732
  import { Link2, Share2 } from "lucide-react";
692
733
  import { FaWhatsapp } from "react-icons/fa";
693
734
  import { SiGmail } from "react-icons/si";
694
735
 
695
736
  // src/genre-tree/ShareDestinationButton.tsx
696
- import { Fragment as Fragment4, jsx as jsx9, jsxs as jsxs6 } from "react/jsx-runtime";
737
+ import { Fragment as Fragment4, jsx as jsx10, jsxs as jsxs6 } from "react/jsx-runtime";
697
738
  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";
698
739
  function Contents({ icon, label }) {
699
740
  return /* @__PURE__ */ jsxs6(Fragment4, { children: [
700
- /* @__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 }),
701
- /* @__PURE__ */ jsx9("span", { className: "max-w-full truncate", children: label })
741
+ /* @__PURE__ */ jsx10("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 }),
742
+ /* @__PURE__ */ jsx10("span", { className: "max-w-full truncate", children: label })
702
743
  ] });
703
744
  }
704
745
  function ShareDestinationButton({
@@ -710,29 +751,29 @@ function ShareDestinationButton({
710
751
  ariaLabel
711
752
  }) {
712
753
  if (href) {
713
- return /* @__PURE__ */ jsx9("a", { href, target: "_blank", rel: "noopener noreferrer", "aria-label": ariaLabel, className, children: /* @__PURE__ */ jsx9(Contents, { icon, label }) });
754
+ return /* @__PURE__ */ jsx10("a", { href, target: "_blank", rel: "noopener noreferrer", "aria-label": ariaLabel, className, children: /* @__PURE__ */ jsx10(Contents, { icon, label }) });
714
755
  }
715
- return /* @__PURE__ */ jsx9("button", { type: "button", onClick, disabled, "aria-label": ariaLabel, className, children: /* @__PURE__ */ jsx9(Contents, { icon, label }) });
756
+ return /* @__PURE__ */ jsx10("button", { type: "button", onClick, disabled, "aria-label": ariaLabel, className, children: /* @__PURE__ */ jsx10(Contents, { icon, label }) });
716
757
  }
717
758
 
718
759
  // src/genre-tree/SharePreviewCard.tsx
719
760
  import { Music, Music2, UserRound } from "lucide-react";
720
- import { jsx as jsx10, jsxs as jsxs7 } from "react/jsx-runtime";
761
+ import { jsx as jsx11, jsxs as jsxs7 } from "react/jsx-runtime";
721
762
  function SharePreviewCard({ target, url }) {
722
763
  const Icon = { genre: Music2, artist: UserRound, song: Music }[target.kind];
723
764
  const typeLabel = { genre: "Genre", artist: "Artist", song: "Song" }[target.kind];
724
- 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: [
725
- /* @__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" }) }),
765
+ return /* @__PURE__ */ jsx11("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: [
766
+ /* @__PURE__ */ jsx11("div", { className: "flex w-28 shrink-0 items-center justify-center bg-[var(--color-primary)]/15 text-[var(--color-primary)]", children: /* @__PURE__ */ jsx11(Icon, { "aria-hidden": "true", className: "h-10 w-10" }) }),
726
767
  /* @__PURE__ */ jsxs7("div", { className: "flex min-w-0 flex-1 flex-col justify-center gap-1 p-4", children: [
727
- /* @__PURE__ */ jsx10("span", { className: "text-xs font-medium uppercase tracking-wide text-[var(--color-text-muted)]", children: typeLabel }),
728
- /* @__PURE__ */ jsx10("span", { className: "truncate text-base font-semibold text-[var(--color-text)]", title: target.name, children: target.name }),
729
- /* @__PURE__ */ jsx10("span", { className: "truncate text-sm text-[var(--color-primary)]", title: url, children: url })
768
+ /* @__PURE__ */ jsx11("span", { className: "text-xs font-medium uppercase tracking-wide text-[var(--color-text-muted)]", children: typeLabel }),
769
+ /* @__PURE__ */ jsx11("span", { className: "truncate text-base font-semibold text-[var(--color-text)]", title: target.name, children: target.name }),
770
+ /* @__PURE__ */ jsx11("span", { className: "truncate text-sm text-[var(--color-primary)]", title: url, children: url })
730
771
  ] })
731
772
  ] }) });
732
773
  }
733
774
 
734
775
  // src/genre-tree/SharePopup.tsx
735
- import { Fragment as Fragment5, jsx as jsx11, jsxs as jsxs8 } from "react/jsx-runtime";
776
+ import { Fragment as Fragment5, jsx as jsx12, jsxs as jsxs8 } from "react/jsx-runtime";
736
777
  function resolveAbsoluteUrl(url) {
737
778
  try {
738
779
  const parsed = new URL(url, window.location.href);
@@ -765,11 +806,11 @@ async function copyText(text) {
765
806
  }
766
807
  }
767
808
  function SharePopup({ target, url, onClose }) {
768
- const [absoluteUrl, setAbsoluteUrl] = useState3(url);
769
- const [copyStatus, setCopyStatus] = useState3("idle");
770
- const [canUseNativeShare, setCanUseNativeShare] = useState3(false);
771
- const [shareError, setShareError] = useState3(null);
772
- const [toastId, setToastId] = useState3(0);
809
+ const [absoluteUrl, setAbsoluteUrl] = useState4(url);
810
+ const [copyStatus, setCopyStatus] = useState4("idle");
811
+ const [canUseNativeShare, setCanUseNativeShare] = useState4(false);
812
+ const [shareError, setShareError] = useState4(null);
813
+ const [toastId, setToastId] = useState4(0);
773
814
  useEffect2(() => {
774
815
  setAbsoluteUrl(resolveAbsoluteUrl(url) ?? "");
775
816
  setCopyStatus("idle");
@@ -808,7 +849,7 @@ function SharePopup({ target, url, onClose }) {
808
849
  }
809
850
  };
810
851
  return /* @__PURE__ */ jsxs8(Fragment5, { children: [
811
- /* @__PURE__ */ jsx11(
852
+ /* @__PURE__ */ jsx12(
812
853
  BasePopup_default,
813
854
  {
814
855
  title: "Share",
@@ -824,64 +865,64 @@ function SharePopup({ target, url, onClose }) {
824
865
  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)]",
825
866
  contentClassName: "!rounded-none !bg-transparent !px-6 !pb-6 !pt-2",
826
867
  children: /* @__PURE__ */ jsxs8("div", { className: "flex flex-col gap-4", children: [
827
- /* @__PURE__ */ jsx11(SharePreviewCard, { target, url: absoluteUrl || url }),
868
+ /* @__PURE__ */ jsx12(SharePreviewCard, { target, url: absoluteUrl || url }),
828
869
  /* @__PURE__ */ jsxs8("div", { className: "grid grid-cols-3 gap-1 rounded-3xl bg-[var(--color-surface)] p-3 sm:grid-cols-4", children: [
829
- /* @__PURE__ */ jsx11(
870
+ /* @__PURE__ */ jsx12(
830
871
  ShareDestinationButton,
831
872
  {
832
873
  label: "Copy Link",
833
- icon: /* @__PURE__ */ jsx11(Link2, { "aria-hidden": "true", className: "h-6 w-6" }),
874
+ icon: /* @__PURE__ */ jsx12(Link2, { "aria-hidden": "true", className: "h-6 w-6" }),
834
875
  onClick: () => void handleCopy(),
835
876
  ariaLabel: "Copy link",
836
877
  disabled: !absoluteUrl
837
878
  }
838
879
  ),
839
- /* @__PURE__ */ jsx11(
880
+ /* @__PURE__ */ jsx12(
840
881
  ShareDestinationButton,
841
882
  {
842
883
  label: "WhatsApp",
843
- icon: /* @__PURE__ */ jsx11(FaWhatsapp, { "aria-hidden": "true", className: "h-9 w-9 text-[#25D366]" }),
884
+ icon: /* @__PURE__ */ jsx12(FaWhatsapp, { "aria-hidden": "true", className: "h-9 w-9 text-[#25D366]" }),
844
885
  href: destinationUrls?.whatsapp,
845
886
  ariaLabel: `Share ${target.name} via WhatsApp`,
846
887
  disabled: !absoluteUrl
847
888
  }
848
889
  ),
849
- /* @__PURE__ */ jsx11(
890
+ /* @__PURE__ */ jsx12(
850
891
  ShareDestinationButton,
851
892
  {
852
893
  label: "Gmail",
853
- icon: /* @__PURE__ */ jsx11(SiGmail, { "aria-hidden": "true", className: "h-8 w-8 text-[#EA4335]" }),
894
+ icon: /* @__PURE__ */ jsx12(SiGmail, { "aria-hidden": "true", className: "h-8 w-8 text-[#EA4335]" }),
854
895
  href: destinationUrls?.gmail,
855
896
  ariaLabel: `Email ${target.name} with Gmail`,
856
897
  disabled: !absoluteUrl
857
898
  }
858
899
  ),
859
- canUseNativeShare && /* @__PURE__ */ jsx11(
900
+ canUseNativeShare && /* @__PURE__ */ jsx12(
860
901
  ShareDestinationButton,
861
902
  {
862
903
  label: "More",
863
- icon: /* @__PURE__ */ jsx11(Share2, { "aria-hidden": "true", className: "h-6 w-6" }),
904
+ icon: /* @__PURE__ */ jsx12(Share2, { "aria-hidden": "true", className: "h-6 w-6" }),
864
905
  onClick: () => void handleNativeShare(),
865
906
  ariaLabel: "More sharing options",
866
907
  disabled: !absoluteUrl
867
908
  }
868
909
  )
869
910
  ] }),
870
- copyStatus === "failed" && /* @__PURE__ */ jsx11("p", { role: "alert", className: "text-center text-sm text-[var(--color-red-500)]", children: "Could not copy the link." }),
871
- shareError && /* @__PURE__ */ jsx11("p", { role: "alert", className: "text-center text-sm text-[var(--color-red-500)]", children: shareError })
911
+ copyStatus === "failed" && /* @__PURE__ */ jsx12("p", { role: "alert", className: "text-center text-sm text-[var(--color-red-500)]", children: "Could not copy the link." }),
912
+ shareError && /* @__PURE__ */ jsx12("p", { role: "alert", className: "text-center text-sm text-[var(--color-red-500)]", children: shareError })
872
913
  ] })
873
914
  }
874
915
  ),
875
- toastId > 0 && /* @__PURE__ */ jsx11(Toast, { message: "Link copied", onClose: dismissToast }, toastId)
916
+ toastId > 0 && /* @__PURE__ */ jsx12(Toast, { message: "Link copied", onClose: dismissToast }, toastId)
876
917
  ] });
877
918
  }
878
919
 
879
920
  // src/genre-tree/ShareActionButton.tsx
880
- import { jsx as jsx12, jsxs as jsxs9 } from "react/jsx-runtime";
921
+ import { jsx as jsx13, jsxs as jsxs9 } from "react/jsx-runtime";
881
922
  function ShareActionButton({ target, url }) {
882
923
  const { showPopup, hidePopup } = usePopup3();
883
924
  const openSharePopup = () => {
884
- showPopup(/* @__PURE__ */ jsx12(SharePopup, { target, url, onClose: hidePopup }));
925
+ showPopup(/* @__PURE__ */ jsx13(SharePopup, { target, url, onClose: hidePopup }));
885
926
  };
886
927
  return /* @__PURE__ */ jsxs9(
887
928
  "button",
@@ -892,7 +933,7 @@ function ShareActionButton({ target, url }) {
892
933
  "aria-label": `Share ${target.name}`,
893
934
  title: `Share ${target.name}`,
894
935
  children: [
895
- /* @__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" }) }),
936
+ /* @__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)]", children: /* @__PURE__ */ jsx13(Share22, { "aria-hidden": "true", className: "w-5 h-5" }) }),
896
937
  "Share"
897
938
  ]
898
939
  }
@@ -900,7 +941,7 @@ function ShareActionButton({ target, url }) {
900
941
  }
901
942
 
902
943
  // src/genre-tree/GenreActionBand.tsx
903
- import { jsx as jsx13, jsxs as jsxs10 } from "react/jsx-runtime";
944
+ import { jsx as jsx14, jsxs as jsxs10 } from "react/jsx-runtime";
904
945
  function GenreActionBand({
905
946
  node,
906
947
  onPlayPause,
@@ -922,7 +963,7 @@ function GenreActionBand({
922
963
  items.push({
923
964
  key: "play-pause",
924
965
  label: isPlaying ? "Pause" : "Play",
925
- icon: isPlaying ? /* @__PURE__ */ jsx13(Pause, { "aria-hidden": "true", className: "w-5 h-5" }) : /* @__PURE__ */ jsx13(Play, { "aria-hidden": "true", className: "w-5 h-5" }),
966
+ icon: isPlaying ? /* @__PURE__ */ jsx14(Pause, { "aria-hidden": "true", className: "w-5 h-5" }) : /* @__PURE__ */ jsx14(Play, { "aria-hidden": "true", className: "w-5 h-5" }),
926
967
  onClick: onPlayPause
927
968
  });
928
969
  }
@@ -930,24 +971,24 @@ function GenreActionBand({
930
971
  items.push({
931
972
  key: "zoom-in",
932
973
  label: "Focus",
933
- icon: /* @__PURE__ */ jsx13(ZoomIn, { "aria-hidden": "true", className: "w-5 h-5" }),
974
+ icon: /* @__PURE__ */ jsx14(ZoomIn, { "aria-hidden": "true", className: "w-5 h-5" }),
934
975
  onClick: onZoomIn
935
976
  });
936
977
  }
937
978
  if (onAddChild) {
938
- adminItems.push({ key: "add-child", label: "Add", icon: /* @__PURE__ */ jsx13(Plus, { "aria-hidden": "true", className: "w-5 h-5" }), onClick: onAddChild });
979
+ adminItems.push({ key: "add-child", label: "Add", icon: /* @__PURE__ */ jsx14(Plus, { "aria-hidden": "true", className: "w-5 h-5" }), onClick: onAddChild });
939
980
  }
940
981
  if (onRename) {
941
- adminItems.push({ key: "rename", label: "Rename", icon: /* @__PURE__ */ jsx13(Pencil, { "aria-hidden": "true", className: "w-5 h-5" }), onClick: onRename });
982
+ adminItems.push({ key: "rename", label: "Rename", icon: /* @__PURE__ */ jsx14(Pencil, { "aria-hidden": "true", className: "w-5 h-5" }), onClick: onRename });
942
983
  }
943
984
  if (onChangeParent) {
944
- adminItems.push({ key: "change-parent", label: "Parent", icon: /* @__PURE__ */ jsx13(MoveUpRight, { "aria-hidden": "true", className: "w-5 h-5" }), onClick: onChangeParent });
985
+ adminItems.push({ key: "change-parent", label: "Parent", icon: /* @__PURE__ */ jsx14(MoveUpRight, { "aria-hidden": "true", className: "w-5 h-5" }), onClick: onChangeParent });
945
986
  }
946
987
  if (onToggleSide) {
947
988
  adminItems.push({
948
989
  key: "toggle-side",
949
990
  label: side === "pop" ? "Make core" : "Make pop",
950
- icon: /* @__PURE__ */ jsx13(ArrowLeftRight, { "aria-hidden": "true", className: "w-5 h-5" }),
991
+ icon: /* @__PURE__ */ jsx14(ArrowLeftRight, { "aria-hidden": "true", className: "w-5 h-5" }),
951
992
  onClick: onToggleSide,
952
993
  disabled: !!toggleSideDisabledReason,
953
994
  title: toggleSideDisabledReason
@@ -972,7 +1013,7 @@ function GenreActionBand({
972
1013
  onClick: item.onClick,
973
1014
  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",
974
1015
  children: [
975
- /* @__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 }),
1016
+ /* @__PURE__ */ jsx14("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 }),
976
1017
  item.label
977
1018
  ]
978
1019
  },
@@ -981,7 +1022,7 @@ function GenreActionBand({
981
1022
  return /* @__PURE__ */ jsxs10("div", { className: "genre-action-band border-b border-[var(--color-border)]", children: [
982
1023
  (items.length > 0 || shareTarget && shareUrl) && /* @__PURE__ */ jsxs10("div", { className: "flex flex-wrap gap-1 px-3.5 py-3", children: [
983
1024
  renderItems(items),
984
- shareTarget && shareUrl && /* @__PURE__ */ jsx13(ShareActionButton, { target: shareTarget, url: shareUrl })
1025
+ shareTarget && shareUrl && /* @__PURE__ */ jsx14(ShareActionButton, { target: shareTarget, url: shareUrl })
985
1026
  ] }),
986
1027
  adminItems.length > 0 && /* @__PURE__ */ jsxs10(
987
1028
  "section",
@@ -989,8 +1030,8 @@ function GenreActionBand({
989
1030
  "aria-label": "Admin actions",
990
1031
  className: `px-3.5 py-3 ${items.length > 0 ? "border-t border-[var(--color-border)]" : ""}`,
991
1032
  children: [
992
- /* @__PURE__ */ jsx13("h3", { className: "mb-2 text-xs font-semibold uppercase tracking-wide text-[var(--color-text-muted)]", children: "Admin" }),
993
- /* @__PURE__ */ jsx13("div", { className: "flex flex-wrap gap-1", children: renderItems(adminItems) })
1033
+ /* @__PURE__ */ jsx14("h3", { className: "mb-2 text-xs font-semibold uppercase tracking-wide text-[var(--color-text-muted)]", children: "Admin" }),
1034
+ /* @__PURE__ */ jsx14("div", { className: "flex flex-wrap gap-1", children: renderItems(adminItems) })
994
1035
  ]
995
1036
  }
996
1037
  )
@@ -1002,20 +1043,20 @@ import { PanelSection as PanelSection2, Skeleton as Skeleton2 } from "@behindthe
1002
1043
  import { useFetchGenreOverview } from "@behindthemusictree/app-kit/genre-tree";
1003
1044
 
1004
1045
  // src/genre-tree/ClampedText.tsx
1005
- import { useLayoutEffect, useRef as useRef2, useState as useState4 } from "react";
1006
- import { Fragment as Fragment6, jsx as jsx14, jsxs as jsxs11 } from "react/jsx-runtime";
1046
+ import { useLayoutEffect, useRef as useRef2, useState as useState5 } from "react";
1047
+ import { Fragment as Fragment6, jsx as jsx15, jsxs as jsxs11 } from "react/jsx-runtime";
1007
1048
  function ClampedText({ children, className: className2 = "" }) {
1008
1049
  const ref = useRef2(null);
1009
- const [expanded, setExpanded] = useState4(false);
1010
- const [overflows, setOverflows] = useState4(false);
1050
+ const [expanded, setExpanded] = useState5(false);
1051
+ const [overflows, setOverflows] = useState5(false);
1011
1052
  useLayoutEffect(() => {
1012
1053
  const element = ref.current;
1013
1054
  if (!element || expanded) return;
1014
1055
  setOverflows(element.scrollHeight > element.clientHeight);
1015
1056
  }, [children, expanded]);
1016
1057
  return /* @__PURE__ */ jsxs11(Fragment6, { children: [
1017
- /* @__PURE__ */ jsx14("p", { ref, className: `${className2} ${expanded ? "" : "line-clamp-3"}`, children }),
1018
- (overflows || expanded) && /* @__PURE__ */ jsx14(
1058
+ /* @__PURE__ */ jsx15("p", { ref, className: `${className2} ${expanded ? "" : "line-clamp-3"}`, children }),
1059
+ (overflows || expanded) && /* @__PURE__ */ jsx15(
1019
1060
  "button",
1020
1061
  {
1021
1062
  type: "button",
@@ -1029,7 +1070,7 @@ function ClampedText({ children, className: className2 = "" }) {
1029
1070
  }
1030
1071
 
1031
1072
  // src/genre-tree/GenrePlaylistTracks.tsx
1032
- import { useEffect as useEffect3, useState as useState5 } from "react";
1073
+ import { useEffect as useEffect3, useState as useState6 } from "react";
1033
1074
  import { useInfiniteQuery } from "@tanstack/react-query";
1034
1075
  import { z } from "zod";
1035
1076
  import { FaPlay, FaPause } from "react-icons/fa";
@@ -1050,15 +1091,15 @@ import { useTrackList as useTrackList2 } from "@behindthemusictree/app-kit/genre
1050
1091
 
1051
1092
  // src/genre-tree/MusicBrainzRecordingLink.tsx
1052
1093
  import { musicBrainzRecordingUrl } from "@behindthemusictree/app-kit/genre-tree";
1053
- import { Fragment as Fragment7, jsx as jsx15 } from "react/jsx-runtime";
1094
+ import { Fragment as Fragment7, jsx as jsx16 } from "react/jsx-runtime";
1054
1095
  function MusicBrainzRecordingLink({
1055
1096
  song,
1056
1097
  children,
1057
1098
  className: className2 = ""
1058
1099
  }) {
1059
1100
  const url = musicBrainzRecordingUrl(song);
1060
- if (!url) return /* @__PURE__ */ jsx15(Fragment7, { children });
1061
- return /* @__PURE__ */ jsx15(
1101
+ if (!url) return /* @__PURE__ */ jsx16(Fragment7, { children });
1102
+ return /* @__PURE__ */ jsx16(
1062
1103
  "a",
1063
1104
  {
1064
1105
  href: url,
@@ -1075,7 +1116,7 @@ function MusicBrainzRecordingLink({
1075
1116
  // src/genre-tree/GenrePlaylistTracks.tsx
1076
1117
  import { ArtistNames } from "@behindthemusictree/app-kit/genre-tree";
1077
1118
  import { capitalize, useTrackNoun } from "@behindthemusictree/app-kit/track-noun";
1078
- import { jsx as jsx16, jsxs as jsxs12 } from "react/jsx-runtime";
1119
+ import { jsx as jsx17, jsxs as jsxs12 } from "react/jsx-runtime";
1079
1120
  var CATALOGUE_PAGE_SIZE = 100;
1080
1121
  var SongPageSchema = PaginatedResponseSchema(SongDetailedSchema).extend({
1081
1122
  overallTotal: z.number().nullable(),
@@ -1131,7 +1172,7 @@ function GenrePlaylistTracks({
1131
1172
  getNextPageParam: (lastPage) => lastPage.nextPage ?? void 0,
1132
1173
  enabled: playback.ready && (scope !== "me" || sessionRestored && !!session?.accessToken)
1133
1174
  });
1134
- const [sentinel, setSentinel] = useState5(null);
1175
+ const [sentinel, setSentinel] = useState6(null);
1135
1176
  useEffect3(() => {
1136
1177
  if (!hasNextPage || isFetchingNextPage || !sentinel) return;
1137
1178
  const observer = new IntersectionObserver((entries) => {
@@ -1154,27 +1195,27 @@ function GenrePlaylistTracks({
1154
1195
  }) : scope === "reference" ? playNewTrackListFromGenreCatalogue({ uuid: genreUuid, name: genrePlaylist.name }, scope, { startSongUuid, ...selection && { selection } }) : playNewTrackListFromGenrePlaylist(genrePlaylist, scope, { startSongUuid });
1155
1196
  started.catch((error) => {
1156
1197
  console.error("Failed to play genre playlist:", error);
1157
- showPopup(/* @__PURE__ */ jsx16(InternalErrorPopup, { errorCode: ErrorCode3.CLIENT_UNKNOWN }));
1198
+ showPopup(/* @__PURE__ */ jsx17(InternalErrorPopup, { errorCode: ErrorCode3.CLIENT_UNKNOWN }));
1158
1199
  });
1159
1200
  };
1160
- return /* @__PURE__ */ jsx16(PanelSection, { title: `${capitalize(trackNoun.plural)}${total !== void 0 ? ` (${total})` : ""}`, children: /* @__PURE__ */ jsxs12("div", { children: [
1201
+ return /* @__PURE__ */ jsx17(PanelSection, { title: `${capitalize(trackNoun.plural)}${total !== void 0 ? ` (${total})` : ""}`, children: /* @__PURE__ */ jsxs12("div", { children: [
1161
1202
  renderTracksToolbar?.(),
1162
- isPending ? /* @__PURE__ */ jsx16(Skeleton, { className: "h-4 w-3/4", "aria-busy": "true" }) : isError && tracks.length === 0 ? /* @__PURE__ */ jsxs12("p", { role: "alert", children: [
1203
+ isPending ? /* @__PURE__ */ jsx17(Skeleton, { className: "h-4 w-3/4", "aria-busy": "true" }) : isError && tracks.length === 0 ? /* @__PURE__ */ jsxs12("p", { role: "alert", children: [
1163
1204
  "Couldn't load ",
1164
1205
  trackNoun.plural,
1165
1206
  ".",
1166
1207
  " ",
1167
- /* @__PURE__ */ jsx16("button", { type: "button", className: "underline", onClick: () => void refetch(), children: "Retry" })
1168
- ] }) : 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: [
1208
+ /* @__PURE__ */ jsx17("button", { type: "button", className: "underline", onClick: () => void refetch(), children: "Retry" })
1209
+ ] }) : tracks.length === 0 ? /* @__PURE__ */ jsx17("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: [
1169
1210
  tracks.map((track, index) => {
1170
1211
  const label = track.artists?.length ? `${track.title} \u2014 ${track.artists.map((artist2) => artist2.name).join(", ")}` : track.title;
1171
1212
  const isCurrent = playerTrackObject?.track.id === track.uuid;
1172
1213
  const isPlaying = isCurrent && playState === PlayStates.PLAYING;
1173
1214
  const text = /* @__PURE__ */ jsxs12("span", { className: TEXT_CELL, children: [
1174
- /* @__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 }),
1175
- track.artists?.length ? /* @__PURE__ */ jsx16("span", { className: SEPARATOR, children: " \u2014 " }) : null,
1176
- /* @__PURE__ */ jsx16("span", { className: COLUMN_CELL, children: track.artists?.length ? /* @__PURE__ */ jsx16(ArtistNames, { artists: track.artists, renderArtistLink }) : null }),
1177
- track.album && /* @__PURE__ */ jsx16("span", { className: ALBUM_CELL, children: track.album.name })
1215
+ /* @__PURE__ */ jsx17("span", { className: TITLE_CELL, children: renderSongLink ? renderSongLink(track) : isSong(track) ? /* @__PURE__ */ jsx17(MusicBrainzRecordingLink, { song: track, className: "hover:underline focus-visible:underline", children: track.title }) : track.title }),
1216
+ track.artists?.length ? /* @__PURE__ */ jsx17("span", { className: SEPARATOR, children: " \u2014 " }) : null,
1217
+ /* @__PURE__ */ jsx17("span", { className: COLUMN_CELL, children: track.artists?.length ? /* @__PURE__ */ jsx17(ArtistNames, { artists: track.artists, renderArtistLink }) : null }),
1218
+ track.album && /* @__PURE__ */ jsx17("span", { className: ALBUM_CELL, children: track.album.name })
1178
1219
  ] });
1179
1220
  const leading = renderSongLeading?.(track, index);
1180
1221
  const actions = renderSongActions?.(track);
@@ -1182,7 +1223,7 @@ function GenrePlaylistTracks({
1182
1223
  if (isUnplayable) {
1183
1224
  return /* @__PURE__ */ jsxs12("li", { className: "flex min-h-8 items-center gap-1 px-1 opacity-50", children: [
1184
1225
  leading,
1185
- /* @__PURE__ */ jsx16(
1226
+ /* @__PURE__ */ jsx17(
1186
1227
  "button",
1187
1228
  {
1188
1229
  type: "button",
@@ -1190,7 +1231,7 @@ function GenrePlaylistTracks({
1190
1231
  "aria-disabled": "true",
1191
1232
  "aria-label": label,
1192
1233
  className: "flex h-6 w-6 shrink-0 items-center justify-center rounded-full opacity-0 cursor-not-allowed",
1193
- children: /* @__PURE__ */ jsx16(FaPlay, { size: 10 })
1234
+ children: /* @__PURE__ */ jsx17(FaPlay, { size: 10 })
1194
1235
  }
1195
1236
  ),
1196
1237
  text,
@@ -1203,14 +1244,14 @@ function GenrePlaylistTracks({
1203
1244
  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)]" : ""}`,
1204
1245
  children: [
1205
1246
  leading,
1206
- /* @__PURE__ */ jsx16(
1247
+ /* @__PURE__ */ jsx17(
1207
1248
  "button",
1208
1249
  {
1209
1250
  type: "button",
1210
1251
  "aria-label": `${isPlaying ? "Pause" : "Play"} ${label}`,
1211
1252
  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"}`,
1212
1253
  onClick: () => isCurrent ? handlePlayPauseAction() : play(track.uuid),
1213
- children: isCurrent && playState === PlayStates.LOADING ? /* @__PURE__ */ jsx16(RingLoader, { size: 10 }) : isPlaying ? /* @__PURE__ */ jsx16(FaPause, { size: 10 }) : /* @__PURE__ */ jsx16(FaPlay, { size: 10 })
1254
+ children: isCurrent && playState === PlayStates.LOADING ? /* @__PURE__ */ jsx17(RingLoader, { size: 10 }) : isPlaying ? /* @__PURE__ */ jsx17(FaPause, { size: 10 }) : /* @__PURE__ */ jsx17(FaPlay, { size: 10 })
1214
1255
  }
1215
1256
  ),
1216
1257
  text,
@@ -1220,7 +1261,7 @@ function GenrePlaylistTracks({
1220
1261
  track.uuid
1221
1262
  );
1222
1263
  }),
1223
- hasNextPage && /* @__PURE__ */ jsx16("li", { ref: setSentinel, "aria-hidden": "true", className: "h-4" })
1264
+ hasNextPage && /* @__PURE__ */ jsx17("li", { ref: setSentinel, "aria-hidden": "true", className: "h-4" })
1224
1265
  ] })
1225
1266
  ] }) });
1226
1267
  }
@@ -1228,7 +1269,7 @@ function GenrePlaylistTracks({
1228
1269
  // src/genre-tree/GenreDetailExtras.tsx
1229
1270
  import { useTrackNoun as useTrackNoun2 } from "@behindthemusictree/app-kit/track-noun";
1230
1271
  import { SiWikidata, SiWikipedia } from "react-icons/si";
1231
- import { Fragment as Fragment8, jsx as jsx17, jsxs as jsxs13 } from "react/jsx-runtime";
1272
+ import { Fragment as Fragment8, jsx as jsx18, jsxs as jsxs13 } from "react/jsx-runtime";
1232
1273
  function GenreDetailExtras({
1233
1274
  genreUuid,
1234
1275
  genrePlaylist,
@@ -1254,15 +1295,15 @@ function GenreDetailExtras({
1254
1295
  );
1255
1296
  if (isPending) {
1256
1297
  return /* @__PURE__ */ jsxs13(Fragment8, { children: [
1257
- /* @__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" }) }) }),
1298
+ /* @__PURE__ */ jsx18(PanelSection2, { title: "Summary", children: /* @__PURE__ */ jsx18("div", { "aria-busy": "true", "data-testid": "genre-detail-extras-skeleton", children: /* @__PURE__ */ jsx18(Skeleton2, { className: "h-4 w-3/4" }) }) }),
1258
1299
  family
1259
1300
  ] });
1260
1301
  }
1261
- if (!overview) return /* @__PURE__ */ jsx17(Fragment8, { children: family });
1302
+ if (!overview) return /* @__PURE__ */ jsx18(Fragment8, { children: family });
1262
1303
  const { summary, summarySourceUrl, essentialSongs } = overview;
1263
1304
  const wikidataUrl = wikidataId ? `https://www.wikidata.org/wiki/${encodeURIComponent(wikidataId)}` : null;
1264
1305
  return /* @__PURE__ */ jsxs13(Fragment8, { children: [
1265
- (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: [
1306
+ (summarySourceUrl || wikidataUrl) && /* @__PURE__ */ jsx18(PanelSection2, { title: "Links", children: /* @__PURE__ */ jsxs13("div", { className: "flex flex-wrap gap-x-3 gap-y-1 text-xs text-[var(--color-text)]", children: [
1266
1307
  summarySourceUrl && /* @__PURE__ */ jsxs13(
1267
1308
  "a",
1268
1309
  {
@@ -1271,7 +1312,7 @@ function GenreDetailExtras({
1271
1312
  rel: "noopener noreferrer",
1272
1313
  className: "inline-flex items-center gap-1.5 text-[var(--color-text-muted)] hover:text-[var(--color-text)]",
1273
1314
  children: [
1274
- /* @__PURE__ */ jsx17(SiWikipedia, { "aria-hidden": "true", className: "h-3.5 w-3.5" }),
1315
+ /* @__PURE__ */ jsx18(SiWikipedia, { "aria-hidden": "true", className: "h-3.5 w-3.5" }),
1275
1316
  "Wikipedia"
1276
1317
  ]
1277
1318
  }
@@ -1284,17 +1325,17 @@ function GenreDetailExtras({
1284
1325
  rel: "noopener noreferrer",
1285
1326
  className: "inline-flex items-center gap-1.5 text-[var(--color-text-muted)] hover:text-[var(--color-text)]",
1286
1327
  children: [
1287
- /* @__PURE__ */ jsx17(SiWikidata, { "aria-hidden": "true", className: "h-3.5 w-3.5" }),
1328
+ /* @__PURE__ */ jsx18(SiWikidata, { "aria-hidden": "true", className: "h-3.5 w-3.5" }),
1288
1329
  "Wikidata"
1289
1330
  ]
1290
1331
  }
1291
1332
  )
1292
1333
  ] }) }),
1293
- /* @__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) }),
1334
+ /* @__PURE__ */ jsx18(PanelSection2, { title: "Summary", children: renderSummary ? renderSummary(overview) : /* @__PURE__ */ jsx18(ClampedText, { className: "text-[0.8125rem] leading-[1.45] text-[var(--color-text)]", children: summary ?? "\u2014" }, genreUuid) }),
1294
1335
  family,
1295
1336
  renderGenreDetailExtras?.(overview),
1296
- (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" }) }),
1297
- /* @__PURE__ */ jsx17(
1337
+ (renderEssentialTracks || essentialSongs) && /* @__PURE__ */ jsx18(PanelSection2, { title: `Essential ${trackNoun.plural}`, children: renderEssentialTracks ? renderEssentialTracks(overview) : essentialSongs && essentialSongs.length > 0 ? /* @__PURE__ */ jsx18("ul", { className: "text-[0.8125rem] leading-[1.45] text-[var(--color-text)]", children: essentialSongs.map((track) => /* @__PURE__ */ jsx18("li", { className: "py-1", children: track.title }, track.uuid)) }) : /* @__PURE__ */ jsx18("p", { className: "text-[0.8125rem] leading-[1.45] text-[var(--color-text)]", children: "\u2014" }) }),
1338
+ /* @__PURE__ */ jsx18(
1298
1339
  GenrePlaylistTracks,
1299
1340
  {
1300
1341
  genreUuid,
@@ -1311,7 +1352,7 @@ function GenreDetailExtras({
1311
1352
  }
1312
1353
 
1313
1354
  // src/genre-tree/GenreInfoPanelBody.tsx
1314
- import { Fragment as Fragment9, jsx as jsx18, jsxs as jsxs14 } from "react/jsx-runtime";
1355
+ import { Fragment as Fragment9, jsx as jsx19, jsxs as jsxs14 } from "react/jsx-runtime";
1315
1356
  import { createElement } from "react";
1316
1357
  function GenreNodeActionBand({ genrePlaylist, playback, ...bandProps }) {
1317
1358
  const { isPlaying, setIsPlaying } = usePlayer5();
@@ -1325,7 +1366,7 @@ function GenreNodeActionBand({ genrePlaylist, playback, ...bandProps }) {
1325
1366
  console.error("Failed to load genre playlist tracks:", error);
1326
1367
  });
1327
1368
  };
1328
- return /* @__PURE__ */ jsx18(
1369
+ return /* @__PURE__ */ jsx19(
1329
1370
  GenreActionBand,
1330
1371
  {
1331
1372
  ...bandProps,
@@ -1356,7 +1397,7 @@ function GenreInfoPanelBody({
1356
1397
  };
1357
1398
  return /* @__PURE__ */ jsxs14(Fragment9, { children: [
1358
1399
  toolbar,
1359
- /* @__PURE__ */ jsx18(GenreNodeActionBand, { ...band, genrePlaylist, playback }),
1400
+ /* @__PURE__ */ jsx19(GenreNodeActionBand, { ...band, genrePlaylist, playback }),
1360
1401
  summary && catalogue && /* @__PURE__ */ jsxs14("div", { className: "px-3.5 py-3 text-sm text-[var(--color-text)]", children: [
1361
1402
  /* @__PURE__ */ jsxs14("p", { children: [
1362
1403
  "Catalogue ",
@@ -1394,7 +1435,7 @@ import {
1394
1435
  getReparentCandidates,
1395
1436
  useUpdateGenre
1396
1437
  } from "@behindthemusictree/app-kit/genre-tree";
1397
- import { jsx as jsx19, jsxs as jsxs15 } from "react/jsx-runtime";
1438
+ import { jsx as jsx20, jsxs as jsxs15 } from "react/jsx-runtime";
1398
1439
  function ChangeParentPopup({
1399
1440
  genrePlaylist,
1400
1441
  genrePlaylists,
@@ -1434,7 +1475,7 @@ function ChangeParentPopup({
1434
1475
  "Current parent: ",
1435
1476
  genrePlaylist.parent?.name ?? "none"
1436
1477
  ] }),
1437
- /* @__PURE__ */ jsx19("div", { "aria-busy": isPending, className: isPending ? "pointer-events-none opacity-60" : void 0, children: /* @__PURE__ */ jsx19(
1478
+ /* @__PURE__ */ jsx20("div", { "aria-busy": isPending, className: isPending ? "pointer-events-none opacity-60" : void 0, children: /* @__PURE__ */ jsx20(
1438
1479
  GenreSearch,
1439
1480
  {
1440
1481
  genrePlaylists: candidates,
@@ -1442,7 +1483,7 @@ function ChangeParentPopup({
1442
1483
  placeholder: "Search a new parent\u2026"
1443
1484
  }
1444
1485
  ) }),
1445
- formErrors.length > 0 && /* @__PURE__ */ jsx19("p", { role: "alert", className: "mt-3 text-sm text-[var(--color-red-500)]", children: formErrors.map(({ message }) => message).join(" ") })
1486
+ formErrors.length > 0 && /* @__PURE__ */ jsx20("p", { role: "alert", className: "mt-3 text-sm text-[var(--color-red-500)]", children: formErrors.map(({ message }) => message).join(" ") })
1446
1487
  ] });
1447
1488
  }
1448
1489
 
@@ -1466,7 +1507,7 @@ import {
1466
1507
  SiYoutube
1467
1508
  } from "react-icons/si";
1468
1509
  import { Chip } from "@behindthemusictree/ui";
1469
- import { jsx as jsx20 } from "react/jsx-runtime";
1510
+ import { jsx as jsx21 } from "react/jsx-runtime";
1470
1511
  var LINK_KINDS = {
1471
1512
  official: { label: "Official website", Icon: Globe },
1472
1513
  wikipedia: { label: "Wikipedia", Icon: SiWikipedia2 },
@@ -1503,7 +1544,7 @@ function artistLinks(artist) {
1503
1544
  return links;
1504
1545
  }
1505
1546
  function ArtistLinks({ links }) {
1506
- 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)) });
1547
+ return /* @__PURE__ */ jsx21("ul", { className: "flex flex-wrap gap-1.5", children: links.map(({ key, url, Icon, label }) => /* @__PURE__ */ jsx21("li", { children: /* @__PURE__ */ jsx21(Chip, { href: url, icon: /* @__PURE__ */ jsx21(Icon, { className: "h-3.5 w-3.5 shrink-0", "aria-hidden": "true" }), children: label }) }, key)) });
1507
1548
  }
1508
1549
 
1509
1550
  // src/genre-tree/artist/formatYears.ts
@@ -1514,7 +1555,7 @@ function formatYears(beginYear, endYear, ended) {
1514
1555
  }
1515
1556
 
1516
1557
  // src/genre-tree/artist/ArtistHeader.tsx
1517
- import { jsx as jsx21 } from "react/jsx-runtime";
1558
+ import { jsx as jsx22 } from "react/jsx-runtime";
1518
1559
  var countryNames = new Intl.DisplayNames(["en"], { type: "region" });
1519
1560
  function ArtistHeader({ artist }) {
1520
1561
  const fields = [];
@@ -1524,35 +1565,35 @@ function ArtistHeader({ artist }) {
1524
1565
  const years = formatYears(artist.beginYear, artist.endYear, artist.ended);
1525
1566
  if (years) fields.push({ label: "Active", value: years });
1526
1567
  const links = artistLinks(artist);
1527
- if (links.length > 0) fields.push({ label: "Links", value: /* @__PURE__ */ jsx21(ArtistLinks, { links }) });
1568
+ if (links.length > 0) fields.push({ label: "Links", value: /* @__PURE__ */ jsx22(ArtistLinks, { links }) });
1528
1569
  if (fields.length === 0) return null;
1529
- return /* @__PURE__ */ jsx21(FieldList, { items: fields });
1570
+ return /* @__PURE__ */ jsx22(FieldList, { items: fields });
1530
1571
  }
1531
1572
 
1532
1573
  // src/genre-tree/artist/ArtistPhoto.tsx
1533
- import { jsx as jsx22, jsxs as jsxs16 } from "react/jsx-runtime";
1574
+ import { jsx as jsx23, jsxs as jsxs16 } from "react/jsx-runtime";
1534
1575
  function ExternalLink({ href, children }) {
1535
- return /* @__PURE__ */ jsx22("a", { href, target: "_blank", rel: "noopener noreferrer", className: "underline-offset-2 hover:underline", children });
1576
+ return /* @__PURE__ */ jsx23("a", { href, target: "_blank", rel: "noopener noreferrer", className: "underline-offset-2 hover:underline", children });
1536
1577
  }
1537
1578
  function ArtistPhoto({ image, name }) {
1538
1579
  return /* @__PURE__ */ jsxs16("figure", { className: "flex flex-col gap-1.5 px-6 py-2.5", children: [
1539
- /* @__PURE__ */ jsx22("img", { src: image.url, alt: name, className: "h-64 w-full object-contain bg-[var(--color-surface-muted)] rounded" }),
1580
+ /* @__PURE__ */ jsx23("img", { src: image.url, alt: name, className: "h-64 w-full object-contain bg-[var(--color-surface-muted)] rounded" }),
1540
1581
  /* @__PURE__ */ jsxs16("figcaption", { className: "text-xs text-[var(--color-text-muted)]", children: [
1541
1582
  "Photo: ",
1542
- /* @__PURE__ */ jsx22(ExternalLink, { href: image.pageUrl, children: image.author ?? "Wikimedia Commons" }),
1583
+ /* @__PURE__ */ jsx23(ExternalLink, { href: image.pageUrl, children: image.author ?? "Wikimedia Commons" }),
1543
1584
  ",",
1544
1585
  " ",
1545
- image.licenseUrl ? /* @__PURE__ */ jsx22(ExternalLink, { href: image.licenseUrl, children: image.license }) : image.license
1586
+ image.licenseUrl ? /* @__PURE__ */ jsx23(ExternalLink, { href: image.licenseUrl, children: image.license }) : image.license
1546
1587
  ] })
1547
1588
  ] });
1548
1589
  }
1549
1590
 
1550
1591
  // src/genre-tree/artist/ArtistMembers.tsx
1551
1592
  import { PanelGroup, PanelSection as PanelSection3 } from "@behindthemusictree/ui";
1552
- import { jsx as jsx23, jsxs as jsxs17 } from "react/jsx-runtime";
1593
+ import { jsx as jsx24, jsxs as jsxs17 } from "react/jsx-runtime";
1553
1594
  function MembershipList({ title, memberships, renderArtistLink }) {
1554
1595
  if (memberships.length === 0) return null;
1555
- return /* @__PURE__ */ jsx23(PanelGroup, { title, children: /* @__PURE__ */ jsx23("ul", { children: memberships.map((membership, index) => {
1596
+ return /* @__PURE__ */ jsx24(PanelGroup, { title, children: /* @__PURE__ */ jsx24("ul", { children: memberships.map((membership, index) => {
1556
1597
  const details = [
1557
1598
  formatYears(membership.beginYear, membership.endYear, membership.ended),
1558
1599
  ...membership.roles
@@ -1561,7 +1602,7 @@ function MembershipList({ title, memberships, renderArtistLink }) {
1561
1602
  return (
1562
1603
  // A member can have several periods in the same group.
1563
1604
  /* @__PURE__ */ jsxs17("li", { className: "truncate py-0.5", title: detailsText || void 0, children: [
1564
- /* @__PURE__ */ jsx23("span", { className: "font-medium text-[var(--color-text)]", children: renderArtistLink(membership.artist) }),
1605
+ /* @__PURE__ */ jsx24("span", { className: "font-medium text-[var(--color-text)]", children: renderArtistLink(membership.artist) }),
1565
1606
  detailsText && /* @__PURE__ */ jsxs17("span", { className: "text-[var(--color-text-muted)]", children: [
1566
1607
  " \u2014 ",
1567
1608
  detailsText
@@ -1574,8 +1615,8 @@ function ArtistMembers({ title, memberships, renderArtistLink }) {
1574
1615
  if (memberships.length === 0) return null;
1575
1616
  const isCurrent = (membership) => !membership.ended && membership.endYear === null;
1576
1617
  return /* @__PURE__ */ jsxs17(PanelSection3, { title, children: [
1577
- /* @__PURE__ */ jsx23(MembershipList, { title: "Current", memberships: memberships.filter(isCurrent), renderArtistLink }),
1578
- /* @__PURE__ */ jsx23(
1618
+ /* @__PURE__ */ jsx24(MembershipList, { title: "Current", memberships: memberships.filter(isCurrent), renderArtistLink }),
1619
+ /* @__PURE__ */ jsx24(
1579
1620
  MembershipList,
1580
1621
  {
1581
1622
  title: "Past",
@@ -1588,7 +1629,7 @@ function ArtistMembers({ title, memberships, renderArtistLink }) {
1588
1629
 
1589
1630
  // src/genre-tree/artist/ArtistDiscography.tsx
1590
1631
  import { PanelGroup as PanelGroup2, PanelSection as PanelSection4 } from "@behindthemusictree/ui";
1591
- import { jsx as jsx24, jsxs as jsxs18 } from "react/jsx-runtime";
1632
+ import { jsx as jsx25, jsxs as jsxs18 } from "react/jsx-runtime";
1592
1633
  var GROUPS = ["Albums", "EPs", "Singles", "Live", "Compilations", "Other"];
1593
1634
  var PRIMARY_GROUPS = { album: "Albums", ep: "EPs", single: "Singles" };
1594
1635
  function discographyGroup({ primaryType, secondaryTypes }) {
@@ -1608,18 +1649,18 @@ function byYear(a, b) {
1608
1649
  function ArtistDiscography({ albums }) {
1609
1650
  if (albums.length === 0) return null;
1610
1651
  const sorted = [...albums].sort(byYear);
1611
- return /* @__PURE__ */ jsx24(PanelSection4, { title: "Discography", children: GROUPS.map((group) => {
1652
+ return /* @__PURE__ */ jsx25(PanelSection4, { title: "Discography", children: GROUPS.map((group) => {
1612
1653
  const groupAlbums = sorted.filter((album) => discographyGroup(album) === group);
1613
1654
  if (groupAlbums.length === 0) return null;
1614
- 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: [
1615
- /* @__PURE__ */ jsx24("span", { className: "tabular-nums text-[var(--color-text-muted)]", children: album.year ?? "\u2014" }),
1616
- /* @__PURE__ */ jsx24("span", { className: "truncate text-[var(--color-text)]", title: album.name, children: album.name })
1655
+ return /* @__PURE__ */ jsx25(PanelGroup2, { title: group, children: /* @__PURE__ */ jsx25("ul", { children: groupAlbums.map((album) => /* @__PURE__ */ jsxs18("li", { className: "grid grid-cols-[2.5rem_minmax(0,1fr)] gap-2 py-0.5", children: [
1656
+ /* @__PURE__ */ jsx25("span", { className: "tabular-nums text-[var(--color-text-muted)]", children: album.year ?? "\u2014" }),
1657
+ /* @__PURE__ */ jsx25("span", { className: "truncate text-[var(--color-text)]", title: album.name, children: album.name })
1617
1658
  ] }, album.uuid)) }) }, group);
1618
1659
  }) });
1619
1660
  }
1620
1661
 
1621
1662
  // src/genre-tree/artist/ArtistSongs.tsx
1622
- import { useState as useState6 } from "react";
1663
+ import { useState as useState7 } from "react";
1623
1664
  import { keepPreviousData } from "@tanstack/react-query";
1624
1665
  import { Play as Play2 } from "lucide-react";
1625
1666
  import { Pagination, PanelSection as PanelSection5, Skeleton as Skeleton3 } from "@behindthemusictree/ui";
@@ -1640,7 +1681,7 @@ import { useTrackList as useTrackList3 } from "@behindthemusictree/app-kit/genre
1640
1681
  import { FaPlay as FaPlay2, FaPause as FaPause2 } from "react-icons/fa";
1641
1682
  import { usePlayer as usePlayer6 } from "@behindthemusictree/app-kit/player";
1642
1683
  import { PlayStates as PlayStates2 } from "@behindthemusictree/app-kit/player";
1643
- import { jsx as jsx25, jsxs as jsxs19 } from "react/jsx-runtime";
1684
+ import { jsx as jsx26, jsxs as jsxs19 } from "react/jsx-runtime";
1644
1685
  function TrackPositionPlayPause({
1645
1686
  position,
1646
1687
  uuid,
@@ -1661,7 +1702,7 @@ function TrackPositionPlayPause({
1661
1702
  style: { minWidth: "4rem", maxWidth: "4rem" },
1662
1703
  onClick: handlePlayPauseClick,
1663
1704
  children: [
1664
- /* @__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(
1705
+ /* @__PURE__ */ jsx26("div", { className: "track-position-play-pause__status group-hover:hidden flex items-center justify-center", children: isAwaitingPlayback ? /* @__PURE__ */ jsx26("span", { className: "track-position-play-pause__spinner", role: "status", "aria-label": "Loading track" }) : isCurrentTrackActive ? /* @__PURE__ */ jsxs19(
1665
1706
  "span",
1666
1707
  {
1667
1708
  className: "track-position-play-pause__bars",
@@ -1669,18 +1710,18 @@ function TrackPositionPlayPause({
1669
1710
  role: "img",
1670
1711
  "aria-label": isPlaying ? "Playing" : "Paused",
1671
1712
  children: [
1672
- /* @__PURE__ */ jsx25("span", { className: "track-position-play-pause__bar" }),
1673
- /* @__PURE__ */ jsx25("span", { className: "track-position-play-pause__bar" }),
1674
- /* @__PURE__ */ jsx25("span", { className: "track-position-play-pause__bar" })
1713
+ /* @__PURE__ */ jsx26("span", { className: "track-position-play-pause__bar" }),
1714
+ /* @__PURE__ */ jsx26("span", { className: "track-position-play-pause__bar" }),
1715
+ /* @__PURE__ */ jsx26("span", { className: "track-position-play-pause__bar" })
1675
1716
  ]
1676
1717
  }
1677
1718
  ) : position }),
1678
- /* @__PURE__ */ jsx25(
1719
+ /* @__PURE__ */ jsx26(
1679
1720
  "div",
1680
1721
  {
1681
1722
  className: `hidden group-hover:flex items-center justify-center ${isCurrentTrackActive ? "" : "absolute inset-0"}`,
1682
1723
  "aria-hidden": "true",
1683
- children: isAwaitingPlayback ? /* @__PURE__ */ jsx25("span", { className: "track-position-play-pause__spinner" }) : isPlaying ? /* @__PURE__ */ jsx25(FaPause2, {}) : /* @__PURE__ */ jsx25(FaPlay2, {})
1724
+ children: isAwaitingPlayback ? /* @__PURE__ */ jsx26("span", { className: "track-position-play-pause__spinner" }) : isPlaying ? /* @__PURE__ */ jsx26(FaPause2, {}) : /* @__PURE__ */ jsx26(FaPlay2, {})
1684
1725
  }
1685
1726
  )
1686
1727
  ]
@@ -1691,7 +1732,7 @@ function TrackPositionPlayPause({
1691
1732
  // src/genre-tree/track-list-sidebar/TrackItem.tsx
1692
1733
  import { isSong as isSong2, songUnplayableReason as songUnplayableReason2 } from "@behindthemusictree/app-kit/genre-tree";
1693
1734
  import { ArtistNames as ArtistNames2 } from "@behindthemusictree/app-kit/genre-tree";
1694
- import { jsx as jsx26, jsxs as jsxs20 } from "react/jsx-runtime";
1735
+ import { jsx as jsx27, jsxs as jsxs20 } from "react/jsx-runtime";
1695
1736
  function TrackItem({
1696
1737
  track,
1697
1738
  position,
@@ -1720,7 +1761,7 @@ function TrackItem({
1720
1761
  {
1721
1762
  className: `track-item flex h-14 text-[var(--color-text)] ${isUnplayable ? "opacity-50" : "hover:bg-[var(--color-surface-muted)] group"}`,
1722
1763
  children: [
1723
- isUnplayable ? /* @__PURE__ */ jsx26(
1764
+ isUnplayable ? /* @__PURE__ */ jsx27(
1724
1765
  "div",
1725
1766
  {
1726
1767
  className: "flex items-center justify-center text-lg w-16",
@@ -1728,7 +1769,7 @@ function TrackItem({
1728
1769
  "aria-disabled": "true",
1729
1770
  children: position
1730
1771
  }
1731
- ) : /* @__PURE__ */ jsx26(
1772
+ ) : /* @__PURE__ */ jsx27(
1732
1773
  TrackPositionPlayPause,
1733
1774
  {
1734
1775
  position,
@@ -1738,11 +1779,11 @@ function TrackItem({
1738
1779
  }
1739
1780
  ),
1740
1781
  /* @__PURE__ */ jsxs20("div", { className: "title-artist-container flex flex-col items-start justify-center min-w-0 flex-1", children: [
1741
- /* @__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 }) }),
1742
- 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 }) }) : ""
1782
+ /* @__PURE__ */ jsx27("div", { className: "flex max-w-full items-center gap-2", children: /* @__PURE__ */ jsx27("div", { className: "title text-lg font-bold text-[var(--color-text)] max-w-full truncate", children: renderSongLink ? renderSongLink(track) : isSong2(track) ? /* @__PURE__ */ jsx27(MusicBrainzRecordingLink, { song: track, className: "hover:underline focus-visible:underline", children: track.title }) : track.title }) }),
1783
+ track.artists && track.artists.length > 0 ? /* @__PURE__ */ jsx27("div", { className: "artist text-base max-w-full truncate text-[var(--color-text-muted)]", children: /* @__PURE__ */ jsx27(ArtistNames2, { artists: track.artists, renderArtistLink }) }) : ""
1743
1784
  ] }),
1744
- /* @__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 }) : "" }),
1745
- renderDuration && /* @__PURE__ */ jsx26(
1785
+ /* @__PURE__ */ jsx27("div", { className: "genre-name-container flex items-center justify-start w-[21.6%] min-w-0 shrink-0", children: track.genre ? /* @__PURE__ */ jsx27("div", { className: "genre-name max-w-full whitespace-normal break-words p-1 text-xs font-bold", children: track.genre.name }) : "" }),
1786
+ renderDuration && /* @__PURE__ */ jsx27(
1746
1787
  "div",
1747
1788
  {
1748
1789
  className: "duration flex text-base w-16 items-center justify-center",
@@ -1750,22 +1791,22 @@ function TrackItem({
1750
1791
  children: renderDuration(track)
1751
1792
  }
1752
1793
  ),
1753
- renderActions && /* @__PURE__ */ jsx26("div", { className: "edit flex text-base w-6 items-center justify-center mr-2 cursor-pointer", children: renderActions(track) })
1794
+ renderActions && /* @__PURE__ */ jsx27("div", { className: "edit flex text-base w-6 items-center justify-center mr-2 cursor-pointer", children: renderActions(track) })
1754
1795
  ]
1755
1796
  }
1756
1797
  );
1757
1798
  }
1758
1799
 
1759
1800
  // src/genre-tree/artist/ArtistSongs.tsx
1760
- import { Fragment as Fragment10, jsx as jsx27, jsxs as jsxs21 } from "react/jsx-runtime";
1801
+ import { Fragment as Fragment10, jsx as jsx28, jsxs as jsxs21 } from "react/jsx-runtime";
1761
1802
  var SongPageSchema2 = PaginatedResponseSchema2(SongDetailedSchema2);
1762
1803
  var SORTS = [
1763
1804
  { ordering: "title", label: "Title" },
1764
1805
  { ordering: "-albumYear", label: "Year" }
1765
1806
  ];
1766
1807
  function ArtistSongs({ artist, getBackendBaseUrl, renderArtistLink, renderSongLink }) {
1767
- const [page, setPage] = useState6(1);
1768
- const [ordering, setOrdering] = useState6("title");
1808
+ const [page, setPage] = useState7(1);
1809
+ const [ordering, setOrdering] = useState7("title");
1769
1810
  const { fetch } = useFetchWrapper2(getBackendBaseUrl);
1770
1811
  const { playNewTrackListFromArtist } = useTrackList4();
1771
1812
  const { playerTrackObject } = usePlayer8();
@@ -1790,7 +1831,7 @@ function ArtistSongs({ artist, getBackendBaseUrl, renderArtistLink, renderSongLi
1790
1831
  event.stopPropagation();
1791
1832
  void play(song.uuid);
1792
1833
  };
1793
- 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: [
1834
+ return /* @__PURE__ */ jsx28(PanelSection5, { title: "Songs", children: isPending ? /* @__PURE__ */ jsx28(Skeleton3, { className: "h-14", "aria-busy": "true" }) : isError ? /* @__PURE__ */ jsx28("p", { className: "text-red-600", children: "Could not load songs." }) : data.results.length === 0 ? /* @__PURE__ */ jsx28("p", { className: "text-[var(--color-text-muted)]", children: "No songs yet." }) : /* @__PURE__ */ jsxs21(Fragment10, { children: [
1794
1835
  /* @__PURE__ */ jsxs21("div", { className: "flex flex-wrap items-center justify-between gap-2 mb-2", children: [
1795
1836
  /* @__PURE__ */ jsxs21(
1796
1837
  "button",
@@ -1799,12 +1840,12 @@ function ArtistSongs({ artist, getBackendBaseUrl, renderArtistLink, renderSongLi
1799
1840
  onClick: () => void play(),
1800
1841
  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",
1801
1842
  children: [
1802
- /* @__PURE__ */ jsx27(Play2, { className: "h-3.5 w-3.5", "aria-hidden": "true" }),
1843
+ /* @__PURE__ */ jsx28(Play2, { className: "h-3.5 w-3.5", "aria-hidden": "true" }),
1803
1844
  "Play all"
1804
1845
  ]
1805
1846
  }
1806
1847
  ),
1807
- /* @__PURE__ */ jsx27("div", { role: "group", "aria-label": "Sort songs by", className: "flex gap-1 text-xs", children: SORTS.map((sort) => /* @__PURE__ */ jsx27(
1848
+ /* @__PURE__ */ jsx28("div", { role: "group", "aria-label": "Sort songs by", className: "flex gap-1 text-xs", children: SORTS.map((sort) => /* @__PURE__ */ jsx28(
1808
1849
  "button",
1809
1850
  {
1810
1851
  type: "button",
@@ -1819,7 +1860,7 @@ function ArtistSongs({ artist, getBackendBaseUrl, renderArtistLink, renderSongLi
1819
1860
  sort.ordering
1820
1861
  )) })
1821
1862
  ] }),
1822
- /* @__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(
1863
+ /* @__PURE__ */ jsx28("ul", { className: "overflow-hidden mb-2 bg-zinc-950 rounded-lg", children: data.results.map((song, index) => /* @__PURE__ */ jsx28("li", { onClickCapture: (event) => handleRowClickCapture(event, song), children: /* @__PURE__ */ jsx28(
1823
1864
  TrackItem,
1824
1865
  {
1825
1866
  track: song,
@@ -1828,12 +1869,12 @@ function ArtistSongs({ artist, getBackendBaseUrl, renderArtistLink, renderSongLi
1828
1869
  renderSongLink
1829
1870
  }
1830
1871
  ) }, song.uuid)) }),
1831
- /* @__PURE__ */ jsx27(Pagination, { currentPage: page, totalPages: data.totalPages, onPageChange: setPage })
1872
+ /* @__PURE__ */ jsx28(Pagination, { currentPage: page, totalPages: data.totalPages, onPageChange: setPage })
1832
1873
  ] }) });
1833
1874
  }
1834
1875
 
1835
1876
  // src/genre-tree/artist/useArtistPanel.tsx
1836
- import { Fragment as Fragment11, jsx as jsx28, jsxs as jsxs22 } from "react/jsx-runtime";
1877
+ import { Fragment as Fragment11, jsx as jsx29, jsxs as jsxs22 } from "react/jsx-runtime";
1837
1878
  function useArtistPanel({
1838
1879
  uuid,
1839
1880
  scope,
@@ -1855,25 +1896,25 @@ function useArtistPanel({
1855
1896
  ...panel,
1856
1897
  title: "Artist",
1857
1898
  content: /* @__PURE__ */ jsxs22("div", { "aria-busy": "true", className: "flex flex-col gap-2.5 px-6 py-2.5", children: [
1858
- /* @__PURE__ */ jsx28(Skeleton4, { className: "h-3 w-16" }),
1859
- /* @__PURE__ */ jsx28(Skeleton4, { className: "h-4 w-32" }),
1860
- /* @__PURE__ */ jsx28(Skeleton4, { className: "h-3 w-16" }),
1861
- /* @__PURE__ */ jsx28(Skeleton4, { className: "h-4 w-24" }),
1862
- /* @__PURE__ */ jsx28(Skeleton4, { className: "h-16 mt-2.5" }),
1863
- /* @__PURE__ */ jsx28(Skeleton4, { className: "h-16" })
1899
+ /* @__PURE__ */ jsx29(Skeleton4, { className: "h-3 w-16" }),
1900
+ /* @__PURE__ */ jsx29(Skeleton4, { className: "h-4 w-32" }),
1901
+ /* @__PURE__ */ jsx29(Skeleton4, { className: "h-3 w-16" }),
1902
+ /* @__PURE__ */ jsx29(Skeleton4, { className: "h-4 w-24" }),
1903
+ /* @__PURE__ */ jsx29(Skeleton4, { className: "h-16 mt-2.5" }),
1904
+ /* @__PURE__ */ jsx29(Skeleton4, { className: "h-16" })
1864
1905
  ] })
1865
1906
  };
1866
1907
  case "not-found":
1867
1908
  return {
1868
1909
  ...panel,
1869
1910
  title: "Artist not found",
1870
- content: /* @__PURE__ */ jsx28("p", { className: "px-6 py-2.5 text-[var(--color-text-muted)]", children: "This artist does not exist." })
1911
+ content: /* @__PURE__ */ jsx29("p", { className: "px-6 py-2.5 text-[var(--color-text-muted)]", children: "This artist does not exist." })
1871
1912
  };
1872
1913
  case "error":
1873
1914
  return {
1874
1915
  ...panel,
1875
1916
  title: "Artist",
1876
- content: /* @__PURE__ */ jsx28("p", { className: "px-6 py-2.5 text-red-600", children: "Could not load this artist." })
1917
+ content: /* @__PURE__ */ jsx29("p", { className: "px-6 py-2.5 text-red-600", children: "Could not load this artist." })
1877
1918
  };
1878
1919
  case "success": {
1879
1920
  const { artist } = result;
@@ -1883,12 +1924,12 @@ function useArtistPanel({
1883
1924
  ...panel,
1884
1925
  title: artist.name,
1885
1926
  content: /* @__PURE__ */ jsxs22(Fragment11, { children: [
1886
- 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 }) }) }),
1887
- artist.image && /* @__PURE__ */ jsx28(ArtistPhoto, { image: artist.image, name: artist.name }),
1888
- /* @__PURE__ */ jsx28(ArtistHeader, { artist }),
1889
- /* @__PURE__ */ jsx28(ArtistMembers, { title: "Members", memberships: artist.members, renderArtistLink }),
1890
- /* @__PURE__ */ jsx28(ArtistMembers, { title: "Member of", memberships: artist.memberOf, renderArtistLink }),
1891
- artist.tracksCount > 0 && /* @__PURE__ */ jsx28(
1927
+ shareUrl && /* @__PURE__ */ jsx29("div", { className: "genre-action-band border-b border-[var(--color-border)]", children: /* @__PURE__ */ jsx29("div", { className: "flex flex-wrap gap-1 px-3.5 py-3", children: shareTarget && /* @__PURE__ */ jsx29(ShareActionButton, { target: shareTarget, url: shareUrl }) }) }),
1928
+ artist.image && /* @__PURE__ */ jsx29(ArtistPhoto, { image: artist.image, name: artist.name }),
1929
+ /* @__PURE__ */ jsx29(ArtistHeader, { artist }),
1930
+ /* @__PURE__ */ jsx29(ArtistMembers, { title: "Members", memberships: artist.members, renderArtistLink }),
1931
+ /* @__PURE__ */ jsx29(ArtistMembers, { title: "Member of", memberships: artist.memberOf, renderArtistLink }),
1932
+ artist.tracksCount > 0 && /* @__PURE__ */ jsx29(
1892
1933
  ArtistSongs,
1893
1934
  {
1894
1935
  artist: { uuid: artist.uuid, name: artist.name },
@@ -1898,7 +1939,7 @@ function useArtistPanel({
1898
1939
  }
1899
1940
  )
1900
1941
  ] }),
1901
- extraContent: artist.albums.length > 0 ? /* @__PURE__ */ jsx28(ArtistDiscography, { albums: artist.albums }) : void 0
1942
+ extraContent: artist.albums.length > 0 ? /* @__PURE__ */ jsx29(ArtistDiscography, { albums: artist.albums }) : void 0
1902
1943
  };
1903
1944
  }
1904
1945
  }
@@ -1911,7 +1952,7 @@ import {
1911
1952
  } from "@behindthemusictree/app-kit/genre-tree";
1912
1953
 
1913
1954
  // src/genre-tree/song/SongPanelContent.tsx
1914
- import { useState as useState7 } from "react";
1955
+ import { useState as useState8 } from "react";
1915
1956
  import { Pause as Pause2, Play as Play3 } from "lucide-react";
1916
1957
  import { FieldList as FieldList2, PanelSection as PanelSection6, Skeleton as Skeleton5 } from "@behindthemusictree/ui";
1917
1958
  import { PlayStates as PlayStates3, usePlayer as usePlayer9 } from "@behindthemusictree/app-kit/player";
@@ -1922,19 +1963,19 @@ import {
1922
1963
  useSongHistory,
1923
1964
  useTrackList as useTrackList5
1924
1965
  } from "@behindthemusictree/app-kit/genre-tree";
1925
- import { Fragment as Fragment12, jsx as jsx29, jsxs as jsxs23 } from "react/jsx-runtime";
1966
+ import { Fragment as Fragment12, jsx as jsx30, jsxs as jsxs23 } from "react/jsx-runtime";
1926
1967
  var numberFormat = new Intl.NumberFormat("en");
1927
1968
  var dateFormat = new Intl.DateTimeFormat("en", { dateStyle: "medium" });
1928
1969
  var externalLink = "text-[var(--color-primary)] hover:underline focus-visible:underline";
1929
1970
  function SongHistory({ uuid, getBackendBaseUrl }) {
1930
- const [open, setOpen] = useState7(false);
1971
+ const [open, setOpen] = useState8(false);
1931
1972
  const history = useSongHistory(uuid, getBackendBaseUrl, open);
1932
1973
  let body = null;
1933
- if (history.status === "loading") body = /* @__PURE__ */ jsx29(Skeleton5, { className: "h-10", "aria-busy": "true" });
1934
- else if (history.status === "error") body = /* @__PURE__ */ jsx29("p", { className: "text-red-600", children: "Could not load the history." });
1974
+ if (history.status === "loading") body = /* @__PURE__ */ jsx30(Skeleton5, { className: "h-10", "aria-busy": "true" });
1975
+ else if (history.status === "error") body = /* @__PURE__ */ jsx30("p", { className: "text-red-600", children: "Could not load the history." });
1935
1976
  else if (history.status === "success")
1936
- 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: [
1937
- /* @__PURE__ */ jsx29("span", { className: "font-medium", children: entry.action }),
1977
+ body = history.entries.length === 0 ? /* @__PURE__ */ jsx30("p", { className: "text-[var(--color-text-muted)]", children: "No changes yet." }) : /* @__PURE__ */ jsx30("ul", { className: "divide-y divide-[var(--color-border)]", children: history.entries.map((entry) => /* @__PURE__ */ jsxs23("li", { className: "py-1.5 text-sm", children: [
1978
+ /* @__PURE__ */ jsx30("span", { className: "font-medium", children: entry.action }),
1938
1979
  entry.oldValue !== null || entry.newValue !== null ? /* @__PURE__ */ jsxs23("span", { className: "text-[var(--color-text-muted)]", children: [
1939
1980
  " ",
1940
1981
  "\u2014 ",
@@ -1954,8 +1995,8 @@ function SongHistory({ uuid, getBackendBaseUrl }) {
1954
1995
  onToggle: (event) => setOpen(event.currentTarget.open),
1955
1996
  className: "px-6 pb-2.5 mt-2.5 border-t border-[var(--color-border)]",
1956
1997
  children: [
1957
- /* @__PURE__ */ jsx29("summary", { className: "mt-2.5 cursor-pointer text-[0.6875rem] font-semibold uppercase text-[var(--color-text-muted)]", children: "History" }),
1958
- /* @__PURE__ */ jsx29("div", { className: "mt-1.5", children: body })
1998
+ /* @__PURE__ */ jsx30("summary", { className: "mt-2.5 cursor-pointer text-[0.6875rem] font-semibold uppercase text-[var(--color-text-muted)]", children: "History" }),
1999
+ /* @__PURE__ */ jsx30("div", { className: "mt-1.5", children: body })
1959
2000
  ]
1960
2001
  }
1961
2002
  );
@@ -1981,13 +2022,13 @@ function SongPanelContent({
1981
2022
  const path = genrePath.length > 0 ? genrePath : null;
1982
2023
  fields.push({
1983
2024
  label: "Genre",
1984
- value: path ? /* @__PURE__ */ jsx29("span", { className: "flex flex-wrap items-center gap-x-1", children: path.map((genrePlaylist, index) => /* @__PURE__ */ jsxs23("span", { children: [
1985
- index > 0 && /* @__PURE__ */ jsx29("span", { "aria-hidden": "true", children: "\u203A " }),
1986
- /* @__PURE__ */ jsx29("button", { type: "button", onClick: () => onSelectGenre(genrePlaylist), className: "hover:underline", children: genrePlaylist.name })
2025
+ value: path ? /* @__PURE__ */ jsx30("span", { className: "flex flex-wrap items-center gap-x-1", children: path.map((genrePlaylist, index) => /* @__PURE__ */ jsxs23("span", { children: [
2026
+ index > 0 && /* @__PURE__ */ jsx30("span", { "aria-hidden": "true", children: "\u203A " }),
2027
+ /* @__PURE__ */ jsx30("button", { type: "button", onClick: () => onSelectGenre(genrePlaylist), className: "hover:underline", children: genrePlaylist.name })
1987
2028
  ] }, genrePlaylist.uuid)) }) : song.genre.name
1988
2029
  });
1989
2030
  } else {
1990
- fields.push({ label: "Genre", value: /* @__PURE__ */ jsx29("span", { className: "text-[var(--color-text-muted)]", children: "No genre" }) });
2031
+ fields.push({ label: "Genre", value: /* @__PURE__ */ jsx30("span", { className: "text-[var(--color-text-muted)]", children: "No genre" }) });
1991
2032
  }
1992
2033
  if (song.firstReleaseYear) fields.push({ label: "First released", value: song.firstReleaseYear });
1993
2034
  const viewCount = song.youtubeVideo?.viewCount;
@@ -1997,11 +2038,11 @@ function SongPanelContent({
1997
2038
  const links = [];
1998
2039
  if (musicBrainzUrl)
1999
2040
  links.push(
2000
- /* @__PURE__ */ jsx29("a", { href: musicBrainzUrl, target: "_blank", rel: "noopener noreferrer", className: externalLink, children: "MusicBrainz" }, "mb")
2041
+ /* @__PURE__ */ jsx30("a", { href: musicBrainzUrl, target: "_blank", rel: "noopener noreferrer", className: externalLink, children: "MusicBrainz" }, "mb")
2001
2042
  );
2002
2043
  if (song.youtubeVideo)
2003
2044
  links.push(
2004
- /* @__PURE__ */ jsx29(
2045
+ /* @__PURE__ */ jsx30(
2005
2046
  "a",
2006
2047
  {
2007
2048
  href: `https://www.youtube.com/watch?v=${encodeURIComponent(song.youtubeVideo.id)}`,
@@ -2016,33 +2057,33 @@ function SongPanelContent({
2016
2057
  if (links.length > 0)
2017
2058
  fields.push({
2018
2059
  label: "Links",
2019
- value: /* @__PURE__ */ jsx29("span", { className: "flex gap-3", children: links })
2060
+ value: /* @__PURE__ */ jsx30("span", { className: "flex gap-3", children: links })
2020
2061
  });
2021
2062
  return /* @__PURE__ */ jsxs23(Fragment12, { children: [
2022
- /* @__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: [
2023
- unplayableReason ? /* @__PURE__ */ jsx29("p", { className: "flex items-center px-2.5 text-sm text-[var(--color-text-muted)]", children: unplayableReason }) : /* @__PURE__ */ jsxs23(
2063
+ /* @__PURE__ */ jsx30("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: [
2064
+ unplayableReason ? /* @__PURE__ */ jsx30("p", { className: "flex items-center px-2.5 text-sm text-[var(--color-text-muted)]", children: unplayableReason }) : /* @__PURE__ */ jsxs23(
2024
2065
  "button",
2025
2066
  {
2026
2067
  type: "button",
2027
2068
  onClick: () => isCurrent ? handlePlayPauseAction() : playNewTrackListFromTrackUuid(song, scope),
2028
2069
  className: "group flex flex-col items-center gap-1 w-16 text-xs text-center text-[var(--color-text)] focus-visible:outline-none",
2029
2070
  children: [
2030
- /* @__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" }) }),
2071
+ /* @__PURE__ */ jsx30("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__ */ jsx30(Pause2, { "aria-hidden": "true", className: "w-5 h-5" }) : /* @__PURE__ */ jsx30(Play3, { "aria-hidden": "true", className: "w-5 h-5" }) }),
2031
2072
  isPlaying ? "Pause" : "Play"
2032
2073
  ]
2033
2074
  }
2034
2075
  ),
2035
- shareUrl && /* @__PURE__ */ jsx29(ShareActionButton, { target: shareTarget, url: shareUrl })
2076
+ shareUrl && /* @__PURE__ */ jsx30(ShareActionButton, { target: shareTarget, url: shareUrl })
2036
2077
  ] }) }),
2037
- 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 }) }),
2038
- /* @__PURE__ */ jsx29(FieldList2, { items: fields }),
2039
- 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)) }) }),
2040
- /* @__PURE__ */ jsx29(SongHistory, { uuid: song.uuid, getBackendBaseUrl })
2078
+ song.artists && song.artists.length > 0 && /* @__PURE__ */ jsx30("p", { className: "px-6 pt-2.5 text-[var(--color-text-muted)]", children: /* @__PURE__ */ jsx30(ArtistNames3, { artists: song.artists, renderArtistLink }) }),
2079
+ /* @__PURE__ */ jsx30(FieldList2, { items: fields }),
2080
+ song.essentialGenres && song.essentialGenres.length > 0 && /* @__PURE__ */ jsx30(PanelSection6, { title: "Essential in", children: /* @__PURE__ */ jsx30("ul", { children: song.essentialGenres.map((genre) => /* @__PURE__ */ jsx30("li", { className: "py-0.5", children: genre.name }, genre.uuid)) }) }),
2081
+ /* @__PURE__ */ jsx30(SongHistory, { uuid: song.uuid, getBackendBaseUrl })
2041
2082
  ] });
2042
2083
  }
2043
2084
 
2044
2085
  // src/genre-tree/song/useSongPanel.tsx
2045
- import { jsx as jsx30, jsxs as jsxs24 } from "react/jsx-runtime";
2086
+ import { jsx as jsx31, jsxs as jsxs24 } from "react/jsx-runtime";
2046
2087
  function useSongPanel({
2047
2088
  uuid,
2048
2089
  scope,
@@ -2065,23 +2106,23 @@ function useSongPanel({
2065
2106
  ...panel,
2066
2107
  title: "Song",
2067
2108
  content: /* @__PURE__ */ jsxs24("div", { "aria-busy": "true", className: "flex flex-col gap-2.5 px-6 py-2.5", children: [
2068
- /* @__PURE__ */ jsx30(Skeleton6, { className: "h-3 w-16" }),
2069
- /* @__PURE__ */ jsx30(Skeleton6, { className: "h-4 w-32" }),
2070
- /* @__PURE__ */ jsx30(Skeleton6, { className: "h-3 w-16" }),
2071
- /* @__PURE__ */ jsx30(Skeleton6, { className: "h-4 w-24" })
2109
+ /* @__PURE__ */ jsx31(Skeleton6, { className: "h-3 w-16" }),
2110
+ /* @__PURE__ */ jsx31(Skeleton6, { className: "h-4 w-32" }),
2111
+ /* @__PURE__ */ jsx31(Skeleton6, { className: "h-3 w-16" }),
2112
+ /* @__PURE__ */ jsx31(Skeleton6, { className: "h-4 w-24" })
2072
2113
  ] })
2073
2114
  };
2074
2115
  case "not-found":
2075
2116
  return {
2076
2117
  ...panel,
2077
2118
  title: "Song not found",
2078
- content: /* @__PURE__ */ jsx30("p", { className: "px-6 py-2.5 text-[var(--color-text-muted)]", children: "This song does not exist." })
2119
+ content: /* @__PURE__ */ jsx31("p", { className: "px-6 py-2.5 text-[var(--color-text-muted)]", children: "This song does not exist." })
2079
2120
  };
2080
2121
  case "error":
2081
2122
  return {
2082
2123
  ...panel,
2083
2124
  title: "Song",
2084
- content: /* @__PURE__ */ jsx30("p", { className: "px-6 py-2.5 text-red-600", children: "Could not load this song." })
2125
+ content: /* @__PURE__ */ jsx31("p", { className: "px-6 py-2.5 text-red-600", children: "Could not load this song." })
2085
2126
  };
2086
2127
  case "success": {
2087
2128
  const { song } = result;
@@ -2089,7 +2130,7 @@ function useSongPanel({
2089
2130
  return {
2090
2131
  ...panel,
2091
2132
  title: song.title,
2092
- content: /* @__PURE__ */ jsx30(
2133
+ content: /* @__PURE__ */ jsx31(
2093
2134
  SongPanelContent,
2094
2135
  {
2095
2136
  song,
@@ -2109,12 +2150,12 @@ function useSongPanel({
2109
2150
  // src/genre-tree/SizeMetricToggle.tsx
2110
2151
  import { MdMusicNote, MdVisibility } from "react-icons/md";
2111
2152
  import { SegmentedControl } from "@behindthemusictree/ui";
2112
- import { jsx as jsx31 } from "react/jsx-runtime";
2153
+ import { jsx as jsx32 } from "react/jsx-runtime";
2113
2154
  function SizeMetricToggle({
2114
2155
  value,
2115
2156
  onChange
2116
2157
  }) {
2117
- return /* @__PURE__ */ jsx31(
2158
+ return /* @__PURE__ */ jsx32(
2118
2159
  SegmentedControl,
2119
2160
  {
2120
2161
  variant: "floating",
@@ -2122,15 +2163,15 @@ function SizeMetricToggle({
2122
2163
  value,
2123
2164
  onChange,
2124
2165
  options: [
2125
- { value: "songs", label: /* @__PURE__ */ jsx31(MdMusicNote, { size: 18, "aria-hidden": true }), "aria-label": "Size by songs", title: "Node size by song count" },
2126
- { value: "views", label: /* @__PURE__ */ jsx31(MdVisibility, { size: 18, "aria-hidden": true }), "aria-label": "Size by views", title: "Node size by song views" }
2166
+ { value: "songs", label: /* @__PURE__ */ jsx32(MdMusicNote, { size: 18, "aria-hidden": true }), "aria-label": "Size by songs", title: "Node size by song count" },
2167
+ { value: "views", label: /* @__PURE__ */ jsx32(MdVisibility, { size: 18, "aria-hidden": true }), "aria-label": "Size by views", title: "Node size by song views" }
2127
2168
  ]
2128
2169
  }
2129
2170
  );
2130
2171
  }
2131
2172
 
2132
2173
  // src/genre-tree/GenreTreeView.tsx
2133
- import { Fragment as Fragment13, jsx as jsx32, jsxs as jsxs25 } from "react/jsx-runtime";
2174
+ import { Fragment as Fragment13, jsx as jsx33, jsxs as jsxs25 } from "react/jsx-runtime";
2134
2175
  var NO_POP_ROOT_TITLE = "This genre tree has no 'Mainstream Pop' root yet";
2135
2176
  var REGIONS_CLASS = "[--gtv-center-left:var(--layout-center-left)] [--gtv-center-right:var(--layout-center-right)] [--gtv-center-top:var(--layout-band-top)]";
2136
2177
  var noop = () => {
@@ -2165,6 +2206,7 @@ function GenreTreeView({
2165
2206
  onArtistExpandedChange,
2166
2207
  getShareUrl,
2167
2208
  extraSearchGroups = [],
2209
+ SearchGroups,
2168
2210
  onSearchQueryChange,
2169
2211
  onSearchFocus,
2170
2212
  artistSearch = true,
@@ -2193,19 +2235,19 @@ function GenreTreeView({
2193
2235
  }) {
2194
2236
  const getShareUrlRef = useRef3(getShareUrl);
2195
2237
  getShareUrlRef.current = getShareUrl;
2196
- const [internalArtistUuid, setInternalArtistUuid] = useState8(null);
2238
+ const [internalArtistUuid, setInternalArtistUuid] = useState9(null);
2197
2239
  const isArtistControlled = controlledArtistUuid !== void 0;
2198
2240
  const artistUuid = isArtistControlled ? controlledArtistUuid : internalArtistUuid;
2199
- const [internalSongUuid, setInternalSongUuid] = useState8(null);
2241
+ const [internalSongUuid, setInternalSongUuid] = useState9(null);
2200
2242
  const isSongControlled = controlledSongUuid !== void 0;
2201
2243
  const songUuid = isSongControlled ? controlledSongUuid : internalSongUuid;
2202
2244
  const changeSong = (uuid) => {
2203
2245
  if (!isSongControlled) setInternalSongUuid(uuid);
2204
2246
  onSongUuidChange?.(uuid);
2205
2247
  };
2206
- const [internalSizeMetric, setInternalSizeMetric] = useState8("songs");
2248
+ const [internalSizeMetric, setInternalSizeMetric] = useState9("songs");
2207
2249
  const sizeMetric = controlledSizeMetric ?? internalSizeMetric;
2208
- const deferredSizeMetric = useDeferredValue(sizeMetric);
2250
+ const deferredSizeMetric = useDeferredValue2(sizeMetric);
2209
2251
  const changeSizeMetric = (metric) => {
2210
2252
  if (controlledSizeMetric === void 0) setInternalSizeMetric(metric);
2211
2253
  onSizeMetricChange?.(metric);
@@ -2242,7 +2284,7 @@ function GenreTreeView({
2242
2284
  artistUuid
2243
2285
  });
2244
2286
  const restoreRevision = viewportRestore?.revision;
2245
- const [stackedRestoreOwner, setStackedRestoreOwner] = useState8({ revision: restoreRevision, rootUuid: selectedGenrePlaylist?.root.uuid });
2287
+ const [stackedRestoreOwner, setStackedRestoreOwner] = useState9({ revision: restoreRevision, rootUuid: selectedGenrePlaylist?.root.uuid });
2246
2288
  let restoreRootUuid = stackedRestoreOwner.rootUuid;
2247
2289
  if (stackedRestoreOwner.revision !== restoreRevision) {
2248
2290
  restoreRootUuid = selectedGenrePlaylist?.root.uuid;
@@ -2276,11 +2318,11 @@ function GenreTreeView({
2276
2318
  const openSongRef = useRef3(openSong);
2277
2319
  openSongRef.current = openSong;
2278
2320
  const resolvedRenderSongLink = useCallback6(
2279
- (song) => renderSongLink ? renderSongLink(song) : /* @__PURE__ */ jsx32("button", { type: "button", onClick: () => openSongRef.current(song.uuid), className: "hover:underline", children: song.title }),
2321
+ (song) => renderSongLink ? renderSongLink(song) : /* @__PURE__ */ jsx33("button", { type: "button", onClick: () => openSongRef.current(song.uuid), className: "hover:underline", children: song.title }),
2280
2322
  [renderSongLink]
2281
2323
  );
2282
- const [expandedSongUuid, setExpandedSongUuid] = useState8(null);
2283
- const [expandedArtistUuid, setExpandedArtistUuid] = useState8(null);
2324
+ const [expandedSongUuid, setExpandedSongUuid] = useState9(null);
2325
+ const [expandedArtistUuid, setExpandedArtistUuid] = useState9(null);
2284
2326
  const artistBaseUrl = artistSearchBaseUrl ?? getBackendBaseUrl;
2285
2327
  const songBaseUrl = getBackendBaseUrl;
2286
2328
  const artistPanel = useArtistPanel({
@@ -2288,7 +2330,7 @@ function GenreTreeView({
2288
2330
  scope,
2289
2331
  getBackendBaseUrl: artistBaseUrl,
2290
2332
  getShareUrl: getShareUrlRef.current,
2291
- renderArtistLink: renderArtistLink ?? ((artist) => artist.isSpecialPurpose ? artist.name : /* @__PURE__ */ jsx32("button", { type: "button", onClick: () => openArtist(artist.uuid), className: "hover:underline", children: artist.name })),
2333
+ renderArtistLink: renderArtistLink ?? ((artist) => artist.isSpecialPurpose ? artist.name : /* @__PURE__ */ jsx33("button", { type: "button", onClick: () => openArtist(artist.uuid), className: "hover:underline", children: artist.name })),
2292
2334
  expanded: controlledArtistExpanded ?? (artistUuid !== null && expandedArtistUuid === artistUuid),
2293
2335
  onExpandedChange: (on) => {
2294
2336
  if (controlledArtistExpanded === void 0) setExpandedArtistUuid(on ? artistUuid : null);
@@ -2297,7 +2339,7 @@ function GenreTreeView({
2297
2339
  renderSongLink: resolvedRenderSongLink,
2298
2340
  onClose: () => changeArtist(null)
2299
2341
  });
2300
- const resolvedRenderArtistLink = renderArtistLink ?? ((artist) => artist.isSpecialPurpose ? artist.name : /* @__PURE__ */ jsx32("button", { type: "button", onClick: () => openArtist(artist.uuid), className: "hover:underline", children: artist.name }));
2342
+ const resolvedRenderArtistLink = renderArtistLink ?? ((artist) => artist.isSpecialPurpose ? artist.name : /* @__PURE__ */ jsx33("button", { type: "button", onClick: () => openArtist(artist.uuid), className: "hover:underline", children: artist.name }));
2301
2343
  const getGenrePath = (genre) => {
2302
2344
  const path = [];
2303
2345
  let current = visibleGenrePlaylists.find((playlist) => playlist.criteria?.uuid === genre.uuid);
@@ -2329,8 +2371,8 @@ function GenreTreeView({
2329
2371
  const builtInSongPanel = overlayPanel || hasSelectedGenreNode ? void 0 : songPanel;
2330
2372
  const builtInArtistPanel = overlayPanel || hasSelectedGenreNode || builtInSongPanel ? void 0 : artistPanel;
2331
2373
  const builtInPanel = builtInSongPanel ?? builtInArtistPanel;
2332
- const [uncontrolledCollapsed, setUncontrolledCollapsed] = useState8(false);
2333
- const [uncontrolledExpanded, setUncontrolledExpanded] = useState8(false);
2374
+ const [uncontrolledCollapsed, setUncontrolledCollapsed] = useState9(false);
2375
+ const [uncontrolledExpanded, setUncontrolledExpanded] = useState9(false);
2334
2376
  const isCollapsed = collapsed ?? uncontrolledCollapsed;
2335
2377
  const isExpanded = expanded ?? uncontrolledExpanded;
2336
2378
  const changeCollapsed = (next) => {
@@ -2344,10 +2386,10 @@ function GenreTreeView({
2344
2386
  useEffect5(() => {
2345
2387
  setUncontrolledCollapsed(false);
2346
2388
  }, [selectedNodeId, artistUuid, songUuid]);
2347
- const [isWheelRevealed, setIsWheelRevealed] = useState8(false);
2389
+ const [isWheelRevealed, setIsWheelRevealed] = useState9(false);
2348
2390
  const usesHandoff = viewMode === "wheel" || viewMode === "pop-core";
2349
2391
  const isTreeReady = !isLoading && (!usesHandoff || isWheelRevealed);
2350
- const [resolveStyle, setResolveStyle] = useState8(null);
2392
+ const [resolveStyle, setResolveStyle] = useState9(null);
2351
2393
  const handleNodeStyleResolverChange = useCallback6(
2352
2394
  (resolver) => setResolveStyle(() => resolver),
2353
2395
  []
@@ -2362,7 +2404,7 @@ function GenreTreeView({
2362
2404
  !overlayPanel && hasSelectedGenreNode ? selectedNodeId : null,
2363
2405
  resolveStyle
2364
2406
  );
2365
- const [selectionHistory, setSelectionHistory] = useState8({
2407
+ const [selectionHistory, setSelectionHistory] = useState9({
2366
2408
  current: selectedNodeId,
2367
2409
  previous: null
2368
2410
  });
@@ -2375,28 +2417,6 @@ function GenreTreeView({
2375
2417
  const previousPlaylist = selectionHistory.previous !== null && selectionHistory.previous !== selectedNodeId ? genrePlaylistByNodeId.get(selectionHistory.previous) : void 0;
2376
2418
  const handlePrevious = previousPlaylist && visibleGenrePlaylists.includes(previousPlaylist) ? () => handleGenreSearchSelect(previousPlaylist) : void 0;
2377
2419
  const { showPopup, hidePopup } = usePopup5();
2378
- const [searchText, setSearchText] = useState8("");
2379
- const artistGroup = useArtistSearchGroup(
2380
- artistBaseUrl,
2381
- searchText,
2382
- (artist) => {
2383
- openArtist(artist.uuid);
2384
- onArtistSelect?.(artist);
2385
- },
2386
- Boolean(artistSearch)
2387
- );
2388
- const songGroup = useSongSearchGroup(
2389
- songBaseUrl,
2390
- searchText,
2391
- (song) => {
2392
- openSong(song.uuid);
2393
- onSongSelect?.(song);
2394
- },
2395
- Boolean(songSearch)
2396
- );
2397
- const extraGroups = [...extraSearchGroups, artistGroup, songGroup].filter(
2398
- (group) => group !== void 0
2399
- );
2400
2420
  const handleSelectedNodeChange = (node) => {
2401
2421
  if (node !== null && songUuid !== null) changeSong(null);
2402
2422
  selectNode(node);
@@ -2420,7 +2440,7 @@ function GenreTreeView({
2420
2440
  };
2421
2441
  const renderGenreBody = (relation) => {
2422
2442
  const { node } = relation;
2423
- const family = /* @__PURE__ */ jsx32(
2443
+ const family = /* @__PURE__ */ jsx33(
2424
2444
  GenreNodeFamily,
2425
2445
  {
2426
2446
  node,
@@ -2431,7 +2451,7 @@ function GenreTreeView({
2431
2451
  onSelectNode: selectGenreFromPanel
2432
2452
  }
2433
2453
  );
2434
- const ancestors = /* @__PURE__ */ jsx32(GenreNodeAncestors, { ancestorNodes: relation.ancestorNodes, onSelectNode: selectGenreFromPanel });
2454
+ const ancestors = /* @__PURE__ */ jsx33(GenreNodeAncestors, { ancestorNodes: relation.ancestorNodes, onSelectNode: selectGenreFromPanel });
2435
2455
  const genrePlaylist = genrePlaylistByNodeId.get(node.id);
2436
2456
  const criteria = genrePlaylist?.criteria;
2437
2457
  if (!genrePlaylist || !criteria) return { primary: /* @__PURE__ */ jsxs25(Fragment13, { children: [
@@ -2455,7 +2475,7 @@ function GenreTreeView({
2455
2475
  ) : void 0;
2456
2476
  return {
2457
2477
  primary: /* @__PURE__ */ jsxs25(Fragment13, { children: [
2458
- /* @__PURE__ */ jsx32(
2478
+ /* @__PURE__ */ jsx33(
2459
2479
  GenreInfoPanelBody,
2460
2480
  {
2461
2481
  family: /* @__PURE__ */ jsxs25(Fragment13, { children: [
@@ -2477,7 +2497,7 @@ function GenreTreeView({
2477
2497
  onAddChild: readOnly ? void 0 : () => handleGenreCreationAction(criteria),
2478
2498
  onRename: readOnly ? void 0 : () => handleGenreRenameAction(criteria),
2479
2499
  onChangeParent: readOnly ? void 0 : () => showPopup(
2480
- /* @__PURE__ */ jsx32(
2500
+ /* @__PURE__ */ jsx33(
2481
2501
  ChangeParentPopup,
2482
2502
  {
2483
2503
  genrePlaylist: { ...genrePlaylist, criteria },
@@ -2552,19 +2572,19 @@ function GenreTreeView({
2552
2572
  edge: activePanel.expanded ? { label: "Shrink panel", onClick: () => activePanel.onExpandedChange?.(false) } : isCollapsed ? null : { label: "Hide panel", onClick: () => changeCollapsed(true) },
2553
2573
  center: activePanel.expanded ? null : isCollapsed ? { label: "Show panel", onClick: () => changeCollapsed(false) } : activePanel.onExpandedChange ? { label: "Extend panel", onClick: () => activePanel.onExpandedChange?.(true) } : null
2554
2574
  } : void 0;
2555
- const expandButton = placement === "default" && activePanel?.onExpandedChange ? /* @__PURE__ */ jsx32(
2575
+ const expandButton = placement === "default" && activePanel?.onExpandedChange ? /* @__PURE__ */ jsx33(
2556
2576
  IconButton,
2557
2577
  {
2558
2578
  "aria-label": activePanel.expanded ? "Shrink panel" : "Extend panel",
2559
2579
  style: activePanel.headerAccent && { color: "inherit" },
2560
2580
  onClick: () => activePanel.onExpandedChange?.(!activePanel.expanded),
2561
- 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" })
2581
+ children: activePanel.expanded ? /* @__PURE__ */ jsx33(Minimize2, { "aria-hidden": "true", className: "h-4 w-4" }) : /* @__PURE__ */ jsx33(Maximize2, { "aria-hidden": "true", className: "h-4 w-4" })
2562
2582
  }
2563
2583
  ) : null;
2564
2584
  const renderArtistFilter = () => {
2565
2585
  if (isLoading || !filterArtist) return null;
2566
2586
  return /* @__PURE__ */ jsxs25("span", { className: "inline-flex items-center overflow-hidden rounded-full bg-[var(--color-neutral-100)] text-sm", children: [
2567
- /* @__PURE__ */ jsx32(
2587
+ /* @__PURE__ */ jsx33(
2568
2588
  "button",
2569
2589
  {
2570
2590
  type: "button",
@@ -2576,7 +2596,7 @@ function GenreTreeView({
2576
2596
  children: filterArtist.name
2577
2597
  }
2578
2598
  ),
2579
- /* @__PURE__ */ jsx32(
2599
+ /* @__PURE__ */ jsx33(
2580
2600
  "button",
2581
2601
  {
2582
2602
  type: "button",
@@ -2589,25 +2609,35 @@ function GenreTreeView({
2589
2609
  ] });
2590
2610
  };
2591
2611
  const actions = /* @__PURE__ */ jsxs25(Fragment13, { children: [
2592
- !isLoading && /* @__PURE__ */ jsx32(
2593
- GenreSearch,
2612
+ !isLoading && /* @__PURE__ */ jsx33(
2613
+ GenreTreeSearch,
2594
2614
  {
2615
+ artistBaseUrl,
2616
+ songBaseUrl,
2617
+ artistSearch: Boolean(artistSearch),
2618
+ songSearch: Boolean(songSearch),
2619
+ onArtistSelect: (artist) => {
2620
+ openArtist(artist.uuid);
2621
+ onArtistSelect?.(artist);
2622
+ },
2623
+ onSongSelect: (song) => {
2624
+ openSong(song.uuid);
2625
+ onSongSelect?.(song);
2626
+ },
2627
+ SearchGroups,
2595
2628
  genrePlaylists: visibleGenrePlaylists,
2596
2629
  onSelect: handleGenreSearchSelect,
2597
2630
  selectedName: selectedGenrePlaylist?.name ?? (typeof builtInPanel?.title === "string" ? builtInPanel.title : null),
2598
2631
  onClear: builtInSongPanel ? () => changeSong(null) : builtInArtistPanel ? () => changeArtist(null) : handleGenreSearchClear,
2599
2632
  onPrevious: handlePrevious,
2600
- onQueryChange: (text) => {
2601
- setSearchText(text);
2602
- onSearchQueryChange?.(text);
2603
- },
2633
+ onQueryChange: onSearchQueryChange,
2604
2634
  onFocus: onSearchFocus,
2605
- extraGroups
2635
+ extraGroups: extraSearchGroups
2606
2636
  }
2607
2637
  ),
2608
- !isLoading && filterArtist && /* @__PURE__ */ jsx32("div", { className: "hidden w-full justify-center max-md:flex", children: renderArtistFilter() }),
2638
+ !isLoading && filterArtist && /* @__PURE__ */ jsx33("div", { className: "hidden w-full justify-center max-md:flex", children: renderArtistFilter() }),
2609
2639
  /* @__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: [
2610
- !isLoading && !isControlled && /* @__PURE__ */ jsx32(
2640
+ !isLoading && !isControlled && /* @__PURE__ */ jsx33(
2611
2641
  SegmentedControl2,
2612
2642
  {
2613
2643
  "aria-label": "Tree view mode",
@@ -2621,13 +2651,13 @@ function GenreTreeView({
2621
2651
  ]
2622
2652
  }
2623
2653
  ),
2624
- !isLoading && showDisplayOptions && /* @__PURE__ */ jsx32(
2654
+ !isLoading && showDisplayOptions && /* @__PURE__ */ jsx33(
2625
2655
  "div",
2626
2656
  {
2627
2657
  className: "flex items-center gap-1",
2628
2658
  role: "group",
2629
2659
  "aria-label": "Tree display options",
2630
- children: !isRotationControlled && viewMode !== "stacked" && viewMode !== "outline" && /* @__PURE__ */ jsx32(
2660
+ children: !isRotationControlled && viewMode !== "stacked" && viewMode !== "outline" && /* @__PURE__ */ jsx33(
2631
2661
  Button,
2632
2662
  {
2633
2663
  variant: allowWheelRotation ? "default" : "outline",
@@ -2638,7 +2668,7 @@ function GenreTreeView({
2638
2668
  )
2639
2669
  }
2640
2670
  ),
2641
- !isLoading && !readOnly && showAddRoot && /* @__PURE__ */ jsx32(
2671
+ !isLoading && !readOnly && showAddRoot && /* @__PURE__ */ jsx33(
2642
2672
  IconTextButton,
2643
2673
  {
2644
2674
  icon: Plus2,
@@ -2654,28 +2684,28 @@ function GenreTreeView({
2654
2684
  "data-left-panel": isPanelShown && !isCollapsed ? void 0 : "hidden",
2655
2685
  className: ["genre-tree-view relative flex flex-col h-full", placement === "regions" && REGIONS_CLASS, className2].filter(Boolean).join(" "),
2656
2686
  children: [
2657
- /* @__PURE__ */ jsx32(
2687
+ /* @__PURE__ */ jsx33(
2658
2688
  "div",
2659
2689
  {
2660
2690
  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"}`,
2661
2691
  children: actions
2662
2692
  }
2663
2693
  ),
2664
- !isLoading && filterArtist && /* @__PURE__ */ jsx32(
2694
+ !isLoading && filterArtist && /* @__PURE__ */ jsx33(
2665
2695
  "div",
2666
2696
  {
2667
2697
  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"}`,
2668
2698
  children: renderArtistFilter()
2669
2699
  }
2670
2700
  ),
2671
- /* @__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: [
2672
- !isLoading && viewMode === "outline" && floatingControlsLeading && /* @__PURE__ */ jsx32("div", { className: "absolute bottom-3 right-3 z-10", children: floatingControlsLeading }),
2673
- isLoading ? /* @__PURE__ */ jsx32(GenreTreeViewSkeleton, { viewMode }) : viewMode === "wheel" ? (
2701
+ /* @__PURE__ */ jsx33("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: [
2702
+ !isLoading && viewMode === "outline" && floatingControlsLeading && /* @__PURE__ */ jsx33("div", { className: "absolute bottom-3 right-3 z-10", children: floatingControlsLeading }),
2703
+ isLoading ? /* @__PURE__ */ jsx33(GenreTreeViewSkeleton, { viewMode }) : viewMode === "wheel" ? (
2674
2704
  // The info panel's top edge aligns with the tree's; the search bar floats `--layout-panel-inset` below it,
2675
2705
  // and the header inset (the bar's height plus that inset) extends the header's fill behind the bar,
2676
2706
  // Google Maps style; the 8px bottom padding mirrors the inset above the bar, and the hidden title's height is zeroed.
2677
2707
  // The panel's own Zoom in button is hidden: the search bar carries it.
2678
- /* @__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(
2708
+ /* @__PURE__ */ jsx33("div", { className: "tree-container search-overlay relative flex-1 w-full min-h-0 ", children: /* @__PURE__ */ jsx33(GenreTreeWheelHandoff, { skeleton: /* @__PURE__ */ jsx33(GenreTreeWheelSkeleton, {}), onRevealedChange: setIsWheelRevealed, children: /* @__PURE__ */ jsx33(
2679
2709
  GenrePlaylistTreeWheel,
2680
2710
  {
2681
2711
  scope,
@@ -2694,7 +2724,7 @@ function GenreTreeView({
2694
2724
  busy,
2695
2725
  floatingControlsLeading: floatingControlsLeading || canSizeByViews ? /* @__PURE__ */ jsxs25("div", { className: "flex items-center gap-2", children: [
2696
2726
  floatingControlsLeading,
2697
- canSizeByViews && /* @__PURE__ */ jsx32(SizeMetricToggle, { value: sizeMetric, onChange: changeSizeMetric })
2727
+ canSizeByViews && /* @__PURE__ */ jsx33(SizeMetricToggle, { value: sizeMetric, onChange: changeSizeMetric })
2698
2728
  ] }) : void 0,
2699
2729
  defaultViewport,
2700
2730
  viewportRestore,
@@ -2703,7 +2733,7 @@ function GenreTreeView({
2703
2733
  ) }) })
2704
2734
  ) : viewMode === "pop-core" ? (
2705
2735
  // Same as the wheel: the header inset extends its fill behind the floating search bar, Google Maps style.
2706
- /* @__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(
2736
+ /* @__PURE__ */ jsx33("div", { className: "tree-container search-overlay relative flex-1 w-full min-h-0 ", children: /* @__PURE__ */ jsx33(GenreTreeWheelHandoff, { skeleton: /* @__PURE__ */ jsx33(GenreTreeWheelSkeleton, {}), onRevealedChange: setIsWheelRevealed, children: /* @__PURE__ */ jsx33(
2707
2737
  GenrePlaylistTreeWheelRadialPopCore,
2708
2738
  {
2709
2739
  scope,
@@ -2722,7 +2752,7 @@ function GenreTreeView({
2722
2752
  busy,
2723
2753
  floatingControlsLeading: floatingControlsLeading || canSizeByViews ? /* @__PURE__ */ jsxs25("div", { className: "flex items-center gap-2", children: [
2724
2754
  floatingControlsLeading,
2725
- canSizeByViews && /* @__PURE__ */ jsx32(SizeMetricToggle, { value: sizeMetric, onChange: changeSizeMetric })
2755
+ canSizeByViews && /* @__PURE__ */ jsx33(SizeMetricToggle, { value: sizeMetric, onChange: changeSizeMetric })
2726
2756
  ] }) : void 0,
2727
2757
  defaultViewport,
2728
2758
  viewportRestore,
@@ -2730,7 +2760,7 @@ function GenreTreeView({
2730
2760
  ...focus
2731
2761
  }
2732
2762
  ) }) })
2733
- ) : viewMode === "outline" ? /* @__PURE__ */ jsx32("div", { className: "tree-container flex-1 min-h-0 w-full overflow-y-auto relative", children: /* @__PURE__ */ jsx32(
2763
+ ) : viewMode === "outline" ? /* @__PURE__ */ jsx33("div", { className: "tree-container flex-1 min-h-0 w-full overflow-y-auto relative", children: /* @__PURE__ */ jsx33(
2734
2764
  GenrePlaylistTreeWheelRadialPopCore,
2735
2765
  {
2736
2766
  outline: true,
@@ -2746,13 +2776,13 @@ function GenreTreeView({
2746
2776
  selectedNodeId,
2747
2777
  readOnly
2748
2778
  }
2749
- ) }) : /* @__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(
2779
+ ) }) : /* @__PURE__ */ jsx33("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(
2750
2780
  ([uuid, genrePlaylistTreePerRoot]) => {
2751
- return /* @__PURE__ */ jsx32(
2781
+ return /* @__PURE__ */ jsx33(
2752
2782
  "div",
2753
2783
  {
2754
2784
  className: "tree-per-root-container relative shrink-0 h-[28rem] mt-2 mr-16 p-2 bg-[var(--color-neutral-100)] rounded-lg",
2755
- children: /* @__PURE__ */ jsx32("div", { className: "graph-container relative z-10 h-full", children: /* @__PURE__ */ jsx32(
2785
+ children: /* @__PURE__ */ jsx33("div", { className: "graph-container relative z-10 h-full", children: /* @__PURE__ */ jsx33(
2756
2786
  GenrePlaylistTreePerRoot,
2757
2787
  {
2758
2788
  scope,
@@ -2778,7 +2808,7 @@ function GenreTreeView({
2778
2808
  );
2779
2809
  }
2780
2810
  ) }),
2781
- /* @__PURE__ */ jsx32(
2811
+ /* @__PURE__ */ jsx33(
2782
2812
  DetailPanel,
2783
2813
  {
2784
2814
  ref: panelRef,
@@ -2824,7 +2854,7 @@ import {
2824
2854
  genreMusicCount as genreMusicCount2,
2825
2855
  GenrePlaylistSummarySchema
2826
2856
  } from "@behindthemusictree/app-kit/genre-tree";
2827
- import { Fragment as Fragment14, jsx as jsx33, jsxs as jsxs26 } from "react/jsx-runtime";
2857
+ import { Fragment as Fragment14, jsx as jsx34, jsxs as jsxs26 } from "react/jsx-runtime";
2828
2858
  var RELATIVE_ITEM_COUNT = 1;
2829
2859
  function toNode(genre, parentId) {
2830
2860
  return {
@@ -2879,17 +2909,17 @@ function GenreDetailPanel({
2879
2909
  };
2880
2910
  }, [detail, scope]);
2881
2911
  if (isError) {
2882
- return /* @__PURE__ */ jsx33("div", { role: "alert", className: "p-4 text-sm text-[var(--color-text)]", children: "This genre could not be loaded." });
2912
+ return /* @__PURE__ */ jsx34("div", { role: "alert", className: "p-4 text-sm text-[var(--color-text)]", children: "This genre could not be loaded." });
2883
2913
  }
2884
2914
  if (isPending || !detail || !view) {
2885
2915
  return /* @__PURE__ */ jsxs26("div", { className: "flex flex-col gap-3 p-4", "aria-busy": "true", "data-testid": "genre-detail-panel-skeleton", children: [
2886
- /* @__PURE__ */ jsx33(Skeleton7, { className: "h-6 w-2/3" }),
2887
- /* @__PURE__ */ jsx33(Skeleton7, { className: "h-4 w-full" }),
2888
- /* @__PURE__ */ jsx33(Skeleton7, { className: "h-4 w-3/4" })
2916
+ /* @__PURE__ */ jsx34(Skeleton7, { className: "h-6 w-2/3" }),
2917
+ /* @__PURE__ */ jsx34(Skeleton7, { className: "h-4 w-full" }),
2918
+ /* @__PURE__ */ jsx34(Skeleton7, { className: "h-4 w-3/4" })
2889
2919
  ] });
2890
2920
  }
2891
2921
  const selectGenre = (nodeId) => onSelectGenre(nodeId);
2892
- const family = /* @__PURE__ */ jsx33(
2922
+ const family = /* @__PURE__ */ jsx34(
2893
2923
  GenreNodeFamily2,
2894
2924
  {
2895
2925
  node: view.node,
@@ -2900,20 +2930,20 @@ function GenreDetailPanel({
2900
2930
  onSelectNode: selectGenre
2901
2931
  }
2902
2932
  );
2903
- const ancestors = /* @__PURE__ */ jsx33(GenreNodeAncestors2, { ancestorNodes: view.ancestorNodes, onSelectNode: selectGenre });
2933
+ const ancestors = /* @__PURE__ */ jsx34(GenreNodeAncestors2, { ancestorNodes: view.ancestorNodes, onSelectNode: selectGenre });
2904
2934
  return /* @__PURE__ */ jsxs26(
2905
2935
  DetailPanel2,
2906
2936
  {
2907
2937
  side: "left",
2908
2938
  title: view.node.name,
2909
2939
  headerAccent: { background: view.fill, color: ACCENT_TEXT_COLOR },
2910
- headerActions: onExpandedChange ? /* @__PURE__ */ jsx33(
2940
+ headerActions: onExpandedChange ? /* @__PURE__ */ jsx34(
2911
2941
  IconButton2,
2912
2942
  {
2913
2943
  "aria-label": expanded ? "Shrink panel" : "Extend panel",
2914
2944
  style: { color: "inherit" },
2915
2945
  onClick: () => onExpandedChange(!expanded),
2916
- children: expanded ? /* @__PURE__ */ jsx33(Minimize22, { "aria-hidden": "true", className: "h-4 w-4" }) : /* @__PURE__ */ jsx33(Maximize22, { "aria-hidden": "true", className: "h-4 w-4" })
2946
+ children: expanded ? /* @__PURE__ */ jsx34(Minimize22, { "aria-hidden": "true", className: "h-4 w-4" }) : /* @__PURE__ */ jsx34(Maximize22, { "aria-hidden": "true", className: "h-4 w-4" })
2917
2947
  }
2918
2948
  ) : void 0,
2919
2949
  onClose,
@@ -2922,7 +2952,7 @@ function GenreDetailPanel({
2922
2952
  onExpandedChange,
2923
2953
  edgeTab,
2924
2954
  children: [
2925
- /* @__PURE__ */ jsx33(
2955
+ /* @__PURE__ */ jsx34(
2926
2956
  GenreInfoPanelBody,
2927
2957
  {
2928
2958
  family: /* @__PURE__ */ jsxs26(Fragment14, { children: [
@@ -2960,7 +2990,7 @@ import { ListMusic } from "lucide-react";
2960
2990
  import { useTrackList as useTrackList6 } from "@behindthemusictree/app-kit/genre-tree";
2961
2991
  import { TrackListOriginType as TrackListOriginType2 } from "@behindthemusictree/app-kit/genre-tree";
2962
2992
  import { useTrackNoun as useTrackNoun4 } from "@behindthemusictree/app-kit/track-noun";
2963
- import { jsx as jsx34, jsxs as jsxs27 } from "react/jsx-runtime";
2993
+ import { jsx as jsx35, jsxs as jsxs27 } from "react/jsx-runtime";
2964
2994
  var useBrowserLayoutEffect = typeof window === "undefined" ? useEffect6 : useLayoutEffect2;
2965
2995
  function TrackListSidebar({
2966
2996
  className: className2 = "",
@@ -3072,15 +3102,15 @@ function TrackListSidebar({
3072
3102
  /* @__PURE__ */ jsxs27("div", { className: "header flex h-16 items-center px-4 py-2 text-[var(--color-text)]", children: [
3073
3103
  /* @__PURE__ */ jsxs27("div", { className: "min-w-0 flex flex-1 flex-col justify-center", children: [
3074
3104
  /* @__PURE__ */ jsxs27("div", { className: "origin flex text-xl", children: [
3075
- /* @__PURE__ */ jsx34("div", { className: "from h-auto flex flex-col justify-center items-center mr-2", children: "From" }),
3076
- /* @__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 }) })
3105
+ /* @__PURE__ */ jsx35("div", { className: "from h-auto flex flex-col justify-center items-center mr-2", children: "From" }),
3106
+ /* @__PURE__ */ jsx35("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__ */ jsx35("div", { className: "name max-w-full truncate", children: trackList.origin.label }) })
3077
3107
  ] }),
3078
3108
  /* @__PURE__ */ jsxs27("div", { className: "info flex items-center text-sm text-[var(--color-text-muted)]", children: [
3079
3109
  trackList.origin.type === TrackListOriginType2.GENRE_PLAYLIST ? "Genre \u2022 " : trackList.origin.type === TrackListOriginType2.ARTIST ? "Artist \u2022 " : `${trackNoun.singular} playlist \u2022 `,
3080
3110
  `${trackList.total} ${trackList.total > 1 ? trackNoun.plural : trackNoun.singular}`
3081
3111
  ] })
3082
3112
  ] }),
3083
- (isCollapsed && onExpand || !isCollapsed && onMinimize) && /* @__PURE__ */ jsx34(
3113
+ (isCollapsed && onExpand || !isCollapsed && onMinimize) && /* @__PURE__ */ jsx35(
3084
3114
  "button",
3085
3115
  {
3086
3116
  type: "button",
@@ -3089,7 +3119,7 @@ function TrackListSidebar({
3089
3119
  "aria-expanded": !isCollapsed,
3090
3120
  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"}`,
3091
3121
  onClick: isCollapsed ? onExpand : onMinimize,
3092
- children: /* @__PURE__ */ jsx34(ListMusic, { "aria-hidden": "true", className: "h-5 w-5" })
3122
+ children: /* @__PURE__ */ jsx35(ListMusic, { "aria-hidden": "true", className: "h-5 w-5" })
3093
3123
  }
3094
3124
  )
3095
3125
  ] }),
@@ -3103,7 +3133,7 @@ function TrackListSidebar({
3103
3133
  onPointerDown: markUserScrollIntent,
3104
3134
  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",
3105
3135
  children: [
3106
- trackList.tracks.map((track, index) => /* @__PURE__ */ jsx34("li", { "data-track-uuid": track.uuid, children: /* @__PURE__ */ jsx34(
3136
+ trackList.tracks.map((track, index) => /* @__PURE__ */ jsx35("li", { "data-track-uuid": track.uuid, children: /* @__PURE__ */ jsx35(
3107
3137
  TrackItem,
3108
3138
  {
3109
3139
  track,
@@ -3114,7 +3144,7 @@ function TrackListSidebar({
3114
3144
  renderSongLink
3115
3145
  }
3116
3146
  ) }, track.uuid)),
3117
- hasMore && /* @__PURE__ */ jsx34("li", { ref: loadMoreSentinelRef, "aria-hidden": "true", className: "h-px" })
3147
+ hasMore && /* @__PURE__ */ jsx35("li", { ref: loadMoreSentinelRef, "aria-hidden": "true", className: "h-px" })
3118
3148
  ]
3119
3149
  }
3120
3150
  )
@@ -3124,7 +3154,7 @@ function TrackListSidebar({
3124
3154
  }
3125
3155
 
3126
3156
  // src/genre-tree/PlayerPanel.tsx
3127
- import { useEffect as useEffect7, useState as useState9 } from "react";
3157
+ import { useEffect as useEffect7, useState as useState10 } from "react";
3128
3158
  import { twMerge } from "tailwind-merge";
3129
3159
  import {
3130
3160
  usePlayer as usePlayer11,
@@ -3139,7 +3169,7 @@ import { PanelEdgeTab } from "@behindthemusictree/ui";
3139
3169
  import { Pause as Pause3, Play as Play4, SkipBack, SkipForward, Volume2, VolumeX } from "lucide-react";
3140
3170
  import { formatTime, useTrackList as useTrackList7 } from "@behindthemusictree/app-kit/genre-tree";
3141
3171
  import { PlayStates as PlayStates4, useCurrentTime, usePlayer as usePlayer10 } from "@behindthemusictree/app-kit/player";
3142
- import { jsx as jsx35, jsxs as jsxs28 } from "react/jsx-runtime";
3172
+ import { jsx as jsx36, jsxs as jsxs28 } from "react/jsx-runtime";
3143
3173
  function PlayerControls() {
3144
3174
  const {
3145
3175
  duration,
@@ -3165,8 +3195,8 @@ function PlayerControls() {
3165
3195
  className: "player-controls flex shrink-0 flex-col gap-2 border-b border-zinc-800 px-3 py-2 text-zinc-200",
3166
3196
  children: [
3167
3197
  /* @__PURE__ */ jsxs28("div", { className: "flex min-w-0 items-center gap-2 text-xs tabular-nums text-zinc-400", children: [
3168
- /* @__PURE__ */ jsx35("span", { "aria-label": "Elapsed time", children: formatTime(safeCurrentTime) }),
3169
- /* @__PURE__ */ jsx35(
3198
+ /* @__PURE__ */ jsx36("span", { "aria-label": "Elapsed time", children: formatTime(safeCurrentTime) }),
3199
+ /* @__PURE__ */ jsx36(
3170
3200
  "input",
3171
3201
  {
3172
3202
  "aria-label": "Seek",
@@ -3180,11 +3210,11 @@ function PlayerControls() {
3180
3210
  onChange: (event) => seekTo(Number(event.currentTarget.value))
3181
3211
  }
3182
3212
  ),
3183
- /* @__PURE__ */ jsx35("span", { "aria-label": "Duration", children: formatTime(safeDuration) })
3213
+ /* @__PURE__ */ jsx36("span", { "aria-label": "Duration", children: formatTime(safeDuration) })
3184
3214
  ] }),
3185
3215
  /* @__PURE__ */ jsxs28("div", { className: "grid min-h-9 grid-cols-[1fr_auto_1fr] items-center gap-3", children: [
3186
3216
  /* @__PURE__ */ jsxs28("div", { className: "col-start-2 flex items-center justify-center gap-2", children: [
3187
- /* @__PURE__ */ jsx35(
3217
+ /* @__PURE__ */ jsx36(
3188
3218
  "button",
3189
3219
  {
3190
3220
  type: "button",
@@ -3193,10 +3223,10 @@ function PlayerControls() {
3193
3223
  disabled: !isReady || !hasPreviousTrack,
3194
3224
  onClick: playPreviousTrack,
3195
3225
  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",
3196
- children: /* @__PURE__ */ jsx35(SkipBack, { "aria-hidden": "true", className: "h-4 w-4" })
3226
+ children: /* @__PURE__ */ jsx36(SkipBack, { "aria-hidden": "true", className: "h-4 w-4" })
3197
3227
  }
3198
3228
  ),
3199
- /* @__PURE__ */ jsx35(
3229
+ /* @__PURE__ */ jsx36(
3200
3230
  "button",
3201
3231
  {
3202
3232
  type: "button",
@@ -3205,10 +3235,10 @@ function PlayerControls() {
3205
3235
  disabled: !isReady,
3206
3236
  onClick: handlePlayPauseAction,
3207
3237
  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",
3208
- 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" })
3238
+ children: isPlaying ? /* @__PURE__ */ jsx36(Pause3, { "aria-hidden": "true", className: "h-4 w-4", fill: "currentColor" }) : /* @__PURE__ */ jsx36(Play4, { "aria-hidden": "true", className: "h-4 w-4", fill: "currentColor" })
3209
3239
  }
3210
3240
  ),
3211
- /* @__PURE__ */ jsx35(
3241
+ /* @__PURE__ */ jsx36(
3212
3242
  "button",
3213
3243
  {
3214
3244
  type: "button",
@@ -3217,14 +3247,14 @@ function PlayerControls() {
3217
3247
  disabled: !isReady || !hasNextTrack,
3218
3248
  onClick: playNextTrack,
3219
3249
  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",
3220
- children: /* @__PURE__ */ jsx35(SkipForward, { "aria-hidden": "true", className: "h-4 w-4" })
3250
+ children: /* @__PURE__ */ jsx36(SkipForward, { "aria-hidden": "true", className: "h-4 w-4" })
3221
3251
  }
3222
3252
  )
3223
3253
  ] }),
3224
3254
  /* @__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: [
3225
- 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" }),
3226
- /* @__PURE__ */ jsx35("span", { className: "sr-only", children: "Volume" }),
3227
- /* @__PURE__ */ jsx35(
3255
+ volume === 0 ? /* @__PURE__ */ jsx36(VolumeX, { "aria-hidden": "true", className: "h-[0.7rem] w-[0.7rem] shrink-0" }) : /* @__PURE__ */ jsx36(Volume2, { "aria-hidden": "true", className: "h-[0.7rem] w-[0.7rem] shrink-0" }),
3256
+ /* @__PURE__ */ jsx36("span", { className: "sr-only", children: "Volume" }),
3257
+ /* @__PURE__ */ jsx36(
3228
3258
  "input",
3229
3259
  {
3230
3260
  "aria-label": "Volume",
@@ -3246,7 +3276,7 @@ function PlayerControls() {
3246
3276
  }
3247
3277
 
3248
3278
  // src/genre-tree/PlayerPanel.tsx
3249
- import { jsx as jsx36, jsxs as jsxs29 } from "react/jsx-runtime";
3279
+ import { jsx as jsx37, jsxs as jsxs29 } from "react/jsx-runtime";
3250
3280
  var PANEL_ID = "player-panel";
3251
3281
  var DEFAULT_EXTENDED_WIDTH = "calc(100vw - var(--layout-center-left) - var(--layout-gutter))";
3252
3282
  function PlayerPanel({
@@ -3260,12 +3290,12 @@ function PlayerPanel({
3260
3290
  }) {
3261
3291
  const { playerTrackObject, retryPlayback } = usePlayer11();
3262
3292
  const { toggleTrackListSidebar, isTrackListSidebarVisible } = useTrackListSidebarVisibility();
3263
- const [lastLoadedTrackTitle, setLastLoadedTrackTitle] = useState9("");
3293
+ const [lastLoadedTrackTitle, setLastLoadedTrackTitle] = useState10("");
3264
3294
  const loadedTrackTitle = playerTrackObject?.track.title;
3265
3295
  useEffect7(() => {
3266
3296
  if (loadedTrackTitle) setLastLoadedTrackTitle(loadedTrackTitle);
3267
3297
  }, [loadedTrackTitle]);
3268
- const [uncontrolledExtended, setUncontrolledExtended] = useState9(false);
3298
+ const [uncontrolledExtended, setUncontrolledExtended] = useState10(false);
3269
3299
  const isExtendRequested = expanded ?? uncontrolledExtended;
3270
3300
  const setIsExtendRequested = (next) => {
3271
3301
  setUncontrolledExtended(next);
@@ -3299,7 +3329,7 @@ function PlayerPanel({
3299
3329
  ),
3300
3330
  style: isExtended ? { width: extendedWidth } : void 0,
3301
3331
  children: [
3302
- /* @__PURE__ */ jsx36(
3332
+ /* @__PURE__ */ jsx37(
3303
3333
  PanelEdgeTab,
3304
3334
  {
3305
3335
  side: "right",
@@ -3318,19 +3348,19 @@ function PlayerPanel({
3318
3348
  ),
3319
3349
  children: [
3320
3350
  /* @__PURE__ */ jsxs29("div", { className: "flex w-[var(--layout-right-w)] shrink-0 flex-col", children: [
3321
- /* @__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 }) }),
3351
+ /* @__PURE__ */ jsx37("div", { className: "flex shrink-0 items-center justify-between gap-2 border-b border-zinc-800 p-2", children: /* @__PURE__ */ jsx37("span", { className: "min-w-0 truncate text-sm font-semibold", children: loadedTrackTitle || lastLoadedTrackTitle }) }),
3322
3352
  /* @__PURE__ */ jsxs29("div", { className: "relative w-full shrink-0", children: [
3323
- /* @__PURE__ */ jsx36(PlayerVideoSurface, { className: "aspect-video w-full bg-black" }),
3353
+ /* @__PURE__ */ jsx37(PlayerVideoSurface, { className: "aspect-video w-full bg-black" }),
3324
3354
  playerTrackObject?.loadError && /* @__PURE__ */ jsxs29("span", { className: "absolute bottom-2 left-2 right-2 text-xs text-red-400", children: [
3325
3355
  playerTrackObject.loadError,
3326
- /* @__PURE__ */ jsx36("button", { type: "button", className: "ml-2 underline", onClick: () => {
3356
+ /* @__PURE__ */ jsx37("button", { type: "button", className: "ml-2 underline", onClick: () => {
3327
3357
  void retryPlayback();
3328
3358
  }, children: "Retry" })
3329
3359
  ] })
3330
3360
  ] }),
3331
- /* @__PURE__ */ jsx36(PlayerControls, {})
3361
+ /* @__PURE__ */ jsx37(PlayerControls, {})
3332
3362
  ] }),
3333
- /* @__PURE__ */ jsx36(
3363
+ /* @__PURE__ */ jsx37(
3334
3364
  TrackListSidebar,
3335
3365
  {
3336
3366
  layout: "inline",
@@ -3357,11 +3387,11 @@ function PlayerPanel({
3357
3387
  import { v4 as uuidv4 } from "uuid";
3358
3388
  import { AiFillStar, AiOutlineStar } from "react-icons/ai";
3359
3389
  import { FORM_RATING_NULL_VALUE } from "@behindthemusictree/app-kit/genre-tree";
3360
- import { jsx as jsx37, jsxs as jsxs30 } from "react/jsx-runtime";
3390
+ import { jsx as jsx38, jsxs as jsxs30 } from "react/jsx-runtime";
3361
3391
  function Rating({ rating, handleChange }) {
3362
3392
  const instanceId = uuidv4();
3363
- 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: [
3364
- /* @__PURE__ */ jsx37(
3393
+ return /* @__PURE__ */ jsx38("div", { className: "flex items-center", children: [...Array(6)].map((_, i) => /* @__PURE__ */ jsxs30("div", { className: `relative ${i === 0 ? "mr-4" : "mr-1"}`, children: [
3394
+ /* @__PURE__ */ jsx38(
3365
3395
  "input",
3366
3396
  {
3367
3397
  id: `star-${instanceId}-${i}`,
@@ -3373,16 +3403,16 @@ function Rating({ rating, handleChange }) {
3373
3403
  onChange: handleChange
3374
3404
  }
3375
3405
  ),
3376
- /* @__PURE__ */ jsx37("label", { htmlFor: `star-${instanceId}-${i}`, className: "cursor-pointer", children: i === 0 ? /* @__PURE__ */ jsxs30("div", { className: "flex", children: [
3377
- /* @__PURE__ */ jsx37(
3406
+ /* @__PURE__ */ jsx38("label", { htmlFor: `star-${instanceId}-${i}`, className: "cursor-pointer", children: i === 0 ? /* @__PURE__ */ jsxs30("div", { className: "flex", children: [
3407
+ /* @__PURE__ */ jsx38(
3378
3408
  AiOutlineStar,
3379
3409
  {
3380
3410
  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)]"}`
3381
3411
  }
3382
3412
  ),
3383
- /* @__PURE__ */ jsx37("span", { className: "flex-grow w-8" }),
3413
+ /* @__PURE__ */ jsx38("span", { className: "flex-grow w-8" }),
3384
3414
  " "
3385
- ] }) : /* @__PURE__ */ jsx37(
3415
+ ] }) : /* @__PURE__ */ jsx38(
3386
3416
  AiFillStar,
3387
3417
  {
3388
3418
  className: `w-7 h-7 absolute top-0 left-0 ${(rating ?? -1) >= i ? "text-[var(--color-accent-rating)]" : "text-[var(--color-text-muted)]"}`
@@ -3415,4 +3445,4 @@ export {
3415
3445
  GenreTreeViewSkeleton2 as GenreTreeViewSkeleton,
3416
3446
  GenreTreeOutlineSkeleton
3417
3447
  };
3418
- //# sourceMappingURL=chunk-A7OWCEIK.js.map
3448
+ //# sourceMappingURL=chunk-JP7PID7L.js.map